blob: f574e22a1d46c20201c1a541977b0bf44c3a2ba6 [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:
Martin Radev1be913c2016-07-11 17:59:16 +0300126 return (context->getClientMajorVersion() >= 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:
Martin Radev1be913c2016-07-11 17:59:16 +0300147 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500148
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:
Martin Radev1be913c2016-07-11 17:59:16 +0300173 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500174
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:
Martin Radev1be913c2016-07-11 17:59:16 +0300246 return (context->getExtensions().pixelBufferObject ||
247 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400248
Shannon Woodsb3801742014-03-27 14:59:19 -0400249 case GL_COPY_READ_BUFFER:
250 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500251 case GL_TRANSFORM_FEEDBACK_BUFFER:
252 case GL_UNIFORM_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300253 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500254
255 default:
256 return false;
257 }
258}
259
Jamie Madill70656a62014-03-05 15:01:26 -0500260bool ValidBufferParameter(const Context *context, GLenum pname)
261{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400262 const Extensions &extensions = context->getExtensions();
263
Jamie Madill70656a62014-03-05 15:01:26 -0500264 switch (pname)
265 {
266 case GL_BUFFER_USAGE:
267 case GL_BUFFER_SIZE:
268 return true;
269
Geoff Langcc6f55d2015-03-20 13:01:02 -0400270 case GL_BUFFER_ACCESS_OES:
271 return extensions.mapBuffer;
272
273 case GL_BUFFER_MAPPED:
274 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
Martin Radev1be913c2016-07-11 17:59:16 +0300275 return (context->getClientMajorVersion() >= 3) || extensions.mapBuffer ||
276 extensions.mapBufferRange;
Geoff Langcc6f55d2015-03-20 13:01:02 -0400277
Jamie Madill70656a62014-03-05 15:01:26 -0500278 // GL_BUFFER_MAP_POINTER is a special case, and may only be
279 // queried with GetBufferPointerv
280 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500281 case GL_BUFFER_MAP_OFFSET:
282 case GL_BUFFER_MAP_LENGTH:
Martin Radev1be913c2016-07-11 17:59:16 +0300283 return (context->getClientMajorVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500284
285 default:
286 return false;
287 }
288}
289
Jamie Madillc29968b2016-01-20 11:17:23 -0500290bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400291{
Jamie Madillc29968b2016-01-20 11:17:23 -0500292 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400293 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400294 switch (target)
295 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500296 case GL_TEXTURE_2D:
297 maxDimension = caps.max2DTextureSize;
298 break;
Geoff Langce635692013-09-24 13:56:32 -0400299 case GL_TEXTURE_CUBE_MAP:
300 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
301 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
302 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
303 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
304 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500305 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
306 maxDimension = caps.maxCubeMapTextureSize;
307 break;
308 case GL_TEXTURE_3D:
309 maxDimension = caps.max3DTextureSize;
310 break;
311 case GL_TEXTURE_2D_ARRAY:
312 maxDimension = caps.max2DTextureSize;
313 break;
Geoff Langce635692013-09-24 13:56:32 -0400314 default: UNREACHABLE();
315 }
316
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700317 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400318}
319
Austin Kinross08528e12015-10-07 16:24:40 -0700320bool ValidImageSizeParameters(const Context *context,
321 GLenum target,
322 GLint level,
323 GLsizei width,
324 GLsizei height,
325 GLsizei depth,
326 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400327{
328 if (level < 0 || width < 0 || height < 0 || depth < 0)
329 {
330 return false;
331 }
332
Austin Kinross08528e12015-10-07 16:24:40 -0700333 // TexSubImage parameters can be NPOT without textureNPOT extension,
334 // as long as the destination texture is POT.
335 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400336 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400337 {
338 return false;
339 }
340
341 if (!ValidMipLevel(context, target, level))
342 {
343 return false;
344 }
345
346 return true;
347}
348
Geoff Lang0d8b7242015-09-09 14:56:53 -0400349bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
350{
351 // List of compressed format that require that the texture size is smaller than or a multiple of
352 // the compressed block size.
353 switch (internalFormat)
354 {
355 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
356 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
357 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
358 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800359 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400360 return true;
361
362 default:
363 return false;
364 }
365}
366
Jamie Madillc29968b2016-01-20 11:17:23 -0500367bool ValidCompressedImageSize(const ValidationContext *context,
368 GLenum internalFormat,
369 GLsizei width,
370 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400371{
Geoff Lang5d601382014-07-22 15:14:06 -0400372 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
373 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400374 {
375 return false;
376 }
377
Geoff Lang0d8b7242015-09-09 14:56:53 -0400378 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400379 {
380 return false;
381 }
382
Geoff Lang0d8b7242015-09-09 14:56:53 -0400383 if (CompressedTextureFormatRequiresExactSize(internalFormat))
384 {
385 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
386 width % formatInfo.compressedBlockWidth != 0) ||
387 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
388 height % formatInfo.compressedBlockHeight != 0))
389 {
390 return false;
391 }
392 }
393
Geoff Langd4f180b2013-09-24 13:57:44 -0400394 return true;
395}
396
Geoff Lang37dde692014-01-31 16:34:54 -0500397bool ValidQueryType(const Context *context, GLenum queryType)
398{
Geoff Langd4475812015-03-18 10:53:05 -0400399 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
400 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 -0500401
402 switch (queryType)
403 {
404 case GL_ANY_SAMPLES_PASSED:
405 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
406 return true;
407 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
Martin Radev1be913c2016-07-11 17:59:16 +0300408 return (context->getClientMajorVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500409 case GL_TIME_ELAPSED_EXT:
410 return context->getExtensions().disjointTimerQuery;
Geoff Lang2b4ce802016-04-28 13:34:50 -0400411 case GL_COMMANDS_COMPLETED_CHROMIUM:
412 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500413 default:
414 return false;
415 }
416}
417
Dian Xiang769769a2015-09-09 15:20:08 -0700418Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500419{
420 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
421 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
422 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
423
Dian Xiang769769a2015-09-09 15:20:08 -0700424 Program *validProgram = context->getProgram(id);
425
426 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500427 {
Dian Xiang769769a2015-09-09 15:20:08 -0700428 if (context->getShader(id))
429 {
Jamie Madill437fa652016-05-03 15:13:24 -0400430 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700431 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
432 }
433 else
434 {
Jamie Madill437fa652016-05-03 15:13:24 -0400435 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700436 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500437 }
Dian Xiang769769a2015-09-09 15:20:08 -0700438
439 return validProgram;
440}
441
442Shader *GetValidShader(Context *context, GLuint id)
443{
444 // See ValidProgram for spec details.
445
446 Shader *validShader = context->getShader(id);
447
448 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500449 {
Dian Xiang769769a2015-09-09 15:20:08 -0700450 if (context->getProgram(id))
451 {
Jamie Madill437fa652016-05-03 15:13:24 -0400452 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700453 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
454 }
455 else
456 {
Jamie Madill437fa652016-05-03 15:13:24 -0400457 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700458 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500459 }
Dian Xiang769769a2015-09-09 15:20:08 -0700460
461 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500462}
463
Geoff Langb1196682014-07-23 13:47:29 -0400464bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400465{
466 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
467 {
468 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
469
Geoff Langaae65a42014-05-26 12:43:44 -0400470 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400471 {
Jamie Madill437fa652016-05-03 15:13:24 -0400472 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400473 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400474 }
475 }
476 else
477 {
478 switch (attachment)
479 {
480 case GL_DEPTH_ATTACHMENT:
481 case GL_STENCIL_ATTACHMENT:
Martin Radev1be913c2016-07-11 17:59:16 +0300482 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400483
484 case GL_DEPTH_STENCIL_ATTACHMENT:
Martin Radev1be913c2016-07-11 17:59:16 +0300485 if (context->getClientMajorVersion() < 3)
486 {
487 context->handleError(Error(GL_INVALID_ENUM));
488 return false;
489 }
490 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400491
492 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400493 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300494 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400495 }
496 }
497
498 return true;
499}
500
Corentin Walleze0902642014-11-04 12:32:15 -0800501bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
502 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400503{
504 switch (target)
505 {
506 case GL_RENDERBUFFER:
507 break;
508 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400509 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400510 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400511 }
512
513 if (width < 0 || height < 0 || samples < 0)
514 {
Jamie Madill437fa652016-05-03 15:13:24 -0400515 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400516 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400517 }
518
Geoff Langd87878e2014-09-19 15:42:59 -0400519 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
520 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400521 {
Jamie Madill437fa652016-05-03 15:13:24 -0400522 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400523 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400524 }
525
526 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
527 // 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 -0800528 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400529 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400530 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400531 {
Jamie Madill437fa652016-05-03 15:13:24 -0400532 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400533 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400534 }
535
Geoff Langaae65a42014-05-26 12:43:44 -0400536 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400537 {
Jamie Madill437fa652016-05-03 15:13:24 -0400538 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400539 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400540 }
541
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700542 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400543 if (handle == 0)
544 {
Jamie Madill437fa652016-05-03 15:13:24 -0400545 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400546 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400547 }
548
549 return true;
550}
551
Corentin Walleze0902642014-11-04 12:32:15 -0800552bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
553 GLenum internalformat, GLsizei width, GLsizei height)
554{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800555 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800556
557 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400558 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800559 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400560 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800561 {
Jamie Madill437fa652016-05-03 15:13:24 -0400562 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800563 return false;
564 }
565
566 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
567 // the specified storage. This is different than ES 3.0 in which a sample number higher
568 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800569 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
Martin Radev1be913c2016-07-11 17:59:16 +0300570 if (context->getClientMajorVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800571 {
Geoff Langa4903b72015-03-02 16:02:48 -0800572 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
573 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
574 {
Jamie Madill437fa652016-05-03 15:13:24 -0400575 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800576 return false;
577 }
Corentin Walleze0902642014-11-04 12:32:15 -0800578 }
579
580 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
581}
582
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500583bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
584 GLenum renderbuffertarget, GLuint renderbuffer)
585{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400586 if (!ValidFramebufferTarget(target))
587 {
Jamie Madill437fa652016-05-03 15:13:24 -0400588 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400589 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400590 }
591
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700592 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500593
Jamie Madill84115c92015-04-23 15:00:07 -0400594 ASSERT(framebuffer);
595 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500596 {
Jamie Madill437fa652016-05-03 15:13:24 -0400597 context->handleError(
598 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400599 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500600 }
601
Jamie Madillb4472272014-07-03 10:38:55 -0400602 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500603 {
Jamie Madillb4472272014-07-03 10:38:55 -0400604 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500605 }
606
Jamie Madillab9d82c2014-01-21 16:38:14 -0500607 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
608 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
609 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
610 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
611 if (renderbuffer != 0)
612 {
613 if (!context->getRenderbuffer(renderbuffer))
614 {
Jamie Madill437fa652016-05-03 15:13:24 -0400615 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400616 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500617 }
618 }
619
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500620 return true;
621}
622
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700623bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500624 GLint srcX0,
625 GLint srcY0,
626 GLint srcX1,
627 GLint srcY1,
628 GLint dstX0,
629 GLint dstY0,
630 GLint dstX1,
631 GLint dstY1,
632 GLbitfield mask,
633 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634{
635 switch (filter)
636 {
637 case GL_NEAREST:
638 break;
639 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640 break;
641 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400642 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400643 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400644 }
645
646 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
647 {
Jamie Madill437fa652016-05-03 15:13:24 -0400648 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400649 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650 }
651
652 if (mask == 0)
653 {
654 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
655 // buffers are copied.
656 return false;
657 }
658
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
660 // color buffer, leaving only nearest being unfiltered from above
661 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
662 {
Jamie Madill437fa652016-05-03 15:13:24 -0400663 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400664 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665 }
666
Jamie Madill51f40ec2016-06-15 14:06:00 -0400667 const auto &glState = context->getGLState();
668 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
669 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500670
671 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 {
Jamie Madill437fa652016-05-03 15:13:24 -0400673 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400674 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 }
676
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700677 if (readFramebuffer->id() == drawFramebuffer->id())
678 {
679 context->handleError(Error(GL_INVALID_OPERATION));
680 return false;
681 }
682
Jamie Madill51f40ec2016-06-15 14:06:00 -0400683 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500684 {
Jamie Madill437fa652016-05-03 15:13:24 -0400685 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500686 return false;
687 }
688
Jamie Madill51f40ec2016-06-15 14:06:00 -0400689 if (drawFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500690 {
Jamie Madill437fa652016-05-03 15:13:24 -0400691 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500692 return false;
693 }
694
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700695 if (drawFramebuffer->getSamples(context->getContextState()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696 {
Jamie Madill437fa652016-05-03 15:13:24 -0400697 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400698 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400699 }
700
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400701 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
702
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 if (mask & GL_COLOR_BUFFER_BIT)
704 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400705 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
706 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500707 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400708
709 if (readColorBuffer && drawColorBuffer)
710 {
Geoff Langd8a22582014-12-17 15:28:23 -0500711 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400712 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400713
Geoff Langa15472a2015-08-11 11:48:03 -0400714 for (size_t drawbufferIdx = 0;
715 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400716 {
Geoff Langa15472a2015-08-11 11:48:03 -0400717 const FramebufferAttachment *attachment =
718 drawFramebuffer->getDrawBuffer(drawbufferIdx);
719 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400720 {
Geoff Langa15472a2015-08-11 11:48:03 -0400721 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400722 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400723
Geoff Langb2f3d052013-08-13 12:49:27 -0400724 // The GL ES 3.0.2 spec (pg 193) states that:
725 // 1) If the read buffer is fixed point format, the draw buffer must be as well
726 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
727 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500728 // Changes with EXT_color_buffer_float:
729 // Case 1) is changed to fixed point OR floating point
730 GLenum readComponentType = readFormatInfo.componentType;
731 GLenum drawComponentType = drawFormatInfo.componentType;
732 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
733 readComponentType == GL_SIGNED_NORMALIZED);
734 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
735 drawComponentType == GL_SIGNED_NORMALIZED);
736
737 if (extensions.colorBufferFloat)
738 {
739 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
740 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
741
742 if (readFixedOrFloat != drawFixedOrFloat)
743 {
Jamie Madill437fa652016-05-03 15:13:24 -0400744 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500745 "If the read buffer contains fixed-point or "
746 "floating-point values, the draw buffer "
747 "must as well."));
748 return false;
749 }
750 }
751 else if (readFixedPoint != drawFixedPoint)
752 {
Jamie Madill437fa652016-05-03 15:13:24 -0400753 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500754 "If the read buffer contains fixed-point "
755 "values, the draw buffer must as well."));
756 return false;
757 }
758
759 if (readComponentType == GL_UNSIGNED_INT &&
760 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 {
Jamie Madill437fa652016-05-03 15:13:24 -0400762 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400763 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 }
765
Jamie Madill6163c752015-12-07 16:32:59 -0500766 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 {
Jamie Madill437fa652016-05-03 15:13:24 -0400768 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400769 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 }
771
Geoff Langb2f3d052013-08-13 12:49:27 -0400772 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773 {
Jamie Madill437fa652016-05-03 15:13:24 -0400774 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400775 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400776 }
777 }
778 }
779
Geoff Lang5d601382014-07-22 15:14:06 -0400780 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400781 {
Jamie Madill437fa652016-05-03 15:13:24 -0400782 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400783 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400784 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785 }
786 }
787
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200788 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
789 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
790 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200792 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400794 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
795 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200797 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798 {
Geoff Langd8a22582014-12-17 15:28:23 -0500799 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 {
Jamie Madill437fa652016-05-03 15:13:24 -0400801 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400802 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400804
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200805 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806 {
Jamie Madill437fa652016-05-03 15:13:24 -0400807 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400808 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400809 }
810 }
811 }
812 }
813
814 return true;
815}
816
Geoff Langb1196682014-07-23 13:47:29 -0400817bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400818{
819 switch (pname)
820 {
821 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
822 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
823 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
824 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
825 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
826 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
827 case GL_CURRENT_VERTEX_ATTRIB:
Martin Radev1be913c2016-07-11 17:59:16 +0300828 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829
830 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
Martin Radev1be913c2016-07-11 17:59:16 +0300831 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
832 // the same constant.
833 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
834 "ANGLE extension enums not equal to GL enums.");
835 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400836
837 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Martin Radev1be913c2016-07-11 17:59:16 +0300838 if (context->getClientMajorVersion() < 3)
839 {
840 context->handleError(Error(GL_INVALID_ENUM));
841 return false;
842 }
843 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400844
845 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400846 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300847 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400848 }
849}
850
Ian Ewellbda75592016-04-18 17:25:54 -0400851bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400852{
853 switch (pname)
854 {
855 case GL_TEXTURE_WRAP_R:
856 case GL_TEXTURE_SWIZZLE_R:
857 case GL_TEXTURE_SWIZZLE_G:
858 case GL_TEXTURE_SWIZZLE_B:
859 case GL_TEXTURE_SWIZZLE_A:
860 case GL_TEXTURE_BASE_LEVEL:
861 case GL_TEXTURE_MAX_LEVEL:
862 case GL_TEXTURE_COMPARE_MODE:
863 case GL_TEXTURE_COMPARE_FUNC:
864 case GL_TEXTURE_MIN_LOD:
865 case GL_TEXTURE_MAX_LOD:
Martin Radev1be913c2016-07-11 17:59:16 +0300866 if (context->getClientMajorVersion() < 3)
867 {
868 context->handleError(Error(GL_INVALID_ENUM));
869 return false;
870 }
871 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
872 {
873 context->handleError(Error(GL_INVALID_ENUM,
874 "ES3 texture parameters are not available without "
875 "GL_OES_EGL_image_external_essl3."));
876 return false;
877 }
878 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400879
880 default: break;
881 }
882
883 switch (pname)
884 {
885 case GL_TEXTURE_WRAP_S:
886 case GL_TEXTURE_WRAP_T:
887 case GL_TEXTURE_WRAP_R:
888 switch (param)
889 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000890 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400891 return true;
892 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400893 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300894 if (target == GL_TEXTURE_EXTERNAL_OES)
895 {
896 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400897 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300898 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
899 return false;
900 }
901 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400902 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400903 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400904 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400905 }
906
907 case GL_TEXTURE_MIN_FILTER:
908 switch (param)
909 {
910 case GL_NEAREST:
911 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400912 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400913 case GL_NEAREST_MIPMAP_NEAREST:
914 case GL_LINEAR_MIPMAP_NEAREST:
915 case GL_NEAREST_MIPMAP_LINEAR:
916 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300917 if (target == GL_TEXTURE_EXTERNAL_OES)
918 {
919 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400920 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300921 Error(GL_INVALID_ENUM,
922 "external textures only support NEAREST and LINEAR filtering"));
923 return false;
924 }
925 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400926 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400927 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400928 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400929 }
930 break;
931
932 case GL_TEXTURE_MAG_FILTER:
933 switch (param)
934 {
935 case GL_NEAREST:
936 case GL_LINEAR:
937 return true;
938 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400939 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400940 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400941 }
942 break;
943
944 case GL_TEXTURE_USAGE_ANGLE:
945 switch (param)
946 {
947 case GL_NONE:
948 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
949 return true;
950 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400951 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400952 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400953 }
954 break;
955
956 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400957 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400958 {
Jamie Madill437fa652016-05-03 15:13:24 -0400959 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400960 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400961 }
962
963 // we assume the parameter passed to this validation method is truncated, not rounded
964 if (param < 1)
965 {
Jamie Madill437fa652016-05-03 15:13:24 -0400966 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400967 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400968 }
969 return true;
970
971 case GL_TEXTURE_MIN_LOD:
972 case GL_TEXTURE_MAX_LOD:
973 // any value is permissible
974 return true;
975
976 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400977 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400978 switch (param)
979 {
980 case GL_NONE:
981 case GL_COMPARE_REF_TO_TEXTURE:
982 return true;
983 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400984 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400985 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400986 }
987 break;
988
989 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400990 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400991 switch (param)
992 {
993 case GL_LEQUAL:
994 case GL_GEQUAL:
995 case GL_LESS:
996 case GL_GREATER:
997 case GL_EQUAL:
998 case GL_NOTEQUAL:
999 case GL_ALWAYS:
1000 case GL_NEVER:
1001 return true;
1002 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001003 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001004 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001005 }
1006 break;
1007
1008 case GL_TEXTURE_SWIZZLE_R:
1009 case GL_TEXTURE_SWIZZLE_G:
1010 case GL_TEXTURE_SWIZZLE_B:
1011 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001012 switch (param)
1013 {
1014 case GL_RED:
1015 case GL_GREEN:
1016 case GL_BLUE:
1017 case GL_ALPHA:
1018 case GL_ZERO:
1019 case GL_ONE:
1020 return true;
1021 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001022 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001023 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001024 }
1025 break;
1026
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001027 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001028 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001029 {
Geoff Langb66a9092016-05-16 15:59:14 -04001030 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001031 return false;
1032 }
Geoff Langb66a9092016-05-16 15:59:14 -04001033 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1034 {
1035 context->handleError(
1036 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1037 return false;
1038 }
1039 return true;
1040
1041 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001042 if (param < 0)
1043 {
1044 context->handleError(Error(GL_INVALID_VALUE));
1045 return false;
1046 }
1047 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001048 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001049 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001050 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001051 }
1052}
1053
Geoff Langb1196682014-07-23 13:47:29 -04001054bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001055{
1056 switch (pname)
1057 {
1058 case GL_TEXTURE_MIN_FILTER:
1059 case GL_TEXTURE_MAG_FILTER:
1060 case GL_TEXTURE_WRAP_S:
1061 case GL_TEXTURE_WRAP_T:
1062 case GL_TEXTURE_WRAP_R:
1063 case GL_TEXTURE_MIN_LOD:
1064 case GL_TEXTURE_MAX_LOD:
1065 case GL_TEXTURE_COMPARE_MODE:
1066 case GL_TEXTURE_COMPARE_FUNC:
1067 return true;
1068
1069 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001070 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001071 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001072 }
1073}
1074
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001075bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001076 GLint x,
1077 GLint y,
1078 GLsizei width,
1079 GLsizei height,
1080 GLenum format,
1081 GLenum type,
1082 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001083{
Jamie Madillc29968b2016-01-20 11:17:23 -05001084 if (width < 0 || height < 0)
1085 {
Jamie Madill437fa652016-05-03 15:13:24 -04001086 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001087 return false;
1088 }
1089
Jamie Madill51f40ec2016-06-15 14:06:00 -04001090 auto readFramebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill26e91952014-03-05 15:01:27 -05001091
Jamie Madill51f40ec2016-06-15 14:06:00 -04001092 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001093 {
Jamie Madill437fa652016-05-03 15:13:24 -04001094 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001095 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001096 }
1097
Jamie Madill51f40ec2016-06-15 14:06:00 -04001098 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001099 {
Jamie Madill437fa652016-05-03 15:13:24 -04001100 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001101 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001102 }
1103
Jamie Madill51f40ec2016-06-15 14:06:00 -04001104 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1105 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001106
1107 if (framebuffer->getReadBufferState() == GL_NONE)
1108 {
1109 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1110 return false;
1111 }
1112
Geoff Langbce529e2014-12-01 12:48:41 -05001113 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1114 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001115 {
Jamie Madill437fa652016-05-03 15:13:24 -04001116 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001117 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001118 }
1119
Geoff Langbce529e2014-12-01 12:48:41 -05001120 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1121 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001122 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Martin Radev1be913c2016-07-11 17:59:16 +03001123 GLuint clientVersion = context->getClientMajorVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001124
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001125 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1126 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001127
1128 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1129 {
Jamie Madill437fa652016-05-03 15:13:24 -04001130 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001131 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001132 }
1133
Jamie Madillc29968b2016-01-20 11:17:23 -05001134 return true;
1135}
1136
1137bool ValidateReadnPixelsEXT(Context *context,
1138 GLint x,
1139 GLint y,
1140 GLsizei width,
1141 GLsizei height,
1142 GLenum format,
1143 GLenum type,
1144 GLsizei bufSize,
1145 GLvoid *pixels)
1146{
1147 if (bufSize < 0)
1148 {
Jamie Madill437fa652016-05-03 15:13:24 -04001149 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001150 return false;
1151 }
1152
Geoff Lang5d601382014-07-22 15:14:06 -04001153 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1154 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001155
Jamie Madille2e406c2016-06-02 13:04:10 -04001156 auto outputPitchOrErr =
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001157 sizedFormatInfo.computeRowPitch(type, width, context->getGLState().getPackAlignment(),
1158 context->getGLState().getPackRowLength());
Jamie Madille2e406c2016-06-02 13:04:10 -04001159
1160 if (outputPitchOrErr.isError())
1161 {
1162 context->handleError(outputPitchOrErr.getError());
1163 return false;
1164 }
1165
1166 CheckedNumeric<GLuint> checkedOutputPitch(outputPitchOrErr.getResult());
1167 auto checkedRequiredSize = checkedOutputPitch * height;
1168 if (!checkedRequiredSize.IsValid())
1169 {
1170 context->handleError(Error(GL_INVALID_OPERATION, "Unsigned multiplication overflow."));
1171 return false;
1172 }
1173
Jamie Madill26e91952014-03-05 15:01:27 -05001174 // sized query sanity check
Jamie Madille2e406c2016-06-02 13:04:10 -04001175 if (checkedRequiredSize.ValueOrDie() > static_cast<GLuint>(bufSize))
Jamie Madill26e91952014-03-05 15:01:27 -05001176 {
Jamie Madill437fa652016-05-03 15:13:24 -04001177 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001178 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001179 }
1180
Jamie Madillc29968b2016-01-20 11:17:23 -05001181 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001182}
1183
Olli Etuaho41997e72016-03-10 13:38:39 +02001184bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001185{
1186 if (!context->getExtensions().occlusionQueryBoolean &&
1187 !context->getExtensions().disjointTimerQuery)
1188 {
Jamie Madill437fa652016-05-03 15:13:24 -04001189 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001190 return false;
1191 }
1192
Olli Etuaho41997e72016-03-10 13:38:39 +02001193 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001194}
1195
Olli Etuaho41997e72016-03-10 13:38:39 +02001196bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001197{
1198 if (!context->getExtensions().occlusionQueryBoolean &&
1199 !context->getExtensions().disjointTimerQuery)
1200 {
Jamie Madill437fa652016-05-03 15:13:24 -04001201 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001202 return false;
1203 }
1204
Olli Etuaho41997e72016-03-10 13:38:39 +02001205 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001206}
1207
1208bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001209{
1210 if (!ValidQueryType(context, target))
1211 {
Jamie Madill437fa652016-05-03 15:13:24 -04001212 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001213 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001214 }
1215
1216 if (id == 0)
1217 {
Jamie Madill437fa652016-05-03 15:13:24 -04001218 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001219 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001220 }
1221
1222 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1223 // of zero, if the active query object name for <target> is non-zero (for the
1224 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1225 // the active query for either target is non-zero), if <id> is the name of an
1226 // existing query object whose type does not match <target>, or if <id> is the
1227 // active query object name for any query type, the error INVALID_OPERATION is
1228 // generated.
1229
1230 // Ensure no other queries are active
1231 // NOTE: If other queries than occlusion are supported, we will need to check
1232 // separately that:
1233 // a) The query ID passed is not the current active query for any target/type
1234 // b) There are no active queries for the requested target (and in the case
1235 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1236 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001237
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001238 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001239 {
Jamie Madill437fa652016-05-03 15:13:24 -04001240 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001241 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001242 }
1243
1244 Query *queryObject = context->getQuery(id, true, target);
1245
1246 // check that name was obtained with glGenQueries
1247 if (!queryObject)
1248 {
Jamie Madill437fa652016-05-03 15:13:24 -04001249 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001250 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001251 }
1252
1253 // check for type mismatch
1254 if (queryObject->getType() != target)
1255 {
Jamie Madill437fa652016-05-03 15:13:24 -04001256 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001257 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001258 }
1259
1260 return true;
1261}
1262
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001263bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1264{
1265 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001266 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001267 {
Jamie Madill437fa652016-05-03 15:13:24 -04001268 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001269 return false;
1270 }
1271
1272 return ValidateBeginQueryBase(context, target, id);
1273}
1274
1275bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001276{
1277 if (!ValidQueryType(context, target))
1278 {
Jamie Madill437fa652016-05-03 15:13:24 -04001279 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001280 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001281 }
1282
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001283 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001284
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001285 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001286 {
Jamie Madill437fa652016-05-03 15:13:24 -04001287 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001288 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001289 }
1290
Jamie Madill45c785d2014-05-13 14:09:34 -04001291 return true;
1292}
1293
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001294bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1295{
1296 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001297 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001298 {
Jamie Madill437fa652016-05-03 15:13:24 -04001299 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001300 return false;
1301 }
1302
1303 return ValidateEndQueryBase(context, target);
1304}
1305
1306bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1307{
1308 if (!context->getExtensions().disjointTimerQuery)
1309 {
Jamie Madill437fa652016-05-03 15:13:24 -04001310 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001311 return false;
1312 }
1313
1314 if (target != GL_TIMESTAMP_EXT)
1315 {
Jamie Madill437fa652016-05-03 15:13:24 -04001316 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001317 return false;
1318 }
1319
1320 Query *queryObject = context->getQuery(id, true, target);
1321 if (queryObject == nullptr)
1322 {
Jamie Madill437fa652016-05-03 15:13:24 -04001323 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001324 return false;
1325 }
1326
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001327 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001328 {
Jamie Madill437fa652016-05-03 15:13:24 -04001329 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001330 return false;
1331 }
1332
1333 return true;
1334}
1335
1336bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1337{
1338 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1339 {
Jamie Madill437fa652016-05-03 15:13:24 -04001340 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001341 return false;
1342 }
1343
1344 switch (pname)
1345 {
1346 case GL_CURRENT_QUERY_EXT:
1347 if (target == GL_TIMESTAMP_EXT)
1348 {
Jamie Madill437fa652016-05-03 15:13:24 -04001349 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001350 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1351 return false;
1352 }
1353 break;
1354 case GL_QUERY_COUNTER_BITS_EXT:
1355 if (!context->getExtensions().disjointTimerQuery ||
1356 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1357 {
Jamie Madill437fa652016-05-03 15:13:24 -04001358 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001359 return false;
1360 }
1361 break;
1362 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001363 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001364 return false;
1365 }
1366
1367 return true;
1368}
1369
1370bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1371{
1372 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001373 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001374 {
Jamie Madill437fa652016-05-03 15:13:24 -04001375 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001376 return false;
1377 }
1378
1379 return ValidateGetQueryivBase(context, target, pname);
1380}
1381
1382bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1383{
1384 Query *queryObject = context->getQuery(id, false, GL_NONE);
1385
1386 if (!queryObject)
1387 {
Jamie Madill437fa652016-05-03 15:13:24 -04001388 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001389 return false;
1390 }
1391
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001392 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001393 {
Jamie Madill437fa652016-05-03 15:13:24 -04001394 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001395 return false;
1396 }
1397
1398 switch (pname)
1399 {
1400 case GL_QUERY_RESULT_EXT:
1401 case GL_QUERY_RESULT_AVAILABLE_EXT:
1402 break;
1403
1404 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001405 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001406 return false;
1407 }
1408
1409 return true;
1410}
1411
1412bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1413{
1414 if (!context->getExtensions().disjointTimerQuery)
1415 {
Jamie Madill437fa652016-05-03 15:13:24 -04001416 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001417 return false;
1418 }
1419 return ValidateGetQueryObjectValueBase(context, id, pname);
1420}
1421
1422bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1423{
1424 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001425 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001426 {
Jamie Madill437fa652016-05-03 15:13:24 -04001427 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001428 return false;
1429 }
1430 return ValidateGetQueryObjectValueBase(context, id, pname);
1431}
1432
1433bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1434{
1435 if (!context->getExtensions().disjointTimerQuery)
1436 {
Jamie Madill437fa652016-05-03 15:13:24 -04001437 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001438 return false;
1439 }
1440 return ValidateGetQueryObjectValueBase(context, id, pname);
1441}
1442
1443bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1444{
1445 if (!context->getExtensions().disjointTimerQuery)
1446 {
Jamie Madill437fa652016-05-03 15:13:24 -04001447 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001448 return false;
1449 }
1450 return ValidateGetQueryObjectValueBase(context, id, pname);
1451}
1452
Jamie Madill62d31cb2015-09-11 13:25:51 -04001453static bool ValidateUniformCommonBase(gl::Context *context,
1454 GLenum targetUniformType,
1455 GLint location,
1456 GLsizei count,
1457 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001458{
1459 if (count < 0)
1460 {
Jamie Madill437fa652016-05-03 15:13:24 -04001461 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001462 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001463 }
1464
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001465 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001466 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001467 {
Jamie Madill437fa652016-05-03 15:13:24 -04001468 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001469 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001470 }
1471
Geoff Langd8605522016-04-13 10:19:12 -04001472 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001473 {
1474 // Silently ignore the uniform command
1475 return false;
1476 }
1477
Geoff Lang7dd2e102014-11-10 15:19:26 -05001478 if (!program->isValidUniformLocation(location))
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 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001485
1486 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001487 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001488 {
Jamie Madill437fa652016-05-03 15:13:24 -04001489 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001490 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001491 }
1492
Jamie Madill62d31cb2015-09-11 13:25:51 -04001493 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001494 return true;
1495}
1496
Jamie Madillaa981bd2014-05-20 10:55:55 -04001497bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1498{
1499 // Check for ES3 uniform entry points
Martin Radev1be913c2016-07-11 17:59:16 +03001500 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT &&
1501 context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001502 {
Jamie Madill437fa652016-05-03 15:13:24 -04001503 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001504 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001505 }
1506
Jamie Madill62d31cb2015-09-11 13:25:51 -04001507 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001508 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1509 {
1510 return false;
1511 }
1512
Jamie Madillf2575982014-06-25 16:04:54 -04001513 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001514 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001515 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1516 {
Jamie Madill437fa652016-05-03 15:13:24 -04001517 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001518 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001519 }
1520
1521 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001522}
1523
1524bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1525 GLboolean transpose)
1526{
1527 // Check for ES3 uniform entry points
1528 int rows = VariableRowCount(matrixType);
1529 int cols = VariableColumnCount(matrixType);
Martin Radev1be913c2016-07-11 17:59:16 +03001530 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001531 {
Jamie Madill437fa652016-05-03 15:13:24 -04001532 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001533 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001534 }
1535
Martin Radev1be913c2016-07-11 17:59:16 +03001536 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001537 {
Jamie Madill437fa652016-05-03 15:13:24 -04001538 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001539 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001540 }
1541
Jamie Madill62d31cb2015-09-11 13:25:51 -04001542 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001543 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1544 {
1545 return false;
1546 }
1547
1548 if (uniform->type != matrixType)
1549 {
Jamie Madill437fa652016-05-03 15:13:24 -04001550 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001551 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001552 }
1553
1554 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001555}
1556
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001557bool ValidateStateQuery(ValidationContext *context,
1558 GLenum pname,
1559 GLenum *nativeType,
1560 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001561{
1562 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1563 {
Jamie Madill437fa652016-05-03 15:13:24 -04001564 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001565 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001566 }
1567
Jamie Madill0af26e12015-03-05 19:54:33 -05001568 const Caps &caps = context->getCaps();
1569
Jamie Madill893ab082014-05-16 16:56:10 -04001570 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1571 {
1572 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1573
Jamie Madill0af26e12015-03-05 19:54:33 -05001574 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001575 {
Jamie Madill437fa652016-05-03 15:13:24 -04001576 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001577 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001578 }
1579 }
1580
1581 switch (pname)
1582 {
1583 case GL_TEXTURE_BINDING_2D:
1584 case GL_TEXTURE_BINDING_CUBE_MAP:
1585 case GL_TEXTURE_BINDING_3D:
1586 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001587 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001588 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1589 if (!context->getExtensions().eglStreamConsumerExternal)
1590 {
Jamie Madill437fa652016-05-03 15:13:24 -04001591 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001592 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1593 return false;
1594 }
1595 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001596
1597 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1598 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1599 {
Jamie Madill51f40ec2016-06-15 14:06:00 -04001600 if (context->getGLState().getReadFramebuffer()->checkStatus(
1601 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001602 {
Jamie Madill437fa652016-05-03 15:13:24 -04001603 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001604 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001605 }
1606
Jamie Madill51f40ec2016-06-15 14:06:00 -04001607 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1608 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001609
1610 if (framebuffer->getReadBufferState() == GL_NONE)
1611 {
1612 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1613 return false;
1614 }
1615
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001616 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001617 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001618 {
Jamie Madill437fa652016-05-03 15:13:24 -04001619 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001620 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001621 }
1622 }
1623 break;
1624
1625 default:
1626 break;
1627 }
1628
1629 // pname is valid, but there are no parameters to return
1630 if (numParams == 0)
1631 {
1632 return false;
1633 }
1634
1635 return true;
1636}
1637
Jamie Madillc29968b2016-01-20 11:17:23 -05001638bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1639 GLenum target,
1640 GLint level,
1641 GLenum internalformat,
1642 bool isSubImage,
1643 GLint xoffset,
1644 GLint yoffset,
1645 GLint zoffset,
1646 GLint x,
1647 GLint y,
1648 GLsizei width,
1649 GLsizei height,
1650 GLint border,
1651 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001652{
Jamie Madill560a8d82014-05-21 13:06:20 -04001653 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1654 {
Jamie Madill437fa652016-05-03 15:13:24 -04001655 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001656 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001657 }
1658
1659 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1660 {
Jamie Madill437fa652016-05-03 15:13:24 -04001661 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001662 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001663 }
1664
1665 if (border != 0)
1666 {
Jamie Madill437fa652016-05-03 15:13:24 -04001667 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001668 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001669 }
1670
1671 if (!ValidMipLevel(context, target, level))
1672 {
Jamie Madill437fa652016-05-03 15:13:24 -04001673 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001674 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001675 }
1676
Jamie Madill51f40ec2016-06-15 14:06:00 -04001677 const auto &state = context->getGLState();
1678 auto readFramebuffer = state.getReadFramebuffer();
1679 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001680 {
Jamie Madill437fa652016-05-03 15:13:24 -04001681 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001682 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001683 }
1684
Jamie Madill51f40ec2016-06-15 14:06:00 -04001685 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001686 {
Jamie Madill437fa652016-05-03 15:13:24 -04001687 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001688 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001689 }
1690
Martin Radev138064f2016-07-15 12:03:41 +03001691 if (readFramebuffer->getReadBufferState() == GL_NONE)
1692 {
1693 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1694 return false;
1695 }
1696
Geoff Langaae65a42014-05-26 12:43:44 -04001697 const gl::Caps &caps = context->getCaps();
1698
Geoff Langaae65a42014-05-26 12:43:44 -04001699 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001700 switch (target)
1701 {
1702 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001703 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001704 break;
1705
1706 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1707 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1708 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1709 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1710 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1711 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001712 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001713 break;
1714
1715 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001716 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001717 break;
1718
1719 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001720 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001721 break;
1722
1723 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001724 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001725 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001726 }
1727
Jamie Madillc29968b2016-01-20 11:17:23 -05001728 gl::Texture *texture =
1729 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001730 if (!texture)
1731 {
Jamie Madill437fa652016-05-03 15:13:24 -04001732 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001733 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001734 }
1735
Geoff Lang69cce582015-09-17 13:20:36 -04001736 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001737 {
Jamie Madill437fa652016-05-03 15:13:24 -04001738 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001739 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001740 }
1741
Geoff Lang5d601382014-07-22 15:14:06 -04001742 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1743
1744 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001745 {
Jamie Madill437fa652016-05-03 15:13:24 -04001746 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001747 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001748 }
1749
Geoff Langa9be0dc2014-12-17 12:34:40 -05001750 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001751 {
Jamie Madill437fa652016-05-03 15:13:24 -04001752 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001753 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001754 }
1755
1756 if (isSubImage)
1757 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001758 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1759 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1760 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001761 {
Jamie Madill437fa652016-05-03 15:13:24 -04001762 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001763 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001764 }
1765 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001766 else
1767 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001768 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001769 {
Jamie Madill437fa652016-05-03 15:13:24 -04001770 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001771 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001772 }
1773
Martin Radev1be913c2016-07-11 17:59:16 +03001774 if (!formatInfo.textureSupport(context->getClientMajorVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001775 {
Jamie Madill437fa652016-05-03 15:13:24 -04001776 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001777 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001778 }
1779
1780 int maxLevelDimension = (maxDimension >> level);
1781 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1782 {
Jamie Madill437fa652016-05-03 15:13:24 -04001783 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001784 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001785 }
1786 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001787
Geoff Langa9be0dc2014-12-17 12:34:40 -05001788 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001789 return true;
1790}
1791
Jamie Madillf25855c2015-11-03 11:06:18 -05001792static bool ValidateDrawBase(ValidationContext *context,
1793 GLenum mode,
1794 GLsizei count,
1795 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001796{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001797 switch (mode)
1798 {
1799 case GL_POINTS:
1800 case GL_LINES:
1801 case GL_LINE_LOOP:
1802 case GL_LINE_STRIP:
1803 case GL_TRIANGLES:
1804 case GL_TRIANGLE_STRIP:
1805 case GL_TRIANGLE_FAN:
1806 break;
1807 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001808 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001809 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001810 }
1811
Jamie Madill250d33f2014-06-06 17:09:03 -04001812 if (count < 0)
1813 {
Jamie Madill437fa652016-05-03 15:13:24 -04001814 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001815 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001816 }
1817
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001818 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001819
Jamie Madill250d33f2014-06-06 17:09:03 -04001820 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001821 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001822 {
Jamie Madill437fa652016-05-03 15:13:24 -04001823 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001824 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001825 }
1826
Jamie Madill51f40ec2016-06-15 14:06:00 -04001827 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001828 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001829 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001830 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1831 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1832 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1833 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1834 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1835 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001836 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001837 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1838 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001839 {
1840 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1841 // Section 6.10 of the WebGL 1.0 spec
1842 ERR(
1843 "This ANGLE implementation does not support separate front/back stencil "
1844 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001845 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001846 return false;
1847 }
Jamie Madillac528012014-06-20 13:21:23 -04001848 }
1849
Jamie Madill51f40ec2016-06-15 14:06:00 -04001850 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001851 {
Jamie Madill437fa652016-05-03 15:13:24 -04001852 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001853 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001854 }
1855
Geoff Lang7dd2e102014-11-10 15:19:26 -05001856 gl::Program *program = state.getProgram();
1857 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001858 {
Jamie Madill437fa652016-05-03 15:13:24 -04001859 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001860 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001861 }
1862
Geoff Lang7dd2e102014-11-10 15:19:26 -05001863 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001864 {
Jamie Madill437fa652016-05-03 15:13:24 -04001865 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001866 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001867 }
1868
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001869 // Uniform buffer validation
1870 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1871 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001872 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001873 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001874 const OffsetBindingPointer<Buffer> &uniformBuffer =
1875 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001876
Geoff Lang5d124a62015-09-15 13:03:27 -04001877 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001878 {
1879 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001880 context->handleError(
1881 Error(GL_INVALID_OPERATION,
1882 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001883 return false;
1884 }
1885
Geoff Lang5d124a62015-09-15 13:03:27 -04001886 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001887 if (uniformBufferSize == 0)
1888 {
1889 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001890 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001891 }
1892
Jamie Madill62d31cb2015-09-11 13:25:51 -04001893 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001894 {
1895 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001896 context->handleError(
1897 Error(GL_INVALID_OPERATION,
1898 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001899 return false;
1900 }
1901 }
1902
Jamie Madill250d33f2014-06-06 17:09:03 -04001903 // No-op if zero count
1904 return (count > 0);
1905}
1906
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001907bool ValidateDrawArrays(ValidationContext *context,
1908 GLenum mode,
1909 GLint first,
1910 GLsizei count,
1911 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001912{
Jamie Madillfd716582014-06-06 17:09:04 -04001913 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001914 {
Jamie Madill437fa652016-05-03 15:13:24 -04001915 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001916 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001917 }
1918
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001919 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001920 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001921 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1922 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001923 {
1924 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1925 // that does not match the current transform feedback object's draw mode (if transform feedback
1926 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001927 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001928 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001929 }
1930
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001931 if (!ValidateDrawBase(context, mode, count, primcount))
1932 {
1933 return false;
1934 }
1935
1936 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001937 {
1938 return false;
1939 }
1940
1941 return true;
1942}
1943
Geoff Langb1196682014-07-23 13:47:29 -04001944bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001945{
1946 if (primcount < 0)
1947 {
Jamie Madill437fa652016-05-03 15:13:24 -04001948 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001949 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001950 }
1951
Jamie Madill2b976812014-08-25 15:47:49 -04001952 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001953 {
1954 return false;
1955 }
1956
1957 // No-op if zero primitive count
1958 return (primcount > 0);
1959}
1960
Geoff Lang87a93302014-09-16 13:29:43 -04001961static bool ValidateDrawInstancedANGLE(Context *context)
1962{
1963 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001964 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04001965
Geoff Lang7dd2e102014-11-10 15:19:26 -05001966 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001967
1968 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001969 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001970 {
1971 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001972 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001973 {
1974 return true;
1975 }
1976 }
1977
Jamie Madill437fa652016-05-03 15:13:24 -04001978 context->handleError(Error(GL_INVALID_OPERATION,
1979 "ANGLE_instanced_arrays requires that at least one active attribute"
1980 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001981 return false;
1982}
1983
1984bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1985{
1986 if (!ValidateDrawInstancedANGLE(context))
1987 {
1988 return false;
1989 }
1990
1991 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1992}
1993
Jamie Madillf25855c2015-11-03 11:06:18 -05001994bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001995 GLenum mode,
1996 GLsizei count,
1997 GLenum type,
1998 const GLvoid *indices,
1999 GLsizei primcount,
2000 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002001{
Jamie Madill250d33f2014-06-06 17:09:03 -04002002 switch (type)
2003 {
2004 case GL_UNSIGNED_BYTE:
2005 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03002006 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002007 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03002008 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2009 {
2010 context->handleError(Error(GL_INVALID_ENUM));
2011 return false;
2012 }
2013 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002014 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002015 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03002016 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002017 }
2018
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002019 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002020
2021 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002022 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002023 {
2024 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2025 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002026 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002027 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002028 }
2029
2030 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002031 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002032 {
Jamie Madill437fa652016-05-03 15:13:24 -04002033 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002034 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002035 }
2036
Jamie Madill2b976812014-08-25 15:47:49 -04002037 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002038 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002039 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002040 {
Jamie Madill437fa652016-05-03 15:13:24 -04002041 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002042 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002043 }
2044
Jamie Madillae3000b2014-08-25 15:47:51 -04002045 if (elementArrayBuffer)
2046 {
2047 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2048
2049 GLint64 offset = reinterpret_cast<GLint64>(indices);
2050 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2051
2052 // check for integer overflows
2053 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2054 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2055 {
Jamie Madill437fa652016-05-03 15:13:24 -04002056 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002057 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002058 }
2059
2060 // Check for reading past the end of the bound buffer object
2061 if (byteCount > elementArrayBuffer->getSize())
2062 {
Jamie Madill437fa652016-05-03 15:13:24 -04002063 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002064 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002065 }
2066 }
2067 else if (!indices)
2068 {
2069 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002070 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002071 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002072 }
2073
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002074 if (!ValidateDrawBase(context, mode, count, primcount))
2075 {
2076 return false;
2077 }
2078
Jamie Madill2b976812014-08-25 15:47:49 -04002079 // Use max index to validate if our vertex buffers are large enough for the pull.
2080 // TODO: offer fast path, with disabled index validation.
2081 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2082 if (elementArrayBuffer)
2083 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002084 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002085 Error error =
2086 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2087 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002088 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002089 {
Jamie Madill437fa652016-05-03 15:13:24 -04002090 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002091 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002092 }
2093 }
2094 else
2095 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002096 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002097 }
2098
Jamie Madille79b1e12015-11-04 16:36:37 -05002099 // If we use an index greater than our maximum supported index range, return an error.
2100 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2101 // return an error if possible here.
2102 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2103 {
Jamie Madill437fa652016-05-03 15:13:24 -04002104 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002105 return false;
2106 }
2107
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002108 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002109 {
2110 return false;
2111 }
2112
Geoff Lang3edfe032015-09-04 16:38:24 -04002113 // No op if there are no real indices in the index data (all are primitive restart).
2114 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002115}
2116
Geoff Langb1196682014-07-23 13:47:29 -04002117bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002118 GLenum mode,
2119 GLsizei count,
2120 GLenum type,
2121 const GLvoid *indices,
2122 GLsizei primcount,
2123 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002124{
2125 if (primcount < 0)
2126 {
Jamie Madill437fa652016-05-03 15:13:24 -04002127 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002128 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002129 }
2130
Jamie Madill2b976812014-08-25 15:47:49 -04002131 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002132 {
2133 return false;
2134 }
2135
2136 // No-op zero primitive count
2137 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002138}
2139
Geoff Lang3edfe032015-09-04 16:38:24 -04002140bool ValidateDrawElementsInstancedANGLE(Context *context,
2141 GLenum mode,
2142 GLsizei count,
2143 GLenum type,
2144 const GLvoid *indices,
2145 GLsizei primcount,
2146 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002147{
2148 if (!ValidateDrawInstancedANGLE(context))
2149 {
2150 return false;
2151 }
2152
2153 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2154}
2155
Geoff Langb1196682014-07-23 13:47:29 -04002156bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002157 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002158{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002159 if (!ValidFramebufferTarget(target))
2160 {
Jamie Madill437fa652016-05-03 15:13:24 -04002161 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002162 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002163 }
2164
2165 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002166 {
2167 return false;
2168 }
2169
Jamie Madill55ec3b12014-07-03 10:38:57 -04002170 if (texture != 0)
2171 {
2172 gl::Texture *tex = context->getTexture(texture);
2173
2174 if (tex == NULL)
2175 {
Jamie Madill437fa652016-05-03 15:13:24 -04002176 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002177 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002178 }
2179
2180 if (level < 0)
2181 {
Jamie Madill437fa652016-05-03 15:13:24 -04002182 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002183 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002184 }
2185 }
2186
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002187 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002188 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002189
Jamie Madill84115c92015-04-23 15:00:07 -04002190 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002191 {
Jamie Madill437fa652016-05-03 15:13:24 -04002192 context->handleError(
2193 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002194 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002195 }
2196
2197 return true;
2198}
2199
Geoff Langb1196682014-07-23 13:47:29 -04002200bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002201 GLenum textarget, GLuint texture, GLint level)
2202{
Geoff Lang95663912015-04-02 15:54:45 -04002203 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
Martin Radev1be913c2016-07-11 17:59:16 +03002204 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2205 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002206 {
Jamie Madill437fa652016-05-03 15:13:24 -04002207 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002208 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002209 }
2210
2211 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002212 {
2213 return false;
2214 }
2215
Jamie Madill55ec3b12014-07-03 10:38:57 -04002216 if (texture != 0)
2217 {
2218 gl::Texture *tex = context->getTexture(texture);
2219 ASSERT(tex);
2220
Jamie Madill2a6564e2014-07-11 09:53:19 -04002221 const gl::Caps &caps = context->getCaps();
2222
Jamie Madill55ec3b12014-07-03 10:38:57 -04002223 switch (textarget)
2224 {
2225 case GL_TEXTURE_2D:
2226 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002227 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002228 {
Jamie Madill437fa652016-05-03 15:13:24 -04002229 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002230 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002231 }
2232 if (tex->getTarget() != GL_TEXTURE_2D)
2233 {
Jamie Madill437fa652016-05-03 15:13:24 -04002234 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002235 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002236 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002237 }
2238 break;
2239
2240 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2241 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2242 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2243 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2244 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2245 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2246 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002247 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002248 {
Jamie Madill437fa652016-05-03 15:13:24 -04002249 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002250 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002251 }
2252 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2253 {
Jamie Madill437fa652016-05-03 15:13:24 -04002254 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002255 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002256 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002257 }
2258 break;
2259
2260 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002261 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002262 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002263 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002264
2265 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2266 if (internalFormatInfo.compressed)
2267 {
Jamie Madill437fa652016-05-03 15:13:24 -04002268 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002269 return false;
2270 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002271 }
2272
Jamie Madill570f7c82014-07-03 10:38:54 -04002273 return true;
2274}
2275
Geoff Langb1196682014-07-23 13:47:29 -04002276bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002277{
2278 if (program == 0)
2279 {
Jamie Madill437fa652016-05-03 15:13:24 -04002280 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002281 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002282 }
2283
Dian Xiang769769a2015-09-09 15:20:08 -07002284 gl::Program *programObject = GetValidProgram(context, program);
2285 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002286 {
2287 return false;
2288 }
2289
Jamie Madill0063c512014-08-25 15:47:53 -04002290 if (!programObject || !programObject->isLinked())
2291 {
Jamie Madill437fa652016-05-03 15:13:24 -04002292 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002293 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002294 }
2295
Geoff Lang7dd2e102014-11-10 15:19:26 -05002296 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002297 {
Jamie Madill437fa652016-05-03 15:13:24 -04002298 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002299 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002300 }
2301
Jamie Madill0063c512014-08-25 15:47:53 -04002302 return true;
2303}
2304
Geoff Langb1196682014-07-23 13:47:29 -04002305bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002306{
2307 return ValidateGetUniformBase(context, program, location);
2308}
2309
Geoff Langb1196682014-07-23 13:47:29 -04002310bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002311{
Jamie Madill78f41802014-08-25 15:47:55 -04002312 return ValidateGetUniformBase(context, program, location);
2313}
2314
Geoff Langb1196682014-07-23 13:47:29 -04002315static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002316{
2317 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002318 {
Jamie Madill78f41802014-08-25 15:47:55 -04002319 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002320 }
2321
Jamie Madilla502c742014-08-28 17:19:13 -04002322 gl::Program *programObject = context->getProgram(program);
2323 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002324
Jamie Madill78f41802014-08-25 15:47:55 -04002325 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002326 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2327 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002328 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002329 {
Jamie Madill437fa652016-05-03 15:13:24 -04002330 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002331 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002332 }
2333
2334 return true;
2335}
2336
Geoff Langb1196682014-07-23 13:47:29 -04002337bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002338{
Jamie Madill78f41802014-08-25 15:47:55 -04002339 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002340}
2341
Geoff Langb1196682014-07-23 13:47:29 -04002342bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002343{
Jamie Madill78f41802014-08-25 15:47:55 -04002344 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002345}
2346
Austin Kinross08332632015-05-05 13:35:47 -07002347bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2348 const GLenum *attachments, bool defaultFramebuffer)
2349{
2350 if (numAttachments < 0)
2351 {
Jamie Madill437fa652016-05-03 15:13:24 -04002352 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002353 return false;
2354 }
2355
2356 for (GLsizei i = 0; i < numAttachments; ++i)
2357 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002358 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002359 {
2360 if (defaultFramebuffer)
2361 {
Jamie Madill437fa652016-05-03 15:13:24 -04002362 context->handleError(Error(
2363 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002364 return false;
2365 }
2366
2367 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2368 {
Jamie Madill437fa652016-05-03 15:13:24 -04002369 context->handleError(Error(GL_INVALID_OPERATION,
2370 "Requested color attachment is greater than the maximum "
2371 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002372 return false;
2373 }
2374 }
2375 else
2376 {
2377 switch (attachments[i])
2378 {
2379 case GL_DEPTH_ATTACHMENT:
2380 case GL_STENCIL_ATTACHMENT:
2381 case GL_DEPTH_STENCIL_ATTACHMENT:
2382 if (defaultFramebuffer)
2383 {
Jamie Madill437fa652016-05-03 15:13:24 -04002384 context->handleError(
2385 Error(GL_INVALID_ENUM,
2386 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002387 return false;
2388 }
2389 break;
2390 case GL_COLOR:
2391 case GL_DEPTH:
2392 case GL_STENCIL:
2393 if (!defaultFramebuffer)
2394 {
Jamie Madill437fa652016-05-03 15:13:24 -04002395 context->handleError(
2396 Error(GL_INVALID_ENUM,
2397 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002398 return false;
2399 }
2400 break;
2401 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002402 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002403 return false;
2404 }
2405 }
2406 }
2407
2408 return true;
2409}
2410
Austin Kinross6ee1e782015-05-29 17:05:37 -07002411bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2412{
2413 // Note that debug marker calls must not set error state
2414
2415 if (length < 0)
2416 {
2417 return false;
2418 }
2419
2420 if (marker == nullptr)
2421 {
2422 return false;
2423 }
2424
2425 return true;
2426}
2427
2428bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2429{
2430 // Note that debug marker calls must not set error state
2431
2432 if (length < 0)
2433 {
2434 return false;
2435 }
2436
2437 if (length > 0 && marker == nullptr)
2438 {
2439 return false;
2440 }
2441
2442 return true;
2443}
2444
Geoff Langdcab33b2015-07-21 13:03:16 -04002445bool ValidateEGLImageTargetTexture2DOES(Context *context,
2446 egl::Display *display,
2447 GLenum target,
2448 egl::Image *image)
2449{
Geoff Langa8406172015-07-21 16:53:39 -04002450 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2451 {
Jamie Madill437fa652016-05-03 15:13:24 -04002452 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002453 return false;
2454 }
2455
2456 switch (target)
2457 {
2458 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002459 if (!context->getExtensions().eglImage)
2460 {
2461 context->handleError(Error(
2462 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2463 }
2464 break;
2465
2466 case GL_TEXTURE_EXTERNAL_OES:
2467 if (!context->getExtensions().eglImageExternal)
2468 {
2469 context->handleError(Error(
2470 GL_INVALID_ENUM,
2471 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2472 }
Geoff Langa8406172015-07-21 16:53:39 -04002473 break;
2474
2475 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002476 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002477 return false;
2478 }
2479
2480 if (!display->isValidImage(image))
2481 {
Jamie Madill437fa652016-05-03 15:13:24 -04002482 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002483 return false;
2484 }
2485
2486 if (image->getSamples() > 0)
2487 {
Jamie Madill437fa652016-05-03 15:13:24 -04002488 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002489 "cannot create a 2D texture from a multisampled EGL image."));
2490 return false;
2491 }
2492
2493 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2494 if (!textureCaps.texturable)
2495 {
Jamie Madill437fa652016-05-03 15:13:24 -04002496 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002497 "EGL image internal format is not supported as a texture."));
2498 return false;
2499 }
2500
Geoff Langdcab33b2015-07-21 13:03:16 -04002501 return true;
2502}
2503
2504bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2505 egl::Display *display,
2506 GLenum target,
2507 egl::Image *image)
2508{
Geoff Langa8406172015-07-21 16:53:39 -04002509 if (!context->getExtensions().eglImage)
2510 {
Jamie Madill437fa652016-05-03 15:13:24 -04002511 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002512 return false;
2513 }
2514
2515 switch (target)
2516 {
2517 case GL_RENDERBUFFER:
2518 break;
2519
2520 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002521 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002522 return false;
2523 }
2524
2525 if (!display->isValidImage(image))
2526 {
Jamie Madill437fa652016-05-03 15:13:24 -04002527 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002528 return false;
2529 }
2530
2531 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2532 if (!textureCaps.renderable)
2533 {
Jamie Madill437fa652016-05-03 15:13:24 -04002534 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002535 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2536 return false;
2537 }
2538
Geoff Langdcab33b2015-07-21 13:03:16 -04002539 return true;
2540}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002541
2542bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2543{
Geoff Lang36167ab2015-12-07 10:27:14 -05002544 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002545 {
2546 // The default VAO should always exist
2547 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002548 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002549 return false;
2550 }
2551
2552 return true;
2553}
2554
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002555bool ValidateLinkProgram(Context *context, GLuint program)
2556{
2557 if (context->hasActiveTransformFeedback(program))
2558 {
2559 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002560 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002561 "Cannot link program while program is associated with an active "
2562 "transform feedback object."));
2563 return false;
2564 }
2565 return true;
2566}
2567
Geoff Langc5629752015-12-07 16:29:04 -05002568bool ValidateProgramBinaryBase(Context *context,
2569 GLuint program,
2570 GLenum binaryFormat,
2571 const void *binary,
2572 GLint length)
2573{
2574 Program *programObject = GetValidProgram(context, program);
2575 if (programObject == nullptr)
2576 {
2577 return false;
2578 }
2579
2580 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2581 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2582 programBinaryFormats.end())
2583 {
Jamie Madill437fa652016-05-03 15:13:24 -04002584 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002585 return false;
2586 }
2587
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002588 if (context->hasActiveTransformFeedback(program))
2589 {
2590 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002591 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002592 "Cannot change program binary while program is associated with "
2593 "an active transform feedback object."));
2594 return false;
2595 }
2596
Geoff Langc5629752015-12-07 16:29:04 -05002597 return true;
2598}
2599
2600bool ValidateGetProgramBinaryBase(Context *context,
2601 GLuint program,
2602 GLsizei bufSize,
2603 GLsizei *length,
2604 GLenum *binaryFormat,
2605 void *binary)
2606{
2607 Program *programObject = GetValidProgram(context, program);
2608 if (programObject == nullptr)
2609 {
2610 return false;
2611 }
2612
2613 if (!programObject->isLinked())
2614 {
Jamie Madill437fa652016-05-03 15:13:24 -04002615 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002616 return false;
2617 }
2618
2619 return true;
2620}
Jamie Madillc29968b2016-01-20 11:17:23 -05002621
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002622bool ValidateUseProgram(Context *context, GLuint program)
2623{
2624 if (program != 0)
2625 {
2626 Program *programObject = context->getProgram(program);
2627 if (!programObject)
2628 {
2629 // ES 3.1.0 section 7.3 page 72
2630 if (context->getShader(program))
2631 {
Jamie Madill437fa652016-05-03 15:13:24 -04002632 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002633 Error(GL_INVALID_OPERATION,
2634 "Attempted to use a single shader instead of a shader program."));
2635 return false;
2636 }
2637 else
2638 {
Jamie Madill437fa652016-05-03 15:13:24 -04002639 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002640 return false;
2641 }
2642 }
2643 if (!programObject->isLinked())
2644 {
Jamie Madill437fa652016-05-03 15:13:24 -04002645 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002646 return false;
2647 }
2648 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002649 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002650 {
2651 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002652 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002653 Error(GL_INVALID_OPERATION,
2654 "Cannot change active program while transform feedback is unpaused."));
2655 return false;
2656 }
2657
2658 return true;
2659}
2660
Jamie Madillc29968b2016-01-20 11:17:23 -05002661bool ValidateCopyTexImage2D(ValidationContext *context,
2662 GLenum target,
2663 GLint level,
2664 GLenum internalformat,
2665 GLint x,
2666 GLint y,
2667 GLsizei width,
2668 GLsizei height,
2669 GLint border)
2670{
Martin Radev1be913c2016-07-11 17:59:16 +03002671 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002672 {
2673 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2674 0, x, y, width, height, border);
2675 }
2676
Martin Radev1be913c2016-07-11 17:59:16 +03002677 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002678 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2679 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002680}
Jamie Madillc29968b2016-01-20 11:17:23 -05002681
2682bool ValidateFramebufferRenderbuffer(Context *context,
2683 GLenum target,
2684 GLenum attachment,
2685 GLenum renderbuffertarget,
2686 GLuint renderbuffer)
2687{
2688 if (!ValidFramebufferTarget(target) ||
2689 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2690 {
Jamie Madill437fa652016-05-03 15:13:24 -04002691 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002692 return false;
2693 }
2694
2695 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2696 renderbuffertarget, renderbuffer);
2697}
2698
2699bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2700{
2701 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2702 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2703 {
Jamie Madill437fa652016-05-03 15:13:24 -04002704 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002705 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2706 return false;
2707 }
2708
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002709 ASSERT(context->getGLState().getDrawFramebuffer());
2710 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002711 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2712
2713 // This should come first before the check for the default frame buffer
2714 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2715 // rather than INVALID_OPERATION
2716 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2717 {
2718 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2719
2720 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002721 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2722 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002723 {
2724 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002725 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2726 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2727 // 3.1 is still a bit ambiguous about the error, but future specs are
2728 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002729 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002730 return false;
2731 }
2732 else if (bufs[colorAttachment] >= maxColorAttachment)
2733 {
Jamie Madill437fa652016-05-03 15:13:24 -04002734 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002735 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002736 return false;
2737 }
2738 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2739 frameBufferId != 0)
2740 {
2741 // INVALID_OPERATION-GL is bound to buffer and ith argument
2742 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002743 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002744 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2745 return false;
2746 }
2747 }
2748
2749 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2750 // and n is not 1 or bufs is bound to value other than BACK and NONE
2751 if (frameBufferId == 0)
2752 {
2753 if (n != 1)
2754 {
Jamie Madill437fa652016-05-03 15:13:24 -04002755 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002756 "n must be 1 when GL is bound to the default framebuffer"));
2757 return false;
2758 }
2759
2760 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2761 {
Jamie Madill437fa652016-05-03 15:13:24 -04002762 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002763 GL_INVALID_OPERATION,
2764 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2765 return false;
2766 }
2767 }
2768
2769 return true;
2770}
2771
2772bool ValidateCopyTexSubImage2D(Context *context,
2773 GLenum target,
2774 GLint level,
2775 GLint xoffset,
2776 GLint yoffset,
2777 GLint x,
2778 GLint y,
2779 GLsizei width,
2780 GLsizei height)
2781{
Martin Radev1be913c2016-07-11 17:59:16 +03002782 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002783 {
2784 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2785 yoffset, x, y, width, height, 0);
2786 }
2787
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002788 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2789 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002790}
2791
Olli Etuaho4f667482016-03-30 15:56:35 +03002792bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2793{
2794 if (!ValidBufferTarget(context, target))
2795 {
Jamie Madill437fa652016-05-03 15:13:24 -04002796 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002797 return false;
2798 }
2799
2800 if (pname != GL_BUFFER_MAP_POINTER)
2801 {
Jamie Madill437fa652016-05-03 15:13:24 -04002802 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002803 return false;
2804 }
2805
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002806 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002807
2808 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2809 // target bound to zero generate an INVALID_OPERATION error."
2810 // GLES 3.1 section 6.6 explicitly specifies this error.
2811 if (!buffer)
2812 {
Jamie Madill437fa652016-05-03 15:13:24 -04002813 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002814 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2815 return false;
2816 }
2817
2818 return true;
2819}
2820
2821bool ValidateUnmapBufferBase(Context *context, GLenum target)
2822{
2823 if (!ValidBufferTarget(context, target))
2824 {
Jamie Madill437fa652016-05-03 15:13:24 -04002825 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002826 return false;
2827 }
2828
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002829 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002830
2831 if (buffer == nullptr || !buffer->isMapped())
2832 {
Jamie Madill437fa652016-05-03 15:13:24 -04002833 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002834 return false;
2835 }
2836
2837 return true;
2838}
2839
2840bool ValidateMapBufferRangeBase(Context *context,
2841 GLenum target,
2842 GLintptr offset,
2843 GLsizeiptr length,
2844 GLbitfield access)
2845{
2846 if (!ValidBufferTarget(context, target))
2847 {
Jamie Madill437fa652016-05-03 15:13:24 -04002848 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002849 return false;
2850 }
2851
2852 if (offset < 0 || length < 0)
2853 {
Jamie Madill437fa652016-05-03 15:13:24 -04002854 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002855 return false;
2856 }
2857
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002858 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002859
2860 if (!buffer)
2861 {
Jamie Madill437fa652016-05-03 15:13:24 -04002862 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002863 return false;
2864 }
2865
2866 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002867 CheckedNumeric<size_t> checkedOffset(offset);
2868 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002869
Jamie Madille2e406c2016-06-02 13:04:10 -04002870 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002871 {
Jamie Madill437fa652016-05-03 15:13:24 -04002872 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002873 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2874 return false;
2875 }
2876
2877 // Check for invalid bits in the mask
2878 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2879 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2880 GL_MAP_UNSYNCHRONIZED_BIT;
2881
2882 if (access & ~(allAccessBits))
2883 {
Jamie Madill437fa652016-05-03 15:13:24 -04002884 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002885 return false;
2886 }
2887
2888 if (length == 0)
2889 {
Jamie Madill437fa652016-05-03 15:13:24 -04002890 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002891 return false;
2892 }
2893
2894 if (buffer->isMapped())
2895 {
Jamie Madill437fa652016-05-03 15:13:24 -04002896 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002897 return false;
2898 }
2899
2900 // Check for invalid bit combinations
2901 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2902 {
Jamie Madill437fa652016-05-03 15:13:24 -04002903 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002904 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2905 return false;
2906 }
2907
2908 GLbitfield writeOnlyBits =
2909 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2910
2911 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2912 {
Jamie Madill437fa652016-05-03 15:13:24 -04002913 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002914 "Invalid access bits when mapping buffer for reading: 0x%X.",
2915 access));
2916 return false;
2917 }
2918
2919 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2920 {
Jamie Madill437fa652016-05-03 15:13:24 -04002921 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002922 GL_INVALID_OPERATION,
2923 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2924 return false;
2925 }
2926 return true;
2927}
2928
2929bool ValidateFlushMappedBufferRangeBase(Context *context,
2930 GLenum target,
2931 GLintptr offset,
2932 GLsizeiptr length)
2933{
2934 if (offset < 0 || length < 0)
2935 {
Jamie Madill437fa652016-05-03 15:13:24 -04002936 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002937 return false;
2938 }
2939
2940 if (!ValidBufferTarget(context, target))
2941 {
Jamie Madill437fa652016-05-03 15:13:24 -04002942 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002943 return false;
2944 }
2945
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002946 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002947
2948 if (buffer == nullptr)
2949 {
Jamie Madill437fa652016-05-03 15:13:24 -04002950 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002951 return false;
2952 }
2953
2954 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2955 {
Jamie Madill437fa652016-05-03 15:13:24 -04002956 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002957 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2958 return false;
2959 }
2960
2961 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002962 CheckedNumeric<size_t> checkedOffset(offset);
2963 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002964
Jamie Madille2e406c2016-06-02 13:04:10 -04002965 if (!checkedSize.IsValid() ||
2966 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002967 {
Jamie Madill437fa652016-05-03 15:13:24 -04002968 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002969 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2970 return false;
2971 }
2972
2973 return true;
2974}
2975
Olli Etuaho0f2b1562016-05-13 16:15:35 +03002976bool ValidateGenerateMipmap(Context *context, GLenum target)
2977{
2978 if (!ValidTextureTarget(context, target))
2979 {
2980 context->handleError(Error(GL_INVALID_ENUM));
2981 return false;
2982 }
2983
2984 Texture *texture = context->getTargetTexture(target);
2985
2986 if (texture == nullptr)
2987 {
2988 context->handleError(Error(GL_INVALID_OPERATION));
2989 return false;
2990 }
2991
2992 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
2993
2994 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
2995 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
2996 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2997 {
2998 context->handleError(Error(GL_INVALID_OPERATION));
2999 return false;
3000 }
3001
3002 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
3003 GLenum internalFormat = texture->getInternalFormat(baseTarget, effectiveBaseLevel);
3004 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
3005 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
3006
3007 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
3008 // unsized formats or that are color renderable and filterable. Since we do not track if
3009 // the texture was created with sized or unsized format (only sized formats are stored),
3010 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
3011 // be able to) because they aren't color renderable. Simply do a special case for LUMA
3012 // textures since they're the only texture format that can be created with unsized formats
3013 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
3014 // was the last version to use add them.
3015 bool isLUMA = internalFormat == GL_LUMINANCE8_EXT ||
3016 internalFormat == GL_LUMINANCE8_ALPHA8_EXT || internalFormat == GL_ALPHA8_EXT;
3017
3018 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable ||
3019 (!formatCaps.renderable && !isLUMA) || formatInfo.compressed)
3020 {
3021 context->handleError(Error(GL_INVALID_OPERATION));
3022 return false;
3023 }
3024
3025 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Martin Radev1be913c2016-07-11 17:59:16 +03003026 if (context->getClientMajorVersion() == 2 && formatInfo.colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003027 {
3028 context->handleError(Error(GL_INVALID_OPERATION));
3029 return false;
3030 }
3031
3032 // Non-power of 2 ES2 check
3033 if (!context->getExtensions().textureNPOT &&
3034 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3035 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3036 {
Martin Radev1be913c2016-07-11 17:59:16 +03003037 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003038 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3039 context->handleError(Error(GL_INVALID_OPERATION));
3040 return false;
3041 }
3042
3043 // Cube completeness check
3044 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3045 {
3046 context->handleError(Error(GL_INVALID_OPERATION));
3047 return false;
3048 }
3049
3050 return true;
3051}
3052
Olli Etuaho41997e72016-03-10 13:38:39 +02003053bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3054{
3055 return ValidateGenOrDelete(context, n);
3056}
3057
3058bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3059{
3060 return ValidateGenOrDelete(context, n);
3061}
3062
3063bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3064{
3065 return ValidateGenOrDelete(context, n);
3066}
3067
3068bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3069{
3070 return ValidateGenOrDelete(context, n);
3071}
3072
3073bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3074{
3075 return ValidateGenOrDelete(context, n);
3076}
3077
3078bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3079{
3080 return ValidateGenOrDelete(context, n);
3081}
3082
3083bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3084{
3085 return ValidateGenOrDelete(context, n);
3086}
3087
3088bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3089{
3090 return ValidateGenOrDelete(context, n);
3091}
3092
3093bool ValidateGenOrDelete(Context *context, GLint n)
3094{
3095 if (n < 0)
3096 {
Jamie Madill437fa652016-05-03 15:13:24 -04003097 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003098 return false;
3099 }
3100 return true;
3101}
3102
Jamie Madillc29968b2016-01-20 11:17:23 -05003103} // namespace gl