blob: f96ad6d9e77b5845d62b72faaa01e7c727a43d7f [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 Madill51f40ec2016-06-15 14:06:00 -0400665 const auto &glState = context->getGLState();
666 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
667 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
Jamie Madill51f40ec2016-06-15 14:06:00 -0400681 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
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 Madill51f40ec2016-06-15 14:06:00 -0400687 if (drawFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
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 Madill51f40ec2016-06-15 14:06:00 -04001088 auto readFramebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill26e91952014-03-05 15:01:27 -05001089
Jamie Madill51f40ec2016-06-15 14:06:00 -04001090 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001091 {
Jamie Madill437fa652016-05-03 15:13:24 -04001092 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001093 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001094 }
1095
Jamie Madill51f40ec2016-06-15 14:06:00 -04001096 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001097 {
Jamie Madill437fa652016-05-03 15:13:24 -04001098 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001099 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001100 }
1101
Jamie Madill51f40ec2016-06-15 14:06:00 -04001102 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1103 ASSERT(framebuffer);
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 Madill51f40ec2016-06-15 14:06:00 -04001590 if (context->getGLState().getReadFramebuffer()->checkStatus(
1591 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001592 {
Jamie Madill437fa652016-05-03 15:13:24 -04001593 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001594 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001595 }
1596
Jamie Madill51f40ec2016-06-15 14:06:00 -04001597 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1598 ASSERT(framebuffer);
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001599 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001600 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001601 {
Jamie Madill437fa652016-05-03 15:13:24 -04001602 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001603 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001604 }
1605 }
1606 break;
1607
1608 default:
1609 break;
1610 }
1611
1612 // pname is valid, but there are no parameters to return
1613 if (numParams == 0)
1614 {
1615 return false;
1616 }
1617
1618 return true;
1619}
1620
Jamie Madillc29968b2016-01-20 11:17:23 -05001621bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1622 GLenum target,
1623 GLint level,
1624 GLenum internalformat,
1625 bool isSubImage,
1626 GLint xoffset,
1627 GLint yoffset,
1628 GLint zoffset,
1629 GLint x,
1630 GLint y,
1631 GLsizei width,
1632 GLsizei height,
1633 GLint border,
1634 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001635{
Jamie Madill560a8d82014-05-21 13:06:20 -04001636 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1637 {
Jamie Madill437fa652016-05-03 15:13:24 -04001638 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001639 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001640 }
1641
1642 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1643 {
Jamie Madill437fa652016-05-03 15:13:24 -04001644 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001645 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001646 }
1647
1648 if (border != 0)
1649 {
Jamie Madill437fa652016-05-03 15:13:24 -04001650 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001651 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001652 }
1653
1654 if (!ValidMipLevel(context, target, level))
1655 {
Jamie Madill437fa652016-05-03 15:13:24 -04001656 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001657 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001658 }
1659
Jamie Madill51f40ec2016-06-15 14:06:00 -04001660 const auto &state = context->getGLState();
1661 auto readFramebuffer = state.getReadFramebuffer();
1662 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001663 {
Jamie Madill437fa652016-05-03 15:13:24 -04001664 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001665 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001666 }
1667
Jamie Madill51f40ec2016-06-15 14:06:00 -04001668 if (readFramebuffer->id() != 0 && readFramebuffer->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
Jamie Madill51f40ec2016-06-15 14:06:00 -04001804 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001805 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001806 {
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 Madill51f40ec2016-06-15 14:06:00 -04001827 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001828 {
Jamie Madill437fa652016-05-03 15:13:24 -04001829 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001830 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001831 }
1832
Geoff Lang7dd2e102014-11-10 15:19:26 -05001833 gl::Program *program = state.getProgram();
1834 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001835 {
Jamie Madill437fa652016-05-03 15:13:24 -04001836 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001837 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001838 }
1839
Geoff Lang7dd2e102014-11-10 15:19:26 -05001840 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001841 {
Jamie Madill437fa652016-05-03 15:13:24 -04001842 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001843 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001844 }
1845
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001846 // Uniform buffer validation
1847 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1848 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001849 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001850 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001851 const OffsetBindingPointer<Buffer> &uniformBuffer =
1852 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001853
Geoff Lang5d124a62015-09-15 13:03:27 -04001854 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001855 {
1856 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001857 context->handleError(
1858 Error(GL_INVALID_OPERATION,
1859 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001860 return false;
1861 }
1862
Geoff Lang5d124a62015-09-15 13:03:27 -04001863 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001864 if (uniformBufferSize == 0)
1865 {
1866 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001867 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001868 }
1869
Jamie Madill62d31cb2015-09-11 13:25:51 -04001870 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001871 {
1872 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001873 context->handleError(
1874 Error(GL_INVALID_OPERATION,
1875 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001876 return false;
1877 }
1878 }
1879
Jamie Madill250d33f2014-06-06 17:09:03 -04001880 // No-op if zero count
1881 return (count > 0);
1882}
1883
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001884bool ValidateDrawArrays(ValidationContext *context,
1885 GLenum mode,
1886 GLint first,
1887 GLsizei count,
1888 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001889{
Jamie Madillfd716582014-06-06 17:09:04 -04001890 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001891 {
Jamie Madill437fa652016-05-03 15:13:24 -04001892 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001893 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001894 }
1895
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001896 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001897 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001898 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1899 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001900 {
1901 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1902 // that does not match the current transform feedback object's draw mode (if transform feedback
1903 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001904 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001905 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001906 }
1907
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001908 if (!ValidateDrawBase(context, mode, count, primcount))
1909 {
1910 return false;
1911 }
1912
1913 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001914 {
1915 return false;
1916 }
1917
1918 return true;
1919}
1920
Geoff Langb1196682014-07-23 13:47:29 -04001921bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001922{
1923 if (primcount < 0)
1924 {
Jamie Madill437fa652016-05-03 15:13:24 -04001925 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001926 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001927 }
1928
Jamie Madill2b976812014-08-25 15:47:49 -04001929 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001930 {
1931 return false;
1932 }
1933
1934 // No-op if zero primitive count
1935 return (primcount > 0);
1936}
1937
Geoff Lang87a93302014-09-16 13:29:43 -04001938static bool ValidateDrawInstancedANGLE(Context *context)
1939{
1940 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001941 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04001942
Geoff Lang7dd2e102014-11-10 15:19:26 -05001943 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001944
1945 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001946 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001947 {
1948 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001949 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001950 {
1951 return true;
1952 }
1953 }
1954
Jamie Madill437fa652016-05-03 15:13:24 -04001955 context->handleError(Error(GL_INVALID_OPERATION,
1956 "ANGLE_instanced_arrays requires that at least one active attribute"
1957 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001958 return false;
1959}
1960
1961bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1962{
1963 if (!ValidateDrawInstancedANGLE(context))
1964 {
1965 return false;
1966 }
1967
1968 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1969}
1970
Jamie Madillf25855c2015-11-03 11:06:18 -05001971bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001972 GLenum mode,
1973 GLsizei count,
1974 GLenum type,
1975 const GLvoid *indices,
1976 GLsizei primcount,
1977 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001978{
Jamie Madill250d33f2014-06-06 17:09:03 -04001979 switch (type)
1980 {
1981 case GL_UNSIGNED_BYTE:
1982 case GL_UNSIGNED_SHORT:
1983 break;
1984 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001985 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001986 {
Jamie Madill437fa652016-05-03 15:13:24 -04001987 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001988 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001989 }
1990 break;
1991 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001992 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001993 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001994 }
1995
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001996 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001997
1998 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001999 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002000 {
2001 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2002 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002003 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002004 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002005 }
2006
2007 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002008 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002009 {
Jamie Madill437fa652016-05-03 15:13:24 -04002010 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002011 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002012 }
2013
Jamie Madill2b976812014-08-25 15:47:49 -04002014 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002015 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002016 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002017 {
Jamie Madill437fa652016-05-03 15:13:24 -04002018 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002019 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002020 }
2021
Jamie Madillae3000b2014-08-25 15:47:51 -04002022 if (elementArrayBuffer)
2023 {
2024 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2025
2026 GLint64 offset = reinterpret_cast<GLint64>(indices);
2027 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2028
2029 // check for integer overflows
2030 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2031 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2032 {
Jamie Madill437fa652016-05-03 15:13:24 -04002033 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002034 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002035 }
2036
2037 // Check for reading past the end of the bound buffer object
2038 if (byteCount > elementArrayBuffer->getSize())
2039 {
Jamie Madill437fa652016-05-03 15:13:24 -04002040 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002041 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002042 }
2043 }
2044 else if (!indices)
2045 {
2046 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002047 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002048 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002049 }
2050
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002051 if (!ValidateDrawBase(context, mode, count, primcount))
2052 {
2053 return false;
2054 }
2055
Jamie Madill2b976812014-08-25 15:47:49 -04002056 // Use max index to validate if our vertex buffers are large enough for the pull.
2057 // TODO: offer fast path, with disabled index validation.
2058 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2059 if (elementArrayBuffer)
2060 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002061 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002062 Error error =
2063 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2064 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002065 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002066 {
Jamie Madill437fa652016-05-03 15:13:24 -04002067 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002068 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002069 }
2070 }
2071 else
2072 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002073 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002074 }
2075
Jamie Madille79b1e12015-11-04 16:36:37 -05002076 // If we use an index greater than our maximum supported index range, return an error.
2077 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2078 // return an error if possible here.
2079 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2080 {
Jamie Madill437fa652016-05-03 15:13:24 -04002081 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002082 return false;
2083 }
2084
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002085 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002086 {
2087 return false;
2088 }
2089
Geoff Lang3edfe032015-09-04 16:38:24 -04002090 // No op if there are no real indices in the index data (all are primitive restart).
2091 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002092}
2093
Geoff Langb1196682014-07-23 13:47:29 -04002094bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002095 GLenum mode,
2096 GLsizei count,
2097 GLenum type,
2098 const GLvoid *indices,
2099 GLsizei primcount,
2100 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002101{
2102 if (primcount < 0)
2103 {
Jamie Madill437fa652016-05-03 15:13:24 -04002104 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002105 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002106 }
2107
Jamie Madill2b976812014-08-25 15:47:49 -04002108 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002109 {
2110 return false;
2111 }
2112
2113 // No-op zero primitive count
2114 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002115}
2116
Geoff Lang3edfe032015-09-04 16:38:24 -04002117bool ValidateDrawElementsInstancedANGLE(Context *context,
2118 GLenum mode,
2119 GLsizei count,
2120 GLenum type,
2121 const GLvoid *indices,
2122 GLsizei primcount,
2123 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002124{
2125 if (!ValidateDrawInstancedANGLE(context))
2126 {
2127 return false;
2128 }
2129
2130 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2131}
2132
Geoff Langb1196682014-07-23 13:47:29 -04002133bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002134 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002135{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002136 if (!ValidFramebufferTarget(target))
2137 {
Jamie Madill437fa652016-05-03 15:13:24 -04002138 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002139 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002140 }
2141
2142 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002143 {
2144 return false;
2145 }
2146
Jamie Madill55ec3b12014-07-03 10:38:57 -04002147 if (texture != 0)
2148 {
2149 gl::Texture *tex = context->getTexture(texture);
2150
2151 if (tex == NULL)
2152 {
Jamie Madill437fa652016-05-03 15:13:24 -04002153 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002154 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002155 }
2156
2157 if (level < 0)
2158 {
Jamie Madill437fa652016-05-03 15:13:24 -04002159 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002160 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002161 }
2162 }
2163
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002164 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002165 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002166
Jamie Madill84115c92015-04-23 15:00:07 -04002167 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002168 {
Jamie Madill437fa652016-05-03 15:13:24 -04002169 context->handleError(
2170 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002171 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002172 }
2173
2174 return true;
2175}
2176
Geoff Langb1196682014-07-23 13:47:29 -04002177bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002178 GLenum textarget, GLuint texture, GLint level)
2179{
Geoff Lang95663912015-04-02 15:54:45 -04002180 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2181 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002182 {
Jamie Madill437fa652016-05-03 15:13:24 -04002183 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002184 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002185 }
2186
2187 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002188 {
2189 return false;
2190 }
2191
Jamie Madill55ec3b12014-07-03 10:38:57 -04002192 if (texture != 0)
2193 {
2194 gl::Texture *tex = context->getTexture(texture);
2195 ASSERT(tex);
2196
Jamie Madill2a6564e2014-07-11 09:53:19 -04002197 const gl::Caps &caps = context->getCaps();
2198
Jamie Madill55ec3b12014-07-03 10:38:57 -04002199 switch (textarget)
2200 {
2201 case GL_TEXTURE_2D:
2202 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002203 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002204 {
Jamie Madill437fa652016-05-03 15:13:24 -04002205 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002206 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002207 }
2208 if (tex->getTarget() != GL_TEXTURE_2D)
2209 {
Jamie Madill437fa652016-05-03 15:13:24 -04002210 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002211 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002212 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002213 }
2214 break;
2215
2216 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2217 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2218 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2219 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2220 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2221 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2222 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002223 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002224 {
Jamie Madill437fa652016-05-03 15:13:24 -04002225 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002226 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002227 }
2228 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2229 {
Jamie Madill437fa652016-05-03 15:13:24 -04002230 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002231 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002232 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002233 }
2234 break;
2235
2236 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002237 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002238 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002239 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002240
2241 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2242 if (internalFormatInfo.compressed)
2243 {
Jamie Madill437fa652016-05-03 15:13:24 -04002244 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002245 return false;
2246 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002247 }
2248
Jamie Madill570f7c82014-07-03 10:38:54 -04002249 return true;
2250}
2251
Geoff Langb1196682014-07-23 13:47:29 -04002252bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002253{
2254 if (program == 0)
2255 {
Jamie Madill437fa652016-05-03 15:13:24 -04002256 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002257 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002258 }
2259
Dian Xiang769769a2015-09-09 15:20:08 -07002260 gl::Program *programObject = GetValidProgram(context, program);
2261 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002262 {
2263 return false;
2264 }
2265
Jamie Madill0063c512014-08-25 15:47:53 -04002266 if (!programObject || !programObject->isLinked())
2267 {
Jamie Madill437fa652016-05-03 15:13:24 -04002268 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002269 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002270 }
2271
Geoff Lang7dd2e102014-11-10 15:19:26 -05002272 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002273 {
Jamie Madill437fa652016-05-03 15:13:24 -04002274 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002275 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002276 }
2277
Jamie Madill0063c512014-08-25 15:47:53 -04002278 return true;
2279}
2280
Geoff Langb1196682014-07-23 13:47:29 -04002281bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002282{
2283 return ValidateGetUniformBase(context, program, location);
2284}
2285
Geoff Langb1196682014-07-23 13:47:29 -04002286bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002287{
Jamie Madill78f41802014-08-25 15:47:55 -04002288 return ValidateGetUniformBase(context, program, location);
2289}
2290
Geoff Langb1196682014-07-23 13:47:29 -04002291static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002292{
2293 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002294 {
Jamie Madill78f41802014-08-25 15:47:55 -04002295 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002296 }
2297
Jamie Madilla502c742014-08-28 17:19:13 -04002298 gl::Program *programObject = context->getProgram(program);
2299 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002300
Jamie Madill78f41802014-08-25 15:47:55 -04002301 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002302 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2303 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002304 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002305 {
Jamie Madill437fa652016-05-03 15:13:24 -04002306 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002307 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002308 }
2309
2310 return true;
2311}
2312
Geoff Langb1196682014-07-23 13:47:29 -04002313bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002314{
Jamie Madill78f41802014-08-25 15:47:55 -04002315 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002316}
2317
Geoff Langb1196682014-07-23 13:47:29 -04002318bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002319{
Jamie Madill78f41802014-08-25 15:47:55 -04002320 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002321}
2322
Austin Kinross08332632015-05-05 13:35:47 -07002323bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2324 const GLenum *attachments, bool defaultFramebuffer)
2325{
2326 if (numAttachments < 0)
2327 {
Jamie Madill437fa652016-05-03 15:13:24 -04002328 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002329 return false;
2330 }
2331
2332 for (GLsizei i = 0; i < numAttachments; ++i)
2333 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002334 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002335 {
2336 if (defaultFramebuffer)
2337 {
Jamie Madill437fa652016-05-03 15:13:24 -04002338 context->handleError(Error(
2339 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002340 return false;
2341 }
2342
2343 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2344 {
Jamie Madill437fa652016-05-03 15:13:24 -04002345 context->handleError(Error(GL_INVALID_OPERATION,
2346 "Requested color attachment is greater than the maximum "
2347 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002348 return false;
2349 }
2350 }
2351 else
2352 {
2353 switch (attachments[i])
2354 {
2355 case GL_DEPTH_ATTACHMENT:
2356 case GL_STENCIL_ATTACHMENT:
2357 case GL_DEPTH_STENCIL_ATTACHMENT:
2358 if (defaultFramebuffer)
2359 {
Jamie Madill437fa652016-05-03 15:13:24 -04002360 context->handleError(
2361 Error(GL_INVALID_ENUM,
2362 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002363 return false;
2364 }
2365 break;
2366 case GL_COLOR:
2367 case GL_DEPTH:
2368 case GL_STENCIL:
2369 if (!defaultFramebuffer)
2370 {
Jamie Madill437fa652016-05-03 15:13:24 -04002371 context->handleError(
2372 Error(GL_INVALID_ENUM,
2373 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002374 return false;
2375 }
2376 break;
2377 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002378 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002379 return false;
2380 }
2381 }
2382 }
2383
2384 return true;
2385}
2386
Austin Kinross6ee1e782015-05-29 17:05:37 -07002387bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2388{
2389 // Note that debug marker calls must not set error state
2390
2391 if (length < 0)
2392 {
2393 return false;
2394 }
2395
2396 if (marker == nullptr)
2397 {
2398 return false;
2399 }
2400
2401 return true;
2402}
2403
2404bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2405{
2406 // Note that debug marker calls must not set error state
2407
2408 if (length < 0)
2409 {
2410 return false;
2411 }
2412
2413 if (length > 0 && marker == nullptr)
2414 {
2415 return false;
2416 }
2417
2418 return true;
2419}
2420
Geoff Langdcab33b2015-07-21 13:03:16 -04002421bool ValidateEGLImageTargetTexture2DOES(Context *context,
2422 egl::Display *display,
2423 GLenum target,
2424 egl::Image *image)
2425{
Geoff Langa8406172015-07-21 16:53:39 -04002426 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2427 {
Jamie Madill437fa652016-05-03 15:13:24 -04002428 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002429 return false;
2430 }
2431
2432 switch (target)
2433 {
2434 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002435 if (!context->getExtensions().eglImage)
2436 {
2437 context->handleError(Error(
2438 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2439 }
2440 break;
2441
2442 case GL_TEXTURE_EXTERNAL_OES:
2443 if (!context->getExtensions().eglImageExternal)
2444 {
2445 context->handleError(Error(
2446 GL_INVALID_ENUM,
2447 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2448 }
Geoff Langa8406172015-07-21 16:53:39 -04002449 break;
2450
2451 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002452 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002453 return false;
2454 }
2455
2456 if (!display->isValidImage(image))
2457 {
Jamie Madill437fa652016-05-03 15:13:24 -04002458 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002459 return false;
2460 }
2461
2462 if (image->getSamples() > 0)
2463 {
Jamie Madill437fa652016-05-03 15:13:24 -04002464 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002465 "cannot create a 2D texture from a multisampled EGL image."));
2466 return false;
2467 }
2468
2469 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2470 if (!textureCaps.texturable)
2471 {
Jamie Madill437fa652016-05-03 15:13:24 -04002472 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002473 "EGL image internal format is not supported as a texture."));
2474 return false;
2475 }
2476
Geoff Langdcab33b2015-07-21 13:03:16 -04002477 return true;
2478}
2479
2480bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2481 egl::Display *display,
2482 GLenum target,
2483 egl::Image *image)
2484{
Geoff Langa8406172015-07-21 16:53:39 -04002485 if (!context->getExtensions().eglImage)
2486 {
Jamie Madill437fa652016-05-03 15:13:24 -04002487 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002488 return false;
2489 }
2490
2491 switch (target)
2492 {
2493 case GL_RENDERBUFFER:
2494 break;
2495
2496 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002497 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002498 return false;
2499 }
2500
2501 if (!display->isValidImage(image))
2502 {
Jamie Madill437fa652016-05-03 15:13:24 -04002503 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002504 return false;
2505 }
2506
2507 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2508 if (!textureCaps.renderable)
2509 {
Jamie Madill437fa652016-05-03 15:13:24 -04002510 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002511 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2512 return false;
2513 }
2514
Geoff Langdcab33b2015-07-21 13:03:16 -04002515 return true;
2516}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002517
2518bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2519{
Geoff Lang36167ab2015-12-07 10:27:14 -05002520 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002521 {
2522 // The default VAO should always exist
2523 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002524 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002525 return false;
2526 }
2527
2528 return true;
2529}
2530
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002531bool ValidateLinkProgram(Context *context, GLuint program)
2532{
2533 if (context->hasActiveTransformFeedback(program))
2534 {
2535 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002536 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002537 "Cannot link program while program is associated with an active "
2538 "transform feedback object."));
2539 return false;
2540 }
2541 return true;
2542}
2543
Geoff Langc5629752015-12-07 16:29:04 -05002544bool ValidateProgramBinaryBase(Context *context,
2545 GLuint program,
2546 GLenum binaryFormat,
2547 const void *binary,
2548 GLint length)
2549{
2550 Program *programObject = GetValidProgram(context, program);
2551 if (programObject == nullptr)
2552 {
2553 return false;
2554 }
2555
2556 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2557 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2558 programBinaryFormats.end())
2559 {
Jamie Madill437fa652016-05-03 15:13:24 -04002560 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002561 return false;
2562 }
2563
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002564 if (context->hasActiveTransformFeedback(program))
2565 {
2566 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002567 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002568 "Cannot change program binary while program is associated with "
2569 "an active transform feedback object."));
2570 return false;
2571 }
2572
Geoff Langc5629752015-12-07 16:29:04 -05002573 return true;
2574}
2575
2576bool ValidateGetProgramBinaryBase(Context *context,
2577 GLuint program,
2578 GLsizei bufSize,
2579 GLsizei *length,
2580 GLenum *binaryFormat,
2581 void *binary)
2582{
2583 Program *programObject = GetValidProgram(context, program);
2584 if (programObject == nullptr)
2585 {
2586 return false;
2587 }
2588
2589 if (!programObject->isLinked())
2590 {
Jamie Madill437fa652016-05-03 15:13:24 -04002591 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002592 return false;
2593 }
2594
2595 return true;
2596}
Jamie Madillc29968b2016-01-20 11:17:23 -05002597
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002598bool ValidateUseProgram(Context *context, GLuint program)
2599{
2600 if (program != 0)
2601 {
2602 Program *programObject = context->getProgram(program);
2603 if (!programObject)
2604 {
2605 // ES 3.1.0 section 7.3 page 72
2606 if (context->getShader(program))
2607 {
Jamie Madill437fa652016-05-03 15:13:24 -04002608 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002609 Error(GL_INVALID_OPERATION,
2610 "Attempted to use a single shader instead of a shader program."));
2611 return false;
2612 }
2613 else
2614 {
Jamie Madill437fa652016-05-03 15:13:24 -04002615 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002616 return false;
2617 }
2618 }
2619 if (!programObject->isLinked())
2620 {
Jamie Madill437fa652016-05-03 15:13:24 -04002621 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002622 return false;
2623 }
2624 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002625 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002626 {
2627 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002628 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002629 Error(GL_INVALID_OPERATION,
2630 "Cannot change active program while transform feedback is unpaused."));
2631 return false;
2632 }
2633
2634 return true;
2635}
2636
Jamie Madillc29968b2016-01-20 11:17:23 -05002637bool ValidateCopyTexImage2D(ValidationContext *context,
2638 GLenum target,
2639 GLint level,
2640 GLenum internalformat,
2641 GLint x,
2642 GLint y,
2643 GLsizei width,
2644 GLsizei height,
2645 GLint border)
2646{
2647 if (context->getClientVersion() < 3)
2648 {
2649 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2650 0, x, y, width, height, border);
2651 }
2652
2653 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002654 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2655 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002656}
Jamie Madillc29968b2016-01-20 11:17:23 -05002657
2658bool ValidateFramebufferRenderbuffer(Context *context,
2659 GLenum target,
2660 GLenum attachment,
2661 GLenum renderbuffertarget,
2662 GLuint renderbuffer)
2663{
2664 if (!ValidFramebufferTarget(target) ||
2665 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2666 {
Jamie Madill437fa652016-05-03 15:13:24 -04002667 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002668 return false;
2669 }
2670
2671 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2672 renderbuffertarget, renderbuffer);
2673}
2674
2675bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2676{
2677 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2678 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2679 {
Jamie Madill437fa652016-05-03 15:13:24 -04002680 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002681 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2682 return false;
2683 }
2684
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002685 ASSERT(context->getGLState().getDrawFramebuffer());
2686 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002687 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2688
2689 // This should come first before the check for the default frame buffer
2690 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2691 // rather than INVALID_OPERATION
2692 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2693 {
2694 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2695
2696 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002697 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2698 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002699 {
2700 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002701 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2702 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2703 // 3.1 is still a bit ambiguous about the error, but future specs are
2704 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002705 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002706 return false;
2707 }
2708 else if (bufs[colorAttachment] >= maxColorAttachment)
2709 {
Jamie Madill437fa652016-05-03 15:13:24 -04002710 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002711 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002712 return false;
2713 }
2714 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2715 frameBufferId != 0)
2716 {
2717 // INVALID_OPERATION-GL is bound to buffer and ith argument
2718 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002719 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002720 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2721 return false;
2722 }
2723 }
2724
2725 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2726 // and n is not 1 or bufs is bound to value other than BACK and NONE
2727 if (frameBufferId == 0)
2728 {
2729 if (n != 1)
2730 {
Jamie Madill437fa652016-05-03 15:13:24 -04002731 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002732 "n must be 1 when GL is bound to the default framebuffer"));
2733 return false;
2734 }
2735
2736 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2737 {
Jamie Madill437fa652016-05-03 15:13:24 -04002738 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002739 GL_INVALID_OPERATION,
2740 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2741 return false;
2742 }
2743 }
2744
2745 return true;
2746}
2747
2748bool ValidateCopyTexSubImage2D(Context *context,
2749 GLenum target,
2750 GLint level,
2751 GLint xoffset,
2752 GLint yoffset,
2753 GLint x,
2754 GLint y,
2755 GLsizei width,
2756 GLsizei height)
2757{
2758 if (context->getClientVersion() < 3)
2759 {
2760 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2761 yoffset, x, y, width, height, 0);
2762 }
2763
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002764 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2765 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002766}
2767
Olli Etuaho4f667482016-03-30 15:56:35 +03002768bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2769{
2770 if (!ValidBufferTarget(context, target))
2771 {
Jamie Madill437fa652016-05-03 15:13:24 -04002772 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002773 return false;
2774 }
2775
2776 if (pname != GL_BUFFER_MAP_POINTER)
2777 {
Jamie Madill437fa652016-05-03 15:13:24 -04002778 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002779 return false;
2780 }
2781
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002782 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002783
2784 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2785 // target bound to zero generate an INVALID_OPERATION error."
2786 // GLES 3.1 section 6.6 explicitly specifies this error.
2787 if (!buffer)
2788 {
Jamie Madill437fa652016-05-03 15:13:24 -04002789 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002790 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2791 return false;
2792 }
2793
2794 return true;
2795}
2796
2797bool ValidateUnmapBufferBase(Context *context, GLenum target)
2798{
2799 if (!ValidBufferTarget(context, target))
2800 {
Jamie Madill437fa652016-05-03 15:13:24 -04002801 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002802 return false;
2803 }
2804
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002805 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002806
2807 if (buffer == nullptr || !buffer->isMapped())
2808 {
Jamie Madill437fa652016-05-03 15:13:24 -04002809 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002810 return false;
2811 }
2812
2813 return true;
2814}
2815
2816bool ValidateMapBufferRangeBase(Context *context,
2817 GLenum target,
2818 GLintptr offset,
2819 GLsizeiptr length,
2820 GLbitfield access)
2821{
2822 if (!ValidBufferTarget(context, target))
2823 {
Jamie Madill437fa652016-05-03 15:13:24 -04002824 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002825 return false;
2826 }
2827
2828 if (offset < 0 || length < 0)
2829 {
Jamie Madill437fa652016-05-03 15:13:24 -04002830 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002831 return false;
2832 }
2833
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002834 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002835
2836 if (!buffer)
2837 {
Jamie Madill437fa652016-05-03 15:13:24 -04002838 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002839 return false;
2840 }
2841
2842 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002843 CheckedNumeric<size_t> checkedOffset(offset);
2844 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002845
Jamie Madille2e406c2016-06-02 13:04:10 -04002846 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002847 {
Jamie Madill437fa652016-05-03 15:13:24 -04002848 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002849 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2850 return false;
2851 }
2852
2853 // Check for invalid bits in the mask
2854 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2855 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2856 GL_MAP_UNSYNCHRONIZED_BIT;
2857
2858 if (access & ~(allAccessBits))
2859 {
Jamie Madill437fa652016-05-03 15:13:24 -04002860 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002861 return false;
2862 }
2863
2864 if (length == 0)
2865 {
Jamie Madill437fa652016-05-03 15:13:24 -04002866 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002867 return false;
2868 }
2869
2870 if (buffer->isMapped())
2871 {
Jamie Madill437fa652016-05-03 15:13:24 -04002872 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002873 return false;
2874 }
2875
2876 // Check for invalid bit combinations
2877 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2878 {
Jamie Madill437fa652016-05-03 15:13:24 -04002879 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002880 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2881 return false;
2882 }
2883
2884 GLbitfield writeOnlyBits =
2885 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2886
2887 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2888 {
Jamie Madill437fa652016-05-03 15:13:24 -04002889 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002890 "Invalid access bits when mapping buffer for reading: 0x%X.",
2891 access));
2892 return false;
2893 }
2894
2895 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2896 {
Jamie Madill437fa652016-05-03 15:13:24 -04002897 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002898 GL_INVALID_OPERATION,
2899 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2900 return false;
2901 }
2902 return true;
2903}
2904
2905bool ValidateFlushMappedBufferRangeBase(Context *context,
2906 GLenum target,
2907 GLintptr offset,
2908 GLsizeiptr length)
2909{
2910 if (offset < 0 || length < 0)
2911 {
Jamie Madill437fa652016-05-03 15:13:24 -04002912 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002913 return false;
2914 }
2915
2916 if (!ValidBufferTarget(context, target))
2917 {
Jamie Madill437fa652016-05-03 15:13:24 -04002918 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002919 return false;
2920 }
2921
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002922 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002923
2924 if (buffer == nullptr)
2925 {
Jamie Madill437fa652016-05-03 15:13:24 -04002926 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002927 return false;
2928 }
2929
2930 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2931 {
Jamie Madill437fa652016-05-03 15:13:24 -04002932 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002933 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2934 return false;
2935 }
2936
2937 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002938 CheckedNumeric<size_t> checkedOffset(offset);
2939 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002940
Jamie Madille2e406c2016-06-02 13:04:10 -04002941 if (!checkedSize.IsValid() ||
2942 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002943 {
Jamie Madill437fa652016-05-03 15:13:24 -04002944 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002945 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2946 return false;
2947 }
2948
2949 return true;
2950}
2951
Olli Etuaho0f2b1562016-05-13 16:15:35 +03002952bool ValidateGenerateMipmap(Context *context, GLenum target)
2953{
2954 if (!ValidTextureTarget(context, target))
2955 {
2956 context->handleError(Error(GL_INVALID_ENUM));
2957 return false;
2958 }
2959
2960 Texture *texture = context->getTargetTexture(target);
2961
2962 if (texture == nullptr)
2963 {
2964 context->handleError(Error(GL_INVALID_OPERATION));
2965 return false;
2966 }
2967
2968 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
2969
2970 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
2971 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
2972 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2973 {
2974 context->handleError(Error(GL_INVALID_OPERATION));
2975 return false;
2976 }
2977
2978 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
2979 GLenum internalFormat = texture->getInternalFormat(baseTarget, effectiveBaseLevel);
2980 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
2981 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
2982
2983 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
2984 // unsized formats or that are color renderable and filterable. Since we do not track if
2985 // the texture was created with sized or unsized format (only sized formats are stored),
2986 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
2987 // be able to) because they aren't color renderable. Simply do a special case for LUMA
2988 // textures since they're the only texture format that can be created with unsized formats
2989 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
2990 // was the last version to use add them.
2991 bool isLUMA = internalFormat == GL_LUMINANCE8_EXT ||
2992 internalFormat == GL_LUMINANCE8_ALPHA8_EXT || internalFormat == GL_ALPHA8_EXT;
2993
2994 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable ||
2995 (!formatCaps.renderable && !isLUMA) || formatInfo.compressed)
2996 {
2997 context->handleError(Error(GL_INVALID_OPERATION));
2998 return false;
2999 }
3000
3001 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
3002 if (context->getClientVersion() == 2 && formatInfo.colorEncoding == GL_SRGB)
3003 {
3004 context->handleError(Error(GL_INVALID_OPERATION));
3005 return false;
3006 }
3007
3008 // Non-power of 2 ES2 check
3009 if (!context->getExtensions().textureNPOT &&
3010 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3011 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3012 {
3013 ASSERT(context->getClientVersion() <= 2 &&
3014 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3015 context->handleError(Error(GL_INVALID_OPERATION));
3016 return false;
3017 }
3018
3019 // Cube completeness check
3020 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3021 {
3022 context->handleError(Error(GL_INVALID_OPERATION));
3023 return false;
3024 }
3025
3026 return true;
3027}
3028
Olli Etuaho41997e72016-03-10 13:38:39 +02003029bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3030{
3031 return ValidateGenOrDelete(context, n);
3032}
3033
3034bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3035{
3036 return ValidateGenOrDelete(context, n);
3037}
3038
3039bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3040{
3041 return ValidateGenOrDelete(context, n);
3042}
3043
3044bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3045{
3046 return ValidateGenOrDelete(context, n);
3047}
3048
3049bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3050{
3051 return ValidateGenOrDelete(context, n);
3052}
3053
3054bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3055{
3056 return ValidateGenOrDelete(context, n);
3057}
3058
3059bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3060{
3061 return ValidateGenOrDelete(context, n);
3062}
3063
3064bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3065{
3066 return ValidateGenOrDelete(context, n);
3067}
3068
3069bool ValidateGenOrDelete(Context *context, GLint n)
3070{
3071 if (n < 0)
3072 {
Jamie Madill437fa652016-05-03 15:13:24 -04003073 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003074 return false;
3075 }
3076 return true;
3077}
3078
Jamie Madillc29968b2016-01-20 11:17:23 -05003079} // namespace gl