blob: eeafe450804e1db246c7106d06f972ec6d887070 [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
Corentin Walleze71ea192016-04-19 13:16:37 -04001171 if (context->getState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001172 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001173 context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001174 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001175 }
1176
1177 Query *queryObject = context->getQuery(id, true, target);
1178
1179 // check that name was obtained with glGenQueries
1180 if (!queryObject)
1181 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001182 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001183 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001184 }
1185
1186 // check for type mismatch
1187 if (queryObject->getType() != target)
1188 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001189 context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001190 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001191 }
1192
1193 return true;
1194}
1195
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001196bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1197{
1198 if (!context->getExtensions().occlusionQueryBoolean &&
1199 !context->getExtensions().disjointTimerQuery)
1200 {
1201 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1202 return false;
1203 }
1204
1205 return ValidateBeginQueryBase(context, target, id);
1206}
1207
1208bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001209{
1210 if (!ValidQueryType(context, target))
1211 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001212 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001213 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001214 }
1215
Shannon Woods53a94a82014-06-24 15:20:36 -04001216 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001217
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001218 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001219 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001220 context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001221 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001222 }
1223
Jamie Madill45c785d2014-05-13 14:09:34 -04001224 return true;
1225}
1226
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001227bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1228{
1229 if (!context->getExtensions().occlusionQueryBoolean &&
1230 !context->getExtensions().disjointTimerQuery)
1231 {
1232 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1233 return false;
1234 }
1235
1236 return ValidateEndQueryBase(context, target);
1237}
1238
1239bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1240{
1241 if (!context->getExtensions().disjointTimerQuery)
1242 {
1243 context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
1244 return false;
1245 }
1246
1247 if (target != GL_TIMESTAMP_EXT)
1248 {
1249 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
1250 return false;
1251 }
1252
1253 Query *queryObject = context->getQuery(id, true, target);
1254 if (queryObject == nullptr)
1255 {
1256 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
1257 return false;
1258 }
1259
1260 if (context->getState().isQueryActive(queryObject))
1261 {
1262 context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
1263 return false;
1264 }
1265
1266 return true;
1267}
1268
1269bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1270{
1271 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1272 {
1273 context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
1274 return false;
1275 }
1276
1277 switch (pname)
1278 {
1279 case GL_CURRENT_QUERY_EXT:
1280 if (target == GL_TIMESTAMP_EXT)
1281 {
1282 context->recordError(
1283 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1284 return false;
1285 }
1286 break;
1287 case GL_QUERY_COUNTER_BITS_EXT:
1288 if (!context->getExtensions().disjointTimerQuery ||
1289 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1290 {
1291 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1292 return false;
1293 }
1294 break;
1295 default:
1296 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1297 return false;
1298 }
1299
1300 return true;
1301}
1302
1303bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1304{
1305 if (!context->getExtensions().occlusionQueryBoolean &&
1306 !context->getExtensions().disjointTimerQuery)
1307 {
1308 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1309 return false;
1310 }
1311
1312 return ValidateGetQueryivBase(context, target, pname);
1313}
1314
1315bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1316{
1317 Query *queryObject = context->getQuery(id, false, GL_NONE);
1318
1319 if (!queryObject)
1320 {
1321 context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
1322 return false;
1323 }
1324
1325 if (context->getState().isQueryActive(queryObject))
1326 {
1327 context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
1328 return false;
1329 }
1330
1331 switch (pname)
1332 {
1333 case GL_QUERY_RESULT_EXT:
1334 case GL_QUERY_RESULT_AVAILABLE_EXT:
1335 break;
1336
1337 default:
1338 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
1339 return false;
1340 }
1341
1342 return true;
1343}
1344
1345bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1346{
1347 if (!context->getExtensions().disjointTimerQuery)
1348 {
1349 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1350 return false;
1351 }
1352 return ValidateGetQueryObjectValueBase(context, id, pname);
1353}
1354
1355bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1356{
1357 if (!context->getExtensions().disjointTimerQuery &&
1358 !context->getExtensions().occlusionQueryBoolean)
1359 {
1360 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1361 return false;
1362 }
1363 return ValidateGetQueryObjectValueBase(context, id, pname);
1364}
1365
1366bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1367{
1368 if (!context->getExtensions().disjointTimerQuery)
1369 {
1370 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1371 return false;
1372 }
1373 return ValidateGetQueryObjectValueBase(context, id, pname);
1374}
1375
1376bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1377{
1378 if (!context->getExtensions().disjointTimerQuery)
1379 {
1380 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1381 return false;
1382 }
1383 return ValidateGetQueryObjectValueBase(context, id, pname);
1384}
1385
Jamie Madill62d31cb2015-09-11 13:25:51 -04001386static bool ValidateUniformCommonBase(gl::Context *context,
1387 GLenum targetUniformType,
1388 GLint location,
1389 GLsizei count,
1390 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001391{
1392 if (count < 0)
1393 {
Geoff Langb1196682014-07-23 13:47:29 -04001394 context->recordError(Error(GL_INVALID_VALUE));
1395 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001396 }
1397
Geoff Lang7dd2e102014-11-10 15:19:26 -05001398 gl::Program *program = context->getState().getProgram();
1399 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001400 {
Geoff Langb1196682014-07-23 13:47:29 -04001401 context->recordError(Error(GL_INVALID_OPERATION));
1402 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001403 }
1404
Geoff Langd8605522016-04-13 10:19:12 -04001405 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001406 {
1407 // Silently ignore the uniform command
1408 return false;
1409 }
1410
Geoff Lang7dd2e102014-11-10 15:19:26 -05001411 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001412 {
Geoff Langb1196682014-07-23 13:47:29 -04001413 context->recordError(Error(GL_INVALID_OPERATION));
1414 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001415 }
1416
Jamie Madill62d31cb2015-09-11 13:25:51 -04001417 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001418
1419 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001420 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001421 {
Geoff Langb1196682014-07-23 13:47:29 -04001422 context->recordError(Error(GL_INVALID_OPERATION));
1423 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001424 }
1425
Jamie Madill62d31cb2015-09-11 13:25:51 -04001426 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001427 return true;
1428}
1429
Jamie Madillaa981bd2014-05-20 10:55:55 -04001430bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1431{
1432 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001433 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001434 {
Geoff Langb1196682014-07-23 13:47:29 -04001435 context->recordError(Error(GL_INVALID_OPERATION));
1436 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001437 }
1438
Jamie Madill62d31cb2015-09-11 13:25:51 -04001439 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001440 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1441 {
1442 return false;
1443 }
1444
Jamie Madillf2575982014-06-25 16:04:54 -04001445 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001446 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001447 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1448 {
Geoff Langb1196682014-07-23 13:47:29 -04001449 context->recordError(Error(GL_INVALID_OPERATION));
1450 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001451 }
1452
1453 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001454}
1455
1456bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1457 GLboolean transpose)
1458{
1459 // Check for ES3 uniform entry points
1460 int rows = VariableRowCount(matrixType);
1461 int cols = VariableColumnCount(matrixType);
1462 if (rows != cols && context->getClientVersion() < 3)
1463 {
Geoff Langb1196682014-07-23 13:47:29 -04001464 context->recordError(Error(GL_INVALID_OPERATION));
1465 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001466 }
1467
1468 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1469 {
Geoff Langb1196682014-07-23 13:47:29 -04001470 context->recordError(Error(GL_INVALID_VALUE));
1471 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001472 }
1473
Jamie Madill62d31cb2015-09-11 13:25:51 -04001474 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001475 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1476 {
1477 return false;
1478 }
1479
1480 if (uniform->type != matrixType)
1481 {
Geoff Langb1196682014-07-23 13:47:29 -04001482 context->recordError(Error(GL_INVALID_OPERATION));
1483 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001484 }
1485
1486 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001487}
1488
Jamie Madill893ab082014-05-16 16:56:10 -04001489bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1490{
1491 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1492 {
Geoff Langb1196682014-07-23 13:47:29 -04001493 context->recordError(Error(GL_INVALID_ENUM));
1494 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001495 }
1496
Jamie Madill0af26e12015-03-05 19:54:33 -05001497 const Caps &caps = context->getCaps();
1498
Jamie Madill893ab082014-05-16 16:56:10 -04001499 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1500 {
1501 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1502
Jamie Madill0af26e12015-03-05 19:54:33 -05001503 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001504 {
Geoff Langb1196682014-07-23 13:47:29 -04001505 context->recordError(Error(GL_INVALID_OPERATION));
1506 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001507 }
1508 }
1509
1510 switch (pname)
1511 {
1512 case GL_TEXTURE_BINDING_2D:
1513 case GL_TEXTURE_BINDING_CUBE_MAP:
1514 case GL_TEXTURE_BINDING_3D:
1515 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001516 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001517 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1518 if (!context->getExtensions().eglStreamConsumerExternal)
1519 {
1520 context->recordError(
1521 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1522 return false;
1523 }
1524 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001525
1526 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1527 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1528 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001529 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001530 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001531 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001532 {
Geoff Langb1196682014-07-23 13:47:29 -04001533 context->recordError(Error(GL_INVALID_OPERATION));
1534 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001535 }
1536
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001537 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001538 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001539 {
Geoff Langb1196682014-07-23 13:47:29 -04001540 context->recordError(Error(GL_INVALID_OPERATION));
1541 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001542 }
1543 }
1544 break;
1545
1546 default:
1547 break;
1548 }
1549
1550 // pname is valid, but there are no parameters to return
1551 if (numParams == 0)
1552 {
1553 return false;
1554 }
1555
1556 return true;
1557}
1558
Jamie Madillc29968b2016-01-20 11:17:23 -05001559bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1560 GLenum target,
1561 GLint level,
1562 GLenum internalformat,
1563 bool isSubImage,
1564 GLint xoffset,
1565 GLint yoffset,
1566 GLint zoffset,
1567 GLint x,
1568 GLint y,
1569 GLsizei width,
1570 GLsizei height,
1571 GLint border,
1572 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001573{
Jamie Madill560a8d82014-05-21 13:06:20 -04001574 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1575 {
Geoff Langb1196682014-07-23 13:47:29 -04001576 context->recordError(Error(GL_INVALID_VALUE));
1577 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001578 }
1579
1580 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1581 {
Geoff Langb1196682014-07-23 13:47:29 -04001582 context->recordError(Error(GL_INVALID_VALUE));
1583 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001584 }
1585
1586 if (border != 0)
1587 {
Geoff Langb1196682014-07-23 13:47:29 -04001588 context->recordError(Error(GL_INVALID_VALUE));
1589 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001590 }
1591
1592 if (!ValidMipLevel(context, target, level))
1593 {
Geoff Langb1196682014-07-23 13:47:29 -04001594 context->recordError(Error(GL_INVALID_VALUE));
1595 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001596 }
1597
Jamie Madillc29968b2016-01-20 11:17:23 -05001598 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001599 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001600 {
Geoff Langb1196682014-07-23 13:47:29 -04001601 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1602 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001603 }
1604
Jamie Madillc29968b2016-01-20 11:17:23 -05001605 const auto &state = context->getState();
1606 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001607 {
Geoff Langb1196682014-07-23 13:47:29 -04001608 context->recordError(Error(GL_INVALID_OPERATION));
1609 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001610 }
1611
Geoff Langaae65a42014-05-26 12:43:44 -04001612 const gl::Caps &caps = context->getCaps();
1613
Geoff Langaae65a42014-05-26 12:43:44 -04001614 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001615 switch (target)
1616 {
1617 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001618 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001619 break;
1620
1621 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1622 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1623 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1624 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1625 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1626 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001627 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001628 break;
1629
1630 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001631 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001632 break;
1633
1634 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001635 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001636 break;
1637
1638 default:
Geoff Langb1196682014-07-23 13:47:29 -04001639 context->recordError(Error(GL_INVALID_ENUM));
1640 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001641 }
1642
Jamie Madillc29968b2016-01-20 11:17:23 -05001643 gl::Texture *texture =
1644 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001645 if (!texture)
1646 {
Geoff Langb1196682014-07-23 13:47:29 -04001647 context->recordError(Error(GL_INVALID_OPERATION));
1648 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001649 }
1650
Geoff Lang69cce582015-09-17 13:20:36 -04001651 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001652 {
Geoff Langb1196682014-07-23 13:47:29 -04001653 context->recordError(Error(GL_INVALID_OPERATION));
1654 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001655 }
1656
Geoff Lang5d601382014-07-22 15:14:06 -04001657 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1658
1659 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001660 {
Geoff Langb1196682014-07-23 13:47:29 -04001661 context->recordError(Error(GL_INVALID_OPERATION));
1662 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001663 }
1664
Geoff Langa9be0dc2014-12-17 12:34:40 -05001665 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001666 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001667 context->recordError(Error(GL_INVALID_OPERATION));
1668 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001669 }
1670
1671 if (isSubImage)
1672 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001673 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1674 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1675 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001676 {
Geoff Langb1196682014-07-23 13:47:29 -04001677 context->recordError(Error(GL_INVALID_VALUE));
1678 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001679 }
1680 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001681 else
1682 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001683 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001684 {
Geoff Langb1196682014-07-23 13:47:29 -04001685 context->recordError(Error(GL_INVALID_VALUE));
1686 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001687 }
1688
Geoff Lang5d601382014-07-22 15:14:06 -04001689 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001690 {
Geoff Langb1196682014-07-23 13:47:29 -04001691 context->recordError(Error(GL_INVALID_ENUM));
1692 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001693 }
1694
1695 int maxLevelDimension = (maxDimension >> level);
1696 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1697 {
Geoff Langb1196682014-07-23 13:47:29 -04001698 context->recordError(Error(GL_INVALID_VALUE));
1699 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001700 }
1701 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001702
Geoff Langa9be0dc2014-12-17 12:34:40 -05001703 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001704 return true;
1705}
1706
Jamie Madillf25855c2015-11-03 11:06:18 -05001707static bool ValidateDrawBase(ValidationContext *context,
1708 GLenum mode,
1709 GLsizei count,
1710 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001711{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001712 switch (mode)
1713 {
1714 case GL_POINTS:
1715 case GL_LINES:
1716 case GL_LINE_LOOP:
1717 case GL_LINE_STRIP:
1718 case GL_TRIANGLES:
1719 case GL_TRIANGLE_STRIP:
1720 case GL_TRIANGLE_FAN:
1721 break;
1722 default:
Geoff Langb1196682014-07-23 13:47:29 -04001723 context->recordError(Error(GL_INVALID_ENUM));
1724 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001725 }
1726
Jamie Madill250d33f2014-06-06 17:09:03 -04001727 if (count < 0)
1728 {
Geoff Langb1196682014-07-23 13:47:29 -04001729 context->recordError(Error(GL_INVALID_VALUE));
1730 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001731 }
1732
Geoff Langb1196682014-07-23 13:47:29 -04001733 const State &state = context->getState();
1734
Jamie Madill250d33f2014-06-06 17:09:03 -04001735 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001736 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001737 {
Geoff Langb1196682014-07-23 13:47:29 -04001738 context->recordError(Error(GL_INVALID_OPERATION));
1739 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001740 }
1741
Geoff Lang3a86ad32015-09-01 11:47:05 -04001742 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001743 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001744 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1745 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1746 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1747 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1748 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1749 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1750 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001751 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001752 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1753 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001754 {
1755 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1756 // Section 6.10 of the WebGL 1.0 spec
1757 ERR(
1758 "This ANGLE implementation does not support separate front/back stencil "
1759 "writemasks, reference values, or stencil mask values.");
1760 context->recordError(Error(GL_INVALID_OPERATION));
1761 return false;
1762 }
Jamie Madillac528012014-06-20 13:21:23 -04001763 }
1764
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001765 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001766 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001767 {
Geoff Langb1196682014-07-23 13:47:29 -04001768 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1769 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001770 }
1771
Geoff Lang7dd2e102014-11-10 15:19:26 -05001772 gl::Program *program = state.getProgram();
1773 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001774 {
Geoff Langb1196682014-07-23 13:47:29 -04001775 context->recordError(Error(GL_INVALID_OPERATION));
1776 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001777 }
1778
Geoff Lang7dd2e102014-11-10 15:19:26 -05001779 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001780 {
Geoff Langb1196682014-07-23 13:47:29 -04001781 context->recordError(Error(GL_INVALID_OPERATION));
1782 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001783 }
1784
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001785 // Uniform buffer validation
1786 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1787 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001788 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001789 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001790 const OffsetBindingPointer<Buffer> &uniformBuffer =
1791 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001792
Geoff Lang5d124a62015-09-15 13:03:27 -04001793 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001794 {
1795 // undefined behaviour
1796 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1797 return false;
1798 }
1799
Geoff Lang5d124a62015-09-15 13:03:27 -04001800 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001801 if (uniformBufferSize == 0)
1802 {
1803 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001804 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001805 }
1806
Jamie Madill62d31cb2015-09-11 13:25:51 -04001807 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001808 {
1809 // undefined behaviour
1810 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1811 return false;
1812 }
1813 }
1814
Jamie Madill250d33f2014-06-06 17:09:03 -04001815 // No-op if zero count
1816 return (count > 0);
1817}
1818
Geoff Langb1196682014-07-23 13:47:29 -04001819bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001820{
Jamie Madillfd716582014-06-06 17:09:04 -04001821 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001822 {
Geoff Langb1196682014-07-23 13:47:29 -04001823 context->recordError(Error(GL_INVALID_VALUE));
1824 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001825 }
1826
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001827 const State &state = context->getState();
1828 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001829 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1830 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001831 {
1832 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1833 // that does not match the current transform feedback object's draw mode (if transform feedback
1834 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001835 context->recordError(Error(GL_INVALID_OPERATION));
1836 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001837 }
1838
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001839 if (!ValidateDrawBase(context, mode, count, primcount))
1840 {
1841 return false;
1842 }
1843
1844 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001845 {
1846 return false;
1847 }
1848
1849 return true;
1850}
1851
Geoff Langb1196682014-07-23 13:47:29 -04001852bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001853{
1854 if (primcount < 0)
1855 {
Geoff Langb1196682014-07-23 13:47:29 -04001856 context->recordError(Error(GL_INVALID_VALUE));
1857 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001858 }
1859
Jamie Madill2b976812014-08-25 15:47:49 -04001860 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001861 {
1862 return false;
1863 }
1864
1865 // No-op if zero primitive count
1866 return (primcount > 0);
1867}
1868
Geoff Lang87a93302014-09-16 13:29:43 -04001869static bool ValidateDrawInstancedANGLE(Context *context)
1870{
1871 // Verify there is at least one active attribute with a divisor of zero
1872 const gl::State& state = context->getState();
1873
Geoff Lang7dd2e102014-11-10 15:19:26 -05001874 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001875
1876 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001877 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001878 {
1879 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001880 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001881 {
1882 return true;
1883 }
1884 }
1885
1886 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1887 "has a divisor of zero."));
1888 return false;
1889}
1890
1891bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1892{
1893 if (!ValidateDrawInstancedANGLE(context))
1894 {
1895 return false;
1896 }
1897
1898 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1899}
1900
Jamie Madillf25855c2015-11-03 11:06:18 -05001901bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001902 GLenum mode,
1903 GLsizei count,
1904 GLenum type,
1905 const GLvoid *indices,
1906 GLsizei primcount,
1907 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001908{
Jamie Madill250d33f2014-06-06 17:09:03 -04001909 switch (type)
1910 {
1911 case GL_UNSIGNED_BYTE:
1912 case GL_UNSIGNED_SHORT:
1913 break;
1914 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001915 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001916 {
Geoff Langb1196682014-07-23 13:47:29 -04001917 context->recordError(Error(GL_INVALID_ENUM));
1918 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001919 }
1920 break;
1921 default:
Geoff Langb1196682014-07-23 13:47:29 -04001922 context->recordError(Error(GL_INVALID_ENUM));
1923 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001924 }
1925
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001926 const State &state = context->getState();
1927
1928 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001929 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001930 {
1931 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1932 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001933 context->recordError(Error(GL_INVALID_OPERATION));
1934 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001935 }
1936
1937 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001938 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001939 {
Geoff Langb1196682014-07-23 13:47:29 -04001940 context->recordError(Error(GL_INVALID_OPERATION));
1941 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001942 }
1943
Jamie Madill2b976812014-08-25 15:47:49 -04001944 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001945 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001946 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001947 {
Geoff Langb1196682014-07-23 13:47:29 -04001948 context->recordError(Error(GL_INVALID_OPERATION));
1949 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001950 }
1951
Jamie Madillae3000b2014-08-25 15:47:51 -04001952 if (elementArrayBuffer)
1953 {
1954 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1955
1956 GLint64 offset = reinterpret_cast<GLint64>(indices);
1957 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1958
1959 // check for integer overflows
1960 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1961 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1962 {
Geoff Langb1196682014-07-23 13:47:29 -04001963 context->recordError(Error(GL_OUT_OF_MEMORY));
1964 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001965 }
1966
1967 // Check for reading past the end of the bound buffer object
1968 if (byteCount > elementArrayBuffer->getSize())
1969 {
Geoff Langb1196682014-07-23 13:47:29 -04001970 context->recordError(Error(GL_INVALID_OPERATION));
1971 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001972 }
1973 }
1974 else if (!indices)
1975 {
1976 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001977 context->recordError(Error(GL_INVALID_OPERATION));
1978 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001979 }
1980
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001981 if (!ValidateDrawBase(context, mode, count, primcount))
1982 {
1983 return false;
1984 }
1985
Jamie Madill2b976812014-08-25 15:47:49 -04001986 // Use max index to validate if our vertex buffers are large enough for the pull.
1987 // TODO: offer fast path, with disabled index validation.
1988 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1989 if (elementArrayBuffer)
1990 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001991 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001992 Error error =
1993 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1994 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001995 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001996 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001997 context->recordError(error);
1998 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001999 }
2000 }
2001 else
2002 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002003 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002004 }
2005
Jamie Madille79b1e12015-11-04 16:36:37 -05002006 // If we use an index greater than our maximum supported index range, return an error.
2007 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2008 // return an error if possible here.
2009 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2010 {
2011 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
2012 return false;
2013 }
2014
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002015 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002016 {
2017 return false;
2018 }
2019
Geoff Lang3edfe032015-09-04 16:38:24 -04002020 // No op if there are no real indices in the index data (all are primitive restart).
2021 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002022}
2023
Geoff Langb1196682014-07-23 13:47:29 -04002024bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002025 GLenum mode,
2026 GLsizei count,
2027 GLenum type,
2028 const GLvoid *indices,
2029 GLsizei primcount,
2030 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002031{
2032 if (primcount < 0)
2033 {
Geoff Langb1196682014-07-23 13:47:29 -04002034 context->recordError(Error(GL_INVALID_VALUE));
2035 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002036 }
2037
Jamie Madill2b976812014-08-25 15:47:49 -04002038 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002039 {
2040 return false;
2041 }
2042
2043 // No-op zero primitive count
2044 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002045}
2046
Geoff Lang3edfe032015-09-04 16:38:24 -04002047bool ValidateDrawElementsInstancedANGLE(Context *context,
2048 GLenum mode,
2049 GLsizei count,
2050 GLenum type,
2051 const GLvoid *indices,
2052 GLsizei primcount,
2053 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002054{
2055 if (!ValidateDrawInstancedANGLE(context))
2056 {
2057 return false;
2058 }
2059
2060 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2061}
2062
Geoff Langb1196682014-07-23 13:47:29 -04002063bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002064 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002065{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002066 if (!ValidFramebufferTarget(target))
2067 {
Geoff Langb1196682014-07-23 13:47:29 -04002068 context->recordError(Error(GL_INVALID_ENUM));
2069 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002070 }
2071
2072 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002073 {
2074 return false;
2075 }
2076
Jamie Madill55ec3b12014-07-03 10:38:57 -04002077 if (texture != 0)
2078 {
2079 gl::Texture *tex = context->getTexture(texture);
2080
2081 if (tex == NULL)
2082 {
Geoff Langb1196682014-07-23 13:47:29 -04002083 context->recordError(Error(GL_INVALID_OPERATION));
2084 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002085 }
2086
2087 if (level < 0)
2088 {
Geoff Langb1196682014-07-23 13:47:29 -04002089 context->recordError(Error(GL_INVALID_VALUE));
2090 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002091 }
2092 }
2093
Shannon Woods53a94a82014-06-24 15:20:36 -04002094 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002095 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002096
Jamie Madill84115c92015-04-23 15:00:07 -04002097 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002098 {
Jamie Madill84115c92015-04-23 15:00:07 -04002099 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002100 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002101 }
2102
2103 return true;
2104}
2105
Geoff Langb1196682014-07-23 13:47:29 -04002106bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002107 GLenum textarget, GLuint texture, GLint level)
2108{
Geoff Lang95663912015-04-02 15:54:45 -04002109 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2110 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002111 {
Geoff Langb1196682014-07-23 13:47:29 -04002112 context->recordError(Error(GL_INVALID_VALUE));
2113 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002114 }
2115
2116 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002117 {
2118 return false;
2119 }
2120
Jamie Madill55ec3b12014-07-03 10:38:57 -04002121 if (texture != 0)
2122 {
2123 gl::Texture *tex = context->getTexture(texture);
2124 ASSERT(tex);
2125
Jamie Madill2a6564e2014-07-11 09:53:19 -04002126 const gl::Caps &caps = context->getCaps();
2127
Jamie Madill55ec3b12014-07-03 10:38:57 -04002128 switch (textarget)
2129 {
2130 case GL_TEXTURE_2D:
2131 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002132 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002133 {
Geoff Langb1196682014-07-23 13:47:29 -04002134 context->recordError(Error(GL_INVALID_VALUE));
2135 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002136 }
2137 if (tex->getTarget() != GL_TEXTURE_2D)
2138 {
Geoff Langb1196682014-07-23 13:47:29 -04002139 context->recordError(Error(GL_INVALID_OPERATION));
2140 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002141 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002142 }
2143 break;
2144
2145 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2146 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2147 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2148 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2149 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2150 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2151 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002152 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002153 {
Geoff Langb1196682014-07-23 13:47:29 -04002154 context->recordError(Error(GL_INVALID_VALUE));
2155 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002156 }
2157 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2158 {
Geoff Langb1196682014-07-23 13:47:29 -04002159 context->recordError(Error(GL_INVALID_OPERATION));
2160 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002161 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002162 }
2163 break;
2164
2165 default:
Geoff Langb1196682014-07-23 13:47:29 -04002166 context->recordError(Error(GL_INVALID_ENUM));
2167 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002168 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002169
2170 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2171 if (internalFormatInfo.compressed)
2172 {
2173 context->recordError(Error(GL_INVALID_OPERATION));
2174 return false;
2175 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002176 }
2177
Jamie Madill570f7c82014-07-03 10:38:54 -04002178 return true;
2179}
2180
Geoff Langb1196682014-07-23 13:47:29 -04002181bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002182{
2183 if (program == 0)
2184 {
Geoff Langb1196682014-07-23 13:47:29 -04002185 context->recordError(Error(GL_INVALID_VALUE));
2186 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002187 }
2188
Dian Xiang769769a2015-09-09 15:20:08 -07002189 gl::Program *programObject = GetValidProgram(context, program);
2190 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002191 {
2192 return false;
2193 }
2194
Jamie Madill0063c512014-08-25 15:47:53 -04002195 if (!programObject || !programObject->isLinked())
2196 {
Geoff Langb1196682014-07-23 13:47:29 -04002197 context->recordError(Error(GL_INVALID_OPERATION));
2198 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002199 }
2200
Geoff Lang7dd2e102014-11-10 15:19:26 -05002201 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002202 {
Geoff Langb1196682014-07-23 13:47:29 -04002203 context->recordError(Error(GL_INVALID_OPERATION));
2204 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002205 }
2206
Jamie Madill0063c512014-08-25 15:47:53 -04002207 return true;
2208}
2209
Geoff Langb1196682014-07-23 13:47:29 -04002210bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002211{
2212 return ValidateGetUniformBase(context, program, location);
2213}
2214
Geoff Langb1196682014-07-23 13:47:29 -04002215bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002216{
Jamie Madill78f41802014-08-25 15:47:55 -04002217 return ValidateGetUniformBase(context, program, location);
2218}
2219
Geoff Langb1196682014-07-23 13:47:29 -04002220static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002221{
2222 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002223 {
Jamie Madill78f41802014-08-25 15:47:55 -04002224 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002225 }
2226
Jamie Madilla502c742014-08-28 17:19:13 -04002227 gl::Program *programObject = context->getProgram(program);
2228 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002229
Jamie Madill78f41802014-08-25 15:47:55 -04002230 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002231 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2232 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002233 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002234 {
Geoff Langb1196682014-07-23 13:47:29 -04002235 context->recordError(Error(GL_INVALID_OPERATION));
2236 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002237 }
2238
2239 return true;
2240}
2241
Geoff Langb1196682014-07-23 13:47:29 -04002242bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002243{
Jamie Madill78f41802014-08-25 15:47:55 -04002244 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002245}
2246
Geoff Langb1196682014-07-23 13:47:29 -04002247bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002248{
Jamie Madill78f41802014-08-25 15:47:55 -04002249 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002250}
2251
Austin Kinross08332632015-05-05 13:35:47 -07002252bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2253 const GLenum *attachments, bool defaultFramebuffer)
2254{
2255 if (numAttachments < 0)
2256 {
2257 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2258 return false;
2259 }
2260
2261 for (GLsizei i = 0; i < numAttachments; ++i)
2262 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002263 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002264 {
2265 if (defaultFramebuffer)
2266 {
2267 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2268 return false;
2269 }
2270
2271 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2272 {
2273 context->recordError(Error(GL_INVALID_OPERATION,
2274 "Requested color attachment is greater than the maximum supported color attachments"));
2275 return false;
2276 }
2277 }
2278 else
2279 {
2280 switch (attachments[i])
2281 {
2282 case GL_DEPTH_ATTACHMENT:
2283 case GL_STENCIL_ATTACHMENT:
2284 case GL_DEPTH_STENCIL_ATTACHMENT:
2285 if (defaultFramebuffer)
2286 {
2287 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2288 return false;
2289 }
2290 break;
2291 case GL_COLOR:
2292 case GL_DEPTH:
2293 case GL_STENCIL:
2294 if (!defaultFramebuffer)
2295 {
2296 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2297 return false;
2298 }
2299 break;
2300 default:
2301 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2302 return false;
2303 }
2304 }
2305 }
2306
2307 return true;
2308}
2309
Austin Kinross6ee1e782015-05-29 17:05:37 -07002310bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2311{
2312 // Note that debug marker calls must not set error state
2313
2314 if (length < 0)
2315 {
2316 return false;
2317 }
2318
2319 if (marker == nullptr)
2320 {
2321 return false;
2322 }
2323
2324 return true;
2325}
2326
2327bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2328{
2329 // Note that debug marker calls must not set error state
2330
2331 if (length < 0)
2332 {
2333 return false;
2334 }
2335
2336 if (length > 0 && marker == nullptr)
2337 {
2338 return false;
2339 }
2340
2341 return true;
2342}
2343
Geoff Langdcab33b2015-07-21 13:03:16 -04002344bool ValidateEGLImageTargetTexture2DOES(Context *context,
2345 egl::Display *display,
2346 GLenum target,
2347 egl::Image *image)
2348{
Geoff Langa8406172015-07-21 16:53:39 -04002349 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2350 {
2351 context->recordError(Error(GL_INVALID_OPERATION));
2352 return false;
2353 }
2354
2355 switch (target)
2356 {
2357 case GL_TEXTURE_2D:
2358 break;
2359
2360 default:
2361 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2362 return false;
2363 }
2364
2365 if (!display->isValidImage(image))
2366 {
2367 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2368 return false;
2369 }
2370
2371 if (image->getSamples() > 0)
2372 {
2373 context->recordError(Error(GL_INVALID_OPERATION,
2374 "cannot create a 2D texture from a multisampled EGL image."));
2375 return false;
2376 }
2377
2378 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2379 if (!textureCaps.texturable)
2380 {
2381 context->recordError(Error(GL_INVALID_OPERATION,
2382 "EGL image internal format is not supported as a texture."));
2383 return false;
2384 }
2385
Geoff Langdcab33b2015-07-21 13:03:16 -04002386 return true;
2387}
2388
2389bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2390 egl::Display *display,
2391 GLenum target,
2392 egl::Image *image)
2393{
Geoff Langa8406172015-07-21 16:53:39 -04002394 if (!context->getExtensions().eglImage)
2395 {
2396 context->recordError(Error(GL_INVALID_OPERATION));
2397 return false;
2398 }
2399
2400 switch (target)
2401 {
2402 case GL_RENDERBUFFER:
2403 break;
2404
2405 default:
2406 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2407 return false;
2408 }
2409
2410 if (!display->isValidImage(image))
2411 {
2412 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2413 return false;
2414 }
2415
2416 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2417 if (!textureCaps.renderable)
2418 {
2419 context->recordError(Error(
2420 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2421 return false;
2422 }
2423
Geoff Langdcab33b2015-07-21 13:03:16 -04002424 return true;
2425}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002426
2427bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2428{
Geoff Lang36167ab2015-12-07 10:27:14 -05002429 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002430 {
2431 // The default VAO should always exist
2432 ASSERT(array != 0);
2433 context->recordError(Error(GL_INVALID_OPERATION));
2434 return false;
2435 }
2436
2437 return true;
2438}
2439
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002440bool ValidateLinkProgram(Context *context, GLuint program)
2441{
2442 if (context->hasActiveTransformFeedback(program))
2443 {
2444 // ES 3.0.4 section 2.15 page 91
2445 context->recordError(Error(GL_INVALID_OPERATION,
2446 "Cannot link program while program is associated with an active "
2447 "transform feedback object."));
2448 return false;
2449 }
2450 return true;
2451}
2452
Geoff Langc5629752015-12-07 16:29:04 -05002453bool ValidateProgramBinaryBase(Context *context,
2454 GLuint program,
2455 GLenum binaryFormat,
2456 const void *binary,
2457 GLint length)
2458{
2459 Program *programObject = GetValidProgram(context, program);
2460 if (programObject == nullptr)
2461 {
2462 return false;
2463 }
2464
2465 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2466 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2467 programBinaryFormats.end())
2468 {
2469 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2470 return false;
2471 }
2472
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002473 if (context->hasActiveTransformFeedback(program))
2474 {
2475 // ES 3.0.4 section 2.15 page 91
2476 context->recordError(Error(GL_INVALID_OPERATION,
2477 "Cannot change program binary while program is associated with "
2478 "an active transform feedback object."));
2479 return false;
2480 }
2481
Geoff Langc5629752015-12-07 16:29:04 -05002482 return true;
2483}
2484
2485bool ValidateGetProgramBinaryBase(Context *context,
2486 GLuint program,
2487 GLsizei bufSize,
2488 GLsizei *length,
2489 GLenum *binaryFormat,
2490 void *binary)
2491{
2492 Program *programObject = GetValidProgram(context, program);
2493 if (programObject == nullptr)
2494 {
2495 return false;
2496 }
2497
2498 if (!programObject->isLinked())
2499 {
2500 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2501 return false;
2502 }
2503
2504 return true;
2505}
Jamie Madillc29968b2016-01-20 11:17:23 -05002506
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002507bool ValidateUseProgram(Context *context, GLuint program)
2508{
2509 if (program != 0)
2510 {
2511 Program *programObject = context->getProgram(program);
2512 if (!programObject)
2513 {
2514 // ES 3.1.0 section 7.3 page 72
2515 if (context->getShader(program))
2516 {
2517 context->recordError(
2518 Error(GL_INVALID_OPERATION,
2519 "Attempted to use a single shader instead of a shader program."));
2520 return false;
2521 }
2522 else
2523 {
2524 context->recordError(Error(GL_INVALID_VALUE, "Program invalid."));
2525 return false;
2526 }
2527 }
2528 if (!programObject->isLinked())
2529 {
2530 context->recordError(Error(GL_INVALID_OPERATION, "Program not linked."));
2531 return false;
2532 }
2533 }
2534 if (context->getState().isTransformFeedbackActiveUnpaused())
2535 {
2536 // ES 3.0.4 section 2.15 page 91
2537 context->recordError(
2538 Error(GL_INVALID_OPERATION,
2539 "Cannot change active program while transform feedback is unpaused."));
2540 return false;
2541 }
2542
2543 return true;
2544}
2545
Jamie Madillc29968b2016-01-20 11:17:23 -05002546bool ValidateCopyTexImage2D(ValidationContext *context,
2547 GLenum target,
2548 GLint level,
2549 GLenum internalformat,
2550 GLint x,
2551 GLint y,
2552 GLsizei width,
2553 GLsizei height,
2554 GLint border)
2555{
2556 if (context->getClientVersion() < 3)
2557 {
2558 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2559 0, x, y, width, height, border);
2560 }
2561
2562 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002563 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2564 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002565}
Jamie Madillc29968b2016-01-20 11:17:23 -05002566
2567bool ValidateFramebufferRenderbuffer(Context *context,
2568 GLenum target,
2569 GLenum attachment,
2570 GLenum renderbuffertarget,
2571 GLuint renderbuffer)
2572{
2573 if (!ValidFramebufferTarget(target) ||
2574 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2575 {
2576 context->recordError(Error(GL_INVALID_ENUM));
2577 return false;
2578 }
2579
2580 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2581 renderbuffertarget, renderbuffer);
2582}
2583
2584bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2585{
2586 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2587 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2588 {
2589 context->recordError(
2590 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2591 return false;
2592 }
2593
2594 ASSERT(context->getState().getDrawFramebuffer());
2595 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2596 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2597
2598 // This should come first before the check for the default frame buffer
2599 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2600 // rather than INVALID_OPERATION
2601 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2602 {
2603 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2604
2605 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002606 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2607 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002608 {
2609 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002610 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2611 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2612 // 3.1 is still a bit ambiguous about the error, but future specs are
2613 // expected to clarify that GL_INVALID_ENUM is the correct error.
2614 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
2615 return false;
2616 }
2617 else if (bufs[colorAttachment] >= maxColorAttachment)
2618 {
2619 context->recordError(
2620 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002621 return false;
2622 }
2623 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2624 frameBufferId != 0)
2625 {
2626 // INVALID_OPERATION-GL is bound to buffer and ith argument
2627 // is not COLOR_ATTACHMENTi or NONE
2628 context->recordError(
2629 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2630 return false;
2631 }
2632 }
2633
2634 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2635 // and n is not 1 or bufs is bound to value other than BACK and NONE
2636 if (frameBufferId == 0)
2637 {
2638 if (n != 1)
2639 {
2640 context->recordError(Error(GL_INVALID_OPERATION,
2641 "n must be 1 when GL is bound to the default framebuffer"));
2642 return false;
2643 }
2644
2645 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2646 {
2647 context->recordError(Error(
2648 GL_INVALID_OPERATION,
2649 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2650 return false;
2651 }
2652 }
2653
2654 return true;
2655}
2656
2657bool ValidateCopyTexSubImage2D(Context *context,
2658 GLenum target,
2659 GLint level,
2660 GLint xoffset,
2661 GLint yoffset,
2662 GLint x,
2663 GLint y,
2664 GLsizei width,
2665 GLsizei height)
2666{
2667 if (context->getClientVersion() < 3)
2668 {
2669 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2670 yoffset, x, y, width, height, 0);
2671 }
2672
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002673 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2674 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002675}
2676
Olli Etuaho4f667482016-03-30 15:56:35 +03002677bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2678{
2679 if (!ValidBufferTarget(context, target))
2680 {
2681 context->recordError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
2682 return false;
2683 }
2684
2685 if (pname != GL_BUFFER_MAP_POINTER)
2686 {
2687 context->recordError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
2688 return false;
2689 }
2690
2691 Buffer *buffer = context->getState().getTargetBuffer(target);
2692
2693 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2694 // target bound to zero generate an INVALID_OPERATION error."
2695 // GLES 3.1 section 6.6 explicitly specifies this error.
2696 if (!buffer)
2697 {
2698 context->recordError(
2699 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2700 return false;
2701 }
2702
2703 return true;
2704}
2705
2706bool ValidateUnmapBufferBase(Context *context, GLenum target)
2707{
2708 if (!ValidBufferTarget(context, target))
2709 {
2710 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2711 return false;
2712 }
2713
2714 Buffer *buffer = context->getState().getTargetBuffer(target);
2715
2716 if (buffer == nullptr || !buffer->isMapped())
2717 {
2718 context->recordError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
2719 return false;
2720 }
2721
2722 return true;
2723}
2724
2725bool ValidateMapBufferRangeBase(Context *context,
2726 GLenum target,
2727 GLintptr offset,
2728 GLsizeiptr length,
2729 GLbitfield access)
2730{
2731 if (!ValidBufferTarget(context, target))
2732 {
2733 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2734 return false;
2735 }
2736
2737 if (offset < 0 || length < 0)
2738 {
2739 context->recordError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
2740 return false;
2741 }
2742
2743 Buffer *buffer = context->getState().getTargetBuffer(target);
2744
2745 if (!buffer)
2746 {
2747 context->recordError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
2748 return false;
2749 }
2750
2751 // Check for buffer overflow
2752 size_t offsetSize = static_cast<size_t>(offset);
2753 size_t lengthSize = static_cast<size_t>(length);
2754
2755 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2756 offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
2757 {
2758 context->recordError(
2759 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2760 return false;
2761 }
2762
2763 // Check for invalid bits in the mask
2764 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2765 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2766 GL_MAP_UNSYNCHRONIZED_BIT;
2767
2768 if (access & ~(allAccessBits))
2769 {
2770 context->recordError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
2771 return false;
2772 }
2773
2774 if (length == 0)
2775 {
2776 context->recordError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
2777 return false;
2778 }
2779
2780 if (buffer->isMapped())
2781 {
2782 context->recordError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
2783 return false;
2784 }
2785
2786 // Check for invalid bit combinations
2787 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2788 {
2789 context->recordError(
2790 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2791 return false;
2792 }
2793
2794 GLbitfield writeOnlyBits =
2795 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2796
2797 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2798 {
2799 context->recordError(Error(GL_INVALID_OPERATION,
2800 "Invalid access bits when mapping buffer for reading: 0x%X.",
2801 access));
2802 return false;
2803 }
2804
2805 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2806 {
2807 context->recordError(Error(
2808 GL_INVALID_OPERATION,
2809 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2810 return false;
2811 }
2812 return true;
2813}
2814
2815bool ValidateFlushMappedBufferRangeBase(Context *context,
2816 GLenum target,
2817 GLintptr offset,
2818 GLsizeiptr length)
2819{
2820 if (offset < 0 || length < 0)
2821 {
2822 context->recordError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
2823 return false;
2824 }
2825
2826 if (!ValidBufferTarget(context, target))
2827 {
2828 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2829 return false;
2830 }
2831
2832 Buffer *buffer = context->getState().getTargetBuffer(target);
2833
2834 if (buffer == nullptr)
2835 {
2836 context->recordError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
2837 return false;
2838 }
2839
2840 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2841 {
2842 context->recordError(Error(
2843 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2844 return false;
2845 }
2846
2847 // Check for buffer overflow
2848 size_t offsetSize = static_cast<size_t>(offset);
2849 size_t lengthSize = static_cast<size_t>(length);
2850
2851 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2852 offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
2853 {
2854 context->recordError(
2855 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2856 return false;
2857 }
2858
2859 return true;
2860}
2861
Olli Etuaho41997e72016-03-10 13:38:39 +02002862bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2863{
2864 return ValidateGenOrDelete(context, n);
2865}
2866
2867bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2868{
2869 return ValidateGenOrDelete(context, n);
2870}
2871
2872bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2873{
2874 return ValidateGenOrDelete(context, n);
2875}
2876
2877bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2878{
2879 return ValidateGenOrDelete(context, n);
2880}
2881
2882bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2883{
2884 return ValidateGenOrDelete(context, n);
2885}
2886
2887bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2888{
2889 return ValidateGenOrDelete(context, n);
2890}
2891
2892bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2893{
2894 return ValidateGenOrDelete(context, n);
2895}
2896
2897bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2898{
2899 return ValidateGenOrDelete(context, n);
2900}
2901
2902bool ValidateGenOrDelete(Context *context, GLint n)
2903{
2904 if (n < 0)
2905 {
2906 context->recordError(Error(GL_INVALID_VALUE, "n < 0"));
2907 return false;
2908 }
2909 return true;
2910}
2911
Jamie Madillc29968b2016-01-20 11:17:23 -05002912} // namespace gl