blob: 2a8c61b54da1d891f50b06475e68f362fa3d7119 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
Jamie Madille2e406c2016-06-02 13:04:10 -040010
Geoff Lang2b5420c2014-11-19 14:20:15 -050011#include "libANGLE/validationES2.h"
12#include "libANGLE/validationES3.h"
13#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040014#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050015#include "libANGLE/Texture.h"
16#include "libANGLE/Framebuffer.h"
17#include "libANGLE/FramebufferAttachment.h"
18#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040019#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050021#include "libANGLE/Program.h"
22#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050023#include "libANGLE/TransformFeedback.h"
24#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040025
26#include "common/mathutil.h"
27#include "common/utilities.h"
28
Jamie Madille2e406c2016-06-02 13:04:10 -040029using namespace angle;
30
Geoff Lange8ebe7f2013-08-05 15:03:13 -040031namespace gl
32{
Jamie Madille79b1e12015-11-04 16:36:37 -050033const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
34
Jamie Madill1ca74672015-07-21 15:14:11 -040035namespace
36{
Jamie Madillf25855c2015-11-03 11:06:18 -050037bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040038{
Jamie Madilldfde6ab2016-06-09 07:07:18 -070039 const gl::State &state = context->getGLState();
Jamie Madill1ca74672015-07-21 15:14:11 -040040 const gl::Program *program = state.getProgram();
41
42 const VertexArray *vao = state.getVertexArray();
43 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040044 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
45 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
46 {
47 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040048 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040049 {
50 gl::Buffer *buffer = attrib.buffer.get();
51
52 if (buffer)
53 {
54 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
55 GLint64 maxVertexElement = 0;
56
57 if (attrib.divisor > 0)
58 {
59 maxVertexElement =
60 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
61 }
62 else
63 {
64 maxVertexElement = static_cast<GLint64>(maxVertex);
65 }
66
67 // If we're drawing zero vertices, we have enough data.
68 if (maxVertexElement > 0)
69 {
70 // Note: Last vertex element does not take the full stride!
71 GLint64 attribSize =
72 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
73 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040074 GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
Jamie Madill1ca74672015-07-21 15:14:11 -040075
76 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
77 // We can return INVALID_OPERATION if our vertex attribute does not have
78 // enough backing data.
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040079 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040080 {
Jamie Madill437fa652016-05-03 15:13:24 -040081 context->handleError(
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040082 Error(GL_INVALID_OPERATION,
83 "Vertex buffer is not big enough for the draw call"));
Jamie Madill1ca74672015-07-21 15:14:11 -040084 return false;
85 }
86 }
87 }
88 else if (attrib.pointer == NULL)
89 {
90 // This is an application error that would normally result in a crash,
91 // but we catch it and return an error
Jamie Madill437fa652016-05-03 15:13:24 -040092 context->handleError(Error(
Jamie Madill1ca74672015-07-21 15:14:11 -040093 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
94 return false;
95 }
96 }
97 }
98
99 return true;
100}
101
102} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400103
Geoff Lang0550d032014-01-30 11:29:07 -0500104bool ValidCap(const Context *context, GLenum cap)
105{
106 switch (cap)
107 {
Sami Väisänen74c23472016-05-09 17:30:30 +0300108 // EXT_multisample_compatibility
109 case GL_MULTISAMPLE_EXT:
110 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
111 return context->getExtensions().multisampleCompatibility;
112
Geoff Lang0550d032014-01-30 11:29:07 -0500113 case GL_CULL_FACE:
114 case GL_POLYGON_OFFSET_FILL:
115 case GL_SAMPLE_ALPHA_TO_COVERAGE:
116 case GL_SAMPLE_COVERAGE:
117 case GL_SCISSOR_TEST:
118 case GL_STENCIL_TEST:
119 case GL_DEPTH_TEST:
120 case GL_BLEND:
121 case GL_DITHER:
122 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500123
Geoff Lang0550d032014-01-30 11:29:07 -0500124 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
125 case GL_RASTERIZER_DISCARD:
Martin Radev1be913c2016-07-11 17:59:16 +0300126 return (context->getClientMajorVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500127
128 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
129 case GL_DEBUG_OUTPUT:
130 return context->getExtensions().debug;
131
Geoff Lang0550d032014-01-30 11:29:07 -0500132 default:
133 return false;
134 }
135}
136
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500137bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400138{
Jamie Madilld7460c72014-01-21 16:38:14 -0500139 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400140 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500141 case GL_TEXTURE_2D:
142 case GL_TEXTURE_CUBE_MAP:
143 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400144
Jamie Madilld7460c72014-01-21 16:38:14 -0500145 case GL_TEXTURE_3D:
146 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300147 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500148
149 default:
150 return false;
151 }
Jamie Madill35d15012013-10-07 10:46:37 -0400152}
153
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500154bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
155{
156 switch (target)
157 {
158 case GL_TEXTURE_2D:
159 case GL_TEXTURE_CUBE_MAP:
160 return true;
161
162 default:
163 return false;
164 }
165}
166
167bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
168{
169 switch (target)
170 {
171 case GL_TEXTURE_3D:
172 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300173 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500174
175 default:
176 return false;
177 }
178}
179
Ian Ewellbda75592016-04-18 17:25:54 -0400180// Most texture GL calls are not compatible with external textures, so we have a separate validation
181// function for use in the GL calls that do
182bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
183{
184 return (target == GL_TEXTURE_EXTERNAL_OES) &&
185 (context->getExtensions().eglImageExternal ||
186 context->getExtensions().eglStreamConsumerExternal);
187}
188
Shannon Woods4dfed832014-03-17 20:03:39 -0400189// This function differs from ValidTextureTarget in that the target must be
190// usable as the destination of a 2D operation-- so a cube face is valid, but
191// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400192// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500193bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400194{
195 switch (target)
196 {
197 case GL_TEXTURE_2D:
198 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
199 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
200 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
201 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
202 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
203 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
204 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500205 default:
206 return false;
207 }
208}
209
210bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
211{
212 switch (target)
213 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400214 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500215 case GL_TEXTURE_2D_ARRAY:
216 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400217 default:
218 return false;
219 }
220}
221
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500222bool ValidFramebufferTarget(GLenum target)
223{
Geoff Langd4475812015-03-18 10:53:05 -0400224 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
225 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500226
227 switch (target)
228 {
229 case GL_FRAMEBUFFER: return true;
230 case GL_READ_FRAMEBUFFER: return true;
231 case GL_DRAW_FRAMEBUFFER: return true;
232 default: return false;
233 }
234}
235
Jamie Madill8c96d582014-03-05 15:01:23 -0500236bool ValidBufferTarget(const Context *context, GLenum target)
237{
238 switch (target)
239 {
240 case GL_ARRAY_BUFFER:
241 case GL_ELEMENT_ARRAY_BUFFER:
242 return true;
243
Jamie Madill8c96d582014-03-05 15:01:23 -0500244 case GL_PIXEL_PACK_BUFFER:
245 case GL_PIXEL_UNPACK_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300246 return (context->getExtensions().pixelBufferObject ||
247 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400248
Shannon Woodsb3801742014-03-27 14:59:19 -0400249 case GL_COPY_READ_BUFFER:
250 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500251 case GL_TRANSFORM_FEEDBACK_BUFFER:
252 case GL_UNIFORM_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300253 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500254
255 default:
256 return false;
257 }
258}
259
Jamie Madill70656a62014-03-05 15:01:26 -0500260bool ValidBufferParameter(const Context *context, GLenum pname)
261{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400262 const Extensions &extensions = context->getExtensions();
263
Jamie Madill70656a62014-03-05 15:01:26 -0500264 switch (pname)
265 {
266 case GL_BUFFER_USAGE:
267 case GL_BUFFER_SIZE:
268 return true;
269
Geoff Langcc6f55d2015-03-20 13:01:02 -0400270 case GL_BUFFER_ACCESS_OES:
271 return extensions.mapBuffer;
272
273 case GL_BUFFER_MAPPED:
274 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
Martin Radev1be913c2016-07-11 17:59:16 +0300275 return (context->getClientMajorVersion() >= 3) || extensions.mapBuffer ||
276 extensions.mapBufferRange;
Geoff Langcc6f55d2015-03-20 13:01:02 -0400277
Jamie Madill70656a62014-03-05 15:01:26 -0500278 // GL_BUFFER_MAP_POINTER is a special case, and may only be
279 // queried with GetBufferPointerv
280 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500281 case GL_BUFFER_MAP_OFFSET:
282 case GL_BUFFER_MAP_LENGTH:
Martin Radev1be913c2016-07-11 17:59:16 +0300283 return (context->getClientMajorVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500284
285 default:
286 return false;
287 }
288}
289
Jamie Madillc29968b2016-01-20 11:17:23 -0500290bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400291{
Jamie Madillc29968b2016-01-20 11:17:23 -0500292 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400293 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400294 switch (target)
295 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500296 case GL_TEXTURE_2D:
297 maxDimension = caps.max2DTextureSize;
298 break;
Geoff Langce635692013-09-24 13:56:32 -0400299 case GL_TEXTURE_CUBE_MAP:
300 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
301 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
302 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
303 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
304 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500305 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
306 maxDimension = caps.maxCubeMapTextureSize;
307 break;
308 case GL_TEXTURE_3D:
309 maxDimension = caps.max3DTextureSize;
310 break;
311 case GL_TEXTURE_2D_ARRAY:
312 maxDimension = caps.max2DTextureSize;
313 break;
Geoff Langce635692013-09-24 13:56:32 -0400314 default: UNREACHABLE();
315 }
316
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700317 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400318}
319
Austin Kinross08528e12015-10-07 16:24:40 -0700320bool ValidImageSizeParameters(const Context *context,
321 GLenum target,
322 GLint level,
323 GLsizei width,
324 GLsizei height,
325 GLsizei depth,
326 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400327{
328 if (level < 0 || width < 0 || height < 0 || depth < 0)
329 {
330 return false;
331 }
332
Austin Kinross08528e12015-10-07 16:24:40 -0700333 // TexSubImage parameters can be NPOT without textureNPOT extension,
334 // as long as the destination texture is POT.
335 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400336 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400337 {
338 return false;
339 }
340
341 if (!ValidMipLevel(context, target, level))
342 {
343 return false;
344 }
345
346 return true;
347}
348
Geoff Lang0d8b7242015-09-09 14:56:53 -0400349bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
350{
351 // List of compressed format that require that the texture size is smaller than or a multiple of
352 // the compressed block size.
353 switch (internalFormat)
354 {
355 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
356 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
357 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
358 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800359 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400360 return true;
361
362 default:
363 return false;
364 }
365}
366
Jamie Madillc29968b2016-01-20 11:17:23 -0500367bool ValidCompressedImageSize(const ValidationContext *context,
368 GLenum internalFormat,
369 GLsizei width,
370 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400371{
Geoff Lang5d601382014-07-22 15:14:06 -0400372 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
373 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400374 {
375 return false;
376 }
377
Geoff Lang0d8b7242015-09-09 14:56:53 -0400378 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400379 {
380 return false;
381 }
382
Geoff Lang0d8b7242015-09-09 14:56:53 -0400383 if (CompressedTextureFormatRequiresExactSize(internalFormat))
384 {
385 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
386 width % formatInfo.compressedBlockWidth != 0) ||
387 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
388 height % formatInfo.compressedBlockHeight != 0))
389 {
390 return false;
391 }
392 }
393
Geoff Langd4f180b2013-09-24 13:57:44 -0400394 return true;
395}
396
Geoff Lang37dde692014-01-31 16:34:54 -0500397bool ValidQueryType(const Context *context, GLenum queryType)
398{
Geoff Langd4475812015-03-18 10:53:05 -0400399 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
400 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500401
402 switch (queryType)
403 {
404 case GL_ANY_SAMPLES_PASSED:
405 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
406 return true;
407 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
Martin Radev1be913c2016-07-11 17:59:16 +0300408 return (context->getClientMajorVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500409 case GL_TIME_ELAPSED_EXT:
410 return context->getExtensions().disjointTimerQuery;
Geoff Lang2b4ce802016-04-28 13:34:50 -0400411 case GL_COMMANDS_COMPLETED_CHROMIUM:
412 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500413 default:
414 return false;
415 }
416}
417
Dian Xiang769769a2015-09-09 15:20:08 -0700418Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500419{
420 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
421 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
422 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
423
Dian Xiang769769a2015-09-09 15:20:08 -0700424 Program *validProgram = context->getProgram(id);
425
426 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500427 {
Dian Xiang769769a2015-09-09 15:20:08 -0700428 if (context->getShader(id))
429 {
Jamie Madill437fa652016-05-03 15:13:24 -0400430 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700431 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
432 }
433 else
434 {
Jamie Madill437fa652016-05-03 15:13:24 -0400435 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700436 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500437 }
Dian Xiang769769a2015-09-09 15:20:08 -0700438
439 return validProgram;
440}
441
442Shader *GetValidShader(Context *context, GLuint id)
443{
444 // See ValidProgram for spec details.
445
446 Shader *validShader = context->getShader(id);
447
448 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500449 {
Dian Xiang769769a2015-09-09 15:20:08 -0700450 if (context->getProgram(id))
451 {
Jamie Madill437fa652016-05-03 15:13:24 -0400452 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700453 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
454 }
455 else
456 {
Jamie Madill437fa652016-05-03 15:13:24 -0400457 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700458 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500459 }
Dian Xiang769769a2015-09-09 15:20:08 -0700460
461 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500462}
463
Geoff Langb1196682014-07-23 13:47:29 -0400464bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400465{
466 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
467 {
468 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
469
Geoff Langaae65a42014-05-26 12:43:44 -0400470 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400471 {
Jamie Madill437fa652016-05-03 15:13:24 -0400472 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400473 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400474 }
475 }
476 else
477 {
478 switch (attachment)
479 {
480 case GL_DEPTH_ATTACHMENT:
481 case GL_STENCIL_ATTACHMENT:
Martin Radev1be913c2016-07-11 17:59:16 +0300482 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400483
484 case GL_DEPTH_STENCIL_ATTACHMENT:
Martin Radev1be913c2016-07-11 17:59:16 +0300485 if (context->getClientMajorVersion() < 3)
486 {
487 context->handleError(Error(GL_INVALID_ENUM));
488 return false;
489 }
490 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400491
492 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400493 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300494 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400495 }
496 }
497
498 return true;
499}
500
Corentin Walleze0902642014-11-04 12:32:15 -0800501bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
502 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400503{
504 switch (target)
505 {
506 case GL_RENDERBUFFER:
507 break;
508 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400509 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400510 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400511 }
512
513 if (width < 0 || height < 0 || samples < 0)
514 {
Jamie Madill437fa652016-05-03 15:13:24 -0400515 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400516 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400517 }
518
Geoff Langd87878e2014-09-19 15:42:59 -0400519 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
520 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400521 {
Jamie Madill437fa652016-05-03 15:13:24 -0400522 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400523 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400524 }
525
526 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
527 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800528 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400529 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400530 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400531 {
Jamie Madill437fa652016-05-03 15:13:24 -0400532 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400533 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400534 }
535
Geoff Langaae65a42014-05-26 12:43:44 -0400536 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400537 {
Jamie Madill437fa652016-05-03 15:13:24 -0400538 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400539 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400540 }
541
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700542 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400543 if (handle == 0)
544 {
Jamie Madill437fa652016-05-03 15:13:24 -0400545 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400546 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400547 }
548
549 return true;
550}
551
Corentin Walleze0902642014-11-04 12:32:15 -0800552bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
553 GLenum internalformat, GLsizei width, GLsizei height)
554{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800555 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800556
557 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400558 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800559 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400560 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800561 {
Jamie Madill437fa652016-05-03 15:13:24 -0400562 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800563 return false;
564 }
565
566 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
567 // the specified storage. This is different than ES 3.0 in which a sample number higher
568 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800569 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
Martin Radev1be913c2016-07-11 17:59:16 +0300570 if (context->getClientMajorVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800571 {
Geoff Langa4903b72015-03-02 16:02:48 -0800572 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
573 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
574 {
Jamie Madill437fa652016-05-03 15:13:24 -0400575 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800576 return false;
577 }
Corentin Walleze0902642014-11-04 12:32:15 -0800578 }
579
580 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
581}
582
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500583bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
584 GLenum renderbuffertarget, GLuint renderbuffer)
585{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400586 if (!ValidFramebufferTarget(target))
587 {
Jamie Madill437fa652016-05-03 15:13:24 -0400588 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400589 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400590 }
591
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700592 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500593
Jamie Madill84115c92015-04-23 15:00:07 -0400594 ASSERT(framebuffer);
595 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500596 {
Jamie Madill437fa652016-05-03 15:13:24 -0400597 context->handleError(
598 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400599 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500600 }
601
Jamie Madillb4472272014-07-03 10:38:55 -0400602 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500603 {
Jamie Madillb4472272014-07-03 10:38:55 -0400604 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500605 }
606
Jamie Madillab9d82c2014-01-21 16:38:14 -0500607 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
608 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
609 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
610 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
611 if (renderbuffer != 0)
612 {
613 if (!context->getRenderbuffer(renderbuffer))
614 {
Jamie Madill437fa652016-05-03 15:13:24 -0400615 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400616 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500617 }
618 }
619
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500620 return true;
621}
622
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700623bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500624 GLint srcX0,
625 GLint srcY0,
626 GLint srcX1,
627 GLint srcY1,
628 GLint dstX0,
629 GLint dstY0,
630 GLint dstX1,
631 GLint dstY1,
632 GLbitfield mask,
633 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634{
635 switch (filter)
636 {
637 case GL_NEAREST:
638 break;
639 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640 break;
641 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400642 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400643 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400644 }
645
646 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
647 {
Jamie Madill437fa652016-05-03 15:13:24 -0400648 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400649 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650 }
651
652 if (mask == 0)
653 {
654 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
655 // buffers are copied.
656 return false;
657 }
658
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
660 // color buffer, leaving only nearest being unfiltered from above
661 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
662 {
Jamie Madill437fa652016-05-03 15:13:24 -0400663 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400664 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665 }
666
Jamie Madill51f40ec2016-06-15 14:06:00 -0400667 const auto &glState = context->getGLState();
668 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
669 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500670
671 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 {
Jamie Madill437fa652016-05-03 15:13:24 -0400673 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400674 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 }
676
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700677 if (readFramebuffer->id() == drawFramebuffer->id())
678 {
679 context->handleError(Error(GL_INVALID_OPERATION));
680 return false;
681 }
682
Jamie Madill51f40ec2016-06-15 14:06:00 -0400683 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500684 {
Jamie Madill437fa652016-05-03 15:13:24 -0400685 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500686 return false;
687 }
688
Jamie Madill51f40ec2016-06-15 14:06:00 -0400689 if (drawFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500690 {
Jamie Madill437fa652016-05-03 15:13:24 -0400691 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500692 return false;
693 }
694
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700695 if (drawFramebuffer->getSamples(context->getContextState()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696 {
Jamie Madill437fa652016-05-03 15:13:24 -0400697 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400698 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400699 }
700
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400701 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
702
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 if (mask & GL_COLOR_BUFFER_BIT)
704 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400705 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
706 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500707 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400708
709 if (readColorBuffer && drawColorBuffer)
710 {
Geoff Langd8a22582014-12-17 15:28:23 -0500711 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400712 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400713
Geoff Langa15472a2015-08-11 11:48:03 -0400714 for (size_t drawbufferIdx = 0;
715 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400716 {
Geoff Langa15472a2015-08-11 11:48:03 -0400717 const FramebufferAttachment *attachment =
718 drawFramebuffer->getDrawBuffer(drawbufferIdx);
719 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400720 {
Geoff Langa15472a2015-08-11 11:48:03 -0400721 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400722 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400723
Geoff Langb2f3d052013-08-13 12:49:27 -0400724 // The GL ES 3.0.2 spec (pg 193) states that:
725 // 1) If the read buffer is fixed point format, the draw buffer must be as well
726 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
727 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500728 // Changes with EXT_color_buffer_float:
729 // Case 1) is changed to fixed point OR floating point
730 GLenum readComponentType = readFormatInfo.componentType;
731 GLenum drawComponentType = drawFormatInfo.componentType;
732 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
733 readComponentType == GL_SIGNED_NORMALIZED);
734 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
735 drawComponentType == GL_SIGNED_NORMALIZED);
736
737 if (extensions.colorBufferFloat)
738 {
739 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
740 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
741
742 if (readFixedOrFloat != drawFixedOrFloat)
743 {
Jamie Madill437fa652016-05-03 15:13:24 -0400744 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500745 "If the read buffer contains fixed-point or "
746 "floating-point values, the draw buffer "
747 "must as well."));
748 return false;
749 }
750 }
751 else if (readFixedPoint != drawFixedPoint)
752 {
Jamie Madill437fa652016-05-03 15:13:24 -0400753 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500754 "If the read buffer contains fixed-point "
755 "values, the draw buffer must as well."));
756 return false;
757 }
758
759 if (readComponentType == GL_UNSIGNED_INT &&
760 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 {
Jamie Madill437fa652016-05-03 15:13:24 -0400762 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400763 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 }
765
Jamie Madill6163c752015-12-07 16:32:59 -0500766 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 {
Jamie Madill437fa652016-05-03 15:13:24 -0400768 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400769 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 }
771
Geoff Langb2f3d052013-08-13 12:49:27 -0400772 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773 {
Jamie Madill437fa652016-05-03 15:13:24 -0400774 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400775 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400776 }
777 }
778 }
779
Geoff Lang5d601382014-07-22 15:14:06 -0400780 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400781 {
Jamie Madill437fa652016-05-03 15:13:24 -0400782 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400783 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400784 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785 }
786 }
787
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200788 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
789 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
790 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200792 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400794 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
795 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200797 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798 {
Geoff Langd8a22582014-12-17 15:28:23 -0500799 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 {
Jamie Madill437fa652016-05-03 15:13:24 -0400801 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400802 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400804
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200805 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806 {
Jamie Madill437fa652016-05-03 15:13:24 -0400807 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400808 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400809 }
810 }
811 }
812 }
813
814 return true;
815}
816
Geoff Langb1196682014-07-23 13:47:29 -0400817bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400818{
819 switch (pname)
820 {
821 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
822 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
823 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
824 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
825 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
826 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
827 case GL_CURRENT_VERTEX_ATTRIB:
Martin Radev1be913c2016-07-11 17:59:16 +0300828 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829
830 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
Martin Radev1be913c2016-07-11 17:59:16 +0300831 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
832 // the same constant.
833 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
834 "ANGLE extension enums not equal to GL enums.");
835 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400836
837 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Martin Radev1be913c2016-07-11 17:59:16 +0300838 if (context->getClientMajorVersion() < 3)
839 {
840 context->handleError(Error(GL_INVALID_ENUM));
841 return false;
842 }
843 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400844
845 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400846 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300847 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400848 }
849}
850
Ian Ewellbda75592016-04-18 17:25:54 -0400851bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400852{
853 switch (pname)
854 {
855 case GL_TEXTURE_WRAP_R:
856 case GL_TEXTURE_SWIZZLE_R:
857 case GL_TEXTURE_SWIZZLE_G:
858 case GL_TEXTURE_SWIZZLE_B:
859 case GL_TEXTURE_SWIZZLE_A:
860 case GL_TEXTURE_BASE_LEVEL:
861 case GL_TEXTURE_MAX_LEVEL:
862 case GL_TEXTURE_COMPARE_MODE:
863 case GL_TEXTURE_COMPARE_FUNC:
864 case GL_TEXTURE_MIN_LOD:
865 case GL_TEXTURE_MAX_LOD:
Martin Radev1be913c2016-07-11 17:59:16 +0300866 if (context->getClientMajorVersion() < 3)
867 {
868 context->handleError(Error(GL_INVALID_ENUM));
869 return false;
870 }
871 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
872 {
873 context->handleError(Error(GL_INVALID_ENUM,
874 "ES3 texture parameters are not available without "
875 "GL_OES_EGL_image_external_essl3."));
876 return false;
877 }
878 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400879
880 default: break;
881 }
882
883 switch (pname)
884 {
885 case GL_TEXTURE_WRAP_S:
886 case GL_TEXTURE_WRAP_T:
887 case GL_TEXTURE_WRAP_R:
888 switch (param)
889 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000890 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400891 return true;
892 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400893 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300894 if (target == GL_TEXTURE_EXTERNAL_OES)
895 {
896 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400897 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300898 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
899 return false;
900 }
901 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400902 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400903 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400904 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400905 }
906
907 case GL_TEXTURE_MIN_FILTER:
908 switch (param)
909 {
910 case GL_NEAREST:
911 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400912 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400913 case GL_NEAREST_MIPMAP_NEAREST:
914 case GL_LINEAR_MIPMAP_NEAREST:
915 case GL_NEAREST_MIPMAP_LINEAR:
916 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300917 if (target == GL_TEXTURE_EXTERNAL_OES)
918 {
919 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400920 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300921 Error(GL_INVALID_ENUM,
922 "external textures only support NEAREST and LINEAR filtering"));
923 return false;
924 }
925 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400926 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400927 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400928 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400929 }
930 break;
931
932 case GL_TEXTURE_MAG_FILTER:
933 switch (param)
934 {
935 case GL_NEAREST:
936 case GL_LINEAR:
937 return true;
938 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400939 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400940 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400941 }
942 break;
943
944 case GL_TEXTURE_USAGE_ANGLE:
945 switch (param)
946 {
947 case GL_NONE:
948 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
949 return true;
950 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400951 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400952 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400953 }
954 break;
955
956 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400957 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400958 {
Jamie Madill437fa652016-05-03 15:13:24 -0400959 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400960 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400961 }
962
963 // we assume the parameter passed to this validation method is truncated, not rounded
964 if (param < 1)
965 {
Jamie Madill437fa652016-05-03 15:13:24 -0400966 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400967 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400968 }
969 return true;
970
971 case GL_TEXTURE_MIN_LOD:
972 case GL_TEXTURE_MAX_LOD:
973 // any value is permissible
974 return true;
975
976 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400977 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400978 switch (param)
979 {
980 case GL_NONE:
981 case GL_COMPARE_REF_TO_TEXTURE:
982 return true;
983 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400984 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400985 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400986 }
987 break;
988
989 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400990 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400991 switch (param)
992 {
993 case GL_LEQUAL:
994 case GL_GEQUAL:
995 case GL_LESS:
996 case GL_GREATER:
997 case GL_EQUAL:
998 case GL_NOTEQUAL:
999 case GL_ALWAYS:
1000 case GL_NEVER:
1001 return true;
1002 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001003 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001004 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001005 }
1006 break;
1007
1008 case GL_TEXTURE_SWIZZLE_R:
1009 case GL_TEXTURE_SWIZZLE_G:
1010 case GL_TEXTURE_SWIZZLE_B:
1011 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001012 switch (param)
1013 {
1014 case GL_RED:
1015 case GL_GREEN:
1016 case GL_BLUE:
1017 case GL_ALPHA:
1018 case GL_ZERO:
1019 case GL_ONE:
1020 return true;
1021 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001022 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001023 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001024 }
1025 break;
1026
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001027 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001028 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001029 {
Geoff Langb66a9092016-05-16 15:59:14 -04001030 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001031 return false;
1032 }
Geoff Langb66a9092016-05-16 15:59:14 -04001033 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1034 {
1035 context->handleError(
1036 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1037 return false;
1038 }
1039 return true;
1040
1041 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001042 if (param < 0)
1043 {
1044 context->handleError(Error(GL_INVALID_VALUE));
1045 return false;
1046 }
1047 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001048 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001049 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001050 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001051 }
1052}
1053
Geoff Langb1196682014-07-23 13:47:29 -04001054bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001055{
1056 switch (pname)
1057 {
1058 case GL_TEXTURE_MIN_FILTER:
1059 case GL_TEXTURE_MAG_FILTER:
1060 case GL_TEXTURE_WRAP_S:
1061 case GL_TEXTURE_WRAP_T:
1062 case GL_TEXTURE_WRAP_R:
1063 case GL_TEXTURE_MIN_LOD:
1064 case GL_TEXTURE_MAX_LOD:
1065 case GL_TEXTURE_COMPARE_MODE:
1066 case GL_TEXTURE_COMPARE_FUNC:
1067 return true;
1068
1069 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001070 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001071 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001072 }
1073}
1074
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001075bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001076 GLint x,
1077 GLint y,
1078 GLsizei width,
1079 GLsizei height,
1080 GLenum format,
1081 GLenum type,
1082 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001083{
Jamie Madillc29968b2016-01-20 11:17:23 -05001084 if (width < 0 || height < 0)
1085 {
Jamie Madill437fa652016-05-03 15:13:24 -04001086 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001087 return false;
1088 }
1089
Jamie Madill51f40ec2016-06-15 14:06:00 -04001090 auto readFramebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill26e91952014-03-05 15:01:27 -05001091
Jamie Madill51f40ec2016-06-15 14:06:00 -04001092 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001093 {
Jamie Madill437fa652016-05-03 15:13:24 -04001094 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001095 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001096 }
1097
Jamie Madill51f40ec2016-06-15 14:06:00 -04001098 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001099 {
Jamie Madill437fa652016-05-03 15:13:24 -04001100 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001101 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001102 }
1103
Jamie Madill51f40ec2016-06-15 14:06:00 -04001104 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1105 ASSERT(framebuffer);
Geoff Langbce529e2014-12-01 12:48:41 -05001106 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1107 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001108 {
Jamie Madill437fa652016-05-03 15:13:24 -04001109 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001110 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001111 }
1112
Geoff Langbce529e2014-12-01 12:48:41 -05001113 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1114 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001115 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Martin Radev1be913c2016-07-11 17:59:16 +03001116 GLuint clientVersion = context->getClientMajorVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001117
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001118 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1119 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001120
1121 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1122 {
Jamie Madill437fa652016-05-03 15:13:24 -04001123 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001124 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001125 }
1126
Jamie Madillc29968b2016-01-20 11:17:23 -05001127 return true;
1128}
1129
1130bool ValidateReadnPixelsEXT(Context *context,
1131 GLint x,
1132 GLint y,
1133 GLsizei width,
1134 GLsizei height,
1135 GLenum format,
1136 GLenum type,
1137 GLsizei bufSize,
1138 GLvoid *pixels)
1139{
1140 if (bufSize < 0)
1141 {
Jamie Madill437fa652016-05-03 15:13:24 -04001142 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001143 return false;
1144 }
1145
Geoff Lang5d601382014-07-22 15:14:06 -04001146 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1147 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001148
Jamie Madille2e406c2016-06-02 13:04:10 -04001149 auto outputPitchOrErr =
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001150 sizedFormatInfo.computeRowPitch(type, width, context->getGLState().getPackAlignment(),
1151 context->getGLState().getPackRowLength());
Jamie Madille2e406c2016-06-02 13:04:10 -04001152
1153 if (outputPitchOrErr.isError())
1154 {
1155 context->handleError(outputPitchOrErr.getError());
1156 return false;
1157 }
1158
1159 CheckedNumeric<GLuint> checkedOutputPitch(outputPitchOrErr.getResult());
1160 auto checkedRequiredSize = checkedOutputPitch * height;
1161 if (!checkedRequiredSize.IsValid())
1162 {
1163 context->handleError(Error(GL_INVALID_OPERATION, "Unsigned multiplication overflow."));
1164 return false;
1165 }
1166
Jamie Madill26e91952014-03-05 15:01:27 -05001167 // sized query sanity check
Jamie Madille2e406c2016-06-02 13:04:10 -04001168 if (checkedRequiredSize.ValueOrDie() > static_cast<GLuint>(bufSize))
Jamie Madill26e91952014-03-05 15:01:27 -05001169 {
Jamie Madill437fa652016-05-03 15:13:24 -04001170 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001171 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001172 }
1173
Jamie Madillc29968b2016-01-20 11:17:23 -05001174 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001175}
1176
Olli Etuaho41997e72016-03-10 13:38:39 +02001177bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001178{
1179 if (!context->getExtensions().occlusionQueryBoolean &&
1180 !context->getExtensions().disjointTimerQuery)
1181 {
Jamie Madill437fa652016-05-03 15:13:24 -04001182 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001183 return false;
1184 }
1185
Olli Etuaho41997e72016-03-10 13:38:39 +02001186 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001187}
1188
Olli Etuaho41997e72016-03-10 13:38:39 +02001189bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001190{
1191 if (!context->getExtensions().occlusionQueryBoolean &&
1192 !context->getExtensions().disjointTimerQuery)
1193 {
Jamie Madill437fa652016-05-03 15:13:24 -04001194 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001195 return false;
1196 }
1197
Olli Etuaho41997e72016-03-10 13:38:39 +02001198 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001199}
1200
1201bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001202{
1203 if (!ValidQueryType(context, target))
1204 {
Jamie Madill437fa652016-05-03 15:13:24 -04001205 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001206 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001207 }
1208
1209 if (id == 0)
1210 {
Jamie Madill437fa652016-05-03 15:13:24 -04001211 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001212 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001213 }
1214
1215 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1216 // of zero, if the active query object name for <target> is non-zero (for the
1217 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1218 // the active query for either target is non-zero), if <id> is the name of an
1219 // existing query object whose type does not match <target>, or if <id> is the
1220 // active query object name for any query type, the error INVALID_OPERATION is
1221 // generated.
1222
1223 // Ensure no other queries are active
1224 // NOTE: If other queries than occlusion are supported, we will need to check
1225 // separately that:
1226 // a) The query ID passed is not the current active query for any target/type
1227 // b) There are no active queries for the requested target (and in the case
1228 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1229 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001230
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001231 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001232 {
Jamie Madill437fa652016-05-03 15:13:24 -04001233 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001234 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001235 }
1236
1237 Query *queryObject = context->getQuery(id, true, target);
1238
1239 // check that name was obtained with glGenQueries
1240 if (!queryObject)
1241 {
Jamie Madill437fa652016-05-03 15:13:24 -04001242 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001243 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001244 }
1245
1246 // check for type mismatch
1247 if (queryObject->getType() != target)
1248 {
Jamie Madill437fa652016-05-03 15:13:24 -04001249 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001250 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001251 }
1252
1253 return true;
1254}
1255
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001256bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1257{
1258 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001259 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001260 {
Jamie Madill437fa652016-05-03 15:13:24 -04001261 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001262 return false;
1263 }
1264
1265 return ValidateBeginQueryBase(context, target, id);
1266}
1267
1268bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001269{
1270 if (!ValidQueryType(context, target))
1271 {
Jamie Madill437fa652016-05-03 15:13:24 -04001272 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001273 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001274 }
1275
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001276 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001277
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001278 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001279 {
Jamie Madill437fa652016-05-03 15:13:24 -04001280 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001281 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001282 }
1283
Jamie Madill45c785d2014-05-13 14:09:34 -04001284 return true;
1285}
1286
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001287bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1288{
1289 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001290 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001291 {
Jamie Madill437fa652016-05-03 15:13:24 -04001292 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001293 return false;
1294 }
1295
1296 return ValidateEndQueryBase(context, target);
1297}
1298
1299bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1300{
1301 if (!context->getExtensions().disjointTimerQuery)
1302 {
Jamie Madill437fa652016-05-03 15:13:24 -04001303 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001304 return false;
1305 }
1306
1307 if (target != GL_TIMESTAMP_EXT)
1308 {
Jamie Madill437fa652016-05-03 15:13:24 -04001309 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001310 return false;
1311 }
1312
1313 Query *queryObject = context->getQuery(id, true, target);
1314 if (queryObject == nullptr)
1315 {
Jamie Madill437fa652016-05-03 15:13:24 -04001316 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001317 return false;
1318 }
1319
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001320 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001321 {
Jamie Madill437fa652016-05-03 15:13:24 -04001322 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001323 return false;
1324 }
1325
1326 return true;
1327}
1328
1329bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1330{
1331 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1332 {
Jamie Madill437fa652016-05-03 15:13:24 -04001333 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001334 return false;
1335 }
1336
1337 switch (pname)
1338 {
1339 case GL_CURRENT_QUERY_EXT:
1340 if (target == GL_TIMESTAMP_EXT)
1341 {
Jamie Madill437fa652016-05-03 15:13:24 -04001342 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001343 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1344 return false;
1345 }
1346 break;
1347 case GL_QUERY_COUNTER_BITS_EXT:
1348 if (!context->getExtensions().disjointTimerQuery ||
1349 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1350 {
Jamie Madill437fa652016-05-03 15:13:24 -04001351 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001352 return false;
1353 }
1354 break;
1355 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001356 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001357 return false;
1358 }
1359
1360 return true;
1361}
1362
1363bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1364{
1365 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001366 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001367 {
Jamie Madill437fa652016-05-03 15:13:24 -04001368 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001369 return false;
1370 }
1371
1372 return ValidateGetQueryivBase(context, target, pname);
1373}
1374
1375bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1376{
1377 Query *queryObject = context->getQuery(id, false, GL_NONE);
1378
1379 if (!queryObject)
1380 {
Jamie Madill437fa652016-05-03 15:13:24 -04001381 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001382 return false;
1383 }
1384
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001385 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001386 {
Jamie Madill437fa652016-05-03 15:13:24 -04001387 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001388 return false;
1389 }
1390
1391 switch (pname)
1392 {
1393 case GL_QUERY_RESULT_EXT:
1394 case GL_QUERY_RESULT_AVAILABLE_EXT:
1395 break;
1396
1397 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001398 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001399 return false;
1400 }
1401
1402 return true;
1403}
1404
1405bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1406{
1407 if (!context->getExtensions().disjointTimerQuery)
1408 {
Jamie Madill437fa652016-05-03 15:13:24 -04001409 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001410 return false;
1411 }
1412 return ValidateGetQueryObjectValueBase(context, id, pname);
1413}
1414
1415bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1416{
1417 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001418 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001419 {
Jamie Madill437fa652016-05-03 15:13:24 -04001420 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001421 return false;
1422 }
1423 return ValidateGetQueryObjectValueBase(context, id, pname);
1424}
1425
1426bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1427{
1428 if (!context->getExtensions().disjointTimerQuery)
1429 {
Jamie Madill437fa652016-05-03 15:13:24 -04001430 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001431 return false;
1432 }
1433 return ValidateGetQueryObjectValueBase(context, id, pname);
1434}
1435
1436bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1437{
1438 if (!context->getExtensions().disjointTimerQuery)
1439 {
Jamie Madill437fa652016-05-03 15:13:24 -04001440 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001441 return false;
1442 }
1443 return ValidateGetQueryObjectValueBase(context, id, pname);
1444}
1445
Jamie Madill62d31cb2015-09-11 13:25:51 -04001446static bool ValidateUniformCommonBase(gl::Context *context,
1447 GLenum targetUniformType,
1448 GLint location,
1449 GLsizei count,
1450 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001451{
1452 if (count < 0)
1453 {
Jamie Madill437fa652016-05-03 15:13:24 -04001454 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001455 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001456 }
1457
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001458 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001459 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001460 {
Jamie Madill437fa652016-05-03 15:13:24 -04001461 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001462 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001463 }
1464
Geoff Langd8605522016-04-13 10:19:12 -04001465 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001466 {
1467 // Silently ignore the uniform command
1468 return false;
1469 }
1470
Geoff Lang7dd2e102014-11-10 15:19:26 -05001471 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001472 {
Jamie Madill437fa652016-05-03 15:13:24 -04001473 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001474 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001475 }
1476
Jamie Madill62d31cb2015-09-11 13:25:51 -04001477 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001478
1479 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001480 if (!uniform.isArray() && count > 1)
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 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001487 return true;
1488}
1489
Jamie Madillaa981bd2014-05-20 10:55:55 -04001490bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1491{
1492 // Check for ES3 uniform entry points
Martin Radev1be913c2016-07-11 17:59:16 +03001493 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT &&
1494 context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001495 {
Jamie Madill437fa652016-05-03 15:13:24 -04001496 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001497 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001498 }
1499
Jamie Madill62d31cb2015-09-11 13:25:51 -04001500 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001501 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1502 {
1503 return false;
1504 }
1505
Jamie Madillf2575982014-06-25 16:04:54 -04001506 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001507 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001508 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1509 {
Jamie Madill437fa652016-05-03 15:13:24 -04001510 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001511 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001512 }
1513
1514 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001515}
1516
1517bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1518 GLboolean transpose)
1519{
1520 // Check for ES3 uniform entry points
1521 int rows = VariableRowCount(matrixType);
1522 int cols = VariableColumnCount(matrixType);
Martin Radev1be913c2016-07-11 17:59:16 +03001523 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001524 {
Jamie Madill437fa652016-05-03 15:13:24 -04001525 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001526 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001527 }
1528
Martin Radev1be913c2016-07-11 17:59:16 +03001529 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001530 {
Jamie Madill437fa652016-05-03 15:13:24 -04001531 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001532 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001533 }
1534
Jamie Madill62d31cb2015-09-11 13:25:51 -04001535 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001536 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1537 {
1538 return false;
1539 }
1540
1541 if (uniform->type != matrixType)
1542 {
Jamie Madill437fa652016-05-03 15:13:24 -04001543 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001544 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001545 }
1546
1547 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001548}
1549
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001550bool ValidateStateQuery(ValidationContext *context,
1551 GLenum pname,
1552 GLenum *nativeType,
1553 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001554{
1555 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1556 {
Jamie Madill437fa652016-05-03 15:13:24 -04001557 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001558 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001559 }
1560
Jamie Madill0af26e12015-03-05 19:54:33 -05001561 const Caps &caps = context->getCaps();
1562
Jamie Madill893ab082014-05-16 16:56:10 -04001563 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1564 {
1565 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1566
Jamie Madill0af26e12015-03-05 19:54:33 -05001567 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001568 {
Jamie Madill437fa652016-05-03 15:13:24 -04001569 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001570 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001571 }
1572 }
1573
1574 switch (pname)
1575 {
1576 case GL_TEXTURE_BINDING_2D:
1577 case GL_TEXTURE_BINDING_CUBE_MAP:
1578 case GL_TEXTURE_BINDING_3D:
1579 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001580 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001581 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1582 if (!context->getExtensions().eglStreamConsumerExternal)
1583 {
Jamie Madill437fa652016-05-03 15:13:24 -04001584 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001585 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1586 return false;
1587 }
1588 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001589
1590 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1591 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1592 {
Jamie Madill51f40ec2016-06-15 14:06:00 -04001593 if (context->getGLState().getReadFramebuffer()->checkStatus(
1594 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001595 {
Jamie Madill437fa652016-05-03 15:13:24 -04001596 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001597 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001598 }
1599
Jamie Madill51f40ec2016-06-15 14:06:00 -04001600 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1601 ASSERT(framebuffer);
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001602 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001603 if (!attachment)
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 }
1609 break;
1610
1611 default:
1612 break;
1613 }
1614
1615 // pname is valid, but there are no parameters to return
1616 if (numParams == 0)
1617 {
1618 return false;
1619 }
1620
1621 return true;
1622}
1623
Jamie Madillc29968b2016-01-20 11:17:23 -05001624bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1625 GLenum target,
1626 GLint level,
1627 GLenum internalformat,
1628 bool isSubImage,
1629 GLint xoffset,
1630 GLint yoffset,
1631 GLint zoffset,
1632 GLint x,
1633 GLint y,
1634 GLsizei width,
1635 GLsizei height,
1636 GLint border,
1637 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001638{
Jamie Madill560a8d82014-05-21 13:06:20 -04001639 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1640 {
Jamie Madill437fa652016-05-03 15:13:24 -04001641 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001642 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001643 }
1644
1645 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1646 {
Jamie Madill437fa652016-05-03 15:13:24 -04001647 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001648 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001649 }
1650
1651 if (border != 0)
1652 {
Jamie Madill437fa652016-05-03 15:13:24 -04001653 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001654 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001655 }
1656
1657 if (!ValidMipLevel(context, target, level))
1658 {
Jamie Madill437fa652016-05-03 15:13:24 -04001659 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001660 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001661 }
1662
Jamie Madill51f40ec2016-06-15 14:06:00 -04001663 const auto &state = context->getGLState();
1664 auto readFramebuffer = state.getReadFramebuffer();
1665 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001666 {
Jamie Madill437fa652016-05-03 15:13:24 -04001667 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001668 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001669 }
1670
Jamie Madill51f40ec2016-06-15 14:06:00 -04001671 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001672 {
Jamie Madill437fa652016-05-03 15:13:24 -04001673 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001674 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001675 }
1676
Geoff Langaae65a42014-05-26 12:43:44 -04001677 const gl::Caps &caps = context->getCaps();
1678
Geoff Langaae65a42014-05-26 12:43:44 -04001679 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001680 switch (target)
1681 {
1682 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001683 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001684 break;
1685
1686 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1687 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1688 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1689 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1690 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1691 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001692 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001693 break;
1694
1695 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001696 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001697 break;
1698
1699 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001700 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001701 break;
1702
1703 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001704 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001705 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001706 }
1707
Jamie Madillc29968b2016-01-20 11:17:23 -05001708 gl::Texture *texture =
1709 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001710 if (!texture)
1711 {
Jamie Madill437fa652016-05-03 15:13:24 -04001712 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001713 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001714 }
1715
Geoff Lang69cce582015-09-17 13:20:36 -04001716 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001717 {
Jamie Madill437fa652016-05-03 15:13:24 -04001718 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001719 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001720 }
1721
Geoff Lang5d601382014-07-22 15:14:06 -04001722 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1723
1724 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001725 {
Jamie Madill437fa652016-05-03 15:13:24 -04001726 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001727 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001728 }
1729
Geoff Langa9be0dc2014-12-17 12:34:40 -05001730 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001731 {
Jamie Madill437fa652016-05-03 15:13:24 -04001732 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001733 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001734 }
1735
1736 if (isSubImage)
1737 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001738 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1739 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1740 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001741 {
Jamie Madill437fa652016-05-03 15:13:24 -04001742 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001743 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001744 }
1745 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001746 else
1747 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001748 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001749 {
Jamie Madill437fa652016-05-03 15:13:24 -04001750 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001751 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001752 }
1753
Martin Radev1be913c2016-07-11 17:59:16 +03001754 if (!formatInfo.textureSupport(context->getClientMajorVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001755 {
Jamie Madill437fa652016-05-03 15:13:24 -04001756 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001757 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001758 }
1759
1760 int maxLevelDimension = (maxDimension >> level);
1761 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1762 {
Jamie Madill437fa652016-05-03 15:13:24 -04001763 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001764 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001765 }
1766 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001767
Geoff Langa9be0dc2014-12-17 12:34:40 -05001768 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001769 return true;
1770}
1771
Jamie Madillf25855c2015-11-03 11:06:18 -05001772static bool ValidateDrawBase(ValidationContext *context,
1773 GLenum mode,
1774 GLsizei count,
1775 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001776{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001777 switch (mode)
1778 {
1779 case GL_POINTS:
1780 case GL_LINES:
1781 case GL_LINE_LOOP:
1782 case GL_LINE_STRIP:
1783 case GL_TRIANGLES:
1784 case GL_TRIANGLE_STRIP:
1785 case GL_TRIANGLE_FAN:
1786 break;
1787 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001788 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001789 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001790 }
1791
Jamie Madill250d33f2014-06-06 17:09:03 -04001792 if (count < 0)
1793 {
Jamie Madill437fa652016-05-03 15:13:24 -04001794 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001795 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001796 }
1797
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001798 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001799
Jamie Madill250d33f2014-06-06 17:09:03 -04001800 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001801 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001802 {
Jamie Madill437fa652016-05-03 15:13:24 -04001803 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001804 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001805 }
1806
Jamie Madill51f40ec2016-06-15 14:06:00 -04001807 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001808 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001809 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001810 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1811 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1812 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1813 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1814 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1815 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001816 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001817 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1818 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001819 {
1820 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1821 // Section 6.10 of the WebGL 1.0 spec
1822 ERR(
1823 "This ANGLE implementation does not support separate front/back stencil "
1824 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001825 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001826 return false;
1827 }
Jamie Madillac528012014-06-20 13:21:23 -04001828 }
1829
Jamie Madill51f40ec2016-06-15 14:06:00 -04001830 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001831 {
Jamie Madill437fa652016-05-03 15:13:24 -04001832 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001833 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001834 }
1835
Geoff Lang7dd2e102014-11-10 15:19:26 -05001836 gl::Program *program = state.getProgram();
1837 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001838 {
Jamie Madill437fa652016-05-03 15:13:24 -04001839 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001840 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001841 }
1842
Geoff Lang7dd2e102014-11-10 15:19:26 -05001843 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001844 {
Jamie Madill437fa652016-05-03 15:13:24 -04001845 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001846 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001847 }
1848
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001849 // Uniform buffer validation
1850 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1851 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001852 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001853 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001854 const OffsetBindingPointer<Buffer> &uniformBuffer =
1855 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001856
Geoff Lang5d124a62015-09-15 13:03:27 -04001857 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001858 {
1859 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001860 context->handleError(
1861 Error(GL_INVALID_OPERATION,
1862 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001863 return false;
1864 }
1865
Geoff Lang5d124a62015-09-15 13:03:27 -04001866 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001867 if (uniformBufferSize == 0)
1868 {
1869 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001870 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001871 }
1872
Jamie Madill62d31cb2015-09-11 13:25:51 -04001873 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001874 {
1875 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001876 context->handleError(
1877 Error(GL_INVALID_OPERATION,
1878 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001879 return false;
1880 }
1881 }
1882
Jamie Madill250d33f2014-06-06 17:09:03 -04001883 // No-op if zero count
1884 return (count > 0);
1885}
1886
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001887bool ValidateDrawArrays(ValidationContext *context,
1888 GLenum mode,
1889 GLint first,
1890 GLsizei count,
1891 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001892{
Jamie Madillfd716582014-06-06 17:09:04 -04001893 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001894 {
Jamie Madill437fa652016-05-03 15:13:24 -04001895 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001896 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001897 }
1898
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001899 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001900 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001901 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1902 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001903 {
1904 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1905 // that does not match the current transform feedback object's draw mode (if transform feedback
1906 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001907 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001908 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001909 }
1910
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001911 if (!ValidateDrawBase(context, mode, count, primcount))
1912 {
1913 return false;
1914 }
1915
1916 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001917 {
1918 return false;
1919 }
1920
1921 return true;
1922}
1923
Geoff Langb1196682014-07-23 13:47:29 -04001924bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001925{
1926 if (primcount < 0)
1927 {
Jamie Madill437fa652016-05-03 15:13:24 -04001928 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001929 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001930 }
1931
Jamie Madill2b976812014-08-25 15:47:49 -04001932 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001933 {
1934 return false;
1935 }
1936
1937 // No-op if zero primitive count
1938 return (primcount > 0);
1939}
1940
Geoff Lang87a93302014-09-16 13:29:43 -04001941static bool ValidateDrawInstancedANGLE(Context *context)
1942{
1943 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001944 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04001945
Geoff Lang7dd2e102014-11-10 15:19:26 -05001946 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001947
1948 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001949 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001950 {
1951 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001952 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001953 {
1954 return true;
1955 }
1956 }
1957
Jamie Madill437fa652016-05-03 15:13:24 -04001958 context->handleError(Error(GL_INVALID_OPERATION,
1959 "ANGLE_instanced_arrays requires that at least one active attribute"
1960 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001961 return false;
1962}
1963
1964bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1965{
1966 if (!ValidateDrawInstancedANGLE(context))
1967 {
1968 return false;
1969 }
1970
1971 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1972}
1973
Jamie Madillf25855c2015-11-03 11:06:18 -05001974bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001975 GLenum mode,
1976 GLsizei count,
1977 GLenum type,
1978 const GLvoid *indices,
1979 GLsizei primcount,
1980 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001981{
Jamie Madill250d33f2014-06-06 17:09:03 -04001982 switch (type)
1983 {
1984 case GL_UNSIGNED_BYTE:
1985 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03001986 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04001987 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03001988 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
1989 {
1990 context->handleError(Error(GL_INVALID_ENUM));
1991 return false;
1992 }
1993 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04001994 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001995 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03001996 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001997 }
1998
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001999 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002000
2001 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002002 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002003 {
2004 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2005 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002006 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002007 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002008 }
2009
2010 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002011 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002012 {
Jamie Madill437fa652016-05-03 15:13:24 -04002013 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002014 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002015 }
2016
Jamie Madill2b976812014-08-25 15:47:49 -04002017 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002018 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002019 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002020 {
Jamie Madill437fa652016-05-03 15:13:24 -04002021 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002022 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002023 }
2024
Jamie Madillae3000b2014-08-25 15:47:51 -04002025 if (elementArrayBuffer)
2026 {
2027 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2028
2029 GLint64 offset = reinterpret_cast<GLint64>(indices);
2030 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2031
2032 // check for integer overflows
2033 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2034 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2035 {
Jamie Madill437fa652016-05-03 15:13:24 -04002036 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002037 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002038 }
2039
2040 // Check for reading past the end of the bound buffer object
2041 if (byteCount > elementArrayBuffer->getSize())
2042 {
Jamie Madill437fa652016-05-03 15:13:24 -04002043 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002044 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002045 }
2046 }
2047 else if (!indices)
2048 {
2049 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002050 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002051 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002052 }
2053
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002054 if (!ValidateDrawBase(context, mode, count, primcount))
2055 {
2056 return false;
2057 }
2058
Jamie Madill2b976812014-08-25 15:47:49 -04002059 // Use max index to validate if our vertex buffers are large enough for the pull.
2060 // TODO: offer fast path, with disabled index validation.
2061 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2062 if (elementArrayBuffer)
2063 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002064 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002065 Error error =
2066 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2067 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002068 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002069 {
Jamie Madill437fa652016-05-03 15:13:24 -04002070 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002071 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002072 }
2073 }
2074 else
2075 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002076 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002077 }
2078
Jamie Madille79b1e12015-11-04 16:36:37 -05002079 // If we use an index greater than our maximum supported index range, return an error.
2080 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2081 // return an error if possible here.
2082 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2083 {
Jamie Madill437fa652016-05-03 15:13:24 -04002084 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002085 return false;
2086 }
2087
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002088 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002089 {
2090 return false;
2091 }
2092
Geoff Lang3edfe032015-09-04 16:38:24 -04002093 // No op if there are no real indices in the index data (all are primitive restart).
2094 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002095}
2096
Geoff Langb1196682014-07-23 13:47:29 -04002097bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002098 GLenum mode,
2099 GLsizei count,
2100 GLenum type,
2101 const GLvoid *indices,
2102 GLsizei primcount,
2103 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002104{
2105 if (primcount < 0)
2106 {
Jamie Madill437fa652016-05-03 15:13:24 -04002107 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002108 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002109 }
2110
Jamie Madill2b976812014-08-25 15:47:49 -04002111 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002112 {
2113 return false;
2114 }
2115
2116 // No-op zero primitive count
2117 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002118}
2119
Geoff Lang3edfe032015-09-04 16:38:24 -04002120bool ValidateDrawElementsInstancedANGLE(Context *context,
2121 GLenum mode,
2122 GLsizei count,
2123 GLenum type,
2124 const GLvoid *indices,
2125 GLsizei primcount,
2126 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002127{
2128 if (!ValidateDrawInstancedANGLE(context))
2129 {
2130 return false;
2131 }
2132
2133 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2134}
2135
Geoff Langb1196682014-07-23 13:47:29 -04002136bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002137 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002138{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002139 if (!ValidFramebufferTarget(target))
2140 {
Jamie Madill437fa652016-05-03 15:13:24 -04002141 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002142 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002143 }
2144
2145 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002146 {
2147 return false;
2148 }
2149
Jamie Madill55ec3b12014-07-03 10:38:57 -04002150 if (texture != 0)
2151 {
2152 gl::Texture *tex = context->getTexture(texture);
2153
2154 if (tex == NULL)
2155 {
Jamie Madill437fa652016-05-03 15:13:24 -04002156 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002157 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002158 }
2159
2160 if (level < 0)
2161 {
Jamie Madill437fa652016-05-03 15:13:24 -04002162 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002163 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002164 }
2165 }
2166
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002167 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002168 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002169
Jamie Madill84115c92015-04-23 15:00:07 -04002170 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002171 {
Jamie Madill437fa652016-05-03 15:13:24 -04002172 context->handleError(
2173 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002174 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002175 }
2176
2177 return true;
2178}
2179
Geoff Langb1196682014-07-23 13:47:29 -04002180bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002181 GLenum textarget, GLuint texture, GLint level)
2182{
Geoff Lang95663912015-04-02 15:54:45 -04002183 // 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 +03002184 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2185 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002186 {
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 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002192 {
2193 return false;
2194 }
2195
Jamie Madill55ec3b12014-07-03 10:38:57 -04002196 if (texture != 0)
2197 {
2198 gl::Texture *tex = context->getTexture(texture);
2199 ASSERT(tex);
2200
Jamie Madill2a6564e2014-07-11 09:53:19 -04002201 const gl::Caps &caps = context->getCaps();
2202
Jamie Madill55ec3b12014-07-03 10:38:57 -04002203 switch (textarget)
2204 {
2205 case GL_TEXTURE_2D:
2206 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002207 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002208 {
Jamie Madill437fa652016-05-03 15:13:24 -04002209 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002210 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002211 }
2212 if (tex->getTarget() != GL_TEXTURE_2D)
2213 {
Jamie Madill437fa652016-05-03 15:13:24 -04002214 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002215 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002216 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002217 }
2218 break;
2219
2220 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2221 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2222 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2223 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2224 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2225 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2226 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002227 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002228 {
Jamie Madill437fa652016-05-03 15:13:24 -04002229 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002230 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002231 }
2232 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2233 {
Jamie Madill437fa652016-05-03 15:13:24 -04002234 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002235 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002236 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002237 }
2238 break;
2239
2240 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002241 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002242 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002243 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002244
2245 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2246 if (internalFormatInfo.compressed)
2247 {
Jamie Madill437fa652016-05-03 15:13:24 -04002248 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002249 return false;
2250 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002251 }
2252
Jamie Madill570f7c82014-07-03 10:38:54 -04002253 return true;
2254}
2255
Geoff Langb1196682014-07-23 13:47:29 -04002256bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002257{
2258 if (program == 0)
2259 {
Jamie Madill437fa652016-05-03 15:13:24 -04002260 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002261 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002262 }
2263
Dian Xiang769769a2015-09-09 15:20:08 -07002264 gl::Program *programObject = GetValidProgram(context, program);
2265 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002266 {
2267 return false;
2268 }
2269
Jamie Madill0063c512014-08-25 15:47:53 -04002270 if (!programObject || !programObject->isLinked())
2271 {
Jamie Madill437fa652016-05-03 15:13:24 -04002272 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002273 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002274 }
2275
Geoff Lang7dd2e102014-11-10 15:19:26 -05002276 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002277 {
Jamie Madill437fa652016-05-03 15:13:24 -04002278 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002279 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002280 }
2281
Jamie Madill0063c512014-08-25 15:47:53 -04002282 return true;
2283}
2284
Geoff Langb1196682014-07-23 13:47:29 -04002285bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002286{
2287 return ValidateGetUniformBase(context, program, location);
2288}
2289
Geoff Langb1196682014-07-23 13:47:29 -04002290bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002291{
Jamie Madill78f41802014-08-25 15:47:55 -04002292 return ValidateGetUniformBase(context, program, location);
2293}
2294
Geoff Langb1196682014-07-23 13:47:29 -04002295static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002296{
2297 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002298 {
Jamie Madill78f41802014-08-25 15:47:55 -04002299 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002300 }
2301
Jamie Madilla502c742014-08-28 17:19:13 -04002302 gl::Program *programObject = context->getProgram(program);
2303 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002304
Jamie Madill78f41802014-08-25 15:47:55 -04002305 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002306 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2307 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002308 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002309 {
Jamie Madill437fa652016-05-03 15:13:24 -04002310 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002311 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002312 }
2313
2314 return true;
2315}
2316
Geoff Langb1196682014-07-23 13:47:29 -04002317bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002318{
Jamie Madill78f41802014-08-25 15:47:55 -04002319 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002320}
2321
Geoff Langb1196682014-07-23 13:47:29 -04002322bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002323{
Jamie Madill78f41802014-08-25 15:47:55 -04002324 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002325}
2326
Austin Kinross08332632015-05-05 13:35:47 -07002327bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2328 const GLenum *attachments, bool defaultFramebuffer)
2329{
2330 if (numAttachments < 0)
2331 {
Jamie Madill437fa652016-05-03 15:13:24 -04002332 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002333 return false;
2334 }
2335
2336 for (GLsizei i = 0; i < numAttachments; ++i)
2337 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002338 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002339 {
2340 if (defaultFramebuffer)
2341 {
Jamie Madill437fa652016-05-03 15:13:24 -04002342 context->handleError(Error(
2343 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002344 return false;
2345 }
2346
2347 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2348 {
Jamie Madill437fa652016-05-03 15:13:24 -04002349 context->handleError(Error(GL_INVALID_OPERATION,
2350 "Requested color attachment is greater than the maximum "
2351 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002352 return false;
2353 }
2354 }
2355 else
2356 {
2357 switch (attachments[i])
2358 {
2359 case GL_DEPTH_ATTACHMENT:
2360 case GL_STENCIL_ATTACHMENT:
2361 case GL_DEPTH_STENCIL_ATTACHMENT:
2362 if (defaultFramebuffer)
2363 {
Jamie Madill437fa652016-05-03 15:13:24 -04002364 context->handleError(
2365 Error(GL_INVALID_ENUM,
2366 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002367 return false;
2368 }
2369 break;
2370 case GL_COLOR:
2371 case GL_DEPTH:
2372 case GL_STENCIL:
2373 if (!defaultFramebuffer)
2374 {
Jamie Madill437fa652016-05-03 15:13:24 -04002375 context->handleError(
2376 Error(GL_INVALID_ENUM,
2377 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002378 return false;
2379 }
2380 break;
2381 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002382 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002383 return false;
2384 }
2385 }
2386 }
2387
2388 return true;
2389}
2390
Austin Kinross6ee1e782015-05-29 17:05:37 -07002391bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2392{
2393 // Note that debug marker calls must not set error state
2394
2395 if (length < 0)
2396 {
2397 return false;
2398 }
2399
2400 if (marker == nullptr)
2401 {
2402 return false;
2403 }
2404
2405 return true;
2406}
2407
2408bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2409{
2410 // Note that debug marker calls must not set error state
2411
2412 if (length < 0)
2413 {
2414 return false;
2415 }
2416
2417 if (length > 0 && marker == nullptr)
2418 {
2419 return false;
2420 }
2421
2422 return true;
2423}
2424
Geoff Langdcab33b2015-07-21 13:03:16 -04002425bool ValidateEGLImageTargetTexture2DOES(Context *context,
2426 egl::Display *display,
2427 GLenum target,
2428 egl::Image *image)
2429{
Geoff Langa8406172015-07-21 16:53:39 -04002430 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2431 {
Jamie Madill437fa652016-05-03 15:13:24 -04002432 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002433 return false;
2434 }
2435
2436 switch (target)
2437 {
2438 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002439 if (!context->getExtensions().eglImage)
2440 {
2441 context->handleError(Error(
2442 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2443 }
2444 break;
2445
2446 case GL_TEXTURE_EXTERNAL_OES:
2447 if (!context->getExtensions().eglImageExternal)
2448 {
2449 context->handleError(Error(
2450 GL_INVALID_ENUM,
2451 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2452 }
Geoff Langa8406172015-07-21 16:53:39 -04002453 break;
2454
2455 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002456 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002457 return false;
2458 }
2459
2460 if (!display->isValidImage(image))
2461 {
Jamie Madill437fa652016-05-03 15:13:24 -04002462 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002463 return false;
2464 }
2465
2466 if (image->getSamples() > 0)
2467 {
Jamie Madill437fa652016-05-03 15:13:24 -04002468 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002469 "cannot create a 2D texture from a multisampled EGL image."));
2470 return false;
2471 }
2472
2473 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2474 if (!textureCaps.texturable)
2475 {
Jamie Madill437fa652016-05-03 15:13:24 -04002476 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002477 "EGL image internal format is not supported as a texture."));
2478 return false;
2479 }
2480
Geoff Langdcab33b2015-07-21 13:03:16 -04002481 return true;
2482}
2483
2484bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2485 egl::Display *display,
2486 GLenum target,
2487 egl::Image *image)
2488{
Geoff Langa8406172015-07-21 16:53:39 -04002489 if (!context->getExtensions().eglImage)
2490 {
Jamie Madill437fa652016-05-03 15:13:24 -04002491 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002492 return false;
2493 }
2494
2495 switch (target)
2496 {
2497 case GL_RENDERBUFFER:
2498 break;
2499
2500 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002501 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002502 return false;
2503 }
2504
2505 if (!display->isValidImage(image))
2506 {
Jamie Madill437fa652016-05-03 15:13:24 -04002507 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002508 return false;
2509 }
2510
2511 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2512 if (!textureCaps.renderable)
2513 {
Jamie Madill437fa652016-05-03 15:13:24 -04002514 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002515 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2516 return false;
2517 }
2518
Geoff Langdcab33b2015-07-21 13:03:16 -04002519 return true;
2520}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002521
2522bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2523{
Geoff Lang36167ab2015-12-07 10:27:14 -05002524 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002525 {
2526 // The default VAO should always exist
2527 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002528 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002529 return false;
2530 }
2531
2532 return true;
2533}
2534
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002535bool ValidateLinkProgram(Context *context, GLuint program)
2536{
2537 if (context->hasActiveTransformFeedback(program))
2538 {
2539 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002540 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002541 "Cannot link program while program is associated with an active "
2542 "transform feedback object."));
2543 return false;
2544 }
2545 return true;
2546}
2547
Geoff Langc5629752015-12-07 16:29:04 -05002548bool ValidateProgramBinaryBase(Context *context,
2549 GLuint program,
2550 GLenum binaryFormat,
2551 const void *binary,
2552 GLint length)
2553{
2554 Program *programObject = GetValidProgram(context, program);
2555 if (programObject == nullptr)
2556 {
2557 return false;
2558 }
2559
2560 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2561 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2562 programBinaryFormats.end())
2563 {
Jamie Madill437fa652016-05-03 15:13:24 -04002564 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002565 return false;
2566 }
2567
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002568 if (context->hasActiveTransformFeedback(program))
2569 {
2570 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002571 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002572 "Cannot change program binary while program is associated with "
2573 "an active transform feedback object."));
2574 return false;
2575 }
2576
Geoff Langc5629752015-12-07 16:29:04 -05002577 return true;
2578}
2579
2580bool ValidateGetProgramBinaryBase(Context *context,
2581 GLuint program,
2582 GLsizei bufSize,
2583 GLsizei *length,
2584 GLenum *binaryFormat,
2585 void *binary)
2586{
2587 Program *programObject = GetValidProgram(context, program);
2588 if (programObject == nullptr)
2589 {
2590 return false;
2591 }
2592
2593 if (!programObject->isLinked())
2594 {
Jamie Madill437fa652016-05-03 15:13:24 -04002595 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002596 return false;
2597 }
2598
2599 return true;
2600}
Jamie Madillc29968b2016-01-20 11:17:23 -05002601
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002602bool ValidateUseProgram(Context *context, GLuint program)
2603{
2604 if (program != 0)
2605 {
2606 Program *programObject = context->getProgram(program);
2607 if (!programObject)
2608 {
2609 // ES 3.1.0 section 7.3 page 72
2610 if (context->getShader(program))
2611 {
Jamie Madill437fa652016-05-03 15:13:24 -04002612 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002613 Error(GL_INVALID_OPERATION,
2614 "Attempted to use a single shader instead of a shader program."));
2615 return false;
2616 }
2617 else
2618 {
Jamie Madill437fa652016-05-03 15:13:24 -04002619 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002620 return false;
2621 }
2622 }
2623 if (!programObject->isLinked())
2624 {
Jamie Madill437fa652016-05-03 15:13:24 -04002625 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002626 return false;
2627 }
2628 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002629 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002630 {
2631 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002632 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002633 Error(GL_INVALID_OPERATION,
2634 "Cannot change active program while transform feedback is unpaused."));
2635 return false;
2636 }
2637
2638 return true;
2639}
2640
Jamie Madillc29968b2016-01-20 11:17:23 -05002641bool ValidateCopyTexImage2D(ValidationContext *context,
2642 GLenum target,
2643 GLint level,
2644 GLenum internalformat,
2645 GLint x,
2646 GLint y,
2647 GLsizei width,
2648 GLsizei height,
2649 GLint border)
2650{
Martin Radev1be913c2016-07-11 17:59:16 +03002651 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002652 {
2653 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2654 0, x, y, width, height, border);
2655 }
2656
Martin Radev1be913c2016-07-11 17:59:16 +03002657 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002658 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2659 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002660}
Jamie Madillc29968b2016-01-20 11:17:23 -05002661
2662bool ValidateFramebufferRenderbuffer(Context *context,
2663 GLenum target,
2664 GLenum attachment,
2665 GLenum renderbuffertarget,
2666 GLuint renderbuffer)
2667{
2668 if (!ValidFramebufferTarget(target) ||
2669 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2670 {
Jamie Madill437fa652016-05-03 15:13:24 -04002671 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002672 return false;
2673 }
2674
2675 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2676 renderbuffertarget, renderbuffer);
2677}
2678
2679bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2680{
2681 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2682 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2683 {
Jamie Madill437fa652016-05-03 15:13:24 -04002684 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002685 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2686 return false;
2687 }
2688
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002689 ASSERT(context->getGLState().getDrawFramebuffer());
2690 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002691 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2692
2693 // This should come first before the check for the default frame buffer
2694 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2695 // rather than INVALID_OPERATION
2696 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2697 {
2698 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2699
2700 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002701 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2702 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002703 {
2704 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002705 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2706 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2707 // 3.1 is still a bit ambiguous about the error, but future specs are
2708 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002709 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002710 return false;
2711 }
2712 else if (bufs[colorAttachment] >= maxColorAttachment)
2713 {
Jamie Madill437fa652016-05-03 15:13:24 -04002714 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002715 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002716 return false;
2717 }
2718 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2719 frameBufferId != 0)
2720 {
2721 // INVALID_OPERATION-GL is bound to buffer and ith argument
2722 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002723 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002724 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2725 return false;
2726 }
2727 }
2728
2729 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2730 // and n is not 1 or bufs is bound to value other than BACK and NONE
2731 if (frameBufferId == 0)
2732 {
2733 if (n != 1)
2734 {
Jamie Madill437fa652016-05-03 15:13:24 -04002735 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002736 "n must be 1 when GL is bound to the default framebuffer"));
2737 return false;
2738 }
2739
2740 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2741 {
Jamie Madill437fa652016-05-03 15:13:24 -04002742 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002743 GL_INVALID_OPERATION,
2744 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2745 return false;
2746 }
2747 }
2748
2749 return true;
2750}
2751
2752bool ValidateCopyTexSubImage2D(Context *context,
2753 GLenum target,
2754 GLint level,
2755 GLint xoffset,
2756 GLint yoffset,
2757 GLint x,
2758 GLint y,
2759 GLsizei width,
2760 GLsizei height)
2761{
Martin Radev1be913c2016-07-11 17:59:16 +03002762 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002763 {
2764 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2765 yoffset, x, y, width, height, 0);
2766 }
2767
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002768 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2769 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002770}
2771
Olli Etuaho4f667482016-03-30 15:56:35 +03002772bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2773{
2774 if (!ValidBufferTarget(context, target))
2775 {
Jamie Madill437fa652016-05-03 15:13:24 -04002776 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002777 return false;
2778 }
2779
2780 if (pname != GL_BUFFER_MAP_POINTER)
2781 {
Jamie Madill437fa652016-05-03 15:13:24 -04002782 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002783 return false;
2784 }
2785
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002786 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002787
2788 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2789 // target bound to zero generate an INVALID_OPERATION error."
2790 // GLES 3.1 section 6.6 explicitly specifies this error.
2791 if (!buffer)
2792 {
Jamie Madill437fa652016-05-03 15:13:24 -04002793 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002794 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2795 return false;
2796 }
2797
2798 return true;
2799}
2800
2801bool ValidateUnmapBufferBase(Context *context, GLenum target)
2802{
2803 if (!ValidBufferTarget(context, target))
2804 {
Jamie Madill437fa652016-05-03 15:13:24 -04002805 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002806 return false;
2807 }
2808
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002809 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002810
2811 if (buffer == nullptr || !buffer->isMapped())
2812 {
Jamie Madill437fa652016-05-03 15:13:24 -04002813 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002814 return false;
2815 }
2816
2817 return true;
2818}
2819
2820bool ValidateMapBufferRangeBase(Context *context,
2821 GLenum target,
2822 GLintptr offset,
2823 GLsizeiptr length,
2824 GLbitfield access)
2825{
2826 if (!ValidBufferTarget(context, target))
2827 {
Jamie Madill437fa652016-05-03 15:13:24 -04002828 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002829 return false;
2830 }
2831
2832 if (offset < 0 || length < 0)
2833 {
Jamie Madill437fa652016-05-03 15:13:24 -04002834 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002835 return false;
2836 }
2837
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002838 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002839
2840 if (!buffer)
2841 {
Jamie Madill437fa652016-05-03 15:13:24 -04002842 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002843 return false;
2844 }
2845
2846 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002847 CheckedNumeric<size_t> checkedOffset(offset);
2848 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002849
Jamie Madille2e406c2016-06-02 13:04:10 -04002850 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002851 {
Jamie Madill437fa652016-05-03 15:13:24 -04002852 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002853 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2854 return false;
2855 }
2856
2857 // Check for invalid bits in the mask
2858 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2859 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2860 GL_MAP_UNSYNCHRONIZED_BIT;
2861
2862 if (access & ~(allAccessBits))
2863 {
Jamie Madill437fa652016-05-03 15:13:24 -04002864 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002865 return false;
2866 }
2867
2868 if (length == 0)
2869 {
Jamie Madill437fa652016-05-03 15:13:24 -04002870 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002871 return false;
2872 }
2873
2874 if (buffer->isMapped())
2875 {
Jamie Madill437fa652016-05-03 15:13:24 -04002876 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002877 return false;
2878 }
2879
2880 // Check for invalid bit combinations
2881 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2882 {
Jamie Madill437fa652016-05-03 15:13:24 -04002883 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002884 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2885 return false;
2886 }
2887
2888 GLbitfield writeOnlyBits =
2889 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2890
2891 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2892 {
Jamie Madill437fa652016-05-03 15:13:24 -04002893 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002894 "Invalid access bits when mapping buffer for reading: 0x%X.",
2895 access));
2896 return false;
2897 }
2898
2899 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2900 {
Jamie Madill437fa652016-05-03 15:13:24 -04002901 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002902 GL_INVALID_OPERATION,
2903 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2904 return false;
2905 }
2906 return true;
2907}
2908
2909bool ValidateFlushMappedBufferRangeBase(Context *context,
2910 GLenum target,
2911 GLintptr offset,
2912 GLsizeiptr length)
2913{
2914 if (offset < 0 || length < 0)
2915 {
Jamie Madill437fa652016-05-03 15:13:24 -04002916 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002917 return false;
2918 }
2919
2920 if (!ValidBufferTarget(context, target))
2921 {
Jamie Madill437fa652016-05-03 15:13:24 -04002922 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002923 return false;
2924 }
2925
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002926 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002927
2928 if (buffer == nullptr)
2929 {
Jamie Madill437fa652016-05-03 15:13:24 -04002930 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002931 return false;
2932 }
2933
2934 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2935 {
Jamie Madill437fa652016-05-03 15:13:24 -04002936 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002937 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2938 return false;
2939 }
2940
2941 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002942 CheckedNumeric<size_t> checkedOffset(offset);
2943 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002944
Jamie Madille2e406c2016-06-02 13:04:10 -04002945 if (!checkedSize.IsValid() ||
2946 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002947 {
Jamie Madill437fa652016-05-03 15:13:24 -04002948 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002949 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2950 return false;
2951 }
2952
2953 return true;
2954}
2955
Olli Etuaho0f2b1562016-05-13 16:15:35 +03002956bool ValidateGenerateMipmap(Context *context, GLenum target)
2957{
2958 if (!ValidTextureTarget(context, target))
2959 {
2960 context->handleError(Error(GL_INVALID_ENUM));
2961 return false;
2962 }
2963
2964 Texture *texture = context->getTargetTexture(target);
2965
2966 if (texture == nullptr)
2967 {
2968 context->handleError(Error(GL_INVALID_OPERATION));
2969 return false;
2970 }
2971
2972 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
2973
2974 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
2975 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
2976 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2977 {
2978 context->handleError(Error(GL_INVALID_OPERATION));
2979 return false;
2980 }
2981
2982 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
2983 GLenum internalFormat = texture->getInternalFormat(baseTarget, effectiveBaseLevel);
2984 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
2985 const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat);
2986
2987 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
2988 // unsized formats or that are color renderable and filterable. Since we do not track if
2989 // the texture was created with sized or unsized format (only sized formats are stored),
2990 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
2991 // be able to) because they aren't color renderable. Simply do a special case for LUMA
2992 // textures since they're the only texture format that can be created with unsized formats
2993 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
2994 // was the last version to use add them.
2995 bool isLUMA = internalFormat == GL_LUMINANCE8_EXT ||
2996 internalFormat == GL_LUMINANCE8_ALPHA8_EXT || internalFormat == GL_ALPHA8_EXT;
2997
2998 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable ||
2999 (!formatCaps.renderable && !isLUMA) || formatInfo.compressed)
3000 {
3001 context->handleError(Error(GL_INVALID_OPERATION));
3002 return false;
3003 }
3004
3005 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Martin Radev1be913c2016-07-11 17:59:16 +03003006 if (context->getClientMajorVersion() == 2 && formatInfo.colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003007 {
3008 context->handleError(Error(GL_INVALID_OPERATION));
3009 return false;
3010 }
3011
3012 // Non-power of 2 ES2 check
3013 if (!context->getExtensions().textureNPOT &&
3014 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3015 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3016 {
Martin Radev1be913c2016-07-11 17:59:16 +03003017 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003018 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3019 context->handleError(Error(GL_INVALID_OPERATION));
3020 return false;
3021 }
3022
3023 // Cube completeness check
3024 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3025 {
3026 context->handleError(Error(GL_INVALID_OPERATION));
3027 return false;
3028 }
3029
3030 return true;
3031}
3032
Olli Etuaho41997e72016-03-10 13:38:39 +02003033bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3034{
3035 return ValidateGenOrDelete(context, n);
3036}
3037
3038bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3039{
3040 return ValidateGenOrDelete(context, n);
3041}
3042
3043bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3044{
3045 return ValidateGenOrDelete(context, n);
3046}
3047
3048bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3049{
3050 return ValidateGenOrDelete(context, n);
3051}
3052
3053bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3054{
3055 return ValidateGenOrDelete(context, n);
3056}
3057
3058bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3059{
3060 return ValidateGenOrDelete(context, n);
3061}
3062
3063bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3064{
3065 return ValidateGenOrDelete(context, n);
3066}
3067
3068bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3069{
3070 return ValidateGenOrDelete(context, n);
3071}
3072
3073bool ValidateGenOrDelete(Context *context, GLint n)
3074{
3075 if (n < 0)
3076 {
Jamie Madill437fa652016-05-03 15:13:24 -04003077 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003078 return false;
3079 }
3080 return true;
3081}
3082
Jamie Madillc29968b2016-01-20 11:17:23 -05003083} // namespace gl