blob: 1b6180d64c6cf6b77005bbc3812f0b8e55f95569 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
9#include "libGLESv2/validationES.h"
Jamie Madill26e91952014-03-05 15:01:27 -050010#include "libGLESv2/validationES2.h"
11#include "libGLESv2/validationES3.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040012#include "libGLESv2/Context.h"
13#include "libGLESv2/Texture.h"
14#include "libGLESv2/Framebuffer.h"
Jamie Madille261b442014-06-25 12:42:21 -040015#include "libGLESv2/FramebufferAttachment.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040016#include "libGLESv2/formatutils.h"
17#include "libGLESv2/main.h"
Jamie Madilldb2f14c2014-05-13 13:56:30 -040018#include "libGLESv2/Query.h"
Jamie Madill36398922014-05-20 14:51:53 -040019#include "libGLESv2/ProgramBinary.h"
Jamie Madill250d33f2014-06-06 17:09:03 -040020#include "libGLESv2/TransformFeedback.h"
Jamie Madilld4cfa572014-07-08 10:00:32 -040021#include "libGLESv2/VertexArray.h"
Jamie Madill2b976812014-08-25 15:47:49 -040022#include "libGLESv2/renderer/BufferImpl.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040023
24#include "common/mathutil.h"
25#include "common/utilities.h"
26
27namespace gl
28{
29
Geoff Lang0550d032014-01-30 11:29:07 -050030bool ValidCap(const Context *context, GLenum cap)
31{
32 switch (cap)
33 {
34 case GL_CULL_FACE:
35 case GL_POLYGON_OFFSET_FILL:
36 case GL_SAMPLE_ALPHA_TO_COVERAGE:
37 case GL_SAMPLE_COVERAGE:
38 case GL_SCISSOR_TEST:
39 case GL_STENCIL_TEST:
40 case GL_DEPTH_TEST:
41 case GL_BLEND:
42 case GL_DITHER:
43 return true;
44 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
45 case GL_RASTERIZER_DISCARD:
46 return (context->getClientVersion() >= 3);
47 default:
48 return false;
49 }
50}
51
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050052bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040053{
Jamie Madilld7460c72014-01-21 16:38:14 -050054 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040055 {
Jamie Madilld7460c72014-01-21 16:38:14 -050056 case GL_TEXTURE_2D:
57 case GL_TEXTURE_CUBE_MAP:
58 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040059
Jamie Madilld7460c72014-01-21 16:38:14 -050060 case GL_TEXTURE_3D:
61 case GL_TEXTURE_2D_ARRAY:
62 return (context->getClientVersion() >= 3);
63
64 default:
65 return false;
66 }
Jamie Madill35d15012013-10-07 10:46:37 -040067}
68
Shannon Woods4dfed832014-03-17 20:03:39 -040069// This function differs from ValidTextureTarget in that the target must be
70// usable as the destination of a 2D operation-- so a cube face is valid, but
71// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -040072// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -040073bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
74{
75 switch (target)
76 {
77 case GL_TEXTURE_2D:
78 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
79 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
80 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
81 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
82 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
83 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
84 return true;
85 case GL_TEXTURE_2D_ARRAY:
86 case GL_TEXTURE_3D:
87 return (context->getClientVersion() >= 3);
88 default:
89 return false;
90 }
91}
92
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050093bool ValidFramebufferTarget(GLenum target)
94{
95 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
96
97 switch (target)
98 {
99 case GL_FRAMEBUFFER: return true;
100 case GL_READ_FRAMEBUFFER: return true;
101 case GL_DRAW_FRAMEBUFFER: return true;
102 default: return false;
103 }
104}
105
Jamie Madill8c96d582014-03-05 15:01:23 -0500106bool ValidBufferTarget(const Context *context, GLenum target)
107{
108 switch (target)
109 {
110 case GL_ARRAY_BUFFER:
111 case GL_ELEMENT_ARRAY_BUFFER:
112 return true;
113
Jamie Madill8c96d582014-03-05 15:01:23 -0500114 case GL_PIXEL_PACK_BUFFER:
115 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400116 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400117
Shannon Woodsb3801742014-03-27 14:59:19 -0400118 case GL_COPY_READ_BUFFER:
119 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500120 case GL_TRANSFORM_FEEDBACK_BUFFER:
121 case GL_UNIFORM_BUFFER:
122 return (context->getClientVersion() >= 3);
123
124 default:
125 return false;
126 }
127}
128
Jamie Madill70656a62014-03-05 15:01:26 -0500129bool ValidBufferParameter(const Context *context, GLenum pname)
130{
131 switch (pname)
132 {
133 case GL_BUFFER_USAGE:
134 case GL_BUFFER_SIZE:
135 return true;
136
137 // GL_BUFFER_MAP_POINTER is a special case, and may only be
138 // queried with GetBufferPointerv
139 case GL_BUFFER_ACCESS_FLAGS:
140 case GL_BUFFER_MAPPED:
141 case GL_BUFFER_MAP_OFFSET:
142 case GL_BUFFER_MAP_LENGTH:
143 return (context->getClientVersion() >= 3);
144
145 default:
146 return false;
147 }
148}
149
Jamie Madill8c96d582014-03-05 15:01:23 -0500150bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400151{
Geoff Langaae65a42014-05-26 12:43:44 -0400152 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400153 switch (target)
154 {
Geoff Langaae65a42014-05-26 12:43:44 -0400155 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400156 case GL_TEXTURE_CUBE_MAP:
157 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
158 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
159 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
160 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
161 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400162 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
163 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
164 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400165 default: UNREACHABLE();
166 }
167
Geoff Langaae65a42014-05-26 12:43:44 -0400168 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400169}
170
Geoff Langb1196682014-07-23 13:47:29 -0400171bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400172 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400173{
174 if (level < 0 || width < 0 || height < 0 || depth < 0)
175 {
176 return false;
177 }
178
Geoff Langc0b9ef42014-07-02 10:02:37 -0400179 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400180 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400181 {
182 return false;
183 }
184
185 if (!ValidMipLevel(context, target, level))
186 {
187 return false;
188 }
189
190 return true;
191}
192
Geoff Langb1196682014-07-23 13:47:29 -0400193bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400194{
Geoff Lang5d601382014-07-22 15:14:06 -0400195 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
196 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400197 {
198 return false;
199 }
200
Geoff Lang5d601382014-07-22 15:14:06 -0400201 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
202 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400203 {
204 return false;
205 }
206
207 return true;
208}
209
Geoff Lang37dde692014-01-31 16:34:54 -0500210bool ValidQueryType(const Context *context, GLenum queryType)
211{
212 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
213 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
214
215 switch (queryType)
216 {
217 case GL_ANY_SAMPLES_PASSED:
218 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
219 return true;
220 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
221 return (context->getClientVersion() >= 3);
222 default:
223 return false;
224 }
225}
226
Geoff Langb1196682014-07-23 13:47:29 -0400227bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500228{
229 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
230 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
231 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
232
233 if (context->getProgram(id) != NULL)
234 {
235 return true;
236 }
237 else if (context->getShader(id) != NULL)
238 {
239 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400240 context->recordError(Error(GL_INVALID_OPERATION));
241 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500242 }
243 else
244 {
245 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400246 context->recordError(Error(GL_INVALID_VALUE));
247 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500248 }
249}
250
Geoff Langb1196682014-07-23 13:47:29 -0400251bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400252{
253 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
254 {
255 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
256
Geoff Langaae65a42014-05-26 12:43:44 -0400257 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400258 {
Geoff Langb1196682014-07-23 13:47:29 -0400259 context->recordError(Error(GL_INVALID_VALUE));
260 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400261 }
262 }
263 else
264 {
265 switch (attachment)
266 {
267 case GL_DEPTH_ATTACHMENT:
268 case GL_STENCIL_ATTACHMENT:
269 break;
270
271 case GL_DEPTH_STENCIL_ATTACHMENT:
272 if (context->getClientVersion() < 3)
273 {
Geoff Langb1196682014-07-23 13:47:29 -0400274 context->recordError(Error(GL_INVALID_ENUM));
275 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400276 }
277 break;
278
279 default:
Geoff Langb1196682014-07-23 13:47:29 -0400280 context->recordError(Error(GL_INVALID_ENUM));
281 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400282 }
283 }
284
285 return true;
286}
287
Geoff Langb1196682014-07-23 13:47:29 -0400288bool ValidateRenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400289 GLenum internalformat, GLsizei width, GLsizei height,
290 bool angleExtension)
291{
292 switch (target)
293 {
294 case GL_RENDERBUFFER:
295 break;
296 default:
Geoff Langb1196682014-07-23 13:47:29 -0400297 context->recordError(Error(GL_INVALID_ENUM));
298 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400299 }
300
301 if (width < 0 || height < 0 || samples < 0)
302 {
Geoff Langb1196682014-07-23 13:47:29 -0400303 context->recordError(Error(GL_INVALID_VALUE));
304 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400305 }
306
Geoff Langd87878e2014-09-19 15:42:59 -0400307 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
308 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400309 {
Geoff Langb1196682014-07-23 13:47:29 -0400310 context->recordError(Error(GL_INVALID_ENUM));
311 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400312 }
313
314 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
315 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
316 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
317 // internal format must be sized and not an integer format if samples is greater than zero.
Geoff Langd87878e2014-09-19 15:42:59 -0400318 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400319 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400320 {
Geoff Langb1196682014-07-23 13:47:29 -0400321 context->recordError(Error(GL_INVALID_ENUM));
322 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400323 }
324
Geoff Lang5d601382014-07-22 15:14:06 -0400325 if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400326 {
Geoff Langb1196682014-07-23 13:47:29 -0400327 context->recordError(Error(GL_INVALID_OPERATION));
328 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400329 }
330
Geoff Langaae65a42014-05-26 12:43:44 -0400331 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400332 {
Geoff Langb1196682014-07-23 13:47:29 -0400333 context->recordError(Error(GL_INVALID_VALUE));
334 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400335 }
336
337 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
338 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
339 // states that samples must be less than or equal to the maximum samples for the specified
340 // internal format.
341 if (angleExtension)
342 {
Geoff Lang5f4c4632014-07-03 13:46:52 -0400343 ASSERT(context->getExtensions().framebufferMultisample);
344 if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400345 {
Geoff Langb1196682014-07-23 13:47:29 -0400346 context->recordError(Error(GL_INVALID_VALUE));
347 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400348 }
Geoff Lang5f4c4632014-07-03 13:46:52 -0400349
350 // Check if this specific format supports enough samples
351 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
352 {
Geoff Langb1196682014-07-23 13:47:29 -0400353 context->recordError(Error(GL_OUT_OF_MEMORY));
354 return false;
Geoff Lang5f4c4632014-07-03 13:46:52 -0400355 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400356 }
357 else
358 {
Geoff Lang5f4c4632014-07-03 13:46:52 -0400359 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400360 {
Geoff Langb1196682014-07-23 13:47:29 -0400361 context->recordError(Error(GL_INVALID_VALUE));
362 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400363 }
364 }
365
Shannon Woods53a94a82014-06-24 15:20:36 -0400366 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400367 if (handle == 0)
368 {
Geoff Langb1196682014-07-23 13:47:29 -0400369 context->recordError(Error(GL_INVALID_OPERATION));
370 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400371 }
372
373 return true;
374}
375
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500376bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
377 GLenum renderbuffertarget, GLuint renderbuffer)
378{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400379 if (!ValidFramebufferTarget(target))
380 {
Geoff Langb1196682014-07-23 13:47:29 -0400381 context->recordError(Error(GL_INVALID_ENUM));
382 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400383 }
384
Shannon Woods53a94a82014-06-24 15:20:36 -0400385 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
386 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500387
388 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
389 {
Geoff Langb1196682014-07-23 13:47:29 -0400390 context->recordError(Error(GL_INVALID_OPERATION));
391 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500392 }
393
Jamie Madillb4472272014-07-03 10:38:55 -0400394 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500395 {
Jamie Madillb4472272014-07-03 10:38:55 -0400396 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500397 }
398
Jamie Madillab9d82c2014-01-21 16:38:14 -0500399 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
400 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
401 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
402 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
403 if (renderbuffer != 0)
404 {
405 if (!context->getRenderbuffer(renderbuffer))
406 {
Geoff Langb1196682014-07-23 13:47:29 -0400407 context->recordError(Error(GL_INVALID_OPERATION));
408 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500409 }
410 }
411
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500412 return true;
413}
414
Jamie Madill3c7fa222014-06-05 13:08:51 -0400415static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400416 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
417 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
418{
419 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
420 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
421 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
422 {
423 return true;
424 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400425 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400426 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400427 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400428
Shannon Woods53a94a82014-06-24 15:20:36 -0400429 return scissor.x > 0 || scissor.y > 0 ||
430 scissor.width < writeBuffer->getWidth() ||
431 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400432 }
433 else
434 {
435 return false;
436 }
437}
438
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400439bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400440 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
441 GLenum filter, bool fromAngleExtension)
442{
443 switch (filter)
444 {
445 case GL_NEAREST:
446 break;
447 case GL_LINEAR:
448 if (fromAngleExtension)
449 {
Geoff Langb1196682014-07-23 13:47:29 -0400450 context->recordError(Error(GL_INVALID_ENUM));
451 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400452 }
453 break;
454 default:
Geoff Langb1196682014-07-23 13:47:29 -0400455 context->recordError(Error(GL_INVALID_ENUM));
456 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400457 }
458
459 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
460 {
Geoff Langb1196682014-07-23 13:47:29 -0400461 context->recordError(Error(GL_INVALID_VALUE));
462 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400463 }
464
465 if (mask == 0)
466 {
467 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
468 // buffers are copied.
469 return false;
470 }
471
472 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
473 {
474 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400475 context->recordError(Error(GL_INVALID_OPERATION));
476 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400477 }
478
479 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
480 // color buffer, leaving only nearest being unfiltered from above
481 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
482 {
Geoff Langb1196682014-07-23 13:47:29 -0400483 context->recordError(Error(GL_INVALID_OPERATION));
484 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400485 }
486
Shannon Woods53a94a82014-06-24 15:20:36 -0400487 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400488 {
489 if (fromAngleExtension)
490 {
491 ERR("Blits with the same source and destination framebuffer are not supported by this "
492 "implementation.");
493 }
Geoff Langb1196682014-07-23 13:47:29 -0400494 context->recordError(Error(GL_INVALID_OPERATION));
495 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400496 }
497
Shannon Woods53a94a82014-06-24 15:20:36 -0400498 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
499 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
501 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
502 {
Geoff Langb1196682014-07-23 13:47:29 -0400503 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
504 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400505 }
506
507 if (drawFramebuffer->getSamples() != 0)
508 {
Geoff Langb1196682014-07-23 13:47:29 -0400509 context->recordError(Error(GL_INVALID_OPERATION));
510 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400511 }
512
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
514
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400515 if (mask & GL_COLOR_BUFFER_BIT)
516 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400517 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
518 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519
520 if (readColorBuffer && drawColorBuffer)
521 {
Geoff Lang005df412013-10-16 14:12:50 -0400522 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400523 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400524
525 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
526 {
527 if (drawFramebuffer->isEnabledColorAttachment(i))
528 {
Geoff Lang005df412013-10-16 14:12:50 -0400529 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400530 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400531
Geoff Langb2f3d052013-08-13 12:49:27 -0400532 // The GL ES 3.0.2 spec (pg 193) states that:
533 // 1) If the read buffer is fixed point format, the draw buffer must be as well
534 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
535 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400536 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
537 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400538 {
Geoff Langb1196682014-07-23 13:47:29 -0400539 context->recordError(Error(GL_INVALID_OPERATION));
540 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400541 }
542
Geoff Lang5d601382014-07-22 15:14:06 -0400543 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400544 {
Geoff Langb1196682014-07-23 13:47:29 -0400545 context->recordError(Error(GL_INVALID_OPERATION));
546 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400547 }
548
Geoff Lang5d601382014-07-22 15:14:06 -0400549 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400550 {
Geoff Langb1196682014-07-23 13:47:29 -0400551 context->recordError(Error(GL_INVALID_OPERATION));
552 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400553 }
554
Geoff Langb2f3d052013-08-13 12:49:27 -0400555 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400556 {
Geoff Langb1196682014-07-23 13:47:29 -0400557 context->recordError(Error(GL_INVALID_OPERATION));
558 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400559 }
560 }
561 }
562
Geoff Lang5d601382014-07-22 15:14:06 -0400563 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400564 {
Geoff Langb1196682014-07-23 13:47:29 -0400565 context->recordError(Error(GL_INVALID_OPERATION));
566 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 }
568
569 if (fromAngleExtension)
570 {
571 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
572 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
573 {
Geoff Langb1196682014-07-23 13:47:29 -0400574 context->recordError(Error(GL_INVALID_OPERATION));
575 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400576 }
577
578 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
579 {
580 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
581 {
Jamie Madille92a3542014-07-03 10:38:58 -0400582 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
583 ASSERT(attachment);
584
585 if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400586 {
Geoff Langb1196682014-07-23 13:47:29 -0400587 context->recordError(Error(GL_INVALID_OPERATION));
588 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400589 }
590
Jamie Madille92a3542014-07-03 10:38:58 -0400591 if (attachment->getActualFormat() != readColorBuffer->getActualFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400592 {
Geoff Langb1196682014-07-23 13:47:29 -0400593 context->recordError(Error(GL_INVALID_OPERATION));
594 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400595 }
596 }
597 }
Geoff Lang125deab2013-08-09 13:34:16 -0400598 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
599 srcX0, srcY0, srcX1, srcY1,
600 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400601 {
Geoff Langb1196682014-07-23 13:47:29 -0400602 context->recordError(Error(GL_INVALID_OPERATION));
603 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400604 }
605 }
606 }
607 }
608
609 if (mask & GL_DEPTH_BUFFER_BIT)
610 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400611 gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
612 gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400613
614 if (readDepthBuffer && drawDepthBuffer)
615 {
616 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
617 {
Geoff Langb1196682014-07-23 13:47:29 -0400618 context->recordError(Error(GL_INVALID_OPERATION));
619 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400620 }
621
622 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
623 {
Geoff Langb1196682014-07-23 13:47:29 -0400624 context->recordError(Error(GL_INVALID_OPERATION));
625 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400626 }
627
628 if (fromAngleExtension)
629 {
Geoff Lang125deab2013-08-09 13:34:16 -0400630 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
631 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632 {
633 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400634 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
635 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400636 }
637
638 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
639 {
Geoff Langb1196682014-07-23 13:47:29 -0400640 context->recordError(Error(GL_INVALID_OPERATION));
641 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400642 }
643 }
644 }
645 }
646
647 if (mask & GL_STENCIL_BUFFER_BIT)
648 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400649 gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
650 gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400651
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652 if (readStencilBuffer && drawStencilBuffer)
653 {
654 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
655 {
Geoff Langb1196682014-07-23 13:47:29 -0400656 context->recordError(Error(GL_INVALID_OPERATION));
657 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400658 }
659
660 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
661 {
Geoff Langb1196682014-07-23 13:47:29 -0400662 context->recordError(Error(GL_INVALID_OPERATION));
663 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400664 }
665
666 if (fromAngleExtension)
667 {
Geoff Lang125deab2013-08-09 13:34:16 -0400668 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
669 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670 {
671 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400672 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
673 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400674 }
675
676 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
677 {
Geoff Langb1196682014-07-23 13:47:29 -0400678 context->recordError(Error(GL_INVALID_OPERATION));
679 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400680 }
681 }
682 }
683 }
684
685 return true;
686}
687
Geoff Langb1196682014-07-23 13:47:29 -0400688bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400689{
690 switch (pname)
691 {
692 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
693 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
694 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
695 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
696 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
697 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
698 case GL_CURRENT_VERTEX_ATTRIB:
699 return true;
700
701 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
702 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
703 // the same constant.
704 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
705 return true;
706
707 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400708 if (context->getClientVersion() < 3)
709 {
710 context->recordError(Error(GL_INVALID_ENUM));
711 return false;
712 }
713 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400714
715 default:
Geoff Langb1196682014-07-23 13:47:29 -0400716 context->recordError(Error(GL_INVALID_ENUM));
717 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400718 }
719}
720
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400721bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400722{
723 switch (pname)
724 {
725 case GL_TEXTURE_WRAP_R:
726 case GL_TEXTURE_SWIZZLE_R:
727 case GL_TEXTURE_SWIZZLE_G:
728 case GL_TEXTURE_SWIZZLE_B:
729 case GL_TEXTURE_SWIZZLE_A:
730 case GL_TEXTURE_BASE_LEVEL:
731 case GL_TEXTURE_MAX_LEVEL:
732 case GL_TEXTURE_COMPARE_MODE:
733 case GL_TEXTURE_COMPARE_FUNC:
734 case GL_TEXTURE_MIN_LOD:
735 case GL_TEXTURE_MAX_LOD:
736 if (context->getClientVersion() < 3)
737 {
Geoff Langb1196682014-07-23 13:47:29 -0400738 context->recordError(Error(GL_INVALID_ENUM));
739 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400740 }
741 break;
742
743 default: break;
744 }
745
746 switch (pname)
747 {
748 case GL_TEXTURE_WRAP_S:
749 case GL_TEXTURE_WRAP_T:
750 case GL_TEXTURE_WRAP_R:
751 switch (param)
752 {
753 case GL_REPEAT:
754 case GL_CLAMP_TO_EDGE:
755 case GL_MIRRORED_REPEAT:
756 return true;
757 default:
Geoff Langb1196682014-07-23 13:47:29 -0400758 context->recordError(Error(GL_INVALID_ENUM));
759 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400760 }
761
762 case GL_TEXTURE_MIN_FILTER:
763 switch (param)
764 {
765 case GL_NEAREST:
766 case GL_LINEAR:
767 case GL_NEAREST_MIPMAP_NEAREST:
768 case GL_LINEAR_MIPMAP_NEAREST:
769 case GL_NEAREST_MIPMAP_LINEAR:
770 case GL_LINEAR_MIPMAP_LINEAR:
771 return true;
772 default:
Geoff Langb1196682014-07-23 13:47:29 -0400773 context->recordError(Error(GL_INVALID_ENUM));
774 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775 }
776 break;
777
778 case GL_TEXTURE_MAG_FILTER:
779 switch (param)
780 {
781 case GL_NEAREST:
782 case GL_LINEAR:
783 return true;
784 default:
Geoff Langb1196682014-07-23 13:47:29 -0400785 context->recordError(Error(GL_INVALID_ENUM));
786 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 }
788 break;
789
790 case GL_TEXTURE_USAGE_ANGLE:
791 switch (param)
792 {
793 case GL_NONE:
794 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
795 return true;
796 default:
Geoff Langb1196682014-07-23 13:47:29 -0400797 context->recordError(Error(GL_INVALID_ENUM));
798 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400799 }
800 break;
801
802 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400803 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400804 {
Geoff Langb1196682014-07-23 13:47:29 -0400805 context->recordError(Error(GL_INVALID_ENUM));
806 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400807 }
808
809 // we assume the parameter passed to this validation method is truncated, not rounded
810 if (param < 1)
811 {
Geoff Langb1196682014-07-23 13:47:29 -0400812 context->recordError(Error(GL_INVALID_VALUE));
813 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400814 }
815 return true;
816
817 case GL_TEXTURE_MIN_LOD:
818 case GL_TEXTURE_MAX_LOD:
819 // any value is permissible
820 return true;
821
822 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400823 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400824 switch (param)
825 {
826 case GL_NONE:
827 case GL_COMPARE_REF_TO_TEXTURE:
828 return true;
829 default:
Geoff Langb1196682014-07-23 13:47:29 -0400830 context->recordError(Error(GL_INVALID_ENUM));
831 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400832 }
833 break;
834
835 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400836 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400837 switch (param)
838 {
839 case GL_LEQUAL:
840 case GL_GEQUAL:
841 case GL_LESS:
842 case GL_GREATER:
843 case GL_EQUAL:
844 case GL_NOTEQUAL:
845 case GL_ALWAYS:
846 case GL_NEVER:
847 return true;
848 default:
Geoff Langb1196682014-07-23 13:47:29 -0400849 context->recordError(Error(GL_INVALID_ENUM));
850 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400851 }
852 break;
853
854 case GL_TEXTURE_SWIZZLE_R:
855 case GL_TEXTURE_SWIZZLE_G:
856 case GL_TEXTURE_SWIZZLE_B:
857 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400858 switch (param)
859 {
860 case GL_RED:
861 case GL_GREEN:
862 case GL_BLUE:
863 case GL_ALPHA:
864 case GL_ZERO:
865 case GL_ONE:
866 return true;
867 default:
Geoff Langb1196682014-07-23 13:47:29 -0400868 context->recordError(Error(GL_INVALID_ENUM));
869 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400870 }
871 break;
872
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400873 case GL_TEXTURE_BASE_LEVEL:
874 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400875 if (param < 0)
876 {
Geoff Langb1196682014-07-23 13:47:29 -0400877 context->recordError(Error(GL_INVALID_VALUE));
878 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400879 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400880 return true;
881
882 default:
Geoff Langb1196682014-07-23 13:47:29 -0400883 context->recordError(Error(GL_INVALID_ENUM));
884 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400885 }
886}
887
Geoff Langb1196682014-07-23 13:47:29 -0400888bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400889{
890 switch (pname)
891 {
892 case GL_TEXTURE_MIN_FILTER:
893 case GL_TEXTURE_MAG_FILTER:
894 case GL_TEXTURE_WRAP_S:
895 case GL_TEXTURE_WRAP_T:
896 case GL_TEXTURE_WRAP_R:
897 case GL_TEXTURE_MIN_LOD:
898 case GL_TEXTURE_MAX_LOD:
899 case GL_TEXTURE_COMPARE_MODE:
900 case GL_TEXTURE_COMPARE_FUNC:
901 return true;
902
903 default:
Geoff Langb1196682014-07-23 13:47:29 -0400904 context->recordError(Error(GL_INVALID_ENUM));
905 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400906 }
907}
908
Jamie Madill26e91952014-03-05 15:01:27 -0500909bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
910 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
911{
Shannon Woods53a94a82014-06-24 15:20:36 -0400912 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400913 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500914
915 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
916 {
Geoff Langb1196682014-07-23 13:47:29 -0400917 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
918 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500919 }
920
Shannon Woods53a94a82014-06-24 15:20:36 -0400921 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500922 {
Geoff Langb1196682014-07-23 13:47:29 -0400923 context->recordError(Error(GL_INVALID_OPERATION));
924 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500925 }
926
Jamie Madill893ab082014-05-16 16:56:10 -0400927 if (!framebuffer->getReadColorbuffer())
928 {
Geoff Langb1196682014-07-23 13:47:29 -0400929 context->recordError(Error(GL_INVALID_OPERATION));
930 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400931 }
932
Jamie Madill26e91952014-03-05 15:01:27 -0500933 GLenum currentInternalFormat, currentFormat, currentType;
Geoff Lange4a492b2014-06-19 14:14:41 -0400934 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500935
Jamie Madill893ab082014-05-16 16:56:10 -0400936 context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
Jamie Madill26e91952014-03-05 15:01:27 -0500937
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400938 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
939 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500940
941 if (!(currentFormat == format && currentType == type) && !validReadFormat)
942 {
Geoff Langb1196682014-07-23 13:47:29 -0400943 context->recordError(Error(GL_INVALID_OPERATION));
944 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500945 }
946
Geoff Lang5d601382014-07-22 15:14:06 -0400947 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
948 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500949
Geoff Lang5d601382014-07-22 15:14:06 -0400950 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
Jamie Madill26e91952014-03-05 15:01:27 -0500951 // sized query sanity check
952 if (bufSize)
953 {
954 int requiredSize = outputPitch * height;
955 if (requiredSize > *bufSize)
956 {
Geoff Langb1196682014-07-23 13:47:29 -0400957 context->recordError(Error(GL_INVALID_OPERATION));
958 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500959 }
960 }
961
962 return true;
963}
964
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400965bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
966{
967 if (!ValidQueryType(context, target))
968 {
Geoff Langb1196682014-07-23 13:47:29 -0400969 context->recordError(Error(GL_INVALID_ENUM));
970 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400971 }
972
973 if (id == 0)
974 {
Geoff Langb1196682014-07-23 13:47:29 -0400975 context->recordError(Error(GL_INVALID_OPERATION));
976 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400977 }
978
979 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
980 // of zero, if the active query object name for <target> is non-zero (for the
981 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
982 // the active query for either target is non-zero), if <id> is the name of an
983 // existing query object whose type does not match <target>, or if <id> is the
984 // active query object name for any query type, the error INVALID_OPERATION is
985 // generated.
986
987 // Ensure no other queries are active
988 // NOTE: If other queries than occlusion are supported, we will need to check
989 // separately that:
990 // a) The query ID passed is not the current active query for any target/type
991 // b) There are no active queries for the requested target (and in the case
992 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
993 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -0400994 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400995 {
Geoff Langb1196682014-07-23 13:47:29 -0400996 context->recordError(Error(GL_INVALID_OPERATION));
997 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400998 }
999
1000 Query *queryObject = context->getQuery(id, true, target);
1001
1002 // check that name was obtained with glGenQueries
1003 if (!queryObject)
1004 {
Geoff Langb1196682014-07-23 13:47:29 -04001005 context->recordError(Error(GL_INVALID_OPERATION));
1006 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001007 }
1008
1009 // check for type mismatch
1010 if (queryObject->getType() != target)
1011 {
Geoff Langb1196682014-07-23 13:47:29 -04001012 context->recordError(Error(GL_INVALID_OPERATION));
1013 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001014 }
1015
1016 return true;
1017}
1018
Jamie Madill45c785d2014-05-13 14:09:34 -04001019bool ValidateEndQuery(gl::Context *context, GLenum target)
1020{
1021 if (!ValidQueryType(context, target))
1022 {
Geoff Langb1196682014-07-23 13:47:29 -04001023 context->recordError(Error(GL_INVALID_ENUM));
1024 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001025 }
1026
Shannon Woods53a94a82014-06-24 15:20:36 -04001027 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001028
1029 if (queryObject == NULL)
1030 {
Geoff Langb1196682014-07-23 13:47:29 -04001031 context->recordError(Error(GL_INVALID_OPERATION));
1032 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001033 }
1034
Jamie Madill45c785d2014-05-13 14:09:34 -04001035 return true;
1036}
1037
Jamie Madill36398922014-05-20 14:51:53 -04001038static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1039 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001040{
1041 if (count < 0)
1042 {
Geoff Langb1196682014-07-23 13:47:29 -04001043 context->recordError(Error(GL_INVALID_VALUE));
1044 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001045 }
1046
Shannon Woods53a94a82014-06-24 15:20:36 -04001047 gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001048 if (!programBinary)
1049 {
Geoff Langb1196682014-07-23 13:47:29 -04001050 context->recordError(Error(GL_INVALID_OPERATION));
1051 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001052 }
1053
1054 if (location == -1)
1055 {
1056 // Silently ignore the uniform command
1057 return false;
1058 }
1059
Jamie Madill36398922014-05-20 14:51:53 -04001060 if (!programBinary->isValidUniformLocation(location))
1061 {
Geoff Langb1196682014-07-23 13:47:29 -04001062 context->recordError(Error(GL_INVALID_OPERATION));
1063 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001064 }
1065
1066 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1067
1068 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1069 if (uniform->elementCount() == 1 && count > 1)
1070 {
Geoff Langb1196682014-07-23 13:47:29 -04001071 context->recordError(Error(GL_INVALID_OPERATION));
1072 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001073 }
1074
1075 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001076 return true;
1077}
1078
Jamie Madillaa981bd2014-05-20 10:55:55 -04001079bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1080{
1081 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001082 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001083 {
Geoff Langb1196682014-07-23 13:47:29 -04001084 context->recordError(Error(GL_INVALID_OPERATION));
1085 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001086 }
1087
Jamie Madill36398922014-05-20 14:51:53 -04001088 LinkedUniform *uniform = NULL;
1089 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1090 {
1091 return false;
1092 }
1093
Jamie Madillf2575982014-06-25 16:04:54 -04001094 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Jamie Madill36398922014-05-20 14:51:53 -04001095 bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1096 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1097 {
Geoff Langb1196682014-07-23 13:47:29 -04001098 context->recordError(Error(GL_INVALID_OPERATION));
1099 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001100 }
1101
1102 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001103}
1104
1105bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1106 GLboolean transpose)
1107{
1108 // Check for ES3 uniform entry points
1109 int rows = VariableRowCount(matrixType);
1110 int cols = VariableColumnCount(matrixType);
1111 if (rows != cols && context->getClientVersion() < 3)
1112 {
Geoff Langb1196682014-07-23 13:47:29 -04001113 context->recordError(Error(GL_INVALID_OPERATION));
1114 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001115 }
1116
1117 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1118 {
Geoff Langb1196682014-07-23 13:47:29 -04001119 context->recordError(Error(GL_INVALID_VALUE));
1120 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001121 }
1122
Jamie Madill36398922014-05-20 14:51:53 -04001123 LinkedUniform *uniform = NULL;
1124 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1125 {
1126 return false;
1127 }
1128
1129 if (uniform->type != matrixType)
1130 {
Geoff Langb1196682014-07-23 13:47:29 -04001131 context->recordError(Error(GL_INVALID_OPERATION));
1132 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001133 }
1134
1135 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001136}
1137
Jamie Madill893ab082014-05-16 16:56:10 -04001138bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1139{
1140 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1141 {
Geoff Langb1196682014-07-23 13:47:29 -04001142 context->recordError(Error(GL_INVALID_ENUM));
1143 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001144 }
1145
1146 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1147 {
1148 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1149
Geoff Langaae65a42014-05-26 12:43:44 -04001150 if (colorAttachment >= context->getCaps().maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001151 {
Geoff Langb1196682014-07-23 13:47:29 -04001152 context->recordError(Error(GL_INVALID_OPERATION));
1153 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001154 }
1155 }
1156
1157 switch (pname)
1158 {
1159 case GL_TEXTURE_BINDING_2D:
1160 case GL_TEXTURE_BINDING_CUBE_MAP:
1161 case GL_TEXTURE_BINDING_3D:
1162 case GL_TEXTURE_BINDING_2D_ARRAY:
Geoff Lang3a61c322014-07-10 13:01:54 -04001163 if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001164 {
Geoff Langb1196682014-07-23 13:47:29 -04001165 context->recordError(Error(GL_INVALID_OPERATION));
1166 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001167 }
1168 break;
1169
1170 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1171 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1172 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001173 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001174 ASSERT(framebuffer);
1175 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1176 {
Geoff Langb1196682014-07-23 13:47:29 -04001177 context->recordError(Error(GL_INVALID_OPERATION));
1178 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001179 }
1180
Jamie Madill3c7fa222014-06-05 13:08:51 -04001181 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1182 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001183 {
Geoff Langb1196682014-07-23 13:47:29 -04001184 context->recordError(Error(GL_INVALID_OPERATION));
1185 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001186 }
1187 }
1188 break;
1189
1190 default:
1191 break;
1192 }
1193
1194 // pname is valid, but there are no parameters to return
1195 if (numParams == 0)
1196 {
1197 return false;
1198 }
1199
1200 return true;
1201}
1202
Jamie Madill560a8d82014-05-21 13:06:20 -04001203bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1204 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1205 GLint border, GLenum *textureFormatOut)
1206{
1207
1208 if (!ValidTexture2DDestinationTarget(context, target))
1209 {
Geoff Langb1196682014-07-23 13:47:29 -04001210 context->recordError(Error(GL_INVALID_ENUM));
1211 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001212 }
1213
1214 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1215 {
Geoff Langb1196682014-07-23 13:47:29 -04001216 context->recordError(Error(GL_INVALID_VALUE));
1217 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001218 }
1219
1220 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1221 {
Geoff Langb1196682014-07-23 13:47:29 -04001222 context->recordError(Error(GL_INVALID_VALUE));
1223 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001224 }
1225
1226 if (border != 0)
1227 {
Geoff Langb1196682014-07-23 13:47:29 -04001228 context->recordError(Error(GL_INVALID_VALUE));
1229 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001230 }
1231
1232 if (!ValidMipLevel(context, target, level))
1233 {
Geoff Langb1196682014-07-23 13:47:29 -04001234 context->recordError(Error(GL_INVALID_VALUE));
1235 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001236 }
1237
Shannon Woods53a94a82014-06-24 15:20:36 -04001238 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill560a8d82014-05-21 13:06:20 -04001239 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1240 {
Geoff Langb1196682014-07-23 13:47:29 -04001241 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1242 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001243 }
1244
Shannon Woods53a94a82014-06-24 15:20:36 -04001245 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001246 {
Geoff Langb1196682014-07-23 13:47:29 -04001247 context->recordError(Error(GL_INVALID_OPERATION));
1248 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001249 }
1250
Geoff Langaae65a42014-05-26 12:43:44 -04001251 const gl::Caps &caps = context->getCaps();
1252
Jamie Madill560a8d82014-05-21 13:06:20 -04001253 gl::Texture *texture = NULL;
1254 GLenum textureInternalFormat = GL_NONE;
Jamie Madill560a8d82014-05-21 13:06:20 -04001255 GLint textureLevelWidth = 0;
1256 GLint textureLevelHeight = 0;
1257 GLint textureLevelDepth = 0;
Geoff Langaae65a42014-05-26 12:43:44 -04001258 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001259
1260 switch (target)
1261 {
1262 case GL_TEXTURE_2D:
1263 {
1264 gl::Texture2D *texture2d = context->getTexture2D();
1265 if (texture2d)
1266 {
1267 textureInternalFormat = texture2d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001268 textureLevelWidth = texture2d->getWidth(level);
1269 textureLevelHeight = texture2d->getHeight(level);
1270 textureLevelDepth = 1;
1271 texture = texture2d;
Geoff Langaae65a42014-05-26 12:43:44 -04001272 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001273 }
1274 }
1275 break;
1276
1277 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1278 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1279 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1280 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1281 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1282 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1283 {
1284 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1285 if (textureCube)
1286 {
1287 textureInternalFormat = textureCube->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001288 textureLevelWidth = textureCube->getWidth(target, level);
1289 textureLevelHeight = textureCube->getHeight(target, level);
1290 textureLevelDepth = 1;
1291 texture = textureCube;
Geoff Langaae65a42014-05-26 12:43:44 -04001292 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001293 }
1294 }
1295 break;
1296
1297 case GL_TEXTURE_2D_ARRAY:
1298 {
1299 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1300 if (texture2dArray)
1301 {
1302 textureInternalFormat = texture2dArray->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001303 textureLevelWidth = texture2dArray->getWidth(level);
1304 textureLevelHeight = texture2dArray->getHeight(level);
1305 textureLevelDepth = texture2dArray->getLayers(level);
1306 texture = texture2dArray;
Geoff Langaae65a42014-05-26 12:43:44 -04001307 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001308 }
1309 }
1310 break;
1311
1312 case GL_TEXTURE_3D:
1313 {
1314 gl::Texture3D *texture3d = context->getTexture3D();
1315 if (texture3d)
1316 {
1317 textureInternalFormat = texture3d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001318 textureLevelWidth = texture3d->getWidth(level);
1319 textureLevelHeight = texture3d->getHeight(level);
1320 textureLevelDepth = texture3d->getDepth(level);
1321 texture = texture3d;
Geoff Langaae65a42014-05-26 12:43:44 -04001322 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001323 }
1324 }
1325 break;
1326
1327 default:
Geoff Langb1196682014-07-23 13:47:29 -04001328 context->recordError(Error(GL_INVALID_ENUM));
1329 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001330 }
1331
1332 if (!texture)
1333 {
Geoff Langb1196682014-07-23 13:47:29 -04001334 context->recordError(Error(GL_INVALID_OPERATION));
1335 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001336 }
1337
1338 if (texture->isImmutable() && !isSubImage)
1339 {
Geoff Langb1196682014-07-23 13:47:29 -04001340 context->recordError(Error(GL_INVALID_OPERATION));
1341 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001342 }
1343
Geoff Lang5d601382014-07-22 15:14:06 -04001344 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1345
1346 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001347 {
Geoff Langb1196682014-07-23 13:47:29 -04001348 context->recordError(Error(GL_INVALID_OPERATION));
1349 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001350 }
1351
Geoff Lang5d601382014-07-22 15:14:06 -04001352 if (formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04001353 {
Geoff Lang5d601382014-07-22 15:14:06 -04001354 if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1355 ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
Jamie Madill560a8d82014-05-21 13:06:20 -04001356 {
Geoff Langb1196682014-07-23 13:47:29 -04001357 context->recordError(Error(GL_INVALID_OPERATION));
1358 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001359 }
1360 }
1361
1362 if (isSubImage)
1363 {
1364 if (xoffset + width > textureLevelWidth ||
1365 yoffset + height > textureLevelHeight ||
1366 zoffset >= textureLevelDepth)
1367 {
Geoff Langb1196682014-07-23 13:47:29 -04001368 context->recordError(Error(GL_INVALID_VALUE));
1369 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001370 }
1371 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001372 else
1373 {
1374 if (IsCubemapTextureTarget(target) && width != height)
1375 {
Geoff Langb1196682014-07-23 13:47:29 -04001376 context->recordError(Error(GL_INVALID_VALUE));
1377 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001378 }
1379
Geoff Lang5d601382014-07-22 15:14:06 -04001380 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001381 {
Geoff Langb1196682014-07-23 13:47:29 -04001382 context->recordError(Error(GL_INVALID_ENUM));
1383 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001384 }
1385
1386 int maxLevelDimension = (maxDimension >> level);
1387 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1388 {
Geoff Langb1196682014-07-23 13:47:29 -04001389 context->recordError(Error(GL_INVALID_VALUE));
1390 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001391 }
1392 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001393
1394 *textureFormatOut = textureInternalFormat;
1395 return true;
1396}
1397
Geoff Langb1196682014-07-23 13:47:29 -04001398static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001399{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001400 switch (mode)
1401 {
1402 case GL_POINTS:
1403 case GL_LINES:
1404 case GL_LINE_LOOP:
1405 case GL_LINE_STRIP:
1406 case GL_TRIANGLES:
1407 case GL_TRIANGLE_STRIP:
1408 case GL_TRIANGLE_FAN:
1409 break;
1410 default:
Geoff Langb1196682014-07-23 13:47:29 -04001411 context->recordError(Error(GL_INVALID_ENUM));
1412 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001413 }
1414
Jamie Madill250d33f2014-06-06 17:09:03 -04001415 if (count < 0)
1416 {
Geoff Langb1196682014-07-23 13:47:29 -04001417 context->recordError(Error(GL_INVALID_VALUE));
1418 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001419 }
1420
Geoff Langb1196682014-07-23 13:47:29 -04001421 const State &state = context->getState();
1422
Jamie Madill250d33f2014-06-06 17:09:03 -04001423 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001424 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001425 {
Geoff Langb1196682014-07-23 13:47:29 -04001426 context->recordError(Error(GL_INVALID_OPERATION));
1427 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001428 }
1429
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001430 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001431 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001432 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001433 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1434 {
1435 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1436 // See Section 6.10 of the WebGL 1.0 spec
1437 ERR("This ANGLE implementation does not support separate front/back stencil "
1438 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001439 context->recordError(Error(GL_INVALID_OPERATION));
1440 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001441 }
1442
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001443 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001444 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
1445 {
Geoff Langb1196682014-07-23 13:47:29 -04001446 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1447 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001448 }
1449
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001450 if (state.getCurrentProgramId() == 0)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001451 {
Geoff Langb1196682014-07-23 13:47:29 -04001452 context->recordError(Error(GL_INVALID_OPERATION));
1453 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001454 }
1455
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001456 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
Brandon Jones43a53e22014-08-28 16:23:22 -07001457 if (!programBinary->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001458 {
Geoff Langb1196682014-07-23 13:47:29 -04001459 context->recordError(Error(GL_INVALID_OPERATION));
1460 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001461 }
1462
Jamie Madill2b976812014-08-25 15:47:49 -04001463 // Buffer validations
1464 const VertexArray *vao = state.getVertexArray();
1465 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1466 {
1467 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1468 bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1);
1469 if (attribActive && attrib.enabled)
1470 {
1471 gl::Buffer *buffer = attrib.buffer.get();
1472
1473 if (buffer)
1474 {
1475 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1476 GLint64 maxVertexElement = 0;
1477
1478 if (attrib.divisor > 0)
1479 {
1480 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1481 }
1482 else
1483 {
1484 maxVertexElement = static_cast<GLint64>(maxVertex);
1485 }
1486
1487 GLint64 attribDataSize = maxVertexElement * attribStride;
1488
1489 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1490 // We can return INVALID_OPERATION if our vertex attribute does not have
1491 // enough backing data.
1492 if (attribDataSize > buffer->getSize())
1493 {
Geoff Langb1196682014-07-23 13:47:29 -04001494 context->recordError(Error(GL_INVALID_OPERATION));
1495 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001496 }
1497 }
1498 else if (attrib.pointer == NULL)
1499 {
1500 // This is an application error that would normally result in a crash,
1501 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001502 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1503 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001504 }
1505 }
1506 }
1507
Jamie Madill250d33f2014-06-06 17:09:03 -04001508 // No-op if zero count
1509 return (count > 0);
1510}
1511
Geoff Langb1196682014-07-23 13:47:29 -04001512bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001513{
Jamie Madillfd716582014-06-06 17:09:04 -04001514 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001515 {
Geoff Langb1196682014-07-23 13:47:29 -04001516 context->recordError(Error(GL_INVALID_VALUE));
1517 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001518 }
1519
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001520 const State &state = context->getState();
1521 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madillfd716582014-06-06 17:09:04 -04001522 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1523 curTransformFeedback->getDrawMode() != mode)
1524 {
1525 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1526 // that does not match the current transform feedback object's draw mode (if transform feedback
1527 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001528 context->recordError(Error(GL_INVALID_OPERATION));
1529 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001530 }
1531
Geoff Langb1196682014-07-23 13:47:29 -04001532 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001533 {
1534 return false;
1535 }
1536
1537 return true;
1538}
1539
Geoff Langb1196682014-07-23 13:47:29 -04001540bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001541{
1542 if (primcount < 0)
1543 {
Geoff Langb1196682014-07-23 13:47:29 -04001544 context->recordError(Error(GL_INVALID_VALUE));
1545 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001546 }
1547
Jamie Madill2b976812014-08-25 15:47:49 -04001548 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001549 {
1550 return false;
1551 }
1552
1553 // No-op if zero primitive count
1554 return (primcount > 0);
1555}
1556
Geoff Lang87a93302014-09-16 13:29:43 -04001557static bool ValidateDrawInstancedANGLE(Context *context)
1558{
1559 // Verify there is at least one active attribute with a divisor of zero
1560 const gl::State& state = context->getState();
1561
1562 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
1563
1564 const VertexArray *vao = state.getVertexArray();
1565 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1566 {
1567 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1568 bool active = (programBinary->getSemanticIndex(attributeIndex) != -1);
1569 if (active && attrib.divisor == 0)
1570 {
1571 return true;
1572 }
1573 }
1574
1575 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1576 "has a divisor of zero."));
1577 return false;
1578}
1579
1580bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1581{
1582 if (!ValidateDrawInstancedANGLE(context))
1583 {
1584 return false;
1585 }
1586
1587 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1588}
1589
Geoff Langb1196682014-07-23 13:47:29 -04001590bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001591 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001592{
Jamie Madill250d33f2014-06-06 17:09:03 -04001593 switch (type)
1594 {
1595 case GL_UNSIGNED_BYTE:
1596 case GL_UNSIGNED_SHORT:
1597 break;
1598 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001599 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001600 {
Geoff Langb1196682014-07-23 13:47:29 -04001601 context->recordError(Error(GL_INVALID_ENUM));
1602 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001603 }
1604 break;
1605 default:
Geoff Langb1196682014-07-23 13:47:29 -04001606 context->recordError(Error(GL_INVALID_ENUM));
1607 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001608 }
1609
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001610 const State &state = context->getState();
1611
1612 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madill250d33f2014-06-06 17:09:03 -04001613 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1614 {
1615 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1616 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001617 context->recordError(Error(GL_INVALID_OPERATION));
1618 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001619 }
1620
1621 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001622 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001623 {
Geoff Langb1196682014-07-23 13:47:29 -04001624 context->recordError(Error(GL_INVALID_OPERATION));
1625 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001626 }
1627
Jamie Madill2b976812014-08-25 15:47:49 -04001628 const gl::VertexArray *vao = state.getVertexArray();
1629 const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1630 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001631 {
Geoff Langb1196682014-07-23 13:47:29 -04001632 context->recordError(Error(GL_INVALID_OPERATION));
1633 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001634 }
1635
Jamie Madillae3000b2014-08-25 15:47:51 -04001636 if (elementArrayBuffer)
1637 {
1638 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1639
1640 GLint64 offset = reinterpret_cast<GLint64>(indices);
1641 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1642
1643 // check for integer overflows
1644 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1645 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1646 {
Geoff Langb1196682014-07-23 13:47:29 -04001647 context->recordError(Error(GL_OUT_OF_MEMORY));
1648 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001649 }
1650
1651 // Check for reading past the end of the bound buffer object
1652 if (byteCount > elementArrayBuffer->getSize())
1653 {
Geoff Langb1196682014-07-23 13:47:29 -04001654 context->recordError(Error(GL_INVALID_OPERATION));
1655 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001656 }
1657 }
1658 else if (!indices)
1659 {
1660 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001661 context->recordError(Error(GL_INVALID_OPERATION));
1662 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001663 }
1664
Jamie Madill2b976812014-08-25 15:47:49 -04001665 // Use max index to validate if our vertex buffers are large enough for the pull.
1666 // TODO: offer fast path, with disabled index validation.
1667 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1668 if (elementArrayBuffer)
1669 {
1670 unsigned int offset = reinterpret_cast<unsigned int>(indices);
1671 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
1672 {
1673 const void *dataPointer = elementArrayBuffer->getImplementation()->getData();
1674 const uint8_t *offsetPointer = static_cast<const uint8_t *>(dataPointer) + offset;
1675 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
1676 }
1677 }
1678 else
1679 {
1680 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1681 }
1682
Geoff Langb1196682014-07-23 13:47:29 -04001683 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001684 {
1685 return false;
1686 }
1687
1688 return true;
1689}
1690
Geoff Langb1196682014-07-23 13:47:29 -04001691bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001692 GLenum mode, GLsizei count, GLenum type,
1693 const GLvoid *indices, GLsizei primcount,
1694 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001695{
1696 if (primcount < 0)
1697 {
Geoff Langb1196682014-07-23 13:47:29 -04001698 context->recordError(Error(GL_INVALID_VALUE));
1699 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001700 }
1701
Jamie Madill2b976812014-08-25 15:47:49 -04001702 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001703 {
1704 return false;
1705 }
1706
1707 // No-op zero primitive count
1708 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001709}
1710
Geoff Lang87a93302014-09-16 13:29:43 -04001711bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1712 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1713{
1714 if (!ValidateDrawInstancedANGLE(context))
1715 {
1716 return false;
1717 }
1718
1719 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1720}
1721
Geoff Langb1196682014-07-23 13:47:29 -04001722bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001723 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001724{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001725 if (!ValidFramebufferTarget(target))
1726 {
Geoff Langb1196682014-07-23 13:47:29 -04001727 context->recordError(Error(GL_INVALID_ENUM));
1728 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001729 }
1730
1731 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001732 {
1733 return false;
1734 }
1735
Jamie Madill55ec3b12014-07-03 10:38:57 -04001736 if (texture != 0)
1737 {
1738 gl::Texture *tex = context->getTexture(texture);
1739
1740 if (tex == NULL)
1741 {
Geoff Langb1196682014-07-23 13:47:29 -04001742 context->recordError(Error(GL_INVALID_OPERATION));
1743 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001744 }
1745
1746 if (level < 0)
1747 {
Geoff Langb1196682014-07-23 13:47:29 -04001748 context->recordError(Error(GL_INVALID_VALUE));
1749 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001750 }
1751 }
1752
Shannon Woods53a94a82014-06-24 15:20:36 -04001753 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1754 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill55ec3b12014-07-03 10:38:57 -04001755
1756 if (framebufferHandle == 0 || !framebuffer)
1757 {
Geoff Langb1196682014-07-23 13:47:29 -04001758 context->recordError(Error(GL_INVALID_OPERATION));
1759 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001760 }
1761
1762 return true;
1763}
1764
Geoff Langb1196682014-07-23 13:47:29 -04001765bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001766 GLenum textarget, GLuint texture, GLint level)
1767{
1768 // Attachments are required to be bound to level 0 in ES2
1769 if (context->getClientVersion() < 3 && level != 0)
1770 {
Geoff Langb1196682014-07-23 13:47:29 -04001771 context->recordError(Error(GL_INVALID_VALUE));
1772 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001773 }
1774
1775 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001776 {
1777 return false;
1778 }
1779
Jamie Madill55ec3b12014-07-03 10:38:57 -04001780 if (texture != 0)
1781 {
1782 gl::Texture *tex = context->getTexture(texture);
1783 ASSERT(tex);
1784
Jamie Madill2a6564e2014-07-11 09:53:19 -04001785 const gl::Caps &caps = context->getCaps();
1786
Jamie Madill55ec3b12014-07-03 10:38:57 -04001787 switch (textarget)
1788 {
1789 case GL_TEXTURE_2D:
1790 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001791 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001792 {
Geoff Langb1196682014-07-23 13:47:29 -04001793 context->recordError(Error(GL_INVALID_VALUE));
1794 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001795 }
1796 if (tex->getTarget() != GL_TEXTURE_2D)
1797 {
Geoff Langb1196682014-07-23 13:47:29 -04001798 context->recordError(Error(GL_INVALID_OPERATION));
1799 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001800 }
1801 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1802 if (tex2d->isCompressed(level))
1803 {
Geoff Langb1196682014-07-23 13:47:29 -04001804 context->recordError(Error(GL_INVALID_OPERATION));
1805 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001806 }
1807 }
1808 break;
1809
1810 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1811 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1812 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1813 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1814 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1815 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1816 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001817 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001818 {
Geoff Langb1196682014-07-23 13:47:29 -04001819 context->recordError(Error(GL_INVALID_VALUE));
1820 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001821 }
1822 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1823 {
Geoff Langb1196682014-07-23 13:47:29 -04001824 context->recordError(Error(GL_INVALID_OPERATION));
1825 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001826 }
1827 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1828 if (texcube->isCompressed(textarget, level))
1829 {
Geoff Langb1196682014-07-23 13:47:29 -04001830 context->recordError(Error(GL_INVALID_OPERATION));
1831 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001832 }
1833 }
1834 break;
1835
1836 default:
Geoff Langb1196682014-07-23 13:47:29 -04001837 context->recordError(Error(GL_INVALID_ENUM));
1838 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001839 }
1840 }
1841
Jamie Madill570f7c82014-07-03 10:38:54 -04001842 return true;
1843}
1844
Geoff Langb1196682014-07-23 13:47:29 -04001845bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001846{
1847 if (program == 0)
1848 {
Geoff Langb1196682014-07-23 13:47:29 -04001849 context->recordError(Error(GL_INVALID_VALUE));
1850 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001851 }
1852
1853 gl::Program *programObject = context->getProgram(program);
1854
1855 if (!programObject || !programObject->isLinked())
1856 {
Geoff Langb1196682014-07-23 13:47:29 -04001857 context->recordError(Error(GL_INVALID_OPERATION));
1858 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001859 }
1860
1861 gl::ProgramBinary *programBinary = programObject->getProgramBinary();
1862 if (!programBinary)
1863 {
Geoff Langb1196682014-07-23 13:47:29 -04001864 context->recordError(Error(GL_INVALID_OPERATION));
1865 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001866 }
1867
Jamie Madill549c7fd2014-08-25 15:47:56 -04001868 if (!programBinary->isValidUniformLocation(location))
1869 {
Geoff Langb1196682014-07-23 13:47:29 -04001870 context->recordError(Error(GL_INVALID_OPERATION));
1871 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001872 }
1873
Jamie Madill0063c512014-08-25 15:47:53 -04001874 return true;
1875}
1876
Geoff Langb1196682014-07-23 13:47:29 -04001877bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001878{
1879 return ValidateGetUniformBase(context, program, location);
1880}
1881
Geoff Langb1196682014-07-23 13:47:29 -04001882bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001883{
Jamie Madill78f41802014-08-25 15:47:55 -04001884 return ValidateGetUniformBase(context, program, location);
1885}
1886
Geoff Langb1196682014-07-23 13:47:29 -04001887static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001888{
1889 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001890 {
Jamie Madill78f41802014-08-25 15:47:55 -04001891 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001892 }
1893
Jamie Madilla502c742014-08-28 17:19:13 -04001894 gl::Program *programObject = context->getProgram(program);
1895 ASSERT(programObject);
1896 gl::ProgramBinary *programBinary = programObject->getProgramBinary();
Jamie Madill0063c512014-08-25 15:47:53 -04001897
Jamie Madill78f41802014-08-25 15:47:55 -04001898 // sized queries -- ensure the provided buffer is large enough
1899 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1900 size_t requiredBytes = VariableExternalSize(uniform->type);
1901 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001902 {
Geoff Langb1196682014-07-23 13:47:29 -04001903 context->recordError(Error(GL_INVALID_OPERATION));
1904 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001905 }
1906
1907 return true;
1908}
1909
Geoff Langb1196682014-07-23 13:47:29 -04001910bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001911{
Jamie Madill78f41802014-08-25 15:47:55 -04001912 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001913}
1914
Geoff Langb1196682014-07-23 13:47:29 -04001915bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001916{
Jamie Madill78f41802014-08-25 15:47:55 -04001917 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001918}
1919
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001920}