blob: 30c7b547440b45d9fe0caf45ec815dd6cc2c3827 [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:
Geoff Langb66a9092016-05-16 15:59:14 -0400860 if (context->getClientVersion() < 3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400861 {
Jamie Madill437fa652016-05-03 15:13:24 -0400862 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400863 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400864 }
Geoff Langb66a9092016-05-16 15:59:14 -0400865 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
866 {
867 context->handleError(Error(GL_INVALID_ENUM,
868 "ES3 texture parameters are not available without "
869 "GL_OES_EGL_image_external_essl3."));
870 return false;
871 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400872 break;
873
874 default: break;
875 }
876
877 switch (pname)
878 {
879 case GL_TEXTURE_WRAP_S:
880 case GL_TEXTURE_WRAP_T:
881 case GL_TEXTURE_WRAP_R:
882 switch (param)
883 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000884 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400885 return true;
886 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400887 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300888 if (target == GL_TEXTURE_EXTERNAL_OES)
889 {
890 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400891 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300892 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
893 return false;
894 }
895 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400896 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400897 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400898 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400899 }
900
901 case GL_TEXTURE_MIN_FILTER:
902 switch (param)
903 {
904 case GL_NEAREST:
905 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400906 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400907 case GL_NEAREST_MIPMAP_NEAREST:
908 case GL_LINEAR_MIPMAP_NEAREST:
909 case GL_NEAREST_MIPMAP_LINEAR:
910 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300911 if (target == GL_TEXTURE_EXTERNAL_OES)
912 {
913 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400914 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300915 Error(GL_INVALID_ENUM,
916 "external textures only support NEAREST and LINEAR filtering"));
917 return false;
918 }
919 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400920 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400921 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400922 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400923 }
924 break;
925
926 case GL_TEXTURE_MAG_FILTER:
927 switch (param)
928 {
929 case GL_NEAREST:
930 case GL_LINEAR:
931 return true;
932 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400933 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400934 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400935 }
936 break;
937
938 case GL_TEXTURE_USAGE_ANGLE:
939 switch (param)
940 {
941 case GL_NONE:
942 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
943 return true;
944 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400945 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400946 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400947 }
948 break;
949
950 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400951 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400952 {
Jamie Madill437fa652016-05-03 15:13:24 -0400953 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400954 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400955 }
956
957 // we assume the parameter passed to this validation method is truncated, not rounded
958 if (param < 1)
959 {
Jamie Madill437fa652016-05-03 15:13:24 -0400960 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400961 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400962 }
963 return true;
964
965 case GL_TEXTURE_MIN_LOD:
966 case GL_TEXTURE_MAX_LOD:
967 // any value is permissible
968 return true;
969
970 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400971 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400972 switch (param)
973 {
974 case GL_NONE:
975 case GL_COMPARE_REF_TO_TEXTURE:
976 return true;
977 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400978 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400979 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400980 }
981 break;
982
983 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400984 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400985 switch (param)
986 {
987 case GL_LEQUAL:
988 case GL_GEQUAL:
989 case GL_LESS:
990 case GL_GREATER:
991 case GL_EQUAL:
992 case GL_NOTEQUAL:
993 case GL_ALWAYS:
994 case GL_NEVER:
995 return true;
996 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400997 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400998 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400999 }
1000 break;
1001
1002 case GL_TEXTURE_SWIZZLE_R:
1003 case GL_TEXTURE_SWIZZLE_G:
1004 case GL_TEXTURE_SWIZZLE_B:
1005 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001006 switch (param)
1007 {
1008 case GL_RED:
1009 case GL_GREEN:
1010 case GL_BLUE:
1011 case GL_ALPHA:
1012 case GL_ZERO:
1013 case GL_ONE:
1014 return true;
1015 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001016 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001017 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001018 }
1019 break;
1020
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001021 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001022 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001023 {
Geoff Langb66a9092016-05-16 15:59:14 -04001024 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001025 return false;
1026 }
Geoff Langb66a9092016-05-16 15:59:14 -04001027 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1028 {
1029 context->handleError(
1030 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1031 return false;
1032 }
1033 return true;
1034
1035 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001036 if (param < 0)
1037 {
1038 context->handleError(Error(GL_INVALID_VALUE));
1039 return false;
1040 }
1041 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001042 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001043 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001044 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001045 }
1046}
1047
Geoff Langb1196682014-07-23 13:47:29 -04001048bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001049{
1050 switch (pname)
1051 {
1052 case GL_TEXTURE_MIN_FILTER:
1053 case GL_TEXTURE_MAG_FILTER:
1054 case GL_TEXTURE_WRAP_S:
1055 case GL_TEXTURE_WRAP_T:
1056 case GL_TEXTURE_WRAP_R:
1057 case GL_TEXTURE_MIN_LOD:
1058 case GL_TEXTURE_MAX_LOD:
1059 case GL_TEXTURE_COMPARE_MODE:
1060 case GL_TEXTURE_COMPARE_FUNC:
1061 return true;
1062
1063 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001064 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001065 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001066 }
1067}
1068
Jamie Madillc29968b2016-01-20 11:17:23 -05001069bool ValidateReadPixels(Context *context,
1070 GLint x,
1071 GLint y,
1072 GLsizei width,
1073 GLsizei height,
1074 GLenum format,
1075 GLenum type,
1076 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001077{
Jamie Madillc29968b2016-01-20 11:17:23 -05001078 if (width < 0 || height < 0)
1079 {
Jamie Madill437fa652016-05-03 15:13:24 -04001080 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001081 return false;
1082 }
1083
1084 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001085 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001086
Geoff Lang748f74e2014-12-01 11:25:34 -05001087 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001088 {
Jamie Madill437fa652016-05-03 15:13:24 -04001089 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001090 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001091 }
1092
Jamie Madill48faf802014-11-06 15:27:22 -05001093 if (context->getState().getReadFramebuffer()->id() != 0 &&
1094 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001095 {
Jamie Madill437fa652016-05-03 15:13:24 -04001096 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001097 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001098 }
1099
Geoff Langbce529e2014-12-01 12:48:41 -05001100 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1101 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001102 {
Jamie Madill437fa652016-05-03 15:13:24 -04001103 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001104 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001105 }
1106
Geoff Langbce529e2014-12-01 12:48:41 -05001107 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1108 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001109 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001110 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001111
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001112 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1113 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001114
1115 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1116 {
Jamie Madill437fa652016-05-03 15:13:24 -04001117 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001118 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001119 }
1120
Jamie Madillc29968b2016-01-20 11:17:23 -05001121 return true;
1122}
1123
1124bool ValidateReadnPixelsEXT(Context *context,
1125 GLint x,
1126 GLint y,
1127 GLsizei width,
1128 GLsizei height,
1129 GLenum format,
1130 GLenum type,
1131 GLsizei bufSize,
1132 GLvoid *pixels)
1133{
1134 if (bufSize < 0)
1135 {
Jamie Madill437fa652016-05-03 15:13:24 -04001136 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001137 return false;
1138 }
1139
Geoff Lang5d601382014-07-22 15:14:06 -04001140 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1141 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001142
Minmin Gongadff67b2015-10-14 10:34:45 -04001143 GLsizei outputPitch =
1144 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1145 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001146 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001147 int requiredSize = outputPitch * height;
1148 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001149 {
Jamie Madill437fa652016-05-03 15:13:24 -04001150 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001151 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001152 }
1153
Jamie Madillc29968b2016-01-20 11:17:23 -05001154 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001155}
1156
Olli Etuaho41997e72016-03-10 13:38:39 +02001157bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001158{
1159 if (!context->getExtensions().occlusionQueryBoolean &&
1160 !context->getExtensions().disjointTimerQuery)
1161 {
Jamie Madill437fa652016-05-03 15:13:24 -04001162 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001163 return false;
1164 }
1165
Olli Etuaho41997e72016-03-10 13:38:39 +02001166 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001167}
1168
Olli Etuaho41997e72016-03-10 13:38:39 +02001169bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001170{
1171 if (!context->getExtensions().occlusionQueryBoolean &&
1172 !context->getExtensions().disjointTimerQuery)
1173 {
Jamie Madill437fa652016-05-03 15:13:24 -04001174 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001175 return false;
1176 }
1177
Olli Etuaho41997e72016-03-10 13:38:39 +02001178 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001179}
1180
1181bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001182{
1183 if (!ValidQueryType(context, target))
1184 {
Jamie Madill437fa652016-05-03 15:13:24 -04001185 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001186 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001187 }
1188
1189 if (id == 0)
1190 {
Jamie Madill437fa652016-05-03 15:13:24 -04001191 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001192 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001193 }
1194
1195 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1196 // of zero, if the active query object name for <target> is non-zero (for the
1197 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1198 // the active query for either target is non-zero), if <id> is the name of an
1199 // existing query object whose type does not match <target>, or if <id> is the
1200 // active query object name for any query type, the error INVALID_OPERATION is
1201 // generated.
1202
1203 // Ensure no other queries are active
1204 // NOTE: If other queries than occlusion are supported, we will need to check
1205 // separately that:
1206 // a) The query ID passed is not the current active query for any target/type
1207 // b) There are no active queries for the requested target (and in the case
1208 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1209 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001210
Corentin Walleze71ea192016-04-19 13:16:37 -04001211 if (context->getState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001212 {
Jamie Madill437fa652016-05-03 15:13:24 -04001213 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001214 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001215 }
1216
1217 Query *queryObject = context->getQuery(id, true, target);
1218
1219 // check that name was obtained with glGenQueries
1220 if (!queryObject)
1221 {
Jamie Madill437fa652016-05-03 15:13:24 -04001222 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001223 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001224 }
1225
1226 // check for type mismatch
1227 if (queryObject->getType() != target)
1228 {
Jamie Madill437fa652016-05-03 15:13:24 -04001229 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001230 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001231 }
1232
1233 return true;
1234}
1235
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001236bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1237{
1238 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001239 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001240 {
Jamie Madill437fa652016-05-03 15:13:24 -04001241 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001242 return false;
1243 }
1244
1245 return ValidateBeginQueryBase(context, target, id);
1246}
1247
1248bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001249{
1250 if (!ValidQueryType(context, target))
1251 {
Jamie Madill437fa652016-05-03 15:13:24 -04001252 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001253 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001254 }
1255
Shannon Woods53a94a82014-06-24 15:20:36 -04001256 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001257
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001258 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001259 {
Jamie Madill437fa652016-05-03 15:13:24 -04001260 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001261 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001262 }
1263
Jamie Madill45c785d2014-05-13 14:09:34 -04001264 return true;
1265}
1266
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001267bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1268{
1269 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001270 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001271 {
Jamie Madill437fa652016-05-03 15:13:24 -04001272 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001273 return false;
1274 }
1275
1276 return ValidateEndQueryBase(context, target);
1277}
1278
1279bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1280{
1281 if (!context->getExtensions().disjointTimerQuery)
1282 {
Jamie Madill437fa652016-05-03 15:13:24 -04001283 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001284 return false;
1285 }
1286
1287 if (target != GL_TIMESTAMP_EXT)
1288 {
Jamie Madill437fa652016-05-03 15:13:24 -04001289 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001290 return false;
1291 }
1292
1293 Query *queryObject = context->getQuery(id, true, target);
1294 if (queryObject == nullptr)
1295 {
Jamie Madill437fa652016-05-03 15:13:24 -04001296 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001297 return false;
1298 }
1299
1300 if (context->getState().isQueryActive(queryObject))
1301 {
Jamie Madill437fa652016-05-03 15:13:24 -04001302 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001303 return false;
1304 }
1305
1306 return true;
1307}
1308
1309bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1310{
1311 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1312 {
Jamie Madill437fa652016-05-03 15:13:24 -04001313 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001314 return false;
1315 }
1316
1317 switch (pname)
1318 {
1319 case GL_CURRENT_QUERY_EXT:
1320 if (target == GL_TIMESTAMP_EXT)
1321 {
Jamie Madill437fa652016-05-03 15:13:24 -04001322 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001323 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1324 return false;
1325 }
1326 break;
1327 case GL_QUERY_COUNTER_BITS_EXT:
1328 if (!context->getExtensions().disjointTimerQuery ||
1329 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1330 {
Jamie Madill437fa652016-05-03 15:13:24 -04001331 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001332 return false;
1333 }
1334 break;
1335 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001336 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001337 return false;
1338 }
1339
1340 return true;
1341}
1342
1343bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1344{
1345 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001346 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001347 {
Jamie Madill437fa652016-05-03 15:13:24 -04001348 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001349 return false;
1350 }
1351
1352 return ValidateGetQueryivBase(context, target, pname);
1353}
1354
1355bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1356{
1357 Query *queryObject = context->getQuery(id, false, GL_NONE);
1358
1359 if (!queryObject)
1360 {
Jamie Madill437fa652016-05-03 15:13:24 -04001361 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001362 return false;
1363 }
1364
1365 if (context->getState().isQueryActive(queryObject))
1366 {
Jamie Madill437fa652016-05-03 15:13:24 -04001367 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001368 return false;
1369 }
1370
1371 switch (pname)
1372 {
1373 case GL_QUERY_RESULT_EXT:
1374 case GL_QUERY_RESULT_AVAILABLE_EXT:
1375 break;
1376
1377 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001378 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001379 return false;
1380 }
1381
1382 return true;
1383}
1384
1385bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1386{
1387 if (!context->getExtensions().disjointTimerQuery)
1388 {
Jamie Madill437fa652016-05-03 15:13:24 -04001389 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001390 return false;
1391 }
1392 return ValidateGetQueryObjectValueBase(context, id, pname);
1393}
1394
1395bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1396{
1397 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001398 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001399 {
Jamie Madill437fa652016-05-03 15:13:24 -04001400 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001401 return false;
1402 }
1403 return ValidateGetQueryObjectValueBase(context, id, pname);
1404}
1405
1406bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1407{
1408 if (!context->getExtensions().disjointTimerQuery)
1409 {
Jamie Madill437fa652016-05-03 15:13:24 -04001410 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001411 return false;
1412 }
1413 return ValidateGetQueryObjectValueBase(context, id, pname);
1414}
1415
1416bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1417{
1418 if (!context->getExtensions().disjointTimerQuery)
1419 {
Jamie Madill437fa652016-05-03 15:13:24 -04001420 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001421 return false;
1422 }
1423 return ValidateGetQueryObjectValueBase(context, id, pname);
1424}
1425
Jamie Madill62d31cb2015-09-11 13:25:51 -04001426static bool ValidateUniformCommonBase(gl::Context *context,
1427 GLenum targetUniformType,
1428 GLint location,
1429 GLsizei count,
1430 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001431{
1432 if (count < 0)
1433 {
Jamie Madill437fa652016-05-03 15:13:24 -04001434 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001435 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001436 }
1437
Geoff Lang7dd2e102014-11-10 15:19:26 -05001438 gl::Program *program = context->getState().getProgram();
1439 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001440 {
Jamie Madill437fa652016-05-03 15:13:24 -04001441 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001442 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001443 }
1444
Geoff Langd8605522016-04-13 10:19:12 -04001445 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001446 {
1447 // Silently ignore the uniform command
1448 return false;
1449 }
1450
Geoff Lang7dd2e102014-11-10 15:19:26 -05001451 if (!program->isValidUniformLocation(location))
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 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001458
1459 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001460 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001461 {
Jamie Madill437fa652016-05-03 15:13:24 -04001462 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001463 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001464 }
1465
Jamie Madill62d31cb2015-09-11 13:25:51 -04001466 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001467 return true;
1468}
1469
Jamie Madillaa981bd2014-05-20 10:55:55 -04001470bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1471{
1472 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001473 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001474 {
Jamie Madill437fa652016-05-03 15:13:24 -04001475 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001476 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001477 }
1478
Jamie Madill62d31cb2015-09-11 13:25:51 -04001479 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001480 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1481 {
1482 return false;
1483 }
1484
Jamie Madillf2575982014-06-25 16:04:54 -04001485 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001486 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001487 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1488 {
Jamie Madill437fa652016-05-03 15:13:24 -04001489 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001490 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001491 }
1492
1493 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001494}
1495
1496bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1497 GLboolean transpose)
1498{
1499 // Check for ES3 uniform entry points
1500 int rows = VariableRowCount(matrixType);
1501 int cols = VariableColumnCount(matrixType);
1502 if (rows != cols && context->getClientVersion() < 3)
1503 {
Jamie Madill437fa652016-05-03 15:13:24 -04001504 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001505 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001506 }
1507
1508 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1509 {
Jamie Madill437fa652016-05-03 15:13:24 -04001510 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001511 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001512 }
1513
Jamie Madill62d31cb2015-09-11 13:25:51 -04001514 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001515 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1516 {
1517 return false;
1518 }
1519
1520 if (uniform->type != matrixType)
1521 {
Jamie Madill437fa652016-05-03 15:13:24 -04001522 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001523 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001524 }
1525
1526 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001527}
1528
Jamie Madill893ab082014-05-16 16:56:10 -04001529bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1530{
1531 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1532 {
Jamie Madill437fa652016-05-03 15:13:24 -04001533 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001534 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001535 }
1536
Jamie Madill0af26e12015-03-05 19:54:33 -05001537 const Caps &caps = context->getCaps();
1538
Jamie Madill893ab082014-05-16 16:56:10 -04001539 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1540 {
1541 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1542
Jamie Madill0af26e12015-03-05 19:54:33 -05001543 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001544 {
Jamie Madill437fa652016-05-03 15:13:24 -04001545 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001546 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001547 }
1548 }
1549
1550 switch (pname)
1551 {
1552 case GL_TEXTURE_BINDING_2D:
1553 case GL_TEXTURE_BINDING_CUBE_MAP:
1554 case GL_TEXTURE_BINDING_3D:
1555 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001556 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001557 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1558 if (!context->getExtensions().eglStreamConsumerExternal)
1559 {
Jamie Madill437fa652016-05-03 15:13:24 -04001560 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001561 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1562 return false;
1563 }
1564 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001565
1566 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1567 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1568 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001569 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001570 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001571 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001572 {
Jamie Madill437fa652016-05-03 15:13:24 -04001573 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001574 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001575 }
1576
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001577 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001578 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001579 {
Jamie Madill437fa652016-05-03 15:13:24 -04001580 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001581 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001582 }
1583 }
1584 break;
1585
1586 default:
1587 break;
1588 }
1589
1590 // pname is valid, but there are no parameters to return
1591 if (numParams == 0)
1592 {
1593 return false;
1594 }
1595
1596 return true;
1597}
1598
Jamie Madillc29968b2016-01-20 11:17:23 -05001599bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1600 GLenum target,
1601 GLint level,
1602 GLenum internalformat,
1603 bool isSubImage,
1604 GLint xoffset,
1605 GLint yoffset,
1606 GLint zoffset,
1607 GLint x,
1608 GLint y,
1609 GLsizei width,
1610 GLsizei height,
1611 GLint border,
1612 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001613{
Jamie Madill560a8d82014-05-21 13:06:20 -04001614 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1615 {
Jamie Madill437fa652016-05-03 15:13:24 -04001616 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001617 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001618 }
1619
1620 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1621 {
Jamie Madill437fa652016-05-03 15:13:24 -04001622 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001623 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001624 }
1625
1626 if (border != 0)
1627 {
Jamie Madill437fa652016-05-03 15:13:24 -04001628 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001629 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001630 }
1631
1632 if (!ValidMipLevel(context, target, level))
1633 {
Jamie Madill437fa652016-05-03 15:13:24 -04001634 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001635 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001636 }
1637
Jamie Madillc29968b2016-01-20 11:17:23 -05001638 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001639 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001640 {
Jamie Madill437fa652016-05-03 15:13:24 -04001641 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001642 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001643 }
1644
Jamie Madillc29968b2016-01-20 11:17:23 -05001645 const auto &state = context->getState();
1646 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001647 {
Jamie Madill437fa652016-05-03 15:13:24 -04001648 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001649 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001650 }
1651
Geoff Langaae65a42014-05-26 12:43:44 -04001652 const gl::Caps &caps = context->getCaps();
1653
Geoff Langaae65a42014-05-26 12:43:44 -04001654 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001655 switch (target)
1656 {
1657 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001658 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001659 break;
1660
1661 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1662 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1663 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1664 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1665 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1666 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001667 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001668 break;
1669
1670 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001671 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001672 break;
1673
1674 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001675 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001676 break;
1677
1678 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001679 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001680 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001681 }
1682
Jamie Madillc29968b2016-01-20 11:17:23 -05001683 gl::Texture *texture =
1684 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001685 if (!texture)
1686 {
Jamie Madill437fa652016-05-03 15:13:24 -04001687 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001688 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001689 }
1690
Geoff Lang69cce582015-09-17 13:20:36 -04001691 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001692 {
Jamie Madill437fa652016-05-03 15:13:24 -04001693 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001694 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001695 }
1696
Geoff Lang5d601382014-07-22 15:14:06 -04001697 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1698
1699 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001700 {
Jamie Madill437fa652016-05-03 15:13:24 -04001701 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001702 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001703 }
1704
Geoff Langa9be0dc2014-12-17 12:34:40 -05001705 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001706 {
Jamie Madill437fa652016-05-03 15:13:24 -04001707 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001708 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001709 }
1710
1711 if (isSubImage)
1712 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001713 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1714 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1715 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001716 {
Jamie Madill437fa652016-05-03 15:13:24 -04001717 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001718 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001719 }
1720 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001721 else
1722 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001723 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001724 {
Jamie Madill437fa652016-05-03 15:13:24 -04001725 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001726 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001727 }
1728
Geoff Lang5d601382014-07-22 15:14:06 -04001729 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001730 {
Jamie Madill437fa652016-05-03 15:13:24 -04001731 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001732 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001733 }
1734
1735 int maxLevelDimension = (maxDimension >> level);
1736 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1737 {
Jamie Madill437fa652016-05-03 15:13:24 -04001738 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001739 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001740 }
1741 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001742
Geoff Langa9be0dc2014-12-17 12:34:40 -05001743 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001744 return true;
1745}
1746
Jamie Madillf25855c2015-11-03 11:06:18 -05001747static bool ValidateDrawBase(ValidationContext *context,
1748 GLenum mode,
1749 GLsizei count,
1750 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001751{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001752 switch (mode)
1753 {
1754 case GL_POINTS:
1755 case GL_LINES:
1756 case GL_LINE_LOOP:
1757 case GL_LINE_STRIP:
1758 case GL_TRIANGLES:
1759 case GL_TRIANGLE_STRIP:
1760 case GL_TRIANGLE_FAN:
1761 break;
1762 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001763 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001764 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001765 }
1766
Jamie Madill250d33f2014-06-06 17:09:03 -04001767 if (count < 0)
1768 {
Jamie Madill437fa652016-05-03 15:13:24 -04001769 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001770 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001771 }
1772
Geoff Langb1196682014-07-23 13:47:29 -04001773 const State &state = context->getState();
1774
Jamie Madill250d33f2014-06-06 17:09:03 -04001775 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001776 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001777 {
Jamie Madill437fa652016-05-03 15:13:24 -04001778 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001779 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001780 }
1781
Geoff Lang3a86ad32015-09-01 11:47:05 -04001782 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001783 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001784 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1785 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1786 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1787 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1788 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1789 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1790 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001791 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001792 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1793 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001794 {
1795 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1796 // Section 6.10 of the WebGL 1.0 spec
1797 ERR(
1798 "This ANGLE implementation does not support separate front/back stencil "
1799 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001800 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001801 return false;
1802 }
Jamie Madillac528012014-06-20 13:21:23 -04001803 }
1804
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001805 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001806 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001807 {
Jamie Madill437fa652016-05-03 15:13:24 -04001808 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001809 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001810 }
1811
Geoff Lang7dd2e102014-11-10 15:19:26 -05001812 gl::Program *program = state.getProgram();
1813 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001814 {
Jamie Madill437fa652016-05-03 15:13:24 -04001815 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001816 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001817 }
1818
Geoff Lang7dd2e102014-11-10 15:19:26 -05001819 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001820 {
Jamie Madill437fa652016-05-03 15:13:24 -04001821 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001822 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001823 }
1824
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001825 // Uniform buffer validation
1826 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1827 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001828 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001829 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001830 const OffsetBindingPointer<Buffer> &uniformBuffer =
1831 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001832
Geoff Lang5d124a62015-09-15 13:03:27 -04001833 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001834 {
1835 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001836 context->handleError(
1837 Error(GL_INVALID_OPERATION,
1838 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001839 return false;
1840 }
1841
Geoff Lang5d124a62015-09-15 13:03:27 -04001842 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001843 if (uniformBufferSize == 0)
1844 {
1845 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001846 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001847 }
1848
Jamie Madill62d31cb2015-09-11 13:25:51 -04001849 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001850 {
1851 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001852 context->handleError(
1853 Error(GL_INVALID_OPERATION,
1854 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001855 return false;
1856 }
1857 }
1858
Jamie Madill250d33f2014-06-06 17:09:03 -04001859 // No-op if zero count
1860 return (count > 0);
1861}
1862
Geoff Langb1196682014-07-23 13:47:29 -04001863bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001864{
Jamie Madillfd716582014-06-06 17:09:04 -04001865 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001866 {
Jamie Madill437fa652016-05-03 15:13:24 -04001867 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001868 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001869 }
1870
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001871 const State &state = context->getState();
1872 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001873 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1874 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001875 {
1876 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1877 // that does not match the current transform feedback object's draw mode (if transform feedback
1878 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001879 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001880 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001881 }
1882
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001883 if (!ValidateDrawBase(context, mode, count, primcount))
1884 {
1885 return false;
1886 }
1887
1888 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001889 {
1890 return false;
1891 }
1892
1893 return true;
1894}
1895
Geoff Langb1196682014-07-23 13:47:29 -04001896bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001897{
1898 if (primcount < 0)
1899 {
Jamie Madill437fa652016-05-03 15:13:24 -04001900 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001901 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001902 }
1903
Jamie Madill2b976812014-08-25 15:47:49 -04001904 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001905 {
1906 return false;
1907 }
1908
1909 // No-op if zero primitive count
1910 return (primcount > 0);
1911}
1912
Geoff Lang87a93302014-09-16 13:29:43 -04001913static bool ValidateDrawInstancedANGLE(Context *context)
1914{
1915 // Verify there is at least one active attribute with a divisor of zero
1916 const gl::State& state = context->getState();
1917
Geoff Lang7dd2e102014-11-10 15:19:26 -05001918 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001919
1920 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001921 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001922 {
1923 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001924 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001925 {
1926 return true;
1927 }
1928 }
1929
Jamie Madill437fa652016-05-03 15:13:24 -04001930 context->handleError(Error(GL_INVALID_OPERATION,
1931 "ANGLE_instanced_arrays requires that at least one active attribute"
1932 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001933 return false;
1934}
1935
1936bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1937{
1938 if (!ValidateDrawInstancedANGLE(context))
1939 {
1940 return false;
1941 }
1942
1943 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1944}
1945
Jamie Madillf25855c2015-11-03 11:06:18 -05001946bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001947 GLenum mode,
1948 GLsizei count,
1949 GLenum type,
1950 const GLvoid *indices,
1951 GLsizei primcount,
1952 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001953{
Jamie Madill250d33f2014-06-06 17:09:03 -04001954 switch (type)
1955 {
1956 case GL_UNSIGNED_BYTE:
1957 case GL_UNSIGNED_SHORT:
1958 break;
1959 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001960 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001961 {
Jamie Madill437fa652016-05-03 15:13:24 -04001962 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001963 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001964 }
1965 break;
1966 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001967 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001968 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001969 }
1970
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001971 const State &state = context->getState();
1972
1973 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001974 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001975 {
1976 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1977 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001978 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001979 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001980 }
1981
1982 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001983 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001984 {
Jamie Madill437fa652016-05-03 15:13:24 -04001985 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001986 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001987 }
1988
Jamie Madill2b976812014-08-25 15:47:49 -04001989 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001990 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001991 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001992 {
Jamie Madill437fa652016-05-03 15:13:24 -04001993 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001994 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001995 }
1996
Jamie Madillae3000b2014-08-25 15:47:51 -04001997 if (elementArrayBuffer)
1998 {
1999 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2000
2001 GLint64 offset = reinterpret_cast<GLint64>(indices);
2002 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2003
2004 // check for integer overflows
2005 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2006 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2007 {
Jamie Madill437fa652016-05-03 15:13:24 -04002008 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002009 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002010 }
2011
2012 // Check for reading past the end of the bound buffer object
2013 if (byteCount > elementArrayBuffer->getSize())
2014 {
Jamie Madill437fa652016-05-03 15:13:24 -04002015 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002016 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002017 }
2018 }
2019 else if (!indices)
2020 {
2021 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002022 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002023 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002024 }
2025
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002026 if (!ValidateDrawBase(context, mode, count, primcount))
2027 {
2028 return false;
2029 }
2030
Jamie Madill2b976812014-08-25 15:47:49 -04002031 // Use max index to validate if our vertex buffers are large enough for the pull.
2032 // TODO: offer fast path, with disabled index validation.
2033 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2034 if (elementArrayBuffer)
2035 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002036 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002037 Error error =
2038 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2039 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002040 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002041 {
Jamie Madill437fa652016-05-03 15:13:24 -04002042 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002043 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002044 }
2045 }
2046 else
2047 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002048 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002049 }
2050
Jamie Madille79b1e12015-11-04 16:36:37 -05002051 // If we use an index greater than our maximum supported index range, return an error.
2052 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2053 // return an error if possible here.
2054 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2055 {
Jamie Madill437fa652016-05-03 15:13:24 -04002056 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002057 return false;
2058 }
2059
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002060 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002061 {
2062 return false;
2063 }
2064
Geoff Lang3edfe032015-09-04 16:38:24 -04002065 // No op if there are no real indices in the index data (all are primitive restart).
2066 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002067}
2068
Geoff Langb1196682014-07-23 13:47:29 -04002069bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002070 GLenum mode,
2071 GLsizei count,
2072 GLenum type,
2073 const GLvoid *indices,
2074 GLsizei primcount,
2075 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002076{
2077 if (primcount < 0)
2078 {
Jamie Madill437fa652016-05-03 15:13:24 -04002079 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002080 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002081 }
2082
Jamie Madill2b976812014-08-25 15:47:49 -04002083 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002084 {
2085 return false;
2086 }
2087
2088 // No-op zero primitive count
2089 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002090}
2091
Geoff Lang3edfe032015-09-04 16:38:24 -04002092bool ValidateDrawElementsInstancedANGLE(Context *context,
2093 GLenum mode,
2094 GLsizei count,
2095 GLenum type,
2096 const GLvoid *indices,
2097 GLsizei primcount,
2098 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002099{
2100 if (!ValidateDrawInstancedANGLE(context))
2101 {
2102 return false;
2103 }
2104
2105 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2106}
2107
Geoff Langb1196682014-07-23 13:47:29 -04002108bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002109 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002110{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002111 if (!ValidFramebufferTarget(target))
2112 {
Jamie Madill437fa652016-05-03 15:13:24 -04002113 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002114 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002115 }
2116
2117 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002118 {
2119 return false;
2120 }
2121
Jamie Madill55ec3b12014-07-03 10:38:57 -04002122 if (texture != 0)
2123 {
2124 gl::Texture *tex = context->getTexture(texture);
2125
2126 if (tex == NULL)
2127 {
Jamie Madill437fa652016-05-03 15:13:24 -04002128 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002129 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002130 }
2131
2132 if (level < 0)
2133 {
Jamie Madill437fa652016-05-03 15:13:24 -04002134 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002135 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002136 }
2137 }
2138
Shannon Woods53a94a82014-06-24 15:20:36 -04002139 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002140 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002141
Jamie Madill84115c92015-04-23 15:00:07 -04002142 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002143 {
Jamie Madill437fa652016-05-03 15:13:24 -04002144 context->handleError(
2145 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002146 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002147 }
2148
2149 return true;
2150}
2151
Geoff Langb1196682014-07-23 13:47:29 -04002152bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002153 GLenum textarget, GLuint texture, GLint level)
2154{
Geoff Lang95663912015-04-02 15:54:45 -04002155 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2156 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002157 {
Jamie Madill437fa652016-05-03 15:13:24 -04002158 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002159 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002160 }
2161
2162 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002163 {
2164 return false;
2165 }
2166
Jamie Madill55ec3b12014-07-03 10:38:57 -04002167 if (texture != 0)
2168 {
2169 gl::Texture *tex = context->getTexture(texture);
2170 ASSERT(tex);
2171
Jamie Madill2a6564e2014-07-11 09:53:19 -04002172 const gl::Caps &caps = context->getCaps();
2173
Jamie Madill55ec3b12014-07-03 10:38:57 -04002174 switch (textarget)
2175 {
2176 case GL_TEXTURE_2D:
2177 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002178 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002179 {
Jamie Madill437fa652016-05-03 15:13:24 -04002180 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002181 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002182 }
2183 if (tex->getTarget() != GL_TEXTURE_2D)
2184 {
Jamie Madill437fa652016-05-03 15:13:24 -04002185 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002186 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002187 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002188 }
2189 break;
2190
2191 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2192 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2193 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2194 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2195 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2196 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2197 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002198 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002199 {
Jamie Madill437fa652016-05-03 15:13:24 -04002200 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002201 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002202 }
2203 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2204 {
Jamie Madill437fa652016-05-03 15:13:24 -04002205 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002206 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002207 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002208 }
2209 break;
2210
2211 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002212 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002213 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002214 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002215
2216 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2217 if (internalFormatInfo.compressed)
2218 {
Jamie Madill437fa652016-05-03 15:13:24 -04002219 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002220 return false;
2221 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002222 }
2223
Jamie Madill570f7c82014-07-03 10:38:54 -04002224 return true;
2225}
2226
Geoff Langb1196682014-07-23 13:47:29 -04002227bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002228{
2229 if (program == 0)
2230 {
Jamie Madill437fa652016-05-03 15:13:24 -04002231 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002232 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002233 }
2234
Dian Xiang769769a2015-09-09 15:20:08 -07002235 gl::Program *programObject = GetValidProgram(context, program);
2236 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002237 {
2238 return false;
2239 }
2240
Jamie Madill0063c512014-08-25 15:47:53 -04002241 if (!programObject || !programObject->isLinked())
2242 {
Jamie Madill437fa652016-05-03 15:13:24 -04002243 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002244 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002245 }
2246
Geoff Lang7dd2e102014-11-10 15:19:26 -05002247 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002248 {
Jamie Madill437fa652016-05-03 15:13:24 -04002249 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002250 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002251 }
2252
Jamie Madill0063c512014-08-25 15:47:53 -04002253 return true;
2254}
2255
Geoff Langb1196682014-07-23 13:47:29 -04002256bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002257{
2258 return ValidateGetUniformBase(context, program, location);
2259}
2260
Geoff Langb1196682014-07-23 13:47:29 -04002261bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002262{
Jamie Madill78f41802014-08-25 15:47:55 -04002263 return ValidateGetUniformBase(context, program, location);
2264}
2265
Geoff Langb1196682014-07-23 13:47:29 -04002266static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002267{
2268 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002269 {
Jamie Madill78f41802014-08-25 15:47:55 -04002270 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002271 }
2272
Jamie Madilla502c742014-08-28 17:19:13 -04002273 gl::Program *programObject = context->getProgram(program);
2274 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002275
Jamie Madill78f41802014-08-25 15:47:55 -04002276 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002277 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2278 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002279 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002280 {
Jamie Madill437fa652016-05-03 15:13:24 -04002281 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002282 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002283 }
2284
2285 return true;
2286}
2287
Geoff Langb1196682014-07-23 13:47:29 -04002288bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002289{
Jamie Madill78f41802014-08-25 15:47:55 -04002290 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002291}
2292
Geoff Langb1196682014-07-23 13:47:29 -04002293bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002294{
Jamie Madill78f41802014-08-25 15:47:55 -04002295 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002296}
2297
Austin Kinross08332632015-05-05 13:35:47 -07002298bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2299 const GLenum *attachments, bool defaultFramebuffer)
2300{
2301 if (numAttachments < 0)
2302 {
Jamie Madill437fa652016-05-03 15:13:24 -04002303 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002304 return false;
2305 }
2306
2307 for (GLsizei i = 0; i < numAttachments; ++i)
2308 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002309 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002310 {
2311 if (defaultFramebuffer)
2312 {
Jamie Madill437fa652016-05-03 15:13:24 -04002313 context->handleError(Error(
2314 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002315 return false;
2316 }
2317
2318 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2319 {
Jamie Madill437fa652016-05-03 15:13:24 -04002320 context->handleError(Error(GL_INVALID_OPERATION,
2321 "Requested color attachment is greater than the maximum "
2322 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002323 return false;
2324 }
2325 }
2326 else
2327 {
2328 switch (attachments[i])
2329 {
2330 case GL_DEPTH_ATTACHMENT:
2331 case GL_STENCIL_ATTACHMENT:
2332 case GL_DEPTH_STENCIL_ATTACHMENT:
2333 if (defaultFramebuffer)
2334 {
Jamie Madill437fa652016-05-03 15:13:24 -04002335 context->handleError(
2336 Error(GL_INVALID_ENUM,
2337 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002338 return false;
2339 }
2340 break;
2341 case GL_COLOR:
2342 case GL_DEPTH:
2343 case GL_STENCIL:
2344 if (!defaultFramebuffer)
2345 {
Jamie Madill437fa652016-05-03 15:13:24 -04002346 context->handleError(
2347 Error(GL_INVALID_ENUM,
2348 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002349 return false;
2350 }
2351 break;
2352 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002353 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002354 return false;
2355 }
2356 }
2357 }
2358
2359 return true;
2360}
2361
Austin Kinross6ee1e782015-05-29 17:05:37 -07002362bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2363{
2364 // Note that debug marker calls must not set error state
2365
2366 if (length < 0)
2367 {
2368 return false;
2369 }
2370
2371 if (marker == nullptr)
2372 {
2373 return false;
2374 }
2375
2376 return true;
2377}
2378
2379bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2380{
2381 // Note that debug marker calls must not set error state
2382
2383 if (length < 0)
2384 {
2385 return false;
2386 }
2387
2388 if (length > 0 && marker == nullptr)
2389 {
2390 return false;
2391 }
2392
2393 return true;
2394}
2395
Geoff Langdcab33b2015-07-21 13:03:16 -04002396bool ValidateEGLImageTargetTexture2DOES(Context *context,
2397 egl::Display *display,
2398 GLenum target,
2399 egl::Image *image)
2400{
Geoff Langa8406172015-07-21 16:53:39 -04002401 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2402 {
Jamie Madill437fa652016-05-03 15:13:24 -04002403 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002404 return false;
2405 }
2406
2407 switch (target)
2408 {
2409 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002410 if (!context->getExtensions().eglImage)
2411 {
2412 context->handleError(Error(
2413 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2414 }
2415 break;
2416
2417 case GL_TEXTURE_EXTERNAL_OES:
2418 if (!context->getExtensions().eglImageExternal)
2419 {
2420 context->handleError(Error(
2421 GL_INVALID_ENUM,
2422 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2423 }
Geoff Langa8406172015-07-21 16:53:39 -04002424 break;
2425
2426 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002427 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002428 return false;
2429 }
2430
2431 if (!display->isValidImage(image))
2432 {
Jamie Madill437fa652016-05-03 15:13:24 -04002433 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002434 return false;
2435 }
2436
2437 if (image->getSamples() > 0)
2438 {
Jamie Madill437fa652016-05-03 15:13:24 -04002439 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002440 "cannot create a 2D texture from a multisampled EGL image."));
2441 return false;
2442 }
2443
2444 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2445 if (!textureCaps.texturable)
2446 {
Jamie Madill437fa652016-05-03 15:13:24 -04002447 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002448 "EGL image internal format is not supported as a texture."));
2449 return false;
2450 }
2451
Geoff Langdcab33b2015-07-21 13:03:16 -04002452 return true;
2453}
2454
2455bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2456 egl::Display *display,
2457 GLenum target,
2458 egl::Image *image)
2459{
Geoff Langa8406172015-07-21 16:53:39 -04002460 if (!context->getExtensions().eglImage)
2461 {
Jamie Madill437fa652016-05-03 15:13:24 -04002462 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002463 return false;
2464 }
2465
2466 switch (target)
2467 {
2468 case GL_RENDERBUFFER:
2469 break;
2470
2471 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002472 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002473 return false;
2474 }
2475
2476 if (!display->isValidImage(image))
2477 {
Jamie Madill437fa652016-05-03 15:13:24 -04002478 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002479 return false;
2480 }
2481
2482 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2483 if (!textureCaps.renderable)
2484 {
Jamie Madill437fa652016-05-03 15:13:24 -04002485 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002486 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2487 return false;
2488 }
2489
Geoff Langdcab33b2015-07-21 13:03:16 -04002490 return true;
2491}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002492
2493bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2494{
Geoff Lang36167ab2015-12-07 10:27:14 -05002495 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002496 {
2497 // The default VAO should always exist
2498 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002499 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002500 return false;
2501 }
2502
2503 return true;
2504}
2505
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002506bool ValidateLinkProgram(Context *context, GLuint program)
2507{
2508 if (context->hasActiveTransformFeedback(program))
2509 {
2510 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002511 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002512 "Cannot link program while program is associated with an active "
2513 "transform feedback object."));
2514 return false;
2515 }
2516 return true;
2517}
2518
Geoff Langc5629752015-12-07 16:29:04 -05002519bool ValidateProgramBinaryBase(Context *context,
2520 GLuint program,
2521 GLenum binaryFormat,
2522 const void *binary,
2523 GLint length)
2524{
2525 Program *programObject = GetValidProgram(context, program);
2526 if (programObject == nullptr)
2527 {
2528 return false;
2529 }
2530
2531 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2532 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2533 programBinaryFormats.end())
2534 {
Jamie Madill437fa652016-05-03 15:13:24 -04002535 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002536 return false;
2537 }
2538
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002539 if (context->hasActiveTransformFeedback(program))
2540 {
2541 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002542 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002543 "Cannot change program binary while program is associated with "
2544 "an active transform feedback object."));
2545 return false;
2546 }
2547
Geoff Langc5629752015-12-07 16:29:04 -05002548 return true;
2549}
2550
2551bool ValidateGetProgramBinaryBase(Context *context,
2552 GLuint program,
2553 GLsizei bufSize,
2554 GLsizei *length,
2555 GLenum *binaryFormat,
2556 void *binary)
2557{
2558 Program *programObject = GetValidProgram(context, program);
2559 if (programObject == nullptr)
2560 {
2561 return false;
2562 }
2563
2564 if (!programObject->isLinked())
2565 {
Jamie Madill437fa652016-05-03 15:13:24 -04002566 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002567 return false;
2568 }
2569
2570 return true;
2571}
Jamie Madillc29968b2016-01-20 11:17:23 -05002572
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002573bool ValidateUseProgram(Context *context, GLuint program)
2574{
2575 if (program != 0)
2576 {
2577 Program *programObject = context->getProgram(program);
2578 if (!programObject)
2579 {
2580 // ES 3.1.0 section 7.3 page 72
2581 if (context->getShader(program))
2582 {
Jamie Madill437fa652016-05-03 15:13:24 -04002583 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002584 Error(GL_INVALID_OPERATION,
2585 "Attempted to use a single shader instead of a shader program."));
2586 return false;
2587 }
2588 else
2589 {
Jamie Madill437fa652016-05-03 15:13:24 -04002590 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002591 return false;
2592 }
2593 }
2594 if (!programObject->isLinked())
2595 {
Jamie Madill437fa652016-05-03 15:13:24 -04002596 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002597 return false;
2598 }
2599 }
2600 if (context->getState().isTransformFeedbackActiveUnpaused())
2601 {
2602 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002603 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002604 Error(GL_INVALID_OPERATION,
2605 "Cannot change active program while transform feedback is unpaused."));
2606 return false;
2607 }
2608
2609 return true;
2610}
2611
Jamie Madillc29968b2016-01-20 11:17:23 -05002612bool ValidateCopyTexImage2D(ValidationContext *context,
2613 GLenum target,
2614 GLint level,
2615 GLenum internalformat,
2616 GLint x,
2617 GLint y,
2618 GLsizei width,
2619 GLsizei height,
2620 GLint border)
2621{
2622 if (context->getClientVersion() < 3)
2623 {
2624 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2625 0, x, y, width, height, border);
2626 }
2627
2628 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002629 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2630 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002631}
Jamie Madillc29968b2016-01-20 11:17:23 -05002632
2633bool ValidateFramebufferRenderbuffer(Context *context,
2634 GLenum target,
2635 GLenum attachment,
2636 GLenum renderbuffertarget,
2637 GLuint renderbuffer)
2638{
2639 if (!ValidFramebufferTarget(target) ||
2640 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2641 {
Jamie Madill437fa652016-05-03 15:13:24 -04002642 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002643 return false;
2644 }
2645
2646 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2647 renderbuffertarget, renderbuffer);
2648}
2649
2650bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2651{
2652 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2653 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2654 {
Jamie Madill437fa652016-05-03 15:13:24 -04002655 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002656 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2657 return false;
2658 }
2659
2660 ASSERT(context->getState().getDrawFramebuffer());
2661 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2662 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2663
2664 // This should come first before the check for the default frame buffer
2665 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2666 // rather than INVALID_OPERATION
2667 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2668 {
2669 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2670
2671 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002672 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2673 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002674 {
2675 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002676 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2677 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2678 // 3.1 is still a bit ambiguous about the error, but future specs are
2679 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002680 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002681 return false;
2682 }
2683 else if (bufs[colorAttachment] >= maxColorAttachment)
2684 {
Jamie Madill437fa652016-05-03 15:13:24 -04002685 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002686 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002687 return false;
2688 }
2689 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2690 frameBufferId != 0)
2691 {
2692 // INVALID_OPERATION-GL is bound to buffer and ith argument
2693 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002694 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002695 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2696 return false;
2697 }
2698 }
2699
2700 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2701 // and n is not 1 or bufs is bound to value other than BACK and NONE
2702 if (frameBufferId == 0)
2703 {
2704 if (n != 1)
2705 {
Jamie Madill437fa652016-05-03 15:13:24 -04002706 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002707 "n must be 1 when GL is bound to the default framebuffer"));
2708 return false;
2709 }
2710
2711 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2712 {
Jamie Madill437fa652016-05-03 15:13:24 -04002713 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002714 GL_INVALID_OPERATION,
2715 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2716 return false;
2717 }
2718 }
2719
2720 return true;
2721}
2722
2723bool ValidateCopyTexSubImage2D(Context *context,
2724 GLenum target,
2725 GLint level,
2726 GLint xoffset,
2727 GLint yoffset,
2728 GLint x,
2729 GLint y,
2730 GLsizei width,
2731 GLsizei height)
2732{
2733 if (context->getClientVersion() < 3)
2734 {
2735 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2736 yoffset, x, y, width, height, 0);
2737 }
2738
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002739 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2740 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002741}
2742
Olli Etuaho4f667482016-03-30 15:56:35 +03002743bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2744{
2745 if (!ValidBufferTarget(context, target))
2746 {
Jamie Madill437fa652016-05-03 15:13:24 -04002747 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002748 return false;
2749 }
2750
2751 if (pname != GL_BUFFER_MAP_POINTER)
2752 {
Jamie Madill437fa652016-05-03 15:13:24 -04002753 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002754 return false;
2755 }
2756
2757 Buffer *buffer = context->getState().getTargetBuffer(target);
2758
2759 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2760 // target bound to zero generate an INVALID_OPERATION error."
2761 // GLES 3.1 section 6.6 explicitly specifies this error.
2762 if (!buffer)
2763 {
Jamie Madill437fa652016-05-03 15:13:24 -04002764 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002765 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2766 return false;
2767 }
2768
2769 return true;
2770}
2771
2772bool ValidateUnmapBufferBase(Context *context, GLenum target)
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 Buffer *buffer = context->getState().getTargetBuffer(target);
2781
2782 if (buffer == nullptr || !buffer->isMapped())
2783 {
Jamie Madill437fa652016-05-03 15:13:24 -04002784 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002785 return false;
2786 }
2787
2788 return true;
2789}
2790
2791bool ValidateMapBufferRangeBase(Context *context,
2792 GLenum target,
2793 GLintptr offset,
2794 GLsizeiptr length,
2795 GLbitfield access)
2796{
2797 if (!ValidBufferTarget(context, target))
2798 {
Jamie Madill437fa652016-05-03 15:13:24 -04002799 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002800 return false;
2801 }
2802
2803 if (offset < 0 || length < 0)
2804 {
Jamie Madill437fa652016-05-03 15:13:24 -04002805 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002806 return false;
2807 }
2808
2809 Buffer *buffer = context->getState().getTargetBuffer(target);
2810
2811 if (!buffer)
2812 {
Jamie Madill437fa652016-05-03 15:13:24 -04002813 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002814 return false;
2815 }
2816
2817 // Check for buffer overflow
2818 size_t offsetSize = static_cast<size_t>(offset);
2819 size_t lengthSize = static_cast<size_t>(length);
2820
2821 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2822 offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
2823 {
Jamie Madill437fa652016-05-03 15:13:24 -04002824 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002825 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2826 return false;
2827 }
2828
2829 // Check for invalid bits in the mask
2830 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2831 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2832 GL_MAP_UNSYNCHRONIZED_BIT;
2833
2834 if (access & ~(allAccessBits))
2835 {
Jamie Madill437fa652016-05-03 15:13:24 -04002836 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002837 return false;
2838 }
2839
2840 if (length == 0)
2841 {
Jamie Madill437fa652016-05-03 15:13:24 -04002842 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002843 return false;
2844 }
2845
2846 if (buffer->isMapped())
2847 {
Jamie Madill437fa652016-05-03 15:13:24 -04002848 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002849 return false;
2850 }
2851
2852 // Check for invalid bit combinations
2853 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2854 {
Jamie Madill437fa652016-05-03 15:13:24 -04002855 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002856 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2857 return false;
2858 }
2859
2860 GLbitfield writeOnlyBits =
2861 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2862
2863 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2864 {
Jamie Madill437fa652016-05-03 15:13:24 -04002865 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002866 "Invalid access bits when mapping buffer for reading: 0x%X.",
2867 access));
2868 return false;
2869 }
2870
2871 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2872 {
Jamie Madill437fa652016-05-03 15:13:24 -04002873 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002874 GL_INVALID_OPERATION,
2875 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2876 return false;
2877 }
2878 return true;
2879}
2880
2881bool ValidateFlushMappedBufferRangeBase(Context *context,
2882 GLenum target,
2883 GLintptr offset,
2884 GLsizeiptr length)
2885{
2886 if (offset < 0 || length < 0)
2887 {
Jamie Madill437fa652016-05-03 15:13:24 -04002888 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002889 return false;
2890 }
2891
2892 if (!ValidBufferTarget(context, target))
2893 {
Jamie Madill437fa652016-05-03 15:13:24 -04002894 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002895 return false;
2896 }
2897
2898 Buffer *buffer = context->getState().getTargetBuffer(target);
2899
2900 if (buffer == nullptr)
2901 {
Jamie Madill437fa652016-05-03 15:13:24 -04002902 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002903 return false;
2904 }
2905
2906 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2907 {
Jamie Madill437fa652016-05-03 15:13:24 -04002908 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002909 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2910 return false;
2911 }
2912
2913 // Check for buffer overflow
2914 size_t offsetSize = static_cast<size_t>(offset);
2915 size_t lengthSize = static_cast<size_t>(length);
2916
2917 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2918 offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
2919 {
Jamie Madill437fa652016-05-03 15:13:24 -04002920 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002921 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2922 return false;
2923 }
2924
2925 return true;
2926}
2927
Olli Etuaho41997e72016-03-10 13:38:39 +02002928bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2929{
2930 return ValidateGenOrDelete(context, n);
2931}
2932
2933bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2934{
2935 return ValidateGenOrDelete(context, n);
2936}
2937
2938bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2939{
2940 return ValidateGenOrDelete(context, n);
2941}
2942
2943bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2944{
2945 return ValidateGenOrDelete(context, n);
2946}
2947
2948bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2949{
2950 return ValidateGenOrDelete(context, n);
2951}
2952
2953bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2954{
2955 return ValidateGenOrDelete(context, n);
2956}
2957
2958bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2959{
2960 return ValidateGenOrDelete(context, n);
2961}
2962
2963bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2964{
2965 return ValidateGenOrDelete(context, n);
2966}
2967
2968bool ValidateGenOrDelete(Context *context, GLint n)
2969{
2970 if (n < 0)
2971 {
Jamie Madill437fa652016-05-03 15:13:24 -04002972 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02002973 return false;
2974 }
2975 return true;
2976}
2977
Jamie Madillc29968b2016-01-20 11:17:23 -05002978} // namespace gl