blob: 0b589ff2e9affb6993acd7cec8c0e912ae039ea7 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040071 GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
Jamie Madill1ca74672015-07-21 15:14:11 -040072
73 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
74 // We can return INVALID_OPERATION if our vertex attribute does not have
75 // enough backing data.
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040076 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040077 {
Jamie Madill437fa652016-05-03 15:13:24 -040078 context->handleError(
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040079 Error(GL_INVALID_OPERATION,
80 "Vertex buffer is not big enough for the draw call"));
Jamie Madill1ca74672015-07-21 15:14:11 -040081 return false;
82 }
83 }
84 }
85 else if (attrib.pointer == NULL)
86 {
87 // This is an application error that would normally result in a crash,
88 // but we catch it and return an error
Jamie Madill437fa652016-05-03 15:13:24 -040089 context->handleError(Error(
Jamie Madill1ca74672015-07-21 15:14:11 -040090 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
91 return false;
92 }
93 }
94 }
95
96 return true;
97}
98
99} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400100
Geoff Lang0550d032014-01-30 11:29:07 -0500101bool ValidCap(const Context *context, GLenum cap)
102{
103 switch (cap)
104 {
105 case GL_CULL_FACE:
106 case GL_POLYGON_OFFSET_FILL:
107 case GL_SAMPLE_ALPHA_TO_COVERAGE:
108 case GL_SAMPLE_COVERAGE:
109 case GL_SCISSOR_TEST:
110 case GL_STENCIL_TEST:
111 case GL_DEPTH_TEST:
112 case GL_BLEND:
113 case GL_DITHER:
114 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500115
Geoff Lang0550d032014-01-30 11:29:07 -0500116 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
117 case GL_RASTERIZER_DISCARD:
118 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500119
120 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
121 case GL_DEBUG_OUTPUT:
122 return context->getExtensions().debug;
123
Geoff Lang0550d032014-01-30 11:29:07 -0500124 default:
125 return false;
126 }
127}
128
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500129bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400130{
Jamie Madilld7460c72014-01-21 16:38:14 -0500131 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400132 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500133 case GL_TEXTURE_2D:
134 case GL_TEXTURE_CUBE_MAP:
135 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400136
Jamie Madilld7460c72014-01-21 16:38:14 -0500137 case GL_TEXTURE_3D:
138 case GL_TEXTURE_2D_ARRAY:
139 return (context->getClientVersion() >= 3);
140
141 default:
142 return false;
143 }
Jamie Madill35d15012013-10-07 10:46:37 -0400144}
145
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500146bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
147{
148 switch (target)
149 {
150 case GL_TEXTURE_2D:
151 case GL_TEXTURE_CUBE_MAP:
152 return true;
153
154 default:
155 return false;
156 }
157}
158
159bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
160{
161 switch (target)
162 {
163 case GL_TEXTURE_3D:
164 case GL_TEXTURE_2D_ARRAY:
165 return (context->getClientVersion() >= 3);
166
167 default:
168 return false;
169 }
170}
171
Ian Ewellbda75592016-04-18 17:25:54 -0400172// Most texture GL calls are not compatible with external textures, so we have a separate validation
173// function for use in the GL calls that do
174bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
175{
176 return (target == GL_TEXTURE_EXTERNAL_OES) &&
177 (context->getExtensions().eglImageExternal ||
178 context->getExtensions().eglStreamConsumerExternal);
179}
180
Shannon Woods4dfed832014-03-17 20:03:39 -0400181// This function differs from ValidTextureTarget in that the target must be
182// usable as the destination of a 2D operation-- so a cube face is valid, but
183// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400184// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500185bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400186{
187 switch (target)
188 {
189 case GL_TEXTURE_2D:
190 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
191 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
192 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
193 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
194 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
195 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
196 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500197 default:
198 return false;
199 }
200}
201
202bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
203{
204 switch (target)
205 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400206 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500207 case GL_TEXTURE_2D_ARRAY:
208 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400209 default:
210 return false;
211 }
212}
213
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500214bool ValidFramebufferTarget(GLenum target)
215{
Geoff Langd4475812015-03-18 10:53:05 -0400216 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
217 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500218
219 switch (target)
220 {
221 case GL_FRAMEBUFFER: return true;
222 case GL_READ_FRAMEBUFFER: return true;
223 case GL_DRAW_FRAMEBUFFER: return true;
224 default: return false;
225 }
226}
227
Jamie Madill8c96d582014-03-05 15:01:23 -0500228bool ValidBufferTarget(const Context *context, GLenum target)
229{
230 switch (target)
231 {
232 case GL_ARRAY_BUFFER:
233 case GL_ELEMENT_ARRAY_BUFFER:
234 return true;
235
Jamie Madill8c96d582014-03-05 15:01:23 -0500236 case GL_PIXEL_PACK_BUFFER:
237 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400238 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400239
Shannon Woodsb3801742014-03-27 14:59:19 -0400240 case GL_COPY_READ_BUFFER:
241 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500242 case GL_TRANSFORM_FEEDBACK_BUFFER:
243 case GL_UNIFORM_BUFFER:
244 return (context->getClientVersion() >= 3);
245
246 default:
247 return false;
248 }
249}
250
Jamie Madill70656a62014-03-05 15:01:26 -0500251bool ValidBufferParameter(const Context *context, GLenum pname)
252{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400253 const Extensions &extensions = context->getExtensions();
254
Jamie Madill70656a62014-03-05 15:01:26 -0500255 switch (pname)
256 {
257 case GL_BUFFER_USAGE:
258 case GL_BUFFER_SIZE:
259 return true;
260
Geoff Langcc6f55d2015-03-20 13:01:02 -0400261 case GL_BUFFER_ACCESS_OES:
262 return extensions.mapBuffer;
263
264 case GL_BUFFER_MAPPED:
265 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
266 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
267
Jamie Madill70656a62014-03-05 15:01:26 -0500268 // GL_BUFFER_MAP_POINTER is a special case, and may only be
269 // queried with GetBufferPointerv
270 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500271 case GL_BUFFER_MAP_OFFSET:
272 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400273 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500274
275 default:
276 return false;
277 }
278}
279
Jamie Madillc29968b2016-01-20 11:17:23 -0500280bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400281{
Jamie Madillc29968b2016-01-20 11:17:23 -0500282 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400283 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400284 switch (target)
285 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500286 case GL_TEXTURE_2D:
287 maxDimension = caps.max2DTextureSize;
288 break;
Geoff Langce635692013-09-24 13:56:32 -0400289 case GL_TEXTURE_CUBE_MAP:
290 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
291 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
292 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
293 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
294 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500295 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
296 maxDimension = caps.maxCubeMapTextureSize;
297 break;
298 case GL_TEXTURE_3D:
299 maxDimension = caps.max3DTextureSize;
300 break;
301 case GL_TEXTURE_2D_ARRAY:
302 maxDimension = caps.max2DTextureSize;
303 break;
Geoff Langce635692013-09-24 13:56:32 -0400304 default: UNREACHABLE();
305 }
306
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700307 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400308}
309
Austin Kinross08528e12015-10-07 16:24:40 -0700310bool ValidImageSizeParameters(const Context *context,
311 GLenum target,
312 GLint level,
313 GLsizei width,
314 GLsizei height,
315 GLsizei depth,
316 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400317{
318 if (level < 0 || width < 0 || height < 0 || depth < 0)
319 {
320 return false;
321 }
322
Austin Kinross08528e12015-10-07 16:24:40 -0700323 // TexSubImage parameters can be NPOT without textureNPOT extension,
324 // as long as the destination texture is POT.
325 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400326 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400327 {
328 return false;
329 }
330
331 if (!ValidMipLevel(context, target, level))
332 {
333 return false;
334 }
335
336 return true;
337}
338
Geoff Lang0d8b7242015-09-09 14:56:53 -0400339bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
340{
341 // List of compressed format that require that the texture size is smaller than or a multiple of
342 // the compressed block size.
343 switch (internalFormat)
344 {
345 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
346 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
347 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
348 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800349 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400350 return true;
351
352 default:
353 return false;
354 }
355}
356
Jamie Madillc29968b2016-01-20 11:17:23 -0500357bool ValidCompressedImageSize(const ValidationContext *context,
358 GLenum internalFormat,
359 GLsizei width,
360 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400361{
Geoff Lang5d601382014-07-22 15:14:06 -0400362 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
363 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400364 {
365 return false;
366 }
367
Geoff Lang0d8b7242015-09-09 14:56:53 -0400368 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400369 {
370 return false;
371 }
372
Geoff Lang0d8b7242015-09-09 14:56:53 -0400373 if (CompressedTextureFormatRequiresExactSize(internalFormat))
374 {
375 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
376 width % formatInfo.compressedBlockWidth != 0) ||
377 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
378 height % formatInfo.compressedBlockHeight != 0))
379 {
380 return false;
381 }
382 }
383
Geoff Langd4f180b2013-09-24 13:57:44 -0400384 return true;
385}
386
Geoff Lang37dde692014-01-31 16:34:54 -0500387bool ValidQueryType(const Context *context, GLenum queryType)
388{
Geoff Langd4475812015-03-18 10:53:05 -0400389 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
390 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500391
392 switch (queryType)
393 {
394 case GL_ANY_SAMPLES_PASSED:
395 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
396 return true;
397 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
398 return (context->getClientVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500399 case GL_TIME_ELAPSED_EXT:
400 return context->getExtensions().disjointTimerQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500401 default:
402 return false;
403 }
404}
405
Dian Xiang769769a2015-09-09 15:20:08 -0700406Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500407{
408 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
409 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
410 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
411
Dian Xiang769769a2015-09-09 15:20:08 -0700412 Program *validProgram = context->getProgram(id);
413
414 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500415 {
Dian Xiang769769a2015-09-09 15:20:08 -0700416 if (context->getShader(id))
417 {
Jamie Madill437fa652016-05-03 15:13:24 -0400418 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700419 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
420 }
421 else
422 {
Jamie Madill437fa652016-05-03 15:13:24 -0400423 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700424 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500425 }
Dian Xiang769769a2015-09-09 15:20:08 -0700426
427 return validProgram;
428}
429
430Shader *GetValidShader(Context *context, GLuint id)
431{
432 // See ValidProgram for spec details.
433
434 Shader *validShader = context->getShader(id);
435
436 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500437 {
Dian Xiang769769a2015-09-09 15:20:08 -0700438 if (context->getProgram(id))
439 {
Jamie Madill437fa652016-05-03 15:13:24 -0400440 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700441 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
442 }
443 else
444 {
Jamie Madill437fa652016-05-03 15:13:24 -0400445 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700446 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500447 }
Dian Xiang769769a2015-09-09 15:20:08 -0700448
449 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500450}
451
Geoff Langb1196682014-07-23 13:47:29 -0400452bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400453{
454 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
455 {
456 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
457
Geoff Langaae65a42014-05-26 12:43:44 -0400458 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400459 {
Jamie Madill437fa652016-05-03 15:13:24 -0400460 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400461 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400462 }
463 }
464 else
465 {
466 switch (attachment)
467 {
468 case GL_DEPTH_ATTACHMENT:
469 case GL_STENCIL_ATTACHMENT:
470 break;
471
472 case GL_DEPTH_STENCIL_ATTACHMENT:
473 if (context->getClientVersion() < 3)
474 {
Jamie Madill437fa652016-05-03 15:13:24 -0400475 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400476 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400477 }
478 break;
479
480 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400481 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400482 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400483 }
484 }
485
486 return true;
487}
488
Corentin Walleze0902642014-11-04 12:32:15 -0800489bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
490 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400491{
492 switch (target)
493 {
494 case GL_RENDERBUFFER:
495 break;
496 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400497 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400498 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400499 }
500
501 if (width < 0 || height < 0 || samples < 0)
502 {
Jamie Madill437fa652016-05-03 15:13:24 -0400503 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400504 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400505 }
506
Geoff Langd87878e2014-09-19 15:42:59 -0400507 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
508 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400509 {
Jamie Madill437fa652016-05-03 15:13:24 -0400510 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400511 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400512 }
513
514 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
515 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800516 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400517 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400518 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 {
Jamie Madill437fa652016-05-03 15:13:24 -0400520 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400521 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 }
523
Geoff Langaae65a42014-05-26 12:43:44 -0400524 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400525 {
Jamie Madill437fa652016-05-03 15:13:24 -0400526 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400527 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400528 }
529
Shannon Woods53a94a82014-06-24 15:20:36 -0400530 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400531 if (handle == 0)
532 {
Jamie Madill437fa652016-05-03 15:13:24 -0400533 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400534 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400535 }
536
537 return true;
538}
539
Corentin Walleze0902642014-11-04 12:32:15 -0800540bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
541 GLenum internalformat, GLsizei width, GLsizei height)
542{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800543 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800544
545 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400546 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800547 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400548 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800549 {
Jamie Madill437fa652016-05-03 15:13:24 -0400550 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800551 return false;
552 }
553
554 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
555 // the specified storage. This is different than ES 3.0 in which a sample number higher
556 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800557 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
558 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800559 {
Geoff Langa4903b72015-03-02 16:02:48 -0800560 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
561 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
562 {
Jamie Madill437fa652016-05-03 15:13:24 -0400563 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800564 return false;
565 }
Corentin Walleze0902642014-11-04 12:32:15 -0800566 }
567
568 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
569}
570
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500571bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
572 GLenum renderbuffertarget, GLuint renderbuffer)
573{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400574 if (!ValidFramebufferTarget(target))
575 {
Jamie Madill437fa652016-05-03 15:13:24 -0400576 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400577 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400578 }
579
Shannon Woods53a94a82014-06-24 15:20:36 -0400580 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500581
Jamie Madill84115c92015-04-23 15:00:07 -0400582 ASSERT(framebuffer);
583 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500584 {
Jamie Madill437fa652016-05-03 15:13:24 -0400585 context->handleError(
586 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400587 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500588 }
589
Jamie Madillb4472272014-07-03 10:38:55 -0400590 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500591 {
Jamie Madillb4472272014-07-03 10:38:55 -0400592 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500593 }
594
Jamie Madillab9d82c2014-01-21 16:38:14 -0500595 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
596 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
597 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
598 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
599 if (renderbuffer != 0)
600 {
601 if (!context->getRenderbuffer(renderbuffer))
602 {
Jamie Madill437fa652016-05-03 15:13:24 -0400603 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400604 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500605 }
606 }
607
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500608 return true;
609}
610
Jamie Madillc29968b2016-01-20 11:17:23 -0500611bool ValidateBlitFramebufferParameters(gl::Context *context,
612 GLint srcX0,
613 GLint srcY0,
614 GLint srcX1,
615 GLint srcY1,
616 GLint dstX0,
617 GLint dstY0,
618 GLint dstX1,
619 GLint dstY1,
620 GLbitfield mask,
621 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622{
623 switch (filter)
624 {
625 case GL_NEAREST:
626 break;
627 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400628 break;
629 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400630 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400631 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632 }
633
634 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
635 {
Jamie Madill437fa652016-05-03 15:13:24 -0400636 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400637 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400638 }
639
640 if (mask == 0)
641 {
642 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
643 // buffers are copied.
644 return false;
645 }
646
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400647 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
648 // color buffer, leaving only nearest being unfiltered from above
649 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
650 {
Jamie Madill437fa652016-05-03 15:13:24 -0400651 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400652 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400653 }
654
Shannon Woods53a94a82014-06-24 15:20:36 -0400655 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400656 {
Jamie Madill437fa652016-05-03 15:13:24 -0400657 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400658 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 }
660
Jamie Madille3ef7152015-04-28 16:55:17 +0000661 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
662 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500663
664 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665 {
Jamie Madill437fa652016-05-03 15:13:24 -0400666 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400667 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400668 }
669
Geoff Lang748f74e2014-12-01 11:25:34 -0500670 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500671 {
Jamie Madill437fa652016-05-03 15:13:24 -0400672 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500673 return false;
674 }
675
Geoff Lang748f74e2014-12-01 11:25:34 -0500676 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500677 {
Jamie Madill437fa652016-05-03 15:13:24 -0400678 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500679 return false;
680 }
681
682 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400683 {
Jamie Madill437fa652016-05-03 15:13:24 -0400684 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400685 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400686 }
687
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400688 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
689
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690 if (mask & GL_COLOR_BUFFER_BIT)
691 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400692 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
693 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500694 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400695
696 if (readColorBuffer && drawColorBuffer)
697 {
Geoff Langd8a22582014-12-17 15:28:23 -0500698 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400699 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700
Geoff Langa15472a2015-08-11 11:48:03 -0400701 for (size_t drawbufferIdx = 0;
702 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 {
Geoff Langa15472a2015-08-11 11:48:03 -0400704 const FramebufferAttachment *attachment =
705 drawFramebuffer->getDrawBuffer(drawbufferIdx);
706 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400707 {
Geoff Langa15472a2015-08-11 11:48:03 -0400708 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400709 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710
Geoff Langb2f3d052013-08-13 12:49:27 -0400711 // The GL ES 3.0.2 spec (pg 193) states that:
712 // 1) If the read buffer is fixed point format, the draw buffer must be as well
713 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
714 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500715 // Changes with EXT_color_buffer_float:
716 // Case 1) is changed to fixed point OR floating point
717 GLenum readComponentType = readFormatInfo.componentType;
718 GLenum drawComponentType = drawFormatInfo.componentType;
719 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
720 readComponentType == GL_SIGNED_NORMALIZED);
721 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
722 drawComponentType == GL_SIGNED_NORMALIZED);
723
724 if (extensions.colorBufferFloat)
725 {
726 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
727 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
728
729 if (readFixedOrFloat != drawFixedOrFloat)
730 {
Jamie Madill437fa652016-05-03 15:13:24 -0400731 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500732 "If the read buffer contains fixed-point or "
733 "floating-point values, the draw buffer "
734 "must as well."));
735 return false;
736 }
737 }
738 else if (readFixedPoint != drawFixedPoint)
739 {
Jamie Madill437fa652016-05-03 15:13:24 -0400740 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500741 "If the read buffer contains fixed-point "
742 "values, the draw buffer must as well."));
743 return false;
744 }
745
746 if (readComponentType == GL_UNSIGNED_INT &&
747 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748 {
Jamie Madill437fa652016-05-03 15:13:24 -0400749 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400750 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400751 }
752
Jamie Madill6163c752015-12-07 16:32:59 -0500753 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754 {
Jamie Madill437fa652016-05-03 15:13:24 -0400755 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400756 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400757 }
758
Geoff Langb2f3d052013-08-13 12:49:27 -0400759 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400760 {
Jamie Madill437fa652016-05-03 15:13:24 -0400761 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400762 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400763 }
764 }
765 }
766
Geoff Lang5d601382014-07-22 15:14:06 -0400767 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 {
Jamie Madill437fa652016-05-03 15:13:24 -0400769 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400770 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400772 }
773 }
774
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200775 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
776 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
777 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400778 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200779 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400781 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
782 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400783
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200784 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785 {
Geoff Langd8a22582014-12-17 15:28:23 -0500786 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 {
Jamie Madill437fa652016-05-03 15:13:24 -0400788 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400789 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400790 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200792 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793 {
Jamie Madill437fa652016-05-03 15:13:24 -0400794 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400795 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796 }
797 }
798 }
799 }
800
801 return true;
802}
803
Geoff Langb1196682014-07-23 13:47:29 -0400804bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805{
806 switch (pname)
807 {
808 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
809 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
810 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
811 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
812 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
813 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
814 case GL_CURRENT_VERTEX_ATTRIB:
815 return true;
816
817 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
818 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
819 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400820 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
821 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400822 return true;
823
824 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400825 if (context->getClientVersion() < 3)
826 {
Jamie Madill437fa652016-05-03 15:13:24 -0400827 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400828 return false;
829 }
830 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400831
832 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400833 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400834 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400835 }
836}
837
Ian Ewellbda75592016-04-18 17:25:54 -0400838bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400839{
840 switch (pname)
841 {
842 case GL_TEXTURE_WRAP_R:
843 case GL_TEXTURE_SWIZZLE_R:
844 case GL_TEXTURE_SWIZZLE_G:
845 case GL_TEXTURE_SWIZZLE_B:
846 case GL_TEXTURE_SWIZZLE_A:
847 case GL_TEXTURE_BASE_LEVEL:
848 case GL_TEXTURE_MAX_LEVEL:
849 case GL_TEXTURE_COMPARE_MODE:
850 case GL_TEXTURE_COMPARE_FUNC:
851 case GL_TEXTURE_MIN_LOD:
852 case GL_TEXTURE_MAX_LOD:
Ian Ewellbda75592016-04-18 17:25:54 -0400853 // ES3 texture paramters are not supported on external textures as the extension is
854 // written against ES2.
855 if (context->getClientVersion() < 3 || target == GL_TEXTURE_EXTERNAL_OES)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400856 {
Jamie Madill437fa652016-05-03 15:13:24 -0400857 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400858 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400859 }
860 break;
861
862 default: break;
863 }
864
865 switch (pname)
866 {
867 case GL_TEXTURE_WRAP_S:
868 case GL_TEXTURE_WRAP_T:
869 case GL_TEXTURE_WRAP_R:
870 switch (param)
871 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000872 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400873 return true;
874 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400875 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300876 if (target == GL_TEXTURE_EXTERNAL_OES)
877 {
878 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400879 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300880 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
881 return false;
882 }
883 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400884 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400885 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400886 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400887 }
888
889 case GL_TEXTURE_MIN_FILTER:
890 switch (param)
891 {
892 case GL_NEAREST:
893 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400894 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400895 case GL_NEAREST_MIPMAP_NEAREST:
896 case GL_LINEAR_MIPMAP_NEAREST:
897 case GL_NEAREST_MIPMAP_LINEAR:
898 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300899 if (target == GL_TEXTURE_EXTERNAL_OES)
900 {
901 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400902 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300903 Error(GL_INVALID_ENUM,
904 "external textures only support NEAREST and LINEAR filtering"));
905 return false;
906 }
907 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400908 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400909 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400910 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400911 }
912 break;
913
914 case GL_TEXTURE_MAG_FILTER:
915 switch (param)
916 {
917 case GL_NEAREST:
918 case GL_LINEAR:
919 return true;
920 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400921 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400922 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400923 }
924 break;
925
926 case GL_TEXTURE_USAGE_ANGLE:
927 switch (param)
928 {
929 case GL_NONE:
930 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
931 return true;
932 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400933 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400934 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400935 }
936 break;
937
938 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400939 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400940 {
Jamie Madill437fa652016-05-03 15:13:24 -0400941 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400942 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400943 }
944
945 // we assume the parameter passed to this validation method is truncated, not rounded
946 if (param < 1)
947 {
Jamie Madill437fa652016-05-03 15:13:24 -0400948 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400949 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400950 }
951 return true;
952
953 case GL_TEXTURE_MIN_LOD:
954 case GL_TEXTURE_MAX_LOD:
955 // any value is permissible
956 return true;
957
958 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400959 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400960 switch (param)
961 {
962 case GL_NONE:
963 case GL_COMPARE_REF_TO_TEXTURE:
964 return true;
965 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400966 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400967 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400968 }
969 break;
970
971 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400972 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400973 switch (param)
974 {
975 case GL_LEQUAL:
976 case GL_GEQUAL:
977 case GL_LESS:
978 case GL_GREATER:
979 case GL_EQUAL:
980 case GL_NOTEQUAL:
981 case GL_ALWAYS:
982 case GL_NEVER:
983 return true;
984 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400985 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400986 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400987 }
988 break;
989
990 case GL_TEXTURE_SWIZZLE_R:
991 case GL_TEXTURE_SWIZZLE_G:
992 case GL_TEXTURE_SWIZZLE_B:
993 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400994 switch (param)
995 {
996 case GL_RED:
997 case GL_GREEN:
998 case GL_BLUE:
999 case GL_ALPHA:
1000 case GL_ZERO:
1001 case GL_ONE:
1002 return true;
1003 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001004 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001005 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001006 }
1007 break;
1008
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001009 case GL_TEXTURE_BASE_LEVEL:
1010 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -04001011 if (param < 0)
1012 {
Jamie Madill437fa652016-05-03 15:13:24 -04001013 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001014 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -04001015 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001016 return true;
1017
1018 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001019 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001020 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001021 }
1022}
1023
Geoff Langb1196682014-07-23 13:47:29 -04001024bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001025{
1026 switch (pname)
1027 {
1028 case GL_TEXTURE_MIN_FILTER:
1029 case GL_TEXTURE_MAG_FILTER:
1030 case GL_TEXTURE_WRAP_S:
1031 case GL_TEXTURE_WRAP_T:
1032 case GL_TEXTURE_WRAP_R:
1033 case GL_TEXTURE_MIN_LOD:
1034 case GL_TEXTURE_MAX_LOD:
1035 case GL_TEXTURE_COMPARE_MODE:
1036 case GL_TEXTURE_COMPARE_FUNC:
1037 return true;
1038
1039 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001040 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001041 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001042 }
1043}
1044
Jamie Madillc29968b2016-01-20 11:17:23 -05001045bool ValidateReadPixels(Context *context,
1046 GLint x,
1047 GLint y,
1048 GLsizei width,
1049 GLsizei height,
1050 GLenum format,
1051 GLenum type,
1052 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001053{
Jamie Madillc29968b2016-01-20 11:17:23 -05001054 if (width < 0 || height < 0)
1055 {
Jamie Madill437fa652016-05-03 15:13:24 -04001056 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001057 return false;
1058 }
1059
1060 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001061 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001062
Geoff Lang748f74e2014-12-01 11:25:34 -05001063 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001064 {
Jamie Madill437fa652016-05-03 15:13:24 -04001065 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001066 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001067 }
1068
Jamie Madill48faf802014-11-06 15:27:22 -05001069 if (context->getState().getReadFramebuffer()->id() != 0 &&
1070 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001071 {
Jamie Madill437fa652016-05-03 15:13:24 -04001072 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001073 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001074 }
1075
Geoff Langbce529e2014-12-01 12:48:41 -05001076 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1077 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001078 {
Jamie Madill437fa652016-05-03 15:13:24 -04001079 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001080 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001081 }
1082
Geoff Langbce529e2014-12-01 12:48:41 -05001083 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1084 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001085 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001086 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001087
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001088 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1089 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001090
1091 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1092 {
Jamie Madill437fa652016-05-03 15:13:24 -04001093 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001094 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001095 }
1096
Jamie Madillc29968b2016-01-20 11:17:23 -05001097 return true;
1098}
1099
1100bool ValidateReadnPixelsEXT(Context *context,
1101 GLint x,
1102 GLint y,
1103 GLsizei width,
1104 GLsizei height,
1105 GLenum format,
1106 GLenum type,
1107 GLsizei bufSize,
1108 GLvoid *pixels)
1109{
1110 if (bufSize < 0)
1111 {
Jamie Madill437fa652016-05-03 15:13:24 -04001112 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001113 return false;
1114 }
1115
Geoff Lang5d601382014-07-22 15:14:06 -04001116 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1117 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001118
Minmin Gongadff67b2015-10-14 10:34:45 -04001119 GLsizei outputPitch =
1120 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1121 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001122 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001123 int requiredSize = outputPitch * height;
1124 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001125 {
Jamie Madill437fa652016-05-03 15:13:24 -04001126 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001127 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001128 }
1129
Jamie Madillc29968b2016-01-20 11:17:23 -05001130 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001131}
1132
Olli Etuaho41997e72016-03-10 13:38:39 +02001133bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001134{
1135 if (!context->getExtensions().occlusionQueryBoolean &&
1136 !context->getExtensions().disjointTimerQuery)
1137 {
Jamie Madill437fa652016-05-03 15:13:24 -04001138 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001139 return false;
1140 }
1141
Olli Etuaho41997e72016-03-10 13:38:39 +02001142 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001143}
1144
Olli Etuaho41997e72016-03-10 13:38:39 +02001145bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001146{
1147 if (!context->getExtensions().occlusionQueryBoolean &&
1148 !context->getExtensions().disjointTimerQuery)
1149 {
Jamie Madill437fa652016-05-03 15:13:24 -04001150 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001151 return false;
1152 }
1153
Olli Etuaho41997e72016-03-10 13:38:39 +02001154 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001155}
1156
1157bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001158{
1159 if (!ValidQueryType(context, target))
1160 {
Jamie Madill437fa652016-05-03 15:13:24 -04001161 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001162 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001163 }
1164
1165 if (id == 0)
1166 {
Jamie Madill437fa652016-05-03 15:13:24 -04001167 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001168 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001169 }
1170
1171 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1172 // of zero, if the active query object name for <target> is non-zero (for the
1173 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1174 // the active query for either target is non-zero), if <id> is the name of an
1175 // existing query object whose type does not match <target>, or if <id> is the
1176 // active query object name for any query type, the error INVALID_OPERATION is
1177 // generated.
1178
1179 // Ensure no other queries are active
1180 // NOTE: If other queries than occlusion are supported, we will need to check
1181 // separately that:
1182 // a) The query ID passed is not the current active query for any target/type
1183 // b) There are no active queries for the requested target (and in the case
1184 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1185 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001186
Corentin Walleze71ea192016-04-19 13:16:37 -04001187 if (context->getState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001188 {
Jamie Madill437fa652016-05-03 15:13:24 -04001189 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001190 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001191 }
1192
1193 Query *queryObject = context->getQuery(id, true, target);
1194
1195 // check that name was obtained with glGenQueries
1196 if (!queryObject)
1197 {
Jamie Madill437fa652016-05-03 15:13:24 -04001198 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001199 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001200 }
1201
1202 // check for type mismatch
1203 if (queryObject->getType() != target)
1204 {
Jamie Madill437fa652016-05-03 15:13:24 -04001205 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001206 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001207 }
1208
1209 return true;
1210}
1211
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001212bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1213{
1214 if (!context->getExtensions().occlusionQueryBoolean &&
1215 !context->getExtensions().disjointTimerQuery)
1216 {
Jamie Madill437fa652016-05-03 15:13:24 -04001217 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001218 return false;
1219 }
1220
1221 return ValidateBeginQueryBase(context, target, id);
1222}
1223
1224bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001225{
1226 if (!ValidQueryType(context, target))
1227 {
Jamie Madill437fa652016-05-03 15:13:24 -04001228 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001229 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001230 }
1231
Shannon Woods53a94a82014-06-24 15:20:36 -04001232 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001233
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001234 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001235 {
Jamie Madill437fa652016-05-03 15:13:24 -04001236 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001237 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001238 }
1239
Jamie Madill45c785d2014-05-13 14:09:34 -04001240 return true;
1241}
1242
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001243bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1244{
1245 if (!context->getExtensions().occlusionQueryBoolean &&
1246 !context->getExtensions().disjointTimerQuery)
1247 {
Jamie Madill437fa652016-05-03 15:13:24 -04001248 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001249 return false;
1250 }
1251
1252 return ValidateEndQueryBase(context, target);
1253}
1254
1255bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1256{
1257 if (!context->getExtensions().disjointTimerQuery)
1258 {
Jamie Madill437fa652016-05-03 15:13:24 -04001259 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001260 return false;
1261 }
1262
1263 if (target != GL_TIMESTAMP_EXT)
1264 {
Jamie Madill437fa652016-05-03 15:13:24 -04001265 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001266 return false;
1267 }
1268
1269 Query *queryObject = context->getQuery(id, true, target);
1270 if (queryObject == nullptr)
1271 {
Jamie Madill437fa652016-05-03 15:13:24 -04001272 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001273 return false;
1274 }
1275
1276 if (context->getState().isQueryActive(queryObject))
1277 {
Jamie Madill437fa652016-05-03 15:13:24 -04001278 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001279 return false;
1280 }
1281
1282 return true;
1283}
1284
1285bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1286{
1287 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1288 {
Jamie Madill437fa652016-05-03 15:13:24 -04001289 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001290 return false;
1291 }
1292
1293 switch (pname)
1294 {
1295 case GL_CURRENT_QUERY_EXT:
1296 if (target == GL_TIMESTAMP_EXT)
1297 {
Jamie Madill437fa652016-05-03 15:13:24 -04001298 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001299 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1300 return false;
1301 }
1302 break;
1303 case GL_QUERY_COUNTER_BITS_EXT:
1304 if (!context->getExtensions().disjointTimerQuery ||
1305 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1306 {
Jamie Madill437fa652016-05-03 15:13:24 -04001307 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001308 return false;
1309 }
1310 break;
1311 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001312 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001313 return false;
1314 }
1315
1316 return true;
1317}
1318
1319bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1320{
1321 if (!context->getExtensions().occlusionQueryBoolean &&
1322 !context->getExtensions().disjointTimerQuery)
1323 {
Jamie Madill437fa652016-05-03 15:13:24 -04001324 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001325 return false;
1326 }
1327
1328 return ValidateGetQueryivBase(context, target, pname);
1329}
1330
1331bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1332{
1333 Query *queryObject = context->getQuery(id, false, GL_NONE);
1334
1335 if (!queryObject)
1336 {
Jamie Madill437fa652016-05-03 15:13:24 -04001337 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001338 return false;
1339 }
1340
1341 if (context->getState().isQueryActive(queryObject))
1342 {
Jamie Madill437fa652016-05-03 15:13:24 -04001343 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001344 return false;
1345 }
1346
1347 switch (pname)
1348 {
1349 case GL_QUERY_RESULT_EXT:
1350 case GL_QUERY_RESULT_AVAILABLE_EXT:
1351 break;
1352
1353 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001354 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001355 return false;
1356 }
1357
1358 return true;
1359}
1360
1361bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1362{
1363 if (!context->getExtensions().disjointTimerQuery)
1364 {
Jamie Madill437fa652016-05-03 15:13:24 -04001365 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001366 return false;
1367 }
1368 return ValidateGetQueryObjectValueBase(context, id, pname);
1369}
1370
1371bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1372{
1373 if (!context->getExtensions().disjointTimerQuery &&
1374 !context->getExtensions().occlusionQueryBoolean)
1375 {
Jamie Madill437fa652016-05-03 15:13:24 -04001376 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001377 return false;
1378 }
1379 return ValidateGetQueryObjectValueBase(context, id, pname);
1380}
1381
1382bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1383{
1384 if (!context->getExtensions().disjointTimerQuery)
1385 {
Jamie Madill437fa652016-05-03 15:13:24 -04001386 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001387 return false;
1388 }
1389 return ValidateGetQueryObjectValueBase(context, id, pname);
1390}
1391
1392bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1393{
1394 if (!context->getExtensions().disjointTimerQuery)
1395 {
Jamie Madill437fa652016-05-03 15:13:24 -04001396 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001397 return false;
1398 }
1399 return ValidateGetQueryObjectValueBase(context, id, pname);
1400}
1401
Jamie Madill62d31cb2015-09-11 13:25:51 -04001402static bool ValidateUniformCommonBase(gl::Context *context,
1403 GLenum targetUniformType,
1404 GLint location,
1405 GLsizei count,
1406 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001407{
1408 if (count < 0)
1409 {
Jamie Madill437fa652016-05-03 15:13:24 -04001410 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001411 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001412 }
1413
Geoff Lang7dd2e102014-11-10 15:19:26 -05001414 gl::Program *program = context->getState().getProgram();
1415 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001416 {
Jamie Madill437fa652016-05-03 15:13:24 -04001417 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001418 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001419 }
1420
Geoff Langd8605522016-04-13 10:19:12 -04001421 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001422 {
1423 // Silently ignore the uniform command
1424 return false;
1425 }
1426
Geoff Lang7dd2e102014-11-10 15:19:26 -05001427 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001428 {
Jamie Madill437fa652016-05-03 15:13:24 -04001429 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001430 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001431 }
1432
Jamie Madill62d31cb2015-09-11 13:25:51 -04001433 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001434
1435 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001436 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001437 {
Jamie Madill437fa652016-05-03 15:13:24 -04001438 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001439 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001440 }
1441
Jamie Madill62d31cb2015-09-11 13:25:51 -04001442 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001443 return true;
1444}
1445
Jamie Madillaa981bd2014-05-20 10:55:55 -04001446bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1447{
1448 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001449 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001450 {
Jamie Madill437fa652016-05-03 15:13:24 -04001451 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001452 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001453 }
1454
Jamie Madill62d31cb2015-09-11 13:25:51 -04001455 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001456 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1457 {
1458 return false;
1459 }
1460
Jamie Madillf2575982014-06-25 16:04:54 -04001461 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001462 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001463 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1464 {
Jamie Madill437fa652016-05-03 15:13:24 -04001465 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001466 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001467 }
1468
1469 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001470}
1471
1472bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1473 GLboolean transpose)
1474{
1475 // Check for ES3 uniform entry points
1476 int rows = VariableRowCount(matrixType);
1477 int cols = VariableColumnCount(matrixType);
1478 if (rows != cols && context->getClientVersion() < 3)
1479 {
Jamie Madill437fa652016-05-03 15:13:24 -04001480 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001481 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001482 }
1483
1484 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1485 {
Jamie Madill437fa652016-05-03 15:13:24 -04001486 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001487 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001488 }
1489
Jamie Madill62d31cb2015-09-11 13:25:51 -04001490 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001491 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1492 {
1493 return false;
1494 }
1495
1496 if (uniform->type != matrixType)
1497 {
Jamie Madill437fa652016-05-03 15:13:24 -04001498 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001499 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001500 }
1501
1502 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001503}
1504
Jamie Madill893ab082014-05-16 16:56:10 -04001505bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1506{
1507 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1508 {
Jamie Madill437fa652016-05-03 15:13:24 -04001509 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001510 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001511 }
1512
Jamie Madill0af26e12015-03-05 19:54:33 -05001513 const Caps &caps = context->getCaps();
1514
Jamie Madill893ab082014-05-16 16:56:10 -04001515 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1516 {
1517 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1518
Jamie Madill0af26e12015-03-05 19:54:33 -05001519 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001520 {
Jamie Madill437fa652016-05-03 15:13:24 -04001521 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001522 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001523 }
1524 }
1525
1526 switch (pname)
1527 {
1528 case GL_TEXTURE_BINDING_2D:
1529 case GL_TEXTURE_BINDING_CUBE_MAP:
1530 case GL_TEXTURE_BINDING_3D:
1531 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001532 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001533 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1534 if (!context->getExtensions().eglStreamConsumerExternal)
1535 {
Jamie Madill437fa652016-05-03 15:13:24 -04001536 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001537 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1538 return false;
1539 }
1540 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001541
1542 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1543 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1544 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001545 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001546 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001547 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001548 {
Jamie Madill437fa652016-05-03 15:13:24 -04001549 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001550 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001551 }
1552
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001553 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001554 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001555 {
Jamie Madill437fa652016-05-03 15:13:24 -04001556 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001557 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001558 }
1559 }
1560 break;
1561
1562 default:
1563 break;
1564 }
1565
1566 // pname is valid, but there are no parameters to return
1567 if (numParams == 0)
1568 {
1569 return false;
1570 }
1571
1572 return true;
1573}
1574
Jamie Madillc29968b2016-01-20 11:17:23 -05001575bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1576 GLenum target,
1577 GLint level,
1578 GLenum internalformat,
1579 bool isSubImage,
1580 GLint xoffset,
1581 GLint yoffset,
1582 GLint zoffset,
1583 GLint x,
1584 GLint y,
1585 GLsizei width,
1586 GLsizei height,
1587 GLint border,
1588 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001589{
Jamie Madill560a8d82014-05-21 13:06:20 -04001590 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1591 {
Jamie Madill437fa652016-05-03 15:13:24 -04001592 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001593 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001594 }
1595
1596 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1597 {
Jamie Madill437fa652016-05-03 15:13:24 -04001598 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001599 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001600 }
1601
1602 if (border != 0)
1603 {
Jamie Madill437fa652016-05-03 15:13:24 -04001604 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001605 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001606 }
1607
1608 if (!ValidMipLevel(context, target, level))
1609 {
Jamie Madill437fa652016-05-03 15:13:24 -04001610 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001611 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001612 }
1613
Jamie Madillc29968b2016-01-20 11:17:23 -05001614 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001615 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001616 {
Jamie Madill437fa652016-05-03 15:13:24 -04001617 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001618 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001619 }
1620
Jamie Madillc29968b2016-01-20 11:17:23 -05001621 const auto &state = context->getState();
1622 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001623 {
Jamie Madill437fa652016-05-03 15:13:24 -04001624 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001625 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001626 }
1627
Geoff Langaae65a42014-05-26 12:43:44 -04001628 const gl::Caps &caps = context->getCaps();
1629
Geoff Langaae65a42014-05-26 12:43:44 -04001630 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001631 switch (target)
1632 {
1633 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001634 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001635 break;
1636
1637 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1638 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1639 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1640 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1641 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1642 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001643 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001644 break;
1645
1646 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001647 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001648 break;
1649
1650 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001651 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001652 break;
1653
1654 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001655 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001656 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001657 }
1658
Jamie Madillc29968b2016-01-20 11:17:23 -05001659 gl::Texture *texture =
1660 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001661 if (!texture)
1662 {
Jamie Madill437fa652016-05-03 15:13:24 -04001663 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001664 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001665 }
1666
Geoff Lang69cce582015-09-17 13:20:36 -04001667 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001668 {
Jamie Madill437fa652016-05-03 15:13:24 -04001669 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001670 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001671 }
1672
Geoff Lang5d601382014-07-22 15:14:06 -04001673 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1674
1675 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001676 {
Jamie Madill437fa652016-05-03 15:13:24 -04001677 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001678 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001679 }
1680
Geoff Langa9be0dc2014-12-17 12:34:40 -05001681 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001682 {
Jamie Madill437fa652016-05-03 15:13:24 -04001683 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001684 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001685 }
1686
1687 if (isSubImage)
1688 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001689 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1690 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1691 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001692 {
Jamie Madill437fa652016-05-03 15:13:24 -04001693 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001694 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001695 }
1696 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001697 else
1698 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001699 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001700 {
Jamie Madill437fa652016-05-03 15:13:24 -04001701 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001702 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001703 }
1704
Geoff Lang5d601382014-07-22 15:14:06 -04001705 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001706 {
Jamie Madill437fa652016-05-03 15:13:24 -04001707 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001708 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001709 }
1710
1711 int maxLevelDimension = (maxDimension >> level);
1712 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1713 {
Jamie Madill437fa652016-05-03 15:13:24 -04001714 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001715 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001716 }
1717 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001718
Geoff Langa9be0dc2014-12-17 12:34:40 -05001719 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001720 return true;
1721}
1722
Jamie Madillf25855c2015-11-03 11:06:18 -05001723static bool ValidateDrawBase(ValidationContext *context,
1724 GLenum mode,
1725 GLsizei count,
1726 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001727{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001728 switch (mode)
1729 {
1730 case GL_POINTS:
1731 case GL_LINES:
1732 case GL_LINE_LOOP:
1733 case GL_LINE_STRIP:
1734 case GL_TRIANGLES:
1735 case GL_TRIANGLE_STRIP:
1736 case GL_TRIANGLE_FAN:
1737 break;
1738 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001739 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001740 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001741 }
1742
Jamie Madill250d33f2014-06-06 17:09:03 -04001743 if (count < 0)
1744 {
Jamie Madill437fa652016-05-03 15:13:24 -04001745 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001746 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001747 }
1748
Geoff Langb1196682014-07-23 13:47:29 -04001749 const State &state = context->getState();
1750
Jamie Madill250d33f2014-06-06 17:09:03 -04001751 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001752 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001753 {
Jamie Madill437fa652016-05-03 15:13:24 -04001754 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001755 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001756 }
1757
Geoff Lang3a86ad32015-09-01 11:47:05 -04001758 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001759 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001760 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1761 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1762 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1763 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1764 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1765 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1766 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001767 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001768 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1769 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001770 {
1771 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1772 // Section 6.10 of the WebGL 1.0 spec
1773 ERR(
1774 "This ANGLE implementation does not support separate front/back stencil "
1775 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001776 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001777 return false;
1778 }
Jamie Madillac528012014-06-20 13:21:23 -04001779 }
1780
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001781 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001782 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001783 {
Jamie Madill437fa652016-05-03 15:13:24 -04001784 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001785 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001786 }
1787
Geoff Lang7dd2e102014-11-10 15:19:26 -05001788 gl::Program *program = state.getProgram();
1789 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001790 {
Jamie Madill437fa652016-05-03 15:13:24 -04001791 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001792 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001793 }
1794
Geoff Lang7dd2e102014-11-10 15:19:26 -05001795 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001796 {
Jamie Madill437fa652016-05-03 15:13:24 -04001797 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001798 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001799 }
1800
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001801 // Uniform buffer validation
1802 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1803 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001804 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001805 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001806 const OffsetBindingPointer<Buffer> &uniformBuffer =
1807 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001808
Geoff Lang5d124a62015-09-15 13:03:27 -04001809 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001810 {
1811 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001812 context->handleError(
1813 Error(GL_INVALID_OPERATION,
1814 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001815 return false;
1816 }
1817
Geoff Lang5d124a62015-09-15 13:03:27 -04001818 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001819 if (uniformBufferSize == 0)
1820 {
1821 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001822 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001823 }
1824
Jamie Madill62d31cb2015-09-11 13:25:51 -04001825 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001826 {
1827 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001828 context->handleError(
1829 Error(GL_INVALID_OPERATION,
1830 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001831 return false;
1832 }
1833 }
1834
Jamie Madill250d33f2014-06-06 17:09:03 -04001835 // No-op if zero count
1836 return (count > 0);
1837}
1838
Geoff Langb1196682014-07-23 13:47:29 -04001839bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001840{
Jamie Madillfd716582014-06-06 17:09:04 -04001841 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001842 {
Jamie Madill437fa652016-05-03 15:13:24 -04001843 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001844 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001845 }
1846
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001847 const State &state = context->getState();
1848 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001849 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1850 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001851 {
1852 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1853 // that does not match the current transform feedback object's draw mode (if transform feedback
1854 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001855 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001856 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001857 }
1858
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001859 if (!ValidateDrawBase(context, mode, count, primcount))
1860 {
1861 return false;
1862 }
1863
1864 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001865 {
1866 return false;
1867 }
1868
1869 return true;
1870}
1871
Geoff Langb1196682014-07-23 13:47:29 -04001872bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001873{
1874 if (primcount < 0)
1875 {
Jamie Madill437fa652016-05-03 15:13:24 -04001876 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001877 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001878 }
1879
Jamie Madill2b976812014-08-25 15:47:49 -04001880 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001881 {
1882 return false;
1883 }
1884
1885 // No-op if zero primitive count
1886 return (primcount > 0);
1887}
1888
Geoff Lang87a93302014-09-16 13:29:43 -04001889static bool ValidateDrawInstancedANGLE(Context *context)
1890{
1891 // Verify there is at least one active attribute with a divisor of zero
1892 const gl::State& state = context->getState();
1893
Geoff Lang7dd2e102014-11-10 15:19:26 -05001894 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001895
1896 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001897 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001898 {
1899 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001900 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001901 {
1902 return true;
1903 }
1904 }
1905
Jamie Madill437fa652016-05-03 15:13:24 -04001906 context->handleError(Error(GL_INVALID_OPERATION,
1907 "ANGLE_instanced_arrays requires that at least one active attribute"
1908 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001909 return false;
1910}
1911
1912bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1913{
1914 if (!ValidateDrawInstancedANGLE(context))
1915 {
1916 return false;
1917 }
1918
1919 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1920}
1921
Jamie Madillf25855c2015-11-03 11:06:18 -05001922bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001923 GLenum mode,
1924 GLsizei count,
1925 GLenum type,
1926 const GLvoid *indices,
1927 GLsizei primcount,
1928 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001929{
Jamie Madill250d33f2014-06-06 17:09:03 -04001930 switch (type)
1931 {
1932 case GL_UNSIGNED_BYTE:
1933 case GL_UNSIGNED_SHORT:
1934 break;
1935 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001936 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001937 {
Jamie Madill437fa652016-05-03 15:13:24 -04001938 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001939 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001940 }
1941 break;
1942 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001943 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001944 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001945 }
1946
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001947 const State &state = context->getState();
1948
1949 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001950 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001951 {
1952 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1953 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001954 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001955 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001956 }
1957
1958 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001959 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001960 {
Jamie Madill437fa652016-05-03 15:13:24 -04001961 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001962 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001963 }
1964
Jamie Madill2b976812014-08-25 15:47:49 -04001965 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001966 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001967 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001968 {
Jamie Madill437fa652016-05-03 15:13:24 -04001969 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001970 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001971 }
1972
Jamie Madillae3000b2014-08-25 15:47:51 -04001973 if (elementArrayBuffer)
1974 {
1975 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1976
1977 GLint64 offset = reinterpret_cast<GLint64>(indices);
1978 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1979
1980 // check for integer overflows
1981 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1982 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1983 {
Jamie Madill437fa652016-05-03 15:13:24 -04001984 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04001985 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001986 }
1987
1988 // Check for reading past the end of the bound buffer object
1989 if (byteCount > elementArrayBuffer->getSize())
1990 {
Jamie Madill437fa652016-05-03 15:13:24 -04001991 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001992 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001993 }
1994 }
1995 else if (!indices)
1996 {
1997 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04001998 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001999 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002000 }
2001
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002002 if (!ValidateDrawBase(context, mode, count, primcount))
2003 {
2004 return false;
2005 }
2006
Jamie Madill2b976812014-08-25 15:47:49 -04002007 // Use max index to validate if our vertex buffers are large enough for the pull.
2008 // TODO: offer fast path, with disabled index validation.
2009 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2010 if (elementArrayBuffer)
2011 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002012 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002013 Error error =
2014 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2015 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002016 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002017 {
Jamie Madill437fa652016-05-03 15:13:24 -04002018 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002019 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002020 }
2021 }
2022 else
2023 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002024 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002025 }
2026
Jamie Madille79b1e12015-11-04 16:36:37 -05002027 // If we use an index greater than our maximum supported index range, return an error.
2028 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2029 // return an error if possible here.
2030 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2031 {
Jamie Madill437fa652016-05-03 15:13:24 -04002032 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002033 return false;
2034 }
2035
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002036 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002037 {
2038 return false;
2039 }
2040
Geoff Lang3edfe032015-09-04 16:38:24 -04002041 // No op if there are no real indices in the index data (all are primitive restart).
2042 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002043}
2044
Geoff Langb1196682014-07-23 13:47:29 -04002045bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002046 GLenum mode,
2047 GLsizei count,
2048 GLenum type,
2049 const GLvoid *indices,
2050 GLsizei primcount,
2051 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002052{
2053 if (primcount < 0)
2054 {
Jamie Madill437fa652016-05-03 15:13:24 -04002055 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002056 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002057 }
2058
Jamie Madill2b976812014-08-25 15:47:49 -04002059 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002060 {
2061 return false;
2062 }
2063
2064 // No-op zero primitive count
2065 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002066}
2067
Geoff Lang3edfe032015-09-04 16:38:24 -04002068bool ValidateDrawElementsInstancedANGLE(Context *context,
2069 GLenum mode,
2070 GLsizei count,
2071 GLenum type,
2072 const GLvoid *indices,
2073 GLsizei primcount,
2074 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002075{
2076 if (!ValidateDrawInstancedANGLE(context))
2077 {
2078 return false;
2079 }
2080
2081 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2082}
2083
Geoff Langb1196682014-07-23 13:47:29 -04002084bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002085 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002086{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002087 if (!ValidFramebufferTarget(target))
2088 {
Jamie Madill437fa652016-05-03 15:13:24 -04002089 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002090 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002091 }
2092
2093 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002094 {
2095 return false;
2096 }
2097
Jamie Madill55ec3b12014-07-03 10:38:57 -04002098 if (texture != 0)
2099 {
2100 gl::Texture *tex = context->getTexture(texture);
2101
2102 if (tex == NULL)
2103 {
Jamie Madill437fa652016-05-03 15:13:24 -04002104 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002105 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002106 }
2107
2108 if (level < 0)
2109 {
Jamie Madill437fa652016-05-03 15:13:24 -04002110 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002111 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002112 }
2113 }
2114
Shannon Woods53a94a82014-06-24 15:20:36 -04002115 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002116 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002117
Jamie Madill84115c92015-04-23 15:00:07 -04002118 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002119 {
Jamie Madill437fa652016-05-03 15:13:24 -04002120 context->handleError(
2121 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002122 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002123 }
2124
2125 return true;
2126}
2127
Geoff Langb1196682014-07-23 13:47:29 -04002128bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002129 GLenum textarget, GLuint texture, GLint level)
2130{
Geoff Lang95663912015-04-02 15:54:45 -04002131 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2132 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002133 {
Jamie Madill437fa652016-05-03 15:13:24 -04002134 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002135 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002136 }
2137
2138 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002139 {
2140 return false;
2141 }
2142
Jamie Madill55ec3b12014-07-03 10:38:57 -04002143 if (texture != 0)
2144 {
2145 gl::Texture *tex = context->getTexture(texture);
2146 ASSERT(tex);
2147
Jamie Madill2a6564e2014-07-11 09:53:19 -04002148 const gl::Caps &caps = context->getCaps();
2149
Jamie Madill55ec3b12014-07-03 10:38:57 -04002150 switch (textarget)
2151 {
2152 case GL_TEXTURE_2D:
2153 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002154 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002155 {
Jamie Madill437fa652016-05-03 15:13:24 -04002156 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002157 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002158 }
2159 if (tex->getTarget() != GL_TEXTURE_2D)
2160 {
Jamie Madill437fa652016-05-03 15:13:24 -04002161 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002162 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002163 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002164 }
2165 break;
2166
2167 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2168 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2169 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2170 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2171 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2172 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2173 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002174 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002175 {
Jamie Madill437fa652016-05-03 15:13:24 -04002176 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002177 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002178 }
2179 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2180 {
Jamie Madill437fa652016-05-03 15:13:24 -04002181 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002182 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002183 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002184 }
2185 break;
2186
2187 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002188 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002189 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002190 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002191
2192 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2193 if (internalFormatInfo.compressed)
2194 {
Jamie Madill437fa652016-05-03 15:13:24 -04002195 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002196 return false;
2197 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002198 }
2199
Jamie Madill570f7c82014-07-03 10:38:54 -04002200 return true;
2201}
2202
Geoff Langb1196682014-07-23 13:47:29 -04002203bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002204{
2205 if (program == 0)
2206 {
Jamie Madill437fa652016-05-03 15:13:24 -04002207 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002208 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002209 }
2210
Dian Xiang769769a2015-09-09 15:20:08 -07002211 gl::Program *programObject = GetValidProgram(context, program);
2212 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002213 {
2214 return false;
2215 }
2216
Jamie Madill0063c512014-08-25 15:47:53 -04002217 if (!programObject || !programObject->isLinked())
2218 {
Jamie Madill437fa652016-05-03 15:13:24 -04002219 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002220 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002221 }
2222
Geoff Lang7dd2e102014-11-10 15:19:26 -05002223 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002224 {
Jamie Madill437fa652016-05-03 15:13:24 -04002225 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002226 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002227 }
2228
Jamie Madill0063c512014-08-25 15:47:53 -04002229 return true;
2230}
2231
Geoff Langb1196682014-07-23 13:47:29 -04002232bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002233{
2234 return ValidateGetUniformBase(context, program, location);
2235}
2236
Geoff Langb1196682014-07-23 13:47:29 -04002237bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002238{
Jamie Madill78f41802014-08-25 15:47:55 -04002239 return ValidateGetUniformBase(context, program, location);
2240}
2241
Geoff Langb1196682014-07-23 13:47:29 -04002242static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002243{
2244 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002245 {
Jamie Madill78f41802014-08-25 15:47:55 -04002246 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002247 }
2248
Jamie Madilla502c742014-08-28 17:19:13 -04002249 gl::Program *programObject = context->getProgram(program);
2250 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002251
Jamie Madill78f41802014-08-25 15:47:55 -04002252 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002253 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2254 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002255 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002256 {
Jamie Madill437fa652016-05-03 15:13:24 -04002257 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002258 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002259 }
2260
2261 return true;
2262}
2263
Geoff Langb1196682014-07-23 13:47:29 -04002264bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002265{
Jamie Madill78f41802014-08-25 15:47:55 -04002266 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002267}
2268
Geoff Langb1196682014-07-23 13:47:29 -04002269bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002270{
Jamie Madill78f41802014-08-25 15:47:55 -04002271 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002272}
2273
Austin Kinross08332632015-05-05 13:35:47 -07002274bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2275 const GLenum *attachments, bool defaultFramebuffer)
2276{
2277 if (numAttachments < 0)
2278 {
Jamie Madill437fa652016-05-03 15:13:24 -04002279 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002280 return false;
2281 }
2282
2283 for (GLsizei i = 0; i < numAttachments; ++i)
2284 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002285 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002286 {
2287 if (defaultFramebuffer)
2288 {
Jamie Madill437fa652016-05-03 15:13:24 -04002289 context->handleError(Error(
2290 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002291 return false;
2292 }
2293
2294 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2295 {
Jamie Madill437fa652016-05-03 15:13:24 -04002296 context->handleError(Error(GL_INVALID_OPERATION,
2297 "Requested color attachment is greater than the maximum "
2298 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002299 return false;
2300 }
2301 }
2302 else
2303 {
2304 switch (attachments[i])
2305 {
2306 case GL_DEPTH_ATTACHMENT:
2307 case GL_STENCIL_ATTACHMENT:
2308 case GL_DEPTH_STENCIL_ATTACHMENT:
2309 if (defaultFramebuffer)
2310 {
Jamie Madill437fa652016-05-03 15:13:24 -04002311 context->handleError(
2312 Error(GL_INVALID_ENUM,
2313 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002314 return false;
2315 }
2316 break;
2317 case GL_COLOR:
2318 case GL_DEPTH:
2319 case GL_STENCIL:
2320 if (!defaultFramebuffer)
2321 {
Jamie Madill437fa652016-05-03 15:13:24 -04002322 context->handleError(
2323 Error(GL_INVALID_ENUM,
2324 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002325 return false;
2326 }
2327 break;
2328 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002329 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002330 return false;
2331 }
2332 }
2333 }
2334
2335 return true;
2336}
2337
Austin Kinross6ee1e782015-05-29 17:05:37 -07002338bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2339{
2340 // Note that debug marker calls must not set error state
2341
2342 if (length < 0)
2343 {
2344 return false;
2345 }
2346
2347 if (marker == nullptr)
2348 {
2349 return false;
2350 }
2351
2352 return true;
2353}
2354
2355bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2356{
2357 // Note that debug marker calls must not set error state
2358
2359 if (length < 0)
2360 {
2361 return false;
2362 }
2363
2364 if (length > 0 && marker == nullptr)
2365 {
2366 return false;
2367 }
2368
2369 return true;
2370}
2371
Geoff Langdcab33b2015-07-21 13:03:16 -04002372bool ValidateEGLImageTargetTexture2DOES(Context *context,
2373 egl::Display *display,
2374 GLenum target,
2375 egl::Image *image)
2376{
Geoff Langa8406172015-07-21 16:53:39 -04002377 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2378 {
Jamie Madill437fa652016-05-03 15:13:24 -04002379 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002380 return false;
2381 }
2382
2383 switch (target)
2384 {
2385 case GL_TEXTURE_2D:
2386 break;
2387
2388 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002389 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002390 return false;
2391 }
2392
2393 if (!display->isValidImage(image))
2394 {
Jamie Madill437fa652016-05-03 15:13:24 -04002395 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002396 return false;
2397 }
2398
2399 if (image->getSamples() > 0)
2400 {
Jamie Madill437fa652016-05-03 15:13:24 -04002401 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002402 "cannot create a 2D texture from a multisampled EGL image."));
2403 return false;
2404 }
2405
2406 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2407 if (!textureCaps.texturable)
2408 {
Jamie Madill437fa652016-05-03 15:13:24 -04002409 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002410 "EGL image internal format is not supported as a texture."));
2411 return false;
2412 }
2413
Geoff Langdcab33b2015-07-21 13:03:16 -04002414 return true;
2415}
2416
2417bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2418 egl::Display *display,
2419 GLenum target,
2420 egl::Image *image)
2421{
Geoff Langa8406172015-07-21 16:53:39 -04002422 if (!context->getExtensions().eglImage)
2423 {
Jamie Madill437fa652016-05-03 15:13:24 -04002424 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002425 return false;
2426 }
2427
2428 switch (target)
2429 {
2430 case GL_RENDERBUFFER:
2431 break;
2432
2433 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002434 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002435 return false;
2436 }
2437
2438 if (!display->isValidImage(image))
2439 {
Jamie Madill437fa652016-05-03 15:13:24 -04002440 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002441 return false;
2442 }
2443
2444 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2445 if (!textureCaps.renderable)
2446 {
Jamie Madill437fa652016-05-03 15:13:24 -04002447 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002448 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2449 return false;
2450 }
2451
Geoff Langdcab33b2015-07-21 13:03:16 -04002452 return true;
2453}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002454
2455bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2456{
Geoff Lang36167ab2015-12-07 10:27:14 -05002457 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002458 {
2459 // The default VAO should always exist
2460 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002461 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002462 return false;
2463 }
2464
2465 return true;
2466}
2467
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002468bool ValidateLinkProgram(Context *context, GLuint program)
2469{
2470 if (context->hasActiveTransformFeedback(program))
2471 {
2472 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002473 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002474 "Cannot link program while program is associated with an active "
2475 "transform feedback object."));
2476 return false;
2477 }
2478 return true;
2479}
2480
Geoff Langc5629752015-12-07 16:29:04 -05002481bool ValidateProgramBinaryBase(Context *context,
2482 GLuint program,
2483 GLenum binaryFormat,
2484 const void *binary,
2485 GLint length)
2486{
2487 Program *programObject = GetValidProgram(context, program);
2488 if (programObject == nullptr)
2489 {
2490 return false;
2491 }
2492
2493 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2494 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2495 programBinaryFormats.end())
2496 {
Jamie Madill437fa652016-05-03 15:13:24 -04002497 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002498 return false;
2499 }
2500
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002501 if (context->hasActiveTransformFeedback(program))
2502 {
2503 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002504 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002505 "Cannot change program binary while program is associated with "
2506 "an active transform feedback object."));
2507 return false;
2508 }
2509
Geoff Langc5629752015-12-07 16:29:04 -05002510 return true;
2511}
2512
2513bool ValidateGetProgramBinaryBase(Context *context,
2514 GLuint program,
2515 GLsizei bufSize,
2516 GLsizei *length,
2517 GLenum *binaryFormat,
2518 void *binary)
2519{
2520 Program *programObject = GetValidProgram(context, program);
2521 if (programObject == nullptr)
2522 {
2523 return false;
2524 }
2525
2526 if (!programObject->isLinked())
2527 {
Jamie Madill437fa652016-05-03 15:13:24 -04002528 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002529 return false;
2530 }
2531
2532 return true;
2533}
Jamie Madillc29968b2016-01-20 11:17:23 -05002534
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002535bool ValidateUseProgram(Context *context, GLuint program)
2536{
2537 if (program != 0)
2538 {
2539 Program *programObject = context->getProgram(program);
2540 if (!programObject)
2541 {
2542 // ES 3.1.0 section 7.3 page 72
2543 if (context->getShader(program))
2544 {
Jamie Madill437fa652016-05-03 15:13:24 -04002545 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002546 Error(GL_INVALID_OPERATION,
2547 "Attempted to use a single shader instead of a shader program."));
2548 return false;
2549 }
2550 else
2551 {
Jamie Madill437fa652016-05-03 15:13:24 -04002552 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002553 return false;
2554 }
2555 }
2556 if (!programObject->isLinked())
2557 {
Jamie Madill437fa652016-05-03 15:13:24 -04002558 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002559 return false;
2560 }
2561 }
2562 if (context->getState().isTransformFeedbackActiveUnpaused())
2563 {
2564 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002565 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002566 Error(GL_INVALID_OPERATION,
2567 "Cannot change active program while transform feedback is unpaused."));
2568 return false;
2569 }
2570
2571 return true;
2572}
2573
Jamie Madillc29968b2016-01-20 11:17:23 -05002574bool ValidateCopyTexImage2D(ValidationContext *context,
2575 GLenum target,
2576 GLint level,
2577 GLenum internalformat,
2578 GLint x,
2579 GLint y,
2580 GLsizei width,
2581 GLsizei height,
2582 GLint border)
2583{
2584 if (context->getClientVersion() < 3)
2585 {
2586 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2587 0, x, y, width, height, border);
2588 }
2589
2590 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002591 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2592 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002593}
Jamie Madillc29968b2016-01-20 11:17:23 -05002594
2595bool ValidateFramebufferRenderbuffer(Context *context,
2596 GLenum target,
2597 GLenum attachment,
2598 GLenum renderbuffertarget,
2599 GLuint renderbuffer)
2600{
2601 if (!ValidFramebufferTarget(target) ||
2602 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2603 {
Jamie Madill437fa652016-05-03 15:13:24 -04002604 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002605 return false;
2606 }
2607
2608 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2609 renderbuffertarget, renderbuffer);
2610}
2611
2612bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2613{
2614 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2615 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2616 {
Jamie Madill437fa652016-05-03 15:13:24 -04002617 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002618 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2619 return false;
2620 }
2621
2622 ASSERT(context->getState().getDrawFramebuffer());
2623 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2624 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2625
2626 // This should come first before the check for the default frame buffer
2627 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2628 // rather than INVALID_OPERATION
2629 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2630 {
2631 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2632
2633 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002634 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2635 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002636 {
2637 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002638 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2639 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2640 // 3.1 is still a bit ambiguous about the error, but future specs are
2641 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002642 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002643 return false;
2644 }
2645 else if (bufs[colorAttachment] >= maxColorAttachment)
2646 {
Jamie Madill437fa652016-05-03 15:13:24 -04002647 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002648 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002649 return false;
2650 }
2651 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2652 frameBufferId != 0)
2653 {
2654 // INVALID_OPERATION-GL is bound to buffer and ith argument
2655 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002656 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002657 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2658 return false;
2659 }
2660 }
2661
2662 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2663 // and n is not 1 or bufs is bound to value other than BACK and NONE
2664 if (frameBufferId == 0)
2665 {
2666 if (n != 1)
2667 {
Jamie Madill437fa652016-05-03 15:13:24 -04002668 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002669 "n must be 1 when GL is bound to the default framebuffer"));
2670 return false;
2671 }
2672
2673 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2674 {
Jamie Madill437fa652016-05-03 15:13:24 -04002675 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002676 GL_INVALID_OPERATION,
2677 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2678 return false;
2679 }
2680 }
2681
2682 return true;
2683}
2684
2685bool ValidateCopyTexSubImage2D(Context *context,
2686 GLenum target,
2687 GLint level,
2688 GLint xoffset,
2689 GLint yoffset,
2690 GLint x,
2691 GLint y,
2692 GLsizei width,
2693 GLsizei height)
2694{
2695 if (context->getClientVersion() < 3)
2696 {
2697 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2698 yoffset, x, y, width, height, 0);
2699 }
2700
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002701 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2702 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002703}
2704
Olli Etuaho4f667482016-03-30 15:56:35 +03002705bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2706{
2707 if (!ValidBufferTarget(context, target))
2708 {
Jamie Madill437fa652016-05-03 15:13:24 -04002709 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002710 return false;
2711 }
2712
2713 if (pname != GL_BUFFER_MAP_POINTER)
2714 {
Jamie Madill437fa652016-05-03 15:13:24 -04002715 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002716 return false;
2717 }
2718
2719 Buffer *buffer = context->getState().getTargetBuffer(target);
2720
2721 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2722 // target bound to zero generate an INVALID_OPERATION error."
2723 // GLES 3.1 section 6.6 explicitly specifies this error.
2724 if (!buffer)
2725 {
Jamie Madill437fa652016-05-03 15:13:24 -04002726 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002727 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2728 return false;
2729 }
2730
2731 return true;
2732}
2733
2734bool ValidateUnmapBufferBase(Context *context, GLenum target)
2735{
2736 if (!ValidBufferTarget(context, target))
2737 {
Jamie Madill437fa652016-05-03 15:13:24 -04002738 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002739 return false;
2740 }
2741
2742 Buffer *buffer = context->getState().getTargetBuffer(target);
2743
2744 if (buffer == nullptr || !buffer->isMapped())
2745 {
Jamie Madill437fa652016-05-03 15:13:24 -04002746 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002747 return false;
2748 }
2749
2750 return true;
2751}
2752
2753bool ValidateMapBufferRangeBase(Context *context,
2754 GLenum target,
2755 GLintptr offset,
2756 GLsizeiptr length,
2757 GLbitfield access)
2758{
2759 if (!ValidBufferTarget(context, target))
2760 {
Jamie Madill437fa652016-05-03 15:13:24 -04002761 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002762 return false;
2763 }
2764
2765 if (offset < 0 || length < 0)
2766 {
Jamie Madill437fa652016-05-03 15:13:24 -04002767 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002768 return false;
2769 }
2770
2771 Buffer *buffer = context->getState().getTargetBuffer(target);
2772
2773 if (!buffer)
2774 {
Jamie Madill437fa652016-05-03 15:13:24 -04002775 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002776 return false;
2777 }
2778
2779 // Check for buffer overflow
2780 size_t offsetSize = static_cast<size_t>(offset);
2781 size_t lengthSize = static_cast<size_t>(length);
2782
2783 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2784 offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
2785 {
Jamie Madill437fa652016-05-03 15:13:24 -04002786 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002787 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2788 return false;
2789 }
2790
2791 // Check for invalid bits in the mask
2792 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2793 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2794 GL_MAP_UNSYNCHRONIZED_BIT;
2795
2796 if (access & ~(allAccessBits))
2797 {
Jamie Madill437fa652016-05-03 15:13:24 -04002798 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002799 return false;
2800 }
2801
2802 if (length == 0)
2803 {
Jamie Madill437fa652016-05-03 15:13:24 -04002804 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002805 return false;
2806 }
2807
2808 if (buffer->isMapped())
2809 {
Jamie Madill437fa652016-05-03 15:13:24 -04002810 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002811 return false;
2812 }
2813
2814 // Check for invalid bit combinations
2815 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2816 {
Jamie Madill437fa652016-05-03 15:13:24 -04002817 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002818 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2819 return false;
2820 }
2821
2822 GLbitfield writeOnlyBits =
2823 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2824
2825 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2826 {
Jamie Madill437fa652016-05-03 15:13:24 -04002827 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002828 "Invalid access bits when mapping buffer for reading: 0x%X.",
2829 access));
2830 return false;
2831 }
2832
2833 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2834 {
Jamie Madill437fa652016-05-03 15:13:24 -04002835 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002836 GL_INVALID_OPERATION,
2837 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2838 return false;
2839 }
2840 return true;
2841}
2842
2843bool ValidateFlushMappedBufferRangeBase(Context *context,
2844 GLenum target,
2845 GLintptr offset,
2846 GLsizeiptr length)
2847{
2848 if (offset < 0 || length < 0)
2849 {
Jamie Madill437fa652016-05-03 15:13:24 -04002850 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002851 return false;
2852 }
2853
2854 if (!ValidBufferTarget(context, target))
2855 {
Jamie Madill437fa652016-05-03 15:13:24 -04002856 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002857 return false;
2858 }
2859
2860 Buffer *buffer = context->getState().getTargetBuffer(target);
2861
2862 if (buffer == nullptr)
2863 {
Jamie Madill437fa652016-05-03 15:13:24 -04002864 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002865 return false;
2866 }
2867
2868 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2869 {
Jamie Madill437fa652016-05-03 15:13:24 -04002870 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002871 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2872 return false;
2873 }
2874
2875 // Check for buffer overflow
2876 size_t offsetSize = static_cast<size_t>(offset);
2877 size_t lengthSize = static_cast<size_t>(length);
2878
2879 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2880 offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
2881 {
Jamie Madill437fa652016-05-03 15:13:24 -04002882 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002883 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2884 return false;
2885 }
2886
2887 return true;
2888}
2889
Olli Etuaho41997e72016-03-10 13:38:39 +02002890bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2891{
2892 return ValidateGenOrDelete(context, n);
2893}
2894
2895bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2896{
2897 return ValidateGenOrDelete(context, n);
2898}
2899
2900bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2901{
2902 return ValidateGenOrDelete(context, n);
2903}
2904
2905bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2906{
2907 return ValidateGenOrDelete(context, n);
2908}
2909
2910bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2911{
2912 return ValidateGenOrDelete(context, n);
2913}
2914
2915bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2916{
2917 return ValidateGenOrDelete(context, n);
2918}
2919
2920bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2921{
2922 return ValidateGenOrDelete(context, n);
2923}
2924
2925bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2926{
2927 return ValidateGenOrDelete(context, n);
2928}
2929
2930bool ValidateGenOrDelete(Context *context, GLint n)
2931{
2932 if (n < 0)
2933 {
Jamie Madill437fa652016-05-03 15:13:24 -04002934 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02002935 return false;
2936 }
2937 return true;
2938}
2939
Jamie Madillc29968b2016-01-20 11:17:23 -05002940} // namespace gl