blob: a84d9eb3ee9d0bb455d6f43e6c44542b3609ed74 [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
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040071 GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
Jamie Madill1ca74672015-07-21 15:14:11 -040072
73 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
74 // We can return INVALID_OPERATION if our vertex attribute does not have
75 // enough backing data.
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040076 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040077 {
Jamie Madill437fa652016-05-03 15:13:24 -040078 context->handleError(
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040079 Error(GL_INVALID_OPERATION,
80 "Vertex buffer is not big enough for the draw call"));
Jamie Madill1ca74672015-07-21 15:14:11 -040081 return false;
82 }
83 }
84 }
85 else if (attrib.pointer == NULL)
86 {
87 // This is an application error that would normally result in a crash,
88 // but we catch it and return an error
Jamie Madill437fa652016-05-03 15:13:24 -040089 context->handleError(Error(
Jamie Madill1ca74672015-07-21 15:14:11 -040090 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
91 return false;
92 }
93 }
94 }
95
96 return true;
97}
98
99} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400100
Geoff Lang0550d032014-01-30 11:29:07 -0500101bool ValidCap(const Context *context, GLenum cap)
102{
103 switch (cap)
104 {
105 case GL_CULL_FACE:
106 case GL_POLYGON_OFFSET_FILL:
107 case GL_SAMPLE_ALPHA_TO_COVERAGE:
108 case GL_SAMPLE_COVERAGE:
109 case GL_SCISSOR_TEST:
110 case GL_STENCIL_TEST:
111 case GL_DEPTH_TEST:
112 case GL_BLEND:
113 case GL_DITHER:
114 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500115
Geoff Lang0550d032014-01-30 11:29:07 -0500116 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
117 case GL_RASTERIZER_DISCARD:
118 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500119
120 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
121 case GL_DEBUG_OUTPUT:
122 return context->getExtensions().debug;
123
Geoff Lang0550d032014-01-30 11:29:07 -0500124 default:
125 return false;
126 }
127}
128
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500129bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400130{
Jamie Madilld7460c72014-01-21 16:38:14 -0500131 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400132 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500133 case GL_TEXTURE_2D:
134 case GL_TEXTURE_CUBE_MAP:
135 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400136
Jamie Madilld7460c72014-01-21 16:38:14 -0500137 case GL_TEXTURE_3D:
138 case GL_TEXTURE_2D_ARRAY:
139 return (context->getClientVersion() >= 3);
140
141 default:
142 return false;
143 }
Jamie Madill35d15012013-10-07 10:46:37 -0400144}
145
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500146bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
147{
148 switch (target)
149 {
150 case GL_TEXTURE_2D:
151 case GL_TEXTURE_CUBE_MAP:
152 return true;
153
154 default:
155 return false;
156 }
157}
158
159bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
160{
161 switch (target)
162 {
163 case GL_TEXTURE_3D:
164 case GL_TEXTURE_2D_ARRAY:
165 return (context->getClientVersion() >= 3);
166
167 default:
168 return false;
169 }
170}
171
Ian Ewellbda75592016-04-18 17:25:54 -0400172// Most texture GL calls are not compatible with external textures, so we have a separate validation
173// function for use in the GL calls that do
174bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
175{
176 return (target == GL_TEXTURE_EXTERNAL_OES) &&
177 (context->getExtensions().eglImageExternal ||
178 context->getExtensions().eglStreamConsumerExternal);
179}
180
Shannon Woods4dfed832014-03-17 20:03:39 -0400181// This function differs from ValidTextureTarget in that the target must be
182// usable as the destination of a 2D operation-- so a cube face is valid, but
183// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400184// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500185bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400186{
187 switch (target)
188 {
189 case GL_TEXTURE_2D:
190 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
191 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
192 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
193 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
194 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
195 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
196 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500197 default:
198 return false;
199 }
200}
201
202bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
203{
204 switch (target)
205 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400206 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500207 case GL_TEXTURE_2D_ARRAY:
208 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400209 default:
210 return false;
211 }
212}
213
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500214bool ValidFramebufferTarget(GLenum target)
215{
Geoff Langd4475812015-03-18 10:53:05 -0400216 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
217 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500218
219 switch (target)
220 {
221 case GL_FRAMEBUFFER: return true;
222 case GL_READ_FRAMEBUFFER: return true;
223 case GL_DRAW_FRAMEBUFFER: return true;
224 default: return false;
225 }
226}
227
Jamie Madill8c96d582014-03-05 15:01:23 -0500228bool ValidBufferTarget(const Context *context, GLenum target)
229{
230 switch (target)
231 {
232 case GL_ARRAY_BUFFER:
233 case GL_ELEMENT_ARRAY_BUFFER:
234 return true;
235
Jamie Madill8c96d582014-03-05 15:01:23 -0500236 case GL_PIXEL_PACK_BUFFER:
237 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400238 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400239
Shannon Woodsb3801742014-03-27 14:59:19 -0400240 case GL_COPY_READ_BUFFER:
241 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500242 case GL_TRANSFORM_FEEDBACK_BUFFER:
243 case GL_UNIFORM_BUFFER:
244 return (context->getClientVersion() >= 3);
245
246 default:
247 return false;
248 }
249}
250
Jamie Madill70656a62014-03-05 15:01:26 -0500251bool ValidBufferParameter(const Context *context, GLenum pname)
252{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400253 const Extensions &extensions = context->getExtensions();
254
Jamie Madill70656a62014-03-05 15:01:26 -0500255 switch (pname)
256 {
257 case GL_BUFFER_USAGE:
258 case GL_BUFFER_SIZE:
259 return true;
260
Geoff Langcc6f55d2015-03-20 13:01:02 -0400261 case GL_BUFFER_ACCESS_OES:
262 return extensions.mapBuffer;
263
264 case GL_BUFFER_MAPPED:
265 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
266 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
267
Jamie Madill70656a62014-03-05 15:01:26 -0500268 // GL_BUFFER_MAP_POINTER is a special case, and may only be
269 // queried with GetBufferPointerv
270 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500271 case GL_BUFFER_MAP_OFFSET:
272 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400273 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500274
275 default:
276 return false;
277 }
278}
279
Jamie Madillc29968b2016-01-20 11:17:23 -0500280bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400281{
Jamie Madillc29968b2016-01-20 11:17:23 -0500282 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400283 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400284 switch (target)
285 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500286 case GL_TEXTURE_2D:
287 maxDimension = caps.max2DTextureSize;
288 break;
Geoff Langce635692013-09-24 13:56:32 -0400289 case GL_TEXTURE_CUBE_MAP:
290 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
291 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
292 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
293 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
294 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500295 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
296 maxDimension = caps.maxCubeMapTextureSize;
297 break;
298 case GL_TEXTURE_3D:
299 maxDimension = caps.max3DTextureSize;
300 break;
301 case GL_TEXTURE_2D_ARRAY:
302 maxDimension = caps.max2DTextureSize;
303 break;
Geoff Langce635692013-09-24 13:56:32 -0400304 default: UNREACHABLE();
305 }
306
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700307 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400308}
309
Austin Kinross08528e12015-10-07 16:24:40 -0700310bool ValidImageSizeParameters(const Context *context,
311 GLenum target,
312 GLint level,
313 GLsizei width,
314 GLsizei height,
315 GLsizei depth,
316 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400317{
318 if (level < 0 || width < 0 || height < 0 || depth < 0)
319 {
320 return false;
321 }
322
Austin Kinross08528e12015-10-07 16:24:40 -0700323 // TexSubImage parameters can be NPOT without textureNPOT extension,
324 // as long as the destination texture is POT.
325 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400326 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400327 {
328 return false;
329 }
330
331 if (!ValidMipLevel(context, target, level))
332 {
333 return false;
334 }
335
336 return true;
337}
338
Geoff Lang0d8b7242015-09-09 14:56:53 -0400339bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
340{
341 // List of compressed format that require that the texture size is smaller than or a multiple of
342 // the compressed block size.
343 switch (internalFormat)
344 {
345 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
346 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
347 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
348 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800349 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400350 return true;
351
352 default:
353 return false;
354 }
355}
356
Jamie Madillc29968b2016-01-20 11:17:23 -0500357bool ValidCompressedImageSize(const ValidationContext *context,
358 GLenum internalFormat,
359 GLsizei width,
360 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400361{
Geoff Lang5d601382014-07-22 15:14:06 -0400362 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
363 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400364 {
365 return false;
366 }
367
Geoff Lang0d8b7242015-09-09 14:56:53 -0400368 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400369 {
370 return false;
371 }
372
Geoff Lang0d8b7242015-09-09 14:56:53 -0400373 if (CompressedTextureFormatRequiresExactSize(internalFormat))
374 {
375 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
376 width % formatInfo.compressedBlockWidth != 0) ||
377 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
378 height % formatInfo.compressedBlockHeight != 0))
379 {
380 return false;
381 }
382 }
383
Geoff Langd4f180b2013-09-24 13:57:44 -0400384 return true;
385}
386
Geoff Lang37dde692014-01-31 16:34:54 -0500387bool ValidQueryType(const Context *context, GLenum queryType)
388{
Geoff Langd4475812015-03-18 10:53:05 -0400389 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
390 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500391
392 switch (queryType)
393 {
394 case GL_ANY_SAMPLES_PASSED:
395 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
396 return true;
397 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
398 return (context->getClientVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500399 case GL_TIME_ELAPSED_EXT:
400 return context->getExtensions().disjointTimerQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500401 default:
402 return false;
403 }
404}
405
Dian Xiang769769a2015-09-09 15:20:08 -0700406Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500407{
408 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
409 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
410 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
411
Dian Xiang769769a2015-09-09 15:20:08 -0700412 Program *validProgram = context->getProgram(id);
413
414 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500415 {
Dian Xiang769769a2015-09-09 15:20:08 -0700416 if (context->getShader(id))
417 {
Jamie Madill437fa652016-05-03 15:13:24 -0400418 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700419 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
420 }
421 else
422 {
Jamie Madill437fa652016-05-03 15:13:24 -0400423 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700424 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500425 }
Dian Xiang769769a2015-09-09 15:20:08 -0700426
427 return validProgram;
428}
429
430Shader *GetValidShader(Context *context, GLuint id)
431{
432 // See ValidProgram for spec details.
433
434 Shader *validShader = context->getShader(id);
435
436 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500437 {
Dian Xiang769769a2015-09-09 15:20:08 -0700438 if (context->getProgram(id))
439 {
Jamie Madill437fa652016-05-03 15:13:24 -0400440 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700441 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
442 }
443 else
444 {
Jamie Madill437fa652016-05-03 15:13:24 -0400445 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700446 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500447 }
Dian Xiang769769a2015-09-09 15:20:08 -0700448
449 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500450}
451
Geoff Langb1196682014-07-23 13:47:29 -0400452bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400453{
454 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
455 {
456 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
457
Geoff Langaae65a42014-05-26 12:43:44 -0400458 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400459 {
Jamie Madill437fa652016-05-03 15:13:24 -0400460 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400461 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400462 }
463 }
464 else
465 {
466 switch (attachment)
467 {
468 case GL_DEPTH_ATTACHMENT:
469 case GL_STENCIL_ATTACHMENT:
470 break;
471
472 case GL_DEPTH_STENCIL_ATTACHMENT:
473 if (context->getClientVersion() < 3)
474 {
Jamie Madill437fa652016-05-03 15:13:24 -0400475 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400476 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400477 }
478 break;
479
480 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400481 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400482 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400483 }
484 }
485
486 return true;
487}
488
Corentin Walleze0902642014-11-04 12:32:15 -0800489bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
490 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400491{
492 switch (target)
493 {
494 case GL_RENDERBUFFER:
495 break;
496 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400497 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400498 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400499 }
500
501 if (width < 0 || height < 0 || samples < 0)
502 {
Jamie Madill437fa652016-05-03 15:13:24 -0400503 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400504 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400505 }
506
Geoff Langd87878e2014-09-19 15:42:59 -0400507 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
508 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400509 {
Jamie Madill437fa652016-05-03 15:13:24 -0400510 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400511 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400512 }
513
514 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
515 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800516 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400517 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400518 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 {
Jamie Madill437fa652016-05-03 15:13:24 -0400520 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400521 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 }
523
Geoff Langaae65a42014-05-26 12:43:44 -0400524 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400525 {
Jamie Madill437fa652016-05-03 15:13:24 -0400526 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400527 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400528 }
529
Shannon Woods53a94a82014-06-24 15:20:36 -0400530 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400531 if (handle == 0)
532 {
Jamie Madill437fa652016-05-03 15:13:24 -0400533 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400534 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400535 }
536
537 return true;
538}
539
Corentin Walleze0902642014-11-04 12:32:15 -0800540bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
541 GLenum internalformat, GLsizei width, GLsizei height)
542{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800543 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800544
545 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400546 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800547 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400548 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800549 {
Jamie Madill437fa652016-05-03 15:13:24 -0400550 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800551 return false;
552 }
553
554 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
555 // the specified storage. This is different than ES 3.0 in which a sample number higher
556 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800557 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
558 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800559 {
Geoff Langa4903b72015-03-02 16:02:48 -0800560 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
561 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
562 {
Jamie Madill437fa652016-05-03 15:13:24 -0400563 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800564 return false;
565 }
Corentin Walleze0902642014-11-04 12:32:15 -0800566 }
567
568 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
569}
570
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500571bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
572 GLenum renderbuffertarget, GLuint renderbuffer)
573{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400574 if (!ValidFramebufferTarget(target))
575 {
Jamie Madill437fa652016-05-03 15:13:24 -0400576 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400577 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400578 }
579
Shannon Woods53a94a82014-06-24 15:20:36 -0400580 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500581
Jamie Madill84115c92015-04-23 15:00:07 -0400582 ASSERT(framebuffer);
583 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500584 {
Jamie Madill437fa652016-05-03 15:13:24 -0400585 context->handleError(
586 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400587 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500588 }
589
Jamie Madillb4472272014-07-03 10:38:55 -0400590 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500591 {
Jamie Madillb4472272014-07-03 10:38:55 -0400592 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500593 }
594
Jamie Madillab9d82c2014-01-21 16:38:14 -0500595 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
596 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
597 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
598 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
599 if (renderbuffer != 0)
600 {
601 if (!context->getRenderbuffer(renderbuffer))
602 {
Jamie Madill437fa652016-05-03 15:13:24 -0400603 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400604 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500605 }
606 }
607
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500608 return true;
609}
610
Jamie Madillc29968b2016-01-20 11:17:23 -0500611bool ValidateBlitFramebufferParameters(gl::Context *context,
612 GLint srcX0,
613 GLint srcY0,
614 GLint srcX1,
615 GLint srcY1,
616 GLint dstX0,
617 GLint dstY0,
618 GLint dstX1,
619 GLint dstY1,
620 GLbitfield mask,
621 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622{
623 switch (filter)
624 {
625 case GL_NEAREST:
626 break;
627 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400628 break;
629 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400630 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400631 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632 }
633
634 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
635 {
Jamie Madill437fa652016-05-03 15:13:24 -0400636 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400637 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400638 }
639
640 if (mask == 0)
641 {
642 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
643 // buffers are copied.
644 return false;
645 }
646
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400647 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
648 // color buffer, leaving only nearest being unfiltered from above
649 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
650 {
Jamie Madill437fa652016-05-03 15:13:24 -0400651 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400652 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400653 }
654
Shannon Woods53a94a82014-06-24 15:20:36 -0400655 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400656 {
Jamie Madill437fa652016-05-03 15:13:24 -0400657 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400658 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 }
660
Jamie Madille3ef7152015-04-28 16:55:17 +0000661 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
662 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500663
664 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665 {
Jamie Madill437fa652016-05-03 15:13:24 -0400666 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400667 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400668 }
669
Geoff Lang748f74e2014-12-01 11:25:34 -0500670 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500671 {
Jamie Madill437fa652016-05-03 15:13:24 -0400672 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500673 return false;
674 }
675
Geoff Lang748f74e2014-12-01 11:25:34 -0500676 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500677 {
Jamie Madill437fa652016-05-03 15:13:24 -0400678 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500679 return false;
680 }
681
682 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400683 {
Jamie Madill437fa652016-05-03 15:13:24 -0400684 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400685 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400686 }
687
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400688 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
689
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690 if (mask & GL_COLOR_BUFFER_BIT)
691 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400692 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
693 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500694 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400695
696 if (readColorBuffer && drawColorBuffer)
697 {
Geoff Langd8a22582014-12-17 15:28:23 -0500698 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400699 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700
Geoff Langa15472a2015-08-11 11:48:03 -0400701 for (size_t drawbufferIdx = 0;
702 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 {
Geoff Langa15472a2015-08-11 11:48:03 -0400704 const FramebufferAttachment *attachment =
705 drawFramebuffer->getDrawBuffer(drawbufferIdx);
706 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400707 {
Geoff Langa15472a2015-08-11 11:48:03 -0400708 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400709 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710
Geoff Langb2f3d052013-08-13 12:49:27 -0400711 // The GL ES 3.0.2 spec (pg 193) states that:
712 // 1) If the read buffer is fixed point format, the draw buffer must be as well
713 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
714 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500715 // Changes with EXT_color_buffer_float:
716 // Case 1) is changed to fixed point OR floating point
717 GLenum readComponentType = readFormatInfo.componentType;
718 GLenum drawComponentType = drawFormatInfo.componentType;
719 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
720 readComponentType == GL_SIGNED_NORMALIZED);
721 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
722 drawComponentType == GL_SIGNED_NORMALIZED);
723
724 if (extensions.colorBufferFloat)
725 {
726 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
727 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
728
729 if (readFixedOrFloat != drawFixedOrFloat)
730 {
Jamie Madill437fa652016-05-03 15:13:24 -0400731 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500732 "If the read buffer contains fixed-point or "
733 "floating-point values, the draw buffer "
734 "must as well."));
735 return false;
736 }
737 }
738 else if (readFixedPoint != drawFixedPoint)
739 {
Jamie Madill437fa652016-05-03 15:13:24 -0400740 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500741 "If the read buffer contains fixed-point "
742 "values, the draw buffer must as well."));
743 return false;
744 }
745
746 if (readComponentType == GL_UNSIGNED_INT &&
747 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748 {
Jamie Madill437fa652016-05-03 15:13:24 -0400749 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400750 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400751 }
752
Jamie Madill6163c752015-12-07 16:32:59 -0500753 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754 {
Jamie Madill437fa652016-05-03 15:13:24 -0400755 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400756 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400757 }
758
Geoff Langb2f3d052013-08-13 12:49:27 -0400759 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400760 {
Jamie Madill437fa652016-05-03 15:13:24 -0400761 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400762 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400763 }
764 }
765 }
766
Geoff Lang5d601382014-07-22 15:14:06 -0400767 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 {
Jamie Madill437fa652016-05-03 15:13:24 -0400769 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400770 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400772 }
773 }
774
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200775 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
776 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
777 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400778 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200779 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400781 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
782 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400783
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200784 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785 {
Geoff Langd8a22582014-12-17 15:28:23 -0500786 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 {
Jamie Madill437fa652016-05-03 15:13:24 -0400788 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400789 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400790 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200792 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793 {
Jamie Madill437fa652016-05-03 15:13:24 -0400794 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400795 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796 }
797 }
798 }
799 }
800
801 return true;
802}
803
Geoff Langb1196682014-07-23 13:47:29 -0400804bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805{
806 switch (pname)
807 {
808 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
809 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
810 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
811 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
812 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
813 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
814 case GL_CURRENT_VERTEX_ATTRIB:
815 return true;
816
817 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
818 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
819 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400820 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
821 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400822 return true;
823
824 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400825 if (context->getClientVersion() < 3)
826 {
Jamie Madill437fa652016-05-03 15:13:24 -0400827 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400828 return false;
829 }
830 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400831
832 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400833 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400834 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400835 }
836}
837
Ian Ewellbda75592016-04-18 17:25:54 -0400838bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400839{
840 switch (pname)
841 {
842 case GL_TEXTURE_WRAP_R:
843 case GL_TEXTURE_SWIZZLE_R:
844 case GL_TEXTURE_SWIZZLE_G:
845 case GL_TEXTURE_SWIZZLE_B:
846 case GL_TEXTURE_SWIZZLE_A:
847 case GL_TEXTURE_BASE_LEVEL:
848 case GL_TEXTURE_MAX_LEVEL:
849 case GL_TEXTURE_COMPARE_MODE:
850 case GL_TEXTURE_COMPARE_FUNC:
851 case GL_TEXTURE_MIN_LOD:
852 case GL_TEXTURE_MAX_LOD:
Ian Ewellbda75592016-04-18 17:25:54 -0400853 // ES3 texture paramters are not supported on external textures as the extension is
854 // written against ES2.
855 if (context->getClientVersion() < 3 || target == GL_TEXTURE_EXTERNAL_OES)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400856 {
Jamie Madill437fa652016-05-03 15:13:24 -0400857 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400858 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400859 }
860 break;
861
862 default: break;
863 }
864
865 switch (pname)
866 {
867 case GL_TEXTURE_WRAP_S:
868 case GL_TEXTURE_WRAP_T:
869 case GL_TEXTURE_WRAP_R:
870 switch (param)
871 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000872 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400873 return true;
874 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400875 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300876 if (target == GL_TEXTURE_EXTERNAL_OES)
877 {
878 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400879 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300880 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
881 return false;
882 }
883 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400884 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400885 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400886 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400887 }
888
889 case GL_TEXTURE_MIN_FILTER:
890 switch (param)
891 {
892 case GL_NEAREST:
893 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400894 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400895 case GL_NEAREST_MIPMAP_NEAREST:
896 case GL_LINEAR_MIPMAP_NEAREST:
897 case GL_NEAREST_MIPMAP_LINEAR:
898 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300899 if (target == GL_TEXTURE_EXTERNAL_OES)
900 {
901 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400902 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300903 Error(GL_INVALID_ENUM,
904 "external textures only support NEAREST and LINEAR filtering"));
905 return false;
906 }
907 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400908 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400909 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400910 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400911 }
912 break;
913
914 case GL_TEXTURE_MAG_FILTER:
915 switch (param)
916 {
917 case GL_NEAREST:
918 case GL_LINEAR:
919 return true;
920 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400921 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400922 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400923 }
924 break;
925
926 case GL_TEXTURE_USAGE_ANGLE:
927 switch (param)
928 {
929 case GL_NONE:
930 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
931 return true;
932 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400933 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400934 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400935 }
936 break;
937
938 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400939 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400940 {
Jamie Madill437fa652016-05-03 15:13:24 -0400941 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400942 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400943 }
944
945 // we assume the parameter passed to this validation method is truncated, not rounded
946 if (param < 1)
947 {
Jamie Madill437fa652016-05-03 15:13:24 -0400948 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400949 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400950 }
951 return true;
952
953 case GL_TEXTURE_MIN_LOD:
954 case GL_TEXTURE_MAX_LOD:
955 // any value is permissible
956 return true;
957
958 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400959 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400960 switch (param)
961 {
962 case GL_NONE:
963 case GL_COMPARE_REF_TO_TEXTURE:
964 return true;
965 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400966 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400967 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400968 }
969 break;
970
971 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400972 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400973 switch (param)
974 {
975 case GL_LEQUAL:
976 case GL_GEQUAL:
977 case GL_LESS:
978 case GL_GREATER:
979 case GL_EQUAL:
980 case GL_NOTEQUAL:
981 case GL_ALWAYS:
982 case GL_NEVER:
983 return true;
984 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400985 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400986 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400987 }
988 break;
989
990 case GL_TEXTURE_SWIZZLE_R:
991 case GL_TEXTURE_SWIZZLE_G:
992 case GL_TEXTURE_SWIZZLE_B:
993 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400994 switch (param)
995 {
996 case GL_RED:
997 case GL_GREEN:
998 case GL_BLUE:
999 case GL_ALPHA:
1000 case GL_ZERO:
1001 case GL_ONE:
1002 return true;
1003 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001004 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001005 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001006 }
1007 break;
1008
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001009 case GL_TEXTURE_BASE_LEVEL:
1010 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001011 if (target == GL_TEXTURE_EXTERNAL_OES)
1012 {
1013 // This is not specified, but in line with the spirit of OES_EGL_image_external spec,
1014 // which generally forbids setting mipmap related parameters on external textures.
1015 context->handleError(
1016 Error(GL_INVALID_OPERATION,
1017 "Setting the base level or max level of external textures not supported"));
1018 return false;
1019 }
1020 if (param < 0)
1021 {
1022 context->handleError(Error(GL_INVALID_VALUE));
1023 return false;
1024 }
1025 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001026 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001027 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001028 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001029 }
1030}
1031
Geoff Langb1196682014-07-23 13:47:29 -04001032bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001033{
1034 switch (pname)
1035 {
1036 case GL_TEXTURE_MIN_FILTER:
1037 case GL_TEXTURE_MAG_FILTER:
1038 case GL_TEXTURE_WRAP_S:
1039 case GL_TEXTURE_WRAP_T:
1040 case GL_TEXTURE_WRAP_R:
1041 case GL_TEXTURE_MIN_LOD:
1042 case GL_TEXTURE_MAX_LOD:
1043 case GL_TEXTURE_COMPARE_MODE:
1044 case GL_TEXTURE_COMPARE_FUNC:
1045 return true;
1046
1047 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001048 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001049 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001050 }
1051}
1052
Jamie Madillc29968b2016-01-20 11:17:23 -05001053bool ValidateReadPixels(Context *context,
1054 GLint x,
1055 GLint y,
1056 GLsizei width,
1057 GLsizei height,
1058 GLenum format,
1059 GLenum type,
1060 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001061{
Jamie Madillc29968b2016-01-20 11:17:23 -05001062 if (width < 0 || height < 0)
1063 {
Jamie Madill437fa652016-05-03 15:13:24 -04001064 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001065 return false;
1066 }
1067
1068 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001069 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001070
Geoff Lang748f74e2014-12-01 11:25:34 -05001071 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001072 {
Jamie Madill437fa652016-05-03 15:13:24 -04001073 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001074 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001075 }
1076
Jamie Madill48faf802014-11-06 15:27:22 -05001077 if (context->getState().getReadFramebuffer()->id() != 0 &&
1078 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001079 {
Jamie Madill437fa652016-05-03 15:13:24 -04001080 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001081 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001082 }
1083
Geoff Langbce529e2014-12-01 12:48:41 -05001084 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1085 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001086 {
Jamie Madill437fa652016-05-03 15:13:24 -04001087 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001088 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001089 }
1090
Geoff Langbce529e2014-12-01 12:48:41 -05001091 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1092 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001093 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001094 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001095
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001096 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1097 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001098
1099 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1100 {
Jamie Madill437fa652016-05-03 15:13:24 -04001101 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001102 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001103 }
1104
Jamie Madillc29968b2016-01-20 11:17:23 -05001105 return true;
1106}
1107
1108bool ValidateReadnPixelsEXT(Context *context,
1109 GLint x,
1110 GLint y,
1111 GLsizei width,
1112 GLsizei height,
1113 GLenum format,
1114 GLenum type,
1115 GLsizei bufSize,
1116 GLvoid *pixels)
1117{
1118 if (bufSize < 0)
1119 {
Jamie Madill437fa652016-05-03 15:13:24 -04001120 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001121 return false;
1122 }
1123
Geoff Lang5d601382014-07-22 15:14:06 -04001124 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1125 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001126
Minmin Gongadff67b2015-10-14 10:34:45 -04001127 GLsizei outputPitch =
1128 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1129 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001130 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001131 int requiredSize = outputPitch * height;
1132 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001133 {
Jamie Madill437fa652016-05-03 15:13:24 -04001134 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001135 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001136 }
1137
Jamie Madillc29968b2016-01-20 11:17:23 -05001138 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001139}
1140
Olli Etuaho41997e72016-03-10 13:38:39 +02001141bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001142{
1143 if (!context->getExtensions().occlusionQueryBoolean &&
1144 !context->getExtensions().disjointTimerQuery)
1145 {
Jamie Madill437fa652016-05-03 15:13:24 -04001146 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001147 return false;
1148 }
1149
Olli Etuaho41997e72016-03-10 13:38:39 +02001150 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001151}
1152
Olli Etuaho41997e72016-03-10 13:38:39 +02001153bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001154{
1155 if (!context->getExtensions().occlusionQueryBoolean &&
1156 !context->getExtensions().disjointTimerQuery)
1157 {
Jamie Madill437fa652016-05-03 15:13:24 -04001158 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001159 return false;
1160 }
1161
Olli Etuaho41997e72016-03-10 13:38:39 +02001162 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001163}
1164
1165bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001166{
1167 if (!ValidQueryType(context, target))
1168 {
Jamie Madill437fa652016-05-03 15:13:24 -04001169 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001170 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001171 }
1172
1173 if (id == 0)
1174 {
Jamie Madill437fa652016-05-03 15:13:24 -04001175 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001176 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001177 }
1178
1179 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1180 // of zero, if the active query object name for <target> is non-zero (for the
1181 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1182 // the active query for either target is non-zero), if <id> is the name of an
1183 // existing query object whose type does not match <target>, or if <id> is the
1184 // active query object name for any query type, the error INVALID_OPERATION is
1185 // generated.
1186
1187 // Ensure no other queries are active
1188 // NOTE: If other queries than occlusion are supported, we will need to check
1189 // separately that:
1190 // a) The query ID passed is not the current active query for any target/type
1191 // b) There are no active queries for the requested target (and in the case
1192 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1193 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001194
Corentin Walleze71ea192016-04-19 13:16:37 -04001195 if (context->getState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001196 {
Jamie Madill437fa652016-05-03 15:13:24 -04001197 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001198 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001199 }
1200
1201 Query *queryObject = context->getQuery(id, true, target);
1202
1203 // check that name was obtained with glGenQueries
1204 if (!queryObject)
1205 {
Jamie Madill437fa652016-05-03 15:13:24 -04001206 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001207 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001208 }
1209
1210 // check for type mismatch
1211 if (queryObject->getType() != target)
1212 {
Jamie Madill437fa652016-05-03 15:13:24 -04001213 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001214 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001215 }
1216
1217 return true;
1218}
1219
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001220bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1221{
1222 if (!context->getExtensions().occlusionQueryBoolean &&
1223 !context->getExtensions().disjointTimerQuery)
1224 {
Jamie Madill437fa652016-05-03 15:13:24 -04001225 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001226 return false;
1227 }
1228
1229 return ValidateBeginQueryBase(context, target, id);
1230}
1231
1232bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001233{
1234 if (!ValidQueryType(context, target))
1235 {
Jamie Madill437fa652016-05-03 15:13:24 -04001236 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001237 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001238 }
1239
Shannon Woods53a94a82014-06-24 15:20:36 -04001240 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001241
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001242 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001243 {
Jamie Madill437fa652016-05-03 15:13:24 -04001244 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001245 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001246 }
1247
Jamie Madill45c785d2014-05-13 14:09:34 -04001248 return true;
1249}
1250
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001251bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1252{
1253 if (!context->getExtensions().occlusionQueryBoolean &&
1254 !context->getExtensions().disjointTimerQuery)
1255 {
Jamie Madill437fa652016-05-03 15:13:24 -04001256 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001257 return false;
1258 }
1259
1260 return ValidateEndQueryBase(context, target);
1261}
1262
1263bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1264{
1265 if (!context->getExtensions().disjointTimerQuery)
1266 {
Jamie Madill437fa652016-05-03 15:13:24 -04001267 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001268 return false;
1269 }
1270
1271 if (target != GL_TIMESTAMP_EXT)
1272 {
Jamie Madill437fa652016-05-03 15:13:24 -04001273 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001274 return false;
1275 }
1276
1277 Query *queryObject = context->getQuery(id, true, target);
1278 if (queryObject == nullptr)
1279 {
Jamie Madill437fa652016-05-03 15:13:24 -04001280 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001281 return false;
1282 }
1283
1284 if (context->getState().isQueryActive(queryObject))
1285 {
Jamie Madill437fa652016-05-03 15:13:24 -04001286 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001287 return false;
1288 }
1289
1290 return true;
1291}
1292
1293bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1294{
1295 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1296 {
Jamie Madill437fa652016-05-03 15:13:24 -04001297 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001298 return false;
1299 }
1300
1301 switch (pname)
1302 {
1303 case GL_CURRENT_QUERY_EXT:
1304 if (target == GL_TIMESTAMP_EXT)
1305 {
Jamie Madill437fa652016-05-03 15:13:24 -04001306 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001307 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1308 return false;
1309 }
1310 break;
1311 case GL_QUERY_COUNTER_BITS_EXT:
1312 if (!context->getExtensions().disjointTimerQuery ||
1313 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1314 {
Jamie Madill437fa652016-05-03 15:13:24 -04001315 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001316 return false;
1317 }
1318 break;
1319 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001320 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001321 return false;
1322 }
1323
1324 return true;
1325}
1326
1327bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1328{
1329 if (!context->getExtensions().occlusionQueryBoolean &&
1330 !context->getExtensions().disjointTimerQuery)
1331 {
Jamie Madill437fa652016-05-03 15:13:24 -04001332 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001333 return false;
1334 }
1335
1336 return ValidateGetQueryivBase(context, target, pname);
1337}
1338
1339bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1340{
1341 Query *queryObject = context->getQuery(id, false, GL_NONE);
1342
1343 if (!queryObject)
1344 {
Jamie Madill437fa652016-05-03 15:13:24 -04001345 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001346 return false;
1347 }
1348
1349 if (context->getState().isQueryActive(queryObject))
1350 {
Jamie Madill437fa652016-05-03 15:13:24 -04001351 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001352 return false;
1353 }
1354
1355 switch (pname)
1356 {
1357 case GL_QUERY_RESULT_EXT:
1358 case GL_QUERY_RESULT_AVAILABLE_EXT:
1359 break;
1360
1361 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001362 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001363 return false;
1364 }
1365
1366 return true;
1367}
1368
1369bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1370{
1371 if (!context->getExtensions().disjointTimerQuery)
1372 {
Jamie Madill437fa652016-05-03 15:13:24 -04001373 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001374 return false;
1375 }
1376 return ValidateGetQueryObjectValueBase(context, id, pname);
1377}
1378
1379bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1380{
1381 if (!context->getExtensions().disjointTimerQuery &&
1382 !context->getExtensions().occlusionQueryBoolean)
1383 {
Jamie Madill437fa652016-05-03 15:13:24 -04001384 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001385 return false;
1386 }
1387 return ValidateGetQueryObjectValueBase(context, id, pname);
1388}
1389
1390bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1391{
1392 if (!context->getExtensions().disjointTimerQuery)
1393 {
Jamie Madill437fa652016-05-03 15:13:24 -04001394 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001395 return false;
1396 }
1397 return ValidateGetQueryObjectValueBase(context, id, pname);
1398}
1399
1400bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1401{
1402 if (!context->getExtensions().disjointTimerQuery)
1403 {
Jamie Madill437fa652016-05-03 15:13:24 -04001404 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001405 return false;
1406 }
1407 return ValidateGetQueryObjectValueBase(context, id, pname);
1408}
1409
Jamie Madill62d31cb2015-09-11 13:25:51 -04001410static bool ValidateUniformCommonBase(gl::Context *context,
1411 GLenum targetUniformType,
1412 GLint location,
1413 GLsizei count,
1414 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001415{
1416 if (count < 0)
1417 {
Jamie Madill437fa652016-05-03 15:13:24 -04001418 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001419 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001420 }
1421
Geoff Lang7dd2e102014-11-10 15:19:26 -05001422 gl::Program *program = context->getState().getProgram();
1423 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001424 {
Jamie Madill437fa652016-05-03 15:13:24 -04001425 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001426 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001427 }
1428
Geoff Langd8605522016-04-13 10:19:12 -04001429 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001430 {
1431 // Silently ignore the uniform command
1432 return false;
1433 }
1434
Geoff Lang7dd2e102014-11-10 15:19:26 -05001435 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001436 {
Jamie Madill437fa652016-05-03 15:13:24 -04001437 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001438 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001439 }
1440
Jamie Madill62d31cb2015-09-11 13:25:51 -04001441 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001442
1443 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001444 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001445 {
Jamie Madill437fa652016-05-03 15:13:24 -04001446 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001447 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001448 }
1449
Jamie Madill62d31cb2015-09-11 13:25:51 -04001450 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001451 return true;
1452}
1453
Jamie Madillaa981bd2014-05-20 10:55:55 -04001454bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1455{
1456 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001457 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001458 {
Jamie Madill437fa652016-05-03 15:13:24 -04001459 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001460 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001461 }
1462
Jamie Madill62d31cb2015-09-11 13:25:51 -04001463 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001464 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1465 {
1466 return false;
1467 }
1468
Jamie Madillf2575982014-06-25 16:04:54 -04001469 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001470 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001471 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1472 {
Jamie Madill437fa652016-05-03 15:13:24 -04001473 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001474 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001475 }
1476
1477 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001478}
1479
1480bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1481 GLboolean transpose)
1482{
1483 // Check for ES3 uniform entry points
1484 int rows = VariableRowCount(matrixType);
1485 int cols = VariableColumnCount(matrixType);
1486 if (rows != cols && context->getClientVersion() < 3)
1487 {
Jamie Madill437fa652016-05-03 15:13:24 -04001488 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001489 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001490 }
1491
1492 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1493 {
Jamie Madill437fa652016-05-03 15:13:24 -04001494 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001495 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001496 }
1497
Jamie Madill62d31cb2015-09-11 13:25:51 -04001498 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001499 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1500 {
1501 return false;
1502 }
1503
1504 if (uniform->type != matrixType)
1505 {
Jamie Madill437fa652016-05-03 15:13:24 -04001506 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001507 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001508 }
1509
1510 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001511}
1512
Jamie Madill893ab082014-05-16 16:56:10 -04001513bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1514{
1515 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1516 {
Jamie Madill437fa652016-05-03 15:13:24 -04001517 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001518 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001519 }
1520
Jamie Madill0af26e12015-03-05 19:54:33 -05001521 const Caps &caps = context->getCaps();
1522
Jamie Madill893ab082014-05-16 16:56:10 -04001523 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1524 {
1525 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1526
Jamie Madill0af26e12015-03-05 19:54:33 -05001527 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001528 {
Jamie Madill437fa652016-05-03 15:13:24 -04001529 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001530 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001531 }
1532 }
1533
1534 switch (pname)
1535 {
1536 case GL_TEXTURE_BINDING_2D:
1537 case GL_TEXTURE_BINDING_CUBE_MAP:
1538 case GL_TEXTURE_BINDING_3D:
1539 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001540 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001541 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1542 if (!context->getExtensions().eglStreamConsumerExternal)
1543 {
Jamie Madill437fa652016-05-03 15:13:24 -04001544 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001545 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1546 return false;
1547 }
1548 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001549
1550 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1551 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1552 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001553 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001554 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001555 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001556 {
Jamie Madill437fa652016-05-03 15:13:24 -04001557 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001558 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001559 }
1560
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001561 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001562 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001563 {
Jamie Madill437fa652016-05-03 15:13:24 -04001564 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001565 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001566 }
1567 }
1568 break;
1569
1570 default:
1571 break;
1572 }
1573
1574 // pname is valid, but there are no parameters to return
1575 if (numParams == 0)
1576 {
1577 return false;
1578 }
1579
1580 return true;
1581}
1582
Jamie Madillc29968b2016-01-20 11:17:23 -05001583bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1584 GLenum target,
1585 GLint level,
1586 GLenum internalformat,
1587 bool isSubImage,
1588 GLint xoffset,
1589 GLint yoffset,
1590 GLint zoffset,
1591 GLint x,
1592 GLint y,
1593 GLsizei width,
1594 GLsizei height,
1595 GLint border,
1596 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001597{
Jamie Madill560a8d82014-05-21 13:06:20 -04001598 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1599 {
Jamie Madill437fa652016-05-03 15:13:24 -04001600 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001601 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001602 }
1603
1604 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1605 {
Jamie Madill437fa652016-05-03 15:13:24 -04001606 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001607 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001608 }
1609
1610 if (border != 0)
1611 {
Jamie Madill437fa652016-05-03 15:13:24 -04001612 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001613 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001614 }
1615
1616 if (!ValidMipLevel(context, target, level))
1617 {
Jamie Madill437fa652016-05-03 15:13:24 -04001618 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001619 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001620 }
1621
Jamie Madillc29968b2016-01-20 11:17:23 -05001622 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001623 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001624 {
Jamie Madill437fa652016-05-03 15:13:24 -04001625 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001626 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001627 }
1628
Jamie Madillc29968b2016-01-20 11:17:23 -05001629 const auto &state = context->getState();
1630 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001631 {
Jamie Madill437fa652016-05-03 15:13:24 -04001632 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001633 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001634 }
1635
Geoff Langaae65a42014-05-26 12:43:44 -04001636 const gl::Caps &caps = context->getCaps();
1637
Geoff Langaae65a42014-05-26 12:43:44 -04001638 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001639 switch (target)
1640 {
1641 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001642 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001643 break;
1644
1645 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1646 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1647 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1648 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1649 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1650 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001651 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001652 break;
1653
1654 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001655 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001656 break;
1657
1658 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001659 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001660 break;
1661
1662 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001663 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001664 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001665 }
1666
Jamie Madillc29968b2016-01-20 11:17:23 -05001667 gl::Texture *texture =
1668 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001669 if (!texture)
1670 {
Jamie Madill437fa652016-05-03 15:13:24 -04001671 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001672 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001673 }
1674
Geoff Lang69cce582015-09-17 13:20:36 -04001675 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001676 {
Jamie Madill437fa652016-05-03 15:13:24 -04001677 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001678 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001679 }
1680
Geoff Lang5d601382014-07-22 15:14:06 -04001681 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1682
1683 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001684 {
Jamie Madill437fa652016-05-03 15:13:24 -04001685 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001686 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001687 }
1688
Geoff Langa9be0dc2014-12-17 12:34:40 -05001689 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001690 {
Jamie Madill437fa652016-05-03 15:13:24 -04001691 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001692 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001693 }
1694
1695 if (isSubImage)
1696 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001697 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1698 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1699 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001700 {
Jamie Madill437fa652016-05-03 15:13:24 -04001701 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001702 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001703 }
1704 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001705 else
1706 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001707 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001708 {
Jamie Madill437fa652016-05-03 15:13:24 -04001709 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001710 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001711 }
1712
Geoff Lang5d601382014-07-22 15:14:06 -04001713 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001714 {
Jamie Madill437fa652016-05-03 15:13:24 -04001715 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001716 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001717 }
1718
1719 int maxLevelDimension = (maxDimension >> level);
1720 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1721 {
Jamie Madill437fa652016-05-03 15:13:24 -04001722 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001723 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001724 }
1725 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001726
Geoff Langa9be0dc2014-12-17 12:34:40 -05001727 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001728 return true;
1729}
1730
Jamie Madillf25855c2015-11-03 11:06:18 -05001731static bool ValidateDrawBase(ValidationContext *context,
1732 GLenum mode,
1733 GLsizei count,
1734 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001735{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001736 switch (mode)
1737 {
1738 case GL_POINTS:
1739 case GL_LINES:
1740 case GL_LINE_LOOP:
1741 case GL_LINE_STRIP:
1742 case GL_TRIANGLES:
1743 case GL_TRIANGLE_STRIP:
1744 case GL_TRIANGLE_FAN:
1745 break;
1746 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001747 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001748 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001749 }
1750
Jamie Madill250d33f2014-06-06 17:09:03 -04001751 if (count < 0)
1752 {
Jamie Madill437fa652016-05-03 15:13:24 -04001753 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001754 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001755 }
1756
Geoff Langb1196682014-07-23 13:47:29 -04001757 const State &state = context->getState();
1758
Jamie Madill250d33f2014-06-06 17:09:03 -04001759 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001760 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001761 {
Jamie Madill437fa652016-05-03 15:13:24 -04001762 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001763 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001764 }
1765
Geoff Lang3a86ad32015-09-01 11:47:05 -04001766 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001767 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001768 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1769 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1770 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1771 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1772 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1773 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1774 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001775 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001776 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1777 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001778 {
1779 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1780 // Section 6.10 of the WebGL 1.0 spec
1781 ERR(
1782 "This ANGLE implementation does not support separate front/back stencil "
1783 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001784 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001785 return false;
1786 }
Jamie Madillac528012014-06-20 13:21:23 -04001787 }
1788
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001789 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001790 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001791 {
Jamie Madill437fa652016-05-03 15:13:24 -04001792 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001793 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001794 }
1795
Geoff Lang7dd2e102014-11-10 15:19:26 -05001796 gl::Program *program = state.getProgram();
1797 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001798 {
Jamie Madill437fa652016-05-03 15:13:24 -04001799 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001800 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001801 }
1802
Geoff Lang7dd2e102014-11-10 15:19:26 -05001803 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001804 {
Jamie Madill437fa652016-05-03 15:13:24 -04001805 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001806 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001807 }
1808
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001809 // Uniform buffer validation
1810 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1811 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001812 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001813 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001814 const OffsetBindingPointer<Buffer> &uniformBuffer =
1815 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001816
Geoff Lang5d124a62015-09-15 13:03:27 -04001817 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001818 {
1819 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001820 context->handleError(
1821 Error(GL_INVALID_OPERATION,
1822 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001823 return false;
1824 }
1825
Geoff Lang5d124a62015-09-15 13:03:27 -04001826 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001827 if (uniformBufferSize == 0)
1828 {
1829 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001830 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001831 }
1832
Jamie Madill62d31cb2015-09-11 13:25:51 -04001833 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001834 {
1835 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001836 context->handleError(
1837 Error(GL_INVALID_OPERATION,
1838 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001839 return false;
1840 }
1841 }
1842
Jamie Madill250d33f2014-06-06 17:09:03 -04001843 // No-op if zero count
1844 return (count > 0);
1845}
1846
Geoff Langb1196682014-07-23 13:47:29 -04001847bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001848{
Jamie Madillfd716582014-06-06 17:09:04 -04001849 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001850 {
Jamie Madill437fa652016-05-03 15:13:24 -04001851 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001852 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001853 }
1854
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001855 const State &state = context->getState();
1856 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001857 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1858 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001859 {
1860 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1861 // that does not match the current transform feedback object's draw mode (if transform feedback
1862 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001863 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001864 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001865 }
1866
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001867 if (!ValidateDrawBase(context, mode, count, primcount))
1868 {
1869 return false;
1870 }
1871
1872 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001873 {
1874 return false;
1875 }
1876
1877 return true;
1878}
1879
Geoff Langb1196682014-07-23 13:47:29 -04001880bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001881{
1882 if (primcount < 0)
1883 {
Jamie Madill437fa652016-05-03 15:13:24 -04001884 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001885 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001886 }
1887
Jamie Madill2b976812014-08-25 15:47:49 -04001888 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001889 {
1890 return false;
1891 }
1892
1893 // No-op if zero primitive count
1894 return (primcount > 0);
1895}
1896
Geoff Lang87a93302014-09-16 13:29:43 -04001897static bool ValidateDrawInstancedANGLE(Context *context)
1898{
1899 // Verify there is at least one active attribute with a divisor of zero
1900 const gl::State& state = context->getState();
1901
Geoff Lang7dd2e102014-11-10 15:19:26 -05001902 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001903
1904 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001905 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001906 {
1907 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001908 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001909 {
1910 return true;
1911 }
1912 }
1913
Jamie Madill437fa652016-05-03 15:13:24 -04001914 context->handleError(Error(GL_INVALID_OPERATION,
1915 "ANGLE_instanced_arrays requires that at least one active attribute"
1916 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001917 return false;
1918}
1919
1920bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1921{
1922 if (!ValidateDrawInstancedANGLE(context))
1923 {
1924 return false;
1925 }
1926
1927 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1928}
1929
Jamie Madillf25855c2015-11-03 11:06:18 -05001930bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001931 GLenum mode,
1932 GLsizei count,
1933 GLenum type,
1934 const GLvoid *indices,
1935 GLsizei primcount,
1936 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001937{
Jamie Madill250d33f2014-06-06 17:09:03 -04001938 switch (type)
1939 {
1940 case GL_UNSIGNED_BYTE:
1941 case GL_UNSIGNED_SHORT:
1942 break;
1943 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001944 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001945 {
Jamie Madill437fa652016-05-03 15:13:24 -04001946 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001947 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001948 }
1949 break;
1950 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001951 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001952 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001953 }
1954
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001955 const State &state = context->getState();
1956
1957 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001958 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001959 {
1960 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1961 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001962 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001963 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001964 }
1965
1966 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001967 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001968 {
Jamie Madill437fa652016-05-03 15:13:24 -04001969 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001970 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001971 }
1972
Jamie Madill2b976812014-08-25 15:47:49 -04001973 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001974 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001975 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001976 {
Jamie Madill437fa652016-05-03 15:13:24 -04001977 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001978 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001979 }
1980
Jamie Madillae3000b2014-08-25 15:47:51 -04001981 if (elementArrayBuffer)
1982 {
1983 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1984
1985 GLint64 offset = reinterpret_cast<GLint64>(indices);
1986 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1987
1988 // check for integer overflows
1989 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1990 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1991 {
Jamie Madill437fa652016-05-03 15:13:24 -04001992 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04001993 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001994 }
1995
1996 // Check for reading past the end of the bound buffer object
1997 if (byteCount > elementArrayBuffer->getSize())
1998 {
Jamie Madill437fa652016-05-03 15:13:24 -04001999 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002000 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002001 }
2002 }
2003 else if (!indices)
2004 {
2005 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002006 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002007 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002008 }
2009
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002010 if (!ValidateDrawBase(context, mode, count, primcount))
2011 {
2012 return false;
2013 }
2014
Jamie Madill2b976812014-08-25 15:47:49 -04002015 // Use max index to validate if our vertex buffers are large enough for the pull.
2016 // TODO: offer fast path, with disabled index validation.
2017 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2018 if (elementArrayBuffer)
2019 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002020 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002021 Error error =
2022 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2023 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002024 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002025 {
Jamie Madill437fa652016-05-03 15:13:24 -04002026 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002027 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002028 }
2029 }
2030 else
2031 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002032 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002033 }
2034
Jamie Madille79b1e12015-11-04 16:36:37 -05002035 // If we use an index greater than our maximum supported index range, return an error.
2036 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2037 // return an error if possible here.
2038 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2039 {
Jamie Madill437fa652016-05-03 15:13:24 -04002040 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002041 return false;
2042 }
2043
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002044 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002045 {
2046 return false;
2047 }
2048
Geoff Lang3edfe032015-09-04 16:38:24 -04002049 // No op if there are no real indices in the index data (all are primitive restart).
2050 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002051}
2052
Geoff Langb1196682014-07-23 13:47:29 -04002053bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002054 GLenum mode,
2055 GLsizei count,
2056 GLenum type,
2057 const GLvoid *indices,
2058 GLsizei primcount,
2059 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002060{
2061 if (primcount < 0)
2062 {
Jamie Madill437fa652016-05-03 15:13:24 -04002063 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002064 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002065 }
2066
Jamie Madill2b976812014-08-25 15:47:49 -04002067 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002068 {
2069 return false;
2070 }
2071
2072 // No-op zero primitive count
2073 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002074}
2075
Geoff Lang3edfe032015-09-04 16:38:24 -04002076bool ValidateDrawElementsInstancedANGLE(Context *context,
2077 GLenum mode,
2078 GLsizei count,
2079 GLenum type,
2080 const GLvoid *indices,
2081 GLsizei primcount,
2082 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002083{
2084 if (!ValidateDrawInstancedANGLE(context))
2085 {
2086 return false;
2087 }
2088
2089 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2090}
2091
Geoff Langb1196682014-07-23 13:47:29 -04002092bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002093 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002094{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002095 if (!ValidFramebufferTarget(target))
2096 {
Jamie Madill437fa652016-05-03 15:13:24 -04002097 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002098 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002099 }
2100
2101 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002102 {
2103 return false;
2104 }
2105
Jamie Madill55ec3b12014-07-03 10:38:57 -04002106 if (texture != 0)
2107 {
2108 gl::Texture *tex = context->getTexture(texture);
2109
2110 if (tex == NULL)
2111 {
Jamie Madill437fa652016-05-03 15:13:24 -04002112 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002113 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002114 }
2115
2116 if (level < 0)
2117 {
Jamie Madill437fa652016-05-03 15:13:24 -04002118 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002119 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002120 }
2121 }
2122
Shannon Woods53a94a82014-06-24 15:20:36 -04002123 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002124 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002125
Jamie Madill84115c92015-04-23 15:00:07 -04002126 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002127 {
Jamie Madill437fa652016-05-03 15:13:24 -04002128 context->handleError(
2129 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002130 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002131 }
2132
2133 return true;
2134}
2135
Geoff Langb1196682014-07-23 13:47:29 -04002136bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002137 GLenum textarget, GLuint texture, GLint level)
2138{
Geoff Lang95663912015-04-02 15:54:45 -04002139 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2140 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002141 {
Jamie Madill437fa652016-05-03 15:13:24 -04002142 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002143 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002144 }
2145
2146 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002147 {
2148 return false;
2149 }
2150
Jamie Madill55ec3b12014-07-03 10:38:57 -04002151 if (texture != 0)
2152 {
2153 gl::Texture *tex = context->getTexture(texture);
2154 ASSERT(tex);
2155
Jamie Madill2a6564e2014-07-11 09:53:19 -04002156 const gl::Caps &caps = context->getCaps();
2157
Jamie Madill55ec3b12014-07-03 10:38:57 -04002158 switch (textarget)
2159 {
2160 case GL_TEXTURE_2D:
2161 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002162 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002163 {
Jamie Madill437fa652016-05-03 15:13:24 -04002164 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002165 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002166 }
2167 if (tex->getTarget() != GL_TEXTURE_2D)
2168 {
Jamie Madill437fa652016-05-03 15:13:24 -04002169 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002170 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002171 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002172 }
2173 break;
2174
2175 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2176 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2177 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2178 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2179 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2180 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2181 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002182 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002183 {
Jamie Madill437fa652016-05-03 15:13:24 -04002184 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002185 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002186 }
2187 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2188 {
Jamie Madill437fa652016-05-03 15:13:24 -04002189 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002190 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002191 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002192 }
2193 break;
2194
2195 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002196 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002197 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002198 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002199
2200 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2201 if (internalFormatInfo.compressed)
2202 {
Jamie Madill437fa652016-05-03 15:13:24 -04002203 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002204 return false;
2205 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002206 }
2207
Jamie Madill570f7c82014-07-03 10:38:54 -04002208 return true;
2209}
2210
Geoff Langb1196682014-07-23 13:47:29 -04002211bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002212{
2213 if (program == 0)
2214 {
Jamie Madill437fa652016-05-03 15:13:24 -04002215 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002216 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002217 }
2218
Dian Xiang769769a2015-09-09 15:20:08 -07002219 gl::Program *programObject = GetValidProgram(context, program);
2220 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002221 {
2222 return false;
2223 }
2224
Jamie Madill0063c512014-08-25 15:47:53 -04002225 if (!programObject || !programObject->isLinked())
2226 {
Jamie Madill437fa652016-05-03 15:13:24 -04002227 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002228 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002229 }
2230
Geoff Lang7dd2e102014-11-10 15:19:26 -05002231 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002232 {
Jamie Madill437fa652016-05-03 15:13:24 -04002233 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002234 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002235 }
2236
Jamie Madill0063c512014-08-25 15:47:53 -04002237 return true;
2238}
2239
Geoff Langb1196682014-07-23 13:47:29 -04002240bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002241{
2242 return ValidateGetUniformBase(context, program, location);
2243}
2244
Geoff Langb1196682014-07-23 13:47:29 -04002245bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002246{
Jamie Madill78f41802014-08-25 15:47:55 -04002247 return ValidateGetUniformBase(context, program, location);
2248}
2249
Geoff Langb1196682014-07-23 13:47:29 -04002250static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002251{
2252 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002253 {
Jamie Madill78f41802014-08-25 15:47:55 -04002254 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002255 }
2256
Jamie Madilla502c742014-08-28 17:19:13 -04002257 gl::Program *programObject = context->getProgram(program);
2258 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002259
Jamie Madill78f41802014-08-25 15:47:55 -04002260 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002261 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2262 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002263 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002264 {
Jamie Madill437fa652016-05-03 15:13:24 -04002265 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002266 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002267 }
2268
2269 return true;
2270}
2271
Geoff Langb1196682014-07-23 13:47:29 -04002272bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002273{
Jamie Madill78f41802014-08-25 15:47:55 -04002274 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002275}
2276
Geoff Langb1196682014-07-23 13:47:29 -04002277bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002278{
Jamie Madill78f41802014-08-25 15:47:55 -04002279 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002280}
2281
Austin Kinross08332632015-05-05 13:35:47 -07002282bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2283 const GLenum *attachments, bool defaultFramebuffer)
2284{
2285 if (numAttachments < 0)
2286 {
Jamie Madill437fa652016-05-03 15:13:24 -04002287 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002288 return false;
2289 }
2290
2291 for (GLsizei i = 0; i < numAttachments; ++i)
2292 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002293 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002294 {
2295 if (defaultFramebuffer)
2296 {
Jamie Madill437fa652016-05-03 15:13:24 -04002297 context->handleError(Error(
2298 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002299 return false;
2300 }
2301
2302 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2303 {
Jamie Madill437fa652016-05-03 15:13:24 -04002304 context->handleError(Error(GL_INVALID_OPERATION,
2305 "Requested color attachment is greater than the maximum "
2306 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002307 return false;
2308 }
2309 }
2310 else
2311 {
2312 switch (attachments[i])
2313 {
2314 case GL_DEPTH_ATTACHMENT:
2315 case GL_STENCIL_ATTACHMENT:
2316 case GL_DEPTH_STENCIL_ATTACHMENT:
2317 if (defaultFramebuffer)
2318 {
Jamie Madill437fa652016-05-03 15:13:24 -04002319 context->handleError(
2320 Error(GL_INVALID_ENUM,
2321 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002322 return false;
2323 }
2324 break;
2325 case GL_COLOR:
2326 case GL_DEPTH:
2327 case GL_STENCIL:
2328 if (!defaultFramebuffer)
2329 {
Jamie Madill437fa652016-05-03 15:13:24 -04002330 context->handleError(
2331 Error(GL_INVALID_ENUM,
2332 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002333 return false;
2334 }
2335 break;
2336 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002337 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002338 return false;
2339 }
2340 }
2341 }
2342
2343 return true;
2344}
2345
Austin Kinross6ee1e782015-05-29 17:05:37 -07002346bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2347{
2348 // Note that debug marker calls must not set error state
2349
2350 if (length < 0)
2351 {
2352 return false;
2353 }
2354
2355 if (marker == nullptr)
2356 {
2357 return false;
2358 }
2359
2360 return true;
2361}
2362
2363bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2364{
2365 // Note that debug marker calls must not set error state
2366
2367 if (length < 0)
2368 {
2369 return false;
2370 }
2371
2372 if (length > 0 && marker == nullptr)
2373 {
2374 return false;
2375 }
2376
2377 return true;
2378}
2379
Geoff Langdcab33b2015-07-21 13:03:16 -04002380bool ValidateEGLImageTargetTexture2DOES(Context *context,
2381 egl::Display *display,
2382 GLenum target,
2383 egl::Image *image)
2384{
Geoff Langa8406172015-07-21 16:53:39 -04002385 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2386 {
Jamie Madill437fa652016-05-03 15:13:24 -04002387 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002388 return false;
2389 }
2390
2391 switch (target)
2392 {
2393 case GL_TEXTURE_2D:
2394 break;
2395
2396 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002397 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002398 return false;
2399 }
2400
2401 if (!display->isValidImage(image))
2402 {
Jamie Madill437fa652016-05-03 15:13:24 -04002403 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002404 return false;
2405 }
2406
2407 if (image->getSamples() > 0)
2408 {
Jamie Madill437fa652016-05-03 15:13:24 -04002409 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002410 "cannot create a 2D texture from a multisampled EGL image."));
2411 return false;
2412 }
2413
2414 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2415 if (!textureCaps.texturable)
2416 {
Jamie Madill437fa652016-05-03 15:13:24 -04002417 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002418 "EGL image internal format is not supported as a texture."));
2419 return false;
2420 }
2421
Geoff Langdcab33b2015-07-21 13:03:16 -04002422 return true;
2423}
2424
2425bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2426 egl::Display *display,
2427 GLenum target,
2428 egl::Image *image)
2429{
Geoff Langa8406172015-07-21 16:53:39 -04002430 if (!context->getExtensions().eglImage)
2431 {
Jamie Madill437fa652016-05-03 15:13:24 -04002432 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002433 return false;
2434 }
2435
2436 switch (target)
2437 {
2438 case GL_RENDERBUFFER:
2439 break;
2440
2441 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002442 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002443 return false;
2444 }
2445
2446 if (!display->isValidImage(image))
2447 {
Jamie Madill437fa652016-05-03 15:13:24 -04002448 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002449 return false;
2450 }
2451
2452 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2453 if (!textureCaps.renderable)
2454 {
Jamie Madill437fa652016-05-03 15:13:24 -04002455 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002456 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2457 return false;
2458 }
2459
Geoff Langdcab33b2015-07-21 13:03:16 -04002460 return true;
2461}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002462
2463bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2464{
Geoff Lang36167ab2015-12-07 10:27:14 -05002465 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002466 {
2467 // The default VAO should always exist
2468 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002469 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002470 return false;
2471 }
2472
2473 return true;
2474}
2475
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002476bool ValidateLinkProgram(Context *context, GLuint program)
2477{
2478 if (context->hasActiveTransformFeedback(program))
2479 {
2480 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002481 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002482 "Cannot link program while program is associated with an active "
2483 "transform feedback object."));
2484 return false;
2485 }
2486 return true;
2487}
2488
Geoff Langc5629752015-12-07 16:29:04 -05002489bool ValidateProgramBinaryBase(Context *context,
2490 GLuint program,
2491 GLenum binaryFormat,
2492 const void *binary,
2493 GLint length)
2494{
2495 Program *programObject = GetValidProgram(context, program);
2496 if (programObject == nullptr)
2497 {
2498 return false;
2499 }
2500
2501 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2502 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2503 programBinaryFormats.end())
2504 {
Jamie Madill437fa652016-05-03 15:13:24 -04002505 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002506 return false;
2507 }
2508
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002509 if (context->hasActiveTransformFeedback(program))
2510 {
2511 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002512 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002513 "Cannot change program binary while program is associated with "
2514 "an active transform feedback object."));
2515 return false;
2516 }
2517
Geoff Langc5629752015-12-07 16:29:04 -05002518 return true;
2519}
2520
2521bool ValidateGetProgramBinaryBase(Context *context,
2522 GLuint program,
2523 GLsizei bufSize,
2524 GLsizei *length,
2525 GLenum *binaryFormat,
2526 void *binary)
2527{
2528 Program *programObject = GetValidProgram(context, program);
2529 if (programObject == nullptr)
2530 {
2531 return false;
2532 }
2533
2534 if (!programObject->isLinked())
2535 {
Jamie Madill437fa652016-05-03 15:13:24 -04002536 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002537 return false;
2538 }
2539
2540 return true;
2541}
Jamie Madillc29968b2016-01-20 11:17:23 -05002542
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002543bool ValidateUseProgram(Context *context, GLuint program)
2544{
2545 if (program != 0)
2546 {
2547 Program *programObject = context->getProgram(program);
2548 if (!programObject)
2549 {
2550 // ES 3.1.0 section 7.3 page 72
2551 if (context->getShader(program))
2552 {
Jamie Madill437fa652016-05-03 15:13:24 -04002553 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002554 Error(GL_INVALID_OPERATION,
2555 "Attempted to use a single shader instead of a shader program."));
2556 return false;
2557 }
2558 else
2559 {
Jamie Madill437fa652016-05-03 15:13:24 -04002560 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002561 return false;
2562 }
2563 }
2564 if (!programObject->isLinked())
2565 {
Jamie Madill437fa652016-05-03 15:13:24 -04002566 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002567 return false;
2568 }
2569 }
2570 if (context->getState().isTransformFeedbackActiveUnpaused())
2571 {
2572 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002573 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002574 Error(GL_INVALID_OPERATION,
2575 "Cannot change active program while transform feedback is unpaused."));
2576 return false;
2577 }
2578
2579 return true;
2580}
2581
Jamie Madillc29968b2016-01-20 11:17:23 -05002582bool ValidateCopyTexImage2D(ValidationContext *context,
2583 GLenum target,
2584 GLint level,
2585 GLenum internalformat,
2586 GLint x,
2587 GLint y,
2588 GLsizei width,
2589 GLsizei height,
2590 GLint border)
2591{
2592 if (context->getClientVersion() < 3)
2593 {
2594 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2595 0, x, y, width, height, border);
2596 }
2597
2598 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002599 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2600 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002601}
Jamie Madillc29968b2016-01-20 11:17:23 -05002602
2603bool ValidateFramebufferRenderbuffer(Context *context,
2604 GLenum target,
2605 GLenum attachment,
2606 GLenum renderbuffertarget,
2607 GLuint renderbuffer)
2608{
2609 if (!ValidFramebufferTarget(target) ||
2610 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2611 {
Jamie Madill437fa652016-05-03 15:13:24 -04002612 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002613 return false;
2614 }
2615
2616 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2617 renderbuffertarget, renderbuffer);
2618}
2619
2620bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2621{
2622 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2623 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2624 {
Jamie Madill437fa652016-05-03 15:13:24 -04002625 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002626 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2627 return false;
2628 }
2629
2630 ASSERT(context->getState().getDrawFramebuffer());
2631 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2632 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2633
2634 // This should come first before the check for the default frame buffer
2635 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2636 // rather than INVALID_OPERATION
2637 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2638 {
2639 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2640
2641 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002642 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2643 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002644 {
2645 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002646 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2647 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2648 // 3.1 is still a bit ambiguous about the error, but future specs are
2649 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002650 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002651 return false;
2652 }
2653 else if (bufs[colorAttachment] >= maxColorAttachment)
2654 {
Jamie Madill437fa652016-05-03 15:13:24 -04002655 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002656 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002657 return false;
2658 }
2659 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2660 frameBufferId != 0)
2661 {
2662 // INVALID_OPERATION-GL is bound to buffer and ith argument
2663 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002664 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002665 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2666 return false;
2667 }
2668 }
2669
2670 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2671 // and n is not 1 or bufs is bound to value other than BACK and NONE
2672 if (frameBufferId == 0)
2673 {
2674 if (n != 1)
2675 {
Jamie Madill437fa652016-05-03 15:13:24 -04002676 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002677 "n must be 1 when GL is bound to the default framebuffer"));
2678 return false;
2679 }
2680
2681 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2682 {
Jamie Madill437fa652016-05-03 15:13:24 -04002683 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002684 GL_INVALID_OPERATION,
2685 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2686 return false;
2687 }
2688 }
2689
2690 return true;
2691}
2692
2693bool ValidateCopyTexSubImage2D(Context *context,
2694 GLenum target,
2695 GLint level,
2696 GLint xoffset,
2697 GLint yoffset,
2698 GLint x,
2699 GLint y,
2700 GLsizei width,
2701 GLsizei height)
2702{
2703 if (context->getClientVersion() < 3)
2704 {
2705 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2706 yoffset, x, y, width, height, 0);
2707 }
2708
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002709 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2710 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002711}
2712
Olli Etuaho4f667482016-03-30 15:56:35 +03002713bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2714{
2715 if (!ValidBufferTarget(context, target))
2716 {
Jamie Madill437fa652016-05-03 15:13:24 -04002717 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002718 return false;
2719 }
2720
2721 if (pname != GL_BUFFER_MAP_POINTER)
2722 {
Jamie Madill437fa652016-05-03 15:13:24 -04002723 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002724 return false;
2725 }
2726
2727 Buffer *buffer = context->getState().getTargetBuffer(target);
2728
2729 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2730 // target bound to zero generate an INVALID_OPERATION error."
2731 // GLES 3.1 section 6.6 explicitly specifies this error.
2732 if (!buffer)
2733 {
Jamie Madill437fa652016-05-03 15:13:24 -04002734 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002735 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2736 return false;
2737 }
2738
2739 return true;
2740}
2741
2742bool ValidateUnmapBufferBase(Context *context, GLenum target)
2743{
2744 if (!ValidBufferTarget(context, target))
2745 {
Jamie Madill437fa652016-05-03 15:13:24 -04002746 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002747 return false;
2748 }
2749
2750 Buffer *buffer = context->getState().getTargetBuffer(target);
2751
2752 if (buffer == nullptr || !buffer->isMapped())
2753 {
Jamie Madill437fa652016-05-03 15:13:24 -04002754 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002755 return false;
2756 }
2757
2758 return true;
2759}
2760
2761bool ValidateMapBufferRangeBase(Context *context,
2762 GLenum target,
2763 GLintptr offset,
2764 GLsizeiptr length,
2765 GLbitfield access)
2766{
2767 if (!ValidBufferTarget(context, target))
2768 {
Jamie Madill437fa652016-05-03 15:13:24 -04002769 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002770 return false;
2771 }
2772
2773 if (offset < 0 || length < 0)
2774 {
Jamie Madill437fa652016-05-03 15:13:24 -04002775 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002776 return false;
2777 }
2778
2779 Buffer *buffer = context->getState().getTargetBuffer(target);
2780
2781 if (!buffer)
2782 {
Jamie Madill437fa652016-05-03 15:13:24 -04002783 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002784 return false;
2785 }
2786
2787 // Check for buffer overflow
2788 size_t offsetSize = static_cast<size_t>(offset);
2789 size_t lengthSize = static_cast<size_t>(length);
2790
2791 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2792 offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
2793 {
Jamie Madill437fa652016-05-03 15:13:24 -04002794 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002795 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2796 return false;
2797 }
2798
2799 // Check for invalid bits in the mask
2800 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2801 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2802 GL_MAP_UNSYNCHRONIZED_BIT;
2803
2804 if (access & ~(allAccessBits))
2805 {
Jamie Madill437fa652016-05-03 15:13:24 -04002806 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002807 return false;
2808 }
2809
2810 if (length == 0)
2811 {
Jamie Madill437fa652016-05-03 15:13:24 -04002812 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002813 return false;
2814 }
2815
2816 if (buffer->isMapped())
2817 {
Jamie Madill437fa652016-05-03 15:13:24 -04002818 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002819 return false;
2820 }
2821
2822 // Check for invalid bit combinations
2823 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2824 {
Jamie Madill437fa652016-05-03 15:13:24 -04002825 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002826 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2827 return false;
2828 }
2829
2830 GLbitfield writeOnlyBits =
2831 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2832
2833 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2834 {
Jamie Madill437fa652016-05-03 15:13:24 -04002835 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002836 "Invalid access bits when mapping buffer for reading: 0x%X.",
2837 access));
2838 return false;
2839 }
2840
2841 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2842 {
Jamie Madill437fa652016-05-03 15:13:24 -04002843 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002844 GL_INVALID_OPERATION,
2845 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2846 return false;
2847 }
2848 return true;
2849}
2850
2851bool ValidateFlushMappedBufferRangeBase(Context *context,
2852 GLenum target,
2853 GLintptr offset,
2854 GLsizeiptr length)
2855{
2856 if (offset < 0 || length < 0)
2857 {
Jamie Madill437fa652016-05-03 15:13:24 -04002858 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002859 return false;
2860 }
2861
2862 if (!ValidBufferTarget(context, target))
2863 {
Jamie Madill437fa652016-05-03 15:13:24 -04002864 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002865 return false;
2866 }
2867
2868 Buffer *buffer = context->getState().getTargetBuffer(target);
2869
2870 if (buffer == nullptr)
2871 {
Jamie Madill437fa652016-05-03 15:13:24 -04002872 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002873 return false;
2874 }
2875
2876 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2877 {
Jamie Madill437fa652016-05-03 15:13:24 -04002878 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002879 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2880 return false;
2881 }
2882
2883 // Check for buffer overflow
2884 size_t offsetSize = static_cast<size_t>(offset);
2885 size_t lengthSize = static_cast<size_t>(length);
2886
2887 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2888 offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
2889 {
Jamie Madill437fa652016-05-03 15:13:24 -04002890 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002891 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2892 return false;
2893 }
2894
2895 return true;
2896}
2897
Olli Etuaho41997e72016-03-10 13:38:39 +02002898bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2899{
2900 return ValidateGenOrDelete(context, n);
2901}
2902
2903bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2904{
2905 return ValidateGenOrDelete(context, n);
2906}
2907
2908bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2909{
2910 return ValidateGenOrDelete(context, n);
2911}
2912
2913bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2914{
2915 return ValidateGenOrDelete(context, n);
2916}
2917
2918bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2919{
2920 return ValidateGenOrDelete(context, n);
2921}
2922
2923bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2924{
2925 return ValidateGenOrDelete(context, n);
2926}
2927
2928bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2929{
2930 return ValidateGenOrDelete(context, n);
2931}
2932
2933bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2934{
2935 return ValidateGenOrDelete(context, n);
2936}
2937
2938bool ValidateGenOrDelete(Context *context, GLint n)
2939{
2940 if (n < 0)
2941 {
Jamie Madill437fa652016-05-03 15:13:24 -04002942 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02002943 return false;
2944 }
2945 return true;
2946}
2947
Jamie Madillc29968b2016-01-20 11:17:23 -05002948} // namespace gl