blob: 40db7aaee080bd1ac401b8c9f832e8afb0fad587 [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 Lang2b4ce802016-04-28 13:34:50 -0400401 case GL_COMMANDS_COMPLETED_CHROMIUM:
402 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500403 default:
404 return false;
405 }
406}
407
Dian Xiang769769a2015-09-09 15:20:08 -0700408Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500409{
410 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
411 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
412 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
413
Dian Xiang769769a2015-09-09 15:20:08 -0700414 Program *validProgram = context->getProgram(id);
415
416 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500417 {
Dian Xiang769769a2015-09-09 15:20:08 -0700418 if (context->getShader(id))
419 {
Jamie Madill437fa652016-05-03 15:13:24 -0400420 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700421 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
422 }
423 else
424 {
Jamie Madill437fa652016-05-03 15:13:24 -0400425 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700426 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500427 }
Dian Xiang769769a2015-09-09 15:20:08 -0700428
429 return validProgram;
430}
431
432Shader *GetValidShader(Context *context, GLuint id)
433{
434 // See ValidProgram for spec details.
435
436 Shader *validShader = context->getShader(id);
437
438 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500439 {
Dian Xiang769769a2015-09-09 15:20:08 -0700440 if (context->getProgram(id))
441 {
Jamie Madill437fa652016-05-03 15:13:24 -0400442 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700443 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
444 }
445 else
446 {
Jamie Madill437fa652016-05-03 15:13:24 -0400447 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700448 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500449 }
Dian Xiang769769a2015-09-09 15:20:08 -0700450
451 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500452}
453
Geoff Langb1196682014-07-23 13:47:29 -0400454bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400455{
456 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
457 {
458 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
459
Geoff Langaae65a42014-05-26 12:43:44 -0400460 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400461 {
Jamie Madill437fa652016-05-03 15:13:24 -0400462 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400463 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400464 }
465 }
466 else
467 {
468 switch (attachment)
469 {
470 case GL_DEPTH_ATTACHMENT:
471 case GL_STENCIL_ATTACHMENT:
472 break;
473
474 case GL_DEPTH_STENCIL_ATTACHMENT:
475 if (context->getClientVersion() < 3)
476 {
Jamie Madill437fa652016-05-03 15:13:24 -0400477 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400478 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400479 }
480 break;
481
482 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400483 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400484 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400485 }
486 }
487
488 return true;
489}
490
Corentin Walleze0902642014-11-04 12:32:15 -0800491bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
492 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400493{
494 switch (target)
495 {
496 case GL_RENDERBUFFER:
497 break;
498 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400499 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400500 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400501 }
502
503 if (width < 0 || height < 0 || samples < 0)
504 {
Jamie Madill437fa652016-05-03 15:13:24 -0400505 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400506 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400507 }
508
Geoff Langd87878e2014-09-19 15:42:59 -0400509 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
510 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400511 {
Jamie Madill437fa652016-05-03 15:13:24 -0400512 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400513 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400514 }
515
516 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
517 // 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 -0800518 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400519 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400520 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400521 {
Jamie Madill437fa652016-05-03 15:13:24 -0400522 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400523 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400524 }
525
Geoff Langaae65a42014-05-26 12:43:44 -0400526 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400527 {
Jamie Madill437fa652016-05-03 15:13:24 -0400528 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400529 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400530 }
531
Shannon Woods53a94a82014-06-24 15:20:36 -0400532 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400533 if (handle == 0)
534 {
Jamie Madill437fa652016-05-03 15:13:24 -0400535 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400536 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400537 }
538
539 return true;
540}
541
Corentin Walleze0902642014-11-04 12:32:15 -0800542bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
543 GLenum internalformat, GLsizei width, GLsizei height)
544{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800545 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800546
547 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400548 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800549 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400550 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800551 {
Jamie Madill437fa652016-05-03 15:13:24 -0400552 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800553 return false;
554 }
555
556 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
557 // the specified storage. This is different than ES 3.0 in which a sample number higher
558 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800559 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
560 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800561 {
Geoff Langa4903b72015-03-02 16:02:48 -0800562 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
563 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
564 {
Jamie Madill437fa652016-05-03 15:13:24 -0400565 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800566 return false;
567 }
Corentin Walleze0902642014-11-04 12:32:15 -0800568 }
569
570 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
571}
572
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500573bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
574 GLenum renderbuffertarget, GLuint renderbuffer)
575{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400576 if (!ValidFramebufferTarget(target))
577 {
Jamie Madill437fa652016-05-03 15:13:24 -0400578 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400579 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400580 }
581
Shannon Woods53a94a82014-06-24 15:20:36 -0400582 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500583
Jamie Madill84115c92015-04-23 15:00:07 -0400584 ASSERT(framebuffer);
585 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500586 {
Jamie Madill437fa652016-05-03 15:13:24 -0400587 context->handleError(
588 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400589 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500590 }
591
Jamie Madillb4472272014-07-03 10:38:55 -0400592 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500593 {
Jamie Madillb4472272014-07-03 10:38:55 -0400594 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500595 }
596
Jamie Madillab9d82c2014-01-21 16:38:14 -0500597 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
598 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
599 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
600 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
601 if (renderbuffer != 0)
602 {
603 if (!context->getRenderbuffer(renderbuffer))
604 {
Jamie Madill437fa652016-05-03 15:13:24 -0400605 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400606 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500607 }
608 }
609
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500610 return true;
611}
612
Jamie Madillc29968b2016-01-20 11:17:23 -0500613bool ValidateBlitFramebufferParameters(gl::Context *context,
614 GLint srcX0,
615 GLint srcY0,
616 GLint srcX1,
617 GLint srcY1,
618 GLint dstX0,
619 GLint dstY0,
620 GLint dstX1,
621 GLint dstY1,
622 GLbitfield mask,
623 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624{
625 switch (filter)
626 {
627 case GL_NEAREST:
628 break;
629 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400630 break;
631 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400632 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400633 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634 }
635
636 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
637 {
Jamie Madill437fa652016-05-03 15:13:24 -0400638 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400639 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640 }
641
642 if (mask == 0)
643 {
644 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
645 // buffers are copied.
646 return false;
647 }
648
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
650 // color buffer, leaving only nearest being unfiltered from above
651 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
652 {
Jamie Madill437fa652016-05-03 15:13:24 -0400653 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400654 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 }
656
Shannon Woods53a94a82014-06-24 15:20:36 -0400657 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400658 {
Jamie Madill437fa652016-05-03 15:13:24 -0400659 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400660 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400661 }
662
Jamie Madille3ef7152015-04-28 16:55:17 +0000663 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
664 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500665
666 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667 {
Jamie Madill437fa652016-05-03 15:13:24 -0400668 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400669 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670 }
671
Geoff Lang748f74e2014-12-01 11:25:34 -0500672 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500673 {
Jamie Madill437fa652016-05-03 15:13:24 -0400674 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500675 return false;
676 }
677
Geoff Lang748f74e2014-12-01 11:25:34 -0500678 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500679 {
Jamie Madill437fa652016-05-03 15:13:24 -0400680 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500681 return false;
682 }
683
684 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400685 {
Jamie Madill437fa652016-05-03 15:13:24 -0400686 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400687 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400688 }
689
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
691
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400692 if (mask & GL_COLOR_BUFFER_BIT)
693 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400694 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
695 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500696 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697
698 if (readColorBuffer && drawColorBuffer)
699 {
Geoff Langd8a22582014-12-17 15:28:23 -0500700 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400701 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400702
Geoff Langa15472a2015-08-11 11:48:03 -0400703 for (size_t drawbufferIdx = 0;
704 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400705 {
Geoff Langa15472a2015-08-11 11:48:03 -0400706 const FramebufferAttachment *attachment =
707 drawFramebuffer->getDrawBuffer(drawbufferIdx);
708 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709 {
Geoff Langa15472a2015-08-11 11:48:03 -0400710 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400711 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400712
Geoff Langb2f3d052013-08-13 12:49:27 -0400713 // The GL ES 3.0.2 spec (pg 193) states that:
714 // 1) If the read buffer is fixed point format, the draw buffer must be as well
715 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
716 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500717 // Changes with EXT_color_buffer_float:
718 // Case 1) is changed to fixed point OR floating point
719 GLenum readComponentType = readFormatInfo.componentType;
720 GLenum drawComponentType = drawFormatInfo.componentType;
721 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
722 readComponentType == GL_SIGNED_NORMALIZED);
723 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
724 drawComponentType == GL_SIGNED_NORMALIZED);
725
726 if (extensions.colorBufferFloat)
727 {
728 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
729 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
730
731 if (readFixedOrFloat != drawFixedOrFloat)
732 {
Jamie Madill437fa652016-05-03 15:13:24 -0400733 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500734 "If the read buffer contains fixed-point or "
735 "floating-point values, the draw buffer "
736 "must as well."));
737 return false;
738 }
739 }
740 else if (readFixedPoint != drawFixedPoint)
741 {
Jamie Madill437fa652016-05-03 15:13:24 -0400742 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500743 "If the read buffer contains fixed-point "
744 "values, the draw buffer must as well."));
745 return false;
746 }
747
748 if (readComponentType == GL_UNSIGNED_INT &&
749 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400750 {
Jamie Madill437fa652016-05-03 15:13:24 -0400751 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400752 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400753 }
754
Jamie Madill6163c752015-12-07 16:32:59 -0500755 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400756 {
Jamie Madill437fa652016-05-03 15:13:24 -0400757 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400758 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 }
760
Geoff Langb2f3d052013-08-13 12:49:27 -0400761 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 {
Jamie Madill437fa652016-05-03 15:13:24 -0400763 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400764 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400765 }
766 }
767 }
768
Geoff Lang5d601382014-07-22 15:14:06 -0400769 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 {
Jamie Madill437fa652016-05-03 15:13:24 -0400771 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400772 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 }
775 }
776
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200777 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
778 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
779 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200781 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400782 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400783 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
784 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200786 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 {
Geoff Langd8a22582014-12-17 15:28:23 -0500788 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400789 {
Jamie Madill437fa652016-05-03 15:13:24 -0400790 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400791 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400792 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200794 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 {
Jamie Madill437fa652016-05-03 15:13:24 -0400796 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400797 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798 }
799 }
800 }
801 }
802
803 return true;
804}
805
Geoff Langb1196682014-07-23 13:47:29 -0400806bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400807{
808 switch (pname)
809 {
810 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
811 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
812 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
813 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
814 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
815 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
816 case GL_CURRENT_VERTEX_ATTRIB:
817 return true;
818
819 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
820 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
821 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400822 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
823 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400824 return true;
825
826 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400827 if (context->getClientVersion() < 3)
828 {
Jamie Madill437fa652016-05-03 15:13:24 -0400829 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400830 return false;
831 }
832 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400833
834 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400835 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400836 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400837 }
838}
839
Ian Ewellbda75592016-04-18 17:25:54 -0400840bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400841{
842 switch (pname)
843 {
844 case GL_TEXTURE_WRAP_R:
845 case GL_TEXTURE_SWIZZLE_R:
846 case GL_TEXTURE_SWIZZLE_G:
847 case GL_TEXTURE_SWIZZLE_B:
848 case GL_TEXTURE_SWIZZLE_A:
849 case GL_TEXTURE_BASE_LEVEL:
850 case GL_TEXTURE_MAX_LEVEL:
851 case GL_TEXTURE_COMPARE_MODE:
852 case GL_TEXTURE_COMPARE_FUNC:
853 case GL_TEXTURE_MIN_LOD:
854 case GL_TEXTURE_MAX_LOD:
Ian Ewellbda75592016-04-18 17:25:54 -0400855 // ES3 texture paramters are not supported on external textures as the extension is
856 // written against ES2.
857 if (context->getClientVersion() < 3 || target == GL_TEXTURE_EXTERNAL_OES)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400858 {
Jamie Madill437fa652016-05-03 15:13:24 -0400859 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400860 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400861 }
862 break;
863
864 default: break;
865 }
866
867 switch (pname)
868 {
869 case GL_TEXTURE_WRAP_S:
870 case GL_TEXTURE_WRAP_T:
871 case GL_TEXTURE_WRAP_R:
872 switch (param)
873 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000874 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400875 return true;
876 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400877 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300878 if (target == GL_TEXTURE_EXTERNAL_OES)
879 {
880 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400881 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300882 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
883 return false;
884 }
885 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400886 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400887 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400888 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400889 }
890
891 case GL_TEXTURE_MIN_FILTER:
892 switch (param)
893 {
894 case GL_NEAREST:
895 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400896 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400897 case GL_NEAREST_MIPMAP_NEAREST:
898 case GL_LINEAR_MIPMAP_NEAREST:
899 case GL_NEAREST_MIPMAP_LINEAR:
900 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300901 if (target == GL_TEXTURE_EXTERNAL_OES)
902 {
903 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400904 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300905 Error(GL_INVALID_ENUM,
906 "external textures only support NEAREST and LINEAR filtering"));
907 return false;
908 }
909 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400910 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400911 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400912 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400913 }
914 break;
915
916 case GL_TEXTURE_MAG_FILTER:
917 switch (param)
918 {
919 case GL_NEAREST:
920 case GL_LINEAR:
921 return true;
922 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400923 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400924 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400925 }
926 break;
927
928 case GL_TEXTURE_USAGE_ANGLE:
929 switch (param)
930 {
931 case GL_NONE:
932 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
933 return true;
934 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400935 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400936 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400937 }
938 break;
939
940 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400941 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400942 {
Jamie Madill437fa652016-05-03 15:13:24 -0400943 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400944 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400945 }
946
947 // we assume the parameter passed to this validation method is truncated, not rounded
948 if (param < 1)
949 {
Jamie Madill437fa652016-05-03 15:13:24 -0400950 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400951 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400952 }
953 return true;
954
955 case GL_TEXTURE_MIN_LOD:
956 case GL_TEXTURE_MAX_LOD:
957 // any value is permissible
958 return true;
959
960 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400961 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400962 switch (param)
963 {
964 case GL_NONE:
965 case GL_COMPARE_REF_TO_TEXTURE:
966 return true;
967 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400968 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400969 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400970 }
971 break;
972
973 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400974 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400975 switch (param)
976 {
977 case GL_LEQUAL:
978 case GL_GEQUAL:
979 case GL_LESS:
980 case GL_GREATER:
981 case GL_EQUAL:
982 case GL_NOTEQUAL:
983 case GL_ALWAYS:
984 case GL_NEVER:
985 return true;
986 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400987 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400988 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400989 }
990 break;
991
992 case GL_TEXTURE_SWIZZLE_R:
993 case GL_TEXTURE_SWIZZLE_G:
994 case GL_TEXTURE_SWIZZLE_B:
995 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400996 switch (param)
997 {
998 case GL_RED:
999 case GL_GREEN:
1000 case GL_BLUE:
1001 case GL_ALPHA:
1002 case GL_ZERO:
1003 case GL_ONE:
1004 return true;
1005 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001006 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001007 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001008 }
1009 break;
1010
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001011 case GL_TEXTURE_BASE_LEVEL:
1012 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001013 if (target == GL_TEXTURE_EXTERNAL_OES)
1014 {
1015 // This is not specified, but in line with the spirit of OES_EGL_image_external spec,
1016 // which generally forbids setting mipmap related parameters on external textures.
1017 context->handleError(
1018 Error(GL_INVALID_OPERATION,
1019 "Setting the base level or max level of external textures not supported"));
1020 return false;
1021 }
1022 if (param < 0)
1023 {
1024 context->handleError(Error(GL_INVALID_VALUE));
1025 return false;
1026 }
1027 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001028 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001029 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001030 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001031 }
1032}
1033
Geoff Langb1196682014-07-23 13:47:29 -04001034bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001035{
1036 switch (pname)
1037 {
1038 case GL_TEXTURE_MIN_FILTER:
1039 case GL_TEXTURE_MAG_FILTER:
1040 case GL_TEXTURE_WRAP_S:
1041 case GL_TEXTURE_WRAP_T:
1042 case GL_TEXTURE_WRAP_R:
1043 case GL_TEXTURE_MIN_LOD:
1044 case GL_TEXTURE_MAX_LOD:
1045 case GL_TEXTURE_COMPARE_MODE:
1046 case GL_TEXTURE_COMPARE_FUNC:
1047 return true;
1048
1049 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001050 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001051 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001052 }
1053}
1054
Jamie Madillc29968b2016-01-20 11:17:23 -05001055bool ValidateReadPixels(Context *context,
1056 GLint x,
1057 GLint y,
1058 GLsizei width,
1059 GLsizei height,
1060 GLenum format,
1061 GLenum type,
1062 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001063{
Jamie Madillc29968b2016-01-20 11:17:23 -05001064 if (width < 0 || height < 0)
1065 {
Jamie Madill437fa652016-05-03 15:13:24 -04001066 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001067 return false;
1068 }
1069
1070 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001071 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001072
Geoff Lang748f74e2014-12-01 11:25:34 -05001073 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001074 {
Jamie Madill437fa652016-05-03 15:13:24 -04001075 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001076 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001077 }
1078
Jamie Madill48faf802014-11-06 15:27:22 -05001079 if (context->getState().getReadFramebuffer()->id() != 0 &&
1080 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001081 {
Jamie Madill437fa652016-05-03 15:13:24 -04001082 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001083 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001084 }
1085
Geoff Langbce529e2014-12-01 12:48:41 -05001086 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1087 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001088 {
Jamie Madill437fa652016-05-03 15:13:24 -04001089 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001090 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001091 }
1092
Geoff Langbce529e2014-12-01 12:48:41 -05001093 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1094 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001095 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001096 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001097
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001098 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1099 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001100
1101 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1102 {
Jamie Madill437fa652016-05-03 15:13:24 -04001103 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001104 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001105 }
1106
Jamie Madillc29968b2016-01-20 11:17:23 -05001107 return true;
1108}
1109
1110bool ValidateReadnPixelsEXT(Context *context,
1111 GLint x,
1112 GLint y,
1113 GLsizei width,
1114 GLsizei height,
1115 GLenum format,
1116 GLenum type,
1117 GLsizei bufSize,
1118 GLvoid *pixels)
1119{
1120 if (bufSize < 0)
1121 {
Jamie Madill437fa652016-05-03 15:13:24 -04001122 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001123 return false;
1124 }
1125
Geoff Lang5d601382014-07-22 15:14:06 -04001126 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1127 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001128
Minmin Gongadff67b2015-10-14 10:34:45 -04001129 GLsizei outputPitch =
1130 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1131 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001132 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001133 int requiredSize = outputPitch * height;
1134 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001135 {
Jamie Madill437fa652016-05-03 15:13:24 -04001136 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001137 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001138 }
1139
Jamie Madillc29968b2016-01-20 11:17:23 -05001140 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001141}
1142
Olli Etuaho41997e72016-03-10 13:38:39 +02001143bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001144{
1145 if (!context->getExtensions().occlusionQueryBoolean &&
1146 !context->getExtensions().disjointTimerQuery)
1147 {
Jamie Madill437fa652016-05-03 15:13:24 -04001148 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001149 return false;
1150 }
1151
Olli Etuaho41997e72016-03-10 13:38:39 +02001152 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001153}
1154
Olli Etuaho41997e72016-03-10 13:38:39 +02001155bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001156{
1157 if (!context->getExtensions().occlusionQueryBoolean &&
1158 !context->getExtensions().disjointTimerQuery)
1159 {
Jamie Madill437fa652016-05-03 15:13:24 -04001160 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001161 return false;
1162 }
1163
Olli Etuaho41997e72016-03-10 13:38:39 +02001164 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001165}
1166
1167bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001168{
1169 if (!ValidQueryType(context, target))
1170 {
Jamie Madill437fa652016-05-03 15:13:24 -04001171 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001172 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001173 }
1174
1175 if (id == 0)
1176 {
Jamie Madill437fa652016-05-03 15:13:24 -04001177 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001178 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001179 }
1180
1181 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1182 // of zero, if the active query object name for <target> is non-zero (for the
1183 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1184 // the active query for either target is non-zero), if <id> is the name of an
1185 // existing query object whose type does not match <target>, or if <id> is the
1186 // active query object name for any query type, the error INVALID_OPERATION is
1187 // generated.
1188
1189 // Ensure no other queries are active
1190 // NOTE: If other queries than occlusion are supported, we will need to check
1191 // separately that:
1192 // a) The query ID passed is not the current active query for any target/type
1193 // b) There are no active queries for the requested target (and in the case
1194 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1195 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001196
Corentin Walleze71ea192016-04-19 13:16:37 -04001197 if (context->getState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001198 {
Jamie Madill437fa652016-05-03 15:13:24 -04001199 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001200 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001201 }
1202
1203 Query *queryObject = context->getQuery(id, true, target);
1204
1205 // check that name was obtained with glGenQueries
1206 if (!queryObject)
1207 {
Jamie Madill437fa652016-05-03 15:13:24 -04001208 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001209 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001210 }
1211
1212 // check for type mismatch
1213 if (queryObject->getType() != target)
1214 {
Jamie Madill437fa652016-05-03 15:13:24 -04001215 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001216 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001217 }
1218
1219 return true;
1220}
1221
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001222bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1223{
1224 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001225 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001226 {
Jamie Madill437fa652016-05-03 15:13:24 -04001227 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001228 return false;
1229 }
1230
1231 return ValidateBeginQueryBase(context, target, id);
1232}
1233
1234bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001235{
1236 if (!ValidQueryType(context, target))
1237 {
Jamie Madill437fa652016-05-03 15:13:24 -04001238 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001239 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001240 }
1241
Shannon Woods53a94a82014-06-24 15:20:36 -04001242 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001243
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001244 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001245 {
Jamie Madill437fa652016-05-03 15:13:24 -04001246 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001247 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001248 }
1249
Jamie Madill45c785d2014-05-13 14:09:34 -04001250 return true;
1251}
1252
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001253bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1254{
1255 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001256 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001257 {
Jamie Madill437fa652016-05-03 15:13:24 -04001258 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001259 return false;
1260 }
1261
1262 return ValidateEndQueryBase(context, target);
1263}
1264
1265bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1266{
1267 if (!context->getExtensions().disjointTimerQuery)
1268 {
Jamie Madill437fa652016-05-03 15:13:24 -04001269 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001270 return false;
1271 }
1272
1273 if (target != GL_TIMESTAMP_EXT)
1274 {
Jamie Madill437fa652016-05-03 15:13:24 -04001275 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001276 return false;
1277 }
1278
1279 Query *queryObject = context->getQuery(id, true, target);
1280 if (queryObject == nullptr)
1281 {
Jamie Madill437fa652016-05-03 15:13:24 -04001282 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001283 return false;
1284 }
1285
1286 if (context->getState().isQueryActive(queryObject))
1287 {
Jamie Madill437fa652016-05-03 15:13:24 -04001288 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001289 return false;
1290 }
1291
1292 return true;
1293}
1294
1295bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1296{
1297 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1298 {
Jamie Madill437fa652016-05-03 15:13:24 -04001299 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001300 return false;
1301 }
1302
1303 switch (pname)
1304 {
1305 case GL_CURRENT_QUERY_EXT:
1306 if (target == GL_TIMESTAMP_EXT)
1307 {
Jamie Madill437fa652016-05-03 15:13:24 -04001308 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001309 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1310 return false;
1311 }
1312 break;
1313 case GL_QUERY_COUNTER_BITS_EXT:
1314 if (!context->getExtensions().disjointTimerQuery ||
1315 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1316 {
Jamie Madill437fa652016-05-03 15:13:24 -04001317 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001318 return false;
1319 }
1320 break;
1321 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001322 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001323 return false;
1324 }
1325
1326 return true;
1327}
1328
1329bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1330{
1331 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001332 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001333 {
Jamie Madill437fa652016-05-03 15:13:24 -04001334 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001335 return false;
1336 }
1337
1338 return ValidateGetQueryivBase(context, target, pname);
1339}
1340
1341bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1342{
1343 Query *queryObject = context->getQuery(id, false, GL_NONE);
1344
1345 if (!queryObject)
1346 {
Jamie Madill437fa652016-05-03 15:13:24 -04001347 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001348 return false;
1349 }
1350
1351 if (context->getState().isQueryActive(queryObject))
1352 {
Jamie Madill437fa652016-05-03 15:13:24 -04001353 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001354 return false;
1355 }
1356
1357 switch (pname)
1358 {
1359 case GL_QUERY_RESULT_EXT:
1360 case GL_QUERY_RESULT_AVAILABLE_EXT:
1361 break;
1362
1363 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001364 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001365 return false;
1366 }
1367
1368 return true;
1369}
1370
1371bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1372{
1373 if (!context->getExtensions().disjointTimerQuery)
1374 {
Jamie Madill437fa652016-05-03 15:13:24 -04001375 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001376 return false;
1377 }
1378 return ValidateGetQueryObjectValueBase(context, id, pname);
1379}
1380
1381bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1382{
1383 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001384 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001385 {
Jamie Madill437fa652016-05-03 15:13:24 -04001386 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001387 return false;
1388 }
1389 return ValidateGetQueryObjectValueBase(context, id, pname);
1390}
1391
1392bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *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
1402bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1403{
1404 if (!context->getExtensions().disjointTimerQuery)
1405 {
Jamie Madill437fa652016-05-03 15:13:24 -04001406 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001407 return false;
1408 }
1409 return ValidateGetQueryObjectValueBase(context, id, pname);
1410}
1411
Jamie Madill62d31cb2015-09-11 13:25:51 -04001412static bool ValidateUniformCommonBase(gl::Context *context,
1413 GLenum targetUniformType,
1414 GLint location,
1415 GLsizei count,
1416 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001417{
1418 if (count < 0)
1419 {
Jamie Madill437fa652016-05-03 15:13:24 -04001420 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001421 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001422 }
1423
Geoff Lang7dd2e102014-11-10 15:19:26 -05001424 gl::Program *program = context->getState().getProgram();
1425 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001426 {
Jamie Madill437fa652016-05-03 15:13:24 -04001427 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001428 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001429 }
1430
Geoff Langd8605522016-04-13 10:19:12 -04001431 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001432 {
1433 // Silently ignore the uniform command
1434 return false;
1435 }
1436
Geoff Lang7dd2e102014-11-10 15:19:26 -05001437 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001438 {
Jamie Madill437fa652016-05-03 15:13:24 -04001439 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001440 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001441 }
1442
Jamie Madill62d31cb2015-09-11 13:25:51 -04001443 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001444
1445 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001446 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001447 {
Jamie Madill437fa652016-05-03 15:13:24 -04001448 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001449 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001450 }
1451
Jamie Madill62d31cb2015-09-11 13:25:51 -04001452 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001453 return true;
1454}
1455
Jamie Madillaa981bd2014-05-20 10:55:55 -04001456bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1457{
1458 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001459 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001460 {
Jamie Madill437fa652016-05-03 15:13:24 -04001461 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001462 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001463 }
1464
Jamie Madill62d31cb2015-09-11 13:25:51 -04001465 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001466 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1467 {
1468 return false;
1469 }
1470
Jamie Madillf2575982014-06-25 16:04:54 -04001471 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001472 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001473 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1474 {
Jamie Madill437fa652016-05-03 15:13:24 -04001475 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001476 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001477 }
1478
1479 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001480}
1481
1482bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1483 GLboolean transpose)
1484{
1485 // Check for ES3 uniform entry points
1486 int rows = VariableRowCount(matrixType);
1487 int cols = VariableColumnCount(matrixType);
1488 if (rows != cols && context->getClientVersion() < 3)
1489 {
Jamie Madill437fa652016-05-03 15:13:24 -04001490 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001491 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001492 }
1493
1494 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1495 {
Jamie Madill437fa652016-05-03 15:13:24 -04001496 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001497 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001498 }
1499
Jamie Madill62d31cb2015-09-11 13:25:51 -04001500 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001501 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1502 {
1503 return false;
1504 }
1505
1506 if (uniform->type != matrixType)
1507 {
Jamie Madill437fa652016-05-03 15:13:24 -04001508 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001509 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001510 }
1511
1512 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001513}
1514
Jamie Madill893ab082014-05-16 16:56:10 -04001515bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1516{
1517 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1518 {
Jamie Madill437fa652016-05-03 15:13:24 -04001519 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001520 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001521 }
1522
Jamie Madill0af26e12015-03-05 19:54:33 -05001523 const Caps &caps = context->getCaps();
1524
Jamie Madill893ab082014-05-16 16:56:10 -04001525 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1526 {
1527 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1528
Jamie Madill0af26e12015-03-05 19:54:33 -05001529 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001530 {
Jamie Madill437fa652016-05-03 15:13:24 -04001531 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001532 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001533 }
1534 }
1535
1536 switch (pname)
1537 {
1538 case GL_TEXTURE_BINDING_2D:
1539 case GL_TEXTURE_BINDING_CUBE_MAP:
1540 case GL_TEXTURE_BINDING_3D:
1541 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001542 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001543 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1544 if (!context->getExtensions().eglStreamConsumerExternal)
1545 {
Jamie Madill437fa652016-05-03 15:13:24 -04001546 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001547 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1548 return false;
1549 }
1550 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001551
1552 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1553 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1554 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001555 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001556 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001557 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001558 {
Jamie Madill437fa652016-05-03 15:13:24 -04001559 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001560 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001561 }
1562
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001563 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001564 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001565 {
Jamie Madill437fa652016-05-03 15:13:24 -04001566 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001567 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001568 }
1569 }
1570 break;
1571
1572 default:
1573 break;
1574 }
1575
1576 // pname is valid, but there are no parameters to return
1577 if (numParams == 0)
1578 {
1579 return false;
1580 }
1581
1582 return true;
1583}
1584
Jamie Madillc29968b2016-01-20 11:17:23 -05001585bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1586 GLenum target,
1587 GLint level,
1588 GLenum internalformat,
1589 bool isSubImage,
1590 GLint xoffset,
1591 GLint yoffset,
1592 GLint zoffset,
1593 GLint x,
1594 GLint y,
1595 GLsizei width,
1596 GLsizei height,
1597 GLint border,
1598 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001599{
Jamie Madill560a8d82014-05-21 13:06:20 -04001600 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1601 {
Jamie Madill437fa652016-05-03 15:13:24 -04001602 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001603 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001604 }
1605
1606 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1607 {
Jamie Madill437fa652016-05-03 15:13:24 -04001608 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001609 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001610 }
1611
1612 if (border != 0)
1613 {
Jamie Madill437fa652016-05-03 15:13:24 -04001614 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001615 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001616 }
1617
1618 if (!ValidMipLevel(context, target, level))
1619 {
Jamie Madill437fa652016-05-03 15:13:24 -04001620 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001621 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001622 }
1623
Jamie Madillc29968b2016-01-20 11:17:23 -05001624 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001625 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001626 {
Jamie Madill437fa652016-05-03 15:13:24 -04001627 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001628 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001629 }
1630
Jamie Madillc29968b2016-01-20 11:17:23 -05001631 const auto &state = context->getState();
1632 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001633 {
Jamie Madill437fa652016-05-03 15:13:24 -04001634 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001635 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001636 }
1637
Geoff Langaae65a42014-05-26 12:43:44 -04001638 const gl::Caps &caps = context->getCaps();
1639
Geoff Langaae65a42014-05-26 12:43:44 -04001640 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001641 switch (target)
1642 {
1643 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001644 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001645 break;
1646
1647 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1648 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1649 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1650 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1651 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1652 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001653 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001654 break;
1655
1656 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001657 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001658 break;
1659
1660 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001661 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001662 break;
1663
1664 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001665 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001666 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001667 }
1668
Jamie Madillc29968b2016-01-20 11:17:23 -05001669 gl::Texture *texture =
1670 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001671 if (!texture)
1672 {
Jamie Madill437fa652016-05-03 15:13:24 -04001673 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001674 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001675 }
1676
Geoff Lang69cce582015-09-17 13:20:36 -04001677 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001678 {
Jamie Madill437fa652016-05-03 15:13:24 -04001679 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001680 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001681 }
1682
Geoff Lang5d601382014-07-22 15:14:06 -04001683 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1684
1685 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001686 {
Jamie Madill437fa652016-05-03 15:13:24 -04001687 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001688 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001689 }
1690
Geoff Langa9be0dc2014-12-17 12:34:40 -05001691 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001692 {
Jamie Madill437fa652016-05-03 15:13:24 -04001693 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001694 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001695 }
1696
1697 if (isSubImage)
1698 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001699 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1700 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1701 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001702 {
Jamie Madill437fa652016-05-03 15:13:24 -04001703 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001704 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001705 }
1706 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001707 else
1708 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001709 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001710 {
Jamie Madill437fa652016-05-03 15:13:24 -04001711 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001712 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001713 }
1714
Geoff Lang5d601382014-07-22 15:14:06 -04001715 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001716 {
Jamie Madill437fa652016-05-03 15:13:24 -04001717 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001718 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001719 }
1720
1721 int maxLevelDimension = (maxDimension >> level);
1722 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1723 {
Jamie Madill437fa652016-05-03 15:13:24 -04001724 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001725 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001726 }
1727 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001728
Geoff Langa9be0dc2014-12-17 12:34:40 -05001729 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001730 return true;
1731}
1732
Jamie Madillf25855c2015-11-03 11:06:18 -05001733static bool ValidateDrawBase(ValidationContext *context,
1734 GLenum mode,
1735 GLsizei count,
1736 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001737{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001738 switch (mode)
1739 {
1740 case GL_POINTS:
1741 case GL_LINES:
1742 case GL_LINE_LOOP:
1743 case GL_LINE_STRIP:
1744 case GL_TRIANGLES:
1745 case GL_TRIANGLE_STRIP:
1746 case GL_TRIANGLE_FAN:
1747 break;
1748 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001749 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001750 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001751 }
1752
Jamie Madill250d33f2014-06-06 17:09:03 -04001753 if (count < 0)
1754 {
Jamie Madill437fa652016-05-03 15:13:24 -04001755 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001756 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001757 }
1758
Geoff Langb1196682014-07-23 13:47:29 -04001759 const State &state = context->getState();
1760
Jamie Madill250d33f2014-06-06 17:09:03 -04001761 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001762 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001763 {
Jamie Madill437fa652016-05-03 15:13:24 -04001764 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001765 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001766 }
1767
Geoff Lang3a86ad32015-09-01 11:47:05 -04001768 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001769 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001770 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1771 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1772 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1773 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1774 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1775 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1776 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001777 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001778 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1779 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001780 {
1781 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1782 // Section 6.10 of the WebGL 1.0 spec
1783 ERR(
1784 "This ANGLE implementation does not support separate front/back stencil "
1785 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001786 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001787 return false;
1788 }
Jamie Madillac528012014-06-20 13:21:23 -04001789 }
1790
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001791 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001792 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001793 {
Jamie Madill437fa652016-05-03 15:13:24 -04001794 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001795 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001796 }
1797
Geoff Lang7dd2e102014-11-10 15:19:26 -05001798 gl::Program *program = state.getProgram();
1799 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001800 {
Jamie Madill437fa652016-05-03 15:13:24 -04001801 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001802 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001803 }
1804
Geoff Lang7dd2e102014-11-10 15:19:26 -05001805 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001806 {
Jamie Madill437fa652016-05-03 15:13:24 -04001807 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001808 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001809 }
1810
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001811 // Uniform buffer validation
1812 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1813 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001814 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001815 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001816 const OffsetBindingPointer<Buffer> &uniformBuffer =
1817 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001818
Geoff Lang5d124a62015-09-15 13:03:27 -04001819 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001820 {
1821 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001822 context->handleError(
1823 Error(GL_INVALID_OPERATION,
1824 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001825 return false;
1826 }
1827
Geoff Lang5d124a62015-09-15 13:03:27 -04001828 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001829 if (uniformBufferSize == 0)
1830 {
1831 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001832 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001833 }
1834
Jamie Madill62d31cb2015-09-11 13:25:51 -04001835 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001836 {
1837 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001838 context->handleError(
1839 Error(GL_INVALID_OPERATION,
1840 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001841 return false;
1842 }
1843 }
1844
Jamie Madill250d33f2014-06-06 17:09:03 -04001845 // No-op if zero count
1846 return (count > 0);
1847}
1848
Geoff Langb1196682014-07-23 13:47:29 -04001849bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001850{
Jamie Madillfd716582014-06-06 17:09:04 -04001851 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001852 {
Jamie Madill437fa652016-05-03 15:13:24 -04001853 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001854 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001855 }
1856
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001857 const State &state = context->getState();
1858 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001859 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1860 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001861 {
1862 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1863 // that does not match the current transform feedback object's draw mode (if transform feedback
1864 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001865 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001866 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001867 }
1868
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001869 if (!ValidateDrawBase(context, mode, count, primcount))
1870 {
1871 return false;
1872 }
1873
1874 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001875 {
1876 return false;
1877 }
1878
1879 return true;
1880}
1881
Geoff Langb1196682014-07-23 13:47:29 -04001882bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001883{
1884 if (primcount < 0)
1885 {
Jamie Madill437fa652016-05-03 15:13:24 -04001886 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001887 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001888 }
1889
Jamie Madill2b976812014-08-25 15:47:49 -04001890 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001891 {
1892 return false;
1893 }
1894
1895 // No-op if zero primitive count
1896 return (primcount > 0);
1897}
1898
Geoff Lang87a93302014-09-16 13:29:43 -04001899static bool ValidateDrawInstancedANGLE(Context *context)
1900{
1901 // Verify there is at least one active attribute with a divisor of zero
1902 const gl::State& state = context->getState();
1903
Geoff Lang7dd2e102014-11-10 15:19:26 -05001904 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001905
1906 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001907 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001908 {
1909 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001910 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001911 {
1912 return true;
1913 }
1914 }
1915
Jamie Madill437fa652016-05-03 15:13:24 -04001916 context->handleError(Error(GL_INVALID_OPERATION,
1917 "ANGLE_instanced_arrays requires that at least one active attribute"
1918 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001919 return false;
1920}
1921
1922bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1923{
1924 if (!ValidateDrawInstancedANGLE(context))
1925 {
1926 return false;
1927 }
1928
1929 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1930}
1931
Jamie Madillf25855c2015-11-03 11:06:18 -05001932bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001933 GLenum mode,
1934 GLsizei count,
1935 GLenum type,
1936 const GLvoid *indices,
1937 GLsizei primcount,
1938 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001939{
Jamie Madill250d33f2014-06-06 17:09:03 -04001940 switch (type)
1941 {
1942 case GL_UNSIGNED_BYTE:
1943 case GL_UNSIGNED_SHORT:
1944 break;
1945 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001946 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001947 {
Jamie Madill437fa652016-05-03 15:13:24 -04001948 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001949 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001950 }
1951 break;
1952 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001953 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001954 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001955 }
1956
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001957 const State &state = context->getState();
1958
1959 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001960 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001961 {
1962 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1963 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001964 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001965 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001966 }
1967
1968 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001969 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001970 {
Jamie Madill437fa652016-05-03 15:13:24 -04001971 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001972 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001973 }
1974
Jamie Madill2b976812014-08-25 15:47:49 -04001975 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001976 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001977 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001978 {
Jamie Madill437fa652016-05-03 15:13:24 -04001979 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001980 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001981 }
1982
Jamie Madillae3000b2014-08-25 15:47:51 -04001983 if (elementArrayBuffer)
1984 {
1985 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1986
1987 GLint64 offset = reinterpret_cast<GLint64>(indices);
1988 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1989
1990 // check for integer overflows
1991 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1992 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1993 {
Jamie Madill437fa652016-05-03 15:13:24 -04001994 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04001995 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001996 }
1997
1998 // Check for reading past the end of the bound buffer object
1999 if (byteCount > elementArrayBuffer->getSize())
2000 {
Jamie Madill437fa652016-05-03 15:13:24 -04002001 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002002 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002003 }
2004 }
2005 else if (!indices)
2006 {
2007 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002008 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002009 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002010 }
2011
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002012 if (!ValidateDrawBase(context, mode, count, primcount))
2013 {
2014 return false;
2015 }
2016
Jamie Madill2b976812014-08-25 15:47:49 -04002017 // Use max index to validate if our vertex buffers are large enough for the pull.
2018 // TODO: offer fast path, with disabled index validation.
2019 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2020 if (elementArrayBuffer)
2021 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002022 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002023 Error error =
2024 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2025 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002026 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002027 {
Jamie Madill437fa652016-05-03 15:13:24 -04002028 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002029 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002030 }
2031 }
2032 else
2033 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002034 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002035 }
2036
Jamie Madille79b1e12015-11-04 16:36:37 -05002037 // If we use an index greater than our maximum supported index range, return an error.
2038 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2039 // return an error if possible here.
2040 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2041 {
Jamie Madill437fa652016-05-03 15:13:24 -04002042 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002043 return false;
2044 }
2045
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002046 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002047 {
2048 return false;
2049 }
2050
Geoff Lang3edfe032015-09-04 16:38:24 -04002051 // No op if there are no real indices in the index data (all are primitive restart).
2052 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002053}
2054
Geoff Langb1196682014-07-23 13:47:29 -04002055bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002056 GLenum mode,
2057 GLsizei count,
2058 GLenum type,
2059 const GLvoid *indices,
2060 GLsizei primcount,
2061 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002062{
2063 if (primcount < 0)
2064 {
Jamie Madill437fa652016-05-03 15:13:24 -04002065 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002066 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002067 }
2068
Jamie Madill2b976812014-08-25 15:47:49 -04002069 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002070 {
2071 return false;
2072 }
2073
2074 // No-op zero primitive count
2075 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002076}
2077
Geoff Lang3edfe032015-09-04 16:38:24 -04002078bool ValidateDrawElementsInstancedANGLE(Context *context,
2079 GLenum mode,
2080 GLsizei count,
2081 GLenum type,
2082 const GLvoid *indices,
2083 GLsizei primcount,
2084 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002085{
2086 if (!ValidateDrawInstancedANGLE(context))
2087 {
2088 return false;
2089 }
2090
2091 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2092}
2093
Geoff Langb1196682014-07-23 13:47:29 -04002094bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002095 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002096{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002097 if (!ValidFramebufferTarget(target))
2098 {
Jamie Madill437fa652016-05-03 15:13:24 -04002099 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002100 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002101 }
2102
2103 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002104 {
2105 return false;
2106 }
2107
Jamie Madill55ec3b12014-07-03 10:38:57 -04002108 if (texture != 0)
2109 {
2110 gl::Texture *tex = context->getTexture(texture);
2111
2112 if (tex == NULL)
2113 {
Jamie Madill437fa652016-05-03 15:13:24 -04002114 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002115 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002116 }
2117
2118 if (level < 0)
2119 {
Jamie Madill437fa652016-05-03 15:13:24 -04002120 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002121 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002122 }
2123 }
2124
Shannon Woods53a94a82014-06-24 15:20:36 -04002125 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002126 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002127
Jamie Madill84115c92015-04-23 15:00:07 -04002128 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002129 {
Jamie Madill437fa652016-05-03 15:13:24 -04002130 context->handleError(
2131 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002132 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002133 }
2134
2135 return true;
2136}
2137
Geoff Langb1196682014-07-23 13:47:29 -04002138bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002139 GLenum textarget, GLuint texture, GLint level)
2140{
Geoff Lang95663912015-04-02 15:54:45 -04002141 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2142 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002143 {
Jamie Madill437fa652016-05-03 15:13:24 -04002144 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002145 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002146 }
2147
2148 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002149 {
2150 return false;
2151 }
2152
Jamie Madill55ec3b12014-07-03 10:38:57 -04002153 if (texture != 0)
2154 {
2155 gl::Texture *tex = context->getTexture(texture);
2156 ASSERT(tex);
2157
Jamie Madill2a6564e2014-07-11 09:53:19 -04002158 const gl::Caps &caps = context->getCaps();
2159
Jamie Madill55ec3b12014-07-03 10:38:57 -04002160 switch (textarget)
2161 {
2162 case GL_TEXTURE_2D:
2163 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002164 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002165 {
Jamie Madill437fa652016-05-03 15:13:24 -04002166 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002167 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002168 }
2169 if (tex->getTarget() != GL_TEXTURE_2D)
2170 {
Jamie Madill437fa652016-05-03 15:13:24 -04002171 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002172 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002173 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002174 }
2175 break;
2176
2177 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2178 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2179 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2180 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2181 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2182 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2183 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002184 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002185 {
Jamie Madill437fa652016-05-03 15:13:24 -04002186 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002187 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002188 }
2189 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2190 {
Jamie Madill437fa652016-05-03 15:13:24 -04002191 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002192 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002193 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002194 }
2195 break;
2196
2197 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002198 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002199 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002200 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002201
2202 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2203 if (internalFormatInfo.compressed)
2204 {
Jamie Madill437fa652016-05-03 15:13:24 -04002205 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002206 return false;
2207 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002208 }
2209
Jamie Madill570f7c82014-07-03 10:38:54 -04002210 return true;
2211}
2212
Geoff Langb1196682014-07-23 13:47:29 -04002213bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002214{
2215 if (program == 0)
2216 {
Jamie Madill437fa652016-05-03 15:13:24 -04002217 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002218 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002219 }
2220
Dian Xiang769769a2015-09-09 15:20:08 -07002221 gl::Program *programObject = GetValidProgram(context, program);
2222 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002223 {
2224 return false;
2225 }
2226
Jamie Madill0063c512014-08-25 15:47:53 -04002227 if (!programObject || !programObject->isLinked())
2228 {
Jamie Madill437fa652016-05-03 15:13:24 -04002229 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002230 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002231 }
2232
Geoff Lang7dd2e102014-11-10 15:19:26 -05002233 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002234 {
Jamie Madill437fa652016-05-03 15:13:24 -04002235 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002236 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002237 }
2238
Jamie Madill0063c512014-08-25 15:47:53 -04002239 return true;
2240}
2241
Geoff Langb1196682014-07-23 13:47:29 -04002242bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002243{
2244 return ValidateGetUniformBase(context, program, location);
2245}
2246
Geoff Langb1196682014-07-23 13:47:29 -04002247bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002248{
Jamie Madill78f41802014-08-25 15:47:55 -04002249 return ValidateGetUniformBase(context, program, location);
2250}
2251
Geoff Langb1196682014-07-23 13:47:29 -04002252static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002253{
2254 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002255 {
Jamie Madill78f41802014-08-25 15:47:55 -04002256 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002257 }
2258
Jamie Madilla502c742014-08-28 17:19:13 -04002259 gl::Program *programObject = context->getProgram(program);
2260 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002261
Jamie Madill78f41802014-08-25 15:47:55 -04002262 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002263 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2264 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002265 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002266 {
Jamie Madill437fa652016-05-03 15:13:24 -04002267 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002268 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002269 }
2270
2271 return true;
2272}
2273
Geoff Langb1196682014-07-23 13:47:29 -04002274bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002275{
Jamie Madill78f41802014-08-25 15:47:55 -04002276 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002277}
2278
Geoff Langb1196682014-07-23 13:47:29 -04002279bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002280{
Jamie Madill78f41802014-08-25 15:47:55 -04002281 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002282}
2283
Austin Kinross08332632015-05-05 13:35:47 -07002284bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2285 const GLenum *attachments, bool defaultFramebuffer)
2286{
2287 if (numAttachments < 0)
2288 {
Jamie Madill437fa652016-05-03 15:13:24 -04002289 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002290 return false;
2291 }
2292
2293 for (GLsizei i = 0; i < numAttachments; ++i)
2294 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002295 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002296 {
2297 if (defaultFramebuffer)
2298 {
Jamie Madill437fa652016-05-03 15:13:24 -04002299 context->handleError(Error(
2300 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002301 return false;
2302 }
2303
2304 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2305 {
Jamie Madill437fa652016-05-03 15:13:24 -04002306 context->handleError(Error(GL_INVALID_OPERATION,
2307 "Requested color attachment is greater than the maximum "
2308 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002309 return false;
2310 }
2311 }
2312 else
2313 {
2314 switch (attachments[i])
2315 {
2316 case GL_DEPTH_ATTACHMENT:
2317 case GL_STENCIL_ATTACHMENT:
2318 case GL_DEPTH_STENCIL_ATTACHMENT:
2319 if (defaultFramebuffer)
2320 {
Jamie Madill437fa652016-05-03 15:13:24 -04002321 context->handleError(
2322 Error(GL_INVALID_ENUM,
2323 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002324 return false;
2325 }
2326 break;
2327 case GL_COLOR:
2328 case GL_DEPTH:
2329 case GL_STENCIL:
2330 if (!defaultFramebuffer)
2331 {
Jamie Madill437fa652016-05-03 15:13:24 -04002332 context->handleError(
2333 Error(GL_INVALID_ENUM,
2334 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002335 return false;
2336 }
2337 break;
2338 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002339 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002340 return false;
2341 }
2342 }
2343 }
2344
2345 return true;
2346}
2347
Austin Kinross6ee1e782015-05-29 17:05:37 -07002348bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2349{
2350 // Note that debug marker calls must not set error state
2351
2352 if (length < 0)
2353 {
2354 return false;
2355 }
2356
2357 if (marker == nullptr)
2358 {
2359 return false;
2360 }
2361
2362 return true;
2363}
2364
2365bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2366{
2367 // Note that debug marker calls must not set error state
2368
2369 if (length < 0)
2370 {
2371 return false;
2372 }
2373
2374 if (length > 0 && marker == nullptr)
2375 {
2376 return false;
2377 }
2378
2379 return true;
2380}
2381
Geoff Langdcab33b2015-07-21 13:03:16 -04002382bool ValidateEGLImageTargetTexture2DOES(Context *context,
2383 egl::Display *display,
2384 GLenum target,
2385 egl::Image *image)
2386{
Geoff Langa8406172015-07-21 16:53:39 -04002387 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2388 {
Jamie Madill437fa652016-05-03 15:13:24 -04002389 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002390 return false;
2391 }
2392
2393 switch (target)
2394 {
2395 case GL_TEXTURE_2D:
2396 break;
2397
2398 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002399 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002400 return false;
2401 }
2402
2403 if (!display->isValidImage(image))
2404 {
Jamie Madill437fa652016-05-03 15:13:24 -04002405 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002406 return false;
2407 }
2408
2409 if (image->getSamples() > 0)
2410 {
Jamie Madill437fa652016-05-03 15:13:24 -04002411 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002412 "cannot create a 2D texture from a multisampled EGL image."));
2413 return false;
2414 }
2415
2416 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2417 if (!textureCaps.texturable)
2418 {
Jamie Madill437fa652016-05-03 15:13:24 -04002419 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002420 "EGL image internal format is not supported as a texture."));
2421 return false;
2422 }
2423
Geoff Langdcab33b2015-07-21 13:03:16 -04002424 return true;
2425}
2426
2427bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2428 egl::Display *display,
2429 GLenum target,
2430 egl::Image *image)
2431{
Geoff Langa8406172015-07-21 16:53:39 -04002432 if (!context->getExtensions().eglImage)
2433 {
Jamie Madill437fa652016-05-03 15:13:24 -04002434 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002435 return false;
2436 }
2437
2438 switch (target)
2439 {
2440 case GL_RENDERBUFFER:
2441 break;
2442
2443 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002444 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002445 return false;
2446 }
2447
2448 if (!display->isValidImage(image))
2449 {
Jamie Madill437fa652016-05-03 15:13:24 -04002450 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002451 return false;
2452 }
2453
2454 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2455 if (!textureCaps.renderable)
2456 {
Jamie Madill437fa652016-05-03 15:13:24 -04002457 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002458 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2459 return false;
2460 }
2461
Geoff Langdcab33b2015-07-21 13:03:16 -04002462 return true;
2463}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002464
2465bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2466{
Geoff Lang36167ab2015-12-07 10:27:14 -05002467 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002468 {
2469 // The default VAO should always exist
2470 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002471 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002472 return false;
2473 }
2474
2475 return true;
2476}
2477
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002478bool ValidateLinkProgram(Context *context, GLuint program)
2479{
2480 if (context->hasActiveTransformFeedback(program))
2481 {
2482 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002483 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002484 "Cannot link program while program is associated with an active "
2485 "transform feedback object."));
2486 return false;
2487 }
2488 return true;
2489}
2490
Geoff Langc5629752015-12-07 16:29:04 -05002491bool ValidateProgramBinaryBase(Context *context,
2492 GLuint program,
2493 GLenum binaryFormat,
2494 const void *binary,
2495 GLint length)
2496{
2497 Program *programObject = GetValidProgram(context, program);
2498 if (programObject == nullptr)
2499 {
2500 return false;
2501 }
2502
2503 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2504 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2505 programBinaryFormats.end())
2506 {
Jamie Madill437fa652016-05-03 15:13:24 -04002507 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002508 return false;
2509 }
2510
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002511 if (context->hasActiveTransformFeedback(program))
2512 {
2513 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002514 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002515 "Cannot change program binary while program is associated with "
2516 "an active transform feedback object."));
2517 return false;
2518 }
2519
Geoff Langc5629752015-12-07 16:29:04 -05002520 return true;
2521}
2522
2523bool ValidateGetProgramBinaryBase(Context *context,
2524 GLuint program,
2525 GLsizei bufSize,
2526 GLsizei *length,
2527 GLenum *binaryFormat,
2528 void *binary)
2529{
2530 Program *programObject = GetValidProgram(context, program);
2531 if (programObject == nullptr)
2532 {
2533 return false;
2534 }
2535
2536 if (!programObject->isLinked())
2537 {
Jamie Madill437fa652016-05-03 15:13:24 -04002538 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002539 return false;
2540 }
2541
2542 return true;
2543}
Jamie Madillc29968b2016-01-20 11:17:23 -05002544
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002545bool ValidateUseProgram(Context *context, GLuint program)
2546{
2547 if (program != 0)
2548 {
2549 Program *programObject = context->getProgram(program);
2550 if (!programObject)
2551 {
2552 // ES 3.1.0 section 7.3 page 72
2553 if (context->getShader(program))
2554 {
Jamie Madill437fa652016-05-03 15:13:24 -04002555 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002556 Error(GL_INVALID_OPERATION,
2557 "Attempted to use a single shader instead of a shader program."));
2558 return false;
2559 }
2560 else
2561 {
Jamie Madill437fa652016-05-03 15:13:24 -04002562 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002563 return false;
2564 }
2565 }
2566 if (!programObject->isLinked())
2567 {
Jamie Madill437fa652016-05-03 15:13:24 -04002568 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002569 return false;
2570 }
2571 }
2572 if (context->getState().isTransformFeedbackActiveUnpaused())
2573 {
2574 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002575 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002576 Error(GL_INVALID_OPERATION,
2577 "Cannot change active program while transform feedback is unpaused."));
2578 return false;
2579 }
2580
2581 return true;
2582}
2583
Jamie Madillc29968b2016-01-20 11:17:23 -05002584bool ValidateCopyTexImage2D(ValidationContext *context,
2585 GLenum target,
2586 GLint level,
2587 GLenum internalformat,
2588 GLint x,
2589 GLint y,
2590 GLsizei width,
2591 GLsizei height,
2592 GLint border)
2593{
2594 if (context->getClientVersion() < 3)
2595 {
2596 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2597 0, x, y, width, height, border);
2598 }
2599
2600 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002601 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2602 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002603}
Jamie Madillc29968b2016-01-20 11:17:23 -05002604
2605bool ValidateFramebufferRenderbuffer(Context *context,
2606 GLenum target,
2607 GLenum attachment,
2608 GLenum renderbuffertarget,
2609 GLuint renderbuffer)
2610{
2611 if (!ValidFramebufferTarget(target) ||
2612 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2613 {
Jamie Madill437fa652016-05-03 15:13:24 -04002614 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002615 return false;
2616 }
2617
2618 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2619 renderbuffertarget, renderbuffer);
2620}
2621
2622bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2623{
2624 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2625 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2626 {
Jamie Madill437fa652016-05-03 15:13:24 -04002627 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002628 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2629 return false;
2630 }
2631
2632 ASSERT(context->getState().getDrawFramebuffer());
2633 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2634 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2635
2636 // This should come first before the check for the default frame buffer
2637 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2638 // rather than INVALID_OPERATION
2639 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2640 {
2641 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2642
2643 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002644 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2645 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002646 {
2647 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002648 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2649 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2650 // 3.1 is still a bit ambiguous about the error, but future specs are
2651 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002652 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002653 return false;
2654 }
2655 else if (bufs[colorAttachment] >= maxColorAttachment)
2656 {
Jamie Madill437fa652016-05-03 15:13:24 -04002657 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002658 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002659 return false;
2660 }
2661 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2662 frameBufferId != 0)
2663 {
2664 // INVALID_OPERATION-GL is bound to buffer and ith argument
2665 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002666 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002667 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2668 return false;
2669 }
2670 }
2671
2672 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2673 // and n is not 1 or bufs is bound to value other than BACK and NONE
2674 if (frameBufferId == 0)
2675 {
2676 if (n != 1)
2677 {
Jamie Madill437fa652016-05-03 15:13:24 -04002678 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002679 "n must be 1 when GL is bound to the default framebuffer"));
2680 return false;
2681 }
2682
2683 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2684 {
Jamie Madill437fa652016-05-03 15:13:24 -04002685 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002686 GL_INVALID_OPERATION,
2687 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2688 return false;
2689 }
2690 }
2691
2692 return true;
2693}
2694
2695bool ValidateCopyTexSubImage2D(Context *context,
2696 GLenum target,
2697 GLint level,
2698 GLint xoffset,
2699 GLint yoffset,
2700 GLint x,
2701 GLint y,
2702 GLsizei width,
2703 GLsizei height)
2704{
2705 if (context->getClientVersion() < 3)
2706 {
2707 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2708 yoffset, x, y, width, height, 0);
2709 }
2710
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002711 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2712 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002713}
2714
Olli Etuaho4f667482016-03-30 15:56:35 +03002715bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2716{
2717 if (!ValidBufferTarget(context, target))
2718 {
Jamie Madill437fa652016-05-03 15:13:24 -04002719 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002720 return false;
2721 }
2722
2723 if (pname != GL_BUFFER_MAP_POINTER)
2724 {
Jamie Madill437fa652016-05-03 15:13:24 -04002725 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002726 return false;
2727 }
2728
2729 Buffer *buffer = context->getState().getTargetBuffer(target);
2730
2731 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2732 // target bound to zero generate an INVALID_OPERATION error."
2733 // GLES 3.1 section 6.6 explicitly specifies this error.
2734 if (!buffer)
2735 {
Jamie Madill437fa652016-05-03 15:13:24 -04002736 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002737 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2738 return false;
2739 }
2740
2741 return true;
2742}
2743
2744bool ValidateUnmapBufferBase(Context *context, GLenum target)
2745{
2746 if (!ValidBufferTarget(context, target))
2747 {
Jamie Madill437fa652016-05-03 15:13:24 -04002748 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002749 return false;
2750 }
2751
2752 Buffer *buffer = context->getState().getTargetBuffer(target);
2753
2754 if (buffer == nullptr || !buffer->isMapped())
2755 {
Jamie Madill437fa652016-05-03 15:13:24 -04002756 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002757 return false;
2758 }
2759
2760 return true;
2761}
2762
2763bool ValidateMapBufferRangeBase(Context *context,
2764 GLenum target,
2765 GLintptr offset,
2766 GLsizeiptr length,
2767 GLbitfield access)
2768{
2769 if (!ValidBufferTarget(context, target))
2770 {
Jamie Madill437fa652016-05-03 15:13:24 -04002771 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002772 return false;
2773 }
2774
2775 if (offset < 0 || length < 0)
2776 {
Jamie Madill437fa652016-05-03 15:13:24 -04002777 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002778 return false;
2779 }
2780
2781 Buffer *buffer = context->getState().getTargetBuffer(target);
2782
2783 if (!buffer)
2784 {
Jamie Madill437fa652016-05-03 15:13:24 -04002785 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002786 return false;
2787 }
2788
2789 // Check for buffer overflow
2790 size_t offsetSize = static_cast<size_t>(offset);
2791 size_t lengthSize = static_cast<size_t>(length);
2792
2793 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2794 offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
2795 {
Jamie Madill437fa652016-05-03 15:13:24 -04002796 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002797 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2798 return false;
2799 }
2800
2801 // Check for invalid bits in the mask
2802 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2803 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2804 GL_MAP_UNSYNCHRONIZED_BIT;
2805
2806 if (access & ~(allAccessBits))
2807 {
Jamie Madill437fa652016-05-03 15:13:24 -04002808 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002809 return false;
2810 }
2811
2812 if (length == 0)
2813 {
Jamie Madill437fa652016-05-03 15:13:24 -04002814 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002815 return false;
2816 }
2817
2818 if (buffer->isMapped())
2819 {
Jamie Madill437fa652016-05-03 15:13:24 -04002820 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002821 return false;
2822 }
2823
2824 // Check for invalid bit combinations
2825 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2826 {
Jamie Madill437fa652016-05-03 15:13:24 -04002827 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002828 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2829 return false;
2830 }
2831
2832 GLbitfield writeOnlyBits =
2833 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2834
2835 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2836 {
Jamie Madill437fa652016-05-03 15:13:24 -04002837 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002838 "Invalid access bits when mapping buffer for reading: 0x%X.",
2839 access));
2840 return false;
2841 }
2842
2843 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2844 {
Jamie Madill437fa652016-05-03 15:13:24 -04002845 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002846 GL_INVALID_OPERATION,
2847 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2848 return false;
2849 }
2850 return true;
2851}
2852
2853bool ValidateFlushMappedBufferRangeBase(Context *context,
2854 GLenum target,
2855 GLintptr offset,
2856 GLsizeiptr length)
2857{
2858 if (offset < 0 || length < 0)
2859 {
Jamie Madill437fa652016-05-03 15:13:24 -04002860 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002861 return false;
2862 }
2863
2864 if (!ValidBufferTarget(context, target))
2865 {
Jamie Madill437fa652016-05-03 15:13:24 -04002866 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002867 return false;
2868 }
2869
2870 Buffer *buffer = context->getState().getTargetBuffer(target);
2871
2872 if (buffer == nullptr)
2873 {
Jamie Madill437fa652016-05-03 15:13:24 -04002874 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002875 return false;
2876 }
2877
2878 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2879 {
Jamie Madill437fa652016-05-03 15:13:24 -04002880 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002881 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2882 return false;
2883 }
2884
2885 // Check for buffer overflow
2886 size_t offsetSize = static_cast<size_t>(offset);
2887 size_t lengthSize = static_cast<size_t>(length);
2888
2889 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2890 offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
2891 {
Jamie Madill437fa652016-05-03 15:13:24 -04002892 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002893 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2894 return false;
2895 }
2896
2897 return true;
2898}
2899
Olli Etuaho41997e72016-03-10 13:38:39 +02002900bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2901{
2902 return ValidateGenOrDelete(context, n);
2903}
2904
2905bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2906{
2907 return ValidateGenOrDelete(context, n);
2908}
2909
2910bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2911{
2912 return ValidateGenOrDelete(context, n);
2913}
2914
2915bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2916{
2917 return ValidateGenOrDelete(context, n);
2918}
2919
2920bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2921{
2922 return ValidateGenOrDelete(context, n);
2923}
2924
2925bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2926{
2927 return ValidateGenOrDelete(context, n);
2928}
2929
2930bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2931{
2932 return ValidateGenOrDelete(context, n);
2933}
2934
2935bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2936{
2937 return ValidateGenOrDelete(context, n);
2938}
2939
2940bool ValidateGenOrDelete(Context *context, GLint n)
2941{
2942 if (n < 0)
2943 {
Jamie Madill437fa652016-05-03 15:13:24 -04002944 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02002945 return false;
2946 }
2947 return true;
2948}
2949
Jamie Madillc29968b2016-01-20 11:17:23 -05002950} // namespace gl