blob: 76e8c64fed55e6ff9be415110a0b4a2a34de1b18 [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 {
Sami Väisänen74c23472016-05-09 17:30:30 +0300105 // EXT_multisample_compatibility
106 case GL_MULTISAMPLE_EXT:
107 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
108 return context->getExtensions().multisampleCompatibility;
109
Geoff Lang0550d032014-01-30 11:29:07 -0500110 case GL_CULL_FACE:
111 case GL_POLYGON_OFFSET_FILL:
112 case GL_SAMPLE_ALPHA_TO_COVERAGE:
113 case GL_SAMPLE_COVERAGE:
114 case GL_SCISSOR_TEST:
115 case GL_STENCIL_TEST:
116 case GL_DEPTH_TEST:
117 case GL_BLEND:
118 case GL_DITHER:
119 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500120
Geoff Lang0550d032014-01-30 11:29:07 -0500121 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
122 case GL_RASTERIZER_DISCARD:
123 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500124
125 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
126 case GL_DEBUG_OUTPUT:
127 return context->getExtensions().debug;
128
Geoff Lang0550d032014-01-30 11:29:07 -0500129 default:
130 return false;
131 }
132}
133
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500134bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400135{
Jamie Madilld7460c72014-01-21 16:38:14 -0500136 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400137 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500138 case GL_TEXTURE_2D:
139 case GL_TEXTURE_CUBE_MAP:
140 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400141
Jamie Madilld7460c72014-01-21 16:38:14 -0500142 case GL_TEXTURE_3D:
143 case GL_TEXTURE_2D_ARRAY:
144 return (context->getClientVersion() >= 3);
145
146 default:
147 return false;
148 }
Jamie Madill35d15012013-10-07 10:46:37 -0400149}
150
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500151bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
152{
153 switch (target)
154 {
155 case GL_TEXTURE_2D:
156 case GL_TEXTURE_CUBE_MAP:
157 return true;
158
159 default:
160 return false;
161 }
162}
163
164bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
165{
166 switch (target)
167 {
168 case GL_TEXTURE_3D:
169 case GL_TEXTURE_2D_ARRAY:
170 return (context->getClientVersion() >= 3);
171
172 default:
173 return false;
174 }
175}
176
Ian Ewellbda75592016-04-18 17:25:54 -0400177// Most texture GL calls are not compatible with external textures, so we have a separate validation
178// function for use in the GL calls that do
179bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
180{
181 return (target == GL_TEXTURE_EXTERNAL_OES) &&
182 (context->getExtensions().eglImageExternal ||
183 context->getExtensions().eglStreamConsumerExternal);
184}
185
Shannon Woods4dfed832014-03-17 20:03:39 -0400186// This function differs from ValidTextureTarget in that the target must be
187// usable as the destination of a 2D operation-- so a cube face is valid, but
188// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400189// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500190bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400191{
192 switch (target)
193 {
194 case GL_TEXTURE_2D:
195 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
196 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
197 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
198 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
199 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
200 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
201 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500202 default:
203 return false;
204 }
205}
206
207bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
208{
209 switch (target)
210 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400211 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500212 case GL_TEXTURE_2D_ARRAY:
213 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400214 default:
215 return false;
216 }
217}
218
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500219bool ValidFramebufferTarget(GLenum target)
220{
Geoff Langd4475812015-03-18 10:53:05 -0400221 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
222 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500223
224 switch (target)
225 {
226 case GL_FRAMEBUFFER: return true;
227 case GL_READ_FRAMEBUFFER: return true;
228 case GL_DRAW_FRAMEBUFFER: return true;
229 default: return false;
230 }
231}
232
Jamie Madill8c96d582014-03-05 15:01:23 -0500233bool ValidBufferTarget(const Context *context, GLenum target)
234{
235 switch (target)
236 {
237 case GL_ARRAY_BUFFER:
238 case GL_ELEMENT_ARRAY_BUFFER:
239 return true;
240
Jamie Madill8c96d582014-03-05 15:01:23 -0500241 case GL_PIXEL_PACK_BUFFER:
242 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400243 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400244
Shannon Woodsb3801742014-03-27 14:59:19 -0400245 case GL_COPY_READ_BUFFER:
246 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500247 case GL_TRANSFORM_FEEDBACK_BUFFER:
248 case GL_UNIFORM_BUFFER:
249 return (context->getClientVersion() >= 3);
250
251 default:
252 return false;
253 }
254}
255
Jamie Madill70656a62014-03-05 15:01:26 -0500256bool ValidBufferParameter(const Context *context, GLenum pname)
257{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400258 const Extensions &extensions = context->getExtensions();
259
Jamie Madill70656a62014-03-05 15:01:26 -0500260 switch (pname)
261 {
262 case GL_BUFFER_USAGE:
263 case GL_BUFFER_SIZE:
264 return true;
265
Geoff Langcc6f55d2015-03-20 13:01:02 -0400266 case GL_BUFFER_ACCESS_OES:
267 return extensions.mapBuffer;
268
269 case GL_BUFFER_MAPPED:
270 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
271 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
272
Jamie Madill70656a62014-03-05 15:01:26 -0500273 // GL_BUFFER_MAP_POINTER is a special case, and may only be
274 // queried with GetBufferPointerv
275 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500276 case GL_BUFFER_MAP_OFFSET:
277 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400278 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500279
280 default:
281 return false;
282 }
283}
284
Jamie Madillc29968b2016-01-20 11:17:23 -0500285bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400286{
Jamie Madillc29968b2016-01-20 11:17:23 -0500287 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400288 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400289 switch (target)
290 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500291 case GL_TEXTURE_2D:
292 maxDimension = caps.max2DTextureSize;
293 break;
Geoff Langce635692013-09-24 13:56:32 -0400294 case GL_TEXTURE_CUBE_MAP:
295 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
296 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
297 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
298 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
299 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500300 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
301 maxDimension = caps.maxCubeMapTextureSize;
302 break;
303 case GL_TEXTURE_3D:
304 maxDimension = caps.max3DTextureSize;
305 break;
306 case GL_TEXTURE_2D_ARRAY:
307 maxDimension = caps.max2DTextureSize;
308 break;
Geoff Langce635692013-09-24 13:56:32 -0400309 default: UNREACHABLE();
310 }
311
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700312 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400313}
314
Austin Kinross08528e12015-10-07 16:24:40 -0700315bool ValidImageSizeParameters(const Context *context,
316 GLenum target,
317 GLint level,
318 GLsizei width,
319 GLsizei height,
320 GLsizei depth,
321 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400322{
323 if (level < 0 || width < 0 || height < 0 || depth < 0)
324 {
325 return false;
326 }
327
Austin Kinross08528e12015-10-07 16:24:40 -0700328 // TexSubImage parameters can be NPOT without textureNPOT extension,
329 // as long as the destination texture is POT.
330 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400331 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400332 {
333 return false;
334 }
335
336 if (!ValidMipLevel(context, target, level))
337 {
338 return false;
339 }
340
341 return true;
342}
343
Geoff Lang0d8b7242015-09-09 14:56:53 -0400344bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
345{
346 // List of compressed format that require that the texture size is smaller than or a multiple of
347 // the compressed block size.
348 switch (internalFormat)
349 {
350 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
351 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
352 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
353 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800354 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400355 return true;
356
357 default:
358 return false;
359 }
360}
361
Jamie Madillc29968b2016-01-20 11:17:23 -0500362bool ValidCompressedImageSize(const ValidationContext *context,
363 GLenum internalFormat,
364 GLsizei width,
365 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400366{
Geoff Lang5d601382014-07-22 15:14:06 -0400367 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
368 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400369 {
370 return false;
371 }
372
Geoff Lang0d8b7242015-09-09 14:56:53 -0400373 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400374 {
375 return false;
376 }
377
Geoff Lang0d8b7242015-09-09 14:56:53 -0400378 if (CompressedTextureFormatRequiresExactSize(internalFormat))
379 {
380 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
381 width % formatInfo.compressedBlockWidth != 0) ||
382 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
383 height % formatInfo.compressedBlockHeight != 0))
384 {
385 return false;
386 }
387 }
388
Geoff Langd4f180b2013-09-24 13:57:44 -0400389 return true;
390}
391
Geoff Lang37dde692014-01-31 16:34:54 -0500392bool ValidQueryType(const Context *context, GLenum queryType)
393{
Geoff Langd4475812015-03-18 10:53:05 -0400394 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
395 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 -0500396
397 switch (queryType)
398 {
399 case GL_ANY_SAMPLES_PASSED:
400 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
401 return true;
402 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
403 return (context->getClientVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500404 case GL_TIME_ELAPSED_EXT:
405 return context->getExtensions().disjointTimerQuery;
Geoff Lang2b4ce802016-04-28 13:34:50 -0400406 case GL_COMMANDS_COMPLETED_CHROMIUM:
407 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500408 default:
409 return false;
410 }
411}
412
Dian Xiang769769a2015-09-09 15:20:08 -0700413Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500414{
415 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
416 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
417 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
418
Dian Xiang769769a2015-09-09 15:20:08 -0700419 Program *validProgram = context->getProgram(id);
420
421 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500422 {
Dian Xiang769769a2015-09-09 15:20:08 -0700423 if (context->getShader(id))
424 {
Jamie Madill437fa652016-05-03 15:13:24 -0400425 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700426 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
427 }
428 else
429 {
Jamie Madill437fa652016-05-03 15:13:24 -0400430 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700431 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500432 }
Dian Xiang769769a2015-09-09 15:20:08 -0700433
434 return validProgram;
435}
436
437Shader *GetValidShader(Context *context, GLuint id)
438{
439 // See ValidProgram for spec details.
440
441 Shader *validShader = context->getShader(id);
442
443 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500444 {
Dian Xiang769769a2015-09-09 15:20:08 -0700445 if (context->getProgram(id))
446 {
Jamie Madill437fa652016-05-03 15:13:24 -0400447 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700448 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
449 }
450 else
451 {
Jamie Madill437fa652016-05-03 15:13:24 -0400452 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700453 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500454 }
Dian Xiang769769a2015-09-09 15:20:08 -0700455
456 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500457}
458
Geoff Langb1196682014-07-23 13:47:29 -0400459bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400460{
461 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
462 {
463 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
464
Geoff Langaae65a42014-05-26 12:43:44 -0400465 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400466 {
Jamie Madill437fa652016-05-03 15:13:24 -0400467 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400468 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400469 }
470 }
471 else
472 {
473 switch (attachment)
474 {
475 case GL_DEPTH_ATTACHMENT:
476 case GL_STENCIL_ATTACHMENT:
477 break;
478
479 case GL_DEPTH_STENCIL_ATTACHMENT:
480 if (context->getClientVersion() < 3)
481 {
Jamie Madill437fa652016-05-03 15:13:24 -0400482 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400483 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400484 }
485 break;
486
487 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400488 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400489 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400490 }
491 }
492
493 return true;
494}
495
Corentin Walleze0902642014-11-04 12:32:15 -0800496bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
497 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400498{
499 switch (target)
500 {
501 case GL_RENDERBUFFER:
502 break;
503 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400504 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400505 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400506 }
507
508 if (width < 0 || height < 0 || samples < 0)
509 {
Jamie Madill437fa652016-05-03 15:13:24 -0400510 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400511 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400512 }
513
Geoff Langd87878e2014-09-19 15:42:59 -0400514 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
515 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 {
Jamie Madill437fa652016-05-03 15:13:24 -0400517 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400518 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 }
520
521 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
522 // 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 -0800523 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400524 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400525 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400526 {
Jamie Madill437fa652016-05-03 15:13:24 -0400527 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400528 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400529 }
530
Geoff Langaae65a42014-05-26 12:43:44 -0400531 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400532 {
Jamie Madill437fa652016-05-03 15:13:24 -0400533 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400534 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400535 }
536
Shannon Woods53a94a82014-06-24 15:20:36 -0400537 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400538 if (handle == 0)
539 {
Jamie Madill437fa652016-05-03 15:13:24 -0400540 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400541 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400542 }
543
544 return true;
545}
546
Corentin Walleze0902642014-11-04 12:32:15 -0800547bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
548 GLenum internalformat, GLsizei width, GLsizei height)
549{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800550 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800551
552 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400553 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800554 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400555 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800556 {
Jamie Madill437fa652016-05-03 15:13:24 -0400557 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800558 return false;
559 }
560
561 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
562 // the specified storage. This is different than ES 3.0 in which a sample number higher
563 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800564 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
565 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800566 {
Geoff Langa4903b72015-03-02 16:02:48 -0800567 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
568 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
569 {
Jamie Madill437fa652016-05-03 15:13:24 -0400570 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800571 return false;
572 }
Corentin Walleze0902642014-11-04 12:32:15 -0800573 }
574
575 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
576}
577
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500578bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
579 GLenum renderbuffertarget, GLuint renderbuffer)
580{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400581 if (!ValidFramebufferTarget(target))
582 {
Jamie Madill437fa652016-05-03 15:13:24 -0400583 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400584 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400585 }
586
Shannon Woods53a94a82014-06-24 15:20:36 -0400587 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500588
Jamie Madill84115c92015-04-23 15:00:07 -0400589 ASSERT(framebuffer);
590 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500591 {
Jamie Madill437fa652016-05-03 15:13:24 -0400592 context->handleError(
593 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400594 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500595 }
596
Jamie Madillb4472272014-07-03 10:38:55 -0400597 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500598 {
Jamie Madillb4472272014-07-03 10:38:55 -0400599 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500600 }
601
Jamie Madillab9d82c2014-01-21 16:38:14 -0500602 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
603 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
604 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
605 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
606 if (renderbuffer != 0)
607 {
608 if (!context->getRenderbuffer(renderbuffer))
609 {
Jamie Madill437fa652016-05-03 15:13:24 -0400610 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400611 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500612 }
613 }
614
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500615 return true;
616}
617
Jamie Madillc29968b2016-01-20 11:17:23 -0500618bool ValidateBlitFramebufferParameters(gl::Context *context,
619 GLint srcX0,
620 GLint srcY0,
621 GLint srcX1,
622 GLint srcY1,
623 GLint dstX0,
624 GLint dstY0,
625 GLint dstX1,
626 GLint dstY1,
627 GLbitfield mask,
628 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400629{
630 switch (filter)
631 {
632 case GL_NEAREST:
633 break;
634 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400635 break;
636 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400637 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400638 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639 }
640
641 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
642 {
Jamie Madill437fa652016-05-03 15:13:24 -0400643 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400644 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645 }
646
647 if (mask == 0)
648 {
649 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
650 // buffers are copied.
651 return false;
652 }
653
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400654 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
655 // color buffer, leaving only nearest being unfiltered from above
656 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
657 {
Jamie Madill437fa652016-05-03 15:13:24 -0400658 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400659 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400660 }
661
Shannon Woods53a94a82014-06-24 15:20:36 -0400662 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400663 {
Jamie Madill437fa652016-05-03 15:13:24 -0400664 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400665 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400666 }
667
Jamie Madille3ef7152015-04-28 16:55:17 +0000668 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
669 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500670
671 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 {
Jamie Madill437fa652016-05-03 15:13:24 -0400673 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400674 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 }
676
Geoff Lang748f74e2014-12-01 11:25:34 -0500677 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500678 {
Jamie Madill437fa652016-05-03 15:13:24 -0400679 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500680 return false;
681 }
682
Geoff Lang748f74e2014-12-01 11:25:34 -0500683 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500684 {
Jamie Madill437fa652016-05-03 15:13:24 -0400685 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500686 return false;
687 }
688
689 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690 {
Jamie Madill437fa652016-05-03 15:13:24 -0400691 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400692 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 }
694
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400695 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
696
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697 if (mask & GL_COLOR_BUFFER_BIT)
698 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400699 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
700 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500701 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400702
703 if (readColorBuffer && drawColorBuffer)
704 {
Geoff Langd8a22582014-12-17 15:28:23 -0500705 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400706 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400707
Geoff Langa15472a2015-08-11 11:48:03 -0400708 for (size_t drawbufferIdx = 0;
709 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710 {
Geoff Langa15472a2015-08-11 11:48:03 -0400711 const FramebufferAttachment *attachment =
712 drawFramebuffer->getDrawBuffer(drawbufferIdx);
713 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400714 {
Geoff Langa15472a2015-08-11 11:48:03 -0400715 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400716 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400717
Geoff Langb2f3d052013-08-13 12:49:27 -0400718 // The GL ES 3.0.2 spec (pg 193) states that:
719 // 1) If the read buffer is fixed point format, the draw buffer must be as well
720 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
721 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500722 // Changes with EXT_color_buffer_float:
723 // Case 1) is changed to fixed point OR floating point
724 GLenum readComponentType = readFormatInfo.componentType;
725 GLenum drawComponentType = drawFormatInfo.componentType;
726 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
727 readComponentType == GL_SIGNED_NORMALIZED);
728 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
729 drawComponentType == GL_SIGNED_NORMALIZED);
730
731 if (extensions.colorBufferFloat)
732 {
733 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
734 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
735
736 if (readFixedOrFloat != drawFixedOrFloat)
737 {
Jamie Madill437fa652016-05-03 15:13:24 -0400738 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500739 "If the read buffer contains fixed-point or "
740 "floating-point values, the draw buffer "
741 "must as well."));
742 return false;
743 }
744 }
745 else if (readFixedPoint != drawFixedPoint)
746 {
Jamie Madill437fa652016-05-03 15:13:24 -0400747 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500748 "If the read buffer contains fixed-point "
749 "values, the draw buffer must as well."));
750 return false;
751 }
752
753 if (readComponentType == GL_UNSIGNED_INT &&
754 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400755 {
Jamie Madill437fa652016-05-03 15:13:24 -0400756 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400757 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400758 }
759
Jamie Madill6163c752015-12-07 16:32:59 -0500760 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 {
Jamie Madill437fa652016-05-03 15:13:24 -0400762 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400763 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 }
765
Geoff Langb2f3d052013-08-13 12:49:27 -0400766 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 {
Jamie Madill437fa652016-05-03 15:13:24 -0400768 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400769 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 }
771 }
772 }
773
Geoff Lang5d601382014-07-22 15:14:06 -0400774 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775 {
Jamie Madill437fa652016-05-03 15:13:24 -0400776 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400777 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400778 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400779 }
780 }
781
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200782 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
783 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
784 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200786 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400788 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
789 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400790
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200791 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400792 {
Geoff Langd8a22582014-12-17 15:28:23 -0500793 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400794 {
Jamie Madill437fa652016-05-03 15:13:24 -0400795 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400796 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400797 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200799 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 {
Jamie Madill437fa652016-05-03 15:13:24 -0400801 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400802 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803 }
804 }
805 }
806 }
807
808 return true;
809}
810
Geoff Langb1196682014-07-23 13:47:29 -0400811bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400812{
813 switch (pname)
814 {
815 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
816 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
817 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
818 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
819 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
820 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
821 case GL_CURRENT_VERTEX_ATTRIB:
822 return true;
823
824 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
825 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
826 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400827 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
828 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829 return true;
830
831 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400832 if (context->getClientVersion() < 3)
833 {
Jamie Madill437fa652016-05-03 15:13:24 -0400834 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400835 return false;
836 }
837 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838
839 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400840 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400841 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400842 }
843}
844
Ian Ewellbda75592016-04-18 17:25:54 -0400845bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846{
847 switch (pname)
848 {
849 case GL_TEXTURE_WRAP_R:
850 case GL_TEXTURE_SWIZZLE_R:
851 case GL_TEXTURE_SWIZZLE_G:
852 case GL_TEXTURE_SWIZZLE_B:
853 case GL_TEXTURE_SWIZZLE_A:
854 case GL_TEXTURE_BASE_LEVEL:
855 case GL_TEXTURE_MAX_LEVEL:
856 case GL_TEXTURE_COMPARE_MODE:
857 case GL_TEXTURE_COMPARE_FUNC:
858 case GL_TEXTURE_MIN_LOD:
859 case GL_TEXTURE_MAX_LOD:
Ian Ewellbda75592016-04-18 17:25:54 -0400860 // ES3 texture paramters are not supported on external textures as the extension is
861 // written against ES2.
862 if (context->getClientVersion() < 3 || target == GL_TEXTURE_EXTERNAL_OES)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400863 {
Jamie Madill437fa652016-05-03 15:13:24 -0400864 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400865 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400866 }
867 break;
868
869 default: break;
870 }
871
872 switch (pname)
873 {
874 case GL_TEXTURE_WRAP_S:
875 case GL_TEXTURE_WRAP_T:
876 case GL_TEXTURE_WRAP_R:
877 switch (param)
878 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000879 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400880 return true;
881 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300883 if (target == GL_TEXTURE_EXTERNAL_OES)
884 {
885 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400886 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300887 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
888 return false;
889 }
890 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400891 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400892 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400893 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400894 }
895
896 case GL_TEXTURE_MIN_FILTER:
897 switch (param)
898 {
899 case GL_NEAREST:
900 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400901 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400902 case GL_NEAREST_MIPMAP_NEAREST:
903 case GL_LINEAR_MIPMAP_NEAREST:
904 case GL_NEAREST_MIPMAP_LINEAR:
905 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300906 if (target == GL_TEXTURE_EXTERNAL_OES)
907 {
908 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400909 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300910 Error(GL_INVALID_ENUM,
911 "external textures only support NEAREST and LINEAR filtering"));
912 return false;
913 }
914 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400915 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400916 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400917 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400918 }
919 break;
920
921 case GL_TEXTURE_MAG_FILTER:
922 switch (param)
923 {
924 case GL_NEAREST:
925 case GL_LINEAR:
926 return true;
927 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400928 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400929 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400930 }
931 break;
932
933 case GL_TEXTURE_USAGE_ANGLE:
934 switch (param)
935 {
936 case GL_NONE:
937 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
938 return true;
939 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400940 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400941 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400942 }
943 break;
944
945 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400946 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400947 {
Jamie Madill437fa652016-05-03 15:13:24 -0400948 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400949 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400950 }
951
952 // we assume the parameter passed to this validation method is truncated, not rounded
953 if (param < 1)
954 {
Jamie Madill437fa652016-05-03 15:13:24 -0400955 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400956 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400957 }
958 return true;
959
960 case GL_TEXTURE_MIN_LOD:
961 case GL_TEXTURE_MAX_LOD:
962 // any value is permissible
963 return true;
964
965 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400966 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400967 switch (param)
968 {
969 case GL_NONE:
970 case GL_COMPARE_REF_TO_TEXTURE:
971 return true;
972 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400973 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400974 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400975 }
976 break;
977
978 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400979 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400980 switch (param)
981 {
982 case GL_LEQUAL:
983 case GL_GEQUAL:
984 case GL_LESS:
985 case GL_GREATER:
986 case GL_EQUAL:
987 case GL_NOTEQUAL:
988 case GL_ALWAYS:
989 case GL_NEVER:
990 return true;
991 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400992 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400993 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400994 }
995 break;
996
997 case GL_TEXTURE_SWIZZLE_R:
998 case GL_TEXTURE_SWIZZLE_G:
999 case GL_TEXTURE_SWIZZLE_B:
1000 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001001 switch (param)
1002 {
1003 case GL_RED:
1004 case GL_GREEN:
1005 case GL_BLUE:
1006 case GL_ALPHA:
1007 case GL_ZERO:
1008 case GL_ONE:
1009 return true;
1010 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001011 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001012 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001013 }
1014 break;
1015
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001016 case GL_TEXTURE_BASE_LEVEL:
1017 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001018 if (target == GL_TEXTURE_EXTERNAL_OES)
1019 {
1020 // This is not specified, but in line with the spirit of OES_EGL_image_external spec,
1021 // which generally forbids setting mipmap related parameters on external textures.
1022 context->handleError(
1023 Error(GL_INVALID_OPERATION,
1024 "Setting the base level or max level of external textures not supported"));
1025 return false;
1026 }
1027 if (param < 0)
1028 {
1029 context->handleError(Error(GL_INVALID_VALUE));
1030 return false;
1031 }
1032 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001033 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001034 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001035 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001036 }
1037}
1038
Geoff Langb1196682014-07-23 13:47:29 -04001039bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001040{
1041 switch (pname)
1042 {
1043 case GL_TEXTURE_MIN_FILTER:
1044 case GL_TEXTURE_MAG_FILTER:
1045 case GL_TEXTURE_WRAP_S:
1046 case GL_TEXTURE_WRAP_T:
1047 case GL_TEXTURE_WRAP_R:
1048 case GL_TEXTURE_MIN_LOD:
1049 case GL_TEXTURE_MAX_LOD:
1050 case GL_TEXTURE_COMPARE_MODE:
1051 case GL_TEXTURE_COMPARE_FUNC:
1052 return true;
1053
1054 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001055 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001056 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001057 }
1058}
1059
Jamie Madillc29968b2016-01-20 11:17:23 -05001060bool ValidateReadPixels(Context *context,
1061 GLint x,
1062 GLint y,
1063 GLsizei width,
1064 GLsizei height,
1065 GLenum format,
1066 GLenum type,
1067 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001068{
Jamie Madillc29968b2016-01-20 11:17:23 -05001069 if (width < 0 || height < 0)
1070 {
Jamie Madill437fa652016-05-03 15:13:24 -04001071 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001072 return false;
1073 }
1074
1075 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001076 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001077
Geoff Lang748f74e2014-12-01 11:25:34 -05001078 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001079 {
Jamie Madill437fa652016-05-03 15:13:24 -04001080 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001081 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001082 }
1083
Jamie Madill48faf802014-11-06 15:27:22 -05001084 if (context->getState().getReadFramebuffer()->id() != 0 &&
1085 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001086 {
Jamie Madill437fa652016-05-03 15:13:24 -04001087 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001088 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001089 }
1090
Geoff Langbce529e2014-12-01 12:48:41 -05001091 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1092 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001093 {
Jamie Madill437fa652016-05-03 15:13:24 -04001094 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001095 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001096 }
1097
Geoff Langbce529e2014-12-01 12:48:41 -05001098 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1099 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001100 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001101 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001102
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001103 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1104 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001105
1106 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1107 {
Jamie Madill437fa652016-05-03 15:13:24 -04001108 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001109 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001110 }
1111
Jamie Madillc29968b2016-01-20 11:17:23 -05001112 return true;
1113}
1114
1115bool ValidateReadnPixelsEXT(Context *context,
1116 GLint x,
1117 GLint y,
1118 GLsizei width,
1119 GLsizei height,
1120 GLenum format,
1121 GLenum type,
1122 GLsizei bufSize,
1123 GLvoid *pixels)
1124{
1125 if (bufSize < 0)
1126 {
Jamie Madill437fa652016-05-03 15:13:24 -04001127 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001128 return false;
1129 }
1130
Geoff Lang5d601382014-07-22 15:14:06 -04001131 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1132 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001133
Minmin Gongadff67b2015-10-14 10:34:45 -04001134 GLsizei outputPitch =
1135 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1136 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001137 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001138 int requiredSize = outputPitch * height;
1139 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001140 {
Jamie Madill437fa652016-05-03 15:13:24 -04001141 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001142 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001143 }
1144
Jamie Madillc29968b2016-01-20 11:17:23 -05001145 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001146}
1147
Olli Etuaho41997e72016-03-10 13:38:39 +02001148bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001149{
1150 if (!context->getExtensions().occlusionQueryBoolean &&
1151 !context->getExtensions().disjointTimerQuery)
1152 {
Jamie Madill437fa652016-05-03 15:13:24 -04001153 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001154 return false;
1155 }
1156
Olli Etuaho41997e72016-03-10 13:38:39 +02001157 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001158}
1159
Olli Etuaho41997e72016-03-10 13:38:39 +02001160bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001161{
1162 if (!context->getExtensions().occlusionQueryBoolean &&
1163 !context->getExtensions().disjointTimerQuery)
1164 {
Jamie Madill437fa652016-05-03 15:13:24 -04001165 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001166 return false;
1167 }
1168
Olli Etuaho41997e72016-03-10 13:38:39 +02001169 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001170}
1171
1172bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001173{
1174 if (!ValidQueryType(context, target))
1175 {
Jamie Madill437fa652016-05-03 15:13:24 -04001176 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001177 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001178 }
1179
1180 if (id == 0)
1181 {
Jamie Madill437fa652016-05-03 15:13:24 -04001182 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001183 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001184 }
1185
1186 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1187 // of zero, if the active query object name for <target> is non-zero (for the
1188 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1189 // the active query for either target is non-zero), if <id> is the name of an
1190 // existing query object whose type does not match <target>, or if <id> is the
1191 // active query object name for any query type, the error INVALID_OPERATION is
1192 // generated.
1193
1194 // Ensure no other queries are active
1195 // NOTE: If other queries than occlusion are supported, we will need to check
1196 // separately that:
1197 // a) The query ID passed is not the current active query for any target/type
1198 // b) There are no active queries for the requested target (and in the case
1199 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1200 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001201
Corentin Walleze71ea192016-04-19 13:16:37 -04001202 if (context->getState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001203 {
Jamie Madill437fa652016-05-03 15:13:24 -04001204 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001205 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001206 }
1207
1208 Query *queryObject = context->getQuery(id, true, target);
1209
1210 // check that name was obtained with glGenQueries
1211 if (!queryObject)
1212 {
Jamie Madill437fa652016-05-03 15:13:24 -04001213 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001214 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001215 }
1216
1217 // check for type mismatch
1218 if (queryObject->getType() != target)
1219 {
Jamie Madill437fa652016-05-03 15:13:24 -04001220 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001221 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001222 }
1223
1224 return true;
1225}
1226
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001227bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1228{
1229 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001230 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001231 {
Jamie Madill437fa652016-05-03 15:13:24 -04001232 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001233 return false;
1234 }
1235
1236 return ValidateBeginQueryBase(context, target, id);
1237}
1238
1239bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001240{
1241 if (!ValidQueryType(context, target))
1242 {
Jamie Madill437fa652016-05-03 15:13:24 -04001243 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001244 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001245 }
1246
Shannon Woods53a94a82014-06-24 15:20:36 -04001247 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001248
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001249 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001250 {
Jamie Madill437fa652016-05-03 15:13:24 -04001251 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001252 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001253 }
1254
Jamie Madill45c785d2014-05-13 14:09:34 -04001255 return true;
1256}
1257
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001258bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1259{
1260 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001261 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001262 {
Jamie Madill437fa652016-05-03 15:13:24 -04001263 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001264 return false;
1265 }
1266
1267 return ValidateEndQueryBase(context, target);
1268}
1269
1270bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1271{
1272 if (!context->getExtensions().disjointTimerQuery)
1273 {
Jamie Madill437fa652016-05-03 15:13:24 -04001274 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001275 return false;
1276 }
1277
1278 if (target != GL_TIMESTAMP_EXT)
1279 {
Jamie Madill437fa652016-05-03 15:13:24 -04001280 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001281 return false;
1282 }
1283
1284 Query *queryObject = context->getQuery(id, true, target);
1285 if (queryObject == nullptr)
1286 {
Jamie Madill437fa652016-05-03 15:13:24 -04001287 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001288 return false;
1289 }
1290
1291 if (context->getState().isQueryActive(queryObject))
1292 {
Jamie Madill437fa652016-05-03 15:13:24 -04001293 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001294 return false;
1295 }
1296
1297 return true;
1298}
1299
1300bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1301{
1302 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1303 {
Jamie Madill437fa652016-05-03 15:13:24 -04001304 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001305 return false;
1306 }
1307
1308 switch (pname)
1309 {
1310 case GL_CURRENT_QUERY_EXT:
1311 if (target == GL_TIMESTAMP_EXT)
1312 {
Jamie Madill437fa652016-05-03 15:13:24 -04001313 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001314 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1315 return false;
1316 }
1317 break;
1318 case GL_QUERY_COUNTER_BITS_EXT:
1319 if (!context->getExtensions().disjointTimerQuery ||
1320 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1321 {
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 break;
1326 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001327 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001328 return false;
1329 }
1330
1331 return true;
1332}
1333
1334bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1335{
1336 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001337 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001338 {
Jamie Madill437fa652016-05-03 15:13:24 -04001339 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001340 return false;
1341 }
1342
1343 return ValidateGetQueryivBase(context, target, pname);
1344}
1345
1346bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1347{
1348 Query *queryObject = context->getQuery(id, false, GL_NONE);
1349
1350 if (!queryObject)
1351 {
Jamie Madill437fa652016-05-03 15:13:24 -04001352 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001353 return false;
1354 }
1355
1356 if (context->getState().isQueryActive(queryObject))
1357 {
Jamie Madill437fa652016-05-03 15:13:24 -04001358 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001359 return false;
1360 }
1361
1362 switch (pname)
1363 {
1364 case GL_QUERY_RESULT_EXT:
1365 case GL_QUERY_RESULT_AVAILABLE_EXT:
1366 break;
1367
1368 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001369 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001370 return false;
1371 }
1372
1373 return true;
1374}
1375
1376bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1377{
1378 if (!context->getExtensions().disjointTimerQuery)
1379 {
Jamie Madill437fa652016-05-03 15:13:24 -04001380 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001381 return false;
1382 }
1383 return ValidateGetQueryObjectValueBase(context, id, pname);
1384}
1385
1386bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1387{
1388 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001389 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001390 {
Jamie Madill437fa652016-05-03 15:13:24 -04001391 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001392 return false;
1393 }
1394 return ValidateGetQueryObjectValueBase(context, id, pname);
1395}
1396
1397bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1398{
1399 if (!context->getExtensions().disjointTimerQuery)
1400 {
Jamie Madill437fa652016-05-03 15:13:24 -04001401 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001402 return false;
1403 }
1404 return ValidateGetQueryObjectValueBase(context, id, pname);
1405}
1406
1407bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1408{
1409 if (!context->getExtensions().disjointTimerQuery)
1410 {
Jamie Madill437fa652016-05-03 15:13:24 -04001411 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001412 return false;
1413 }
1414 return ValidateGetQueryObjectValueBase(context, id, pname);
1415}
1416
Jamie Madill62d31cb2015-09-11 13:25:51 -04001417static bool ValidateUniformCommonBase(gl::Context *context,
1418 GLenum targetUniformType,
1419 GLint location,
1420 GLsizei count,
1421 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001422{
1423 if (count < 0)
1424 {
Jamie Madill437fa652016-05-03 15:13:24 -04001425 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001426 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001427 }
1428
Geoff Lang7dd2e102014-11-10 15:19:26 -05001429 gl::Program *program = context->getState().getProgram();
1430 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001431 {
Jamie Madill437fa652016-05-03 15:13:24 -04001432 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001433 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001434 }
1435
Geoff Langd8605522016-04-13 10:19:12 -04001436 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001437 {
1438 // Silently ignore the uniform command
1439 return false;
1440 }
1441
Geoff Lang7dd2e102014-11-10 15:19:26 -05001442 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001443 {
Jamie Madill437fa652016-05-03 15:13:24 -04001444 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001445 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001446 }
1447
Jamie Madill62d31cb2015-09-11 13:25:51 -04001448 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001449
1450 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001451 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001452 {
Jamie Madill437fa652016-05-03 15:13:24 -04001453 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001454 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001455 }
1456
Jamie Madill62d31cb2015-09-11 13:25:51 -04001457 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001458 return true;
1459}
1460
Jamie Madillaa981bd2014-05-20 10:55:55 -04001461bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1462{
1463 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001464 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001465 {
Jamie Madill437fa652016-05-03 15:13:24 -04001466 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001467 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001468 }
1469
Jamie Madill62d31cb2015-09-11 13:25:51 -04001470 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001471 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1472 {
1473 return false;
1474 }
1475
Jamie Madillf2575982014-06-25 16:04:54 -04001476 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001477 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001478 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1479 {
Jamie Madill437fa652016-05-03 15:13:24 -04001480 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001481 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001482 }
1483
1484 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001485}
1486
1487bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1488 GLboolean transpose)
1489{
1490 // Check for ES3 uniform entry points
1491 int rows = VariableRowCount(matrixType);
1492 int cols = VariableColumnCount(matrixType);
1493 if (rows != cols && context->getClientVersion() < 3)
1494 {
Jamie Madill437fa652016-05-03 15:13:24 -04001495 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001496 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001497 }
1498
1499 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1500 {
Jamie Madill437fa652016-05-03 15:13:24 -04001501 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001502 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001503 }
1504
Jamie Madill62d31cb2015-09-11 13:25:51 -04001505 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001506 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1507 {
1508 return false;
1509 }
1510
1511 if (uniform->type != matrixType)
1512 {
Jamie Madill437fa652016-05-03 15:13:24 -04001513 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001514 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001515 }
1516
1517 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001518}
1519
Jamie Madill893ab082014-05-16 16:56:10 -04001520bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1521{
1522 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1523 {
Jamie Madill437fa652016-05-03 15:13:24 -04001524 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001525 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001526 }
1527
Jamie Madill0af26e12015-03-05 19:54:33 -05001528 const Caps &caps = context->getCaps();
1529
Jamie Madill893ab082014-05-16 16:56:10 -04001530 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1531 {
1532 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1533
Jamie Madill0af26e12015-03-05 19:54:33 -05001534 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001535 {
Jamie Madill437fa652016-05-03 15:13:24 -04001536 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001537 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001538 }
1539 }
1540
1541 switch (pname)
1542 {
1543 case GL_TEXTURE_BINDING_2D:
1544 case GL_TEXTURE_BINDING_CUBE_MAP:
1545 case GL_TEXTURE_BINDING_3D:
1546 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001547 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001548 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1549 if (!context->getExtensions().eglStreamConsumerExternal)
1550 {
Jamie Madill437fa652016-05-03 15:13:24 -04001551 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001552 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1553 return false;
1554 }
1555 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001556
1557 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1558 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1559 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001560 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001561 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001562 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001563 {
Jamie Madill437fa652016-05-03 15:13:24 -04001564 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001565 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001566 }
1567
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001568 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001569 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001570 {
Jamie Madill437fa652016-05-03 15:13:24 -04001571 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001572 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001573 }
1574 }
1575 break;
1576
1577 default:
1578 break;
1579 }
1580
1581 // pname is valid, but there are no parameters to return
1582 if (numParams == 0)
1583 {
1584 return false;
1585 }
1586
1587 return true;
1588}
1589
Jamie Madillc29968b2016-01-20 11:17:23 -05001590bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1591 GLenum target,
1592 GLint level,
1593 GLenum internalformat,
1594 bool isSubImage,
1595 GLint xoffset,
1596 GLint yoffset,
1597 GLint zoffset,
1598 GLint x,
1599 GLint y,
1600 GLsizei width,
1601 GLsizei height,
1602 GLint border,
1603 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001604{
Jamie Madill560a8d82014-05-21 13:06:20 -04001605 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1606 {
Jamie Madill437fa652016-05-03 15:13:24 -04001607 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001608 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001609 }
1610
1611 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1612 {
Jamie Madill437fa652016-05-03 15:13:24 -04001613 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001614 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001615 }
1616
1617 if (border != 0)
1618 {
Jamie Madill437fa652016-05-03 15:13:24 -04001619 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001620 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001621 }
1622
1623 if (!ValidMipLevel(context, target, level))
1624 {
Jamie Madill437fa652016-05-03 15:13:24 -04001625 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001626 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001627 }
1628
Jamie Madillc29968b2016-01-20 11:17:23 -05001629 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001630 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001631 {
Jamie Madill437fa652016-05-03 15:13:24 -04001632 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001633 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001634 }
1635
Jamie Madillc29968b2016-01-20 11:17:23 -05001636 const auto &state = context->getState();
1637 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001638 {
Jamie Madill437fa652016-05-03 15:13:24 -04001639 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001640 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001641 }
1642
Geoff Langaae65a42014-05-26 12:43:44 -04001643 const gl::Caps &caps = context->getCaps();
1644
Geoff Langaae65a42014-05-26 12:43:44 -04001645 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001646 switch (target)
1647 {
1648 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001649 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001650 break;
1651
1652 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1653 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1654 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1655 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1656 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1657 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001658 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001659 break;
1660
1661 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001662 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001663 break;
1664
1665 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001666 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001667 break;
1668
1669 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001670 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001671 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001672 }
1673
Jamie Madillc29968b2016-01-20 11:17:23 -05001674 gl::Texture *texture =
1675 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001676 if (!texture)
1677 {
Jamie Madill437fa652016-05-03 15:13:24 -04001678 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001679 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001680 }
1681
Geoff Lang69cce582015-09-17 13:20:36 -04001682 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001683 {
Jamie Madill437fa652016-05-03 15:13:24 -04001684 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001685 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001686 }
1687
Geoff Lang5d601382014-07-22 15:14:06 -04001688 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1689
1690 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001691 {
Jamie Madill437fa652016-05-03 15:13:24 -04001692 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001693 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001694 }
1695
Geoff Langa9be0dc2014-12-17 12:34:40 -05001696 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001697 {
Jamie Madill437fa652016-05-03 15:13:24 -04001698 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001699 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001700 }
1701
1702 if (isSubImage)
1703 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001704 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1705 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1706 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001707 {
Jamie Madill437fa652016-05-03 15:13:24 -04001708 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001709 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001710 }
1711 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001712 else
1713 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001714 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001715 {
Jamie Madill437fa652016-05-03 15:13:24 -04001716 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001717 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001718 }
1719
Geoff Lang5d601382014-07-22 15:14:06 -04001720 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001721 {
Jamie Madill437fa652016-05-03 15:13:24 -04001722 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001723 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001724 }
1725
1726 int maxLevelDimension = (maxDimension >> level);
1727 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1728 {
Jamie Madill437fa652016-05-03 15:13:24 -04001729 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001730 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001731 }
1732 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001733
Geoff Langa9be0dc2014-12-17 12:34:40 -05001734 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001735 return true;
1736}
1737
Jamie Madillf25855c2015-11-03 11:06:18 -05001738static bool ValidateDrawBase(ValidationContext *context,
1739 GLenum mode,
1740 GLsizei count,
1741 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001742{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001743 switch (mode)
1744 {
1745 case GL_POINTS:
1746 case GL_LINES:
1747 case GL_LINE_LOOP:
1748 case GL_LINE_STRIP:
1749 case GL_TRIANGLES:
1750 case GL_TRIANGLE_STRIP:
1751 case GL_TRIANGLE_FAN:
1752 break;
1753 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001754 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001755 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001756 }
1757
Jamie Madill250d33f2014-06-06 17:09:03 -04001758 if (count < 0)
1759 {
Jamie Madill437fa652016-05-03 15:13:24 -04001760 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001761 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001762 }
1763
Geoff Langb1196682014-07-23 13:47:29 -04001764 const State &state = context->getState();
1765
Jamie Madill250d33f2014-06-06 17:09:03 -04001766 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001767 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001768 {
Jamie Madill437fa652016-05-03 15:13:24 -04001769 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001770 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001771 }
1772
Geoff Lang3a86ad32015-09-01 11:47:05 -04001773 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001774 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001775 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1776 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1777 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1778 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1779 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1780 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1781 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001782 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001783 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1784 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001785 {
1786 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1787 // Section 6.10 of the WebGL 1.0 spec
1788 ERR(
1789 "This ANGLE implementation does not support separate front/back stencil "
1790 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001791 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001792 return false;
1793 }
Jamie Madillac528012014-06-20 13:21:23 -04001794 }
1795
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001796 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001797 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001798 {
Jamie Madill437fa652016-05-03 15:13:24 -04001799 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001800 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001801 }
1802
Geoff Lang7dd2e102014-11-10 15:19:26 -05001803 gl::Program *program = state.getProgram();
1804 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001805 {
Jamie Madill437fa652016-05-03 15:13:24 -04001806 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001807 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001808 }
1809
Geoff Lang7dd2e102014-11-10 15:19:26 -05001810 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001811 {
Jamie Madill437fa652016-05-03 15:13:24 -04001812 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001813 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001814 }
1815
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001816 // Uniform buffer validation
1817 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1818 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001819 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001820 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001821 const OffsetBindingPointer<Buffer> &uniformBuffer =
1822 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001823
Geoff Lang5d124a62015-09-15 13:03:27 -04001824 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001825 {
1826 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001827 context->handleError(
1828 Error(GL_INVALID_OPERATION,
1829 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001830 return false;
1831 }
1832
Geoff Lang5d124a62015-09-15 13:03:27 -04001833 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001834 if (uniformBufferSize == 0)
1835 {
1836 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001837 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001838 }
1839
Jamie Madill62d31cb2015-09-11 13:25:51 -04001840 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001841 {
1842 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001843 context->handleError(
1844 Error(GL_INVALID_OPERATION,
1845 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001846 return false;
1847 }
1848 }
1849
Jamie Madill250d33f2014-06-06 17:09:03 -04001850 // No-op if zero count
1851 return (count > 0);
1852}
1853
Geoff Langb1196682014-07-23 13:47:29 -04001854bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001855{
Jamie Madillfd716582014-06-06 17:09:04 -04001856 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001857 {
Jamie Madill437fa652016-05-03 15:13:24 -04001858 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001859 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001860 }
1861
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001862 const State &state = context->getState();
1863 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001864 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1865 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001866 {
1867 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1868 // that does not match the current transform feedback object's draw mode (if transform feedback
1869 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001870 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001871 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001872 }
1873
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001874 if (!ValidateDrawBase(context, mode, count, primcount))
1875 {
1876 return false;
1877 }
1878
1879 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001880 {
1881 return false;
1882 }
1883
1884 return true;
1885}
1886
Geoff Langb1196682014-07-23 13:47:29 -04001887bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001888{
1889 if (primcount < 0)
1890 {
Jamie Madill437fa652016-05-03 15:13:24 -04001891 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001892 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001893 }
1894
Jamie Madill2b976812014-08-25 15:47:49 -04001895 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001896 {
1897 return false;
1898 }
1899
1900 // No-op if zero primitive count
1901 return (primcount > 0);
1902}
1903
Geoff Lang87a93302014-09-16 13:29:43 -04001904static bool ValidateDrawInstancedANGLE(Context *context)
1905{
1906 // Verify there is at least one active attribute with a divisor of zero
1907 const gl::State& state = context->getState();
1908
Geoff Lang7dd2e102014-11-10 15:19:26 -05001909 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001910
1911 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001912 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001913 {
1914 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001915 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001916 {
1917 return true;
1918 }
1919 }
1920
Jamie Madill437fa652016-05-03 15:13:24 -04001921 context->handleError(Error(GL_INVALID_OPERATION,
1922 "ANGLE_instanced_arrays requires that at least one active attribute"
1923 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001924 return false;
1925}
1926
1927bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1928{
1929 if (!ValidateDrawInstancedANGLE(context))
1930 {
1931 return false;
1932 }
1933
1934 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1935}
1936
Jamie Madillf25855c2015-11-03 11:06:18 -05001937bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001938 GLenum mode,
1939 GLsizei count,
1940 GLenum type,
1941 const GLvoid *indices,
1942 GLsizei primcount,
1943 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001944{
Jamie Madill250d33f2014-06-06 17:09:03 -04001945 switch (type)
1946 {
1947 case GL_UNSIGNED_BYTE:
1948 case GL_UNSIGNED_SHORT:
1949 break;
1950 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001951 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001952 {
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 break;
1957 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001958 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001959 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001960 }
1961
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001962 const State &state = context->getState();
1963
1964 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001965 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001966 {
1967 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1968 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001969 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001970 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001971 }
1972
1973 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001974 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001975 {
Jamie Madill437fa652016-05-03 15:13:24 -04001976 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001977 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001978 }
1979
Jamie Madill2b976812014-08-25 15:47:49 -04001980 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001981 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001982 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001983 {
Jamie Madill437fa652016-05-03 15:13:24 -04001984 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001985 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001986 }
1987
Jamie Madillae3000b2014-08-25 15:47:51 -04001988 if (elementArrayBuffer)
1989 {
1990 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1991
1992 GLint64 offset = reinterpret_cast<GLint64>(indices);
1993 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1994
1995 // check for integer overflows
1996 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1997 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1998 {
Jamie Madill437fa652016-05-03 15:13:24 -04001999 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002000 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002001 }
2002
2003 // Check for reading past the end of the bound buffer object
2004 if (byteCount > elementArrayBuffer->getSize())
2005 {
Jamie Madill437fa652016-05-03 15:13:24 -04002006 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002007 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002008 }
2009 }
2010 else if (!indices)
2011 {
2012 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002013 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002014 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002015 }
2016
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002017 if (!ValidateDrawBase(context, mode, count, primcount))
2018 {
2019 return false;
2020 }
2021
Jamie Madill2b976812014-08-25 15:47:49 -04002022 // Use max index to validate if our vertex buffers are large enough for the pull.
2023 // TODO: offer fast path, with disabled index validation.
2024 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2025 if (elementArrayBuffer)
2026 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002027 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002028 Error error =
2029 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2030 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002031 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002032 {
Jamie Madill437fa652016-05-03 15:13:24 -04002033 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002034 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002035 }
2036 }
2037 else
2038 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002039 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002040 }
2041
Jamie Madille79b1e12015-11-04 16:36:37 -05002042 // If we use an index greater than our maximum supported index range, return an error.
2043 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2044 // return an error if possible here.
2045 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2046 {
Jamie Madill437fa652016-05-03 15:13:24 -04002047 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002048 return false;
2049 }
2050
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002051 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002052 {
2053 return false;
2054 }
2055
Geoff Lang3edfe032015-09-04 16:38:24 -04002056 // No op if there are no real indices in the index data (all are primitive restart).
2057 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002058}
2059
Geoff Langb1196682014-07-23 13:47:29 -04002060bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002061 GLenum mode,
2062 GLsizei count,
2063 GLenum type,
2064 const GLvoid *indices,
2065 GLsizei primcount,
2066 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002067{
2068 if (primcount < 0)
2069 {
Jamie Madill437fa652016-05-03 15:13:24 -04002070 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002071 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002072 }
2073
Jamie Madill2b976812014-08-25 15:47:49 -04002074 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002075 {
2076 return false;
2077 }
2078
2079 // No-op zero primitive count
2080 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002081}
2082
Geoff Lang3edfe032015-09-04 16:38:24 -04002083bool ValidateDrawElementsInstancedANGLE(Context *context,
2084 GLenum mode,
2085 GLsizei count,
2086 GLenum type,
2087 const GLvoid *indices,
2088 GLsizei primcount,
2089 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002090{
2091 if (!ValidateDrawInstancedANGLE(context))
2092 {
2093 return false;
2094 }
2095
2096 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2097}
2098
Geoff Langb1196682014-07-23 13:47:29 -04002099bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002100 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002101{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002102 if (!ValidFramebufferTarget(target))
2103 {
Jamie Madill437fa652016-05-03 15:13:24 -04002104 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002105 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002106 }
2107
2108 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002109 {
2110 return false;
2111 }
2112
Jamie Madill55ec3b12014-07-03 10:38:57 -04002113 if (texture != 0)
2114 {
2115 gl::Texture *tex = context->getTexture(texture);
2116
2117 if (tex == NULL)
2118 {
Jamie Madill437fa652016-05-03 15:13:24 -04002119 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002120 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002121 }
2122
2123 if (level < 0)
2124 {
Jamie Madill437fa652016-05-03 15:13:24 -04002125 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002126 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002127 }
2128 }
2129
Shannon Woods53a94a82014-06-24 15:20:36 -04002130 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002131 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002132
Jamie Madill84115c92015-04-23 15:00:07 -04002133 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002134 {
Jamie Madill437fa652016-05-03 15:13:24 -04002135 context->handleError(
2136 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002137 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002138 }
2139
2140 return true;
2141}
2142
Geoff Langb1196682014-07-23 13:47:29 -04002143bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002144 GLenum textarget, GLuint texture, GLint level)
2145{
Geoff Lang95663912015-04-02 15:54:45 -04002146 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2147 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002148 {
Jamie Madill437fa652016-05-03 15:13:24 -04002149 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002150 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002151 }
2152
2153 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002154 {
2155 return false;
2156 }
2157
Jamie Madill55ec3b12014-07-03 10:38:57 -04002158 if (texture != 0)
2159 {
2160 gl::Texture *tex = context->getTexture(texture);
2161 ASSERT(tex);
2162
Jamie Madill2a6564e2014-07-11 09:53:19 -04002163 const gl::Caps &caps = context->getCaps();
2164
Jamie Madill55ec3b12014-07-03 10:38:57 -04002165 switch (textarget)
2166 {
2167 case GL_TEXTURE_2D:
2168 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002169 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002170 {
Jamie Madill437fa652016-05-03 15:13:24 -04002171 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002172 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002173 }
2174 if (tex->getTarget() != GL_TEXTURE_2D)
2175 {
Jamie Madill437fa652016-05-03 15:13:24 -04002176 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002177 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002178 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002179 }
2180 break;
2181
2182 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2183 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2184 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2185 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2186 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2187 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2188 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002189 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002190 {
Jamie Madill437fa652016-05-03 15:13:24 -04002191 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002192 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002193 }
2194 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2195 {
Jamie Madill437fa652016-05-03 15:13:24 -04002196 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002197 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002198 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002199 }
2200 break;
2201
2202 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002203 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002204 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002205 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002206
2207 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2208 if (internalFormatInfo.compressed)
2209 {
Jamie Madill437fa652016-05-03 15:13:24 -04002210 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002211 return false;
2212 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002213 }
2214
Jamie Madill570f7c82014-07-03 10:38:54 -04002215 return true;
2216}
2217
Geoff Langb1196682014-07-23 13:47:29 -04002218bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002219{
2220 if (program == 0)
2221 {
Jamie Madill437fa652016-05-03 15:13:24 -04002222 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002223 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002224 }
2225
Dian Xiang769769a2015-09-09 15:20:08 -07002226 gl::Program *programObject = GetValidProgram(context, program);
2227 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002228 {
2229 return false;
2230 }
2231
Jamie Madill0063c512014-08-25 15:47:53 -04002232 if (!programObject || !programObject->isLinked())
2233 {
Jamie Madill437fa652016-05-03 15:13:24 -04002234 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002235 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002236 }
2237
Geoff Lang7dd2e102014-11-10 15:19:26 -05002238 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002239 {
Jamie Madill437fa652016-05-03 15:13:24 -04002240 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002241 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002242 }
2243
Jamie Madill0063c512014-08-25 15:47:53 -04002244 return true;
2245}
2246
Geoff Langb1196682014-07-23 13:47:29 -04002247bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002248{
2249 return ValidateGetUniformBase(context, program, location);
2250}
2251
Geoff Langb1196682014-07-23 13:47:29 -04002252bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002253{
Jamie Madill78f41802014-08-25 15:47:55 -04002254 return ValidateGetUniformBase(context, program, location);
2255}
2256
Geoff Langb1196682014-07-23 13:47:29 -04002257static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002258{
2259 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002260 {
Jamie Madill78f41802014-08-25 15:47:55 -04002261 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002262 }
2263
Jamie Madilla502c742014-08-28 17:19:13 -04002264 gl::Program *programObject = context->getProgram(program);
2265 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002266
Jamie Madill78f41802014-08-25 15:47:55 -04002267 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002268 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2269 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002270 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002271 {
Jamie Madill437fa652016-05-03 15:13:24 -04002272 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002273 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002274 }
2275
2276 return true;
2277}
2278
Geoff Langb1196682014-07-23 13:47:29 -04002279bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* 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
Geoff Langb1196682014-07-23 13:47:29 -04002284bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002285{
Jamie Madill78f41802014-08-25 15:47:55 -04002286 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002287}
2288
Austin Kinross08332632015-05-05 13:35:47 -07002289bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2290 const GLenum *attachments, bool defaultFramebuffer)
2291{
2292 if (numAttachments < 0)
2293 {
Jamie Madill437fa652016-05-03 15:13:24 -04002294 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002295 return false;
2296 }
2297
2298 for (GLsizei i = 0; i < numAttachments; ++i)
2299 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002300 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002301 {
2302 if (defaultFramebuffer)
2303 {
Jamie Madill437fa652016-05-03 15:13:24 -04002304 context->handleError(Error(
2305 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002306 return false;
2307 }
2308
2309 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2310 {
Jamie Madill437fa652016-05-03 15:13:24 -04002311 context->handleError(Error(GL_INVALID_OPERATION,
2312 "Requested color attachment is greater than the maximum "
2313 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002314 return false;
2315 }
2316 }
2317 else
2318 {
2319 switch (attachments[i])
2320 {
2321 case GL_DEPTH_ATTACHMENT:
2322 case GL_STENCIL_ATTACHMENT:
2323 case GL_DEPTH_STENCIL_ATTACHMENT:
2324 if (defaultFramebuffer)
2325 {
Jamie Madill437fa652016-05-03 15:13:24 -04002326 context->handleError(
2327 Error(GL_INVALID_ENUM,
2328 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002329 return false;
2330 }
2331 break;
2332 case GL_COLOR:
2333 case GL_DEPTH:
2334 case GL_STENCIL:
2335 if (!defaultFramebuffer)
2336 {
Jamie Madill437fa652016-05-03 15:13:24 -04002337 context->handleError(
2338 Error(GL_INVALID_ENUM,
2339 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002340 return false;
2341 }
2342 break;
2343 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002344 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002345 return false;
2346 }
2347 }
2348 }
2349
2350 return true;
2351}
2352
Austin Kinross6ee1e782015-05-29 17:05:37 -07002353bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2354{
2355 // Note that debug marker calls must not set error state
2356
2357 if (length < 0)
2358 {
2359 return false;
2360 }
2361
2362 if (marker == nullptr)
2363 {
2364 return false;
2365 }
2366
2367 return true;
2368}
2369
2370bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2371{
2372 // Note that debug marker calls must not set error state
2373
2374 if (length < 0)
2375 {
2376 return false;
2377 }
2378
2379 if (length > 0 && marker == nullptr)
2380 {
2381 return false;
2382 }
2383
2384 return true;
2385}
2386
Geoff Langdcab33b2015-07-21 13:03:16 -04002387bool ValidateEGLImageTargetTexture2DOES(Context *context,
2388 egl::Display *display,
2389 GLenum target,
2390 egl::Image *image)
2391{
Geoff Langa8406172015-07-21 16:53:39 -04002392 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2393 {
Jamie Madill437fa652016-05-03 15:13:24 -04002394 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002395 return false;
2396 }
2397
2398 switch (target)
2399 {
2400 case GL_TEXTURE_2D:
2401 break;
2402
2403 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002404 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002405 return false;
2406 }
2407
2408 if (!display->isValidImage(image))
2409 {
Jamie Madill437fa652016-05-03 15:13:24 -04002410 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002411 return false;
2412 }
2413
2414 if (image->getSamples() > 0)
2415 {
Jamie Madill437fa652016-05-03 15:13:24 -04002416 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002417 "cannot create a 2D texture from a multisampled EGL image."));
2418 return false;
2419 }
2420
2421 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2422 if (!textureCaps.texturable)
2423 {
Jamie Madill437fa652016-05-03 15:13:24 -04002424 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002425 "EGL image internal format is not supported as a texture."));
2426 return false;
2427 }
2428
Geoff Langdcab33b2015-07-21 13:03:16 -04002429 return true;
2430}
2431
2432bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2433 egl::Display *display,
2434 GLenum target,
2435 egl::Image *image)
2436{
Geoff Langa8406172015-07-21 16:53:39 -04002437 if (!context->getExtensions().eglImage)
2438 {
Jamie Madill437fa652016-05-03 15:13:24 -04002439 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002440 return false;
2441 }
2442
2443 switch (target)
2444 {
2445 case GL_RENDERBUFFER:
2446 break;
2447
2448 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002449 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002450 return false;
2451 }
2452
2453 if (!display->isValidImage(image))
2454 {
Jamie Madill437fa652016-05-03 15:13:24 -04002455 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002456 return false;
2457 }
2458
2459 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2460 if (!textureCaps.renderable)
2461 {
Jamie Madill437fa652016-05-03 15:13:24 -04002462 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002463 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2464 return false;
2465 }
2466
Geoff Langdcab33b2015-07-21 13:03:16 -04002467 return true;
2468}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002469
2470bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2471{
Geoff Lang36167ab2015-12-07 10:27:14 -05002472 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002473 {
2474 // The default VAO should always exist
2475 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002476 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002477 return false;
2478 }
2479
2480 return true;
2481}
2482
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002483bool ValidateLinkProgram(Context *context, GLuint program)
2484{
2485 if (context->hasActiveTransformFeedback(program))
2486 {
2487 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002488 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002489 "Cannot link program while program is associated with an active "
2490 "transform feedback object."));
2491 return false;
2492 }
2493 return true;
2494}
2495
Geoff Langc5629752015-12-07 16:29:04 -05002496bool ValidateProgramBinaryBase(Context *context,
2497 GLuint program,
2498 GLenum binaryFormat,
2499 const void *binary,
2500 GLint length)
2501{
2502 Program *programObject = GetValidProgram(context, program);
2503 if (programObject == nullptr)
2504 {
2505 return false;
2506 }
2507
2508 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2509 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2510 programBinaryFormats.end())
2511 {
Jamie Madill437fa652016-05-03 15:13:24 -04002512 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002513 return false;
2514 }
2515
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002516 if (context->hasActiveTransformFeedback(program))
2517 {
2518 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002519 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002520 "Cannot change program binary while program is associated with "
2521 "an active transform feedback object."));
2522 return false;
2523 }
2524
Geoff Langc5629752015-12-07 16:29:04 -05002525 return true;
2526}
2527
2528bool ValidateGetProgramBinaryBase(Context *context,
2529 GLuint program,
2530 GLsizei bufSize,
2531 GLsizei *length,
2532 GLenum *binaryFormat,
2533 void *binary)
2534{
2535 Program *programObject = GetValidProgram(context, program);
2536 if (programObject == nullptr)
2537 {
2538 return false;
2539 }
2540
2541 if (!programObject->isLinked())
2542 {
Jamie Madill437fa652016-05-03 15:13:24 -04002543 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002544 return false;
2545 }
2546
2547 return true;
2548}
Jamie Madillc29968b2016-01-20 11:17:23 -05002549
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002550bool ValidateUseProgram(Context *context, GLuint program)
2551{
2552 if (program != 0)
2553 {
2554 Program *programObject = context->getProgram(program);
2555 if (!programObject)
2556 {
2557 // ES 3.1.0 section 7.3 page 72
2558 if (context->getShader(program))
2559 {
Jamie Madill437fa652016-05-03 15:13:24 -04002560 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002561 Error(GL_INVALID_OPERATION,
2562 "Attempted to use a single shader instead of a shader program."));
2563 return false;
2564 }
2565 else
2566 {
Jamie Madill437fa652016-05-03 15:13:24 -04002567 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002568 return false;
2569 }
2570 }
2571 if (!programObject->isLinked())
2572 {
Jamie Madill437fa652016-05-03 15:13:24 -04002573 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002574 return false;
2575 }
2576 }
2577 if (context->getState().isTransformFeedbackActiveUnpaused())
2578 {
2579 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002580 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002581 Error(GL_INVALID_OPERATION,
2582 "Cannot change active program while transform feedback is unpaused."));
2583 return false;
2584 }
2585
2586 return true;
2587}
2588
Jamie Madillc29968b2016-01-20 11:17:23 -05002589bool ValidateCopyTexImage2D(ValidationContext *context,
2590 GLenum target,
2591 GLint level,
2592 GLenum internalformat,
2593 GLint x,
2594 GLint y,
2595 GLsizei width,
2596 GLsizei height,
2597 GLint border)
2598{
2599 if (context->getClientVersion() < 3)
2600 {
2601 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2602 0, x, y, width, height, border);
2603 }
2604
2605 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002606 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2607 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002608}
Jamie Madillc29968b2016-01-20 11:17:23 -05002609
2610bool ValidateFramebufferRenderbuffer(Context *context,
2611 GLenum target,
2612 GLenum attachment,
2613 GLenum renderbuffertarget,
2614 GLuint renderbuffer)
2615{
2616 if (!ValidFramebufferTarget(target) ||
2617 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2618 {
Jamie Madill437fa652016-05-03 15:13:24 -04002619 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002620 return false;
2621 }
2622
2623 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2624 renderbuffertarget, renderbuffer);
2625}
2626
2627bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2628{
2629 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2630 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2631 {
Jamie Madill437fa652016-05-03 15:13:24 -04002632 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002633 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2634 return false;
2635 }
2636
2637 ASSERT(context->getState().getDrawFramebuffer());
2638 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2639 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2640
2641 // This should come first before the check for the default frame buffer
2642 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2643 // rather than INVALID_OPERATION
2644 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2645 {
2646 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2647
2648 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002649 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2650 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002651 {
2652 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002653 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2654 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2655 // 3.1 is still a bit ambiguous about the error, but future specs are
2656 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002657 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002658 return false;
2659 }
2660 else if (bufs[colorAttachment] >= maxColorAttachment)
2661 {
Jamie Madill437fa652016-05-03 15:13:24 -04002662 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002663 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002664 return false;
2665 }
2666 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2667 frameBufferId != 0)
2668 {
2669 // INVALID_OPERATION-GL is bound to buffer and ith argument
2670 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002671 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002672 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2673 return false;
2674 }
2675 }
2676
2677 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2678 // and n is not 1 or bufs is bound to value other than BACK and NONE
2679 if (frameBufferId == 0)
2680 {
2681 if (n != 1)
2682 {
Jamie Madill437fa652016-05-03 15:13:24 -04002683 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002684 "n must be 1 when GL is bound to the default framebuffer"));
2685 return false;
2686 }
2687
2688 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2689 {
Jamie Madill437fa652016-05-03 15:13:24 -04002690 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002691 GL_INVALID_OPERATION,
2692 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2693 return false;
2694 }
2695 }
2696
2697 return true;
2698}
2699
2700bool ValidateCopyTexSubImage2D(Context *context,
2701 GLenum target,
2702 GLint level,
2703 GLint xoffset,
2704 GLint yoffset,
2705 GLint x,
2706 GLint y,
2707 GLsizei width,
2708 GLsizei height)
2709{
2710 if (context->getClientVersion() < 3)
2711 {
2712 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2713 yoffset, x, y, width, height, 0);
2714 }
2715
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002716 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2717 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002718}
2719
Olli Etuaho4f667482016-03-30 15:56:35 +03002720bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2721{
2722 if (!ValidBufferTarget(context, target))
2723 {
Jamie Madill437fa652016-05-03 15:13:24 -04002724 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002725 return false;
2726 }
2727
2728 if (pname != GL_BUFFER_MAP_POINTER)
2729 {
Jamie Madill437fa652016-05-03 15:13:24 -04002730 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002731 return false;
2732 }
2733
2734 Buffer *buffer = context->getState().getTargetBuffer(target);
2735
2736 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2737 // target bound to zero generate an INVALID_OPERATION error."
2738 // GLES 3.1 section 6.6 explicitly specifies this error.
2739 if (!buffer)
2740 {
Jamie Madill437fa652016-05-03 15:13:24 -04002741 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002742 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2743 return false;
2744 }
2745
2746 return true;
2747}
2748
2749bool ValidateUnmapBufferBase(Context *context, GLenum target)
2750{
2751 if (!ValidBufferTarget(context, target))
2752 {
Jamie Madill437fa652016-05-03 15:13:24 -04002753 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002754 return false;
2755 }
2756
2757 Buffer *buffer = context->getState().getTargetBuffer(target);
2758
2759 if (buffer == nullptr || !buffer->isMapped())
2760 {
Jamie Madill437fa652016-05-03 15:13:24 -04002761 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002762 return false;
2763 }
2764
2765 return true;
2766}
2767
2768bool ValidateMapBufferRangeBase(Context *context,
2769 GLenum target,
2770 GLintptr offset,
2771 GLsizeiptr length,
2772 GLbitfield access)
2773{
2774 if (!ValidBufferTarget(context, target))
2775 {
Jamie Madill437fa652016-05-03 15:13:24 -04002776 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002777 return false;
2778 }
2779
2780 if (offset < 0 || length < 0)
2781 {
Jamie Madill437fa652016-05-03 15:13:24 -04002782 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002783 return false;
2784 }
2785
2786 Buffer *buffer = context->getState().getTargetBuffer(target);
2787
2788 if (!buffer)
2789 {
Jamie Madill437fa652016-05-03 15:13:24 -04002790 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002791 return false;
2792 }
2793
2794 // Check for buffer overflow
2795 size_t offsetSize = static_cast<size_t>(offset);
2796 size_t lengthSize = static_cast<size_t>(length);
2797
2798 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2799 offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
2800 {
Jamie Madill437fa652016-05-03 15:13:24 -04002801 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002802 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2803 return false;
2804 }
2805
2806 // Check for invalid bits in the mask
2807 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2808 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2809 GL_MAP_UNSYNCHRONIZED_BIT;
2810
2811 if (access & ~(allAccessBits))
2812 {
Jamie Madill437fa652016-05-03 15:13:24 -04002813 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002814 return false;
2815 }
2816
2817 if (length == 0)
2818 {
Jamie Madill437fa652016-05-03 15:13:24 -04002819 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002820 return false;
2821 }
2822
2823 if (buffer->isMapped())
2824 {
Jamie Madill437fa652016-05-03 15:13:24 -04002825 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002826 return false;
2827 }
2828
2829 // Check for invalid bit combinations
2830 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2831 {
Jamie Madill437fa652016-05-03 15:13:24 -04002832 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002833 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2834 return false;
2835 }
2836
2837 GLbitfield writeOnlyBits =
2838 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2839
2840 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2841 {
Jamie Madill437fa652016-05-03 15:13:24 -04002842 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002843 "Invalid access bits when mapping buffer for reading: 0x%X.",
2844 access));
2845 return false;
2846 }
2847
2848 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2849 {
Jamie Madill437fa652016-05-03 15:13:24 -04002850 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002851 GL_INVALID_OPERATION,
2852 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2853 return false;
2854 }
2855 return true;
2856}
2857
2858bool ValidateFlushMappedBufferRangeBase(Context *context,
2859 GLenum target,
2860 GLintptr offset,
2861 GLsizeiptr length)
2862{
2863 if (offset < 0 || length < 0)
2864 {
Jamie Madill437fa652016-05-03 15:13:24 -04002865 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002866 return false;
2867 }
2868
2869 if (!ValidBufferTarget(context, target))
2870 {
Jamie Madill437fa652016-05-03 15:13:24 -04002871 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002872 return false;
2873 }
2874
2875 Buffer *buffer = context->getState().getTargetBuffer(target);
2876
2877 if (buffer == nullptr)
2878 {
Jamie Madill437fa652016-05-03 15:13:24 -04002879 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002880 return false;
2881 }
2882
2883 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2884 {
Jamie Madill437fa652016-05-03 15:13:24 -04002885 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002886 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2887 return false;
2888 }
2889
2890 // Check for buffer overflow
2891 size_t offsetSize = static_cast<size_t>(offset);
2892 size_t lengthSize = static_cast<size_t>(length);
2893
2894 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2895 offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
2896 {
Jamie Madill437fa652016-05-03 15:13:24 -04002897 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002898 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2899 return false;
2900 }
2901
2902 return true;
2903}
2904
Olli Etuaho41997e72016-03-10 13:38:39 +02002905bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2906{
2907 return ValidateGenOrDelete(context, n);
2908}
2909
2910bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2911{
2912 return ValidateGenOrDelete(context, n);
2913}
2914
2915bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2916{
2917 return ValidateGenOrDelete(context, n);
2918}
2919
2920bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2921{
2922 return ValidateGenOrDelete(context, n);
2923}
2924
2925bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2926{
2927 return ValidateGenOrDelete(context, n);
2928}
2929
2930bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2931{
2932 return ValidateGenOrDelete(context, n);
2933}
2934
2935bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2936{
2937 return ValidateGenOrDelete(context, n);
2938}
2939
2940bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2941{
2942 return ValidateGenOrDelete(context, n);
2943}
2944
2945bool ValidateGenOrDelete(Context *context, GLint n)
2946{
2947 if (n < 0)
2948 {
Jamie Madill437fa652016-05-03 15:13:24 -04002949 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02002950 return false;
2951 }
2952 return true;
2953}
2954
Jamie Madillc29968b2016-01-20 11:17:23 -05002955} // namespace gl