blob: 0f73448786a6048269b01b5f88a2b8d2fa8653bc [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"
Jamie Madille2e406c2016-06-02 13:04:10 -040010
Geoff Lang2b5420c2014-11-19 14:20:15 -050011#include "libANGLE/validationES2.h"
12#include "libANGLE/validationES3.h"
13#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040014#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050015#include "libANGLE/Texture.h"
16#include "libANGLE/Framebuffer.h"
17#include "libANGLE/FramebufferAttachment.h"
18#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040019#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050021#include "libANGLE/Program.h"
22#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050023#include "libANGLE/TransformFeedback.h"
24#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040025
26#include "common/mathutil.h"
27#include "common/utilities.h"
28
Jamie Madille2e406c2016-06-02 13:04:10 -040029using namespace angle;
30
Geoff Lange8ebe7f2013-08-05 15:03:13 -040031namespace gl
32{
Jamie Madille79b1e12015-11-04 16:36:37 -050033const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
34
Jamie Madill1ca74672015-07-21 15:14:11 -040035namespace
36{
Jamie Madillf25855c2015-11-03 11:06:18 -050037bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040038{
39 const gl::State &state = context->getState();
40 const gl::Program *program = state.getProgram();
41
42 const VertexArray *vao = state.getVertexArray();
43 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040044 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
45 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
46 {
47 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040048 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040049 {
50 gl::Buffer *buffer = attrib.buffer.get();
51
52 if (buffer)
53 {
54 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
55 GLint64 maxVertexElement = 0;
56
57 if (attrib.divisor > 0)
58 {
59 maxVertexElement =
60 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
61 }
62 else
63 {
64 maxVertexElement = static_cast<GLint64>(maxVertex);
65 }
66
67 // If we're drawing zero vertices, we have enough data.
68 if (maxVertexElement > 0)
69 {
70 // Note: Last vertex element does not take the full stride!
71 GLint64 attribSize =
72 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
73 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040074 GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
Jamie Madill1ca74672015-07-21 15:14:11 -040075
76 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
77 // We can return INVALID_OPERATION if our vertex attribute does not have
78 // enough backing data.
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040079 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040080 {
Jamie Madill437fa652016-05-03 15:13:24 -040081 context->handleError(
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040082 Error(GL_INVALID_OPERATION,
83 "Vertex buffer is not big enough for the draw call"));
Jamie Madill1ca74672015-07-21 15:14:11 -040084 return false;
85 }
86 }
87 }
88 else if (attrib.pointer == NULL)
89 {
90 // This is an application error that would normally result in a crash,
91 // but we catch it and return an error
Jamie Madill437fa652016-05-03 15:13:24 -040092 context->handleError(Error(
Jamie Madill1ca74672015-07-21 15:14:11 -040093 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
94 return false;
95 }
96 }
97 }
98
99 return true;
100}
101
102} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400103
Geoff Lang0550d032014-01-30 11:29:07 -0500104bool ValidCap(const Context *context, GLenum cap)
105{
106 switch (cap)
107 {
Sami Väisänen74c23472016-05-09 17:30:30 +0300108 // EXT_multisample_compatibility
109 case GL_MULTISAMPLE_EXT:
110 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
111 return context->getExtensions().multisampleCompatibility;
112
Geoff Lang0550d032014-01-30 11:29:07 -0500113 case GL_CULL_FACE:
114 case GL_POLYGON_OFFSET_FILL:
115 case GL_SAMPLE_ALPHA_TO_COVERAGE:
116 case GL_SAMPLE_COVERAGE:
117 case GL_SCISSOR_TEST:
118 case GL_STENCIL_TEST:
119 case GL_DEPTH_TEST:
120 case GL_BLEND:
121 case GL_DITHER:
122 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500123
Geoff Lang0550d032014-01-30 11:29:07 -0500124 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
125 case GL_RASTERIZER_DISCARD:
126 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500127
128 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
129 case GL_DEBUG_OUTPUT:
130 return context->getExtensions().debug;
131
Geoff Lang0550d032014-01-30 11:29:07 -0500132 default:
133 return false;
134 }
135}
136
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500137bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400138{
Jamie Madilld7460c72014-01-21 16:38:14 -0500139 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400140 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500141 case GL_TEXTURE_2D:
142 case GL_TEXTURE_CUBE_MAP:
143 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400144
Jamie Madilld7460c72014-01-21 16:38:14 -0500145 case GL_TEXTURE_3D:
146 case GL_TEXTURE_2D_ARRAY:
147 return (context->getClientVersion() >= 3);
148
149 default:
150 return false;
151 }
Jamie Madill35d15012013-10-07 10:46:37 -0400152}
153
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500154bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
155{
156 switch (target)
157 {
158 case GL_TEXTURE_2D:
159 case GL_TEXTURE_CUBE_MAP:
160 return true;
161
162 default:
163 return false;
164 }
165}
166
167bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
168{
169 switch (target)
170 {
171 case GL_TEXTURE_3D:
172 case GL_TEXTURE_2D_ARRAY:
173 return (context->getClientVersion() >= 3);
174
175 default:
176 return false;
177 }
178}
179
Ian Ewellbda75592016-04-18 17:25:54 -0400180// Most texture GL calls are not compatible with external textures, so we have a separate validation
181// function for use in the GL calls that do
182bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
183{
184 return (target == GL_TEXTURE_EXTERNAL_OES) &&
185 (context->getExtensions().eglImageExternal ||
186 context->getExtensions().eglStreamConsumerExternal);
187}
188
Shannon Woods4dfed832014-03-17 20:03:39 -0400189// This function differs from ValidTextureTarget in that the target must be
190// usable as the destination of a 2D operation-- so a cube face is valid, but
191// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400192// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500193bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400194{
195 switch (target)
196 {
197 case GL_TEXTURE_2D:
198 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
199 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
200 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
201 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
202 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
203 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
204 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500205 default:
206 return false;
207 }
208}
209
210bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
211{
212 switch (target)
213 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400214 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500215 case GL_TEXTURE_2D_ARRAY:
216 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400217 default:
218 return false;
219 }
220}
221
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500222bool ValidFramebufferTarget(GLenum target)
223{
Geoff Langd4475812015-03-18 10:53:05 -0400224 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
225 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500226
227 switch (target)
228 {
229 case GL_FRAMEBUFFER: return true;
230 case GL_READ_FRAMEBUFFER: return true;
231 case GL_DRAW_FRAMEBUFFER: return true;
232 default: return false;
233 }
234}
235
Jamie Madill8c96d582014-03-05 15:01:23 -0500236bool ValidBufferTarget(const Context *context, GLenum target)
237{
238 switch (target)
239 {
240 case GL_ARRAY_BUFFER:
241 case GL_ELEMENT_ARRAY_BUFFER:
242 return true;
243
Jamie Madill8c96d582014-03-05 15:01:23 -0500244 case GL_PIXEL_PACK_BUFFER:
245 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400246 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400247
Shannon Woodsb3801742014-03-27 14:59:19 -0400248 case GL_COPY_READ_BUFFER:
249 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500250 case GL_TRANSFORM_FEEDBACK_BUFFER:
251 case GL_UNIFORM_BUFFER:
252 return (context->getClientVersion() >= 3);
253
254 default:
255 return false;
256 }
257}
258
Jamie Madill70656a62014-03-05 15:01:26 -0500259bool ValidBufferParameter(const Context *context, GLenum pname)
260{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400261 const Extensions &extensions = context->getExtensions();
262
Jamie Madill70656a62014-03-05 15:01:26 -0500263 switch (pname)
264 {
265 case GL_BUFFER_USAGE:
266 case GL_BUFFER_SIZE:
267 return true;
268
Geoff Langcc6f55d2015-03-20 13:01:02 -0400269 case GL_BUFFER_ACCESS_OES:
270 return extensions.mapBuffer;
271
272 case GL_BUFFER_MAPPED:
273 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
274 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
275
Jamie Madill70656a62014-03-05 15:01:26 -0500276 // GL_BUFFER_MAP_POINTER is a special case, and may only be
277 // queried with GetBufferPointerv
278 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500279 case GL_BUFFER_MAP_OFFSET:
280 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400281 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500282
283 default:
284 return false;
285 }
286}
287
Jamie Madillc29968b2016-01-20 11:17:23 -0500288bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400289{
Jamie Madillc29968b2016-01-20 11:17:23 -0500290 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400291 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400292 switch (target)
293 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500294 case GL_TEXTURE_2D:
295 maxDimension = caps.max2DTextureSize;
296 break;
Geoff Langce635692013-09-24 13:56:32 -0400297 case GL_TEXTURE_CUBE_MAP:
298 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
299 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
300 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
301 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
302 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500303 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
304 maxDimension = caps.maxCubeMapTextureSize;
305 break;
306 case GL_TEXTURE_3D:
307 maxDimension = caps.max3DTextureSize;
308 break;
309 case GL_TEXTURE_2D_ARRAY:
310 maxDimension = caps.max2DTextureSize;
311 break;
Geoff Langce635692013-09-24 13:56:32 -0400312 default: UNREACHABLE();
313 }
314
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700315 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400316}
317
Austin Kinross08528e12015-10-07 16:24:40 -0700318bool ValidImageSizeParameters(const Context *context,
319 GLenum target,
320 GLint level,
321 GLsizei width,
322 GLsizei height,
323 GLsizei depth,
324 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400325{
326 if (level < 0 || width < 0 || height < 0 || depth < 0)
327 {
328 return false;
329 }
330
Austin Kinross08528e12015-10-07 16:24:40 -0700331 // TexSubImage parameters can be NPOT without textureNPOT extension,
332 // as long as the destination texture is POT.
333 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400334 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400335 {
336 return false;
337 }
338
339 if (!ValidMipLevel(context, target, level))
340 {
341 return false;
342 }
343
344 return true;
345}
346
Geoff Lang0d8b7242015-09-09 14:56:53 -0400347bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
348{
349 // List of compressed format that require that the texture size is smaller than or a multiple of
350 // the compressed block size.
351 switch (internalFormat)
352 {
353 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
354 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
355 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
356 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800357 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400358 return true;
359
360 default:
361 return false;
362 }
363}
364
Jamie Madillc29968b2016-01-20 11:17:23 -0500365bool ValidCompressedImageSize(const ValidationContext *context,
366 GLenum internalFormat,
367 GLsizei width,
368 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400369{
Geoff Lang5d601382014-07-22 15:14:06 -0400370 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
371 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400372 {
373 return false;
374 }
375
Geoff Lang0d8b7242015-09-09 14:56:53 -0400376 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400377 {
378 return false;
379 }
380
Geoff Lang0d8b7242015-09-09 14:56:53 -0400381 if (CompressedTextureFormatRequiresExactSize(internalFormat))
382 {
383 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
384 width % formatInfo.compressedBlockWidth != 0) ||
385 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
386 height % formatInfo.compressedBlockHeight != 0))
387 {
388 return false;
389 }
390 }
391
Geoff Langd4f180b2013-09-24 13:57:44 -0400392 return true;
393}
394
Geoff Lang37dde692014-01-31 16:34:54 -0500395bool ValidQueryType(const Context *context, GLenum queryType)
396{
Geoff Langd4475812015-03-18 10:53:05 -0400397 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
398 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 -0500399
400 switch (queryType)
401 {
402 case GL_ANY_SAMPLES_PASSED:
403 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
404 return true;
405 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
406 return (context->getClientVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500407 case GL_TIME_ELAPSED_EXT:
408 return context->getExtensions().disjointTimerQuery;
Geoff Lang2b4ce802016-04-28 13:34:50 -0400409 case GL_COMMANDS_COMPLETED_CHROMIUM:
410 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500411 default:
412 return false;
413 }
414}
415
Dian Xiang769769a2015-09-09 15:20:08 -0700416Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500417{
418 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
419 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
420 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
421
Dian Xiang769769a2015-09-09 15:20:08 -0700422 Program *validProgram = context->getProgram(id);
423
424 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500425 {
Dian Xiang769769a2015-09-09 15:20:08 -0700426 if (context->getShader(id))
427 {
Jamie Madill437fa652016-05-03 15:13:24 -0400428 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700429 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
430 }
431 else
432 {
Jamie Madill437fa652016-05-03 15:13:24 -0400433 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700434 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500435 }
Dian Xiang769769a2015-09-09 15:20:08 -0700436
437 return validProgram;
438}
439
440Shader *GetValidShader(Context *context, GLuint id)
441{
442 // See ValidProgram for spec details.
443
444 Shader *validShader = context->getShader(id);
445
446 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500447 {
Dian Xiang769769a2015-09-09 15:20:08 -0700448 if (context->getProgram(id))
449 {
Jamie Madill437fa652016-05-03 15:13:24 -0400450 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700451 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
452 }
453 else
454 {
Jamie Madill437fa652016-05-03 15:13:24 -0400455 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700456 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500457 }
Dian Xiang769769a2015-09-09 15:20:08 -0700458
459 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500460}
461
Geoff Langb1196682014-07-23 13:47:29 -0400462bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400463{
464 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
465 {
466 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
467
Geoff Langaae65a42014-05-26 12:43:44 -0400468 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400469 {
Jamie Madill437fa652016-05-03 15:13:24 -0400470 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400471 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400472 }
473 }
474 else
475 {
476 switch (attachment)
477 {
478 case GL_DEPTH_ATTACHMENT:
479 case GL_STENCIL_ATTACHMENT:
480 break;
481
482 case GL_DEPTH_STENCIL_ATTACHMENT:
483 if (context->getClientVersion() < 3)
484 {
Jamie Madill437fa652016-05-03 15:13:24 -0400485 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400486 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400487 }
488 break;
489
490 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400491 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400492 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400493 }
494 }
495
496 return true;
497}
498
Corentin Walleze0902642014-11-04 12:32:15 -0800499bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
500 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400501{
502 switch (target)
503 {
504 case GL_RENDERBUFFER:
505 break;
506 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400507 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400508 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400509 }
510
511 if (width < 0 || height < 0 || samples < 0)
512 {
Jamie Madill437fa652016-05-03 15:13:24 -0400513 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400514 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400515 }
516
Geoff Langd87878e2014-09-19 15:42:59 -0400517 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
518 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 {
Jamie Madill437fa652016-05-03 15:13:24 -0400520 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400521 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 }
523
524 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
525 // 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 -0800526 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400527 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400528 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400529 {
Jamie Madill437fa652016-05-03 15:13:24 -0400530 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400531 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400532 }
533
Geoff Langaae65a42014-05-26 12:43:44 -0400534 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400535 {
Jamie Madill437fa652016-05-03 15:13:24 -0400536 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400537 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400538 }
539
Shannon Woods53a94a82014-06-24 15:20:36 -0400540 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400541 if (handle == 0)
542 {
Jamie Madill437fa652016-05-03 15:13:24 -0400543 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400544 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400545 }
546
547 return true;
548}
549
Corentin Walleze0902642014-11-04 12:32:15 -0800550bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
551 GLenum internalformat, GLsizei width, GLsizei height)
552{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800553 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800554
555 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400556 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800557 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400558 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800559 {
Jamie Madill437fa652016-05-03 15:13:24 -0400560 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800561 return false;
562 }
563
564 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
565 // the specified storage. This is different than ES 3.0 in which a sample number higher
566 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800567 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
568 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800569 {
Geoff Langa4903b72015-03-02 16:02:48 -0800570 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
571 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
572 {
Jamie Madill437fa652016-05-03 15:13:24 -0400573 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800574 return false;
575 }
Corentin Walleze0902642014-11-04 12:32:15 -0800576 }
577
578 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
579}
580
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500581bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
582 GLenum renderbuffertarget, GLuint renderbuffer)
583{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400584 if (!ValidFramebufferTarget(target))
585 {
Jamie Madill437fa652016-05-03 15:13:24 -0400586 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400587 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400588 }
589
Shannon Woods53a94a82014-06-24 15:20:36 -0400590 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500591
Jamie Madill84115c92015-04-23 15:00:07 -0400592 ASSERT(framebuffer);
593 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500594 {
Jamie Madill437fa652016-05-03 15:13:24 -0400595 context->handleError(
596 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400597 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500598 }
599
Jamie Madillb4472272014-07-03 10:38:55 -0400600 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500601 {
Jamie Madillb4472272014-07-03 10:38:55 -0400602 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500603 }
604
Jamie Madillab9d82c2014-01-21 16:38:14 -0500605 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
606 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
607 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
608 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
609 if (renderbuffer != 0)
610 {
611 if (!context->getRenderbuffer(renderbuffer))
612 {
Jamie Madill437fa652016-05-03 15:13:24 -0400613 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400614 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500615 }
616 }
617
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500618 return true;
619}
620
Jamie Madillc29968b2016-01-20 11:17:23 -0500621bool ValidateBlitFramebufferParameters(gl::Context *context,
622 GLint srcX0,
623 GLint srcY0,
624 GLint srcX1,
625 GLint srcY1,
626 GLint dstX0,
627 GLint dstY0,
628 GLint dstX1,
629 GLint dstY1,
630 GLbitfield mask,
631 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632{
633 switch (filter)
634 {
635 case GL_NEAREST:
636 break;
637 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400638 break;
639 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400640 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400641 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400642 }
643
644 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
645 {
Jamie Madill437fa652016-05-03 15:13:24 -0400646 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400647 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400648 }
649
650 if (mask == 0)
651 {
652 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
653 // buffers are copied.
654 return false;
655 }
656
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400657 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
658 // color buffer, leaving only nearest being unfiltered from above
659 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
660 {
Jamie Madill437fa652016-05-03 15:13:24 -0400661 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400662 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400663 }
664
Shannon Woods53a94a82014-06-24 15:20:36 -0400665 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400666 {
Jamie Madill437fa652016-05-03 15:13:24 -0400667 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400668 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400669 }
670
Jamie Madille3ef7152015-04-28 16:55:17 +0000671 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
672 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500673
674 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 {
Jamie Madill437fa652016-05-03 15:13:24 -0400676 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400677 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400678 }
679
Geoff Lang748f74e2014-12-01 11:25:34 -0500680 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500681 {
Jamie Madill437fa652016-05-03 15:13:24 -0400682 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500683 return false;
684 }
685
Geoff Lang748f74e2014-12-01 11:25:34 -0500686 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500687 {
Jamie Madill437fa652016-05-03 15:13:24 -0400688 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500689 return false;
690 }
691
692 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 {
Jamie Madill437fa652016-05-03 15:13:24 -0400694 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400695 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696 }
697
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400698 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
699
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700 if (mask & GL_COLOR_BUFFER_BIT)
701 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400702 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
703 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500704 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400705
706 if (readColorBuffer && drawColorBuffer)
707 {
Geoff Langd8a22582014-12-17 15:28:23 -0500708 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400709 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710
Geoff Langa15472a2015-08-11 11:48:03 -0400711 for (size_t drawbufferIdx = 0;
712 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400713 {
Geoff Langa15472a2015-08-11 11:48:03 -0400714 const FramebufferAttachment *attachment =
715 drawFramebuffer->getDrawBuffer(drawbufferIdx);
716 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400717 {
Geoff Langa15472a2015-08-11 11:48:03 -0400718 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400719 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400720
Geoff Langb2f3d052013-08-13 12:49:27 -0400721 // The GL ES 3.0.2 spec (pg 193) states that:
722 // 1) If the read buffer is fixed point format, the draw buffer must be as well
723 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
724 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500725 // Changes with EXT_color_buffer_float:
726 // Case 1) is changed to fixed point OR floating point
727 GLenum readComponentType = readFormatInfo.componentType;
728 GLenum drawComponentType = drawFormatInfo.componentType;
729 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
730 readComponentType == GL_SIGNED_NORMALIZED);
731 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
732 drawComponentType == GL_SIGNED_NORMALIZED);
733
734 if (extensions.colorBufferFloat)
735 {
736 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
737 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
738
739 if (readFixedOrFloat != drawFixedOrFloat)
740 {
Jamie Madill437fa652016-05-03 15:13:24 -0400741 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500742 "If the read buffer contains fixed-point or "
743 "floating-point values, the draw buffer "
744 "must as well."));
745 return false;
746 }
747 }
748 else if (readFixedPoint != drawFixedPoint)
749 {
Jamie Madill437fa652016-05-03 15:13:24 -0400750 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500751 "If the read buffer contains fixed-point "
752 "values, the draw buffer must as well."));
753 return false;
754 }
755
756 if (readComponentType == GL_UNSIGNED_INT &&
757 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400758 {
Jamie Madill437fa652016-05-03 15:13:24 -0400759 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400760 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 }
762
Jamie Madill6163c752015-12-07 16:32:59 -0500763 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 {
Jamie Madill437fa652016-05-03 15:13:24 -0400765 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400766 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 }
768
Geoff Langb2f3d052013-08-13 12:49:27 -0400769 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 {
Jamie Madill437fa652016-05-03 15:13:24 -0400771 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400772 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773 }
774 }
775 }
776
Geoff Lang5d601382014-07-22 15:14:06 -0400777 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400778 {
Jamie Madill437fa652016-05-03 15:13:24 -0400779 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400780 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400781 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400782 }
783 }
784
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200785 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
786 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
787 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400788 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200789 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400790 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400791 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
792 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200794 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 {
Geoff Langd8a22582014-12-17 15:28:23 -0500796 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400797 {
Jamie Madill437fa652016-05-03 15:13:24 -0400798 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400799 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400801
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200802 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803 {
Jamie Madill437fa652016-05-03 15:13:24 -0400804 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400805 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806 }
807 }
808 }
809 }
810
811 return true;
812}
813
Geoff Langb1196682014-07-23 13:47:29 -0400814bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400815{
816 switch (pname)
817 {
818 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
819 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
820 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
821 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
822 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
823 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
824 case GL_CURRENT_VERTEX_ATTRIB:
825 return true;
826
827 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
828 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
829 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400830 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
831 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400832 return true;
833
834 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400835 if (context->getClientVersion() < 3)
836 {
Jamie Madill437fa652016-05-03 15:13:24 -0400837 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400838 return false;
839 }
840 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400841
842 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400843 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400844 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400845 }
846}
847
Ian Ewellbda75592016-04-18 17:25:54 -0400848bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400849{
850 switch (pname)
851 {
852 case GL_TEXTURE_WRAP_R:
853 case GL_TEXTURE_SWIZZLE_R:
854 case GL_TEXTURE_SWIZZLE_G:
855 case GL_TEXTURE_SWIZZLE_B:
856 case GL_TEXTURE_SWIZZLE_A:
857 case GL_TEXTURE_BASE_LEVEL:
858 case GL_TEXTURE_MAX_LEVEL:
859 case GL_TEXTURE_COMPARE_MODE:
860 case GL_TEXTURE_COMPARE_FUNC:
861 case GL_TEXTURE_MIN_LOD:
862 case GL_TEXTURE_MAX_LOD:
Geoff Langb66a9092016-05-16 15:59:14 -0400863 if (context->getClientVersion() < 3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400864 {
Jamie Madill437fa652016-05-03 15:13:24 -0400865 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400866 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400867 }
Geoff Langb66a9092016-05-16 15:59:14 -0400868 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
869 {
870 context->handleError(Error(GL_INVALID_ENUM,
871 "ES3 texture parameters are not available without "
872 "GL_OES_EGL_image_external_essl3."));
873 return false;
874 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400875 break;
876
877 default: break;
878 }
879
880 switch (pname)
881 {
882 case GL_TEXTURE_WRAP_S:
883 case GL_TEXTURE_WRAP_T:
884 case GL_TEXTURE_WRAP_R:
885 switch (param)
886 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000887 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400888 return true;
889 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400890 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300891 if (target == GL_TEXTURE_EXTERNAL_OES)
892 {
893 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400894 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300895 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
896 return false;
897 }
898 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400899 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400900 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400901 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400902 }
903
904 case GL_TEXTURE_MIN_FILTER:
905 switch (param)
906 {
907 case GL_NEAREST:
908 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400909 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400910 case GL_NEAREST_MIPMAP_NEAREST:
911 case GL_LINEAR_MIPMAP_NEAREST:
912 case GL_NEAREST_MIPMAP_LINEAR:
913 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300914 if (target == GL_TEXTURE_EXTERNAL_OES)
915 {
916 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400917 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300918 Error(GL_INVALID_ENUM,
919 "external textures only support NEAREST and LINEAR filtering"));
920 return false;
921 }
922 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400923 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400924 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400925 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400926 }
927 break;
928
929 case GL_TEXTURE_MAG_FILTER:
930 switch (param)
931 {
932 case GL_NEAREST:
933 case GL_LINEAR:
934 return true;
935 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400936 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400937 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400938 }
939 break;
940
941 case GL_TEXTURE_USAGE_ANGLE:
942 switch (param)
943 {
944 case GL_NONE:
945 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
946 return true;
947 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400948 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400949 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400950 }
951 break;
952
953 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400954 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400955 {
Jamie Madill437fa652016-05-03 15:13:24 -0400956 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400957 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400958 }
959
960 // we assume the parameter passed to this validation method is truncated, not rounded
961 if (param < 1)
962 {
Jamie Madill437fa652016-05-03 15:13:24 -0400963 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400964 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400965 }
966 return true;
967
968 case GL_TEXTURE_MIN_LOD:
969 case GL_TEXTURE_MAX_LOD:
970 // any value is permissible
971 return true;
972
973 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400974 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400975 switch (param)
976 {
977 case GL_NONE:
978 case GL_COMPARE_REF_TO_TEXTURE:
979 return true;
980 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400981 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400982 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400983 }
984 break;
985
986 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400987 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400988 switch (param)
989 {
990 case GL_LEQUAL:
991 case GL_GEQUAL:
992 case GL_LESS:
993 case GL_GREATER:
994 case GL_EQUAL:
995 case GL_NOTEQUAL:
996 case GL_ALWAYS:
997 case GL_NEVER:
998 return true;
999 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001000 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001001 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001002 }
1003 break;
1004
1005 case GL_TEXTURE_SWIZZLE_R:
1006 case GL_TEXTURE_SWIZZLE_G:
1007 case GL_TEXTURE_SWIZZLE_B:
1008 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001009 switch (param)
1010 {
1011 case GL_RED:
1012 case GL_GREEN:
1013 case GL_BLUE:
1014 case GL_ALPHA:
1015 case GL_ZERO:
1016 case GL_ONE:
1017 return true;
1018 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001019 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001020 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001021 }
1022 break;
1023
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001024 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001025 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001026 {
Geoff Langb66a9092016-05-16 15:59:14 -04001027 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001028 return false;
1029 }
Geoff Langb66a9092016-05-16 15:59:14 -04001030 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1031 {
1032 context->handleError(
1033 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1034 return false;
1035 }
1036 return true;
1037
1038 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001039 if (param < 0)
1040 {
1041 context->handleError(Error(GL_INVALID_VALUE));
1042 return false;
1043 }
1044 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001045 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001046 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001047 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001048 }
1049}
1050
Geoff Langb1196682014-07-23 13:47:29 -04001051bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001052{
1053 switch (pname)
1054 {
1055 case GL_TEXTURE_MIN_FILTER:
1056 case GL_TEXTURE_MAG_FILTER:
1057 case GL_TEXTURE_WRAP_S:
1058 case GL_TEXTURE_WRAP_T:
1059 case GL_TEXTURE_WRAP_R:
1060 case GL_TEXTURE_MIN_LOD:
1061 case GL_TEXTURE_MAX_LOD:
1062 case GL_TEXTURE_COMPARE_MODE:
1063 case GL_TEXTURE_COMPARE_FUNC:
1064 return true;
1065
1066 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001067 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001068 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001069 }
1070}
1071
Jamie Madillc29968b2016-01-20 11:17:23 -05001072bool ValidateReadPixels(Context *context,
1073 GLint x,
1074 GLint y,
1075 GLsizei width,
1076 GLsizei height,
1077 GLenum format,
1078 GLenum type,
1079 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001080{
Jamie Madillc29968b2016-01-20 11:17:23 -05001081 if (width < 0 || height < 0)
1082 {
Jamie Madill437fa652016-05-03 15:13:24 -04001083 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001084 return false;
1085 }
1086
1087 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001088 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001089
Geoff Lang748f74e2014-12-01 11:25:34 -05001090 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001091 {
Jamie Madill437fa652016-05-03 15:13:24 -04001092 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001093 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001094 }
1095
Jamie Madill48faf802014-11-06 15:27:22 -05001096 if (context->getState().getReadFramebuffer()->id() != 0 &&
1097 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001098 {
Jamie Madill437fa652016-05-03 15:13:24 -04001099 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001100 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001101 }
1102
Geoff Langbce529e2014-12-01 12:48:41 -05001103 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1104 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001105 {
Jamie Madill437fa652016-05-03 15:13:24 -04001106 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001107 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001108 }
1109
Geoff Langbce529e2014-12-01 12:48:41 -05001110 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1111 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001112 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001113 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001114
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001115 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1116 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001117
1118 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1119 {
Jamie Madill437fa652016-05-03 15:13:24 -04001120 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001121 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001122 }
1123
Jamie Madillc29968b2016-01-20 11:17:23 -05001124 return true;
1125}
1126
1127bool ValidateReadnPixelsEXT(Context *context,
1128 GLint x,
1129 GLint y,
1130 GLsizei width,
1131 GLsizei height,
1132 GLenum format,
1133 GLenum type,
1134 GLsizei bufSize,
1135 GLvoid *pixels)
1136{
1137 if (bufSize < 0)
1138 {
Jamie Madill437fa652016-05-03 15:13:24 -04001139 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001140 return false;
1141 }
1142
Geoff Lang5d601382014-07-22 15:14:06 -04001143 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1144 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001145
Jamie Madille2e406c2016-06-02 13:04:10 -04001146 auto outputPitchOrErr =
Minmin Gongadff67b2015-10-14 10:34:45 -04001147 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1148 context->getState().getPackRowLength());
Jamie Madille2e406c2016-06-02 13:04:10 -04001149
1150 if (outputPitchOrErr.isError())
1151 {
1152 context->handleError(outputPitchOrErr.getError());
1153 return false;
1154 }
1155
1156 CheckedNumeric<GLuint> checkedOutputPitch(outputPitchOrErr.getResult());
1157 auto checkedRequiredSize = checkedOutputPitch * height;
1158 if (!checkedRequiredSize.IsValid())
1159 {
1160 context->handleError(Error(GL_INVALID_OPERATION, "Unsigned multiplication overflow."));
1161 return false;
1162 }
1163
Jamie Madill26e91952014-03-05 15:01:27 -05001164 // sized query sanity check
Jamie Madille2e406c2016-06-02 13:04:10 -04001165 if (checkedRequiredSize.ValueOrDie() > static_cast<GLuint>(bufSize))
Jamie Madill26e91952014-03-05 15:01:27 -05001166 {
Jamie Madill437fa652016-05-03 15:13:24 -04001167 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001168 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001169 }
1170
Jamie Madillc29968b2016-01-20 11:17:23 -05001171 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001172}
1173
Olli Etuaho41997e72016-03-10 13:38:39 +02001174bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001175{
1176 if (!context->getExtensions().occlusionQueryBoolean &&
1177 !context->getExtensions().disjointTimerQuery)
1178 {
Jamie Madill437fa652016-05-03 15:13:24 -04001179 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001180 return false;
1181 }
1182
Olli Etuaho41997e72016-03-10 13:38:39 +02001183 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001184}
1185
Olli Etuaho41997e72016-03-10 13:38:39 +02001186bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001187{
1188 if (!context->getExtensions().occlusionQueryBoolean &&
1189 !context->getExtensions().disjointTimerQuery)
1190 {
Jamie Madill437fa652016-05-03 15:13:24 -04001191 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001192 return false;
1193 }
1194
Olli Etuaho41997e72016-03-10 13:38:39 +02001195 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001196}
1197
1198bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001199{
1200 if (!ValidQueryType(context, target))
1201 {
Jamie Madill437fa652016-05-03 15:13:24 -04001202 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001203 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001204 }
1205
1206 if (id == 0)
1207 {
Jamie Madill437fa652016-05-03 15:13:24 -04001208 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001209 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001210 }
1211
1212 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1213 // of zero, if the active query object name for <target> is non-zero (for the
1214 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1215 // the active query for either target is non-zero), if <id> is the name of an
1216 // existing query object whose type does not match <target>, or if <id> is the
1217 // active query object name for any query type, the error INVALID_OPERATION is
1218 // generated.
1219
1220 // Ensure no other queries are active
1221 // NOTE: If other queries than occlusion are supported, we will need to check
1222 // separately that:
1223 // a) The query ID passed is not the current active query for any target/type
1224 // b) There are no active queries for the requested target (and in the case
1225 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1226 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001227
Corentin Walleze71ea192016-04-19 13:16:37 -04001228 if (context->getState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001229 {
Jamie Madill437fa652016-05-03 15:13:24 -04001230 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001231 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001232 }
1233
1234 Query *queryObject = context->getQuery(id, true, target);
1235
1236 // check that name was obtained with glGenQueries
1237 if (!queryObject)
1238 {
Jamie Madill437fa652016-05-03 15:13:24 -04001239 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001240 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001241 }
1242
1243 // check for type mismatch
1244 if (queryObject->getType() != target)
1245 {
Jamie Madill437fa652016-05-03 15:13:24 -04001246 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001247 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001248 }
1249
1250 return true;
1251}
1252
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001253bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1254{
1255 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001256 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001257 {
Jamie Madill437fa652016-05-03 15:13:24 -04001258 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001259 return false;
1260 }
1261
1262 return ValidateBeginQueryBase(context, target, id);
1263}
1264
1265bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001266{
1267 if (!ValidQueryType(context, target))
1268 {
Jamie Madill437fa652016-05-03 15:13:24 -04001269 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001270 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001271 }
1272
Shannon Woods53a94a82014-06-24 15:20:36 -04001273 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001274
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001275 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001276 {
Jamie Madill437fa652016-05-03 15:13:24 -04001277 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001278 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001279 }
1280
Jamie Madill45c785d2014-05-13 14:09:34 -04001281 return true;
1282}
1283
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001284bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1285{
1286 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001287 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001288 {
Jamie Madill437fa652016-05-03 15:13:24 -04001289 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001290 return false;
1291 }
1292
1293 return ValidateEndQueryBase(context, target);
1294}
1295
1296bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1297{
1298 if (!context->getExtensions().disjointTimerQuery)
1299 {
Jamie Madill437fa652016-05-03 15:13:24 -04001300 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001301 return false;
1302 }
1303
1304 if (target != GL_TIMESTAMP_EXT)
1305 {
Jamie Madill437fa652016-05-03 15:13:24 -04001306 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001307 return false;
1308 }
1309
1310 Query *queryObject = context->getQuery(id, true, target);
1311 if (queryObject == nullptr)
1312 {
Jamie Madill437fa652016-05-03 15:13:24 -04001313 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001314 return false;
1315 }
1316
1317 if (context->getState().isQueryActive(queryObject))
1318 {
Jamie Madill437fa652016-05-03 15:13:24 -04001319 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001320 return false;
1321 }
1322
1323 return true;
1324}
1325
1326bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1327{
1328 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1329 {
Jamie Madill437fa652016-05-03 15:13:24 -04001330 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001331 return false;
1332 }
1333
1334 switch (pname)
1335 {
1336 case GL_CURRENT_QUERY_EXT:
1337 if (target == GL_TIMESTAMP_EXT)
1338 {
Jamie Madill437fa652016-05-03 15:13:24 -04001339 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001340 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1341 return false;
1342 }
1343 break;
1344 case GL_QUERY_COUNTER_BITS_EXT:
1345 if (!context->getExtensions().disjointTimerQuery ||
1346 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1347 {
Jamie Madill437fa652016-05-03 15:13:24 -04001348 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001349 return false;
1350 }
1351 break;
1352 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001353 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001354 return false;
1355 }
1356
1357 return true;
1358}
1359
1360bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1361{
1362 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001363 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001364 {
Jamie Madill437fa652016-05-03 15:13:24 -04001365 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001366 return false;
1367 }
1368
1369 return ValidateGetQueryivBase(context, target, pname);
1370}
1371
1372bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1373{
1374 Query *queryObject = context->getQuery(id, false, GL_NONE);
1375
1376 if (!queryObject)
1377 {
Jamie Madill437fa652016-05-03 15:13:24 -04001378 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001379 return false;
1380 }
1381
1382 if (context->getState().isQueryActive(queryObject))
1383 {
Jamie Madill437fa652016-05-03 15:13:24 -04001384 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001385 return false;
1386 }
1387
1388 switch (pname)
1389 {
1390 case GL_QUERY_RESULT_EXT:
1391 case GL_QUERY_RESULT_AVAILABLE_EXT:
1392 break;
1393
1394 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001395 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001396 return false;
1397 }
1398
1399 return true;
1400}
1401
1402bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1403{
1404 if (!context->getExtensions().disjointTimerQuery)
1405 {
Jamie Madill437fa652016-05-03 15:13:24 -04001406 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001407 return false;
1408 }
1409 return ValidateGetQueryObjectValueBase(context, id, pname);
1410}
1411
1412bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1413{
1414 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001415 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001416 {
Jamie Madill437fa652016-05-03 15:13:24 -04001417 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001418 return false;
1419 }
1420 return ValidateGetQueryObjectValueBase(context, id, pname);
1421}
1422
1423bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1424{
1425 if (!context->getExtensions().disjointTimerQuery)
1426 {
Jamie Madill437fa652016-05-03 15:13:24 -04001427 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001428 return false;
1429 }
1430 return ValidateGetQueryObjectValueBase(context, id, pname);
1431}
1432
1433bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1434{
1435 if (!context->getExtensions().disjointTimerQuery)
1436 {
Jamie Madill437fa652016-05-03 15:13:24 -04001437 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001438 return false;
1439 }
1440 return ValidateGetQueryObjectValueBase(context, id, pname);
1441}
1442
Jamie Madill62d31cb2015-09-11 13:25:51 -04001443static bool ValidateUniformCommonBase(gl::Context *context,
1444 GLenum targetUniformType,
1445 GLint location,
1446 GLsizei count,
1447 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001448{
1449 if (count < 0)
1450 {
Jamie Madill437fa652016-05-03 15:13:24 -04001451 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001452 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001453 }
1454
Geoff Lang7dd2e102014-11-10 15:19:26 -05001455 gl::Program *program = context->getState().getProgram();
1456 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001457 {
Jamie Madill437fa652016-05-03 15:13:24 -04001458 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001459 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001460 }
1461
Geoff Langd8605522016-04-13 10:19:12 -04001462 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001463 {
1464 // Silently ignore the uniform command
1465 return false;
1466 }
1467
Geoff Lang7dd2e102014-11-10 15:19:26 -05001468 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001469 {
Jamie Madill437fa652016-05-03 15:13:24 -04001470 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001471 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001472 }
1473
Jamie Madill62d31cb2015-09-11 13:25:51 -04001474 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001475
1476 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001477 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001478 {
Jamie Madill437fa652016-05-03 15:13:24 -04001479 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001480 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001481 }
1482
Jamie Madill62d31cb2015-09-11 13:25:51 -04001483 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001484 return true;
1485}
1486
Jamie Madillaa981bd2014-05-20 10:55:55 -04001487bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1488{
1489 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001490 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001491 {
Jamie Madill437fa652016-05-03 15:13:24 -04001492 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001493 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001494 }
1495
Jamie Madill62d31cb2015-09-11 13:25:51 -04001496 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001497 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1498 {
1499 return false;
1500 }
1501
Jamie Madillf2575982014-06-25 16:04:54 -04001502 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001503 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001504 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1505 {
Jamie Madill437fa652016-05-03 15:13:24 -04001506 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001507 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001508 }
1509
1510 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001511}
1512
1513bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1514 GLboolean transpose)
1515{
1516 // Check for ES3 uniform entry points
1517 int rows = VariableRowCount(matrixType);
1518 int cols = VariableColumnCount(matrixType);
1519 if (rows != cols && context->getClientVersion() < 3)
1520 {
Jamie Madill437fa652016-05-03 15:13:24 -04001521 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001522 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001523 }
1524
1525 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1526 {
Jamie Madill437fa652016-05-03 15:13:24 -04001527 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001528 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001529 }
1530
Jamie Madill62d31cb2015-09-11 13:25:51 -04001531 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001532 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1533 {
1534 return false;
1535 }
1536
1537 if (uniform->type != matrixType)
1538 {
Jamie Madill437fa652016-05-03 15:13:24 -04001539 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001540 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001541 }
1542
1543 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001544}
1545
Jamie Madill893ab082014-05-16 16:56:10 -04001546bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1547{
1548 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1549 {
Jamie Madill437fa652016-05-03 15:13:24 -04001550 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001551 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001552 }
1553
Jamie Madill0af26e12015-03-05 19:54:33 -05001554 const Caps &caps = context->getCaps();
1555
Jamie Madill893ab082014-05-16 16:56:10 -04001556 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1557 {
1558 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1559
Jamie Madill0af26e12015-03-05 19:54:33 -05001560 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001561 {
Jamie Madill437fa652016-05-03 15:13:24 -04001562 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001563 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001564 }
1565 }
1566
1567 switch (pname)
1568 {
1569 case GL_TEXTURE_BINDING_2D:
1570 case GL_TEXTURE_BINDING_CUBE_MAP:
1571 case GL_TEXTURE_BINDING_3D:
1572 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001573 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001574 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1575 if (!context->getExtensions().eglStreamConsumerExternal)
1576 {
Jamie Madill437fa652016-05-03 15:13:24 -04001577 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001578 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1579 return false;
1580 }
1581 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001582
1583 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1584 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1585 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001586 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001587 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001588 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001589 {
Jamie Madill437fa652016-05-03 15:13:24 -04001590 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001591 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001592 }
1593
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001594 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001595 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001596 {
Jamie Madill437fa652016-05-03 15:13:24 -04001597 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001598 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001599 }
1600 }
1601 break;
1602
1603 default:
1604 break;
1605 }
1606
1607 // pname is valid, but there are no parameters to return
1608 if (numParams == 0)
1609 {
1610 return false;
1611 }
1612
1613 return true;
1614}
1615
Jamie Madillc29968b2016-01-20 11:17:23 -05001616bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1617 GLenum target,
1618 GLint level,
1619 GLenum internalformat,
1620 bool isSubImage,
1621 GLint xoffset,
1622 GLint yoffset,
1623 GLint zoffset,
1624 GLint x,
1625 GLint y,
1626 GLsizei width,
1627 GLsizei height,
1628 GLint border,
1629 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001630{
Jamie Madill560a8d82014-05-21 13:06:20 -04001631 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1632 {
Jamie Madill437fa652016-05-03 15:13:24 -04001633 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001634 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001635 }
1636
1637 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1638 {
Jamie Madill437fa652016-05-03 15:13:24 -04001639 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001640 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001641 }
1642
1643 if (border != 0)
1644 {
Jamie Madill437fa652016-05-03 15:13:24 -04001645 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001646 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001647 }
1648
1649 if (!ValidMipLevel(context, target, level))
1650 {
Jamie Madill437fa652016-05-03 15:13:24 -04001651 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001652 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001653 }
1654
Jamie Madillc29968b2016-01-20 11:17:23 -05001655 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001656 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001657 {
Jamie Madill437fa652016-05-03 15:13:24 -04001658 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001659 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001660 }
1661
Jamie Madillc29968b2016-01-20 11:17:23 -05001662 const auto &state = context->getState();
1663 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001664 {
Jamie Madill437fa652016-05-03 15:13:24 -04001665 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001666 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001667 }
1668
Geoff Langaae65a42014-05-26 12:43:44 -04001669 const gl::Caps &caps = context->getCaps();
1670
Geoff Langaae65a42014-05-26 12:43:44 -04001671 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001672 switch (target)
1673 {
1674 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001675 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001676 break;
1677
1678 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1679 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1680 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1681 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1682 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1683 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001684 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001685 break;
1686
1687 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001688 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001689 break;
1690
1691 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001692 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001693 break;
1694
1695 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001696 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001697 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001698 }
1699
Jamie Madillc29968b2016-01-20 11:17:23 -05001700 gl::Texture *texture =
1701 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001702 if (!texture)
1703 {
Jamie Madill437fa652016-05-03 15:13:24 -04001704 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001705 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001706 }
1707
Geoff Lang69cce582015-09-17 13:20:36 -04001708 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001709 {
Jamie Madill437fa652016-05-03 15:13:24 -04001710 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001711 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001712 }
1713
Geoff Lang5d601382014-07-22 15:14:06 -04001714 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1715
1716 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001717 {
Jamie Madill437fa652016-05-03 15:13:24 -04001718 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001719 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001720 }
1721
Geoff Langa9be0dc2014-12-17 12:34:40 -05001722 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001723 {
Jamie Madill437fa652016-05-03 15:13:24 -04001724 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001725 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001726 }
1727
1728 if (isSubImage)
1729 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001730 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1731 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1732 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001733 {
Jamie Madill437fa652016-05-03 15:13:24 -04001734 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001735 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001736 }
1737 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001738 else
1739 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001740 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001741 {
Jamie Madill437fa652016-05-03 15:13:24 -04001742 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001743 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001744 }
1745
Geoff Lang5d601382014-07-22 15:14:06 -04001746 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001747 {
Jamie Madill437fa652016-05-03 15:13:24 -04001748 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001749 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001750 }
1751
1752 int maxLevelDimension = (maxDimension >> level);
1753 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1754 {
Jamie Madill437fa652016-05-03 15:13:24 -04001755 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001756 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001757 }
1758 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001759
Geoff Langa9be0dc2014-12-17 12:34:40 -05001760 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001761 return true;
1762}
1763
Jamie Madillf25855c2015-11-03 11:06:18 -05001764static bool ValidateDrawBase(ValidationContext *context,
1765 GLenum mode,
1766 GLsizei count,
1767 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001768{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001769 switch (mode)
1770 {
1771 case GL_POINTS:
1772 case GL_LINES:
1773 case GL_LINE_LOOP:
1774 case GL_LINE_STRIP:
1775 case GL_TRIANGLES:
1776 case GL_TRIANGLE_STRIP:
1777 case GL_TRIANGLE_FAN:
1778 break;
1779 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001780 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001781 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001782 }
1783
Jamie Madill250d33f2014-06-06 17:09:03 -04001784 if (count < 0)
1785 {
Jamie Madill437fa652016-05-03 15:13:24 -04001786 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001787 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001788 }
1789
Geoff Langb1196682014-07-23 13:47:29 -04001790 const State &state = context->getState();
1791
Jamie Madill250d33f2014-06-06 17:09:03 -04001792 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001793 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001794 {
Jamie Madill437fa652016-05-03 15:13:24 -04001795 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001796 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001797 }
1798
Geoff Lang3a86ad32015-09-01 11:47:05 -04001799 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001800 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001801 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1802 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1803 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1804 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1805 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1806 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1807 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001808 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001809 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1810 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001811 {
1812 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1813 // Section 6.10 of the WebGL 1.0 spec
1814 ERR(
1815 "This ANGLE implementation does not support separate front/back stencil "
1816 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001817 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001818 return false;
1819 }
Jamie Madillac528012014-06-20 13:21:23 -04001820 }
1821
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001822 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001823 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001824 {
Jamie Madill437fa652016-05-03 15:13:24 -04001825 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001826 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001827 }
1828
Geoff Lang7dd2e102014-11-10 15:19:26 -05001829 gl::Program *program = state.getProgram();
1830 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001831 {
Jamie Madill437fa652016-05-03 15:13:24 -04001832 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001833 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001834 }
1835
Geoff Lang7dd2e102014-11-10 15:19:26 -05001836 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001837 {
Jamie Madill437fa652016-05-03 15:13:24 -04001838 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001839 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001840 }
1841
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001842 // Uniform buffer validation
1843 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1844 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001845 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001846 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001847 const OffsetBindingPointer<Buffer> &uniformBuffer =
1848 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001849
Geoff Lang5d124a62015-09-15 13:03:27 -04001850 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001851 {
1852 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001853 context->handleError(
1854 Error(GL_INVALID_OPERATION,
1855 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001856 return false;
1857 }
1858
Geoff Lang5d124a62015-09-15 13:03:27 -04001859 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001860 if (uniformBufferSize == 0)
1861 {
1862 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001863 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001864 }
1865
Jamie Madill62d31cb2015-09-11 13:25:51 -04001866 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001867 {
1868 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001869 context->handleError(
1870 Error(GL_INVALID_OPERATION,
1871 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001872 return false;
1873 }
1874 }
1875
Jamie Madill250d33f2014-06-06 17:09:03 -04001876 // No-op if zero count
1877 return (count > 0);
1878}
1879
Geoff Langb1196682014-07-23 13:47:29 -04001880bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001881{
Jamie Madillfd716582014-06-06 17:09:04 -04001882 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001883 {
Jamie Madill437fa652016-05-03 15:13:24 -04001884 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001885 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001886 }
1887
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001888 const State &state = context->getState();
1889 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001890 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1891 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001892 {
1893 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1894 // that does not match the current transform feedback object's draw mode (if transform feedback
1895 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001896 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001897 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001898 }
1899
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001900 if (!ValidateDrawBase(context, mode, count, primcount))
1901 {
1902 return false;
1903 }
1904
1905 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001906 {
1907 return false;
1908 }
1909
1910 return true;
1911}
1912
Geoff Langb1196682014-07-23 13:47:29 -04001913bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001914{
1915 if (primcount < 0)
1916 {
Jamie Madill437fa652016-05-03 15:13:24 -04001917 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001918 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001919 }
1920
Jamie Madill2b976812014-08-25 15:47:49 -04001921 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001922 {
1923 return false;
1924 }
1925
1926 // No-op if zero primitive count
1927 return (primcount > 0);
1928}
1929
Geoff Lang87a93302014-09-16 13:29:43 -04001930static bool ValidateDrawInstancedANGLE(Context *context)
1931{
1932 // Verify there is at least one active attribute with a divisor of zero
1933 const gl::State& state = context->getState();
1934
Geoff Lang7dd2e102014-11-10 15:19:26 -05001935 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001936
1937 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001938 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001939 {
1940 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001941 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001942 {
1943 return true;
1944 }
1945 }
1946
Jamie Madill437fa652016-05-03 15:13:24 -04001947 context->handleError(Error(GL_INVALID_OPERATION,
1948 "ANGLE_instanced_arrays requires that at least one active attribute"
1949 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001950 return false;
1951}
1952
1953bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1954{
1955 if (!ValidateDrawInstancedANGLE(context))
1956 {
1957 return false;
1958 }
1959
1960 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1961}
1962
Jamie Madillf25855c2015-11-03 11:06:18 -05001963bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001964 GLenum mode,
1965 GLsizei count,
1966 GLenum type,
1967 const GLvoid *indices,
1968 GLsizei primcount,
1969 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001970{
Jamie Madill250d33f2014-06-06 17:09:03 -04001971 switch (type)
1972 {
1973 case GL_UNSIGNED_BYTE:
1974 case GL_UNSIGNED_SHORT:
1975 break;
1976 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001977 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001978 {
Jamie Madill437fa652016-05-03 15:13:24 -04001979 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001980 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001981 }
1982 break;
1983 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001984 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001985 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001986 }
1987
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001988 const State &state = context->getState();
1989
1990 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001991 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001992 {
1993 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1994 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001995 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001996 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001997 }
1998
1999 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002000 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002001 {
Jamie Madill437fa652016-05-03 15:13:24 -04002002 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002003 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002004 }
2005
Jamie Madill2b976812014-08-25 15:47:49 -04002006 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002007 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002008 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002009 {
Jamie Madill437fa652016-05-03 15:13:24 -04002010 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002011 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002012 }
2013
Jamie Madillae3000b2014-08-25 15:47:51 -04002014 if (elementArrayBuffer)
2015 {
2016 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2017
2018 GLint64 offset = reinterpret_cast<GLint64>(indices);
2019 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2020
2021 // check for integer overflows
2022 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2023 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2024 {
Jamie Madill437fa652016-05-03 15:13:24 -04002025 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002026 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002027 }
2028
2029 // Check for reading past the end of the bound buffer object
2030 if (byteCount > elementArrayBuffer->getSize())
2031 {
Jamie Madill437fa652016-05-03 15:13:24 -04002032 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002033 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002034 }
2035 }
2036 else if (!indices)
2037 {
2038 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002039 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002040 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002041 }
2042
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002043 if (!ValidateDrawBase(context, mode, count, primcount))
2044 {
2045 return false;
2046 }
2047
Jamie Madill2b976812014-08-25 15:47:49 -04002048 // Use max index to validate if our vertex buffers are large enough for the pull.
2049 // TODO: offer fast path, with disabled index validation.
2050 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2051 if (elementArrayBuffer)
2052 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002053 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002054 Error error =
2055 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2056 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002057 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002058 {
Jamie Madill437fa652016-05-03 15:13:24 -04002059 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002060 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002061 }
2062 }
2063 else
2064 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002065 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002066 }
2067
Jamie Madille79b1e12015-11-04 16:36:37 -05002068 // If we use an index greater than our maximum supported index range, return an error.
2069 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2070 // return an error if possible here.
2071 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2072 {
Jamie Madill437fa652016-05-03 15:13:24 -04002073 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002074 return false;
2075 }
2076
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002077 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002078 {
2079 return false;
2080 }
2081
Geoff Lang3edfe032015-09-04 16:38:24 -04002082 // No op if there are no real indices in the index data (all are primitive restart).
2083 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002084}
2085
Geoff Langb1196682014-07-23 13:47:29 -04002086bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002087 GLenum mode,
2088 GLsizei count,
2089 GLenum type,
2090 const GLvoid *indices,
2091 GLsizei primcount,
2092 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002093{
2094 if (primcount < 0)
2095 {
Jamie Madill437fa652016-05-03 15:13:24 -04002096 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002097 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002098 }
2099
Jamie Madill2b976812014-08-25 15:47:49 -04002100 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002101 {
2102 return false;
2103 }
2104
2105 // No-op zero primitive count
2106 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002107}
2108
Geoff Lang3edfe032015-09-04 16:38:24 -04002109bool ValidateDrawElementsInstancedANGLE(Context *context,
2110 GLenum mode,
2111 GLsizei count,
2112 GLenum type,
2113 const GLvoid *indices,
2114 GLsizei primcount,
2115 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002116{
2117 if (!ValidateDrawInstancedANGLE(context))
2118 {
2119 return false;
2120 }
2121
2122 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2123}
2124
Geoff Langb1196682014-07-23 13:47:29 -04002125bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002126 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002127{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002128 if (!ValidFramebufferTarget(target))
2129 {
Jamie Madill437fa652016-05-03 15:13:24 -04002130 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002131 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002132 }
2133
2134 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002135 {
2136 return false;
2137 }
2138
Jamie Madill55ec3b12014-07-03 10:38:57 -04002139 if (texture != 0)
2140 {
2141 gl::Texture *tex = context->getTexture(texture);
2142
2143 if (tex == NULL)
2144 {
Jamie Madill437fa652016-05-03 15:13:24 -04002145 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002146 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002147 }
2148
2149 if (level < 0)
2150 {
Jamie Madill437fa652016-05-03 15:13:24 -04002151 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002152 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002153 }
2154 }
2155
Shannon Woods53a94a82014-06-24 15:20:36 -04002156 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002157 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002158
Jamie Madill84115c92015-04-23 15:00:07 -04002159 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002160 {
Jamie Madill437fa652016-05-03 15:13:24 -04002161 context->handleError(
2162 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002163 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002164 }
2165
2166 return true;
2167}
2168
Geoff Langb1196682014-07-23 13:47:29 -04002169bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002170 GLenum textarget, GLuint texture, GLint level)
2171{
Geoff Lang95663912015-04-02 15:54:45 -04002172 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2173 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002174 {
Jamie Madill437fa652016-05-03 15:13:24 -04002175 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002176 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002177 }
2178
2179 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002180 {
2181 return false;
2182 }
2183
Jamie Madill55ec3b12014-07-03 10:38:57 -04002184 if (texture != 0)
2185 {
2186 gl::Texture *tex = context->getTexture(texture);
2187 ASSERT(tex);
2188
Jamie Madill2a6564e2014-07-11 09:53:19 -04002189 const gl::Caps &caps = context->getCaps();
2190
Jamie Madill55ec3b12014-07-03 10:38:57 -04002191 switch (textarget)
2192 {
2193 case GL_TEXTURE_2D:
2194 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002195 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002196 {
Jamie Madill437fa652016-05-03 15:13:24 -04002197 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002198 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002199 }
2200 if (tex->getTarget() != GL_TEXTURE_2D)
2201 {
Jamie Madill437fa652016-05-03 15:13:24 -04002202 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002203 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002204 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002205 }
2206 break;
2207
2208 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2209 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2210 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2211 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2212 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2213 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2214 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002215 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002216 {
Jamie Madill437fa652016-05-03 15:13:24 -04002217 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002218 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002219 }
2220 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2221 {
Jamie Madill437fa652016-05-03 15:13:24 -04002222 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002223 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002224 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002225 }
2226 break;
2227
2228 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002229 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002230 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002231 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002232
2233 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2234 if (internalFormatInfo.compressed)
2235 {
Jamie Madill437fa652016-05-03 15:13:24 -04002236 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002237 return false;
2238 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002239 }
2240
Jamie Madill570f7c82014-07-03 10:38:54 -04002241 return true;
2242}
2243
Geoff Langb1196682014-07-23 13:47:29 -04002244bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002245{
2246 if (program == 0)
2247 {
Jamie Madill437fa652016-05-03 15:13:24 -04002248 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002249 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002250 }
2251
Dian Xiang769769a2015-09-09 15:20:08 -07002252 gl::Program *programObject = GetValidProgram(context, program);
2253 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002254 {
2255 return false;
2256 }
2257
Jamie Madill0063c512014-08-25 15:47:53 -04002258 if (!programObject || !programObject->isLinked())
2259 {
Jamie Madill437fa652016-05-03 15:13:24 -04002260 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002261 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002262 }
2263
Geoff Lang7dd2e102014-11-10 15:19:26 -05002264 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002265 {
Jamie Madill437fa652016-05-03 15:13:24 -04002266 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002267 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002268 }
2269
Jamie Madill0063c512014-08-25 15:47:53 -04002270 return true;
2271}
2272
Geoff Langb1196682014-07-23 13:47:29 -04002273bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002274{
2275 return ValidateGetUniformBase(context, program, location);
2276}
2277
Geoff Langb1196682014-07-23 13:47:29 -04002278bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002279{
Jamie Madill78f41802014-08-25 15:47:55 -04002280 return ValidateGetUniformBase(context, program, location);
2281}
2282
Geoff Langb1196682014-07-23 13:47:29 -04002283static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002284{
2285 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002286 {
Jamie Madill78f41802014-08-25 15:47:55 -04002287 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002288 }
2289
Jamie Madilla502c742014-08-28 17:19:13 -04002290 gl::Program *programObject = context->getProgram(program);
2291 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002292
Jamie Madill78f41802014-08-25 15:47:55 -04002293 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002294 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2295 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002296 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002297 {
Jamie Madill437fa652016-05-03 15:13:24 -04002298 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002299 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002300 }
2301
2302 return true;
2303}
2304
Geoff Langb1196682014-07-23 13:47:29 -04002305bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002306{
Jamie Madill78f41802014-08-25 15:47:55 -04002307 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002308}
2309
Geoff Langb1196682014-07-23 13:47:29 -04002310bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002311{
Jamie Madill78f41802014-08-25 15:47:55 -04002312 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002313}
2314
Austin Kinross08332632015-05-05 13:35:47 -07002315bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2316 const GLenum *attachments, bool defaultFramebuffer)
2317{
2318 if (numAttachments < 0)
2319 {
Jamie Madill437fa652016-05-03 15:13:24 -04002320 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002321 return false;
2322 }
2323
2324 for (GLsizei i = 0; i < numAttachments; ++i)
2325 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002326 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002327 {
2328 if (defaultFramebuffer)
2329 {
Jamie Madill437fa652016-05-03 15:13:24 -04002330 context->handleError(Error(
2331 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002332 return false;
2333 }
2334
2335 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2336 {
Jamie Madill437fa652016-05-03 15:13:24 -04002337 context->handleError(Error(GL_INVALID_OPERATION,
2338 "Requested color attachment is greater than the maximum "
2339 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002340 return false;
2341 }
2342 }
2343 else
2344 {
2345 switch (attachments[i])
2346 {
2347 case GL_DEPTH_ATTACHMENT:
2348 case GL_STENCIL_ATTACHMENT:
2349 case GL_DEPTH_STENCIL_ATTACHMENT:
2350 if (defaultFramebuffer)
2351 {
Jamie Madill437fa652016-05-03 15:13:24 -04002352 context->handleError(
2353 Error(GL_INVALID_ENUM,
2354 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002355 return false;
2356 }
2357 break;
2358 case GL_COLOR:
2359 case GL_DEPTH:
2360 case GL_STENCIL:
2361 if (!defaultFramebuffer)
2362 {
Jamie Madill437fa652016-05-03 15:13:24 -04002363 context->handleError(
2364 Error(GL_INVALID_ENUM,
2365 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002366 return false;
2367 }
2368 break;
2369 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002370 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002371 return false;
2372 }
2373 }
2374 }
2375
2376 return true;
2377}
2378
Austin Kinross6ee1e782015-05-29 17:05:37 -07002379bool ValidateInsertEventMarkerEXT(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 (marker == nullptr)
2389 {
2390 return false;
2391 }
2392
2393 return true;
2394}
2395
2396bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2397{
2398 // Note that debug marker calls must not set error state
2399
2400 if (length < 0)
2401 {
2402 return false;
2403 }
2404
2405 if (length > 0 && marker == nullptr)
2406 {
2407 return false;
2408 }
2409
2410 return true;
2411}
2412
Geoff Langdcab33b2015-07-21 13:03:16 -04002413bool ValidateEGLImageTargetTexture2DOES(Context *context,
2414 egl::Display *display,
2415 GLenum target,
2416 egl::Image *image)
2417{
Geoff Langa8406172015-07-21 16:53:39 -04002418 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2419 {
Jamie Madill437fa652016-05-03 15:13:24 -04002420 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002421 return false;
2422 }
2423
2424 switch (target)
2425 {
2426 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002427 if (!context->getExtensions().eglImage)
2428 {
2429 context->handleError(Error(
2430 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2431 }
2432 break;
2433
2434 case GL_TEXTURE_EXTERNAL_OES:
2435 if (!context->getExtensions().eglImageExternal)
2436 {
2437 context->handleError(Error(
2438 GL_INVALID_ENUM,
2439 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2440 }
Geoff Langa8406172015-07-21 16:53:39 -04002441 break;
2442
2443 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002444 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002445 return false;
2446 }
2447
2448 if (!display->isValidImage(image))
2449 {
Jamie Madill437fa652016-05-03 15:13:24 -04002450 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002451 return false;
2452 }
2453
2454 if (image->getSamples() > 0)
2455 {
Jamie Madill437fa652016-05-03 15:13:24 -04002456 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002457 "cannot create a 2D texture from a multisampled EGL image."));
2458 return false;
2459 }
2460
2461 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2462 if (!textureCaps.texturable)
2463 {
Jamie Madill437fa652016-05-03 15:13:24 -04002464 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002465 "EGL image internal format is not supported as a texture."));
2466 return false;
2467 }
2468
Geoff Langdcab33b2015-07-21 13:03:16 -04002469 return true;
2470}
2471
2472bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2473 egl::Display *display,
2474 GLenum target,
2475 egl::Image *image)
2476{
Geoff Langa8406172015-07-21 16:53:39 -04002477 if (!context->getExtensions().eglImage)
2478 {
Jamie Madill437fa652016-05-03 15:13:24 -04002479 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002480 return false;
2481 }
2482
2483 switch (target)
2484 {
2485 case GL_RENDERBUFFER:
2486 break;
2487
2488 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002489 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002490 return false;
2491 }
2492
2493 if (!display->isValidImage(image))
2494 {
Jamie Madill437fa652016-05-03 15:13:24 -04002495 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002496 return false;
2497 }
2498
2499 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2500 if (!textureCaps.renderable)
2501 {
Jamie Madill437fa652016-05-03 15:13:24 -04002502 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002503 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2504 return false;
2505 }
2506
Geoff Langdcab33b2015-07-21 13:03:16 -04002507 return true;
2508}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002509
2510bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2511{
Geoff Lang36167ab2015-12-07 10:27:14 -05002512 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002513 {
2514 // The default VAO should always exist
2515 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002516 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002517 return false;
2518 }
2519
2520 return true;
2521}
2522
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002523bool ValidateLinkProgram(Context *context, GLuint program)
2524{
2525 if (context->hasActiveTransformFeedback(program))
2526 {
2527 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002528 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002529 "Cannot link program while program is associated with an active "
2530 "transform feedback object."));
2531 return false;
2532 }
2533 return true;
2534}
2535
Geoff Langc5629752015-12-07 16:29:04 -05002536bool ValidateProgramBinaryBase(Context *context,
2537 GLuint program,
2538 GLenum binaryFormat,
2539 const void *binary,
2540 GLint length)
2541{
2542 Program *programObject = GetValidProgram(context, program);
2543 if (programObject == nullptr)
2544 {
2545 return false;
2546 }
2547
2548 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2549 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2550 programBinaryFormats.end())
2551 {
Jamie Madill437fa652016-05-03 15:13:24 -04002552 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002553 return false;
2554 }
2555
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002556 if (context->hasActiveTransformFeedback(program))
2557 {
2558 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002559 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002560 "Cannot change program binary while program is associated with "
2561 "an active transform feedback object."));
2562 return false;
2563 }
2564
Geoff Langc5629752015-12-07 16:29:04 -05002565 return true;
2566}
2567
2568bool ValidateGetProgramBinaryBase(Context *context,
2569 GLuint program,
2570 GLsizei bufSize,
2571 GLsizei *length,
2572 GLenum *binaryFormat,
2573 void *binary)
2574{
2575 Program *programObject = GetValidProgram(context, program);
2576 if (programObject == nullptr)
2577 {
2578 return false;
2579 }
2580
2581 if (!programObject->isLinked())
2582 {
Jamie Madill437fa652016-05-03 15:13:24 -04002583 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002584 return false;
2585 }
2586
2587 return true;
2588}
Jamie Madillc29968b2016-01-20 11:17:23 -05002589
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002590bool ValidateUseProgram(Context *context, GLuint program)
2591{
2592 if (program != 0)
2593 {
2594 Program *programObject = context->getProgram(program);
2595 if (!programObject)
2596 {
2597 // ES 3.1.0 section 7.3 page 72
2598 if (context->getShader(program))
2599 {
Jamie Madill437fa652016-05-03 15:13:24 -04002600 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002601 Error(GL_INVALID_OPERATION,
2602 "Attempted to use a single shader instead of a shader program."));
2603 return false;
2604 }
2605 else
2606 {
Jamie Madill437fa652016-05-03 15:13:24 -04002607 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002608 return false;
2609 }
2610 }
2611 if (!programObject->isLinked())
2612 {
Jamie Madill437fa652016-05-03 15:13:24 -04002613 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002614 return false;
2615 }
2616 }
2617 if (context->getState().isTransformFeedbackActiveUnpaused())
2618 {
2619 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002620 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002621 Error(GL_INVALID_OPERATION,
2622 "Cannot change active program while transform feedback is unpaused."));
2623 return false;
2624 }
2625
2626 return true;
2627}
2628
Jamie Madillc29968b2016-01-20 11:17:23 -05002629bool ValidateCopyTexImage2D(ValidationContext *context,
2630 GLenum target,
2631 GLint level,
2632 GLenum internalformat,
2633 GLint x,
2634 GLint y,
2635 GLsizei width,
2636 GLsizei height,
2637 GLint border)
2638{
2639 if (context->getClientVersion() < 3)
2640 {
2641 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2642 0, x, y, width, height, border);
2643 }
2644
2645 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002646 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2647 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002648}
Jamie Madillc29968b2016-01-20 11:17:23 -05002649
2650bool ValidateFramebufferRenderbuffer(Context *context,
2651 GLenum target,
2652 GLenum attachment,
2653 GLenum renderbuffertarget,
2654 GLuint renderbuffer)
2655{
2656 if (!ValidFramebufferTarget(target) ||
2657 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2658 {
Jamie Madill437fa652016-05-03 15:13:24 -04002659 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002660 return false;
2661 }
2662
2663 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2664 renderbuffertarget, renderbuffer);
2665}
2666
2667bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2668{
2669 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2670 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2671 {
Jamie Madill437fa652016-05-03 15:13:24 -04002672 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002673 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2674 return false;
2675 }
2676
2677 ASSERT(context->getState().getDrawFramebuffer());
2678 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2679 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2680
2681 // This should come first before the check for the default frame buffer
2682 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2683 // rather than INVALID_OPERATION
2684 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2685 {
2686 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2687
2688 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002689 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2690 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002691 {
2692 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002693 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2694 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2695 // 3.1 is still a bit ambiguous about the error, but future specs are
2696 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002697 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002698 return false;
2699 }
2700 else if (bufs[colorAttachment] >= maxColorAttachment)
2701 {
Jamie Madill437fa652016-05-03 15:13:24 -04002702 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002703 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002704 return false;
2705 }
2706 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2707 frameBufferId != 0)
2708 {
2709 // INVALID_OPERATION-GL is bound to buffer and ith argument
2710 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002711 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002712 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2713 return false;
2714 }
2715 }
2716
2717 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2718 // and n is not 1 or bufs is bound to value other than BACK and NONE
2719 if (frameBufferId == 0)
2720 {
2721 if (n != 1)
2722 {
Jamie Madill437fa652016-05-03 15:13:24 -04002723 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002724 "n must be 1 when GL is bound to the default framebuffer"));
2725 return false;
2726 }
2727
2728 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2729 {
Jamie Madill437fa652016-05-03 15:13:24 -04002730 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002731 GL_INVALID_OPERATION,
2732 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2733 return false;
2734 }
2735 }
2736
2737 return true;
2738}
2739
2740bool ValidateCopyTexSubImage2D(Context *context,
2741 GLenum target,
2742 GLint level,
2743 GLint xoffset,
2744 GLint yoffset,
2745 GLint x,
2746 GLint y,
2747 GLsizei width,
2748 GLsizei height)
2749{
2750 if (context->getClientVersion() < 3)
2751 {
2752 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2753 yoffset, x, y, width, height, 0);
2754 }
2755
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002756 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2757 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002758}
2759
Olli Etuaho4f667482016-03-30 15:56:35 +03002760bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2761{
2762 if (!ValidBufferTarget(context, target))
2763 {
Jamie Madill437fa652016-05-03 15:13:24 -04002764 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002765 return false;
2766 }
2767
2768 if (pname != GL_BUFFER_MAP_POINTER)
2769 {
Jamie Madill437fa652016-05-03 15:13:24 -04002770 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002771 return false;
2772 }
2773
2774 Buffer *buffer = context->getState().getTargetBuffer(target);
2775
2776 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2777 // target bound to zero generate an INVALID_OPERATION error."
2778 // GLES 3.1 section 6.6 explicitly specifies this error.
2779 if (!buffer)
2780 {
Jamie Madill437fa652016-05-03 15:13:24 -04002781 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002782 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2783 return false;
2784 }
2785
2786 return true;
2787}
2788
2789bool ValidateUnmapBufferBase(Context *context, GLenum target)
2790{
2791 if (!ValidBufferTarget(context, target))
2792 {
Jamie Madill437fa652016-05-03 15:13:24 -04002793 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002794 return false;
2795 }
2796
2797 Buffer *buffer = context->getState().getTargetBuffer(target);
2798
2799 if (buffer == nullptr || !buffer->isMapped())
2800 {
Jamie Madill437fa652016-05-03 15:13:24 -04002801 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002802 return false;
2803 }
2804
2805 return true;
2806}
2807
2808bool ValidateMapBufferRangeBase(Context *context,
2809 GLenum target,
2810 GLintptr offset,
2811 GLsizeiptr length,
2812 GLbitfield access)
2813{
2814 if (!ValidBufferTarget(context, target))
2815 {
Jamie Madill437fa652016-05-03 15:13:24 -04002816 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002817 return false;
2818 }
2819
2820 if (offset < 0 || length < 0)
2821 {
Jamie Madill437fa652016-05-03 15:13:24 -04002822 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002823 return false;
2824 }
2825
2826 Buffer *buffer = context->getState().getTargetBuffer(target);
2827
2828 if (!buffer)
2829 {
Jamie Madill437fa652016-05-03 15:13:24 -04002830 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002831 return false;
2832 }
2833
2834 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002835 CheckedNumeric<size_t> checkedOffset(offset);
2836 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002837
Jamie Madille2e406c2016-06-02 13:04:10 -04002838 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002839 {
Jamie Madill437fa652016-05-03 15:13:24 -04002840 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002841 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2842 return false;
2843 }
2844
2845 // Check for invalid bits in the mask
2846 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2847 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2848 GL_MAP_UNSYNCHRONIZED_BIT;
2849
2850 if (access & ~(allAccessBits))
2851 {
Jamie Madill437fa652016-05-03 15:13:24 -04002852 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002853 return false;
2854 }
2855
2856 if (length == 0)
2857 {
Jamie Madill437fa652016-05-03 15:13:24 -04002858 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002859 return false;
2860 }
2861
2862 if (buffer->isMapped())
2863 {
Jamie Madill437fa652016-05-03 15:13:24 -04002864 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002865 return false;
2866 }
2867
2868 // Check for invalid bit combinations
2869 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2870 {
Jamie Madill437fa652016-05-03 15:13:24 -04002871 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002872 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2873 return false;
2874 }
2875
2876 GLbitfield writeOnlyBits =
2877 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2878
2879 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2880 {
Jamie Madill437fa652016-05-03 15:13:24 -04002881 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002882 "Invalid access bits when mapping buffer for reading: 0x%X.",
2883 access));
2884 return false;
2885 }
2886
2887 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2888 {
Jamie Madill437fa652016-05-03 15:13:24 -04002889 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002890 GL_INVALID_OPERATION,
2891 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2892 return false;
2893 }
2894 return true;
2895}
2896
2897bool ValidateFlushMappedBufferRangeBase(Context *context,
2898 GLenum target,
2899 GLintptr offset,
2900 GLsizeiptr length)
2901{
2902 if (offset < 0 || length < 0)
2903 {
Jamie Madill437fa652016-05-03 15:13:24 -04002904 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002905 return false;
2906 }
2907
2908 if (!ValidBufferTarget(context, target))
2909 {
Jamie Madill437fa652016-05-03 15:13:24 -04002910 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002911 return false;
2912 }
2913
2914 Buffer *buffer = context->getState().getTargetBuffer(target);
2915
2916 if (buffer == nullptr)
2917 {
Jamie Madill437fa652016-05-03 15:13:24 -04002918 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002919 return false;
2920 }
2921
2922 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2923 {
Jamie Madill437fa652016-05-03 15:13:24 -04002924 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002925 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2926 return false;
2927 }
2928
2929 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002930 CheckedNumeric<size_t> checkedOffset(offset);
2931 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002932
Jamie Madille2e406c2016-06-02 13:04:10 -04002933 if (!checkedSize.IsValid() ||
2934 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002935 {
Jamie Madill437fa652016-05-03 15:13:24 -04002936 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002937 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2938 return false;
2939 }
2940
2941 return true;
2942}
2943
Olli Etuaho0f2b1562016-05-13 16:15:35 +03002944bool ValidateGenerateMipmap(Context *context, GLenum target)
2945{
2946 if (!ValidTextureTarget(context, target))
2947 {
2948 context->handleError(Error(GL_INVALID_ENUM));
2949 return false;
2950 }
2951
2952 Texture *texture = context->getTargetTexture(target);
2953
2954 if (texture == nullptr)
2955 {
2956 context->handleError(Error(GL_INVALID_OPERATION));
2957 return false;
2958 }
2959
2960 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
2961
2962 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
2963 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
2964 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2965 {
2966 context->handleError(Error(GL_INVALID_OPERATION));
2967 return false;
2968 }
2969
2970 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
2971 GLenum internalFormat = texture->getInternalFormat(baseTarget, effectiveBaseLevel);
2972 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
2973 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
2974
2975 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
2976 // unsized formats or that are color renderable and filterable. Since we do not track if
2977 // the texture was created with sized or unsized format (only sized formats are stored),
2978 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
2979 // be able to) because they aren't color renderable. Simply do a special case for LUMA
2980 // textures since they're the only texture format that can be created with unsized formats
2981 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
2982 // was the last version to use add them.
2983 bool isLUMA = internalFormat == GL_LUMINANCE8_EXT ||
2984 internalFormat == GL_LUMINANCE8_ALPHA8_EXT || internalFormat == GL_ALPHA8_EXT;
2985
2986 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable ||
2987 (!formatCaps.renderable && !isLUMA) || formatInfo.compressed)
2988 {
2989 context->handleError(Error(GL_INVALID_OPERATION));
2990 return false;
2991 }
2992
2993 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
2994 if (context->getClientVersion() == 2 && formatInfo.colorEncoding == GL_SRGB)
2995 {
2996 context->handleError(Error(GL_INVALID_OPERATION));
2997 return false;
2998 }
2999
3000 // Non-power of 2 ES2 check
3001 if (!context->getExtensions().textureNPOT &&
3002 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3003 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3004 {
3005 ASSERT(context->getClientVersion() <= 2 &&
3006 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3007 context->handleError(Error(GL_INVALID_OPERATION));
3008 return false;
3009 }
3010
3011 // Cube completeness check
3012 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3013 {
3014 context->handleError(Error(GL_INVALID_OPERATION));
3015 return false;
3016 }
3017
3018 return true;
3019}
3020
Olli Etuaho41997e72016-03-10 13:38:39 +02003021bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3022{
3023 return ValidateGenOrDelete(context, n);
3024}
3025
3026bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3027{
3028 return ValidateGenOrDelete(context, n);
3029}
3030
3031bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3032{
3033 return ValidateGenOrDelete(context, n);
3034}
3035
3036bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3037{
3038 return ValidateGenOrDelete(context, n);
3039}
3040
3041bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3042{
3043 return ValidateGenOrDelete(context, n);
3044}
3045
3046bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3047{
3048 return ValidateGenOrDelete(context, n);
3049}
3050
3051bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3052{
3053 return ValidateGenOrDelete(context, n);
3054}
3055
3056bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3057{
3058 return ValidateGenOrDelete(context, n);
3059}
3060
3061bool ValidateGenOrDelete(Context *context, GLint n)
3062{
3063 if (n < 0)
3064 {
Jamie Madill437fa652016-05-03 15:13:24 -04003065 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003066 return false;
3067 }
3068 return true;
3069}
3070
Jamie Madillc29968b2016-01-20 11:17:23 -05003071} // namespace gl