blob: 52c5e5b481f3c7eb56e48dff63fd5c10ad09c211 [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{
Jamie Madilldfde6ab2016-06-09 07:07:18 -070039 const gl::State &state = context->getGLState();
Jamie Madill1ca74672015-07-21 15:14:11 -040040 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
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700540 GLuint handle = context->getGLState().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
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700590 gl::Framebuffer *framebuffer = context->getGLState().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 Madilldfde6ab2016-06-09 07:07:18 -0700621bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500622 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
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700665 const auto &glState = context->getGLState();
666 const gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
667 const gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500668
669 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670 {
Jamie Madill437fa652016-05-03 15:13:24 -0400671 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400672 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 }
674
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700675 if (readFramebuffer->id() == drawFramebuffer->id())
676 {
677 context->handleError(Error(GL_INVALID_OPERATION));
678 return false;
679 }
680
681 if (!readFramebuffer->checkStatus(context->getContextState()))
Jamie Madill48faf802014-11-06 15:27:22 -0500682 {
Jamie Madill437fa652016-05-03 15:13:24 -0400683 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500684 return false;
685 }
686
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700687 if (!drawFramebuffer->checkStatus(context->getContextState()))
Jamie Madill48faf802014-11-06 15:27:22 -0500688 {
Jamie Madill437fa652016-05-03 15:13:24 -0400689 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500690 return false;
691 }
692
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700693 if (drawFramebuffer->getSamples(context->getContextState()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694 {
Jamie Madill437fa652016-05-03 15:13:24 -0400695 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400696 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697 }
698
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400699 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
700
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400701 if (mask & GL_COLOR_BUFFER_BIT)
702 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400703 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
704 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500705 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400706
707 if (readColorBuffer && drawColorBuffer)
708 {
Geoff Langd8a22582014-12-17 15:28:23 -0500709 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400710 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400711
Geoff Langa15472a2015-08-11 11:48:03 -0400712 for (size_t drawbufferIdx = 0;
713 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400714 {
Geoff Langa15472a2015-08-11 11:48:03 -0400715 const FramebufferAttachment *attachment =
716 drawFramebuffer->getDrawBuffer(drawbufferIdx);
717 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400718 {
Geoff Langa15472a2015-08-11 11:48:03 -0400719 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400720 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400721
Geoff Langb2f3d052013-08-13 12:49:27 -0400722 // The GL ES 3.0.2 spec (pg 193) states that:
723 // 1) If the read buffer is fixed point format, the draw buffer must be as well
724 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
725 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500726 // Changes with EXT_color_buffer_float:
727 // Case 1) is changed to fixed point OR floating point
728 GLenum readComponentType = readFormatInfo.componentType;
729 GLenum drawComponentType = drawFormatInfo.componentType;
730 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
731 readComponentType == GL_SIGNED_NORMALIZED);
732 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
733 drawComponentType == GL_SIGNED_NORMALIZED);
734
735 if (extensions.colorBufferFloat)
736 {
737 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
738 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
739
740 if (readFixedOrFloat != drawFixedOrFloat)
741 {
Jamie Madill437fa652016-05-03 15:13:24 -0400742 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500743 "If the read buffer contains fixed-point or "
744 "floating-point values, the draw buffer "
745 "must as well."));
746 return false;
747 }
748 }
749 else if (readFixedPoint != drawFixedPoint)
750 {
Jamie Madill437fa652016-05-03 15:13:24 -0400751 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500752 "If the read buffer contains fixed-point "
753 "values, the draw buffer must as well."));
754 return false;
755 }
756
757 if (readComponentType == GL_UNSIGNED_INT &&
758 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 {
Jamie Madill437fa652016-05-03 15:13:24 -0400760 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400761 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 }
763
Jamie Madill6163c752015-12-07 16:32:59 -0500764 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400765 {
Jamie Madill437fa652016-05-03 15:13:24 -0400766 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400767 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 }
769
Geoff Langb2f3d052013-08-13 12:49:27 -0400770 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 {
Jamie Madill437fa652016-05-03 15:13:24 -0400772 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400773 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 }
775 }
776 }
777
Geoff Lang5d601382014-07-22 15:14:06 -0400778 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400779 {
Jamie Madill437fa652016-05-03 15:13:24 -0400780 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400781 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400782 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400783 }
784 }
785
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200786 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
787 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
788 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400789 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200790 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400792 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
793 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400794
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200795 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796 {
Geoff Langd8a22582014-12-17 15:28:23 -0500797 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798 {
Jamie Madill437fa652016-05-03 15:13:24 -0400799 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400800 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400801 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400802
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200803 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400804 {
Jamie Madill437fa652016-05-03 15:13:24 -0400805 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400806 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400807 }
808 }
809 }
810 }
811
812 return true;
813}
814
Geoff Langb1196682014-07-23 13:47:29 -0400815bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400816{
817 switch (pname)
818 {
819 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
820 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
821 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
822 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
823 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
824 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
825 case GL_CURRENT_VERTEX_ATTRIB:
826 return true;
827
828 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
829 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
830 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400831 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
832 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400833 return true;
834
835 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400836 if (context->getClientVersion() < 3)
837 {
Jamie Madill437fa652016-05-03 15:13:24 -0400838 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400839 return false;
840 }
841 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400842
843 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400844 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400845 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846 }
847}
848
Ian Ewellbda75592016-04-18 17:25:54 -0400849bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400850{
851 switch (pname)
852 {
853 case GL_TEXTURE_WRAP_R:
854 case GL_TEXTURE_SWIZZLE_R:
855 case GL_TEXTURE_SWIZZLE_G:
856 case GL_TEXTURE_SWIZZLE_B:
857 case GL_TEXTURE_SWIZZLE_A:
858 case GL_TEXTURE_BASE_LEVEL:
859 case GL_TEXTURE_MAX_LEVEL:
860 case GL_TEXTURE_COMPARE_MODE:
861 case GL_TEXTURE_COMPARE_FUNC:
862 case GL_TEXTURE_MIN_LOD:
863 case GL_TEXTURE_MAX_LOD:
Geoff Langb66a9092016-05-16 15:59:14 -0400864 if (context->getClientVersion() < 3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400865 {
Jamie Madill437fa652016-05-03 15:13:24 -0400866 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400867 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400868 }
Geoff Langb66a9092016-05-16 15:59:14 -0400869 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
870 {
871 context->handleError(Error(GL_INVALID_ENUM,
872 "ES3 texture parameters are not available without "
873 "GL_OES_EGL_image_external_essl3."));
874 return false;
875 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400876 break;
877
878 default: break;
879 }
880
881 switch (pname)
882 {
883 case GL_TEXTURE_WRAP_S:
884 case GL_TEXTURE_WRAP_T:
885 case GL_TEXTURE_WRAP_R:
886 switch (param)
887 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000888 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400889 return true;
890 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400891 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300892 if (target == GL_TEXTURE_EXTERNAL_OES)
893 {
894 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400895 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300896 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
897 return false;
898 }
899 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400900 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400901 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400902 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400903 }
904
905 case GL_TEXTURE_MIN_FILTER:
906 switch (param)
907 {
908 case GL_NEAREST:
909 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400910 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400911 case GL_NEAREST_MIPMAP_NEAREST:
912 case GL_LINEAR_MIPMAP_NEAREST:
913 case GL_NEAREST_MIPMAP_LINEAR:
914 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300915 if (target == GL_TEXTURE_EXTERNAL_OES)
916 {
917 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400918 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300919 Error(GL_INVALID_ENUM,
920 "external textures only support NEAREST and LINEAR filtering"));
921 return false;
922 }
923 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400924 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400925 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400926 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400927 }
928 break;
929
930 case GL_TEXTURE_MAG_FILTER:
931 switch (param)
932 {
933 case GL_NEAREST:
934 case GL_LINEAR:
935 return true;
936 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400937 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400938 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 }
940 break;
941
942 case GL_TEXTURE_USAGE_ANGLE:
943 switch (param)
944 {
945 case GL_NONE:
946 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
947 return true;
948 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400949 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400950 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400951 }
952 break;
953
954 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400955 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400956 {
Jamie Madill437fa652016-05-03 15:13:24 -0400957 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400958 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400959 }
960
961 // we assume the parameter passed to this validation method is truncated, not rounded
962 if (param < 1)
963 {
Jamie Madill437fa652016-05-03 15:13:24 -0400964 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400965 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400966 }
967 return true;
968
969 case GL_TEXTURE_MIN_LOD:
970 case GL_TEXTURE_MAX_LOD:
971 // any value is permissible
972 return true;
973
974 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400975 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400976 switch (param)
977 {
978 case GL_NONE:
979 case GL_COMPARE_REF_TO_TEXTURE:
980 return true;
981 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400982 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400983 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400984 }
985 break;
986
987 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400988 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400989 switch (param)
990 {
991 case GL_LEQUAL:
992 case GL_GEQUAL:
993 case GL_LESS:
994 case GL_GREATER:
995 case GL_EQUAL:
996 case GL_NOTEQUAL:
997 case GL_ALWAYS:
998 case GL_NEVER:
999 return true;
1000 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001001 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001002 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001003 }
1004 break;
1005
1006 case GL_TEXTURE_SWIZZLE_R:
1007 case GL_TEXTURE_SWIZZLE_G:
1008 case GL_TEXTURE_SWIZZLE_B:
1009 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001010 switch (param)
1011 {
1012 case GL_RED:
1013 case GL_GREEN:
1014 case GL_BLUE:
1015 case GL_ALPHA:
1016 case GL_ZERO:
1017 case GL_ONE:
1018 return true;
1019 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001020 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001021 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001022 }
1023 break;
1024
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001025 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001026 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001027 {
Geoff Langb66a9092016-05-16 15:59:14 -04001028 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001029 return false;
1030 }
Geoff Langb66a9092016-05-16 15:59:14 -04001031 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1032 {
1033 context->handleError(
1034 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1035 return false;
1036 }
1037 return true;
1038
1039 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001040 if (param < 0)
1041 {
1042 context->handleError(Error(GL_INVALID_VALUE));
1043 return false;
1044 }
1045 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001046 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001047 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001048 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001049 }
1050}
1051
Geoff Langb1196682014-07-23 13:47:29 -04001052bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001053{
1054 switch (pname)
1055 {
1056 case GL_TEXTURE_MIN_FILTER:
1057 case GL_TEXTURE_MAG_FILTER:
1058 case GL_TEXTURE_WRAP_S:
1059 case GL_TEXTURE_WRAP_T:
1060 case GL_TEXTURE_WRAP_R:
1061 case GL_TEXTURE_MIN_LOD:
1062 case GL_TEXTURE_MAX_LOD:
1063 case GL_TEXTURE_COMPARE_MODE:
1064 case GL_TEXTURE_COMPARE_FUNC:
1065 return true;
1066
1067 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001068 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001069 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001070 }
1071}
1072
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001073bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001074 GLint x,
1075 GLint y,
1076 GLsizei width,
1077 GLsizei height,
1078 GLenum format,
1079 GLenum type,
1080 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001081{
Jamie Madillc29968b2016-01-20 11:17:23 -05001082 if (width < 0 || height < 0)
1083 {
Jamie Madill437fa652016-05-03 15:13:24 -04001084 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001085 return false;
1086 }
1087
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001088 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001089 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001090
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001091 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001092 {
Jamie Madill437fa652016-05-03 15:13:24 -04001093 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001094 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001095 }
1096
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001097 if (context->getGLState().getReadFramebuffer()->id() != 0 &&
1098 framebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001099 {
Jamie Madill437fa652016-05-03 15:13:24 -04001100 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001101 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001102 }
1103
Geoff Langbce529e2014-12-01 12:48:41 -05001104 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1105 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001106 {
Jamie Madill437fa652016-05-03 15:13:24 -04001107 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001108 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001109 }
1110
Geoff Langbce529e2014-12-01 12:48:41 -05001111 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1112 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001113 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001114 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001115
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001116 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1117 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001118
1119 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1120 {
Jamie Madill437fa652016-05-03 15:13:24 -04001121 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001122 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001123 }
1124
Jamie Madillc29968b2016-01-20 11:17:23 -05001125 return true;
1126}
1127
1128bool ValidateReadnPixelsEXT(Context *context,
1129 GLint x,
1130 GLint y,
1131 GLsizei width,
1132 GLsizei height,
1133 GLenum format,
1134 GLenum type,
1135 GLsizei bufSize,
1136 GLvoid *pixels)
1137{
1138 if (bufSize < 0)
1139 {
Jamie Madill437fa652016-05-03 15:13:24 -04001140 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001141 return false;
1142 }
1143
Geoff Lang5d601382014-07-22 15:14:06 -04001144 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1145 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001146
Jamie Madille2e406c2016-06-02 13:04:10 -04001147 auto outputPitchOrErr =
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001148 sizedFormatInfo.computeRowPitch(type, width, context->getGLState().getPackAlignment(),
1149 context->getGLState().getPackRowLength());
Jamie Madille2e406c2016-06-02 13:04:10 -04001150
1151 if (outputPitchOrErr.isError())
1152 {
1153 context->handleError(outputPitchOrErr.getError());
1154 return false;
1155 }
1156
1157 CheckedNumeric<GLuint> checkedOutputPitch(outputPitchOrErr.getResult());
1158 auto checkedRequiredSize = checkedOutputPitch * height;
1159 if (!checkedRequiredSize.IsValid())
1160 {
1161 context->handleError(Error(GL_INVALID_OPERATION, "Unsigned multiplication overflow."));
1162 return false;
1163 }
1164
Jamie Madill26e91952014-03-05 15:01:27 -05001165 // sized query sanity check
Jamie Madille2e406c2016-06-02 13:04:10 -04001166 if (checkedRequiredSize.ValueOrDie() > static_cast<GLuint>(bufSize))
Jamie Madill26e91952014-03-05 15:01:27 -05001167 {
Jamie Madill437fa652016-05-03 15:13:24 -04001168 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001169 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001170 }
1171
Jamie Madillc29968b2016-01-20 11:17:23 -05001172 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001173}
1174
Olli Etuaho41997e72016-03-10 13:38:39 +02001175bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001176{
1177 if (!context->getExtensions().occlusionQueryBoolean &&
1178 !context->getExtensions().disjointTimerQuery)
1179 {
Jamie Madill437fa652016-05-03 15:13:24 -04001180 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001181 return false;
1182 }
1183
Olli Etuaho41997e72016-03-10 13:38:39 +02001184 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001185}
1186
Olli Etuaho41997e72016-03-10 13:38:39 +02001187bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001188{
1189 if (!context->getExtensions().occlusionQueryBoolean &&
1190 !context->getExtensions().disjointTimerQuery)
1191 {
Jamie Madill437fa652016-05-03 15:13:24 -04001192 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001193 return false;
1194 }
1195
Olli Etuaho41997e72016-03-10 13:38:39 +02001196 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001197}
1198
1199bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001200{
1201 if (!ValidQueryType(context, target))
1202 {
Jamie Madill437fa652016-05-03 15:13:24 -04001203 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001204 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001205 }
1206
1207 if (id == 0)
1208 {
Jamie Madill437fa652016-05-03 15:13:24 -04001209 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001210 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001211 }
1212
1213 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1214 // of zero, if the active query object name for <target> is non-zero (for the
1215 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1216 // the active query for either target is non-zero), if <id> is the name of an
1217 // existing query object whose type does not match <target>, or if <id> is the
1218 // active query object name for any query type, the error INVALID_OPERATION is
1219 // generated.
1220
1221 // Ensure no other queries are active
1222 // NOTE: If other queries than occlusion are supported, we will need to check
1223 // separately that:
1224 // a) The query ID passed is not the current active query for any target/type
1225 // b) There are no active queries for the requested target (and in the case
1226 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1227 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001228
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001229 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001230 {
Jamie Madill437fa652016-05-03 15:13:24 -04001231 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001232 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001233 }
1234
1235 Query *queryObject = context->getQuery(id, true, target);
1236
1237 // check that name was obtained with glGenQueries
1238 if (!queryObject)
1239 {
Jamie Madill437fa652016-05-03 15:13:24 -04001240 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001241 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001242 }
1243
1244 // check for type mismatch
1245 if (queryObject->getType() != target)
1246 {
Jamie Madill437fa652016-05-03 15:13:24 -04001247 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001248 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001249 }
1250
1251 return true;
1252}
1253
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001254bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1255{
1256 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001257 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001258 {
Jamie Madill437fa652016-05-03 15:13:24 -04001259 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001260 return false;
1261 }
1262
1263 return ValidateBeginQueryBase(context, target, id);
1264}
1265
1266bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001267{
1268 if (!ValidQueryType(context, target))
1269 {
Jamie Madill437fa652016-05-03 15:13:24 -04001270 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001271 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001272 }
1273
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001274 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001275
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001276 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001277 {
Jamie Madill437fa652016-05-03 15:13:24 -04001278 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001279 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001280 }
1281
Jamie Madill45c785d2014-05-13 14:09:34 -04001282 return true;
1283}
1284
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001285bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1286{
1287 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001288 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001289 {
Jamie Madill437fa652016-05-03 15:13:24 -04001290 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001291 return false;
1292 }
1293
1294 return ValidateEndQueryBase(context, target);
1295}
1296
1297bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1298{
1299 if (!context->getExtensions().disjointTimerQuery)
1300 {
Jamie Madill437fa652016-05-03 15:13:24 -04001301 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001302 return false;
1303 }
1304
1305 if (target != GL_TIMESTAMP_EXT)
1306 {
Jamie Madill437fa652016-05-03 15:13:24 -04001307 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001308 return false;
1309 }
1310
1311 Query *queryObject = context->getQuery(id, true, target);
1312 if (queryObject == nullptr)
1313 {
Jamie Madill437fa652016-05-03 15:13:24 -04001314 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001315 return false;
1316 }
1317
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001318 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001319 {
Jamie Madill437fa652016-05-03 15:13:24 -04001320 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001321 return false;
1322 }
1323
1324 return true;
1325}
1326
1327bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1328{
1329 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1330 {
Jamie Madill437fa652016-05-03 15:13:24 -04001331 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001332 return false;
1333 }
1334
1335 switch (pname)
1336 {
1337 case GL_CURRENT_QUERY_EXT:
1338 if (target == GL_TIMESTAMP_EXT)
1339 {
Jamie Madill437fa652016-05-03 15:13:24 -04001340 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001341 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1342 return false;
1343 }
1344 break;
1345 case GL_QUERY_COUNTER_BITS_EXT:
1346 if (!context->getExtensions().disjointTimerQuery ||
1347 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1348 {
Jamie Madill437fa652016-05-03 15:13:24 -04001349 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001350 return false;
1351 }
1352 break;
1353 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001354 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001355 return false;
1356 }
1357
1358 return true;
1359}
1360
1361bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1362{
1363 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001364 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001365 {
Jamie Madill437fa652016-05-03 15:13:24 -04001366 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001367 return false;
1368 }
1369
1370 return ValidateGetQueryivBase(context, target, pname);
1371}
1372
1373bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1374{
1375 Query *queryObject = context->getQuery(id, false, GL_NONE);
1376
1377 if (!queryObject)
1378 {
Jamie Madill437fa652016-05-03 15:13:24 -04001379 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001380 return false;
1381 }
1382
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001383 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001384 {
Jamie Madill437fa652016-05-03 15:13:24 -04001385 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001386 return false;
1387 }
1388
1389 switch (pname)
1390 {
1391 case GL_QUERY_RESULT_EXT:
1392 case GL_QUERY_RESULT_AVAILABLE_EXT:
1393 break;
1394
1395 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001396 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001397 return false;
1398 }
1399
1400 return true;
1401}
1402
1403bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1404{
1405 if (!context->getExtensions().disjointTimerQuery)
1406 {
Jamie Madill437fa652016-05-03 15:13:24 -04001407 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001408 return false;
1409 }
1410 return ValidateGetQueryObjectValueBase(context, id, pname);
1411}
1412
1413bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1414{
1415 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001416 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001417 {
Jamie Madill437fa652016-05-03 15:13:24 -04001418 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001419 return false;
1420 }
1421 return ValidateGetQueryObjectValueBase(context, id, pname);
1422}
1423
1424bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1425{
1426 if (!context->getExtensions().disjointTimerQuery)
1427 {
Jamie Madill437fa652016-05-03 15:13:24 -04001428 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001429 return false;
1430 }
1431 return ValidateGetQueryObjectValueBase(context, id, pname);
1432}
1433
1434bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1435{
1436 if (!context->getExtensions().disjointTimerQuery)
1437 {
Jamie Madill437fa652016-05-03 15:13:24 -04001438 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001439 return false;
1440 }
1441 return ValidateGetQueryObjectValueBase(context, id, pname);
1442}
1443
Jamie Madill62d31cb2015-09-11 13:25:51 -04001444static bool ValidateUniformCommonBase(gl::Context *context,
1445 GLenum targetUniformType,
1446 GLint location,
1447 GLsizei count,
1448 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001449{
1450 if (count < 0)
1451 {
Jamie Madill437fa652016-05-03 15:13:24 -04001452 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001453 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001454 }
1455
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001456 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001457 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001458 {
Jamie Madill437fa652016-05-03 15:13:24 -04001459 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001460 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001461 }
1462
Geoff Langd8605522016-04-13 10:19:12 -04001463 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001464 {
1465 // Silently ignore the uniform command
1466 return false;
1467 }
1468
Geoff Lang7dd2e102014-11-10 15:19:26 -05001469 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001470 {
Jamie Madill437fa652016-05-03 15:13:24 -04001471 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001472 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001473 }
1474
Jamie Madill62d31cb2015-09-11 13:25:51 -04001475 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001476
1477 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001478 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001479 {
Jamie Madill437fa652016-05-03 15:13:24 -04001480 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001481 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001482 }
1483
Jamie Madill62d31cb2015-09-11 13:25:51 -04001484 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001485 return true;
1486}
1487
Jamie Madillaa981bd2014-05-20 10:55:55 -04001488bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1489{
1490 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001491 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001492 {
Jamie Madill437fa652016-05-03 15:13:24 -04001493 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001494 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001495 }
1496
Jamie Madill62d31cb2015-09-11 13:25:51 -04001497 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001498 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1499 {
1500 return false;
1501 }
1502
Jamie Madillf2575982014-06-25 16:04:54 -04001503 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001504 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001505 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1506 {
Jamie Madill437fa652016-05-03 15:13:24 -04001507 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001508 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001509 }
1510
1511 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001512}
1513
1514bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1515 GLboolean transpose)
1516{
1517 // Check for ES3 uniform entry points
1518 int rows = VariableRowCount(matrixType);
1519 int cols = VariableColumnCount(matrixType);
1520 if (rows != cols && context->getClientVersion() < 3)
1521 {
Jamie Madill437fa652016-05-03 15:13:24 -04001522 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001523 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001524 }
1525
1526 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1527 {
Jamie Madill437fa652016-05-03 15:13:24 -04001528 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001529 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001530 }
1531
Jamie Madill62d31cb2015-09-11 13:25:51 -04001532 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001533 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1534 {
1535 return false;
1536 }
1537
1538 if (uniform->type != matrixType)
1539 {
Jamie Madill437fa652016-05-03 15:13:24 -04001540 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001541 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001542 }
1543
1544 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001545}
1546
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001547bool ValidateStateQuery(ValidationContext *context,
1548 GLenum pname,
1549 GLenum *nativeType,
1550 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001551{
1552 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1553 {
Jamie Madill437fa652016-05-03 15:13:24 -04001554 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001555 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001556 }
1557
Jamie Madill0af26e12015-03-05 19:54:33 -05001558 const Caps &caps = context->getCaps();
1559
Jamie Madill893ab082014-05-16 16:56:10 -04001560 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1561 {
1562 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1563
Jamie Madill0af26e12015-03-05 19:54:33 -05001564 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001565 {
Jamie Madill437fa652016-05-03 15:13:24 -04001566 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001567 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001568 }
1569 }
1570
1571 switch (pname)
1572 {
1573 case GL_TEXTURE_BINDING_2D:
1574 case GL_TEXTURE_BINDING_CUBE_MAP:
1575 case GL_TEXTURE_BINDING_3D:
1576 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001577 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001578 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1579 if (!context->getExtensions().eglStreamConsumerExternal)
1580 {
Jamie Madill437fa652016-05-03 15:13:24 -04001581 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001582 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1583 return false;
1584 }
1585 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001586
1587 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1588 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1589 {
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001590 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001591 ASSERT(framebuffer);
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001592 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001593 {
Jamie Madill437fa652016-05-03 15:13:24 -04001594 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001595 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001596 }
1597
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001598 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001599 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001600 {
Jamie Madill437fa652016-05-03 15:13:24 -04001601 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001602 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001603 }
1604 }
1605 break;
1606
1607 default:
1608 break;
1609 }
1610
1611 // pname is valid, but there are no parameters to return
1612 if (numParams == 0)
1613 {
1614 return false;
1615 }
1616
1617 return true;
1618}
1619
Jamie Madillc29968b2016-01-20 11:17:23 -05001620bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1621 GLenum target,
1622 GLint level,
1623 GLenum internalformat,
1624 bool isSubImage,
1625 GLint xoffset,
1626 GLint yoffset,
1627 GLint zoffset,
1628 GLint x,
1629 GLint y,
1630 GLsizei width,
1631 GLsizei height,
1632 GLint border,
1633 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001634{
Jamie Madill560a8d82014-05-21 13:06:20 -04001635 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1636 {
Jamie Madill437fa652016-05-03 15:13:24 -04001637 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001638 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001639 }
1640
1641 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1642 {
Jamie Madill437fa652016-05-03 15:13:24 -04001643 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001644 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001645 }
1646
1647 if (border != 0)
1648 {
Jamie Madill437fa652016-05-03 15:13:24 -04001649 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001650 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001651 }
1652
1653 if (!ValidMipLevel(context, target, level))
1654 {
Jamie Madill437fa652016-05-03 15:13:24 -04001655 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001656 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001657 }
1658
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001659 const auto &state = context->getGLState();
1660 const gl::Framebuffer *framebuffer = state.getReadFramebuffer();
1661 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001662 {
Jamie Madill437fa652016-05-03 15:13:24 -04001663 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001664 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001665 }
1666
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001667 if (state.getReadFramebuffer()->id() != 0 &&
1668 framebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001669 {
Jamie Madill437fa652016-05-03 15:13:24 -04001670 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001671 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001672 }
1673
Geoff Langaae65a42014-05-26 12:43:44 -04001674 const gl::Caps &caps = context->getCaps();
1675
Geoff Langaae65a42014-05-26 12:43:44 -04001676 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001677 switch (target)
1678 {
1679 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001680 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001681 break;
1682
1683 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1684 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1685 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1686 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1687 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1688 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001689 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001690 break;
1691
1692 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001693 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001694 break;
1695
1696 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001697 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001698 break;
1699
1700 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001701 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001702 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001703 }
1704
Jamie Madillc29968b2016-01-20 11:17:23 -05001705 gl::Texture *texture =
1706 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001707 if (!texture)
1708 {
Jamie Madill437fa652016-05-03 15:13:24 -04001709 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001710 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001711 }
1712
Geoff Lang69cce582015-09-17 13:20:36 -04001713 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001714 {
Jamie Madill437fa652016-05-03 15:13:24 -04001715 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001716 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001717 }
1718
Geoff Lang5d601382014-07-22 15:14:06 -04001719 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1720
1721 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001722 {
Jamie Madill437fa652016-05-03 15:13:24 -04001723 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001724 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001725 }
1726
Geoff Langa9be0dc2014-12-17 12:34:40 -05001727 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001728 {
Jamie Madill437fa652016-05-03 15:13:24 -04001729 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001730 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001731 }
1732
1733 if (isSubImage)
1734 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001735 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1736 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1737 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001738 {
Jamie Madill437fa652016-05-03 15:13:24 -04001739 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001740 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001741 }
1742 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001743 else
1744 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001745 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001746 {
Jamie Madill437fa652016-05-03 15:13:24 -04001747 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001748 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001749 }
1750
Geoff Lang5d601382014-07-22 15:14:06 -04001751 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001752 {
Jamie Madill437fa652016-05-03 15:13:24 -04001753 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001754 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001755 }
1756
1757 int maxLevelDimension = (maxDimension >> level);
1758 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1759 {
Jamie Madill437fa652016-05-03 15:13:24 -04001760 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001761 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001762 }
1763 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001764
Geoff Langa9be0dc2014-12-17 12:34:40 -05001765 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001766 return true;
1767}
1768
Jamie Madillf25855c2015-11-03 11:06:18 -05001769static bool ValidateDrawBase(ValidationContext *context,
1770 GLenum mode,
1771 GLsizei count,
1772 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001773{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001774 switch (mode)
1775 {
1776 case GL_POINTS:
1777 case GL_LINES:
1778 case GL_LINE_LOOP:
1779 case GL_LINE_STRIP:
1780 case GL_TRIANGLES:
1781 case GL_TRIANGLE_STRIP:
1782 case GL_TRIANGLE_FAN:
1783 break;
1784 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001785 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001786 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001787 }
1788
Jamie Madill250d33f2014-06-06 17:09:03 -04001789 if (count < 0)
1790 {
Jamie Madill437fa652016-05-03 15:13:24 -04001791 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001792 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001793 }
1794
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001795 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001796
Jamie Madill250d33f2014-06-06 17:09:03 -04001797 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001798 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001799 {
Jamie Madill437fa652016-05-03 15:13:24 -04001800 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001801 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001802 }
1803
Geoff Lang3a86ad32015-09-01 11:47:05 -04001804 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001805 {
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001806 const Framebuffer *framebuffer = state.getDrawFramebuffer();
Jinyoung Hur85769f02015-10-20 17:08:44 -04001807 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1808 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1809 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1810 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1811 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1812 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001813 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001814 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1815 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001816 {
1817 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1818 // Section 6.10 of the WebGL 1.0 spec
1819 ERR(
1820 "This ANGLE implementation does not support separate front/back stencil "
1821 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001822 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001823 return false;
1824 }
Jamie Madillac528012014-06-20 13:21:23 -04001825 }
1826
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001827 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001828 if (!fbo || fbo->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001829 {
Jamie Madill437fa652016-05-03 15:13:24 -04001830 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001831 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001832 }
1833
Geoff Lang7dd2e102014-11-10 15:19:26 -05001834 gl::Program *program = state.getProgram();
1835 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001836 {
Jamie Madill437fa652016-05-03 15:13:24 -04001837 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001838 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001839 }
1840
Geoff Lang7dd2e102014-11-10 15:19:26 -05001841 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001842 {
Jamie Madill437fa652016-05-03 15:13:24 -04001843 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001844 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001845 }
1846
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001847 // Uniform buffer validation
1848 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1849 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001850 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001851 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001852 const OffsetBindingPointer<Buffer> &uniformBuffer =
1853 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001854
Geoff Lang5d124a62015-09-15 13:03:27 -04001855 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001856 {
1857 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001858 context->handleError(
1859 Error(GL_INVALID_OPERATION,
1860 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001861 return false;
1862 }
1863
Geoff Lang5d124a62015-09-15 13:03:27 -04001864 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001865 if (uniformBufferSize == 0)
1866 {
1867 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001868 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001869 }
1870
Jamie Madill62d31cb2015-09-11 13:25:51 -04001871 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001872 {
1873 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001874 context->handleError(
1875 Error(GL_INVALID_OPERATION,
1876 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001877 return false;
1878 }
1879 }
1880
Jamie Madill250d33f2014-06-06 17:09:03 -04001881 // No-op if zero count
1882 return (count > 0);
1883}
1884
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001885bool ValidateDrawArrays(ValidationContext *context,
1886 GLenum mode,
1887 GLint first,
1888 GLsizei count,
1889 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001890{
Jamie Madillfd716582014-06-06 17:09:04 -04001891 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001892 {
Jamie Madill437fa652016-05-03 15:13:24 -04001893 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001894 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001895 }
1896
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001897 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001898 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001899 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1900 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001901 {
1902 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1903 // that does not match the current transform feedback object's draw mode (if transform feedback
1904 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001905 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001906 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001907 }
1908
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001909 if (!ValidateDrawBase(context, mode, count, primcount))
1910 {
1911 return false;
1912 }
1913
1914 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001915 {
1916 return false;
1917 }
1918
1919 return true;
1920}
1921
Geoff Langb1196682014-07-23 13:47:29 -04001922bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001923{
1924 if (primcount < 0)
1925 {
Jamie Madill437fa652016-05-03 15:13:24 -04001926 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001927 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001928 }
1929
Jamie Madill2b976812014-08-25 15:47:49 -04001930 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001931 {
1932 return false;
1933 }
1934
1935 // No-op if zero primitive count
1936 return (primcount > 0);
1937}
1938
Geoff Lang87a93302014-09-16 13:29:43 -04001939static bool ValidateDrawInstancedANGLE(Context *context)
1940{
1941 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001942 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04001943
Geoff Lang7dd2e102014-11-10 15:19:26 -05001944 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001945
1946 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001947 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001948 {
1949 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001950 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001951 {
1952 return true;
1953 }
1954 }
1955
Jamie Madill437fa652016-05-03 15:13:24 -04001956 context->handleError(Error(GL_INVALID_OPERATION,
1957 "ANGLE_instanced_arrays requires that at least one active attribute"
1958 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001959 return false;
1960}
1961
1962bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1963{
1964 if (!ValidateDrawInstancedANGLE(context))
1965 {
1966 return false;
1967 }
1968
1969 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1970}
1971
Jamie Madillf25855c2015-11-03 11:06:18 -05001972bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001973 GLenum mode,
1974 GLsizei count,
1975 GLenum type,
1976 const GLvoid *indices,
1977 GLsizei primcount,
1978 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001979{
Jamie Madill250d33f2014-06-06 17:09:03 -04001980 switch (type)
1981 {
1982 case GL_UNSIGNED_BYTE:
1983 case GL_UNSIGNED_SHORT:
1984 break;
1985 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001986 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001987 {
Jamie Madill437fa652016-05-03 15:13:24 -04001988 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001989 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001990 }
1991 break;
1992 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001993 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001994 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001995 }
1996
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001997 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001998
1999 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002000 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002001 {
2002 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2003 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002004 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002005 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002006 }
2007
2008 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002009 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002010 {
Jamie Madill437fa652016-05-03 15:13:24 -04002011 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002012 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002013 }
2014
Jamie Madill2b976812014-08-25 15:47:49 -04002015 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002016 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002017 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002018 {
Jamie Madill437fa652016-05-03 15:13:24 -04002019 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002020 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002021 }
2022
Jamie Madillae3000b2014-08-25 15:47:51 -04002023 if (elementArrayBuffer)
2024 {
2025 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2026
2027 GLint64 offset = reinterpret_cast<GLint64>(indices);
2028 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2029
2030 // check for integer overflows
2031 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2032 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2033 {
Jamie Madill437fa652016-05-03 15:13:24 -04002034 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002035 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002036 }
2037
2038 // Check for reading past the end of the bound buffer object
2039 if (byteCount > elementArrayBuffer->getSize())
2040 {
Jamie Madill437fa652016-05-03 15:13:24 -04002041 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002042 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002043 }
2044 }
2045 else if (!indices)
2046 {
2047 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002048 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002049 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002050 }
2051
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002052 if (!ValidateDrawBase(context, mode, count, primcount))
2053 {
2054 return false;
2055 }
2056
Jamie Madill2b976812014-08-25 15:47:49 -04002057 // Use max index to validate if our vertex buffers are large enough for the pull.
2058 // TODO: offer fast path, with disabled index validation.
2059 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2060 if (elementArrayBuffer)
2061 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002062 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002063 Error error =
2064 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2065 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002066 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002067 {
Jamie Madill437fa652016-05-03 15:13:24 -04002068 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002069 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002070 }
2071 }
2072 else
2073 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002074 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002075 }
2076
Jamie Madille79b1e12015-11-04 16:36:37 -05002077 // If we use an index greater than our maximum supported index range, return an error.
2078 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2079 // return an error if possible here.
2080 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2081 {
Jamie Madill437fa652016-05-03 15:13:24 -04002082 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002083 return false;
2084 }
2085
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002086 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002087 {
2088 return false;
2089 }
2090
Geoff Lang3edfe032015-09-04 16:38:24 -04002091 // No op if there are no real indices in the index data (all are primitive restart).
2092 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002093}
2094
Geoff Langb1196682014-07-23 13:47:29 -04002095bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002096 GLenum mode,
2097 GLsizei count,
2098 GLenum type,
2099 const GLvoid *indices,
2100 GLsizei primcount,
2101 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002102{
2103 if (primcount < 0)
2104 {
Jamie Madill437fa652016-05-03 15:13:24 -04002105 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002106 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002107 }
2108
Jamie Madill2b976812014-08-25 15:47:49 -04002109 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002110 {
2111 return false;
2112 }
2113
2114 // No-op zero primitive count
2115 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002116}
2117
Geoff Lang3edfe032015-09-04 16:38:24 -04002118bool ValidateDrawElementsInstancedANGLE(Context *context,
2119 GLenum mode,
2120 GLsizei count,
2121 GLenum type,
2122 const GLvoid *indices,
2123 GLsizei primcount,
2124 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002125{
2126 if (!ValidateDrawInstancedANGLE(context))
2127 {
2128 return false;
2129 }
2130
2131 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2132}
2133
Geoff Langb1196682014-07-23 13:47:29 -04002134bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002135 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002136{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002137 if (!ValidFramebufferTarget(target))
2138 {
Jamie Madill437fa652016-05-03 15:13:24 -04002139 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002140 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002141 }
2142
2143 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002144 {
2145 return false;
2146 }
2147
Jamie Madill55ec3b12014-07-03 10:38:57 -04002148 if (texture != 0)
2149 {
2150 gl::Texture *tex = context->getTexture(texture);
2151
2152 if (tex == NULL)
2153 {
Jamie Madill437fa652016-05-03 15:13:24 -04002154 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002155 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002156 }
2157
2158 if (level < 0)
2159 {
Jamie Madill437fa652016-05-03 15:13:24 -04002160 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002161 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002162 }
2163 }
2164
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002165 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002166 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002167
Jamie Madill84115c92015-04-23 15:00:07 -04002168 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002169 {
Jamie Madill437fa652016-05-03 15:13:24 -04002170 context->handleError(
2171 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002172 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002173 }
2174
2175 return true;
2176}
2177
Geoff Langb1196682014-07-23 13:47:29 -04002178bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002179 GLenum textarget, GLuint texture, GLint level)
2180{
Geoff Lang95663912015-04-02 15:54:45 -04002181 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2182 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002183 {
Jamie Madill437fa652016-05-03 15:13:24 -04002184 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002185 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002186 }
2187
2188 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002189 {
2190 return false;
2191 }
2192
Jamie Madill55ec3b12014-07-03 10:38:57 -04002193 if (texture != 0)
2194 {
2195 gl::Texture *tex = context->getTexture(texture);
2196 ASSERT(tex);
2197
Jamie Madill2a6564e2014-07-11 09:53:19 -04002198 const gl::Caps &caps = context->getCaps();
2199
Jamie Madill55ec3b12014-07-03 10:38:57 -04002200 switch (textarget)
2201 {
2202 case GL_TEXTURE_2D:
2203 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002204 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002205 {
Jamie Madill437fa652016-05-03 15:13:24 -04002206 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002207 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002208 }
2209 if (tex->getTarget() != GL_TEXTURE_2D)
2210 {
Jamie Madill437fa652016-05-03 15:13:24 -04002211 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002212 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002213 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002214 }
2215 break;
2216
2217 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2218 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2219 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2220 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2221 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2222 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2223 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002224 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002225 {
Jamie Madill437fa652016-05-03 15:13:24 -04002226 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002227 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002228 }
2229 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2230 {
Jamie Madill437fa652016-05-03 15:13:24 -04002231 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002232 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002233 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002234 }
2235 break;
2236
2237 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002238 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002239 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002240 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002241
2242 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2243 if (internalFormatInfo.compressed)
2244 {
Jamie Madill437fa652016-05-03 15:13:24 -04002245 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002246 return false;
2247 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002248 }
2249
Jamie Madill570f7c82014-07-03 10:38:54 -04002250 return true;
2251}
2252
Geoff Langb1196682014-07-23 13:47:29 -04002253bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002254{
2255 if (program == 0)
2256 {
Jamie Madill437fa652016-05-03 15:13:24 -04002257 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002258 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002259 }
2260
Dian Xiang769769a2015-09-09 15:20:08 -07002261 gl::Program *programObject = GetValidProgram(context, program);
2262 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002263 {
2264 return false;
2265 }
2266
Jamie Madill0063c512014-08-25 15:47:53 -04002267 if (!programObject || !programObject->isLinked())
2268 {
Jamie Madill437fa652016-05-03 15:13:24 -04002269 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002270 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002271 }
2272
Geoff Lang7dd2e102014-11-10 15:19:26 -05002273 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002274 {
Jamie Madill437fa652016-05-03 15:13:24 -04002275 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002276 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002277 }
2278
Jamie Madill0063c512014-08-25 15:47:53 -04002279 return true;
2280}
2281
Geoff Langb1196682014-07-23 13:47:29 -04002282bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002283{
2284 return ValidateGetUniformBase(context, program, location);
2285}
2286
Geoff Langb1196682014-07-23 13:47:29 -04002287bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002288{
Jamie Madill78f41802014-08-25 15:47:55 -04002289 return ValidateGetUniformBase(context, program, location);
2290}
2291
Geoff Langb1196682014-07-23 13:47:29 -04002292static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002293{
2294 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002295 {
Jamie Madill78f41802014-08-25 15:47:55 -04002296 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002297 }
2298
Jamie Madilla502c742014-08-28 17:19:13 -04002299 gl::Program *programObject = context->getProgram(program);
2300 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002301
Jamie Madill78f41802014-08-25 15:47:55 -04002302 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002303 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2304 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002305 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002306 {
Jamie Madill437fa652016-05-03 15:13:24 -04002307 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002308 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002309 }
2310
2311 return true;
2312}
2313
Geoff Langb1196682014-07-23 13:47:29 -04002314bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002315{
Jamie Madill78f41802014-08-25 15:47:55 -04002316 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002317}
2318
Geoff Langb1196682014-07-23 13:47:29 -04002319bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002320{
Jamie Madill78f41802014-08-25 15:47:55 -04002321 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002322}
2323
Austin Kinross08332632015-05-05 13:35:47 -07002324bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2325 const GLenum *attachments, bool defaultFramebuffer)
2326{
2327 if (numAttachments < 0)
2328 {
Jamie Madill437fa652016-05-03 15:13:24 -04002329 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002330 return false;
2331 }
2332
2333 for (GLsizei i = 0; i < numAttachments; ++i)
2334 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002335 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002336 {
2337 if (defaultFramebuffer)
2338 {
Jamie Madill437fa652016-05-03 15:13:24 -04002339 context->handleError(Error(
2340 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002341 return false;
2342 }
2343
2344 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2345 {
Jamie Madill437fa652016-05-03 15:13:24 -04002346 context->handleError(Error(GL_INVALID_OPERATION,
2347 "Requested color attachment is greater than the maximum "
2348 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002349 return false;
2350 }
2351 }
2352 else
2353 {
2354 switch (attachments[i])
2355 {
2356 case GL_DEPTH_ATTACHMENT:
2357 case GL_STENCIL_ATTACHMENT:
2358 case GL_DEPTH_STENCIL_ATTACHMENT:
2359 if (defaultFramebuffer)
2360 {
Jamie Madill437fa652016-05-03 15:13:24 -04002361 context->handleError(
2362 Error(GL_INVALID_ENUM,
2363 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002364 return false;
2365 }
2366 break;
2367 case GL_COLOR:
2368 case GL_DEPTH:
2369 case GL_STENCIL:
2370 if (!defaultFramebuffer)
2371 {
Jamie Madill437fa652016-05-03 15:13:24 -04002372 context->handleError(
2373 Error(GL_INVALID_ENUM,
2374 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002375 return false;
2376 }
2377 break;
2378 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002379 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002380 return false;
2381 }
2382 }
2383 }
2384
2385 return true;
2386}
2387
Austin Kinross6ee1e782015-05-29 17:05:37 -07002388bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2389{
2390 // Note that debug marker calls must not set error state
2391
2392 if (length < 0)
2393 {
2394 return false;
2395 }
2396
2397 if (marker == nullptr)
2398 {
2399 return false;
2400 }
2401
2402 return true;
2403}
2404
2405bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2406{
2407 // Note that debug marker calls must not set error state
2408
2409 if (length < 0)
2410 {
2411 return false;
2412 }
2413
2414 if (length > 0 && marker == nullptr)
2415 {
2416 return false;
2417 }
2418
2419 return true;
2420}
2421
Geoff Langdcab33b2015-07-21 13:03:16 -04002422bool ValidateEGLImageTargetTexture2DOES(Context *context,
2423 egl::Display *display,
2424 GLenum target,
2425 egl::Image *image)
2426{
Geoff Langa8406172015-07-21 16:53:39 -04002427 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2428 {
Jamie Madill437fa652016-05-03 15:13:24 -04002429 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002430 return false;
2431 }
2432
2433 switch (target)
2434 {
2435 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002436 if (!context->getExtensions().eglImage)
2437 {
2438 context->handleError(Error(
2439 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2440 }
2441 break;
2442
2443 case GL_TEXTURE_EXTERNAL_OES:
2444 if (!context->getExtensions().eglImageExternal)
2445 {
2446 context->handleError(Error(
2447 GL_INVALID_ENUM,
2448 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2449 }
Geoff Langa8406172015-07-21 16:53:39 -04002450 break;
2451
2452 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002453 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002454 return false;
2455 }
2456
2457 if (!display->isValidImage(image))
2458 {
Jamie Madill437fa652016-05-03 15:13:24 -04002459 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002460 return false;
2461 }
2462
2463 if (image->getSamples() > 0)
2464 {
Jamie Madill437fa652016-05-03 15:13:24 -04002465 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002466 "cannot create a 2D texture from a multisampled EGL image."));
2467 return false;
2468 }
2469
2470 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2471 if (!textureCaps.texturable)
2472 {
Jamie Madill437fa652016-05-03 15:13:24 -04002473 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002474 "EGL image internal format is not supported as a texture."));
2475 return false;
2476 }
2477
Geoff Langdcab33b2015-07-21 13:03:16 -04002478 return true;
2479}
2480
2481bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2482 egl::Display *display,
2483 GLenum target,
2484 egl::Image *image)
2485{
Geoff Langa8406172015-07-21 16:53:39 -04002486 if (!context->getExtensions().eglImage)
2487 {
Jamie Madill437fa652016-05-03 15:13:24 -04002488 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002489 return false;
2490 }
2491
2492 switch (target)
2493 {
2494 case GL_RENDERBUFFER:
2495 break;
2496
2497 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002498 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002499 return false;
2500 }
2501
2502 if (!display->isValidImage(image))
2503 {
Jamie Madill437fa652016-05-03 15:13:24 -04002504 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002505 return false;
2506 }
2507
2508 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2509 if (!textureCaps.renderable)
2510 {
Jamie Madill437fa652016-05-03 15:13:24 -04002511 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002512 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2513 return false;
2514 }
2515
Geoff Langdcab33b2015-07-21 13:03:16 -04002516 return true;
2517}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002518
2519bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2520{
Geoff Lang36167ab2015-12-07 10:27:14 -05002521 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002522 {
2523 // The default VAO should always exist
2524 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002525 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002526 return false;
2527 }
2528
2529 return true;
2530}
2531
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002532bool ValidateLinkProgram(Context *context, GLuint program)
2533{
2534 if (context->hasActiveTransformFeedback(program))
2535 {
2536 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002537 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002538 "Cannot link program while program is associated with an active "
2539 "transform feedback object."));
2540 return false;
2541 }
2542 return true;
2543}
2544
Geoff Langc5629752015-12-07 16:29:04 -05002545bool ValidateProgramBinaryBase(Context *context,
2546 GLuint program,
2547 GLenum binaryFormat,
2548 const void *binary,
2549 GLint length)
2550{
2551 Program *programObject = GetValidProgram(context, program);
2552 if (programObject == nullptr)
2553 {
2554 return false;
2555 }
2556
2557 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2558 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2559 programBinaryFormats.end())
2560 {
Jamie Madill437fa652016-05-03 15:13:24 -04002561 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002562 return false;
2563 }
2564
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002565 if (context->hasActiveTransformFeedback(program))
2566 {
2567 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002568 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002569 "Cannot change program binary while program is associated with "
2570 "an active transform feedback object."));
2571 return false;
2572 }
2573
Geoff Langc5629752015-12-07 16:29:04 -05002574 return true;
2575}
2576
2577bool ValidateGetProgramBinaryBase(Context *context,
2578 GLuint program,
2579 GLsizei bufSize,
2580 GLsizei *length,
2581 GLenum *binaryFormat,
2582 void *binary)
2583{
2584 Program *programObject = GetValidProgram(context, program);
2585 if (programObject == nullptr)
2586 {
2587 return false;
2588 }
2589
2590 if (!programObject->isLinked())
2591 {
Jamie Madill437fa652016-05-03 15:13:24 -04002592 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002593 return false;
2594 }
2595
2596 return true;
2597}
Jamie Madillc29968b2016-01-20 11:17:23 -05002598
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002599bool ValidateUseProgram(Context *context, GLuint program)
2600{
2601 if (program != 0)
2602 {
2603 Program *programObject = context->getProgram(program);
2604 if (!programObject)
2605 {
2606 // ES 3.1.0 section 7.3 page 72
2607 if (context->getShader(program))
2608 {
Jamie Madill437fa652016-05-03 15:13:24 -04002609 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002610 Error(GL_INVALID_OPERATION,
2611 "Attempted to use a single shader instead of a shader program."));
2612 return false;
2613 }
2614 else
2615 {
Jamie Madill437fa652016-05-03 15:13:24 -04002616 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002617 return false;
2618 }
2619 }
2620 if (!programObject->isLinked())
2621 {
Jamie Madill437fa652016-05-03 15:13:24 -04002622 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002623 return false;
2624 }
2625 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002626 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002627 {
2628 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002629 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002630 Error(GL_INVALID_OPERATION,
2631 "Cannot change active program while transform feedback is unpaused."));
2632 return false;
2633 }
2634
2635 return true;
2636}
2637
Jamie Madillc29968b2016-01-20 11:17:23 -05002638bool ValidateCopyTexImage2D(ValidationContext *context,
2639 GLenum target,
2640 GLint level,
2641 GLenum internalformat,
2642 GLint x,
2643 GLint y,
2644 GLsizei width,
2645 GLsizei height,
2646 GLint border)
2647{
2648 if (context->getClientVersion() < 3)
2649 {
2650 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2651 0, x, y, width, height, border);
2652 }
2653
2654 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002655 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2656 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002657}
Jamie Madillc29968b2016-01-20 11:17:23 -05002658
2659bool ValidateFramebufferRenderbuffer(Context *context,
2660 GLenum target,
2661 GLenum attachment,
2662 GLenum renderbuffertarget,
2663 GLuint renderbuffer)
2664{
2665 if (!ValidFramebufferTarget(target) ||
2666 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2667 {
Jamie Madill437fa652016-05-03 15:13:24 -04002668 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002669 return false;
2670 }
2671
2672 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2673 renderbuffertarget, renderbuffer);
2674}
2675
2676bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2677{
2678 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2679 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2680 {
Jamie Madill437fa652016-05-03 15:13:24 -04002681 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002682 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2683 return false;
2684 }
2685
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002686 ASSERT(context->getGLState().getDrawFramebuffer());
2687 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002688 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2689
2690 // This should come first before the check for the default frame buffer
2691 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2692 // rather than INVALID_OPERATION
2693 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2694 {
2695 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2696
2697 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002698 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2699 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002700 {
2701 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002702 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2703 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2704 // 3.1 is still a bit ambiguous about the error, but future specs are
2705 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002706 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002707 return false;
2708 }
2709 else if (bufs[colorAttachment] >= maxColorAttachment)
2710 {
Jamie Madill437fa652016-05-03 15:13:24 -04002711 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002712 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002713 return false;
2714 }
2715 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2716 frameBufferId != 0)
2717 {
2718 // INVALID_OPERATION-GL is bound to buffer and ith argument
2719 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002720 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002721 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2722 return false;
2723 }
2724 }
2725
2726 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2727 // and n is not 1 or bufs is bound to value other than BACK and NONE
2728 if (frameBufferId == 0)
2729 {
2730 if (n != 1)
2731 {
Jamie Madill437fa652016-05-03 15:13:24 -04002732 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002733 "n must be 1 when GL is bound to the default framebuffer"));
2734 return false;
2735 }
2736
2737 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2738 {
Jamie Madill437fa652016-05-03 15:13:24 -04002739 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002740 GL_INVALID_OPERATION,
2741 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2742 return false;
2743 }
2744 }
2745
2746 return true;
2747}
2748
2749bool ValidateCopyTexSubImage2D(Context *context,
2750 GLenum target,
2751 GLint level,
2752 GLint xoffset,
2753 GLint yoffset,
2754 GLint x,
2755 GLint y,
2756 GLsizei width,
2757 GLsizei height)
2758{
2759 if (context->getClientVersion() < 3)
2760 {
2761 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2762 yoffset, x, y, width, height, 0);
2763 }
2764
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002765 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2766 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002767}
2768
Olli Etuaho4f667482016-03-30 15:56:35 +03002769bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2770{
2771 if (!ValidBufferTarget(context, target))
2772 {
Jamie Madill437fa652016-05-03 15:13:24 -04002773 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002774 return false;
2775 }
2776
2777 if (pname != GL_BUFFER_MAP_POINTER)
2778 {
Jamie Madill437fa652016-05-03 15:13:24 -04002779 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002780 return false;
2781 }
2782
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002783 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002784
2785 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2786 // target bound to zero generate an INVALID_OPERATION error."
2787 // GLES 3.1 section 6.6 explicitly specifies this error.
2788 if (!buffer)
2789 {
Jamie Madill437fa652016-05-03 15:13:24 -04002790 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002791 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2792 return false;
2793 }
2794
2795 return true;
2796}
2797
2798bool ValidateUnmapBufferBase(Context *context, GLenum target)
2799{
2800 if (!ValidBufferTarget(context, target))
2801 {
Jamie Madill437fa652016-05-03 15:13:24 -04002802 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002803 return false;
2804 }
2805
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002806 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002807
2808 if (buffer == nullptr || !buffer->isMapped())
2809 {
Jamie Madill437fa652016-05-03 15:13:24 -04002810 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002811 return false;
2812 }
2813
2814 return true;
2815}
2816
2817bool ValidateMapBufferRangeBase(Context *context,
2818 GLenum target,
2819 GLintptr offset,
2820 GLsizeiptr length,
2821 GLbitfield access)
2822{
2823 if (!ValidBufferTarget(context, target))
2824 {
Jamie Madill437fa652016-05-03 15:13:24 -04002825 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002826 return false;
2827 }
2828
2829 if (offset < 0 || length < 0)
2830 {
Jamie Madill437fa652016-05-03 15:13:24 -04002831 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002832 return false;
2833 }
2834
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002835 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002836
2837 if (!buffer)
2838 {
Jamie Madill437fa652016-05-03 15:13:24 -04002839 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002840 return false;
2841 }
2842
2843 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002844 CheckedNumeric<size_t> checkedOffset(offset);
2845 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002846
Jamie Madille2e406c2016-06-02 13:04:10 -04002847 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002848 {
Jamie Madill437fa652016-05-03 15:13:24 -04002849 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002850 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2851 return false;
2852 }
2853
2854 // Check for invalid bits in the mask
2855 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2856 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2857 GL_MAP_UNSYNCHRONIZED_BIT;
2858
2859 if (access & ~(allAccessBits))
2860 {
Jamie Madill437fa652016-05-03 15:13:24 -04002861 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002862 return false;
2863 }
2864
2865 if (length == 0)
2866 {
Jamie Madill437fa652016-05-03 15:13:24 -04002867 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002868 return false;
2869 }
2870
2871 if (buffer->isMapped())
2872 {
Jamie Madill437fa652016-05-03 15:13:24 -04002873 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002874 return false;
2875 }
2876
2877 // Check for invalid bit combinations
2878 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2879 {
Jamie Madill437fa652016-05-03 15:13:24 -04002880 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002881 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2882 return false;
2883 }
2884
2885 GLbitfield writeOnlyBits =
2886 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2887
2888 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2889 {
Jamie Madill437fa652016-05-03 15:13:24 -04002890 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002891 "Invalid access bits when mapping buffer for reading: 0x%X.",
2892 access));
2893 return false;
2894 }
2895
2896 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2897 {
Jamie Madill437fa652016-05-03 15:13:24 -04002898 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002899 GL_INVALID_OPERATION,
2900 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2901 return false;
2902 }
2903 return true;
2904}
2905
2906bool ValidateFlushMappedBufferRangeBase(Context *context,
2907 GLenum target,
2908 GLintptr offset,
2909 GLsizeiptr length)
2910{
2911 if (offset < 0 || length < 0)
2912 {
Jamie Madill437fa652016-05-03 15:13:24 -04002913 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002914 return false;
2915 }
2916
2917 if (!ValidBufferTarget(context, target))
2918 {
Jamie Madill437fa652016-05-03 15:13:24 -04002919 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002920 return false;
2921 }
2922
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002923 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002924
2925 if (buffer == nullptr)
2926 {
Jamie Madill437fa652016-05-03 15:13:24 -04002927 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002928 return false;
2929 }
2930
2931 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2932 {
Jamie Madill437fa652016-05-03 15:13:24 -04002933 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002934 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2935 return false;
2936 }
2937
2938 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002939 CheckedNumeric<size_t> checkedOffset(offset);
2940 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002941
Jamie Madille2e406c2016-06-02 13:04:10 -04002942 if (!checkedSize.IsValid() ||
2943 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002944 {
Jamie Madill437fa652016-05-03 15:13:24 -04002945 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002946 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2947 return false;
2948 }
2949
2950 return true;
2951}
2952
Olli Etuaho0f2b1562016-05-13 16:15:35 +03002953bool ValidateGenerateMipmap(Context *context, GLenum target)
2954{
2955 if (!ValidTextureTarget(context, target))
2956 {
2957 context->handleError(Error(GL_INVALID_ENUM));
2958 return false;
2959 }
2960
2961 Texture *texture = context->getTargetTexture(target);
2962
2963 if (texture == nullptr)
2964 {
2965 context->handleError(Error(GL_INVALID_OPERATION));
2966 return false;
2967 }
2968
2969 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
2970
2971 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
2972 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
2973 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2974 {
2975 context->handleError(Error(GL_INVALID_OPERATION));
2976 return false;
2977 }
2978
2979 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
2980 GLenum internalFormat = texture->getInternalFormat(baseTarget, effectiveBaseLevel);
2981 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
2982 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
2983
2984 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
2985 // unsized formats or that are color renderable and filterable. Since we do not track if
2986 // the texture was created with sized or unsized format (only sized formats are stored),
2987 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
2988 // be able to) because they aren't color renderable. Simply do a special case for LUMA
2989 // textures since they're the only texture format that can be created with unsized formats
2990 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
2991 // was the last version to use add them.
2992 bool isLUMA = internalFormat == GL_LUMINANCE8_EXT ||
2993 internalFormat == GL_LUMINANCE8_ALPHA8_EXT || internalFormat == GL_ALPHA8_EXT;
2994
2995 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable ||
2996 (!formatCaps.renderable && !isLUMA) || formatInfo.compressed)
2997 {
2998 context->handleError(Error(GL_INVALID_OPERATION));
2999 return false;
3000 }
3001
3002 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
3003 if (context->getClientVersion() == 2 && formatInfo.colorEncoding == GL_SRGB)
3004 {
3005 context->handleError(Error(GL_INVALID_OPERATION));
3006 return false;
3007 }
3008
3009 // Non-power of 2 ES2 check
3010 if (!context->getExtensions().textureNPOT &&
3011 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3012 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3013 {
3014 ASSERT(context->getClientVersion() <= 2 &&
3015 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3016 context->handleError(Error(GL_INVALID_OPERATION));
3017 return false;
3018 }
3019
3020 // Cube completeness check
3021 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3022 {
3023 context->handleError(Error(GL_INVALID_OPERATION));
3024 return false;
3025 }
3026
3027 return true;
3028}
3029
Olli Etuaho41997e72016-03-10 13:38:39 +02003030bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3031{
3032 return ValidateGenOrDelete(context, n);
3033}
3034
3035bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3036{
3037 return ValidateGenOrDelete(context, n);
3038}
3039
3040bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3041{
3042 return ValidateGenOrDelete(context, n);
3043}
3044
3045bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3046{
3047 return ValidateGenOrDelete(context, n);
3048}
3049
3050bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3051{
3052 return ValidateGenOrDelete(context, n);
3053}
3054
3055bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3056{
3057 return ValidateGenOrDelete(context, n);
3058}
3059
3060bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3061{
3062 return ValidateGenOrDelete(context, n);
3063}
3064
3065bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3066{
3067 return ValidateGenOrDelete(context, n);
3068}
3069
3070bool ValidateGenOrDelete(Context *context, GLint n)
3071{
3072 if (n < 0)
3073 {
Jamie Madill437fa652016-05-03 15:13:24 -04003074 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003075 return false;
3076 }
3077 return true;
3078}
3079
Jamie Madillc29968b2016-01-20 11:17:23 -05003080} // namespace gl