blob: 6ea31bf89fd62a4a2e521c4400b477d8fc2d5af4 [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 Madillbc4c4bc2016-03-23 21:04:43 -040078 context->recordError(
79 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
89 context->recordError(Error(
90 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 {
418 context->recordError(
419 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
420 }
421 else
422 {
423 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
424 }
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 {
440 context->recordError(
441 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
442 }
443 else
444 {
445 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
446 }
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 {
Geoff Langb1196682014-07-23 13:47:29 -0400460 context->recordError(Error(GL_INVALID_VALUE));
461 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 {
Geoff Langb1196682014-07-23 13:47:29 -0400475 context->recordError(Error(GL_INVALID_ENUM));
476 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400477 }
478 break;
479
480 default:
Geoff Langb1196682014-07-23 13:47:29 -0400481 context->recordError(Error(GL_INVALID_ENUM));
482 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:
Geoff Langb1196682014-07-23 13:47:29 -0400497 context->recordError(Error(GL_INVALID_ENUM));
498 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400499 }
500
501 if (width < 0 || height < 0 || samples < 0)
502 {
Geoff Langb1196682014-07-23 13:47:29 -0400503 context->recordError(Error(GL_INVALID_VALUE));
504 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 {
Geoff Langb1196682014-07-23 13:47:29 -0400510 context->recordError(Error(GL_INVALID_ENUM));
511 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 {
Geoff Langb1196682014-07-23 13:47:29 -0400520 context->recordError(Error(GL_INVALID_ENUM));
521 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 {
Geoff Langb1196682014-07-23 13:47:29 -0400526 context->recordError(Error(GL_INVALID_VALUE));
527 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 {
Geoff Langb1196682014-07-23 13:47:29 -0400533 context->recordError(Error(GL_INVALID_OPERATION));
534 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 {
550 context->recordError(Error(GL_INVALID_VALUE));
551 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 {
563 context->recordError(Error(GL_OUT_OF_MEMORY));
564 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 {
Geoff Langb1196682014-07-23 13:47:29 -0400576 context->recordError(Error(GL_INVALID_ENUM));
577 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 Madill84115c92015-04-23 15:00:07 -0400585 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400586 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500587 }
588
Jamie Madillb4472272014-07-03 10:38:55 -0400589 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500590 {
Jamie Madillb4472272014-07-03 10:38:55 -0400591 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500592 }
593
Jamie Madillab9d82c2014-01-21 16:38:14 -0500594 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
595 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
596 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
597 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
598 if (renderbuffer != 0)
599 {
600 if (!context->getRenderbuffer(renderbuffer))
601 {
Geoff Langb1196682014-07-23 13:47:29 -0400602 context->recordError(Error(GL_INVALID_OPERATION));
603 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500604 }
605 }
606
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500607 return true;
608}
609
Jamie Madillc29968b2016-01-20 11:17:23 -0500610bool ValidateBlitFramebufferParameters(gl::Context *context,
611 GLint srcX0,
612 GLint srcY0,
613 GLint srcX1,
614 GLint srcY1,
615 GLint dstX0,
616 GLint dstY0,
617 GLint dstX1,
618 GLint dstY1,
619 GLbitfield mask,
620 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400621{
622 switch (filter)
623 {
624 case GL_NEAREST:
625 break;
626 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400627 break;
628 default:
Geoff Langb1196682014-07-23 13:47:29 -0400629 context->recordError(Error(GL_INVALID_ENUM));
630 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400631 }
632
633 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
634 {
Geoff Langb1196682014-07-23 13:47:29 -0400635 context->recordError(Error(GL_INVALID_VALUE));
636 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 }
638
639 if (mask == 0)
640 {
641 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
642 // buffers are copied.
643 return false;
644 }
645
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400646 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
647 // color buffer, leaving only nearest being unfiltered from above
648 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
649 {
Geoff Langb1196682014-07-23 13:47:29 -0400650 context->recordError(Error(GL_INVALID_OPERATION));
651 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652 }
653
Shannon Woods53a94a82014-06-24 15:20:36 -0400654 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 {
Geoff Langb1196682014-07-23 13:47:29 -0400656 context->recordError(Error(GL_INVALID_OPERATION));
657 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400658 }
659
Jamie Madille3ef7152015-04-28 16:55:17 +0000660 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
661 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500662
663 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400664 {
Geoff Langb1196682014-07-23 13:47:29 -0400665 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
666 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667 }
668
Geoff Lang748f74e2014-12-01 11:25:34 -0500669 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500670 {
671 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
672 return false;
673 }
674
Geoff Lang748f74e2014-12-01 11:25:34 -0500675 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500676 {
677 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
678 return false;
679 }
680
681 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400682 {
Geoff Langb1196682014-07-23 13:47:29 -0400683 context->recordError(Error(GL_INVALID_OPERATION));
684 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400685 }
686
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400687 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
688
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400689 if (mask & GL_COLOR_BUFFER_BIT)
690 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400691 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
692 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500693 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694
695 if (readColorBuffer && drawColorBuffer)
696 {
Geoff Langd8a22582014-12-17 15:28:23 -0500697 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400698 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400699
Geoff Langa15472a2015-08-11 11:48:03 -0400700 for (size_t drawbufferIdx = 0;
701 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400702 {
Geoff Langa15472a2015-08-11 11:48:03 -0400703 const FramebufferAttachment *attachment =
704 drawFramebuffer->getDrawBuffer(drawbufferIdx);
705 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400706 {
Geoff Langa15472a2015-08-11 11:48:03 -0400707 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400708 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709
Geoff Langb2f3d052013-08-13 12:49:27 -0400710 // The GL ES 3.0.2 spec (pg 193) states that:
711 // 1) If the read buffer is fixed point format, the draw buffer must be as well
712 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
713 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500714 // Changes with EXT_color_buffer_float:
715 // Case 1) is changed to fixed point OR floating point
716 GLenum readComponentType = readFormatInfo.componentType;
717 GLenum drawComponentType = drawFormatInfo.componentType;
718 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
719 readComponentType == GL_SIGNED_NORMALIZED);
720 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
721 drawComponentType == GL_SIGNED_NORMALIZED);
722
723 if (extensions.colorBufferFloat)
724 {
725 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
726 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
727
728 if (readFixedOrFloat != drawFixedOrFloat)
729 {
730 context->recordError(Error(GL_INVALID_OPERATION,
731 "If the read buffer contains fixed-point or "
732 "floating-point values, the draw buffer "
733 "must as well."));
734 return false;
735 }
736 }
737 else if (readFixedPoint != drawFixedPoint)
738 {
739 context->recordError(Error(GL_INVALID_OPERATION,
740 "If the read buffer contains fixed-point "
741 "values, the draw buffer must as well."));
742 return false;
743 }
744
745 if (readComponentType == GL_UNSIGNED_INT &&
746 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400747 {
Geoff Langb1196682014-07-23 13:47:29 -0400748 context->recordError(Error(GL_INVALID_OPERATION));
749 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400750 }
751
Jamie Madill6163c752015-12-07 16:32:59 -0500752 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400753 {
Geoff Langb1196682014-07-23 13:47:29 -0400754 context->recordError(Error(GL_INVALID_OPERATION));
755 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400756 }
757
Geoff Langb2f3d052013-08-13 12:49:27 -0400758 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 {
Geoff Langb1196682014-07-23 13:47:29 -0400760 context->recordError(Error(GL_INVALID_OPERATION));
761 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 }
763 }
764 }
765
Geoff Lang5d601382014-07-22 15:14:06 -0400766 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 {
Geoff Langb1196682014-07-23 13:47:29 -0400768 context->recordError(Error(GL_INVALID_OPERATION));
769 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 }
772 }
773
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200774 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
775 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
776 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200778 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400779 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400780 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
781 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400782
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200783 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400784 {
Geoff Langd8a22582014-12-17 15:28:23 -0500785 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400786 {
Geoff Langb1196682014-07-23 13:47:29 -0400787 context->recordError(Error(GL_INVALID_OPERATION));
788 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400789 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400790
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200791 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400792 {
Geoff Langb1196682014-07-23 13:47:29 -0400793 context->recordError(Error(GL_INVALID_OPERATION));
794 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 }
796 }
797 }
798 }
799
800 return true;
801}
802
Geoff Langb1196682014-07-23 13:47:29 -0400803bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400804{
805 switch (pname)
806 {
807 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
808 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
809 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
810 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
811 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
812 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
813 case GL_CURRENT_VERTEX_ATTRIB:
814 return true;
815
816 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
817 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
818 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400819 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
820 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400821 return true;
822
823 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400824 if (context->getClientVersion() < 3)
825 {
826 context->recordError(Error(GL_INVALID_ENUM));
827 return false;
828 }
829 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400830
831 default:
Geoff Langb1196682014-07-23 13:47:29 -0400832 context->recordError(Error(GL_INVALID_ENUM));
833 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400834 }
835}
836
Ian Ewellbda75592016-04-18 17:25:54 -0400837bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838{
839 switch (pname)
840 {
841 case GL_TEXTURE_WRAP_R:
842 case GL_TEXTURE_SWIZZLE_R:
843 case GL_TEXTURE_SWIZZLE_G:
844 case GL_TEXTURE_SWIZZLE_B:
845 case GL_TEXTURE_SWIZZLE_A:
846 case GL_TEXTURE_BASE_LEVEL:
847 case GL_TEXTURE_MAX_LEVEL:
848 case GL_TEXTURE_COMPARE_MODE:
849 case GL_TEXTURE_COMPARE_FUNC:
850 case GL_TEXTURE_MIN_LOD:
851 case GL_TEXTURE_MAX_LOD:
Ian Ewellbda75592016-04-18 17:25:54 -0400852 // ES3 texture paramters are not supported on external textures as the extension is
853 // written against ES2.
854 if (context->getClientVersion() < 3 || target == GL_TEXTURE_EXTERNAL_OES)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400855 {
Geoff Langb1196682014-07-23 13:47:29 -0400856 context->recordError(Error(GL_INVALID_ENUM));
857 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400858 }
859 break;
860
861 default: break;
862 }
863
864 switch (pname)
865 {
866 case GL_TEXTURE_WRAP_S:
867 case GL_TEXTURE_WRAP_T:
868 case GL_TEXTURE_WRAP_R:
869 switch (param)
870 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000871 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400872 return true;
873 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400874 case GL_MIRRORED_REPEAT:
Ian Ewellbda75592016-04-18 17:25:54 -0400875 return (target != GL_TEXTURE_EXTERNAL_OES);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400876 default:
Geoff Langb1196682014-07-23 13:47:29 -0400877 context->recordError(Error(GL_INVALID_ENUM));
878 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400879 }
880
881 case GL_TEXTURE_MIN_FILTER:
882 switch (param)
883 {
884 case GL_NEAREST:
885 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400886 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400887 case GL_NEAREST_MIPMAP_NEAREST:
888 case GL_LINEAR_MIPMAP_NEAREST:
889 case GL_NEAREST_MIPMAP_LINEAR:
890 case GL_LINEAR_MIPMAP_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400891 return (target != GL_TEXTURE_EXTERNAL_OES);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400892 default:
Geoff Langb1196682014-07-23 13:47:29 -0400893 context->recordError(Error(GL_INVALID_ENUM));
894 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400895 }
896 break;
897
898 case GL_TEXTURE_MAG_FILTER:
899 switch (param)
900 {
901 case GL_NEAREST:
902 case GL_LINEAR:
903 return true;
904 default:
Geoff Langb1196682014-07-23 13:47:29 -0400905 context->recordError(Error(GL_INVALID_ENUM));
906 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400907 }
908 break;
909
910 case GL_TEXTURE_USAGE_ANGLE:
911 switch (param)
912 {
913 case GL_NONE:
914 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
915 return true;
916 default:
Geoff Langb1196682014-07-23 13:47:29 -0400917 context->recordError(Error(GL_INVALID_ENUM));
918 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400919 }
920 break;
921
922 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400923 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400924 {
Geoff Langb1196682014-07-23 13:47:29 -0400925 context->recordError(Error(GL_INVALID_ENUM));
926 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400927 }
928
929 // we assume the parameter passed to this validation method is truncated, not rounded
930 if (param < 1)
931 {
Geoff Langb1196682014-07-23 13:47:29 -0400932 context->recordError(Error(GL_INVALID_VALUE));
933 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400934 }
935 return true;
936
937 case GL_TEXTURE_MIN_LOD:
938 case GL_TEXTURE_MAX_LOD:
939 // any value is permissible
940 return true;
941
942 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400943 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400944 switch (param)
945 {
946 case GL_NONE:
947 case GL_COMPARE_REF_TO_TEXTURE:
948 return true;
949 default:
Geoff Langb1196682014-07-23 13:47:29 -0400950 context->recordError(Error(GL_INVALID_ENUM));
951 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400952 }
953 break;
954
955 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400956 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400957 switch (param)
958 {
959 case GL_LEQUAL:
960 case GL_GEQUAL:
961 case GL_LESS:
962 case GL_GREATER:
963 case GL_EQUAL:
964 case GL_NOTEQUAL:
965 case GL_ALWAYS:
966 case GL_NEVER:
967 return true;
968 default:
Geoff Langb1196682014-07-23 13:47:29 -0400969 context->recordError(Error(GL_INVALID_ENUM));
970 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400971 }
972 break;
973
974 case GL_TEXTURE_SWIZZLE_R:
975 case GL_TEXTURE_SWIZZLE_G:
976 case GL_TEXTURE_SWIZZLE_B:
977 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400978 switch (param)
979 {
980 case GL_RED:
981 case GL_GREEN:
982 case GL_BLUE:
983 case GL_ALPHA:
984 case GL_ZERO:
985 case GL_ONE:
986 return true;
987 default:
Geoff Langb1196682014-07-23 13:47:29 -0400988 context->recordError(Error(GL_INVALID_ENUM));
989 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400990 }
991 break;
992
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400993 case GL_TEXTURE_BASE_LEVEL:
994 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400995 if (param < 0)
996 {
Geoff Langb1196682014-07-23 13:47:29 -0400997 context->recordError(Error(GL_INVALID_VALUE));
998 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400999 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001000 return true;
1001
1002 default:
Geoff Langb1196682014-07-23 13:47:29 -04001003 context->recordError(Error(GL_INVALID_ENUM));
1004 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001005 }
1006}
1007
Geoff Langb1196682014-07-23 13:47:29 -04001008bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001009{
1010 switch (pname)
1011 {
1012 case GL_TEXTURE_MIN_FILTER:
1013 case GL_TEXTURE_MAG_FILTER:
1014 case GL_TEXTURE_WRAP_S:
1015 case GL_TEXTURE_WRAP_T:
1016 case GL_TEXTURE_WRAP_R:
1017 case GL_TEXTURE_MIN_LOD:
1018 case GL_TEXTURE_MAX_LOD:
1019 case GL_TEXTURE_COMPARE_MODE:
1020 case GL_TEXTURE_COMPARE_FUNC:
1021 return true;
1022
1023 default:
Geoff Langb1196682014-07-23 13:47:29 -04001024 context->recordError(Error(GL_INVALID_ENUM));
1025 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001026 }
1027}
1028
Jamie Madillc29968b2016-01-20 11:17:23 -05001029bool ValidateReadPixels(Context *context,
1030 GLint x,
1031 GLint y,
1032 GLsizei width,
1033 GLsizei height,
1034 GLenum format,
1035 GLenum type,
1036 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001037{
Jamie Madillc29968b2016-01-20 11:17:23 -05001038 if (width < 0 || height < 0)
1039 {
1040 context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
1041 return false;
1042 }
1043
1044 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001045 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001046
Geoff Lang748f74e2014-12-01 11:25:34 -05001047 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001048 {
Geoff Langb1196682014-07-23 13:47:29 -04001049 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1050 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001051 }
1052
Jamie Madill48faf802014-11-06 15:27:22 -05001053 if (context->getState().getReadFramebuffer()->id() != 0 &&
1054 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001055 {
Geoff Langb1196682014-07-23 13:47:29 -04001056 context->recordError(Error(GL_INVALID_OPERATION));
1057 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001058 }
1059
Geoff Langbce529e2014-12-01 12:48:41 -05001060 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1061 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001062 {
Geoff Langb1196682014-07-23 13:47:29 -04001063 context->recordError(Error(GL_INVALID_OPERATION));
1064 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001065 }
1066
Geoff Langbce529e2014-12-01 12:48:41 -05001067 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1068 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001069 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001070 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001071
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001072 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1073 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001074
1075 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1076 {
Geoff Langb1196682014-07-23 13:47:29 -04001077 context->recordError(Error(GL_INVALID_OPERATION));
1078 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001079 }
1080
Jamie Madillc29968b2016-01-20 11:17:23 -05001081 return true;
1082}
1083
1084bool ValidateReadnPixelsEXT(Context *context,
1085 GLint x,
1086 GLint y,
1087 GLsizei width,
1088 GLsizei height,
1089 GLenum format,
1090 GLenum type,
1091 GLsizei bufSize,
1092 GLvoid *pixels)
1093{
1094 if (bufSize < 0)
1095 {
1096 context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
1097 return false;
1098 }
1099
Geoff Lang5d601382014-07-22 15:14:06 -04001100 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1101 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001102
Minmin Gongadff67b2015-10-14 10:34:45 -04001103 GLsizei outputPitch =
1104 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1105 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001106 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001107 int requiredSize = outputPitch * height;
1108 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001109 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001110 context->recordError(Error(GL_INVALID_OPERATION));
1111 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001112 }
1113
Jamie Madillc29968b2016-01-20 11:17:23 -05001114 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001115}
1116
Olli Etuaho41997e72016-03-10 13:38:39 +02001117bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001118{
1119 if (!context->getExtensions().occlusionQueryBoolean &&
1120 !context->getExtensions().disjointTimerQuery)
1121 {
1122 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1123 return false;
1124 }
1125
Olli Etuaho41997e72016-03-10 13:38:39 +02001126 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001127}
1128
Olli Etuaho41997e72016-03-10 13:38:39 +02001129bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001130{
1131 if (!context->getExtensions().occlusionQueryBoolean &&
1132 !context->getExtensions().disjointTimerQuery)
1133 {
1134 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1135 return false;
1136 }
1137
Olli Etuaho41997e72016-03-10 13:38:39 +02001138 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001139}
1140
1141bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001142{
1143 if (!ValidQueryType(context, target))
1144 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001145 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001146 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001147 }
1148
1149 if (id == 0)
1150 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001151 context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001152 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001153 }
1154
1155 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1156 // of zero, if the active query object name for <target> is non-zero (for the
1157 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1158 // the active query for either target is non-zero), if <id> is the name of an
1159 // existing query object whose type does not match <target>, or if <id> is the
1160 // active query object name for any query type, the error INVALID_OPERATION is
1161 // generated.
1162
1163 // Ensure no other queries are active
1164 // NOTE: If other queries than occlusion are supported, we will need to check
1165 // separately that:
1166 // a) The query ID passed is not the current active query for any target/type
1167 // b) There are no active queries for the requested target (and in the case
1168 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1169 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001170
1171 // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
1172 // same time
Shannon Woods53a94a82014-06-24 15:20:36 -04001173 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001174 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001175 context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001176 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001177 }
1178
1179 Query *queryObject = context->getQuery(id, true, target);
1180
1181 // check that name was obtained with glGenQueries
1182 if (!queryObject)
1183 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001184 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001185 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001186 }
1187
1188 // check for type mismatch
1189 if (queryObject->getType() != target)
1190 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001191 context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001192 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001193 }
1194
1195 return true;
1196}
1197
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001198bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1199{
1200 if (!context->getExtensions().occlusionQueryBoolean &&
1201 !context->getExtensions().disjointTimerQuery)
1202 {
1203 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1204 return false;
1205 }
1206
1207 return ValidateBeginQueryBase(context, target, id);
1208}
1209
1210bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001211{
1212 if (!ValidQueryType(context, target))
1213 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001214 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001215 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001216 }
1217
Shannon Woods53a94a82014-06-24 15:20:36 -04001218 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001219
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001220 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001221 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001222 context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001223 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001224 }
1225
Jamie Madill45c785d2014-05-13 14:09:34 -04001226 return true;
1227}
1228
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001229bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1230{
1231 if (!context->getExtensions().occlusionQueryBoolean &&
1232 !context->getExtensions().disjointTimerQuery)
1233 {
1234 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1235 return false;
1236 }
1237
1238 return ValidateEndQueryBase(context, target);
1239}
1240
1241bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1242{
1243 if (!context->getExtensions().disjointTimerQuery)
1244 {
1245 context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
1246 return false;
1247 }
1248
1249 if (target != GL_TIMESTAMP_EXT)
1250 {
1251 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
1252 return false;
1253 }
1254
1255 Query *queryObject = context->getQuery(id, true, target);
1256 if (queryObject == nullptr)
1257 {
1258 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
1259 return false;
1260 }
1261
1262 if (context->getState().isQueryActive(queryObject))
1263 {
1264 context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
1265 return false;
1266 }
1267
1268 return true;
1269}
1270
1271bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1272{
1273 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1274 {
1275 context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
1276 return false;
1277 }
1278
1279 switch (pname)
1280 {
1281 case GL_CURRENT_QUERY_EXT:
1282 if (target == GL_TIMESTAMP_EXT)
1283 {
1284 context->recordError(
1285 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1286 return false;
1287 }
1288 break;
1289 case GL_QUERY_COUNTER_BITS_EXT:
1290 if (!context->getExtensions().disjointTimerQuery ||
1291 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1292 {
1293 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1294 return false;
1295 }
1296 break;
1297 default:
1298 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1299 return false;
1300 }
1301
1302 return true;
1303}
1304
1305bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1306{
1307 if (!context->getExtensions().occlusionQueryBoolean &&
1308 !context->getExtensions().disjointTimerQuery)
1309 {
1310 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1311 return false;
1312 }
1313
1314 return ValidateGetQueryivBase(context, target, pname);
1315}
1316
1317bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1318{
1319 Query *queryObject = context->getQuery(id, false, GL_NONE);
1320
1321 if (!queryObject)
1322 {
1323 context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
1324 return false;
1325 }
1326
1327 if (context->getState().isQueryActive(queryObject))
1328 {
1329 context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
1330 return false;
1331 }
1332
1333 switch (pname)
1334 {
1335 case GL_QUERY_RESULT_EXT:
1336 case GL_QUERY_RESULT_AVAILABLE_EXT:
1337 break;
1338
1339 default:
1340 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
1341 return false;
1342 }
1343
1344 return true;
1345}
1346
1347bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1348{
1349 if (!context->getExtensions().disjointTimerQuery)
1350 {
1351 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1352 return false;
1353 }
1354 return ValidateGetQueryObjectValueBase(context, id, pname);
1355}
1356
1357bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1358{
1359 if (!context->getExtensions().disjointTimerQuery &&
1360 !context->getExtensions().occlusionQueryBoolean)
1361 {
1362 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1363 return false;
1364 }
1365 return ValidateGetQueryObjectValueBase(context, id, pname);
1366}
1367
1368bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1369{
1370 if (!context->getExtensions().disjointTimerQuery)
1371 {
1372 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1373 return false;
1374 }
1375 return ValidateGetQueryObjectValueBase(context, id, pname);
1376}
1377
1378bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1379{
1380 if (!context->getExtensions().disjointTimerQuery)
1381 {
1382 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1383 return false;
1384 }
1385 return ValidateGetQueryObjectValueBase(context, id, pname);
1386}
1387
Jamie Madill62d31cb2015-09-11 13:25:51 -04001388static bool ValidateUniformCommonBase(gl::Context *context,
1389 GLenum targetUniformType,
1390 GLint location,
1391 GLsizei count,
1392 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001393{
1394 if (count < 0)
1395 {
Geoff Langb1196682014-07-23 13:47:29 -04001396 context->recordError(Error(GL_INVALID_VALUE));
1397 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001398 }
1399
Geoff Lang7dd2e102014-11-10 15:19:26 -05001400 gl::Program *program = context->getState().getProgram();
1401 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001402 {
Geoff Langb1196682014-07-23 13:47:29 -04001403 context->recordError(Error(GL_INVALID_OPERATION));
1404 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001405 }
1406
Geoff Langd8605522016-04-13 10:19:12 -04001407 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001408 {
1409 // Silently ignore the uniform command
1410 return false;
1411 }
1412
Geoff Lang7dd2e102014-11-10 15:19:26 -05001413 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001414 {
Geoff Langb1196682014-07-23 13:47:29 -04001415 context->recordError(Error(GL_INVALID_OPERATION));
1416 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001417 }
1418
Jamie Madill62d31cb2015-09-11 13:25:51 -04001419 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001420
1421 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001422 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001423 {
Geoff Langb1196682014-07-23 13:47:29 -04001424 context->recordError(Error(GL_INVALID_OPERATION));
1425 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001426 }
1427
Jamie Madill62d31cb2015-09-11 13:25:51 -04001428 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001429 return true;
1430}
1431
Jamie Madillaa981bd2014-05-20 10:55:55 -04001432bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1433{
1434 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001435 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001436 {
Geoff Langb1196682014-07-23 13:47:29 -04001437 context->recordError(Error(GL_INVALID_OPERATION));
1438 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001439 }
1440
Jamie Madill62d31cb2015-09-11 13:25:51 -04001441 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001442 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1443 {
1444 return false;
1445 }
1446
Jamie Madillf2575982014-06-25 16:04:54 -04001447 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001448 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001449 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1450 {
Geoff Langb1196682014-07-23 13:47:29 -04001451 context->recordError(Error(GL_INVALID_OPERATION));
1452 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001453 }
1454
1455 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001456}
1457
1458bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1459 GLboolean transpose)
1460{
1461 // Check for ES3 uniform entry points
1462 int rows = VariableRowCount(matrixType);
1463 int cols = VariableColumnCount(matrixType);
1464 if (rows != cols && context->getClientVersion() < 3)
1465 {
Geoff Langb1196682014-07-23 13:47:29 -04001466 context->recordError(Error(GL_INVALID_OPERATION));
1467 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001468 }
1469
1470 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1471 {
Geoff Langb1196682014-07-23 13:47:29 -04001472 context->recordError(Error(GL_INVALID_VALUE));
1473 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001474 }
1475
Jamie Madill62d31cb2015-09-11 13:25:51 -04001476 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001477 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1478 {
1479 return false;
1480 }
1481
1482 if (uniform->type != matrixType)
1483 {
Geoff Langb1196682014-07-23 13:47:29 -04001484 context->recordError(Error(GL_INVALID_OPERATION));
1485 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001486 }
1487
1488 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001489}
1490
Jamie Madill893ab082014-05-16 16:56:10 -04001491bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1492{
1493 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1494 {
Geoff Langb1196682014-07-23 13:47:29 -04001495 context->recordError(Error(GL_INVALID_ENUM));
1496 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001497 }
1498
Jamie Madill0af26e12015-03-05 19:54:33 -05001499 const Caps &caps = context->getCaps();
1500
Jamie Madill893ab082014-05-16 16:56:10 -04001501 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1502 {
1503 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1504
Jamie Madill0af26e12015-03-05 19:54:33 -05001505 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001506 {
Geoff Langb1196682014-07-23 13:47:29 -04001507 context->recordError(Error(GL_INVALID_OPERATION));
1508 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001509 }
1510 }
1511
1512 switch (pname)
1513 {
1514 case GL_TEXTURE_BINDING_2D:
1515 case GL_TEXTURE_BINDING_CUBE_MAP:
1516 case GL_TEXTURE_BINDING_3D:
1517 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001518 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001519 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1520 if (!context->getExtensions().eglStreamConsumerExternal)
1521 {
1522 context->recordError(
1523 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1524 return false;
1525 }
1526 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001527
1528 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1529 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1530 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001531 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001532 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001533 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001534 {
Geoff Langb1196682014-07-23 13:47:29 -04001535 context->recordError(Error(GL_INVALID_OPERATION));
1536 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001537 }
1538
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001539 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001540 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001541 {
Geoff Langb1196682014-07-23 13:47:29 -04001542 context->recordError(Error(GL_INVALID_OPERATION));
1543 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001544 }
1545 }
1546 break;
1547
1548 default:
1549 break;
1550 }
1551
1552 // pname is valid, but there are no parameters to return
1553 if (numParams == 0)
1554 {
1555 return false;
1556 }
1557
1558 return true;
1559}
1560
Jamie Madillc29968b2016-01-20 11:17:23 -05001561bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1562 GLenum target,
1563 GLint level,
1564 GLenum internalformat,
1565 bool isSubImage,
1566 GLint xoffset,
1567 GLint yoffset,
1568 GLint zoffset,
1569 GLint x,
1570 GLint y,
1571 GLsizei width,
1572 GLsizei height,
1573 GLint border,
1574 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001575{
Jamie Madill560a8d82014-05-21 13:06:20 -04001576 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1577 {
Geoff Langb1196682014-07-23 13:47:29 -04001578 context->recordError(Error(GL_INVALID_VALUE));
1579 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001580 }
1581
1582 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1583 {
Geoff Langb1196682014-07-23 13:47:29 -04001584 context->recordError(Error(GL_INVALID_VALUE));
1585 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001586 }
1587
1588 if (border != 0)
1589 {
Geoff Langb1196682014-07-23 13:47:29 -04001590 context->recordError(Error(GL_INVALID_VALUE));
1591 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001592 }
1593
1594 if (!ValidMipLevel(context, target, level))
1595 {
Geoff Langb1196682014-07-23 13:47:29 -04001596 context->recordError(Error(GL_INVALID_VALUE));
1597 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001598 }
1599
Jamie Madillc29968b2016-01-20 11:17:23 -05001600 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001601 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001602 {
Geoff Langb1196682014-07-23 13:47:29 -04001603 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1604 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001605 }
1606
Jamie Madillc29968b2016-01-20 11:17:23 -05001607 const auto &state = context->getState();
1608 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001609 {
Geoff Langb1196682014-07-23 13:47:29 -04001610 context->recordError(Error(GL_INVALID_OPERATION));
1611 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001612 }
1613
Geoff Langaae65a42014-05-26 12:43:44 -04001614 const gl::Caps &caps = context->getCaps();
1615
Geoff Langaae65a42014-05-26 12:43:44 -04001616 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001617 switch (target)
1618 {
1619 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001620 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001621 break;
1622
1623 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1624 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1625 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1626 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1627 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1628 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001629 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001630 break;
1631
1632 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001633 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001634 break;
1635
1636 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001637 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001638 break;
1639
1640 default:
Geoff Langb1196682014-07-23 13:47:29 -04001641 context->recordError(Error(GL_INVALID_ENUM));
1642 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001643 }
1644
Jamie Madillc29968b2016-01-20 11:17:23 -05001645 gl::Texture *texture =
1646 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001647 if (!texture)
1648 {
Geoff Langb1196682014-07-23 13:47:29 -04001649 context->recordError(Error(GL_INVALID_OPERATION));
1650 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001651 }
1652
Geoff Lang69cce582015-09-17 13:20:36 -04001653 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001654 {
Geoff Langb1196682014-07-23 13:47:29 -04001655 context->recordError(Error(GL_INVALID_OPERATION));
1656 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001657 }
1658
Geoff Lang5d601382014-07-22 15:14:06 -04001659 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1660
1661 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001662 {
Geoff Langb1196682014-07-23 13:47:29 -04001663 context->recordError(Error(GL_INVALID_OPERATION));
1664 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001665 }
1666
Geoff Langa9be0dc2014-12-17 12:34:40 -05001667 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001668 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001669 context->recordError(Error(GL_INVALID_OPERATION));
1670 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001671 }
1672
1673 if (isSubImage)
1674 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001675 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1676 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1677 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001678 {
Geoff Langb1196682014-07-23 13:47:29 -04001679 context->recordError(Error(GL_INVALID_VALUE));
1680 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001681 }
1682 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001683 else
1684 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001685 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001686 {
Geoff Langb1196682014-07-23 13:47:29 -04001687 context->recordError(Error(GL_INVALID_VALUE));
1688 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001689 }
1690
Geoff Lang5d601382014-07-22 15:14:06 -04001691 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001692 {
Geoff Langb1196682014-07-23 13:47:29 -04001693 context->recordError(Error(GL_INVALID_ENUM));
1694 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001695 }
1696
1697 int maxLevelDimension = (maxDimension >> level);
1698 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1699 {
Geoff Langb1196682014-07-23 13:47:29 -04001700 context->recordError(Error(GL_INVALID_VALUE));
1701 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001702 }
1703 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001704
Geoff Langa9be0dc2014-12-17 12:34:40 -05001705 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001706 return true;
1707}
1708
Jamie Madillf25855c2015-11-03 11:06:18 -05001709static bool ValidateDrawBase(ValidationContext *context,
1710 GLenum mode,
1711 GLsizei count,
1712 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001713{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001714 switch (mode)
1715 {
1716 case GL_POINTS:
1717 case GL_LINES:
1718 case GL_LINE_LOOP:
1719 case GL_LINE_STRIP:
1720 case GL_TRIANGLES:
1721 case GL_TRIANGLE_STRIP:
1722 case GL_TRIANGLE_FAN:
1723 break;
1724 default:
Geoff Langb1196682014-07-23 13:47:29 -04001725 context->recordError(Error(GL_INVALID_ENUM));
1726 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001727 }
1728
Jamie Madill250d33f2014-06-06 17:09:03 -04001729 if (count < 0)
1730 {
Geoff Langb1196682014-07-23 13:47:29 -04001731 context->recordError(Error(GL_INVALID_VALUE));
1732 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001733 }
1734
Geoff Langb1196682014-07-23 13:47:29 -04001735 const State &state = context->getState();
1736
Jamie Madill250d33f2014-06-06 17:09:03 -04001737 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001738 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001739 {
Geoff Langb1196682014-07-23 13:47:29 -04001740 context->recordError(Error(GL_INVALID_OPERATION));
1741 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001742 }
1743
Geoff Lang3a86ad32015-09-01 11:47:05 -04001744 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001745 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001746 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1747 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1748 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1749 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1750 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1751 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1752 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001753 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001754 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1755 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001756 {
1757 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1758 // Section 6.10 of the WebGL 1.0 spec
1759 ERR(
1760 "This ANGLE implementation does not support separate front/back stencil "
1761 "writemasks, reference values, or stencil mask values.");
1762 context->recordError(Error(GL_INVALID_OPERATION));
1763 return false;
1764 }
Jamie Madillac528012014-06-20 13:21:23 -04001765 }
1766
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001767 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001768 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001769 {
Geoff Langb1196682014-07-23 13:47:29 -04001770 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1771 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001772 }
1773
Geoff Lang7dd2e102014-11-10 15:19:26 -05001774 gl::Program *program = state.getProgram();
1775 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001776 {
Geoff Langb1196682014-07-23 13:47:29 -04001777 context->recordError(Error(GL_INVALID_OPERATION));
1778 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001779 }
1780
Geoff Lang7dd2e102014-11-10 15:19:26 -05001781 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001782 {
Geoff Langb1196682014-07-23 13:47:29 -04001783 context->recordError(Error(GL_INVALID_OPERATION));
1784 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001785 }
1786
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001787 // Uniform buffer validation
1788 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1789 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001790 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001791 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001792 const OffsetBindingPointer<Buffer> &uniformBuffer =
1793 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001794
Geoff Lang5d124a62015-09-15 13:03:27 -04001795 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001796 {
1797 // undefined behaviour
1798 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1799 return false;
1800 }
1801
Geoff Lang5d124a62015-09-15 13:03:27 -04001802 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001803 if (uniformBufferSize == 0)
1804 {
1805 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001806 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001807 }
1808
Jamie Madill62d31cb2015-09-11 13:25:51 -04001809 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001810 {
1811 // undefined behaviour
1812 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1813 return false;
1814 }
1815 }
1816
Jamie Madill250d33f2014-06-06 17:09:03 -04001817 // No-op if zero count
1818 return (count > 0);
1819}
1820
Geoff Langb1196682014-07-23 13:47:29 -04001821bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001822{
Jamie Madillfd716582014-06-06 17:09:04 -04001823 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001824 {
Geoff Langb1196682014-07-23 13:47:29 -04001825 context->recordError(Error(GL_INVALID_VALUE));
1826 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001827 }
1828
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001829 const State &state = context->getState();
1830 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001831 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1832 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001833 {
1834 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1835 // that does not match the current transform feedback object's draw mode (if transform feedback
1836 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001837 context->recordError(Error(GL_INVALID_OPERATION));
1838 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001839 }
1840
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001841 if (!ValidateDrawBase(context, mode, count, primcount))
1842 {
1843 return false;
1844 }
1845
1846 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001847 {
1848 return false;
1849 }
1850
1851 return true;
1852}
1853
Geoff Langb1196682014-07-23 13:47:29 -04001854bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001855{
1856 if (primcount < 0)
1857 {
Geoff Langb1196682014-07-23 13:47:29 -04001858 context->recordError(Error(GL_INVALID_VALUE));
1859 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001860 }
1861
Jamie Madill2b976812014-08-25 15:47:49 -04001862 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001863 {
1864 return false;
1865 }
1866
1867 // No-op if zero primitive count
1868 return (primcount > 0);
1869}
1870
Geoff Lang87a93302014-09-16 13:29:43 -04001871static bool ValidateDrawInstancedANGLE(Context *context)
1872{
1873 // Verify there is at least one active attribute with a divisor of zero
1874 const gl::State& state = context->getState();
1875
Geoff Lang7dd2e102014-11-10 15:19:26 -05001876 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001877
1878 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001879 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001880 {
1881 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001882 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001883 {
1884 return true;
1885 }
1886 }
1887
1888 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1889 "has a divisor of zero."));
1890 return false;
1891}
1892
1893bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1894{
1895 if (!ValidateDrawInstancedANGLE(context))
1896 {
1897 return false;
1898 }
1899
1900 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1901}
1902
Jamie Madillf25855c2015-11-03 11:06:18 -05001903bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001904 GLenum mode,
1905 GLsizei count,
1906 GLenum type,
1907 const GLvoid *indices,
1908 GLsizei primcount,
1909 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001910{
Jamie Madill250d33f2014-06-06 17:09:03 -04001911 switch (type)
1912 {
1913 case GL_UNSIGNED_BYTE:
1914 case GL_UNSIGNED_SHORT:
1915 break;
1916 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001917 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001918 {
Geoff Langb1196682014-07-23 13:47:29 -04001919 context->recordError(Error(GL_INVALID_ENUM));
1920 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001921 }
1922 break;
1923 default:
Geoff Langb1196682014-07-23 13:47:29 -04001924 context->recordError(Error(GL_INVALID_ENUM));
1925 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001926 }
1927
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001928 const State &state = context->getState();
1929
1930 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001931 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001932 {
1933 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1934 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001935 context->recordError(Error(GL_INVALID_OPERATION));
1936 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001937 }
1938
1939 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001940 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001941 {
Geoff Langb1196682014-07-23 13:47:29 -04001942 context->recordError(Error(GL_INVALID_OPERATION));
1943 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001944 }
1945
Jamie Madill2b976812014-08-25 15:47:49 -04001946 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001947 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001948 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001949 {
Geoff Langb1196682014-07-23 13:47:29 -04001950 context->recordError(Error(GL_INVALID_OPERATION));
1951 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001952 }
1953
Jamie Madillae3000b2014-08-25 15:47:51 -04001954 if (elementArrayBuffer)
1955 {
1956 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1957
1958 GLint64 offset = reinterpret_cast<GLint64>(indices);
1959 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1960
1961 // check for integer overflows
1962 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1963 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1964 {
Geoff Langb1196682014-07-23 13:47:29 -04001965 context->recordError(Error(GL_OUT_OF_MEMORY));
1966 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001967 }
1968
1969 // Check for reading past the end of the bound buffer object
1970 if (byteCount > elementArrayBuffer->getSize())
1971 {
Geoff Langb1196682014-07-23 13:47:29 -04001972 context->recordError(Error(GL_INVALID_OPERATION));
1973 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001974 }
1975 }
1976 else if (!indices)
1977 {
1978 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001979 context->recordError(Error(GL_INVALID_OPERATION));
1980 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001981 }
1982
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001983 if (!ValidateDrawBase(context, mode, count, primcount))
1984 {
1985 return false;
1986 }
1987
Jamie Madill2b976812014-08-25 15:47:49 -04001988 // Use max index to validate if our vertex buffers are large enough for the pull.
1989 // TODO: offer fast path, with disabled index validation.
1990 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1991 if (elementArrayBuffer)
1992 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001993 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001994 Error error =
1995 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1996 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001997 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001998 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001999 context->recordError(error);
2000 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002001 }
2002 }
2003 else
2004 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002005 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002006 }
2007
Jamie Madille79b1e12015-11-04 16:36:37 -05002008 // If we use an index greater than our maximum supported index range, return an error.
2009 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2010 // return an error if possible here.
2011 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2012 {
2013 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
2014 return false;
2015 }
2016
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002017 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002018 {
2019 return false;
2020 }
2021
Geoff Lang3edfe032015-09-04 16:38:24 -04002022 // No op if there are no real indices in the index data (all are primitive restart).
2023 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002024}
2025
Geoff Langb1196682014-07-23 13:47:29 -04002026bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002027 GLenum mode,
2028 GLsizei count,
2029 GLenum type,
2030 const GLvoid *indices,
2031 GLsizei primcount,
2032 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002033{
2034 if (primcount < 0)
2035 {
Geoff Langb1196682014-07-23 13:47:29 -04002036 context->recordError(Error(GL_INVALID_VALUE));
2037 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002038 }
2039
Jamie Madill2b976812014-08-25 15:47:49 -04002040 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002041 {
2042 return false;
2043 }
2044
2045 // No-op zero primitive count
2046 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002047}
2048
Geoff Lang3edfe032015-09-04 16:38:24 -04002049bool ValidateDrawElementsInstancedANGLE(Context *context,
2050 GLenum mode,
2051 GLsizei count,
2052 GLenum type,
2053 const GLvoid *indices,
2054 GLsizei primcount,
2055 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002056{
2057 if (!ValidateDrawInstancedANGLE(context))
2058 {
2059 return false;
2060 }
2061
2062 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2063}
2064
Geoff Langb1196682014-07-23 13:47:29 -04002065bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002066 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002067{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002068 if (!ValidFramebufferTarget(target))
2069 {
Geoff Langb1196682014-07-23 13:47:29 -04002070 context->recordError(Error(GL_INVALID_ENUM));
2071 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002072 }
2073
2074 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002075 {
2076 return false;
2077 }
2078
Jamie Madill55ec3b12014-07-03 10:38:57 -04002079 if (texture != 0)
2080 {
2081 gl::Texture *tex = context->getTexture(texture);
2082
2083 if (tex == NULL)
2084 {
Geoff Langb1196682014-07-23 13:47:29 -04002085 context->recordError(Error(GL_INVALID_OPERATION));
2086 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002087 }
2088
2089 if (level < 0)
2090 {
Geoff Langb1196682014-07-23 13:47:29 -04002091 context->recordError(Error(GL_INVALID_VALUE));
2092 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002093 }
2094 }
2095
Shannon Woods53a94a82014-06-24 15:20:36 -04002096 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002097 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002098
Jamie Madill84115c92015-04-23 15:00:07 -04002099 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002100 {
Jamie Madill84115c92015-04-23 15:00:07 -04002101 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002102 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002103 }
2104
2105 return true;
2106}
2107
Geoff Langb1196682014-07-23 13:47:29 -04002108bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002109 GLenum textarget, GLuint texture, GLint level)
2110{
Geoff Lang95663912015-04-02 15:54:45 -04002111 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2112 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002113 {
Geoff Langb1196682014-07-23 13:47:29 -04002114 context->recordError(Error(GL_INVALID_VALUE));
2115 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002116 }
2117
2118 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002119 {
2120 return false;
2121 }
2122
Jamie Madill55ec3b12014-07-03 10:38:57 -04002123 if (texture != 0)
2124 {
2125 gl::Texture *tex = context->getTexture(texture);
2126 ASSERT(tex);
2127
Jamie Madill2a6564e2014-07-11 09:53:19 -04002128 const gl::Caps &caps = context->getCaps();
2129
Jamie Madill55ec3b12014-07-03 10:38:57 -04002130 switch (textarget)
2131 {
2132 case GL_TEXTURE_2D:
2133 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002134 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002135 {
Geoff Langb1196682014-07-23 13:47:29 -04002136 context->recordError(Error(GL_INVALID_VALUE));
2137 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002138 }
2139 if (tex->getTarget() != GL_TEXTURE_2D)
2140 {
Geoff Langb1196682014-07-23 13:47:29 -04002141 context->recordError(Error(GL_INVALID_OPERATION));
2142 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002143 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002144 }
2145 break;
2146
2147 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2148 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2149 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2150 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2151 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2152 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2153 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002154 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002155 {
Geoff Langb1196682014-07-23 13:47:29 -04002156 context->recordError(Error(GL_INVALID_VALUE));
2157 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002158 }
2159 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2160 {
Geoff Langb1196682014-07-23 13:47:29 -04002161 context->recordError(Error(GL_INVALID_OPERATION));
2162 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002163 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002164 }
2165 break;
2166
2167 default:
Geoff Langb1196682014-07-23 13:47:29 -04002168 context->recordError(Error(GL_INVALID_ENUM));
2169 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002170 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002171
2172 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2173 if (internalFormatInfo.compressed)
2174 {
2175 context->recordError(Error(GL_INVALID_OPERATION));
2176 return false;
2177 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002178 }
2179
Jamie Madill570f7c82014-07-03 10:38:54 -04002180 return true;
2181}
2182
Geoff Langb1196682014-07-23 13:47:29 -04002183bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002184{
2185 if (program == 0)
2186 {
Geoff Langb1196682014-07-23 13:47:29 -04002187 context->recordError(Error(GL_INVALID_VALUE));
2188 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002189 }
2190
Dian Xiang769769a2015-09-09 15:20:08 -07002191 gl::Program *programObject = GetValidProgram(context, program);
2192 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002193 {
2194 return false;
2195 }
2196
Jamie Madill0063c512014-08-25 15:47:53 -04002197 if (!programObject || !programObject->isLinked())
2198 {
Geoff Langb1196682014-07-23 13:47:29 -04002199 context->recordError(Error(GL_INVALID_OPERATION));
2200 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002201 }
2202
Geoff Lang7dd2e102014-11-10 15:19:26 -05002203 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002204 {
Geoff Langb1196682014-07-23 13:47:29 -04002205 context->recordError(Error(GL_INVALID_OPERATION));
2206 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002207 }
2208
Jamie Madill0063c512014-08-25 15:47:53 -04002209 return true;
2210}
2211
Geoff Langb1196682014-07-23 13:47:29 -04002212bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002213{
2214 return ValidateGetUniformBase(context, program, location);
2215}
2216
Geoff Langb1196682014-07-23 13:47:29 -04002217bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002218{
Jamie Madill78f41802014-08-25 15:47:55 -04002219 return ValidateGetUniformBase(context, program, location);
2220}
2221
Geoff Langb1196682014-07-23 13:47:29 -04002222static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002223{
2224 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002225 {
Jamie Madill78f41802014-08-25 15:47:55 -04002226 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002227 }
2228
Jamie Madilla502c742014-08-28 17:19:13 -04002229 gl::Program *programObject = context->getProgram(program);
2230 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002231
Jamie Madill78f41802014-08-25 15:47:55 -04002232 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002233 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2234 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002235 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002236 {
Geoff Langb1196682014-07-23 13:47:29 -04002237 context->recordError(Error(GL_INVALID_OPERATION));
2238 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002239 }
2240
2241 return true;
2242}
2243
Geoff Langb1196682014-07-23 13:47:29 -04002244bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002245{
Jamie Madill78f41802014-08-25 15:47:55 -04002246 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002247}
2248
Geoff Langb1196682014-07-23 13:47:29 -04002249bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002250{
Jamie Madill78f41802014-08-25 15:47:55 -04002251 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002252}
2253
Austin Kinross08332632015-05-05 13:35:47 -07002254bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2255 const GLenum *attachments, bool defaultFramebuffer)
2256{
2257 if (numAttachments < 0)
2258 {
2259 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2260 return false;
2261 }
2262
2263 for (GLsizei i = 0; i < numAttachments; ++i)
2264 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002265 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002266 {
2267 if (defaultFramebuffer)
2268 {
2269 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2270 return false;
2271 }
2272
2273 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2274 {
2275 context->recordError(Error(GL_INVALID_OPERATION,
2276 "Requested color attachment is greater than the maximum supported color attachments"));
2277 return false;
2278 }
2279 }
2280 else
2281 {
2282 switch (attachments[i])
2283 {
2284 case GL_DEPTH_ATTACHMENT:
2285 case GL_STENCIL_ATTACHMENT:
2286 case GL_DEPTH_STENCIL_ATTACHMENT:
2287 if (defaultFramebuffer)
2288 {
2289 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2290 return false;
2291 }
2292 break;
2293 case GL_COLOR:
2294 case GL_DEPTH:
2295 case GL_STENCIL:
2296 if (!defaultFramebuffer)
2297 {
2298 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2299 return false;
2300 }
2301 break;
2302 default:
2303 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2304 return false;
2305 }
2306 }
2307 }
2308
2309 return true;
2310}
2311
Austin Kinross6ee1e782015-05-29 17:05:37 -07002312bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2313{
2314 // Note that debug marker calls must not set error state
2315
2316 if (length < 0)
2317 {
2318 return false;
2319 }
2320
2321 if (marker == nullptr)
2322 {
2323 return false;
2324 }
2325
2326 return true;
2327}
2328
2329bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2330{
2331 // Note that debug marker calls must not set error state
2332
2333 if (length < 0)
2334 {
2335 return false;
2336 }
2337
2338 if (length > 0 && marker == nullptr)
2339 {
2340 return false;
2341 }
2342
2343 return true;
2344}
2345
Geoff Langdcab33b2015-07-21 13:03:16 -04002346bool ValidateEGLImageTargetTexture2DOES(Context *context,
2347 egl::Display *display,
2348 GLenum target,
2349 egl::Image *image)
2350{
Geoff Langa8406172015-07-21 16:53:39 -04002351 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2352 {
2353 context->recordError(Error(GL_INVALID_OPERATION));
2354 return false;
2355 }
2356
2357 switch (target)
2358 {
2359 case GL_TEXTURE_2D:
2360 break;
2361
2362 default:
2363 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2364 return false;
2365 }
2366
2367 if (!display->isValidImage(image))
2368 {
2369 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2370 return false;
2371 }
2372
2373 if (image->getSamples() > 0)
2374 {
2375 context->recordError(Error(GL_INVALID_OPERATION,
2376 "cannot create a 2D texture from a multisampled EGL image."));
2377 return false;
2378 }
2379
2380 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2381 if (!textureCaps.texturable)
2382 {
2383 context->recordError(Error(GL_INVALID_OPERATION,
2384 "EGL image internal format is not supported as a texture."));
2385 return false;
2386 }
2387
Geoff Langdcab33b2015-07-21 13:03:16 -04002388 return true;
2389}
2390
2391bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2392 egl::Display *display,
2393 GLenum target,
2394 egl::Image *image)
2395{
Geoff Langa8406172015-07-21 16:53:39 -04002396 if (!context->getExtensions().eglImage)
2397 {
2398 context->recordError(Error(GL_INVALID_OPERATION));
2399 return false;
2400 }
2401
2402 switch (target)
2403 {
2404 case GL_RENDERBUFFER:
2405 break;
2406
2407 default:
2408 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2409 return false;
2410 }
2411
2412 if (!display->isValidImage(image))
2413 {
2414 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2415 return false;
2416 }
2417
2418 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2419 if (!textureCaps.renderable)
2420 {
2421 context->recordError(Error(
2422 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2423 return false;
2424 }
2425
Geoff Langdcab33b2015-07-21 13:03:16 -04002426 return true;
2427}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002428
2429bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2430{
Geoff Lang36167ab2015-12-07 10:27:14 -05002431 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002432 {
2433 // The default VAO should always exist
2434 ASSERT(array != 0);
2435 context->recordError(Error(GL_INVALID_OPERATION));
2436 return false;
2437 }
2438
2439 return true;
2440}
2441
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002442bool ValidateLinkProgram(Context *context, GLuint program)
2443{
2444 if (context->hasActiveTransformFeedback(program))
2445 {
2446 // ES 3.0.4 section 2.15 page 91
2447 context->recordError(Error(GL_INVALID_OPERATION,
2448 "Cannot link program while program is associated with an active "
2449 "transform feedback object."));
2450 return false;
2451 }
2452 return true;
2453}
2454
Geoff Langc5629752015-12-07 16:29:04 -05002455bool ValidateProgramBinaryBase(Context *context,
2456 GLuint program,
2457 GLenum binaryFormat,
2458 const void *binary,
2459 GLint length)
2460{
2461 Program *programObject = GetValidProgram(context, program);
2462 if (programObject == nullptr)
2463 {
2464 return false;
2465 }
2466
2467 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2468 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2469 programBinaryFormats.end())
2470 {
2471 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2472 return false;
2473 }
2474
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002475 if (context->hasActiveTransformFeedback(program))
2476 {
2477 // ES 3.0.4 section 2.15 page 91
2478 context->recordError(Error(GL_INVALID_OPERATION,
2479 "Cannot change program binary while program is associated with "
2480 "an active transform feedback object."));
2481 return false;
2482 }
2483
Geoff Langc5629752015-12-07 16:29:04 -05002484 return true;
2485}
2486
2487bool ValidateGetProgramBinaryBase(Context *context,
2488 GLuint program,
2489 GLsizei bufSize,
2490 GLsizei *length,
2491 GLenum *binaryFormat,
2492 void *binary)
2493{
2494 Program *programObject = GetValidProgram(context, program);
2495 if (programObject == nullptr)
2496 {
2497 return false;
2498 }
2499
2500 if (!programObject->isLinked())
2501 {
2502 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2503 return false;
2504 }
2505
2506 return true;
2507}
Jamie Madillc29968b2016-01-20 11:17:23 -05002508
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002509bool ValidateUseProgram(Context *context, GLuint program)
2510{
2511 if (program != 0)
2512 {
2513 Program *programObject = context->getProgram(program);
2514 if (!programObject)
2515 {
2516 // ES 3.1.0 section 7.3 page 72
2517 if (context->getShader(program))
2518 {
2519 context->recordError(
2520 Error(GL_INVALID_OPERATION,
2521 "Attempted to use a single shader instead of a shader program."));
2522 return false;
2523 }
2524 else
2525 {
2526 context->recordError(Error(GL_INVALID_VALUE, "Program invalid."));
2527 return false;
2528 }
2529 }
2530 if (!programObject->isLinked())
2531 {
2532 context->recordError(Error(GL_INVALID_OPERATION, "Program not linked."));
2533 return false;
2534 }
2535 }
2536 if (context->getState().isTransformFeedbackActiveUnpaused())
2537 {
2538 // ES 3.0.4 section 2.15 page 91
2539 context->recordError(
2540 Error(GL_INVALID_OPERATION,
2541 "Cannot change active program while transform feedback is unpaused."));
2542 return false;
2543 }
2544
2545 return true;
2546}
2547
Jamie Madillc29968b2016-01-20 11:17:23 -05002548bool ValidateCopyTexImage2D(ValidationContext *context,
2549 GLenum target,
2550 GLint level,
2551 GLenum internalformat,
2552 GLint x,
2553 GLint y,
2554 GLsizei width,
2555 GLsizei height,
2556 GLint border)
2557{
2558 if (context->getClientVersion() < 3)
2559 {
2560 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2561 0, x, y, width, height, border);
2562 }
2563
2564 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002565 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2566 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002567}
Jamie Madillc29968b2016-01-20 11:17:23 -05002568
2569bool ValidateFramebufferRenderbuffer(Context *context,
2570 GLenum target,
2571 GLenum attachment,
2572 GLenum renderbuffertarget,
2573 GLuint renderbuffer)
2574{
2575 if (!ValidFramebufferTarget(target) ||
2576 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2577 {
2578 context->recordError(Error(GL_INVALID_ENUM));
2579 return false;
2580 }
2581
2582 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2583 renderbuffertarget, renderbuffer);
2584}
2585
2586bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2587{
2588 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2589 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2590 {
2591 context->recordError(
2592 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2593 return false;
2594 }
2595
2596 ASSERT(context->getState().getDrawFramebuffer());
2597 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2598 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2599
2600 // This should come first before the check for the default frame buffer
2601 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2602 // rather than INVALID_OPERATION
2603 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2604 {
2605 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2606
2607 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002608 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2609 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002610 {
2611 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002612 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2613 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2614 // 3.1 is still a bit ambiguous about the error, but future specs are
2615 // expected to clarify that GL_INVALID_ENUM is the correct error.
2616 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
2617 return false;
2618 }
2619 else if (bufs[colorAttachment] >= maxColorAttachment)
2620 {
2621 context->recordError(
2622 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002623 return false;
2624 }
2625 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2626 frameBufferId != 0)
2627 {
2628 // INVALID_OPERATION-GL is bound to buffer and ith argument
2629 // is not COLOR_ATTACHMENTi or NONE
2630 context->recordError(
2631 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2632 return false;
2633 }
2634 }
2635
2636 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2637 // and n is not 1 or bufs is bound to value other than BACK and NONE
2638 if (frameBufferId == 0)
2639 {
2640 if (n != 1)
2641 {
2642 context->recordError(Error(GL_INVALID_OPERATION,
2643 "n must be 1 when GL is bound to the default framebuffer"));
2644 return false;
2645 }
2646
2647 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2648 {
2649 context->recordError(Error(
2650 GL_INVALID_OPERATION,
2651 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2652 return false;
2653 }
2654 }
2655
2656 return true;
2657}
2658
2659bool ValidateCopyTexSubImage2D(Context *context,
2660 GLenum target,
2661 GLint level,
2662 GLint xoffset,
2663 GLint yoffset,
2664 GLint x,
2665 GLint y,
2666 GLsizei width,
2667 GLsizei height)
2668{
2669 if (context->getClientVersion() < 3)
2670 {
2671 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2672 yoffset, x, y, width, height, 0);
2673 }
2674
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002675 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2676 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002677}
2678
Olli Etuaho4f667482016-03-30 15:56:35 +03002679bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2680{
2681 if (!ValidBufferTarget(context, target))
2682 {
2683 context->recordError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
2684 return false;
2685 }
2686
2687 if (pname != GL_BUFFER_MAP_POINTER)
2688 {
2689 context->recordError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
2690 return false;
2691 }
2692
2693 Buffer *buffer = context->getState().getTargetBuffer(target);
2694
2695 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2696 // target bound to zero generate an INVALID_OPERATION error."
2697 // GLES 3.1 section 6.6 explicitly specifies this error.
2698 if (!buffer)
2699 {
2700 context->recordError(
2701 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2702 return false;
2703 }
2704
2705 return true;
2706}
2707
2708bool ValidateUnmapBufferBase(Context *context, GLenum target)
2709{
2710 if (!ValidBufferTarget(context, target))
2711 {
2712 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2713 return false;
2714 }
2715
2716 Buffer *buffer = context->getState().getTargetBuffer(target);
2717
2718 if (buffer == nullptr || !buffer->isMapped())
2719 {
2720 context->recordError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
2721 return false;
2722 }
2723
2724 return true;
2725}
2726
2727bool ValidateMapBufferRangeBase(Context *context,
2728 GLenum target,
2729 GLintptr offset,
2730 GLsizeiptr length,
2731 GLbitfield access)
2732{
2733 if (!ValidBufferTarget(context, target))
2734 {
2735 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2736 return false;
2737 }
2738
2739 if (offset < 0 || length < 0)
2740 {
2741 context->recordError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
2742 return false;
2743 }
2744
2745 Buffer *buffer = context->getState().getTargetBuffer(target);
2746
2747 if (!buffer)
2748 {
2749 context->recordError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
2750 return false;
2751 }
2752
2753 // Check for buffer overflow
2754 size_t offsetSize = static_cast<size_t>(offset);
2755 size_t lengthSize = static_cast<size_t>(length);
2756
2757 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2758 offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
2759 {
2760 context->recordError(
2761 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2762 return false;
2763 }
2764
2765 // Check for invalid bits in the mask
2766 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2767 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2768 GL_MAP_UNSYNCHRONIZED_BIT;
2769
2770 if (access & ~(allAccessBits))
2771 {
2772 context->recordError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
2773 return false;
2774 }
2775
2776 if (length == 0)
2777 {
2778 context->recordError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
2779 return false;
2780 }
2781
2782 if (buffer->isMapped())
2783 {
2784 context->recordError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
2785 return false;
2786 }
2787
2788 // Check for invalid bit combinations
2789 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2790 {
2791 context->recordError(
2792 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2793 return false;
2794 }
2795
2796 GLbitfield writeOnlyBits =
2797 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2798
2799 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2800 {
2801 context->recordError(Error(GL_INVALID_OPERATION,
2802 "Invalid access bits when mapping buffer for reading: 0x%X.",
2803 access));
2804 return false;
2805 }
2806
2807 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2808 {
2809 context->recordError(Error(
2810 GL_INVALID_OPERATION,
2811 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2812 return false;
2813 }
2814 return true;
2815}
2816
2817bool ValidateFlushMappedBufferRangeBase(Context *context,
2818 GLenum target,
2819 GLintptr offset,
2820 GLsizeiptr length)
2821{
2822 if (offset < 0 || length < 0)
2823 {
2824 context->recordError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
2825 return false;
2826 }
2827
2828 if (!ValidBufferTarget(context, target))
2829 {
2830 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2831 return false;
2832 }
2833
2834 Buffer *buffer = context->getState().getTargetBuffer(target);
2835
2836 if (buffer == nullptr)
2837 {
2838 context->recordError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
2839 return false;
2840 }
2841
2842 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2843 {
2844 context->recordError(Error(
2845 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2846 return false;
2847 }
2848
2849 // Check for buffer overflow
2850 size_t offsetSize = static_cast<size_t>(offset);
2851 size_t lengthSize = static_cast<size_t>(length);
2852
2853 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2854 offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
2855 {
2856 context->recordError(
2857 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2858 return false;
2859 }
2860
2861 return true;
2862}
2863
Olli Etuaho41997e72016-03-10 13:38:39 +02002864bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2865{
2866 return ValidateGenOrDelete(context, n);
2867}
2868
2869bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2870{
2871 return ValidateGenOrDelete(context, n);
2872}
2873
2874bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2875{
2876 return ValidateGenOrDelete(context, n);
2877}
2878
2879bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2880{
2881 return ValidateGenOrDelete(context, n);
2882}
2883
2884bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2885{
2886 return ValidateGenOrDelete(context, n);
2887}
2888
2889bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2890{
2891 return ValidateGenOrDelete(context, n);
2892}
2893
2894bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2895{
2896 return ValidateGenOrDelete(context, n);
2897}
2898
2899bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2900{
2901 return ValidateGenOrDelete(context, n);
2902}
2903
2904bool ValidateGenOrDelete(Context *context, GLint n)
2905{
2906 if (n < 0)
2907 {
2908 context->recordError(Error(GL_INVALID_VALUE, "n < 0"));
2909 return false;
2910 }
2911 return true;
2912}
2913
Jamie Madillc29968b2016-01-20 11:17:23 -05002914} // namespace gl