blob: 0846f0dbf4545e13cf2a2a77c69810847a248e54 [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 Madill29639852016-09-02 15:00:09 -0400236bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -0500237{
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:
Geoff Langc287ea62016-09-16 14:46:51 -0400485 if (!context->getExtensions().webglCompatibility &&
486 context->getClientMajorVersion() < 3)
Martin Radev1be913c2016-07-11 17:59:16 +0300487 {
488 context->handleError(Error(GL_INVALID_ENUM));
489 return false;
490 }
491 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400492
493 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400494 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300495 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400496 }
497 }
498
499 return true;
500}
501
Corentin Walleze0902642014-11-04 12:32:15 -0800502bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
503 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400504{
505 switch (target)
506 {
507 case GL_RENDERBUFFER:
508 break;
509 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400510 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400511 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400512 }
513
514 if (width < 0 || height < 0 || samples < 0)
515 {
Jamie Madill437fa652016-05-03 15:13:24 -0400516 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400517 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400518 }
519
Geoff Langd87878e2014-09-19 15:42:59 -0400520 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
521 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 {
Jamie Madill437fa652016-05-03 15:13:24 -0400523 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400524 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400525 }
526
527 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
528 // 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 -0800529 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400530 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400531 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400532 {
Jamie Madill437fa652016-05-03 15:13:24 -0400533 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400534 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400535 }
536
Geoff Langaae65a42014-05-26 12:43:44 -0400537 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400538 {
Jamie Madill437fa652016-05-03 15:13:24 -0400539 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400540 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400541 }
542
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700543 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400544 if (handle == 0)
545 {
Jamie Madill437fa652016-05-03 15:13:24 -0400546 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400547 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400548 }
549
550 return true;
551}
552
Corentin Walleze0902642014-11-04 12:32:15 -0800553bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
554 GLenum internalformat, GLsizei width, GLsizei height)
555{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800556 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800557
558 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400559 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800560 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400561 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800562 {
Jamie Madill437fa652016-05-03 15:13:24 -0400563 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800564 return false;
565 }
566
567 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
568 // the specified storage. This is different than ES 3.0 in which a sample number higher
569 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800570 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
Martin Radev1be913c2016-07-11 17:59:16 +0300571 if (context->getClientMajorVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800572 {
Geoff Langa4903b72015-03-02 16:02:48 -0800573 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
574 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
575 {
Jamie Madill437fa652016-05-03 15:13:24 -0400576 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800577 return false;
578 }
Corentin Walleze0902642014-11-04 12:32:15 -0800579 }
580
581 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
582}
583
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500584bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
585 GLenum renderbuffertarget, GLuint renderbuffer)
586{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400587 if (!ValidFramebufferTarget(target))
588 {
Jamie Madill437fa652016-05-03 15:13:24 -0400589 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400590 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400591 }
592
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700593 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500594
Jamie Madill84115c92015-04-23 15:00:07 -0400595 ASSERT(framebuffer);
596 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500597 {
Jamie Madill437fa652016-05-03 15:13:24 -0400598 context->handleError(
599 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400600 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500601 }
602
Jamie Madillb4472272014-07-03 10:38:55 -0400603 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500604 {
Jamie Madillb4472272014-07-03 10:38:55 -0400605 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500606 }
607
Jamie Madillab9d82c2014-01-21 16:38:14 -0500608 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
609 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
610 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
611 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
612 if (renderbuffer != 0)
613 {
614 if (!context->getRenderbuffer(renderbuffer))
615 {
Jamie Madill437fa652016-05-03 15:13:24 -0400616 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400617 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500618 }
619 }
620
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500621 return true;
622}
623
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700624bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500625 GLint srcX0,
626 GLint srcY0,
627 GLint srcX1,
628 GLint srcY1,
629 GLint dstX0,
630 GLint dstY0,
631 GLint dstX1,
632 GLint dstY1,
633 GLbitfield mask,
634 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400635{
636 switch (filter)
637 {
638 case GL_NEAREST:
639 break;
640 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400641 break;
642 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400643 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400644 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645 }
646
647 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
648 {
Jamie Madill437fa652016-05-03 15:13:24 -0400649 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400650 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400651 }
652
653 if (mask == 0)
654 {
655 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
656 // buffers are copied.
657 return false;
658 }
659
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400660 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
661 // color buffer, leaving only nearest being unfiltered from above
662 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
663 {
Jamie Madill437fa652016-05-03 15:13:24 -0400664 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400665 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400666 }
667
Jamie Madill51f40ec2016-06-15 14:06:00 -0400668 const auto &glState = context->getGLState();
669 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
670 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500671
672 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 {
Jamie Madill437fa652016-05-03 15:13:24 -0400674 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400675 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400676 }
677
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700678 if (readFramebuffer->id() == drawFramebuffer->id())
679 {
680 context->handleError(Error(GL_INVALID_OPERATION));
681 return false;
682 }
683
Jamie Madill51f40ec2016-06-15 14:06:00 -0400684 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500685 {
Jamie Madill437fa652016-05-03 15:13:24 -0400686 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500687 return false;
688 }
689
Jamie Madill51f40ec2016-06-15 14:06:00 -0400690 if (drawFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500691 {
Jamie Madill437fa652016-05-03 15:13:24 -0400692 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500693 return false;
694 }
695
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700696 if (drawFramebuffer->getSamples(context->getContextState()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697 {
Jamie Madill437fa652016-05-03 15:13:24 -0400698 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400699 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700 }
701
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400702 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
703
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400704 if (mask & GL_COLOR_BUFFER_BIT)
705 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400706 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
707 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500708 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709
710 if (readColorBuffer && drawColorBuffer)
711 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400712 const Format &readFormat = readColorBuffer->getFormat();
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 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400721 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400722
Geoff Langb2f3d052013-08-13 12:49:27 -0400723 // The GL ES 3.0.2 spec (pg 193) states that:
724 // 1) If the read buffer is fixed point format, the draw buffer must be as well
725 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
726 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500727 // Changes with EXT_color_buffer_float:
728 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -0400729 GLenum readComponentType = readFormat.info->componentType;
730 GLenum drawComponentType = drawFormat.info->componentType;
Jamie Madill6163c752015-12-07 16:32:59 -0500731 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
732 readComponentType == GL_SIGNED_NORMALIZED);
733 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
734 drawComponentType == GL_SIGNED_NORMALIZED);
735
736 if (extensions.colorBufferFloat)
737 {
738 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
739 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
740
741 if (readFixedOrFloat != drawFixedOrFloat)
742 {
Jamie Madill437fa652016-05-03 15:13:24 -0400743 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500744 "If the read buffer contains fixed-point or "
745 "floating-point values, the draw buffer "
746 "must as well."));
747 return false;
748 }
749 }
750 else if (readFixedPoint != drawFixedPoint)
751 {
Jamie Madill437fa652016-05-03 15:13:24 -0400752 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500753 "If the read buffer contains fixed-point "
754 "values, the draw buffer must as well."));
755 return false;
756 }
757
758 if (readComponentType == GL_UNSIGNED_INT &&
759 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400760 {
Jamie Madill437fa652016-05-03 15:13:24 -0400761 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400762 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400763 }
764
Jamie Madill6163c752015-12-07 16:32:59 -0500765 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400766 {
Jamie Madill437fa652016-05-03 15:13:24 -0400767 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400768 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400769 }
770
Jamie Madilla3944d42016-07-22 22:13:26 -0400771 if (readColorBuffer->getSamples() > 0 &&
772 (!Format::SameSized(readFormat, drawFormat) || !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
Jamie Madilla3944d42016-07-22 22:13:26 -0400780 if ((readFormat.info->componentType == GL_INT ||
781 readFormat.info->componentType == GL_UNSIGNED_INT) &&
782 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400783 {
Jamie Madill437fa652016-05-03 15:13:24 -0400784 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400785 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400786 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 }
788 }
789
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200790 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
791 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
792 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200794 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400796 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
797 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200799 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400801 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400802 {
Jamie Madill437fa652016-05-03 15:13:24 -0400803 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400804 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200807 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400808 {
Jamie Madill437fa652016-05-03 15:13:24 -0400809 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400810 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400811 }
812 }
813 }
814 }
815
816 return true;
817}
818
Geoff Langb1196682014-07-23 13:47:29 -0400819bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400820{
821 switch (pname)
822 {
823 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
824 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
825 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
826 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
827 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
828 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
829 case GL_CURRENT_VERTEX_ATTRIB:
Martin Radev1be913c2016-07-11 17:59:16 +0300830 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400831
832 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
Martin Radev1be913c2016-07-11 17:59:16 +0300833 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
834 // the same constant.
835 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
836 "ANGLE extension enums not equal to GL enums.");
837 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838
839 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Martin Radev1be913c2016-07-11 17:59:16 +0300840 if (context->getClientMajorVersion() < 3)
841 {
842 context->handleError(Error(GL_INVALID_ENUM));
843 return false;
844 }
845 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846
847 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400848 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300849 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400850 }
851}
852
Ian Ewellbda75592016-04-18 17:25:54 -0400853bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400854{
855 switch (pname)
856 {
857 case GL_TEXTURE_WRAP_R:
858 case GL_TEXTURE_SWIZZLE_R:
859 case GL_TEXTURE_SWIZZLE_G:
860 case GL_TEXTURE_SWIZZLE_B:
861 case GL_TEXTURE_SWIZZLE_A:
862 case GL_TEXTURE_BASE_LEVEL:
863 case GL_TEXTURE_MAX_LEVEL:
864 case GL_TEXTURE_COMPARE_MODE:
865 case GL_TEXTURE_COMPARE_FUNC:
866 case GL_TEXTURE_MIN_LOD:
867 case GL_TEXTURE_MAX_LOD:
Martin Radev1be913c2016-07-11 17:59:16 +0300868 if (context->getClientMajorVersion() < 3)
869 {
870 context->handleError(Error(GL_INVALID_ENUM));
871 return false;
872 }
873 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
874 {
875 context->handleError(Error(GL_INVALID_ENUM,
876 "ES3 texture parameters are not available without "
877 "GL_OES_EGL_image_external_essl3."));
878 return false;
879 }
880 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400881
882 default: break;
883 }
884
885 switch (pname)
886 {
887 case GL_TEXTURE_WRAP_S:
888 case GL_TEXTURE_WRAP_T:
889 case GL_TEXTURE_WRAP_R:
890 switch (param)
891 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000892 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400893 return true;
894 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400895 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300896 if (target == GL_TEXTURE_EXTERNAL_OES)
897 {
898 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400899 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300900 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
901 return false;
902 }
903 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400904 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400905 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400906 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400907 }
908
909 case GL_TEXTURE_MIN_FILTER:
910 switch (param)
911 {
912 case GL_NEAREST:
913 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400914 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400915 case GL_NEAREST_MIPMAP_NEAREST:
916 case GL_LINEAR_MIPMAP_NEAREST:
917 case GL_NEAREST_MIPMAP_LINEAR:
918 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300919 if (target == GL_TEXTURE_EXTERNAL_OES)
920 {
921 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400922 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300923 Error(GL_INVALID_ENUM,
924 "external textures only support NEAREST and LINEAR filtering"));
925 return false;
926 }
927 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400928 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400929 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400930 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400931 }
932 break;
933
934 case GL_TEXTURE_MAG_FILTER:
935 switch (param)
936 {
937 case GL_NEAREST:
938 case GL_LINEAR:
939 return true;
940 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400941 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400942 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400943 }
944 break;
945
946 case GL_TEXTURE_USAGE_ANGLE:
947 switch (param)
948 {
949 case GL_NONE:
950 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
951 return true;
952 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400953 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400954 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400955 }
956 break;
957
958 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400959 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400960 {
Jamie Madill437fa652016-05-03 15:13:24 -0400961 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400962 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400963 }
964
965 // we assume the parameter passed to this validation method is truncated, not rounded
966 if (param < 1)
967 {
Jamie Madill437fa652016-05-03 15:13:24 -0400968 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400969 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400970 }
971 return true;
972
973 case GL_TEXTURE_MIN_LOD:
974 case GL_TEXTURE_MAX_LOD:
975 // any value is permissible
976 return true;
977
978 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400979 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400980 switch (param)
981 {
982 case GL_NONE:
983 case GL_COMPARE_REF_TO_TEXTURE:
984 return true;
985 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400986 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400987 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400988 }
989 break;
990
991 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400992 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400993 switch (param)
994 {
995 case GL_LEQUAL:
996 case GL_GEQUAL:
997 case GL_LESS:
998 case GL_GREATER:
999 case GL_EQUAL:
1000 case GL_NOTEQUAL:
1001 case GL_ALWAYS:
1002 case GL_NEVER:
1003 return true;
1004 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001005 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001006 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001007 }
1008 break;
1009
1010 case GL_TEXTURE_SWIZZLE_R:
1011 case GL_TEXTURE_SWIZZLE_G:
1012 case GL_TEXTURE_SWIZZLE_B:
1013 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001014 switch (param)
1015 {
1016 case GL_RED:
1017 case GL_GREEN:
1018 case GL_BLUE:
1019 case GL_ALPHA:
1020 case GL_ZERO:
1021 case GL_ONE:
1022 return true;
1023 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001024 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001025 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001026 }
1027 break;
1028
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001029 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001030 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001031 {
Geoff Langb66a9092016-05-16 15:59:14 -04001032 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001033 return false;
1034 }
Geoff Langb66a9092016-05-16 15:59:14 -04001035 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1036 {
1037 context->handleError(
1038 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1039 return false;
1040 }
1041 return true;
1042
1043 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001044 if (param < 0)
1045 {
1046 context->handleError(Error(GL_INVALID_VALUE));
1047 return false;
1048 }
1049 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001050 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001051 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001052 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001053 }
1054}
1055
Geoff Langb1196682014-07-23 13:47:29 -04001056bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001057{
1058 switch (pname)
1059 {
1060 case GL_TEXTURE_MIN_FILTER:
1061 case GL_TEXTURE_MAG_FILTER:
1062 case GL_TEXTURE_WRAP_S:
1063 case GL_TEXTURE_WRAP_T:
1064 case GL_TEXTURE_WRAP_R:
1065 case GL_TEXTURE_MIN_LOD:
1066 case GL_TEXTURE_MAX_LOD:
1067 case GL_TEXTURE_COMPARE_MODE:
1068 case GL_TEXTURE_COMPARE_FUNC:
1069 return true;
1070
1071 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001072 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001073 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001074 }
1075}
1076
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001077bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001078 GLint x,
1079 GLint y,
1080 GLsizei width,
1081 GLsizei height,
1082 GLenum format,
1083 GLenum type,
1084 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001085{
Jamie Madillc29968b2016-01-20 11:17:23 -05001086 if (width < 0 || height < 0)
1087 {
Jamie Madill437fa652016-05-03 15:13:24 -04001088 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001089 return false;
1090 }
1091
Jamie Madill51f40ec2016-06-15 14:06:00 -04001092 auto readFramebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill26e91952014-03-05 15:01:27 -05001093
Jamie Madill51f40ec2016-06-15 14:06:00 -04001094 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001095 {
Jamie Madill437fa652016-05-03 15:13:24 -04001096 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001097 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001098 }
1099
Jamie Madill51f40ec2016-06-15 14:06:00 -04001100 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001101 {
Jamie Madill437fa652016-05-03 15:13:24 -04001102 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001103 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001104 }
1105
Jamie Madill51f40ec2016-06-15 14:06:00 -04001106 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1107 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001108
1109 if (framebuffer->getReadBufferState() == GL_NONE)
1110 {
1111 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1112 return false;
1113 }
1114
Geoff Langbce529e2014-12-01 12:48:41 -05001115 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1116 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001117 {
Jamie Madill437fa652016-05-03 15:13:24 -04001118 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001119 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001120 }
1121
Geoff Langbce529e2014-12-01 12:48:41 -05001122 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1123 GLenum currentType = framebuffer->getImplementationColorReadType();
Jamie Madilla3944d42016-07-22 22:13:26 -04001124 GLenum currentInternalFormat = readBuffer->getFormat().asSized();
Martin Radev1be913c2016-07-11 17:59:16 +03001125 GLuint clientVersion = context->getClientMajorVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001126
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001127 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1128 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001129
1130 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1131 {
Jamie Madill437fa652016-05-03 15:13:24 -04001132 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001133 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001134 }
1135
Jamie Madillc29968b2016-01-20 11:17:23 -05001136 return true;
1137}
1138
1139bool ValidateReadnPixelsEXT(Context *context,
1140 GLint x,
1141 GLint y,
1142 GLsizei width,
1143 GLsizei height,
1144 GLenum format,
1145 GLenum type,
1146 GLsizei bufSize,
1147 GLvoid *pixels)
1148{
1149 if (bufSize < 0)
1150 {
Jamie Madill437fa652016-05-03 15:13:24 -04001151 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001152 return false;
1153 }
1154
Geoff Lang5d601382014-07-22 15:14:06 -04001155 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1156 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001157
Jamie Madille2e406c2016-06-02 13:04:10 -04001158 auto outputPitchOrErr =
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001159 sizedFormatInfo.computeRowPitch(type, width, context->getGLState().getPackAlignment(),
1160 context->getGLState().getPackRowLength());
Jamie Madille2e406c2016-06-02 13:04:10 -04001161
1162 if (outputPitchOrErr.isError())
1163 {
1164 context->handleError(outputPitchOrErr.getError());
1165 return false;
1166 }
1167
1168 CheckedNumeric<GLuint> checkedOutputPitch(outputPitchOrErr.getResult());
1169 auto checkedRequiredSize = checkedOutputPitch * height;
1170 if (!checkedRequiredSize.IsValid())
1171 {
1172 context->handleError(Error(GL_INVALID_OPERATION, "Unsigned multiplication overflow."));
1173 return false;
1174 }
1175
Jamie Madill26e91952014-03-05 15:01:27 -05001176 // sized query sanity check
Jamie Madille2e406c2016-06-02 13:04:10 -04001177 if (checkedRequiredSize.ValueOrDie() > static_cast<GLuint>(bufSize))
Jamie Madill26e91952014-03-05 15:01:27 -05001178 {
Jamie Madill437fa652016-05-03 15:13:24 -04001179 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001180 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001181 }
1182
Jamie Madillc29968b2016-01-20 11:17:23 -05001183 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001184}
1185
Olli Etuaho41997e72016-03-10 13:38:39 +02001186bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001187{
1188 if (!context->getExtensions().occlusionQueryBoolean &&
1189 !context->getExtensions().disjointTimerQuery)
1190 {
Jamie Madill437fa652016-05-03 15:13:24 -04001191 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001192 return false;
1193 }
1194
Olli Etuaho41997e72016-03-10 13:38:39 +02001195 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001196}
1197
Olli Etuaho41997e72016-03-10 13:38:39 +02001198bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001199{
1200 if (!context->getExtensions().occlusionQueryBoolean &&
1201 !context->getExtensions().disjointTimerQuery)
1202 {
Jamie Madill437fa652016-05-03 15:13:24 -04001203 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001204 return false;
1205 }
1206
Olli Etuaho41997e72016-03-10 13:38:39 +02001207 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001208}
1209
1210bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001211{
1212 if (!ValidQueryType(context, target))
1213 {
Jamie Madill437fa652016-05-03 15:13:24 -04001214 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001215 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001216 }
1217
1218 if (id == 0)
1219 {
Jamie Madill437fa652016-05-03 15:13:24 -04001220 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001221 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001222 }
1223
1224 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1225 // of zero, if the active query object name for <target> is non-zero (for the
1226 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1227 // the active query for either target is non-zero), if <id> is the name of an
1228 // existing query object whose type does not match <target>, or if <id> is the
1229 // active query object name for any query type, the error INVALID_OPERATION is
1230 // generated.
1231
1232 // Ensure no other queries are active
1233 // NOTE: If other queries than occlusion are supported, we will need to check
1234 // separately that:
1235 // a) The query ID passed is not the current active query for any target/type
1236 // b) There are no active queries for the requested target (and in the case
1237 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1238 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001239
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001240 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001241 {
Jamie Madill437fa652016-05-03 15:13:24 -04001242 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001243 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001244 }
1245
1246 Query *queryObject = context->getQuery(id, true, target);
1247
1248 // check that name was obtained with glGenQueries
1249 if (!queryObject)
1250 {
Jamie Madill437fa652016-05-03 15:13:24 -04001251 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001252 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001253 }
1254
1255 // check for type mismatch
1256 if (queryObject->getType() != target)
1257 {
Jamie Madill437fa652016-05-03 15:13:24 -04001258 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001259 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001260 }
1261
1262 return true;
1263}
1264
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001265bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1266{
1267 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001268 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001269 {
Jamie Madill437fa652016-05-03 15:13:24 -04001270 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001271 return false;
1272 }
1273
1274 return ValidateBeginQueryBase(context, target, id);
1275}
1276
1277bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001278{
1279 if (!ValidQueryType(context, target))
1280 {
Jamie Madill437fa652016-05-03 15:13:24 -04001281 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001282 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001283 }
1284
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001285 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001286
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001287 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001288 {
Jamie Madill437fa652016-05-03 15:13:24 -04001289 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001290 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001291 }
1292
Jamie Madill45c785d2014-05-13 14:09:34 -04001293 return true;
1294}
1295
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001296bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1297{
1298 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001299 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001300 {
Jamie Madill437fa652016-05-03 15:13:24 -04001301 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001302 return false;
1303 }
1304
1305 return ValidateEndQueryBase(context, target);
1306}
1307
1308bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1309{
1310 if (!context->getExtensions().disjointTimerQuery)
1311 {
Jamie Madill437fa652016-05-03 15:13:24 -04001312 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001313 return false;
1314 }
1315
1316 if (target != GL_TIMESTAMP_EXT)
1317 {
Jamie Madill437fa652016-05-03 15:13:24 -04001318 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001319 return false;
1320 }
1321
1322 Query *queryObject = context->getQuery(id, true, target);
1323 if (queryObject == nullptr)
1324 {
Jamie Madill437fa652016-05-03 15:13:24 -04001325 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001326 return false;
1327 }
1328
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001329 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001330 {
Jamie Madill437fa652016-05-03 15:13:24 -04001331 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001332 return false;
1333 }
1334
1335 return true;
1336}
1337
1338bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1339{
1340 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1341 {
Jamie Madill437fa652016-05-03 15:13:24 -04001342 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001343 return false;
1344 }
1345
1346 switch (pname)
1347 {
1348 case GL_CURRENT_QUERY_EXT:
1349 if (target == GL_TIMESTAMP_EXT)
1350 {
Jamie Madill437fa652016-05-03 15:13:24 -04001351 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001352 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1353 return false;
1354 }
1355 break;
1356 case GL_QUERY_COUNTER_BITS_EXT:
1357 if (!context->getExtensions().disjointTimerQuery ||
1358 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1359 {
Jamie Madill437fa652016-05-03 15:13:24 -04001360 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001361 return false;
1362 }
1363 break;
1364 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001365 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001366 return false;
1367 }
1368
1369 return true;
1370}
1371
1372bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1373{
1374 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001375 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001376 {
Jamie Madill437fa652016-05-03 15:13:24 -04001377 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001378 return false;
1379 }
1380
1381 return ValidateGetQueryivBase(context, target, pname);
1382}
1383
1384bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1385{
1386 Query *queryObject = context->getQuery(id, false, GL_NONE);
1387
1388 if (!queryObject)
1389 {
Jamie Madill437fa652016-05-03 15:13:24 -04001390 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001391 return false;
1392 }
1393
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001394 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001395 {
Jamie Madill437fa652016-05-03 15:13:24 -04001396 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001397 return false;
1398 }
1399
1400 switch (pname)
1401 {
1402 case GL_QUERY_RESULT_EXT:
1403 case GL_QUERY_RESULT_AVAILABLE_EXT:
1404 break;
1405
1406 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001407 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001408 return false;
1409 }
1410
1411 return true;
1412}
1413
1414bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1415{
1416 if (!context->getExtensions().disjointTimerQuery)
1417 {
Jamie Madill437fa652016-05-03 15:13:24 -04001418 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001419 return false;
1420 }
1421 return ValidateGetQueryObjectValueBase(context, id, pname);
1422}
1423
1424bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1425{
1426 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001427 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001428 {
Jamie Madill437fa652016-05-03 15:13:24 -04001429 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001430 return false;
1431 }
1432 return ValidateGetQueryObjectValueBase(context, id, pname);
1433}
1434
1435bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1436{
1437 if (!context->getExtensions().disjointTimerQuery)
1438 {
Jamie Madill437fa652016-05-03 15:13:24 -04001439 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001440 return false;
1441 }
1442 return ValidateGetQueryObjectValueBase(context, id, pname);
1443}
1444
1445bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1446{
1447 if (!context->getExtensions().disjointTimerQuery)
1448 {
Jamie Madill437fa652016-05-03 15:13:24 -04001449 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001450 return false;
1451 }
1452 return ValidateGetQueryObjectValueBase(context, id, pname);
1453}
1454
Jamie Madill62d31cb2015-09-11 13:25:51 -04001455static bool ValidateUniformCommonBase(gl::Context *context,
1456 GLenum targetUniformType,
1457 GLint location,
1458 GLsizei count,
1459 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001460{
1461 if (count < 0)
1462 {
Jamie Madill437fa652016-05-03 15:13:24 -04001463 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001464 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001465 }
1466
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001467 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001468 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001469 {
Jamie Madill437fa652016-05-03 15:13:24 -04001470 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001471 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001472 }
1473
Geoff Langd8605522016-04-13 10:19:12 -04001474 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001475 {
1476 // Silently ignore the uniform command
1477 return false;
1478 }
1479
Geoff Lang7dd2e102014-11-10 15:19:26 -05001480 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001481 {
Jamie Madill437fa652016-05-03 15:13:24 -04001482 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001483 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001484 }
1485
Jamie Madill62d31cb2015-09-11 13:25:51 -04001486 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001487
1488 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001489 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001490 {
Jamie Madill437fa652016-05-03 15:13:24 -04001491 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001492 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001493 }
1494
Jamie Madill62d31cb2015-09-11 13:25:51 -04001495 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001496 return true;
1497}
1498
Jamie Madillaa981bd2014-05-20 10:55:55 -04001499bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1500{
1501 // Check for ES3 uniform entry points
Martin Radev1be913c2016-07-11 17:59:16 +03001502 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT &&
1503 context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001504 {
Jamie Madill437fa652016-05-03 15:13:24 -04001505 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001506 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001507 }
1508
Jamie Madill62d31cb2015-09-11 13:25:51 -04001509 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001510 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1511 {
1512 return false;
1513 }
1514
Jamie Madillf2575982014-06-25 16:04:54 -04001515 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001516 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001517 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1518 {
Jamie Madill437fa652016-05-03 15:13:24 -04001519 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001520 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001521 }
1522
1523 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001524}
1525
1526bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1527 GLboolean transpose)
1528{
1529 // Check for ES3 uniform entry points
1530 int rows = VariableRowCount(matrixType);
1531 int cols = VariableColumnCount(matrixType);
Martin Radev1be913c2016-07-11 17:59:16 +03001532 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001533 {
Jamie Madill437fa652016-05-03 15:13:24 -04001534 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001535 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001536 }
1537
Martin Radev1be913c2016-07-11 17:59:16 +03001538 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001539 {
Jamie Madill437fa652016-05-03 15:13:24 -04001540 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001541 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001542 }
1543
Jamie Madill62d31cb2015-09-11 13:25:51 -04001544 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001545 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1546 {
1547 return false;
1548 }
1549
1550 if (uniform->type != matrixType)
1551 {
Jamie Madill437fa652016-05-03 15:13:24 -04001552 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001553 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001554 }
1555
1556 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001557}
1558
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001559bool ValidateStateQuery(ValidationContext *context,
1560 GLenum pname,
1561 GLenum *nativeType,
1562 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001563{
1564 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1565 {
Jamie Madill437fa652016-05-03 15:13:24 -04001566 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001567 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001568 }
1569
Jamie Madill0af26e12015-03-05 19:54:33 -05001570 const Caps &caps = context->getCaps();
1571
Jamie Madill893ab082014-05-16 16:56:10 -04001572 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1573 {
1574 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1575
Jamie Madill0af26e12015-03-05 19:54:33 -05001576 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001577 {
Jamie Madill437fa652016-05-03 15:13:24 -04001578 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001579 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001580 }
1581 }
1582
1583 switch (pname)
1584 {
1585 case GL_TEXTURE_BINDING_2D:
1586 case GL_TEXTURE_BINDING_CUBE_MAP:
1587 case GL_TEXTURE_BINDING_3D:
1588 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001589 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001590 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1591 if (!context->getExtensions().eglStreamConsumerExternal)
1592 {
Jamie Madill437fa652016-05-03 15:13:24 -04001593 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001594 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1595 return false;
1596 }
1597 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001598
1599 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1600 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1601 {
Jamie Madill51f40ec2016-06-15 14:06:00 -04001602 if (context->getGLState().getReadFramebuffer()->checkStatus(
1603 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001604 {
Jamie Madill437fa652016-05-03 15:13:24 -04001605 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001606 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001607 }
1608
Jamie Madill51f40ec2016-06-15 14:06:00 -04001609 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1610 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001611
1612 if (framebuffer->getReadBufferState() == GL_NONE)
1613 {
1614 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1615 return false;
1616 }
1617
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001618 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001619 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001620 {
Jamie Madill437fa652016-05-03 15:13:24 -04001621 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001622 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001623 }
1624 }
1625 break;
1626
1627 default:
1628 break;
1629 }
1630
1631 // pname is valid, but there are no parameters to return
1632 if (numParams == 0)
1633 {
1634 return false;
1635 }
1636
1637 return true;
1638}
1639
Jamie Madillc29968b2016-01-20 11:17:23 -05001640bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1641 GLenum target,
1642 GLint level,
1643 GLenum internalformat,
1644 bool isSubImage,
1645 GLint xoffset,
1646 GLint yoffset,
1647 GLint zoffset,
1648 GLint x,
1649 GLint y,
1650 GLsizei width,
1651 GLsizei height,
1652 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04001653 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001654{
Jamie Madill560a8d82014-05-21 13:06:20 -04001655 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1656 {
Jamie Madill437fa652016-05-03 15:13:24 -04001657 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001658 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001659 }
1660
1661 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1662 {
Jamie Madill437fa652016-05-03 15:13:24 -04001663 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001664 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001665 }
1666
1667 if (border != 0)
1668 {
Jamie Madill437fa652016-05-03 15:13:24 -04001669 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001670 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001671 }
1672
1673 if (!ValidMipLevel(context, target, level))
1674 {
Jamie Madill437fa652016-05-03 15:13:24 -04001675 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001676 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001677 }
1678
Jamie Madill51f40ec2016-06-15 14:06:00 -04001679 const auto &state = context->getGLState();
1680 auto readFramebuffer = state.getReadFramebuffer();
1681 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001682 {
Jamie Madill437fa652016-05-03 15:13:24 -04001683 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001684 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001685 }
1686
Jamie Madill51f40ec2016-06-15 14:06:00 -04001687 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001688 {
Jamie Madill437fa652016-05-03 15:13:24 -04001689 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001690 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001691 }
1692
Martin Radev138064f2016-07-15 12:03:41 +03001693 if (readFramebuffer->getReadBufferState() == GL_NONE)
1694 {
1695 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1696 return false;
1697 }
1698
Geoff Langaae65a42014-05-26 12:43:44 -04001699 const gl::Caps &caps = context->getCaps();
1700
Geoff Langaae65a42014-05-26 12:43:44 -04001701 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001702 switch (target)
1703 {
1704 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001705 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001706 break;
1707
1708 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1709 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1710 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1711 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1712 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1713 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001714 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001715 break;
1716
1717 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001718 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001719 break;
1720
1721 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001722 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001723 break;
1724
1725 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001726 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001727 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001728 }
1729
Jamie Madillc29968b2016-01-20 11:17:23 -05001730 gl::Texture *texture =
1731 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001732 if (!texture)
1733 {
Jamie Madill437fa652016-05-03 15:13:24 -04001734 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001735 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001736 }
1737
Geoff Lang69cce582015-09-17 13:20:36 -04001738 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001739 {
Jamie Madill437fa652016-05-03 15:13:24 -04001740 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001741 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001742 }
1743
Geoff Lang5d601382014-07-22 15:14:06 -04001744 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1745
1746 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001747 {
Jamie Madill437fa652016-05-03 15:13:24 -04001748 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001749 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001750 }
1751
Geoff Langa9be0dc2014-12-17 12:34:40 -05001752 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001753 {
Jamie Madill437fa652016-05-03 15:13:24 -04001754 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001755 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001756 }
1757
1758 if (isSubImage)
1759 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001760 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1761 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1762 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001763 {
Jamie Madill437fa652016-05-03 15:13:24 -04001764 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001765 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001766 }
1767 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001768 else
1769 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001770 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001771 {
Jamie Madill437fa652016-05-03 15:13:24 -04001772 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001773 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001774 }
1775
Martin Radev1be913c2016-07-11 17:59:16 +03001776 if (!formatInfo.textureSupport(context->getClientMajorVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001777 {
Jamie Madill437fa652016-05-03 15:13:24 -04001778 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001779 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001780 }
1781
1782 int maxLevelDimension = (maxDimension >> level);
1783 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1784 {
Jamie Madill437fa652016-05-03 15:13:24 -04001785 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001786 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001787 }
1788 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001789
Jamie Madill0c8abca2016-07-22 20:21:26 -04001790 if (textureFormatOut)
1791 {
1792 *textureFormatOut = texture->getFormat(target, level);
1793 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001794 return true;
1795}
1796
Jamie Madillf25855c2015-11-03 11:06:18 -05001797static bool ValidateDrawBase(ValidationContext *context,
1798 GLenum mode,
1799 GLsizei count,
1800 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001801{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001802 switch (mode)
1803 {
1804 case GL_POINTS:
1805 case GL_LINES:
1806 case GL_LINE_LOOP:
1807 case GL_LINE_STRIP:
1808 case GL_TRIANGLES:
1809 case GL_TRIANGLE_STRIP:
1810 case GL_TRIANGLE_FAN:
1811 break;
1812 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001813 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001814 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001815 }
1816
Jamie Madill250d33f2014-06-06 17:09:03 -04001817 if (count < 0)
1818 {
Jamie Madill437fa652016-05-03 15:13:24 -04001819 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001820 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001821 }
1822
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001823 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001824
Jamie Madill250d33f2014-06-06 17:09:03 -04001825 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001826 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001827 {
Jamie Madill437fa652016-05-03 15:13:24 -04001828 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001829 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001830 }
1831
Jamie Madill51f40ec2016-06-15 14:06:00 -04001832 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001833 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001834 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001835 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1836 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1837 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1838 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1839 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1840 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001841 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001842 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1843 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001844 {
1845 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1846 // Section 6.10 of the WebGL 1.0 spec
1847 ERR(
1848 "This ANGLE implementation does not support separate front/back stencil "
1849 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001850 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001851 return false;
1852 }
Jamie Madillac528012014-06-20 13:21:23 -04001853 }
1854
Jamie Madill51f40ec2016-06-15 14:06:00 -04001855 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001856 {
Jamie Madill437fa652016-05-03 15:13:24 -04001857 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001858 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001859 }
1860
Geoff Lang7dd2e102014-11-10 15:19:26 -05001861 gl::Program *program = state.getProgram();
1862 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001863 {
Jamie Madill437fa652016-05-03 15:13:24 -04001864 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001865 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001866 }
1867
Geoff Lang7dd2e102014-11-10 15:19:26 -05001868 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001869 {
Jamie Madill437fa652016-05-03 15:13:24 -04001870 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001871 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001872 }
1873
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001874 // Uniform buffer validation
1875 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1876 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001877 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001878 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001879 const OffsetBindingPointer<Buffer> &uniformBuffer =
1880 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001881
Geoff Lang5d124a62015-09-15 13:03:27 -04001882 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001883 {
1884 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001885 context->handleError(
1886 Error(GL_INVALID_OPERATION,
1887 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001888 return false;
1889 }
1890
Geoff Lang5d124a62015-09-15 13:03:27 -04001891 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001892 if (uniformBufferSize == 0)
1893 {
1894 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001895 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001896 }
1897
Jamie Madill62d31cb2015-09-11 13:25:51 -04001898 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001899 {
1900 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001901 context->handleError(
1902 Error(GL_INVALID_OPERATION,
1903 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001904 return false;
1905 }
1906 }
1907
Jamie Madill250d33f2014-06-06 17:09:03 -04001908 // No-op if zero count
1909 return (count > 0);
1910}
1911
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001912bool ValidateDrawArrays(ValidationContext *context,
1913 GLenum mode,
1914 GLint first,
1915 GLsizei count,
1916 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001917{
Jamie Madillfd716582014-06-06 17:09:04 -04001918 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001919 {
Jamie Madill437fa652016-05-03 15:13:24 -04001920 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001921 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001922 }
1923
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001924 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001925 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001926 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1927 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001928 {
1929 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1930 // that does not match the current transform feedback object's draw mode (if transform feedback
1931 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001932 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001933 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001934 }
1935
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001936 if (!ValidateDrawBase(context, mode, count, primcount))
1937 {
1938 return false;
1939 }
1940
1941 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001942 {
1943 return false;
1944 }
1945
1946 return true;
1947}
1948
Geoff Langb1196682014-07-23 13:47:29 -04001949bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001950{
1951 if (primcount < 0)
1952 {
Jamie Madill437fa652016-05-03 15:13:24 -04001953 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001954 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001955 }
1956
Jamie Madill2b976812014-08-25 15:47:49 -04001957 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001958 {
1959 return false;
1960 }
1961
1962 // No-op if zero primitive count
1963 return (primcount > 0);
1964}
1965
Geoff Lang87a93302014-09-16 13:29:43 -04001966static bool ValidateDrawInstancedANGLE(Context *context)
1967{
1968 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001969 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04001970
Geoff Lang7dd2e102014-11-10 15:19:26 -05001971 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001972
1973 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001974 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001975 {
1976 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001977 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001978 {
1979 return true;
1980 }
1981 }
1982
Jamie Madill437fa652016-05-03 15:13:24 -04001983 context->handleError(Error(GL_INVALID_OPERATION,
1984 "ANGLE_instanced_arrays requires that at least one active attribute"
1985 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001986 return false;
1987}
1988
1989bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1990{
1991 if (!ValidateDrawInstancedANGLE(context))
1992 {
1993 return false;
1994 }
1995
1996 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1997}
1998
Jamie Madillf25855c2015-11-03 11:06:18 -05001999bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002000 GLenum mode,
2001 GLsizei count,
2002 GLenum type,
2003 const GLvoid *indices,
2004 GLsizei primcount,
2005 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002006{
Jamie Madill250d33f2014-06-06 17:09:03 -04002007 switch (type)
2008 {
2009 case GL_UNSIGNED_BYTE:
2010 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03002011 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002012 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03002013 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2014 {
2015 context->handleError(Error(GL_INVALID_ENUM));
2016 return false;
2017 }
2018 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002019 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002020 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03002021 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002022 }
2023
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002024 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002025
2026 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002027 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002028 {
2029 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2030 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002031 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002032 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002033 }
2034
2035 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002036 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002037 {
Jamie Madill437fa652016-05-03 15:13:24 -04002038 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002039 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002040 }
2041
Jamie Madill2b976812014-08-25 15:47:49 -04002042 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002043 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002044 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002045 {
Jamie Madill437fa652016-05-03 15:13:24 -04002046 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002047 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002048 }
2049
Jamie Madillae3000b2014-08-25 15:47:51 -04002050 if (elementArrayBuffer)
2051 {
2052 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2053
2054 GLint64 offset = reinterpret_cast<GLint64>(indices);
2055 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2056
2057 // check for integer overflows
2058 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2059 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2060 {
Jamie Madill437fa652016-05-03 15:13:24 -04002061 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002062 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002063 }
2064
2065 // Check for reading past the end of the bound buffer object
2066 if (byteCount > elementArrayBuffer->getSize())
2067 {
Jamie Madill437fa652016-05-03 15:13:24 -04002068 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002069 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002070 }
2071 }
2072 else if (!indices)
2073 {
2074 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002075 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002076 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002077 }
2078
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002079 if (!ValidateDrawBase(context, mode, count, primcount))
2080 {
2081 return false;
2082 }
2083
Jamie Madill2b976812014-08-25 15:47:49 -04002084 // Use max index to validate if our vertex buffers are large enough for the pull.
2085 // TODO: offer fast path, with disabled index validation.
2086 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2087 if (elementArrayBuffer)
2088 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002089 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002090 Error error =
2091 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2092 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002093 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002094 {
Jamie Madill437fa652016-05-03 15:13:24 -04002095 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002096 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002097 }
2098 }
2099 else
2100 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002101 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002102 }
2103
Jamie Madille79b1e12015-11-04 16:36:37 -05002104 // If we use an index greater than our maximum supported index range, return an error.
2105 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2106 // return an error if possible here.
2107 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2108 {
Jamie Madill437fa652016-05-03 15:13:24 -04002109 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002110 return false;
2111 }
2112
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002113 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002114 {
2115 return false;
2116 }
2117
Geoff Lang3edfe032015-09-04 16:38:24 -04002118 // No op if there are no real indices in the index data (all are primitive restart).
2119 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002120}
2121
Geoff Langb1196682014-07-23 13:47:29 -04002122bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002123 GLenum mode,
2124 GLsizei count,
2125 GLenum type,
2126 const GLvoid *indices,
2127 GLsizei primcount,
2128 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002129{
2130 if (primcount < 0)
2131 {
Jamie Madill437fa652016-05-03 15:13:24 -04002132 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002133 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002134 }
2135
Jamie Madill2b976812014-08-25 15:47:49 -04002136 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002137 {
2138 return false;
2139 }
2140
2141 // No-op zero primitive count
2142 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002143}
2144
Geoff Lang3edfe032015-09-04 16:38:24 -04002145bool ValidateDrawElementsInstancedANGLE(Context *context,
2146 GLenum mode,
2147 GLsizei count,
2148 GLenum type,
2149 const GLvoid *indices,
2150 GLsizei primcount,
2151 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002152{
2153 if (!ValidateDrawInstancedANGLE(context))
2154 {
2155 return false;
2156 }
2157
2158 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2159}
2160
Geoff Langb1196682014-07-23 13:47:29 -04002161bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002162 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002163{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002164 if (!ValidFramebufferTarget(target))
2165 {
Jamie Madill437fa652016-05-03 15:13:24 -04002166 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002167 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002168 }
2169
2170 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002171 {
2172 return false;
2173 }
2174
Jamie Madill55ec3b12014-07-03 10:38:57 -04002175 if (texture != 0)
2176 {
2177 gl::Texture *tex = context->getTexture(texture);
2178
2179 if (tex == NULL)
2180 {
Jamie Madill437fa652016-05-03 15:13:24 -04002181 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002182 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002183 }
2184
2185 if (level < 0)
2186 {
Jamie Madill437fa652016-05-03 15:13:24 -04002187 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002188 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002189 }
2190 }
2191
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002192 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002193 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002194
Jamie Madill84115c92015-04-23 15:00:07 -04002195 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002196 {
Jamie Madill437fa652016-05-03 15:13:24 -04002197 context->handleError(
2198 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002199 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002200 }
2201
2202 return true;
2203}
2204
Geoff Langb1196682014-07-23 13:47:29 -04002205bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002206 GLenum textarget, GLuint texture, GLint level)
2207{
Geoff Lang95663912015-04-02 15:54:45 -04002208 // 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 +03002209 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2210 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002211 {
Jamie Madill437fa652016-05-03 15:13:24 -04002212 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002213 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002214 }
2215
2216 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002217 {
2218 return false;
2219 }
2220
Jamie Madill55ec3b12014-07-03 10:38:57 -04002221 if (texture != 0)
2222 {
2223 gl::Texture *tex = context->getTexture(texture);
2224 ASSERT(tex);
2225
Jamie Madill2a6564e2014-07-11 09:53:19 -04002226 const gl::Caps &caps = context->getCaps();
2227
Jamie Madill55ec3b12014-07-03 10:38:57 -04002228 switch (textarget)
2229 {
2230 case GL_TEXTURE_2D:
2231 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002232 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002233 {
Jamie Madill437fa652016-05-03 15:13:24 -04002234 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002235 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002236 }
2237 if (tex->getTarget() != GL_TEXTURE_2D)
2238 {
Jamie Madill437fa652016-05-03 15:13:24 -04002239 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002240 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002241 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002242 }
2243 break;
2244
2245 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2246 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2247 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2248 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2249 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2250 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2251 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002252 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002253 {
Jamie Madill437fa652016-05-03 15:13:24 -04002254 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002255 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002256 }
2257 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2258 {
Jamie Madill437fa652016-05-03 15:13:24 -04002259 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002260 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002261 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002262 }
2263 break;
2264
2265 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002266 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002267 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002268 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002269
Jamie Madilla3944d42016-07-22 22:13:26 -04002270 const Format &format = tex->getFormat(textarget, level);
2271 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05002272 {
Jamie Madill437fa652016-05-03 15:13:24 -04002273 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002274 return false;
2275 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002276 }
2277
Jamie Madill570f7c82014-07-03 10:38:54 -04002278 return true;
2279}
2280
Geoff Langb1196682014-07-23 13:47:29 -04002281bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002282{
2283 if (program == 0)
2284 {
Jamie Madill437fa652016-05-03 15:13:24 -04002285 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002286 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002287 }
2288
Dian Xiang769769a2015-09-09 15:20:08 -07002289 gl::Program *programObject = GetValidProgram(context, program);
2290 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002291 {
2292 return false;
2293 }
2294
Jamie Madill0063c512014-08-25 15:47:53 -04002295 if (!programObject || !programObject->isLinked())
2296 {
Jamie Madill437fa652016-05-03 15:13:24 -04002297 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002298 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002299 }
2300
Geoff Lang7dd2e102014-11-10 15:19:26 -05002301 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002302 {
Jamie Madill437fa652016-05-03 15:13:24 -04002303 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002304 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002305 }
2306
Jamie Madill0063c512014-08-25 15:47:53 -04002307 return true;
2308}
2309
Geoff Langb1196682014-07-23 13:47:29 -04002310bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002311{
2312 return ValidateGetUniformBase(context, program, location);
2313}
2314
Geoff Langb1196682014-07-23 13:47:29 -04002315bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002316{
Jamie Madill78f41802014-08-25 15:47:55 -04002317 return ValidateGetUniformBase(context, program, location);
2318}
2319
Geoff Langb1196682014-07-23 13:47:29 -04002320static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002321{
2322 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002323 {
Jamie Madill78f41802014-08-25 15:47:55 -04002324 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002325 }
2326
Jamie Madilla502c742014-08-28 17:19:13 -04002327 gl::Program *programObject = context->getProgram(program);
2328 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002329
Jamie Madill78f41802014-08-25 15:47:55 -04002330 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002331 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2332 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002333 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002334 {
Jamie Madill437fa652016-05-03 15:13:24 -04002335 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002336 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002337 }
2338
2339 return true;
2340}
2341
Geoff Langb1196682014-07-23 13:47:29 -04002342bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* 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
Geoff Langb1196682014-07-23 13:47:29 -04002347bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002348{
Jamie Madill78f41802014-08-25 15:47:55 -04002349 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002350}
2351
Austin Kinross08332632015-05-05 13:35:47 -07002352bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2353 const GLenum *attachments, bool defaultFramebuffer)
2354{
2355 if (numAttachments < 0)
2356 {
Jamie Madill437fa652016-05-03 15:13:24 -04002357 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002358 return false;
2359 }
2360
2361 for (GLsizei i = 0; i < numAttachments; ++i)
2362 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002363 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002364 {
2365 if (defaultFramebuffer)
2366 {
Jamie Madill437fa652016-05-03 15:13:24 -04002367 context->handleError(Error(
2368 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002369 return false;
2370 }
2371
2372 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2373 {
Jamie Madill437fa652016-05-03 15:13:24 -04002374 context->handleError(Error(GL_INVALID_OPERATION,
2375 "Requested color attachment is greater than the maximum "
2376 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002377 return false;
2378 }
2379 }
2380 else
2381 {
2382 switch (attachments[i])
2383 {
2384 case GL_DEPTH_ATTACHMENT:
2385 case GL_STENCIL_ATTACHMENT:
2386 case GL_DEPTH_STENCIL_ATTACHMENT:
2387 if (defaultFramebuffer)
2388 {
Jamie Madill437fa652016-05-03 15:13:24 -04002389 context->handleError(
2390 Error(GL_INVALID_ENUM,
2391 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002392 return false;
2393 }
2394 break;
2395 case GL_COLOR:
2396 case GL_DEPTH:
2397 case GL_STENCIL:
2398 if (!defaultFramebuffer)
2399 {
Jamie Madill437fa652016-05-03 15:13:24 -04002400 context->handleError(
2401 Error(GL_INVALID_ENUM,
2402 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002403 return false;
2404 }
2405 break;
2406 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002407 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002408 return false;
2409 }
2410 }
2411 }
2412
2413 return true;
2414}
2415
Austin Kinross6ee1e782015-05-29 17:05:37 -07002416bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2417{
2418 // Note that debug marker calls must not set error state
2419
2420 if (length < 0)
2421 {
2422 return false;
2423 }
2424
2425 if (marker == nullptr)
2426 {
2427 return false;
2428 }
2429
2430 return true;
2431}
2432
2433bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2434{
2435 // Note that debug marker calls must not set error state
2436
2437 if (length < 0)
2438 {
2439 return false;
2440 }
2441
2442 if (length > 0 && marker == nullptr)
2443 {
2444 return false;
2445 }
2446
2447 return true;
2448}
2449
Geoff Langdcab33b2015-07-21 13:03:16 -04002450bool ValidateEGLImageTargetTexture2DOES(Context *context,
2451 egl::Display *display,
2452 GLenum target,
2453 egl::Image *image)
2454{
Geoff Langa8406172015-07-21 16:53:39 -04002455 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2456 {
Jamie Madill437fa652016-05-03 15:13:24 -04002457 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002458 return false;
2459 }
2460
2461 switch (target)
2462 {
2463 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002464 if (!context->getExtensions().eglImage)
2465 {
2466 context->handleError(Error(
2467 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2468 }
2469 break;
2470
2471 case GL_TEXTURE_EXTERNAL_OES:
2472 if (!context->getExtensions().eglImageExternal)
2473 {
2474 context->handleError(Error(
2475 GL_INVALID_ENUM,
2476 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2477 }
Geoff Langa8406172015-07-21 16:53:39 -04002478 break;
2479
2480 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002481 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002482 return false;
2483 }
2484
2485 if (!display->isValidImage(image))
2486 {
Jamie Madill437fa652016-05-03 15:13:24 -04002487 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002488 return false;
2489 }
2490
2491 if (image->getSamples() > 0)
2492 {
Jamie Madill437fa652016-05-03 15:13:24 -04002493 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002494 "cannot create a 2D texture from a multisampled EGL image."));
2495 return false;
2496 }
2497
Jamie Madilla3944d42016-07-22 22:13:26 -04002498 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002499 if (!textureCaps.texturable)
2500 {
Jamie Madill437fa652016-05-03 15:13:24 -04002501 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002502 "EGL image internal format is not supported as a texture."));
2503 return false;
2504 }
2505
Geoff Langdcab33b2015-07-21 13:03:16 -04002506 return true;
2507}
2508
2509bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2510 egl::Display *display,
2511 GLenum target,
2512 egl::Image *image)
2513{
Geoff Langa8406172015-07-21 16:53:39 -04002514 if (!context->getExtensions().eglImage)
2515 {
Jamie Madill437fa652016-05-03 15:13:24 -04002516 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002517 return false;
2518 }
2519
2520 switch (target)
2521 {
2522 case GL_RENDERBUFFER:
2523 break;
2524
2525 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002526 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002527 return false;
2528 }
2529
2530 if (!display->isValidImage(image))
2531 {
Jamie Madill437fa652016-05-03 15:13:24 -04002532 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002533 return false;
2534 }
2535
Jamie Madilla3944d42016-07-22 22:13:26 -04002536 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002537 if (!textureCaps.renderable)
2538 {
Jamie Madill437fa652016-05-03 15:13:24 -04002539 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002540 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2541 return false;
2542 }
2543
Geoff Langdcab33b2015-07-21 13:03:16 -04002544 return true;
2545}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002546
2547bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2548{
Geoff Lang36167ab2015-12-07 10:27:14 -05002549 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002550 {
2551 // The default VAO should always exist
2552 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002553 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002554 return false;
2555 }
2556
2557 return true;
2558}
2559
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002560bool ValidateLinkProgram(Context *context, GLuint program)
2561{
2562 if (context->hasActiveTransformFeedback(program))
2563 {
2564 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002565 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002566 "Cannot link program while program is associated with an active "
2567 "transform feedback object."));
2568 return false;
2569 }
2570 return true;
2571}
2572
Geoff Langc5629752015-12-07 16:29:04 -05002573bool ValidateProgramBinaryBase(Context *context,
2574 GLuint program,
2575 GLenum binaryFormat,
2576 const void *binary,
2577 GLint length)
2578{
2579 Program *programObject = GetValidProgram(context, program);
2580 if (programObject == nullptr)
2581 {
2582 return false;
2583 }
2584
2585 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2586 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2587 programBinaryFormats.end())
2588 {
Jamie Madill437fa652016-05-03 15:13:24 -04002589 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002590 return false;
2591 }
2592
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002593 if (context->hasActiveTransformFeedback(program))
2594 {
2595 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002596 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002597 "Cannot change program binary while program is associated with "
2598 "an active transform feedback object."));
2599 return false;
2600 }
2601
Geoff Langc5629752015-12-07 16:29:04 -05002602 return true;
2603}
2604
2605bool ValidateGetProgramBinaryBase(Context *context,
2606 GLuint program,
2607 GLsizei bufSize,
2608 GLsizei *length,
2609 GLenum *binaryFormat,
2610 void *binary)
2611{
2612 Program *programObject = GetValidProgram(context, program);
2613 if (programObject == nullptr)
2614 {
2615 return false;
2616 }
2617
2618 if (!programObject->isLinked())
2619 {
Jamie Madill437fa652016-05-03 15:13:24 -04002620 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002621 return false;
2622 }
2623
2624 return true;
2625}
Jamie Madillc29968b2016-01-20 11:17:23 -05002626
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002627bool ValidateUseProgram(Context *context, GLuint program)
2628{
2629 if (program != 0)
2630 {
2631 Program *programObject = context->getProgram(program);
2632 if (!programObject)
2633 {
2634 // ES 3.1.0 section 7.3 page 72
2635 if (context->getShader(program))
2636 {
Jamie Madill437fa652016-05-03 15:13:24 -04002637 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002638 Error(GL_INVALID_OPERATION,
2639 "Attempted to use a single shader instead of a shader program."));
2640 return false;
2641 }
2642 else
2643 {
Jamie Madill437fa652016-05-03 15:13:24 -04002644 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002645 return false;
2646 }
2647 }
2648 if (!programObject->isLinked())
2649 {
Jamie Madill437fa652016-05-03 15:13:24 -04002650 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002651 return false;
2652 }
2653 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002654 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002655 {
2656 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002657 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002658 Error(GL_INVALID_OPERATION,
2659 "Cannot change active program while transform feedback is unpaused."));
2660 return false;
2661 }
2662
2663 return true;
2664}
2665
Jamie Madillc29968b2016-01-20 11:17:23 -05002666bool ValidateCopyTexImage2D(ValidationContext *context,
2667 GLenum target,
2668 GLint level,
2669 GLenum internalformat,
2670 GLint x,
2671 GLint y,
2672 GLsizei width,
2673 GLsizei height,
2674 GLint border)
2675{
Martin Radev1be913c2016-07-11 17:59:16 +03002676 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002677 {
2678 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2679 0, x, y, width, height, border);
2680 }
2681
Martin Radev1be913c2016-07-11 17:59:16 +03002682 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002683 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2684 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002685}
Jamie Madillc29968b2016-01-20 11:17:23 -05002686
2687bool ValidateFramebufferRenderbuffer(Context *context,
2688 GLenum target,
2689 GLenum attachment,
2690 GLenum renderbuffertarget,
2691 GLuint renderbuffer)
2692{
2693 if (!ValidFramebufferTarget(target) ||
2694 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2695 {
Jamie Madill437fa652016-05-03 15:13:24 -04002696 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002697 return false;
2698 }
2699
2700 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2701 renderbuffertarget, renderbuffer);
2702}
2703
2704bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2705{
2706 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2707 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2708 {
Jamie Madill437fa652016-05-03 15:13:24 -04002709 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002710 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2711 return false;
2712 }
2713
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002714 ASSERT(context->getGLState().getDrawFramebuffer());
2715 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002716 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2717
2718 // This should come first before the check for the default frame buffer
2719 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2720 // rather than INVALID_OPERATION
2721 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2722 {
2723 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2724
2725 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002726 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2727 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002728 {
2729 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002730 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2731 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2732 // 3.1 is still a bit ambiguous about the error, but future specs are
2733 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002734 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002735 return false;
2736 }
2737 else if (bufs[colorAttachment] >= maxColorAttachment)
2738 {
Jamie Madill437fa652016-05-03 15:13:24 -04002739 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002740 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002741 return false;
2742 }
2743 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2744 frameBufferId != 0)
2745 {
2746 // INVALID_OPERATION-GL is bound to buffer and ith argument
2747 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002748 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002749 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2750 return false;
2751 }
2752 }
2753
2754 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2755 // and n is not 1 or bufs is bound to value other than BACK and NONE
2756 if (frameBufferId == 0)
2757 {
2758 if (n != 1)
2759 {
Jamie Madill437fa652016-05-03 15:13:24 -04002760 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002761 "n must be 1 when GL is bound to the default framebuffer"));
2762 return false;
2763 }
2764
2765 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2766 {
Jamie Madill437fa652016-05-03 15:13:24 -04002767 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002768 GL_INVALID_OPERATION,
2769 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2770 return false;
2771 }
2772 }
2773
2774 return true;
2775}
2776
2777bool ValidateCopyTexSubImage2D(Context *context,
2778 GLenum target,
2779 GLint level,
2780 GLint xoffset,
2781 GLint yoffset,
2782 GLint x,
2783 GLint y,
2784 GLsizei width,
2785 GLsizei height)
2786{
Martin Radev1be913c2016-07-11 17:59:16 +03002787 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002788 {
2789 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2790 yoffset, x, y, width, height, 0);
2791 }
2792
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002793 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2794 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002795}
2796
Olli Etuaho4f667482016-03-30 15:56:35 +03002797bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2798{
2799 if (!ValidBufferTarget(context, target))
2800 {
Jamie Madill437fa652016-05-03 15:13:24 -04002801 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002802 return false;
2803 }
2804
2805 if (pname != GL_BUFFER_MAP_POINTER)
2806 {
Jamie Madill437fa652016-05-03 15:13:24 -04002807 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002808 return false;
2809 }
2810
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002811 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002812
2813 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2814 // target bound to zero generate an INVALID_OPERATION error."
2815 // GLES 3.1 section 6.6 explicitly specifies this error.
2816 if (!buffer)
2817 {
Jamie Madill437fa652016-05-03 15:13:24 -04002818 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002819 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2820 return false;
2821 }
2822
2823 return true;
2824}
2825
2826bool ValidateUnmapBufferBase(Context *context, GLenum target)
2827{
2828 if (!ValidBufferTarget(context, target))
2829 {
Jamie Madill437fa652016-05-03 15:13:24 -04002830 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002831 return false;
2832 }
2833
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002834 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002835
2836 if (buffer == nullptr || !buffer->isMapped())
2837 {
Jamie Madill437fa652016-05-03 15:13:24 -04002838 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002839 return false;
2840 }
2841
2842 return true;
2843}
2844
2845bool ValidateMapBufferRangeBase(Context *context,
2846 GLenum target,
2847 GLintptr offset,
2848 GLsizeiptr length,
2849 GLbitfield access)
2850{
2851 if (!ValidBufferTarget(context, target))
2852 {
Jamie Madill437fa652016-05-03 15:13:24 -04002853 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002854 return false;
2855 }
2856
2857 if (offset < 0 || length < 0)
2858 {
Jamie Madill437fa652016-05-03 15:13:24 -04002859 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002860 return false;
2861 }
2862
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002863 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002864
2865 if (!buffer)
2866 {
Jamie Madill437fa652016-05-03 15:13:24 -04002867 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002868 return false;
2869 }
2870
2871 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002872 CheckedNumeric<size_t> checkedOffset(offset);
2873 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002874
Jamie Madille2e406c2016-06-02 13:04:10 -04002875 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002876 {
Jamie Madill437fa652016-05-03 15:13:24 -04002877 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002878 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2879 return false;
2880 }
2881
2882 // Check for invalid bits in the mask
2883 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2884 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2885 GL_MAP_UNSYNCHRONIZED_BIT;
2886
2887 if (access & ~(allAccessBits))
2888 {
Jamie Madill437fa652016-05-03 15:13:24 -04002889 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002890 return false;
2891 }
2892
2893 if (length == 0)
2894 {
Jamie Madill437fa652016-05-03 15:13:24 -04002895 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002896 return false;
2897 }
2898
2899 if (buffer->isMapped())
2900 {
Jamie Madill437fa652016-05-03 15:13:24 -04002901 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002902 return false;
2903 }
2904
2905 // Check for invalid bit combinations
2906 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2907 {
Jamie Madill437fa652016-05-03 15:13:24 -04002908 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002909 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2910 return false;
2911 }
2912
2913 GLbitfield writeOnlyBits =
2914 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2915
2916 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2917 {
Jamie Madill437fa652016-05-03 15:13:24 -04002918 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002919 "Invalid access bits when mapping buffer for reading: 0x%X.",
2920 access));
2921 return false;
2922 }
2923
2924 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2925 {
Jamie Madill437fa652016-05-03 15:13:24 -04002926 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002927 GL_INVALID_OPERATION,
2928 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2929 return false;
2930 }
2931 return true;
2932}
2933
2934bool ValidateFlushMappedBufferRangeBase(Context *context,
2935 GLenum target,
2936 GLintptr offset,
2937 GLsizeiptr length)
2938{
2939 if (offset < 0 || length < 0)
2940 {
Jamie Madill437fa652016-05-03 15:13:24 -04002941 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002942 return false;
2943 }
2944
2945 if (!ValidBufferTarget(context, target))
2946 {
Jamie Madill437fa652016-05-03 15:13:24 -04002947 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002948 return false;
2949 }
2950
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002951 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002952
2953 if (buffer == nullptr)
2954 {
Jamie Madill437fa652016-05-03 15:13:24 -04002955 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002956 return false;
2957 }
2958
2959 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2960 {
Jamie Madill437fa652016-05-03 15:13:24 -04002961 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002962 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2963 return false;
2964 }
2965
2966 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002967 CheckedNumeric<size_t> checkedOffset(offset);
2968 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002969
Jamie Madille2e406c2016-06-02 13:04:10 -04002970 if (!checkedSize.IsValid() ||
2971 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002972 {
Jamie Madill437fa652016-05-03 15:13:24 -04002973 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002974 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2975 return false;
2976 }
2977
2978 return true;
2979}
2980
Olli Etuaho0f2b1562016-05-13 16:15:35 +03002981bool ValidateGenerateMipmap(Context *context, GLenum target)
2982{
2983 if (!ValidTextureTarget(context, target))
2984 {
2985 context->handleError(Error(GL_INVALID_ENUM));
2986 return false;
2987 }
2988
2989 Texture *texture = context->getTargetTexture(target);
2990
2991 if (texture == nullptr)
2992 {
2993 context->handleError(Error(GL_INVALID_OPERATION));
2994 return false;
2995 }
2996
2997 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
2998
2999 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
3000 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
3001 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3002 {
3003 context->handleError(Error(GL_INVALID_OPERATION));
3004 return false;
3005 }
3006
Jamie Madilla3944d42016-07-22 22:13:26 -04003007 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
3008 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
3009 const TextureCaps &formatCaps = context->getTextureCaps().get(format.asSized());
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003010
3011 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
3012 // unsized formats or that are color renderable and filterable. Since we do not track if
3013 // the texture was created with sized or unsized format (only sized formats are stored),
3014 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
3015 // be able to) because they aren't color renderable. Simply do a special case for LUMA
3016 // textures since they're the only texture format that can be created with unsized formats
3017 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
3018 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04003019 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
3020 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003021 {
3022 context->handleError(Error(GL_INVALID_OPERATION));
3023 return false;
3024 }
3025
3026 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04003027 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003028 {
3029 context->handleError(Error(GL_INVALID_OPERATION));
3030 return false;
3031 }
3032
3033 // Non-power of 2 ES2 check
3034 if (!context->getExtensions().textureNPOT &&
3035 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3036 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3037 {
Martin Radev1be913c2016-07-11 17:59:16 +03003038 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003039 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3040 context->handleError(Error(GL_INVALID_OPERATION));
3041 return false;
3042 }
3043
3044 // Cube completeness check
3045 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3046 {
3047 context->handleError(Error(GL_INVALID_OPERATION));
3048 return false;
3049 }
3050
3051 return true;
3052}
3053
Olli Etuaho41997e72016-03-10 13:38:39 +02003054bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3055{
3056 return ValidateGenOrDelete(context, n);
3057}
3058
3059bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3060{
3061 return ValidateGenOrDelete(context, n);
3062}
3063
3064bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3065{
3066 return ValidateGenOrDelete(context, n);
3067}
3068
3069bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3070{
3071 return ValidateGenOrDelete(context, n);
3072}
3073
3074bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3075{
3076 return ValidateGenOrDelete(context, n);
3077}
3078
3079bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3080{
3081 return ValidateGenOrDelete(context, n);
3082}
3083
3084bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3085{
3086 return ValidateGenOrDelete(context, n);
3087}
3088
3089bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3090{
3091 return ValidateGenOrDelete(context, n);
3092}
3093
3094bool ValidateGenOrDelete(Context *context, GLint n)
3095{
3096 if (n < 0)
3097 {
Jamie Madill437fa652016-05-03 15:13:24 -04003098 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003099 return false;
3100 }
3101 return true;
3102}
3103
Jamie Madillc29968b2016-01-20 11:17:23 -05003104} // namespace gl