blob: ab575f1c4220c2972ea646969708f83129b3edf4 [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 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400711 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400712
Geoff Langa15472a2015-08-11 11:48:03 -0400713 for (size_t drawbufferIdx = 0;
714 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400715 {
Geoff Langa15472a2015-08-11 11:48:03 -0400716 const FramebufferAttachment *attachment =
717 drawFramebuffer->getDrawBuffer(drawbufferIdx);
718 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400719 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400720 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400721
Geoff Langb2f3d052013-08-13 12:49:27 -0400722 // The GL ES 3.0.2 spec (pg 193) states that:
723 // 1) If the read buffer is fixed point format, the draw buffer must be as well
724 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
725 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500726 // Changes with EXT_color_buffer_float:
727 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -0400728 GLenum readComponentType = readFormat.info->componentType;
729 GLenum drawComponentType = drawFormat.info->componentType;
Jamie Madill6163c752015-12-07 16:32:59 -0500730 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
731 readComponentType == GL_SIGNED_NORMALIZED);
732 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
733 drawComponentType == GL_SIGNED_NORMALIZED);
734
735 if (extensions.colorBufferFloat)
736 {
737 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
738 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
739
740 if (readFixedOrFloat != drawFixedOrFloat)
741 {
Jamie Madill437fa652016-05-03 15:13:24 -0400742 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500743 "If the read buffer contains fixed-point or "
744 "floating-point values, the draw buffer "
745 "must as well."));
746 return false;
747 }
748 }
749 else if (readFixedPoint != drawFixedPoint)
750 {
Jamie Madill437fa652016-05-03 15:13:24 -0400751 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500752 "If the read buffer contains fixed-point "
753 "values, the draw buffer must as well."));
754 return false;
755 }
756
757 if (readComponentType == GL_UNSIGNED_INT &&
758 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 {
Jamie Madill437fa652016-05-03 15:13:24 -0400760 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400761 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 }
763
Jamie Madill6163c752015-12-07 16:32:59 -0500764 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400765 {
Jamie Madill437fa652016-05-03 15:13:24 -0400766 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400767 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 }
769
Jamie Madilla3944d42016-07-22 22:13:26 -0400770 if (readColorBuffer->getSamples() > 0 &&
771 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400772 {
Jamie Madill437fa652016-05-03 15:13:24 -0400773 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400774 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775 }
776 }
777 }
778
Jamie Madilla3944d42016-07-22 22:13:26 -0400779 if ((readFormat.info->componentType == GL_INT ||
780 readFormat.info->componentType == GL_UNSIGNED_INT) &&
781 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400782 {
Jamie Madill437fa652016-05-03 15:13:24 -0400783 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400784 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400786 }
787 }
788
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200789 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
790 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
791 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400792 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200793 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400794 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400795 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
796 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400797
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200798 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400799 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400800 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400801 {
Jamie Madill437fa652016-05-03 15:13:24 -0400802 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400803 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400804 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200806 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400807 {
Jamie Madill437fa652016-05-03 15:13:24 -0400808 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400809 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400810 }
811 }
812 }
813 }
814
815 return true;
816}
817
Geoff Langb1196682014-07-23 13:47:29 -0400818bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400819{
820 switch (pname)
821 {
822 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
823 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
824 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
825 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
826 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
827 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
828 case GL_CURRENT_VERTEX_ATTRIB:
Martin Radev1be913c2016-07-11 17:59:16 +0300829 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400830
831 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
Martin Radev1be913c2016-07-11 17:59:16 +0300832 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
833 // the same constant.
834 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
835 "ANGLE extension enums not equal to GL enums.");
836 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400837
838 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Martin Radev1be913c2016-07-11 17:59:16 +0300839 if (context->getClientMajorVersion() < 3)
840 {
841 context->handleError(Error(GL_INVALID_ENUM));
842 return false;
843 }
844 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400845
846 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400847 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300848 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400849 }
850}
851
Ian Ewellbda75592016-04-18 17:25:54 -0400852bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400853{
854 switch (pname)
855 {
856 case GL_TEXTURE_WRAP_R:
857 case GL_TEXTURE_SWIZZLE_R:
858 case GL_TEXTURE_SWIZZLE_G:
859 case GL_TEXTURE_SWIZZLE_B:
860 case GL_TEXTURE_SWIZZLE_A:
861 case GL_TEXTURE_BASE_LEVEL:
862 case GL_TEXTURE_MAX_LEVEL:
863 case GL_TEXTURE_COMPARE_MODE:
864 case GL_TEXTURE_COMPARE_FUNC:
865 case GL_TEXTURE_MIN_LOD:
866 case GL_TEXTURE_MAX_LOD:
Martin Radev1be913c2016-07-11 17:59:16 +0300867 if (context->getClientMajorVersion() < 3)
868 {
869 context->handleError(Error(GL_INVALID_ENUM));
870 return false;
871 }
872 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
873 {
874 context->handleError(Error(GL_INVALID_ENUM,
875 "ES3 texture parameters are not available without "
876 "GL_OES_EGL_image_external_essl3."));
877 return false;
878 }
879 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400880
881 default: break;
882 }
883
884 switch (pname)
885 {
886 case GL_TEXTURE_WRAP_S:
887 case GL_TEXTURE_WRAP_T:
888 case GL_TEXTURE_WRAP_R:
889 switch (param)
890 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000891 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400892 return true;
893 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400894 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300895 if (target == GL_TEXTURE_EXTERNAL_OES)
896 {
897 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400898 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300899 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
900 return false;
901 }
902 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400903 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400904 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400905 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400906 }
907
908 case GL_TEXTURE_MIN_FILTER:
909 switch (param)
910 {
911 case GL_NEAREST:
912 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400913 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400914 case GL_NEAREST_MIPMAP_NEAREST:
915 case GL_LINEAR_MIPMAP_NEAREST:
916 case GL_NEAREST_MIPMAP_LINEAR:
917 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300918 if (target == GL_TEXTURE_EXTERNAL_OES)
919 {
920 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400921 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300922 Error(GL_INVALID_ENUM,
923 "external textures only support NEAREST and LINEAR filtering"));
924 return false;
925 }
926 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400927 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400928 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400929 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400930 }
931 break;
932
933 case GL_TEXTURE_MAG_FILTER:
934 switch (param)
935 {
936 case GL_NEAREST:
937 case GL_LINEAR:
938 return true;
939 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400940 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400941 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400942 }
943 break;
944
945 case GL_TEXTURE_USAGE_ANGLE:
946 switch (param)
947 {
948 case GL_NONE:
949 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
950 return true;
951 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400952 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400953 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400954 }
955 break;
956
957 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400958 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400959 {
Jamie Madill437fa652016-05-03 15:13:24 -0400960 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400961 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400962 }
963
964 // we assume the parameter passed to this validation method is truncated, not rounded
965 if (param < 1)
966 {
Jamie Madill437fa652016-05-03 15:13:24 -0400967 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400968 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400969 }
970 return true;
971
972 case GL_TEXTURE_MIN_LOD:
973 case GL_TEXTURE_MAX_LOD:
974 // any value is permissible
975 return true;
976
977 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400978 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400979 switch (param)
980 {
981 case GL_NONE:
982 case GL_COMPARE_REF_TO_TEXTURE:
983 return true;
984 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400985 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400986 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400987 }
988 break;
989
990 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400991 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400992 switch (param)
993 {
994 case GL_LEQUAL:
995 case GL_GEQUAL:
996 case GL_LESS:
997 case GL_GREATER:
998 case GL_EQUAL:
999 case GL_NOTEQUAL:
1000 case GL_ALWAYS:
1001 case GL_NEVER:
1002 return true;
1003 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001004 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001005 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001006 }
1007 break;
1008
1009 case GL_TEXTURE_SWIZZLE_R:
1010 case GL_TEXTURE_SWIZZLE_G:
1011 case GL_TEXTURE_SWIZZLE_B:
1012 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001013 switch (param)
1014 {
1015 case GL_RED:
1016 case GL_GREEN:
1017 case GL_BLUE:
1018 case GL_ALPHA:
1019 case GL_ZERO:
1020 case GL_ONE:
1021 return true;
1022 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001023 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001024 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001025 }
1026 break;
1027
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001028 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001029 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001030 {
Geoff Langb66a9092016-05-16 15:59:14 -04001031 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001032 return false;
1033 }
Geoff Langb66a9092016-05-16 15:59:14 -04001034 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1035 {
1036 context->handleError(
1037 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1038 return false;
1039 }
1040 return true;
1041
1042 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001043 if (param < 0)
1044 {
1045 context->handleError(Error(GL_INVALID_VALUE));
1046 return false;
1047 }
1048 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001049 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001050 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001051 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001052 }
1053}
1054
Geoff Langb1196682014-07-23 13:47:29 -04001055bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001056{
1057 switch (pname)
1058 {
1059 case GL_TEXTURE_MIN_FILTER:
1060 case GL_TEXTURE_MAG_FILTER:
1061 case GL_TEXTURE_WRAP_S:
1062 case GL_TEXTURE_WRAP_T:
1063 case GL_TEXTURE_WRAP_R:
1064 case GL_TEXTURE_MIN_LOD:
1065 case GL_TEXTURE_MAX_LOD:
1066 case GL_TEXTURE_COMPARE_MODE:
1067 case GL_TEXTURE_COMPARE_FUNC:
1068 return true;
1069
1070 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001071 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001072 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001073 }
1074}
1075
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001076bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001077 GLint x,
1078 GLint y,
1079 GLsizei width,
1080 GLsizei height,
1081 GLenum format,
1082 GLenum type,
1083 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001084{
Jamie Madillc29968b2016-01-20 11:17:23 -05001085 if (width < 0 || height < 0)
1086 {
Jamie Madill437fa652016-05-03 15:13:24 -04001087 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001088 return false;
1089 }
1090
Jamie Madill51f40ec2016-06-15 14:06:00 -04001091 auto readFramebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill26e91952014-03-05 15:01:27 -05001092
Jamie Madill51f40ec2016-06-15 14:06:00 -04001093 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001094 {
Jamie Madill437fa652016-05-03 15:13:24 -04001095 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001096 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001097 }
1098
Jamie Madill51f40ec2016-06-15 14:06:00 -04001099 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001100 {
Jamie Madill437fa652016-05-03 15:13:24 -04001101 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001102 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001103 }
1104
Jamie Madill51f40ec2016-06-15 14:06:00 -04001105 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1106 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001107
1108 if (framebuffer->getReadBufferState() == GL_NONE)
1109 {
1110 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1111 return false;
1112 }
1113
Geoff Langbce529e2014-12-01 12:48:41 -05001114 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1115 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001116 {
Jamie Madill437fa652016-05-03 15:13:24 -04001117 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001118 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001119 }
1120
Geoff Langbce529e2014-12-01 12:48:41 -05001121 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1122 GLenum currentType = framebuffer->getImplementationColorReadType();
Jamie Madilla3944d42016-07-22 22:13:26 -04001123 GLenum currentInternalFormat = readBuffer->getFormat().asSized();
Martin Radev1be913c2016-07-11 17:59:16 +03001124 GLuint clientVersion = context->getClientMajorVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001125
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001126 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1127 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001128
1129 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1130 {
Jamie Madill437fa652016-05-03 15:13:24 -04001131 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001132 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001133 }
1134
Jamie Madillc29968b2016-01-20 11:17:23 -05001135 return true;
1136}
1137
1138bool ValidateReadnPixelsEXT(Context *context,
1139 GLint x,
1140 GLint y,
1141 GLsizei width,
1142 GLsizei height,
1143 GLenum format,
1144 GLenum type,
1145 GLsizei bufSize,
1146 GLvoid *pixels)
1147{
1148 if (bufSize < 0)
1149 {
Jamie Madill437fa652016-05-03 15:13:24 -04001150 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001151 return false;
1152 }
1153
Geoff Lang5d601382014-07-22 15:14:06 -04001154 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1155 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001156
Jamie Madille2e406c2016-06-02 13:04:10 -04001157 auto outputPitchOrErr =
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001158 sizedFormatInfo.computeRowPitch(type, width, context->getGLState().getPackAlignment(),
1159 context->getGLState().getPackRowLength());
Jamie Madille2e406c2016-06-02 13:04:10 -04001160
1161 if (outputPitchOrErr.isError())
1162 {
1163 context->handleError(outputPitchOrErr.getError());
1164 return false;
1165 }
1166
1167 CheckedNumeric<GLuint> checkedOutputPitch(outputPitchOrErr.getResult());
1168 auto checkedRequiredSize = checkedOutputPitch * height;
1169 if (!checkedRequiredSize.IsValid())
1170 {
1171 context->handleError(Error(GL_INVALID_OPERATION, "Unsigned multiplication overflow."));
1172 return false;
1173 }
1174
Jamie Madill26e91952014-03-05 15:01:27 -05001175 // sized query sanity check
Jamie Madille2e406c2016-06-02 13:04:10 -04001176 if (checkedRequiredSize.ValueOrDie() > static_cast<GLuint>(bufSize))
Jamie Madill26e91952014-03-05 15:01:27 -05001177 {
Jamie Madill437fa652016-05-03 15:13:24 -04001178 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001179 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001180 }
1181
Jamie Madillc29968b2016-01-20 11:17:23 -05001182 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001183}
1184
Olli Etuaho41997e72016-03-10 13:38:39 +02001185bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001186{
1187 if (!context->getExtensions().occlusionQueryBoolean &&
1188 !context->getExtensions().disjointTimerQuery)
1189 {
Jamie Madill437fa652016-05-03 15:13:24 -04001190 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001191 return false;
1192 }
1193
Olli Etuaho41997e72016-03-10 13:38:39 +02001194 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001195}
1196
Olli Etuaho41997e72016-03-10 13:38:39 +02001197bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001198{
1199 if (!context->getExtensions().occlusionQueryBoolean &&
1200 !context->getExtensions().disjointTimerQuery)
1201 {
Jamie Madill437fa652016-05-03 15:13:24 -04001202 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001203 return false;
1204 }
1205
Olli Etuaho41997e72016-03-10 13:38:39 +02001206 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001207}
1208
1209bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001210{
1211 if (!ValidQueryType(context, target))
1212 {
Jamie Madill437fa652016-05-03 15:13:24 -04001213 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001214 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001215 }
1216
1217 if (id == 0)
1218 {
Jamie Madill437fa652016-05-03 15:13:24 -04001219 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001220 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001221 }
1222
1223 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1224 // of zero, if the active query object name for <target> is non-zero (for the
1225 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1226 // the active query for either target is non-zero), if <id> is the name of an
1227 // existing query object whose type does not match <target>, or if <id> is the
1228 // active query object name for any query type, the error INVALID_OPERATION is
1229 // generated.
1230
1231 // Ensure no other queries are active
1232 // NOTE: If other queries than occlusion are supported, we will need to check
1233 // separately that:
1234 // a) The query ID passed is not the current active query for any target/type
1235 // b) There are no active queries for the requested target (and in the case
1236 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1237 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001238
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001239 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001240 {
Jamie Madill437fa652016-05-03 15:13:24 -04001241 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001242 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001243 }
1244
1245 Query *queryObject = context->getQuery(id, true, target);
1246
1247 // check that name was obtained with glGenQueries
1248 if (!queryObject)
1249 {
Jamie Madill437fa652016-05-03 15:13:24 -04001250 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001251 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001252 }
1253
1254 // check for type mismatch
1255 if (queryObject->getType() != target)
1256 {
Jamie Madill437fa652016-05-03 15:13:24 -04001257 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001258 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001259 }
1260
1261 return true;
1262}
1263
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001264bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1265{
1266 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001267 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001268 {
Jamie Madill437fa652016-05-03 15:13:24 -04001269 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001270 return false;
1271 }
1272
1273 return ValidateBeginQueryBase(context, target, id);
1274}
1275
1276bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001277{
1278 if (!ValidQueryType(context, target))
1279 {
Jamie Madill437fa652016-05-03 15:13:24 -04001280 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001281 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001282 }
1283
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001284 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001285
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001286 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001287 {
Jamie Madill437fa652016-05-03 15:13:24 -04001288 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001289 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001290 }
1291
Jamie Madill45c785d2014-05-13 14:09:34 -04001292 return true;
1293}
1294
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001295bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1296{
1297 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001298 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001299 {
Jamie Madill437fa652016-05-03 15:13:24 -04001300 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001301 return false;
1302 }
1303
1304 return ValidateEndQueryBase(context, target);
1305}
1306
1307bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1308{
1309 if (!context->getExtensions().disjointTimerQuery)
1310 {
Jamie Madill437fa652016-05-03 15:13:24 -04001311 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001312 return false;
1313 }
1314
1315 if (target != GL_TIMESTAMP_EXT)
1316 {
Jamie Madill437fa652016-05-03 15:13:24 -04001317 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001318 return false;
1319 }
1320
1321 Query *queryObject = context->getQuery(id, true, target);
1322 if (queryObject == nullptr)
1323 {
Jamie Madill437fa652016-05-03 15:13:24 -04001324 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001325 return false;
1326 }
1327
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001328 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001329 {
Jamie Madill437fa652016-05-03 15:13:24 -04001330 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001331 return false;
1332 }
1333
1334 return true;
1335}
1336
1337bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1338{
1339 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1340 {
Jamie Madill437fa652016-05-03 15:13:24 -04001341 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001342 return false;
1343 }
1344
1345 switch (pname)
1346 {
1347 case GL_CURRENT_QUERY_EXT:
1348 if (target == GL_TIMESTAMP_EXT)
1349 {
Jamie Madill437fa652016-05-03 15:13:24 -04001350 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001351 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1352 return false;
1353 }
1354 break;
1355 case GL_QUERY_COUNTER_BITS_EXT:
1356 if (!context->getExtensions().disjointTimerQuery ||
1357 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1358 {
Jamie Madill437fa652016-05-03 15:13:24 -04001359 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001360 return false;
1361 }
1362 break;
1363 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001364 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001365 return false;
1366 }
1367
1368 return true;
1369}
1370
1371bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1372{
1373 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001374 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001375 {
Jamie Madill437fa652016-05-03 15:13:24 -04001376 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001377 return false;
1378 }
1379
1380 return ValidateGetQueryivBase(context, target, pname);
1381}
1382
1383bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1384{
1385 Query *queryObject = context->getQuery(id, false, GL_NONE);
1386
1387 if (!queryObject)
1388 {
Jamie Madill437fa652016-05-03 15:13:24 -04001389 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001390 return false;
1391 }
1392
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001393 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001394 {
Jamie Madill437fa652016-05-03 15:13:24 -04001395 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001396 return false;
1397 }
1398
1399 switch (pname)
1400 {
1401 case GL_QUERY_RESULT_EXT:
1402 case GL_QUERY_RESULT_AVAILABLE_EXT:
1403 break;
1404
1405 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001406 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001407 return false;
1408 }
1409
1410 return true;
1411}
1412
1413bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1414{
1415 if (!context->getExtensions().disjointTimerQuery)
1416 {
Jamie Madill437fa652016-05-03 15:13:24 -04001417 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001418 return false;
1419 }
1420 return ValidateGetQueryObjectValueBase(context, id, pname);
1421}
1422
1423bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1424{
1425 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001426 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001427 {
Jamie Madill437fa652016-05-03 15:13:24 -04001428 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001429 return false;
1430 }
1431 return ValidateGetQueryObjectValueBase(context, id, pname);
1432}
1433
1434bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1435{
1436 if (!context->getExtensions().disjointTimerQuery)
1437 {
Jamie Madill437fa652016-05-03 15:13:24 -04001438 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001439 return false;
1440 }
1441 return ValidateGetQueryObjectValueBase(context, id, pname);
1442}
1443
1444bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1445{
1446 if (!context->getExtensions().disjointTimerQuery)
1447 {
Jamie Madill437fa652016-05-03 15:13:24 -04001448 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001449 return false;
1450 }
1451 return ValidateGetQueryObjectValueBase(context, id, pname);
1452}
1453
Jamie Madill62d31cb2015-09-11 13:25:51 -04001454static bool ValidateUniformCommonBase(gl::Context *context,
1455 GLenum targetUniformType,
1456 GLint location,
1457 GLsizei count,
1458 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001459{
1460 if (count < 0)
1461 {
Jamie Madill437fa652016-05-03 15:13:24 -04001462 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001463 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001464 }
1465
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001466 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001467 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001468 {
Jamie Madill437fa652016-05-03 15:13:24 -04001469 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001470 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001471 }
1472
Geoff Langd8605522016-04-13 10:19:12 -04001473 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001474 {
1475 // Silently ignore the uniform command
1476 return false;
1477 }
1478
Geoff Lang7dd2e102014-11-10 15:19:26 -05001479 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001480 {
Jamie Madill437fa652016-05-03 15:13:24 -04001481 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001482 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001483 }
1484
Jamie Madill62d31cb2015-09-11 13:25:51 -04001485 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001486
1487 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001488 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001489 {
Jamie Madill437fa652016-05-03 15:13:24 -04001490 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001491 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001492 }
1493
Jamie Madill62d31cb2015-09-11 13:25:51 -04001494 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001495 return true;
1496}
1497
Jamie Madillaa981bd2014-05-20 10:55:55 -04001498bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1499{
1500 // Check for ES3 uniform entry points
Martin Radev1be913c2016-07-11 17:59:16 +03001501 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT &&
1502 context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001503 {
Jamie Madill437fa652016-05-03 15:13:24 -04001504 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001505 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001506 }
1507
Jamie Madill62d31cb2015-09-11 13:25:51 -04001508 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001509 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1510 {
1511 return false;
1512 }
1513
Jamie Madillf2575982014-06-25 16:04:54 -04001514 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001515 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001516 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1517 {
Jamie Madill437fa652016-05-03 15:13:24 -04001518 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001519 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001520 }
1521
1522 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001523}
1524
1525bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1526 GLboolean transpose)
1527{
1528 // Check for ES3 uniform entry points
1529 int rows = VariableRowCount(matrixType);
1530 int cols = VariableColumnCount(matrixType);
Martin Radev1be913c2016-07-11 17:59:16 +03001531 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001532 {
Jamie Madill437fa652016-05-03 15:13:24 -04001533 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001534 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001535 }
1536
Martin Radev1be913c2016-07-11 17:59:16 +03001537 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001538 {
Jamie Madill437fa652016-05-03 15:13:24 -04001539 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001540 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001541 }
1542
Jamie Madill62d31cb2015-09-11 13:25:51 -04001543 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001544 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1545 {
1546 return false;
1547 }
1548
1549 if (uniform->type != matrixType)
1550 {
Jamie Madill437fa652016-05-03 15:13:24 -04001551 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001552 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001553 }
1554
1555 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001556}
1557
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001558bool ValidateStateQuery(ValidationContext *context,
1559 GLenum pname,
1560 GLenum *nativeType,
1561 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001562{
1563 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1564 {
Jamie Madill437fa652016-05-03 15:13:24 -04001565 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001566 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001567 }
1568
Jamie Madill0af26e12015-03-05 19:54:33 -05001569 const Caps &caps = context->getCaps();
1570
Jamie Madill893ab082014-05-16 16:56:10 -04001571 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1572 {
1573 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1574
Jamie Madill0af26e12015-03-05 19:54:33 -05001575 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001576 {
Jamie Madill437fa652016-05-03 15:13:24 -04001577 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001578 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001579 }
1580 }
1581
1582 switch (pname)
1583 {
1584 case GL_TEXTURE_BINDING_2D:
1585 case GL_TEXTURE_BINDING_CUBE_MAP:
1586 case GL_TEXTURE_BINDING_3D:
1587 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001588 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001589 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1590 if (!context->getExtensions().eglStreamConsumerExternal)
1591 {
Jamie Madill437fa652016-05-03 15:13:24 -04001592 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001593 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1594 return false;
1595 }
1596 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001597
1598 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1599 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1600 {
Jamie Madill51f40ec2016-06-15 14:06:00 -04001601 if (context->getGLState().getReadFramebuffer()->checkStatus(
1602 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001603 {
Jamie Madill437fa652016-05-03 15:13:24 -04001604 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001605 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001606 }
1607
Jamie Madill51f40ec2016-06-15 14:06:00 -04001608 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1609 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001610
1611 if (framebuffer->getReadBufferState() == GL_NONE)
1612 {
1613 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1614 return false;
1615 }
1616
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001617 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001618 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001619 {
Jamie Madill437fa652016-05-03 15:13:24 -04001620 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001621 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001622 }
1623 }
1624 break;
1625
1626 default:
1627 break;
1628 }
1629
1630 // pname is valid, but there are no parameters to return
1631 if (numParams == 0)
1632 {
1633 return false;
1634 }
1635
1636 return true;
1637}
1638
Jamie Madillc29968b2016-01-20 11:17:23 -05001639bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1640 GLenum target,
1641 GLint level,
1642 GLenum internalformat,
1643 bool isSubImage,
1644 GLint xoffset,
1645 GLint yoffset,
1646 GLint zoffset,
1647 GLint x,
1648 GLint y,
1649 GLsizei width,
1650 GLsizei height,
1651 GLint border,
1652 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001653{
Jamie Madill560a8d82014-05-21 13:06:20 -04001654 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1655 {
Jamie Madill437fa652016-05-03 15:13:24 -04001656 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001657 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001658 }
1659
1660 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1661 {
Jamie Madill437fa652016-05-03 15:13:24 -04001662 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001663 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001664 }
1665
1666 if (border != 0)
1667 {
Jamie Madill437fa652016-05-03 15:13:24 -04001668 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001669 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001670 }
1671
1672 if (!ValidMipLevel(context, target, level))
1673 {
Jamie Madill437fa652016-05-03 15:13:24 -04001674 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001675 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001676 }
1677
Jamie Madill51f40ec2016-06-15 14:06:00 -04001678 const auto &state = context->getGLState();
1679 auto readFramebuffer = state.getReadFramebuffer();
1680 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001681 {
Jamie Madill437fa652016-05-03 15:13:24 -04001682 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001683 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001684 }
1685
Jamie Madill51f40ec2016-06-15 14:06:00 -04001686 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001687 {
Jamie Madill437fa652016-05-03 15:13:24 -04001688 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001689 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001690 }
1691
Martin Radev138064f2016-07-15 12:03:41 +03001692 if (readFramebuffer->getReadBufferState() == GL_NONE)
1693 {
1694 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1695 return false;
1696 }
1697
Geoff Langaae65a42014-05-26 12:43:44 -04001698 const gl::Caps &caps = context->getCaps();
1699
Geoff Langaae65a42014-05-26 12:43:44 -04001700 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001701 switch (target)
1702 {
1703 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001704 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001705 break;
1706
1707 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1708 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1709 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1710 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1711 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1712 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001713 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001714 break;
1715
1716 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001717 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001718 break;
1719
1720 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001721 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001722 break;
1723
1724 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001725 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001726 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001727 }
1728
Jamie Madillc29968b2016-01-20 11:17:23 -05001729 gl::Texture *texture =
1730 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001731 if (!texture)
1732 {
Jamie Madill437fa652016-05-03 15:13:24 -04001733 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001734 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001735 }
1736
Geoff Lang69cce582015-09-17 13:20:36 -04001737 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001738 {
Jamie Madill437fa652016-05-03 15:13:24 -04001739 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001740 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001741 }
1742
Geoff Lang5d601382014-07-22 15:14:06 -04001743 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1744
1745 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001746 {
Jamie Madill437fa652016-05-03 15:13:24 -04001747 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001748 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001749 }
1750
Geoff Langa9be0dc2014-12-17 12:34:40 -05001751 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001752 {
Jamie Madill437fa652016-05-03 15:13:24 -04001753 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001754 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001755 }
1756
1757 if (isSubImage)
1758 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001759 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1760 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1761 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001762 {
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 Madill560a8d82014-05-21 13:06:20 -04001765 }
1766 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001767 else
1768 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001769 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001770 {
Jamie Madill437fa652016-05-03 15:13:24 -04001771 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001772 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001773 }
1774
Martin Radev1be913c2016-07-11 17:59:16 +03001775 if (!formatInfo.textureSupport(context->getClientMajorVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001776 {
Jamie Madill437fa652016-05-03 15:13:24 -04001777 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001778 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001779 }
1780
1781 int maxLevelDimension = (maxDimension >> level);
1782 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1783 {
Jamie Madill437fa652016-05-03 15:13:24 -04001784 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001785 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001786 }
1787 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001788
Jamie Madilla3944d42016-07-22 22:13:26 -04001789 *textureFormatOut = texture->getFormat(target, level).asSized();
Jamie Madill560a8d82014-05-21 13:06:20 -04001790 return true;
1791}
1792
Jamie Madillf25855c2015-11-03 11:06:18 -05001793static bool ValidateDrawBase(ValidationContext *context,
1794 GLenum mode,
1795 GLsizei count,
1796 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001797{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001798 switch (mode)
1799 {
1800 case GL_POINTS:
1801 case GL_LINES:
1802 case GL_LINE_LOOP:
1803 case GL_LINE_STRIP:
1804 case GL_TRIANGLES:
1805 case GL_TRIANGLE_STRIP:
1806 case GL_TRIANGLE_FAN:
1807 break;
1808 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001809 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001810 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001811 }
1812
Jamie Madill250d33f2014-06-06 17:09:03 -04001813 if (count < 0)
1814 {
Jamie Madill437fa652016-05-03 15:13:24 -04001815 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001816 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001817 }
1818
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001819 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001820
Jamie Madill250d33f2014-06-06 17:09:03 -04001821 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001822 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001823 {
Jamie Madill437fa652016-05-03 15:13:24 -04001824 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001825 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001826 }
1827
Jamie Madill51f40ec2016-06-15 14:06:00 -04001828 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001829 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001830 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001831 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1832 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1833 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1834 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1835 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1836 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001837 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001838 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1839 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001840 {
1841 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1842 // Section 6.10 of the WebGL 1.0 spec
1843 ERR(
1844 "This ANGLE implementation does not support separate front/back stencil "
1845 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001846 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001847 return false;
1848 }
Jamie Madillac528012014-06-20 13:21:23 -04001849 }
1850
Jamie Madill51f40ec2016-06-15 14:06:00 -04001851 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001852 {
Jamie Madill437fa652016-05-03 15:13:24 -04001853 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001854 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001855 }
1856
Geoff Lang7dd2e102014-11-10 15:19:26 -05001857 gl::Program *program = state.getProgram();
1858 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001859 {
Jamie Madill437fa652016-05-03 15:13:24 -04001860 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001861 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001862 }
1863
Geoff Lang7dd2e102014-11-10 15:19:26 -05001864 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001865 {
Jamie Madill437fa652016-05-03 15:13:24 -04001866 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001867 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001868 }
1869
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001870 // Uniform buffer validation
1871 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1872 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001873 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001874 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001875 const OffsetBindingPointer<Buffer> &uniformBuffer =
1876 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001877
Geoff Lang5d124a62015-09-15 13:03:27 -04001878 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001879 {
1880 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001881 context->handleError(
1882 Error(GL_INVALID_OPERATION,
1883 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001884 return false;
1885 }
1886
Geoff Lang5d124a62015-09-15 13:03:27 -04001887 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001888 if (uniformBufferSize == 0)
1889 {
1890 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001891 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001892 }
1893
Jamie Madill62d31cb2015-09-11 13:25:51 -04001894 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001895 {
1896 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001897 context->handleError(
1898 Error(GL_INVALID_OPERATION,
1899 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001900 return false;
1901 }
1902 }
1903
Jamie Madill250d33f2014-06-06 17:09:03 -04001904 // No-op if zero count
1905 return (count > 0);
1906}
1907
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001908bool ValidateDrawArrays(ValidationContext *context,
1909 GLenum mode,
1910 GLint first,
1911 GLsizei count,
1912 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001913{
Jamie Madillfd716582014-06-06 17:09:04 -04001914 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001915 {
Jamie Madill437fa652016-05-03 15:13:24 -04001916 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001917 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001918 }
1919
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001920 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001921 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001922 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1923 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001924 {
1925 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1926 // that does not match the current transform feedback object's draw mode (if transform feedback
1927 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001928 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001929 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001930 }
1931
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001932 if (!ValidateDrawBase(context, mode, count, primcount))
1933 {
1934 return false;
1935 }
1936
1937 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001938 {
1939 return false;
1940 }
1941
1942 return true;
1943}
1944
Geoff Langb1196682014-07-23 13:47:29 -04001945bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001946{
1947 if (primcount < 0)
1948 {
Jamie Madill437fa652016-05-03 15:13:24 -04001949 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001950 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001951 }
1952
Jamie Madill2b976812014-08-25 15:47:49 -04001953 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001954 {
1955 return false;
1956 }
1957
1958 // No-op if zero primitive count
1959 return (primcount > 0);
1960}
1961
Geoff Lang87a93302014-09-16 13:29:43 -04001962static bool ValidateDrawInstancedANGLE(Context *context)
1963{
1964 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001965 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04001966
Geoff Lang7dd2e102014-11-10 15:19:26 -05001967 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001968
1969 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001970 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001971 {
1972 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001973 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001974 {
1975 return true;
1976 }
1977 }
1978
Jamie Madill437fa652016-05-03 15:13:24 -04001979 context->handleError(Error(GL_INVALID_OPERATION,
1980 "ANGLE_instanced_arrays requires that at least one active attribute"
1981 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001982 return false;
1983}
1984
1985bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1986{
1987 if (!ValidateDrawInstancedANGLE(context))
1988 {
1989 return false;
1990 }
1991
1992 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1993}
1994
Jamie Madillf25855c2015-11-03 11:06:18 -05001995bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001996 GLenum mode,
1997 GLsizei count,
1998 GLenum type,
1999 const GLvoid *indices,
2000 GLsizei primcount,
2001 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002002{
Jamie Madill250d33f2014-06-06 17:09:03 -04002003 switch (type)
2004 {
2005 case GL_UNSIGNED_BYTE:
2006 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03002007 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002008 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03002009 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2010 {
2011 context->handleError(Error(GL_INVALID_ENUM));
2012 return false;
2013 }
2014 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002015 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002016 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03002017 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002018 }
2019
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002020 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002021
2022 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002023 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002024 {
2025 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2026 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002027 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002028 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002029 }
2030
2031 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002032 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002033 {
Jamie Madill437fa652016-05-03 15:13:24 -04002034 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002035 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002036 }
2037
Jamie Madill2b976812014-08-25 15:47:49 -04002038 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002039 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002040 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002041 {
Jamie Madill437fa652016-05-03 15:13:24 -04002042 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002043 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002044 }
2045
Jamie Madillae3000b2014-08-25 15:47:51 -04002046 if (elementArrayBuffer)
2047 {
2048 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2049
2050 GLint64 offset = reinterpret_cast<GLint64>(indices);
2051 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2052
2053 // check for integer overflows
2054 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2055 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2056 {
Jamie Madill437fa652016-05-03 15:13:24 -04002057 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002058 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002059 }
2060
2061 // Check for reading past the end of the bound buffer object
2062 if (byteCount > elementArrayBuffer->getSize())
2063 {
Jamie Madill437fa652016-05-03 15:13:24 -04002064 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002065 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002066 }
2067 }
2068 else if (!indices)
2069 {
2070 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002071 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002072 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002073 }
2074
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002075 if (!ValidateDrawBase(context, mode, count, primcount))
2076 {
2077 return false;
2078 }
2079
Jamie Madill2b976812014-08-25 15:47:49 -04002080 // Use max index to validate if our vertex buffers are large enough for the pull.
2081 // TODO: offer fast path, with disabled index validation.
2082 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2083 if (elementArrayBuffer)
2084 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002085 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002086 Error error =
2087 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2088 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002089 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002090 {
Jamie Madill437fa652016-05-03 15:13:24 -04002091 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002092 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002093 }
2094 }
2095 else
2096 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002097 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002098 }
2099
Jamie Madille79b1e12015-11-04 16:36:37 -05002100 // If we use an index greater than our maximum supported index range, return an error.
2101 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2102 // return an error if possible here.
2103 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2104 {
Jamie Madill437fa652016-05-03 15:13:24 -04002105 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002106 return false;
2107 }
2108
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002109 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002110 {
2111 return false;
2112 }
2113
Geoff Lang3edfe032015-09-04 16:38:24 -04002114 // No op if there are no real indices in the index data (all are primitive restart).
2115 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002116}
2117
Geoff Langb1196682014-07-23 13:47:29 -04002118bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002119 GLenum mode,
2120 GLsizei count,
2121 GLenum type,
2122 const GLvoid *indices,
2123 GLsizei primcount,
2124 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002125{
2126 if (primcount < 0)
2127 {
Jamie Madill437fa652016-05-03 15:13:24 -04002128 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002129 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002130 }
2131
Jamie Madill2b976812014-08-25 15:47:49 -04002132 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002133 {
2134 return false;
2135 }
2136
2137 // No-op zero primitive count
2138 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002139}
2140
Geoff Lang3edfe032015-09-04 16:38:24 -04002141bool ValidateDrawElementsInstancedANGLE(Context *context,
2142 GLenum mode,
2143 GLsizei count,
2144 GLenum type,
2145 const GLvoid *indices,
2146 GLsizei primcount,
2147 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002148{
2149 if (!ValidateDrawInstancedANGLE(context))
2150 {
2151 return false;
2152 }
2153
2154 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2155}
2156
Geoff Langb1196682014-07-23 13:47:29 -04002157bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002158 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002159{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002160 if (!ValidFramebufferTarget(target))
2161 {
Jamie Madill437fa652016-05-03 15:13:24 -04002162 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002163 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002164 }
2165
2166 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002167 {
2168 return false;
2169 }
2170
Jamie Madill55ec3b12014-07-03 10:38:57 -04002171 if (texture != 0)
2172 {
2173 gl::Texture *tex = context->getTexture(texture);
2174
2175 if (tex == NULL)
2176 {
Jamie Madill437fa652016-05-03 15:13:24 -04002177 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002178 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002179 }
2180
2181 if (level < 0)
2182 {
Jamie Madill437fa652016-05-03 15:13:24 -04002183 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002184 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002185 }
2186 }
2187
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002188 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002189 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002190
Jamie Madill84115c92015-04-23 15:00:07 -04002191 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002192 {
Jamie Madill437fa652016-05-03 15:13:24 -04002193 context->handleError(
2194 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002195 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002196 }
2197
2198 return true;
2199}
2200
Geoff Langb1196682014-07-23 13:47:29 -04002201bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002202 GLenum textarget, GLuint texture, GLint level)
2203{
Geoff Lang95663912015-04-02 15:54:45 -04002204 // 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 +03002205 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2206 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002207 {
Jamie Madill437fa652016-05-03 15:13:24 -04002208 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002209 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002210 }
2211
2212 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002213 {
2214 return false;
2215 }
2216
Jamie Madill55ec3b12014-07-03 10:38:57 -04002217 if (texture != 0)
2218 {
2219 gl::Texture *tex = context->getTexture(texture);
2220 ASSERT(tex);
2221
Jamie Madill2a6564e2014-07-11 09:53:19 -04002222 const gl::Caps &caps = context->getCaps();
2223
Jamie Madill55ec3b12014-07-03 10:38:57 -04002224 switch (textarget)
2225 {
2226 case GL_TEXTURE_2D:
2227 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002228 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002229 {
Jamie Madill437fa652016-05-03 15:13:24 -04002230 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002231 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002232 }
2233 if (tex->getTarget() != GL_TEXTURE_2D)
2234 {
Jamie Madill437fa652016-05-03 15:13:24 -04002235 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002236 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002237 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002238 }
2239 break;
2240
2241 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2242 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2243 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2244 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2245 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2246 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2247 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002248 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002249 {
Jamie Madill437fa652016-05-03 15:13:24 -04002250 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002251 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002252 }
2253 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2254 {
Jamie Madill437fa652016-05-03 15:13:24 -04002255 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002256 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002257 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002258 }
2259 break;
2260
2261 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002262 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002263 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002264 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002265
Jamie Madilla3944d42016-07-22 22:13:26 -04002266 const Format &format = tex->getFormat(textarget, level);
2267 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05002268 {
Jamie Madill437fa652016-05-03 15:13:24 -04002269 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002270 return false;
2271 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002272 }
2273
Jamie Madill570f7c82014-07-03 10:38:54 -04002274 return true;
2275}
2276
Geoff Langb1196682014-07-23 13:47:29 -04002277bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002278{
2279 if (program == 0)
2280 {
Jamie Madill437fa652016-05-03 15:13:24 -04002281 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002282 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002283 }
2284
Dian Xiang769769a2015-09-09 15:20:08 -07002285 gl::Program *programObject = GetValidProgram(context, program);
2286 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002287 {
2288 return false;
2289 }
2290
Jamie Madill0063c512014-08-25 15:47:53 -04002291 if (!programObject || !programObject->isLinked())
2292 {
Jamie Madill437fa652016-05-03 15:13:24 -04002293 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002294 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002295 }
2296
Geoff Lang7dd2e102014-11-10 15:19:26 -05002297 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002298 {
Jamie Madill437fa652016-05-03 15:13:24 -04002299 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002300 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002301 }
2302
Jamie Madill0063c512014-08-25 15:47:53 -04002303 return true;
2304}
2305
Geoff Langb1196682014-07-23 13:47:29 -04002306bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002307{
2308 return ValidateGetUniformBase(context, program, location);
2309}
2310
Geoff Langb1196682014-07-23 13:47:29 -04002311bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002312{
Jamie Madill78f41802014-08-25 15:47:55 -04002313 return ValidateGetUniformBase(context, program, location);
2314}
2315
Geoff Langb1196682014-07-23 13:47:29 -04002316static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002317{
2318 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002319 {
Jamie Madill78f41802014-08-25 15:47:55 -04002320 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002321 }
2322
Jamie Madilla502c742014-08-28 17:19:13 -04002323 gl::Program *programObject = context->getProgram(program);
2324 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002325
Jamie Madill78f41802014-08-25 15:47:55 -04002326 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002327 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2328 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002329 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002330 {
Jamie Madill437fa652016-05-03 15:13:24 -04002331 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002332 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002333 }
2334
2335 return true;
2336}
2337
Geoff Langb1196682014-07-23 13:47:29 -04002338bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002339{
Jamie Madill78f41802014-08-25 15:47:55 -04002340 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002341}
2342
Geoff Langb1196682014-07-23 13:47:29 -04002343bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002344{
Jamie Madill78f41802014-08-25 15:47:55 -04002345 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002346}
2347
Austin Kinross08332632015-05-05 13:35:47 -07002348bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2349 const GLenum *attachments, bool defaultFramebuffer)
2350{
2351 if (numAttachments < 0)
2352 {
Jamie Madill437fa652016-05-03 15:13:24 -04002353 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002354 return false;
2355 }
2356
2357 for (GLsizei i = 0; i < numAttachments; ++i)
2358 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002359 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002360 {
2361 if (defaultFramebuffer)
2362 {
Jamie Madill437fa652016-05-03 15:13:24 -04002363 context->handleError(Error(
2364 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002365 return false;
2366 }
2367
2368 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2369 {
Jamie Madill437fa652016-05-03 15:13:24 -04002370 context->handleError(Error(GL_INVALID_OPERATION,
2371 "Requested color attachment is greater than the maximum "
2372 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002373 return false;
2374 }
2375 }
2376 else
2377 {
2378 switch (attachments[i])
2379 {
2380 case GL_DEPTH_ATTACHMENT:
2381 case GL_STENCIL_ATTACHMENT:
2382 case GL_DEPTH_STENCIL_ATTACHMENT:
2383 if (defaultFramebuffer)
2384 {
Jamie Madill437fa652016-05-03 15:13:24 -04002385 context->handleError(
2386 Error(GL_INVALID_ENUM,
2387 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002388 return false;
2389 }
2390 break;
2391 case GL_COLOR:
2392 case GL_DEPTH:
2393 case GL_STENCIL:
2394 if (!defaultFramebuffer)
2395 {
Jamie Madill437fa652016-05-03 15:13:24 -04002396 context->handleError(
2397 Error(GL_INVALID_ENUM,
2398 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002399 return false;
2400 }
2401 break;
2402 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002403 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002404 return false;
2405 }
2406 }
2407 }
2408
2409 return true;
2410}
2411
Austin Kinross6ee1e782015-05-29 17:05:37 -07002412bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2413{
2414 // Note that debug marker calls must not set error state
2415
2416 if (length < 0)
2417 {
2418 return false;
2419 }
2420
2421 if (marker == nullptr)
2422 {
2423 return false;
2424 }
2425
2426 return true;
2427}
2428
2429bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2430{
2431 // Note that debug marker calls must not set error state
2432
2433 if (length < 0)
2434 {
2435 return false;
2436 }
2437
2438 if (length > 0 && marker == nullptr)
2439 {
2440 return false;
2441 }
2442
2443 return true;
2444}
2445
Geoff Langdcab33b2015-07-21 13:03:16 -04002446bool ValidateEGLImageTargetTexture2DOES(Context *context,
2447 egl::Display *display,
2448 GLenum target,
2449 egl::Image *image)
2450{
Geoff Langa8406172015-07-21 16:53:39 -04002451 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2452 {
Jamie Madill437fa652016-05-03 15:13:24 -04002453 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002454 return false;
2455 }
2456
2457 switch (target)
2458 {
2459 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002460 if (!context->getExtensions().eglImage)
2461 {
2462 context->handleError(Error(
2463 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2464 }
2465 break;
2466
2467 case GL_TEXTURE_EXTERNAL_OES:
2468 if (!context->getExtensions().eglImageExternal)
2469 {
2470 context->handleError(Error(
2471 GL_INVALID_ENUM,
2472 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2473 }
Geoff Langa8406172015-07-21 16:53:39 -04002474 break;
2475
2476 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002477 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002478 return false;
2479 }
2480
2481 if (!display->isValidImage(image))
2482 {
Jamie Madill437fa652016-05-03 15:13:24 -04002483 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002484 return false;
2485 }
2486
2487 if (image->getSamples() > 0)
2488 {
Jamie Madill437fa652016-05-03 15:13:24 -04002489 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002490 "cannot create a 2D texture from a multisampled EGL image."));
2491 return false;
2492 }
2493
Jamie Madilla3944d42016-07-22 22:13:26 -04002494 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002495 if (!textureCaps.texturable)
2496 {
Jamie Madill437fa652016-05-03 15:13:24 -04002497 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002498 "EGL image internal format is not supported as a texture."));
2499 return false;
2500 }
2501
Geoff Langdcab33b2015-07-21 13:03:16 -04002502 return true;
2503}
2504
2505bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2506 egl::Display *display,
2507 GLenum target,
2508 egl::Image *image)
2509{
Geoff Langa8406172015-07-21 16:53:39 -04002510 if (!context->getExtensions().eglImage)
2511 {
Jamie Madill437fa652016-05-03 15:13:24 -04002512 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002513 return false;
2514 }
2515
2516 switch (target)
2517 {
2518 case GL_RENDERBUFFER:
2519 break;
2520
2521 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002522 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002523 return false;
2524 }
2525
2526 if (!display->isValidImage(image))
2527 {
Jamie Madill437fa652016-05-03 15:13:24 -04002528 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002529 return false;
2530 }
2531
Jamie Madilla3944d42016-07-22 22:13:26 -04002532 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002533 if (!textureCaps.renderable)
2534 {
Jamie Madill437fa652016-05-03 15:13:24 -04002535 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002536 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2537 return false;
2538 }
2539
Geoff Langdcab33b2015-07-21 13:03:16 -04002540 return true;
2541}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002542
2543bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2544{
Geoff Lang36167ab2015-12-07 10:27:14 -05002545 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002546 {
2547 // The default VAO should always exist
2548 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002549 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002550 return false;
2551 }
2552
2553 return true;
2554}
2555
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002556bool ValidateLinkProgram(Context *context, GLuint program)
2557{
2558 if (context->hasActiveTransformFeedback(program))
2559 {
2560 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002561 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002562 "Cannot link program while program is associated with an active "
2563 "transform feedback object."));
2564 return false;
2565 }
2566 return true;
2567}
2568
Geoff Langc5629752015-12-07 16:29:04 -05002569bool ValidateProgramBinaryBase(Context *context,
2570 GLuint program,
2571 GLenum binaryFormat,
2572 const void *binary,
2573 GLint length)
2574{
2575 Program *programObject = GetValidProgram(context, program);
2576 if (programObject == nullptr)
2577 {
2578 return false;
2579 }
2580
2581 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2582 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2583 programBinaryFormats.end())
2584 {
Jamie Madill437fa652016-05-03 15:13:24 -04002585 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002586 return false;
2587 }
2588
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002589 if (context->hasActiveTransformFeedback(program))
2590 {
2591 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002592 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002593 "Cannot change program binary while program is associated with "
2594 "an active transform feedback object."));
2595 return false;
2596 }
2597
Geoff Langc5629752015-12-07 16:29:04 -05002598 return true;
2599}
2600
2601bool ValidateGetProgramBinaryBase(Context *context,
2602 GLuint program,
2603 GLsizei bufSize,
2604 GLsizei *length,
2605 GLenum *binaryFormat,
2606 void *binary)
2607{
2608 Program *programObject = GetValidProgram(context, program);
2609 if (programObject == nullptr)
2610 {
2611 return false;
2612 }
2613
2614 if (!programObject->isLinked())
2615 {
Jamie Madill437fa652016-05-03 15:13:24 -04002616 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002617 return false;
2618 }
2619
2620 return true;
2621}
Jamie Madillc29968b2016-01-20 11:17:23 -05002622
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002623bool ValidateUseProgram(Context *context, GLuint program)
2624{
2625 if (program != 0)
2626 {
2627 Program *programObject = context->getProgram(program);
2628 if (!programObject)
2629 {
2630 // ES 3.1.0 section 7.3 page 72
2631 if (context->getShader(program))
2632 {
Jamie Madill437fa652016-05-03 15:13:24 -04002633 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002634 Error(GL_INVALID_OPERATION,
2635 "Attempted to use a single shader instead of a shader program."));
2636 return false;
2637 }
2638 else
2639 {
Jamie Madill437fa652016-05-03 15:13:24 -04002640 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002641 return false;
2642 }
2643 }
2644 if (!programObject->isLinked())
2645 {
Jamie Madill437fa652016-05-03 15:13:24 -04002646 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002647 return false;
2648 }
2649 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002650 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002651 {
2652 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002653 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002654 Error(GL_INVALID_OPERATION,
2655 "Cannot change active program while transform feedback is unpaused."));
2656 return false;
2657 }
2658
2659 return true;
2660}
2661
Jamie Madillc29968b2016-01-20 11:17:23 -05002662bool ValidateCopyTexImage2D(ValidationContext *context,
2663 GLenum target,
2664 GLint level,
2665 GLenum internalformat,
2666 GLint x,
2667 GLint y,
2668 GLsizei width,
2669 GLsizei height,
2670 GLint border)
2671{
Martin Radev1be913c2016-07-11 17:59:16 +03002672 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002673 {
2674 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2675 0, x, y, width, height, border);
2676 }
2677
Martin Radev1be913c2016-07-11 17:59:16 +03002678 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002679 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2680 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002681}
Jamie Madillc29968b2016-01-20 11:17:23 -05002682
2683bool ValidateFramebufferRenderbuffer(Context *context,
2684 GLenum target,
2685 GLenum attachment,
2686 GLenum renderbuffertarget,
2687 GLuint renderbuffer)
2688{
2689 if (!ValidFramebufferTarget(target) ||
2690 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2691 {
Jamie Madill437fa652016-05-03 15:13:24 -04002692 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002693 return false;
2694 }
2695
2696 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2697 renderbuffertarget, renderbuffer);
2698}
2699
2700bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2701{
2702 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2703 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2704 {
Jamie Madill437fa652016-05-03 15:13:24 -04002705 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002706 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2707 return false;
2708 }
2709
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002710 ASSERT(context->getGLState().getDrawFramebuffer());
2711 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002712 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2713
2714 // This should come first before the check for the default frame buffer
2715 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2716 // rather than INVALID_OPERATION
2717 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2718 {
2719 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2720
2721 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002722 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2723 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002724 {
2725 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002726 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2727 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2728 // 3.1 is still a bit ambiguous about the error, but future specs are
2729 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002730 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002731 return false;
2732 }
2733 else if (bufs[colorAttachment] >= maxColorAttachment)
2734 {
Jamie Madill437fa652016-05-03 15:13:24 -04002735 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002736 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002737 return false;
2738 }
2739 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2740 frameBufferId != 0)
2741 {
2742 // INVALID_OPERATION-GL is bound to buffer and ith argument
2743 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002744 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002745 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2746 return false;
2747 }
2748 }
2749
2750 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2751 // and n is not 1 or bufs is bound to value other than BACK and NONE
2752 if (frameBufferId == 0)
2753 {
2754 if (n != 1)
2755 {
Jamie Madill437fa652016-05-03 15:13:24 -04002756 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002757 "n must be 1 when GL is bound to the default framebuffer"));
2758 return false;
2759 }
2760
2761 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2762 {
Jamie Madill437fa652016-05-03 15:13:24 -04002763 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002764 GL_INVALID_OPERATION,
2765 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2766 return false;
2767 }
2768 }
2769
2770 return true;
2771}
2772
2773bool ValidateCopyTexSubImage2D(Context *context,
2774 GLenum target,
2775 GLint level,
2776 GLint xoffset,
2777 GLint yoffset,
2778 GLint x,
2779 GLint y,
2780 GLsizei width,
2781 GLsizei height)
2782{
Martin Radev1be913c2016-07-11 17:59:16 +03002783 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002784 {
2785 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2786 yoffset, x, y, width, height, 0);
2787 }
2788
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002789 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2790 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002791}
2792
Olli Etuaho4f667482016-03-30 15:56:35 +03002793bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2794{
2795 if (!ValidBufferTarget(context, target))
2796 {
Jamie Madill437fa652016-05-03 15:13:24 -04002797 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002798 return false;
2799 }
2800
2801 if (pname != GL_BUFFER_MAP_POINTER)
2802 {
Jamie Madill437fa652016-05-03 15:13:24 -04002803 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002804 return false;
2805 }
2806
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002807 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002808
2809 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2810 // target bound to zero generate an INVALID_OPERATION error."
2811 // GLES 3.1 section 6.6 explicitly specifies this error.
2812 if (!buffer)
2813 {
Jamie Madill437fa652016-05-03 15:13:24 -04002814 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002815 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2816 return false;
2817 }
2818
2819 return true;
2820}
2821
2822bool ValidateUnmapBufferBase(Context *context, GLenum target)
2823{
2824 if (!ValidBufferTarget(context, target))
2825 {
Jamie Madill437fa652016-05-03 15:13:24 -04002826 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002827 return false;
2828 }
2829
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002830 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002831
2832 if (buffer == nullptr || !buffer->isMapped())
2833 {
Jamie Madill437fa652016-05-03 15:13:24 -04002834 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002835 return false;
2836 }
2837
2838 return true;
2839}
2840
2841bool ValidateMapBufferRangeBase(Context *context,
2842 GLenum target,
2843 GLintptr offset,
2844 GLsizeiptr length,
2845 GLbitfield access)
2846{
2847 if (!ValidBufferTarget(context, target))
2848 {
Jamie Madill437fa652016-05-03 15:13:24 -04002849 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002850 return false;
2851 }
2852
2853 if (offset < 0 || length < 0)
2854 {
Jamie Madill437fa652016-05-03 15:13:24 -04002855 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002856 return false;
2857 }
2858
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002859 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002860
2861 if (!buffer)
2862 {
Jamie Madill437fa652016-05-03 15:13:24 -04002863 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002864 return false;
2865 }
2866
2867 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002868 CheckedNumeric<size_t> checkedOffset(offset);
2869 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002870
Jamie Madille2e406c2016-06-02 13:04:10 -04002871 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002872 {
Jamie Madill437fa652016-05-03 15:13:24 -04002873 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002874 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2875 return false;
2876 }
2877
2878 // Check for invalid bits in the mask
2879 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2880 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2881 GL_MAP_UNSYNCHRONIZED_BIT;
2882
2883 if (access & ~(allAccessBits))
2884 {
Jamie Madill437fa652016-05-03 15:13:24 -04002885 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002886 return false;
2887 }
2888
2889 if (length == 0)
2890 {
Jamie Madill437fa652016-05-03 15:13:24 -04002891 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002892 return false;
2893 }
2894
2895 if (buffer->isMapped())
2896 {
Jamie Madill437fa652016-05-03 15:13:24 -04002897 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002898 return false;
2899 }
2900
2901 // Check for invalid bit combinations
2902 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2903 {
Jamie Madill437fa652016-05-03 15:13:24 -04002904 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002905 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2906 return false;
2907 }
2908
2909 GLbitfield writeOnlyBits =
2910 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2911
2912 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2913 {
Jamie Madill437fa652016-05-03 15:13:24 -04002914 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002915 "Invalid access bits when mapping buffer for reading: 0x%X.",
2916 access));
2917 return false;
2918 }
2919
2920 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2921 {
Jamie Madill437fa652016-05-03 15:13:24 -04002922 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002923 GL_INVALID_OPERATION,
2924 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2925 return false;
2926 }
2927 return true;
2928}
2929
2930bool ValidateFlushMappedBufferRangeBase(Context *context,
2931 GLenum target,
2932 GLintptr offset,
2933 GLsizeiptr length)
2934{
2935 if (offset < 0 || length < 0)
2936 {
Jamie Madill437fa652016-05-03 15:13:24 -04002937 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002938 return false;
2939 }
2940
2941 if (!ValidBufferTarget(context, target))
2942 {
Jamie Madill437fa652016-05-03 15:13:24 -04002943 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002944 return false;
2945 }
2946
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002947 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002948
2949 if (buffer == nullptr)
2950 {
Jamie Madill437fa652016-05-03 15:13:24 -04002951 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002952 return false;
2953 }
2954
2955 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2956 {
Jamie Madill437fa652016-05-03 15:13:24 -04002957 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002958 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2959 return false;
2960 }
2961
2962 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002963 CheckedNumeric<size_t> checkedOffset(offset);
2964 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002965
Jamie Madille2e406c2016-06-02 13:04:10 -04002966 if (!checkedSize.IsValid() ||
2967 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002968 {
Jamie Madill437fa652016-05-03 15:13:24 -04002969 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002970 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2971 return false;
2972 }
2973
2974 return true;
2975}
2976
Olli Etuaho0f2b1562016-05-13 16:15:35 +03002977bool ValidateGenerateMipmap(Context *context, GLenum target)
2978{
2979 if (!ValidTextureTarget(context, target))
2980 {
2981 context->handleError(Error(GL_INVALID_ENUM));
2982 return false;
2983 }
2984
2985 Texture *texture = context->getTargetTexture(target);
2986
2987 if (texture == nullptr)
2988 {
2989 context->handleError(Error(GL_INVALID_OPERATION));
2990 return false;
2991 }
2992
2993 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
2994
2995 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
2996 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
2997 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2998 {
2999 context->handleError(Error(GL_INVALID_OPERATION));
3000 return false;
3001 }
3002
Jamie Madilla3944d42016-07-22 22:13:26 -04003003 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
3004 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
3005 const TextureCaps &formatCaps = context->getTextureCaps().get(format.asSized());
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003006
3007 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
3008 // unsized formats or that are color renderable and filterable. Since we do not track if
3009 // the texture was created with sized or unsized format (only sized formats are stored),
3010 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
3011 // be able to) because they aren't color renderable. Simply do a special case for LUMA
3012 // textures since they're the only texture format that can be created with unsized formats
3013 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
3014 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04003015 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
3016 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003017 {
3018 context->handleError(Error(GL_INVALID_OPERATION));
3019 return false;
3020 }
3021
3022 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04003023 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003024 {
3025 context->handleError(Error(GL_INVALID_OPERATION));
3026 return false;
3027 }
3028
3029 // Non-power of 2 ES2 check
3030 if (!context->getExtensions().textureNPOT &&
3031 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3032 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3033 {
Martin Radev1be913c2016-07-11 17:59:16 +03003034 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003035 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3036 context->handleError(Error(GL_INVALID_OPERATION));
3037 return false;
3038 }
3039
3040 // Cube completeness check
3041 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3042 {
3043 context->handleError(Error(GL_INVALID_OPERATION));
3044 return false;
3045 }
3046
3047 return true;
3048}
3049
Olli Etuaho41997e72016-03-10 13:38:39 +02003050bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3051{
3052 return ValidateGenOrDelete(context, n);
3053}
3054
3055bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3056{
3057 return ValidateGenOrDelete(context, n);
3058}
3059
3060bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3061{
3062 return ValidateGenOrDelete(context, n);
3063}
3064
3065bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3066{
3067 return ValidateGenOrDelete(context, n);
3068}
3069
3070bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3071{
3072 return ValidateGenOrDelete(context, n);
3073}
3074
3075bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3076{
3077 return ValidateGenOrDelete(context, n);
3078}
3079
3080bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3081{
3082 return ValidateGenOrDelete(context, n);
3083}
3084
3085bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3086{
3087 return ValidateGenOrDelete(context, n);
3088}
3089
3090bool ValidateGenOrDelete(Context *context, GLint n)
3091{
3092 if (n < 0)
3093 {
Jamie Madill437fa652016-05-03 15:13:24 -04003094 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003095 return false;
3096 }
3097 return true;
3098}
3099
Jamie Madillc29968b2016-01-20 11:17:23 -05003100} // namespace gl