blob: 339624c96132f145fb06542393cb5f1d65aa49b0 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
Jamie Madille2e406c2016-06-02 13:04:10 -040010
Geoff Lang2b5420c2014-11-19 14:20:15 -050011#include "libANGLE/validationES2.h"
12#include "libANGLE/validationES3.h"
13#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040014#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050015#include "libANGLE/Texture.h"
16#include "libANGLE/Framebuffer.h"
17#include "libANGLE/FramebufferAttachment.h"
18#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040019#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050021#include "libANGLE/Program.h"
22#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050023#include "libANGLE/TransformFeedback.h"
24#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040025
26#include "common/mathutil.h"
27#include "common/utilities.h"
28
Jamie Madille2e406c2016-06-02 13:04:10 -040029using namespace angle;
30
Geoff Lange8ebe7f2013-08-05 15:03:13 -040031namespace gl
32{
Jamie Madille79b1e12015-11-04 16:36:37 -050033const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
34
Jamie Madill1ca74672015-07-21 15:14:11 -040035namespace
36{
Jamie Madillf25855c2015-11-03 11:06:18 -050037bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040038{
Jamie Madilldfde6ab2016-06-09 07:07:18 -070039 const gl::State &state = context->getGLState();
Jamie Madill1ca74672015-07-21 15:14:11 -040040 const gl::Program *program = state.getProgram();
41
42 const VertexArray *vao = state.getVertexArray();
43 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040044 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
45 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
46 {
47 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040048 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040049 {
50 gl::Buffer *buffer = attrib.buffer.get();
51
52 if (buffer)
53 {
54 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
55 GLint64 maxVertexElement = 0;
56
57 if (attrib.divisor > 0)
58 {
59 maxVertexElement =
60 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
61 }
62 else
63 {
64 maxVertexElement = static_cast<GLint64>(maxVertex);
65 }
66
67 // If we're drawing zero vertices, we have enough data.
68 if (maxVertexElement > 0)
69 {
70 // Note: Last vertex element does not take the full stride!
71 GLint64 attribSize =
72 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
73 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040074 GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
Jamie Madill1ca74672015-07-21 15:14:11 -040075
76 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
77 // We can return INVALID_OPERATION if our vertex attribute does not have
78 // enough backing data.
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040079 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040080 {
Jamie Madill437fa652016-05-03 15:13:24 -040081 context->handleError(
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040082 Error(GL_INVALID_OPERATION,
83 "Vertex buffer is not big enough for the draw call"));
Jamie Madill1ca74672015-07-21 15:14:11 -040084 return false;
85 }
86 }
87 }
88 else if (attrib.pointer == NULL)
89 {
90 // This is an application error that would normally result in a crash,
91 // but we catch it and return an error
Jamie Madill437fa652016-05-03 15:13:24 -040092 context->handleError(Error(
Jamie Madill1ca74672015-07-21 15:14:11 -040093 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
94 return false;
95 }
96 }
97 }
98
99 return true;
100}
101
102} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400103
Geoff Lang0550d032014-01-30 11:29:07 -0500104bool ValidCap(const Context *context, GLenum cap)
105{
106 switch (cap)
107 {
Sami Väisänen74c23472016-05-09 17:30:30 +0300108 // EXT_multisample_compatibility
109 case GL_MULTISAMPLE_EXT:
110 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
111 return context->getExtensions().multisampleCompatibility;
112
Geoff Lang0550d032014-01-30 11:29:07 -0500113 case GL_CULL_FACE:
114 case GL_POLYGON_OFFSET_FILL:
115 case GL_SAMPLE_ALPHA_TO_COVERAGE:
116 case GL_SAMPLE_COVERAGE:
117 case GL_SCISSOR_TEST:
118 case GL_STENCIL_TEST:
119 case GL_DEPTH_TEST:
120 case GL_BLEND:
121 case GL_DITHER:
122 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500123
Geoff Lang0550d032014-01-30 11:29:07 -0500124 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
125 case GL_RASTERIZER_DISCARD:
Martin Radev1be913c2016-07-11 17:59:16 +0300126 return (context->getClientMajorVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500127
128 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
129 case GL_DEBUG_OUTPUT:
130 return context->getExtensions().debug;
131
Geoff Lang0550d032014-01-30 11:29:07 -0500132 default:
133 return false;
134 }
135}
136
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500137bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400138{
Jamie Madilld7460c72014-01-21 16:38:14 -0500139 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400140 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500141 case GL_TEXTURE_2D:
142 case GL_TEXTURE_CUBE_MAP:
143 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400144
Jamie Madilld7460c72014-01-21 16:38:14 -0500145 case GL_TEXTURE_3D:
146 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300147 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500148
149 default:
150 return false;
151 }
Jamie Madill35d15012013-10-07 10:46:37 -0400152}
153
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500154bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
155{
156 switch (target)
157 {
158 case GL_TEXTURE_2D:
159 case GL_TEXTURE_CUBE_MAP:
160 return true;
161
162 default:
163 return false;
164 }
165}
166
167bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
168{
169 switch (target)
170 {
171 case GL_TEXTURE_3D:
172 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300173 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500174
175 default:
176 return false;
177 }
178}
179
Ian Ewellbda75592016-04-18 17:25:54 -0400180// Most texture GL calls are not compatible with external textures, so we have a separate validation
181// function for use in the GL calls that do
182bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
183{
184 return (target == GL_TEXTURE_EXTERNAL_OES) &&
185 (context->getExtensions().eglImageExternal ||
186 context->getExtensions().eglStreamConsumerExternal);
187}
188
Shannon Woods4dfed832014-03-17 20:03:39 -0400189// This function differs from ValidTextureTarget in that the target must be
190// usable as the destination of a 2D operation-- so a cube face is valid, but
191// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400192// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500193bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400194{
195 switch (target)
196 {
197 case GL_TEXTURE_2D:
198 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
199 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
200 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
201 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
202 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
203 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
204 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500205 default:
206 return false;
207 }
208}
209
210bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
211{
212 switch (target)
213 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400214 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500215 case GL_TEXTURE_2D_ARRAY:
216 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400217 default:
218 return false;
219 }
220}
221
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500222bool ValidFramebufferTarget(GLenum target)
223{
Geoff Langd4475812015-03-18 10:53:05 -0400224 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
225 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500226
227 switch (target)
228 {
229 case GL_FRAMEBUFFER: return true;
230 case GL_READ_FRAMEBUFFER: return true;
231 case GL_DRAW_FRAMEBUFFER: return true;
232 default: return false;
233 }
234}
235
Jamie Madill29639852016-09-02 15:00:09 -0400236bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -0500237{
238 switch (target)
239 {
240 case GL_ARRAY_BUFFER:
241 case GL_ELEMENT_ARRAY_BUFFER:
242 return true;
243
Jamie Madill8c96d582014-03-05 15:01:23 -0500244 case GL_PIXEL_PACK_BUFFER:
245 case GL_PIXEL_UNPACK_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300246 return (context->getExtensions().pixelBufferObject ||
247 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400248
Shannon Woodsb3801742014-03-27 14:59:19 -0400249 case GL_COPY_READ_BUFFER:
250 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500251 case GL_TRANSFORM_FEEDBACK_BUFFER:
252 case GL_UNIFORM_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300253 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500254
255 default:
256 return false;
257 }
258}
259
Jamie Madill70656a62014-03-05 15:01:26 -0500260bool ValidBufferParameter(const Context *context, GLenum pname)
261{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400262 const Extensions &extensions = context->getExtensions();
263
Jamie Madill70656a62014-03-05 15:01:26 -0500264 switch (pname)
265 {
266 case GL_BUFFER_USAGE:
267 case GL_BUFFER_SIZE:
268 return true;
269
Geoff Langcc6f55d2015-03-20 13:01:02 -0400270 case GL_BUFFER_ACCESS_OES:
271 return extensions.mapBuffer;
272
273 case GL_BUFFER_MAPPED:
274 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
Martin Radev1be913c2016-07-11 17:59:16 +0300275 return (context->getClientMajorVersion() >= 3) || extensions.mapBuffer ||
276 extensions.mapBufferRange;
Geoff Langcc6f55d2015-03-20 13:01:02 -0400277
Jamie Madill70656a62014-03-05 15:01:26 -0500278 // GL_BUFFER_MAP_POINTER is a special case, and may only be
279 // queried with GetBufferPointerv
280 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500281 case GL_BUFFER_MAP_OFFSET:
282 case GL_BUFFER_MAP_LENGTH:
Martin Radev1be913c2016-07-11 17:59:16 +0300283 return (context->getClientMajorVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500284
285 default:
286 return false;
287 }
288}
289
Jamie Madillc29968b2016-01-20 11:17:23 -0500290bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400291{
Jamie Madillc29968b2016-01-20 11:17:23 -0500292 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400293 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400294 switch (target)
295 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500296 case GL_TEXTURE_2D:
297 maxDimension = caps.max2DTextureSize;
298 break;
Geoff Langce635692013-09-24 13:56:32 -0400299 case GL_TEXTURE_CUBE_MAP:
300 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
301 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
302 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
303 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
304 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500305 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
306 maxDimension = caps.maxCubeMapTextureSize;
307 break;
308 case GL_TEXTURE_3D:
309 maxDimension = caps.max3DTextureSize;
310 break;
311 case GL_TEXTURE_2D_ARRAY:
312 maxDimension = caps.max2DTextureSize;
313 break;
Geoff Langce635692013-09-24 13:56:32 -0400314 default: UNREACHABLE();
315 }
316
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700317 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400318}
319
Austin Kinross08528e12015-10-07 16:24:40 -0700320bool ValidImageSizeParameters(const Context *context,
321 GLenum target,
322 GLint level,
323 GLsizei width,
324 GLsizei height,
325 GLsizei depth,
326 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400327{
328 if (level < 0 || width < 0 || height < 0 || depth < 0)
329 {
330 return false;
331 }
332
Austin Kinross08528e12015-10-07 16:24:40 -0700333 // TexSubImage parameters can be NPOT without textureNPOT extension,
334 // as long as the destination texture is POT.
335 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400336 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400337 {
338 return false;
339 }
340
341 if (!ValidMipLevel(context, target, level))
342 {
343 return false;
344 }
345
346 return true;
347}
348
Geoff Lang0d8b7242015-09-09 14:56:53 -0400349bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
350{
351 // List of compressed format that require that the texture size is smaller than or a multiple of
352 // the compressed block size.
353 switch (internalFormat)
354 {
355 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
356 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
357 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
358 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800359 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400360 return true;
361
362 default:
363 return false;
364 }
365}
366
Jamie Madillc29968b2016-01-20 11:17:23 -0500367bool ValidCompressedImageSize(const ValidationContext *context,
368 GLenum internalFormat,
369 GLsizei width,
370 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400371{
Geoff Lang5d601382014-07-22 15:14:06 -0400372 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
373 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400374 {
375 return false;
376 }
377
Geoff Lang0d8b7242015-09-09 14:56:53 -0400378 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400379 {
380 return false;
381 }
382
Geoff Lang0d8b7242015-09-09 14:56:53 -0400383 if (CompressedTextureFormatRequiresExactSize(internalFormat))
384 {
385 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
386 width % formatInfo.compressedBlockWidth != 0) ||
387 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
388 height % formatInfo.compressedBlockHeight != 0))
389 {
390 return false;
391 }
392 }
393
Geoff Langd4f180b2013-09-24 13:57:44 -0400394 return true;
395}
396
Geoff Lang37dde692014-01-31 16:34:54 -0500397bool ValidQueryType(const Context *context, GLenum queryType)
398{
Geoff Langd4475812015-03-18 10:53:05 -0400399 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
400 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500401
402 switch (queryType)
403 {
404 case GL_ANY_SAMPLES_PASSED:
405 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
406 return true;
407 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
Martin Radev1be913c2016-07-11 17:59:16 +0300408 return (context->getClientMajorVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500409 case GL_TIME_ELAPSED_EXT:
410 return context->getExtensions().disjointTimerQuery;
Geoff Lang2b4ce802016-04-28 13:34:50 -0400411 case GL_COMMANDS_COMPLETED_CHROMIUM:
412 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500413 default:
414 return false;
415 }
416}
417
Dian Xiang769769a2015-09-09 15:20:08 -0700418Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500419{
420 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
421 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
422 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
423
Dian Xiang769769a2015-09-09 15:20:08 -0700424 Program *validProgram = context->getProgram(id);
425
426 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500427 {
Dian Xiang769769a2015-09-09 15:20:08 -0700428 if (context->getShader(id))
429 {
Jamie Madill437fa652016-05-03 15:13:24 -0400430 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700431 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
432 }
433 else
434 {
Jamie Madill437fa652016-05-03 15:13:24 -0400435 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700436 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500437 }
Dian Xiang769769a2015-09-09 15:20:08 -0700438
439 return validProgram;
440}
441
442Shader *GetValidShader(Context *context, GLuint id)
443{
444 // See ValidProgram for spec details.
445
446 Shader *validShader = context->getShader(id);
447
448 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500449 {
Dian Xiang769769a2015-09-09 15:20:08 -0700450 if (context->getProgram(id))
451 {
Jamie Madill437fa652016-05-03 15:13:24 -0400452 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700453 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
454 }
455 else
456 {
Jamie Madill437fa652016-05-03 15:13:24 -0400457 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700458 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500459 }
Dian Xiang769769a2015-09-09 15:20:08 -0700460
461 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500462}
463
Geoff Langb1196682014-07-23 13:47:29 -0400464bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400465{
466 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
467 {
468 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
469
Geoff Langaae65a42014-05-26 12:43:44 -0400470 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400471 {
Jamie Madill437fa652016-05-03 15:13:24 -0400472 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400473 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400474 }
475 }
476 else
477 {
478 switch (attachment)
479 {
480 case GL_DEPTH_ATTACHMENT:
481 case GL_STENCIL_ATTACHMENT:
Martin Radev1be913c2016-07-11 17:59:16 +0300482 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400483
484 case GL_DEPTH_STENCIL_ATTACHMENT:
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,
Jamie Madill0c8abca2016-07-22 20:21:26 -04001652 Format *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 Madill0c8abca2016-07-22 20:21:26 -04001789 if (textureFormatOut)
1790 {
1791 *textureFormatOut = texture->getFormat(target, level);
1792 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001793 return true;
1794}
1795
Jamie Madillf25855c2015-11-03 11:06:18 -05001796static bool ValidateDrawBase(ValidationContext *context,
1797 GLenum mode,
1798 GLsizei count,
1799 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001800{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001801 switch (mode)
1802 {
1803 case GL_POINTS:
1804 case GL_LINES:
1805 case GL_LINE_LOOP:
1806 case GL_LINE_STRIP:
1807 case GL_TRIANGLES:
1808 case GL_TRIANGLE_STRIP:
1809 case GL_TRIANGLE_FAN:
1810 break;
1811 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001812 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001813 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001814 }
1815
Jamie Madill250d33f2014-06-06 17:09:03 -04001816 if (count < 0)
1817 {
Jamie Madill437fa652016-05-03 15:13:24 -04001818 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001819 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001820 }
1821
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001822 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001823
Jamie Madill250d33f2014-06-06 17:09:03 -04001824 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001825 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001826 {
Jamie Madill437fa652016-05-03 15:13:24 -04001827 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001828 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001829 }
1830
Jamie Madill51f40ec2016-06-15 14:06:00 -04001831 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001832 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001833 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001834 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1835 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1836 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1837 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1838 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1839 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001840 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001841 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1842 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001843 {
1844 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1845 // Section 6.10 of the WebGL 1.0 spec
1846 ERR(
1847 "This ANGLE implementation does not support separate front/back stencil "
1848 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001849 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001850 return false;
1851 }
Jamie Madillac528012014-06-20 13:21:23 -04001852 }
1853
Jamie Madill51f40ec2016-06-15 14:06:00 -04001854 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001855 {
Jamie Madill437fa652016-05-03 15:13:24 -04001856 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001857 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001858 }
1859
Geoff Lang7dd2e102014-11-10 15:19:26 -05001860 gl::Program *program = state.getProgram();
1861 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001862 {
Jamie Madill437fa652016-05-03 15:13:24 -04001863 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001864 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001865 }
1866
Geoff Lang7dd2e102014-11-10 15:19:26 -05001867 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001868 {
Jamie Madill437fa652016-05-03 15:13:24 -04001869 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001870 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001871 }
1872
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001873 // Uniform buffer validation
1874 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1875 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001876 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001877 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001878 const OffsetBindingPointer<Buffer> &uniformBuffer =
1879 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001880
Geoff Lang5d124a62015-09-15 13:03:27 -04001881 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001882 {
1883 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001884 context->handleError(
1885 Error(GL_INVALID_OPERATION,
1886 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001887 return false;
1888 }
1889
Geoff Lang5d124a62015-09-15 13:03:27 -04001890 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001891 if (uniformBufferSize == 0)
1892 {
1893 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001894 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001895 }
1896
Jamie Madill62d31cb2015-09-11 13:25:51 -04001897 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001898 {
1899 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001900 context->handleError(
1901 Error(GL_INVALID_OPERATION,
1902 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001903 return false;
1904 }
1905 }
1906
Jamie Madill250d33f2014-06-06 17:09:03 -04001907 // No-op if zero count
1908 return (count > 0);
1909}
1910
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001911bool ValidateDrawArrays(ValidationContext *context,
1912 GLenum mode,
1913 GLint first,
1914 GLsizei count,
1915 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001916{
Jamie Madillfd716582014-06-06 17:09:04 -04001917 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001918 {
Jamie Madill437fa652016-05-03 15:13:24 -04001919 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001920 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001921 }
1922
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001923 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001924 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001925 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1926 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001927 {
1928 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1929 // that does not match the current transform feedback object's draw mode (if transform feedback
1930 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001931 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001932 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001933 }
1934
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001935 if (!ValidateDrawBase(context, mode, count, primcount))
1936 {
1937 return false;
1938 }
1939
1940 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001941 {
1942 return false;
1943 }
1944
1945 return true;
1946}
1947
Geoff Langb1196682014-07-23 13:47:29 -04001948bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001949{
1950 if (primcount < 0)
1951 {
Jamie Madill437fa652016-05-03 15:13:24 -04001952 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001953 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001954 }
1955
Jamie Madill2b976812014-08-25 15:47:49 -04001956 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001957 {
1958 return false;
1959 }
1960
1961 // No-op if zero primitive count
1962 return (primcount > 0);
1963}
1964
Geoff Lang87a93302014-09-16 13:29:43 -04001965static bool ValidateDrawInstancedANGLE(Context *context)
1966{
1967 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001968 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04001969
Geoff Lang7dd2e102014-11-10 15:19:26 -05001970 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001971
1972 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001973 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001974 {
1975 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001976 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001977 {
1978 return true;
1979 }
1980 }
1981
Jamie Madill437fa652016-05-03 15:13:24 -04001982 context->handleError(Error(GL_INVALID_OPERATION,
1983 "ANGLE_instanced_arrays requires that at least one active attribute"
1984 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04001985 return false;
1986}
1987
1988bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1989{
1990 if (!ValidateDrawInstancedANGLE(context))
1991 {
1992 return false;
1993 }
1994
1995 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1996}
1997
Jamie Madillf25855c2015-11-03 11:06:18 -05001998bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001999 GLenum mode,
2000 GLsizei count,
2001 GLenum type,
2002 const GLvoid *indices,
2003 GLsizei primcount,
2004 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002005{
Jamie Madill250d33f2014-06-06 17:09:03 -04002006 switch (type)
2007 {
2008 case GL_UNSIGNED_BYTE:
2009 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03002010 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002011 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03002012 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2013 {
2014 context->handleError(Error(GL_INVALID_ENUM));
2015 return false;
2016 }
2017 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002018 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002019 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03002020 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002021 }
2022
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002023 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002024
2025 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002026 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002027 {
2028 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2029 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002030 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002031 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002032 }
2033
2034 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002035 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002036 {
Jamie Madill437fa652016-05-03 15:13:24 -04002037 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002038 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002039 }
2040
Jamie Madill2b976812014-08-25 15:47:49 -04002041 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002042 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002043 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002044 {
Jamie Madill437fa652016-05-03 15:13:24 -04002045 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002046 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002047 }
2048
Jamie Madillae3000b2014-08-25 15:47:51 -04002049 if (elementArrayBuffer)
2050 {
2051 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2052
2053 GLint64 offset = reinterpret_cast<GLint64>(indices);
2054 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2055
2056 // check for integer overflows
2057 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2058 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2059 {
Jamie Madill437fa652016-05-03 15:13:24 -04002060 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002061 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002062 }
2063
2064 // Check for reading past the end of the bound buffer object
2065 if (byteCount > elementArrayBuffer->getSize())
2066 {
Jamie Madill437fa652016-05-03 15:13:24 -04002067 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002068 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002069 }
2070 }
2071 else if (!indices)
2072 {
2073 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002074 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002075 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002076 }
2077
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002078 if (!ValidateDrawBase(context, mode, count, primcount))
2079 {
2080 return false;
2081 }
2082
Jamie Madill2b976812014-08-25 15:47:49 -04002083 // Use max index to validate if our vertex buffers are large enough for the pull.
2084 // TODO: offer fast path, with disabled index validation.
2085 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2086 if (elementArrayBuffer)
2087 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002088 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002089 Error error =
2090 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2091 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002092 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002093 {
Jamie Madill437fa652016-05-03 15:13:24 -04002094 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002095 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002096 }
2097 }
2098 else
2099 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002100 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002101 }
2102
Jamie Madille79b1e12015-11-04 16:36:37 -05002103 // If we use an index greater than our maximum supported index range, return an error.
2104 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2105 // return an error if possible here.
2106 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2107 {
Jamie Madill437fa652016-05-03 15:13:24 -04002108 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002109 return false;
2110 }
2111
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002112 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002113 {
2114 return false;
2115 }
2116
Geoff Lang3edfe032015-09-04 16:38:24 -04002117 // No op if there are no real indices in the index data (all are primitive restart).
2118 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002119}
2120
Geoff Langb1196682014-07-23 13:47:29 -04002121bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002122 GLenum mode,
2123 GLsizei count,
2124 GLenum type,
2125 const GLvoid *indices,
2126 GLsizei primcount,
2127 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002128{
2129 if (primcount < 0)
2130 {
Jamie Madill437fa652016-05-03 15:13:24 -04002131 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002132 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002133 }
2134
Jamie Madill2b976812014-08-25 15:47:49 -04002135 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002136 {
2137 return false;
2138 }
2139
2140 // No-op zero primitive count
2141 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002142}
2143
Geoff Lang3edfe032015-09-04 16:38:24 -04002144bool ValidateDrawElementsInstancedANGLE(Context *context,
2145 GLenum mode,
2146 GLsizei count,
2147 GLenum type,
2148 const GLvoid *indices,
2149 GLsizei primcount,
2150 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002151{
2152 if (!ValidateDrawInstancedANGLE(context))
2153 {
2154 return false;
2155 }
2156
2157 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2158}
2159
Geoff Langb1196682014-07-23 13:47:29 -04002160bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002161 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002162{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002163 if (!ValidFramebufferTarget(target))
2164 {
Jamie Madill437fa652016-05-03 15:13:24 -04002165 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002166 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002167 }
2168
2169 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002170 {
2171 return false;
2172 }
2173
Jamie Madill55ec3b12014-07-03 10:38:57 -04002174 if (texture != 0)
2175 {
2176 gl::Texture *tex = context->getTexture(texture);
2177
2178 if (tex == NULL)
2179 {
Jamie Madill437fa652016-05-03 15:13:24 -04002180 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002181 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002182 }
2183
2184 if (level < 0)
2185 {
Jamie Madill437fa652016-05-03 15:13:24 -04002186 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002187 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002188 }
2189 }
2190
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002191 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002192 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002193
Jamie Madill84115c92015-04-23 15:00:07 -04002194 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002195 {
Jamie Madill437fa652016-05-03 15:13:24 -04002196 context->handleError(
2197 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002198 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002199 }
2200
2201 return true;
2202}
2203
Geoff Langb1196682014-07-23 13:47:29 -04002204bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002205 GLenum textarget, GLuint texture, GLint level)
2206{
Geoff Lang95663912015-04-02 15:54:45 -04002207 // 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 +03002208 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2209 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002210 {
Jamie Madill437fa652016-05-03 15:13:24 -04002211 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002212 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002213 }
2214
2215 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002216 {
2217 return false;
2218 }
2219
Jamie Madill55ec3b12014-07-03 10:38:57 -04002220 if (texture != 0)
2221 {
2222 gl::Texture *tex = context->getTexture(texture);
2223 ASSERT(tex);
2224
Jamie Madill2a6564e2014-07-11 09:53:19 -04002225 const gl::Caps &caps = context->getCaps();
2226
Jamie Madill55ec3b12014-07-03 10:38:57 -04002227 switch (textarget)
2228 {
2229 case GL_TEXTURE_2D:
2230 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002231 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002232 {
Jamie Madill437fa652016-05-03 15:13:24 -04002233 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002234 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002235 }
2236 if (tex->getTarget() != GL_TEXTURE_2D)
2237 {
Jamie Madill437fa652016-05-03 15:13:24 -04002238 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002239 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002240 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002241 }
2242 break;
2243
2244 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2245 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2246 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2247 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2248 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2249 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2250 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002251 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002252 {
Jamie Madill437fa652016-05-03 15:13:24 -04002253 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002254 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002255 }
2256 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2257 {
Jamie Madill437fa652016-05-03 15:13:24 -04002258 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002259 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002260 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002261 }
2262 break;
2263
2264 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002265 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002266 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002267 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002268
Jamie Madilla3944d42016-07-22 22:13:26 -04002269 const Format &format = tex->getFormat(textarget, level);
2270 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05002271 {
Jamie Madill437fa652016-05-03 15:13:24 -04002272 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002273 return false;
2274 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002275 }
2276
Jamie Madill570f7c82014-07-03 10:38:54 -04002277 return true;
2278}
2279
Geoff Langb1196682014-07-23 13:47:29 -04002280bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002281{
2282 if (program == 0)
2283 {
Jamie Madill437fa652016-05-03 15:13:24 -04002284 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002285 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002286 }
2287
Dian Xiang769769a2015-09-09 15:20:08 -07002288 gl::Program *programObject = GetValidProgram(context, program);
2289 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002290 {
2291 return false;
2292 }
2293
Jamie Madill0063c512014-08-25 15:47:53 -04002294 if (!programObject || !programObject->isLinked())
2295 {
Jamie Madill437fa652016-05-03 15:13:24 -04002296 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002297 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002298 }
2299
Geoff Lang7dd2e102014-11-10 15:19:26 -05002300 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002301 {
Jamie Madill437fa652016-05-03 15:13:24 -04002302 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002303 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002304 }
2305
Jamie Madill0063c512014-08-25 15:47:53 -04002306 return true;
2307}
2308
Geoff Langb1196682014-07-23 13:47:29 -04002309bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002310{
2311 return ValidateGetUniformBase(context, program, location);
2312}
2313
Geoff Langb1196682014-07-23 13:47:29 -04002314bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002315{
Jamie Madill78f41802014-08-25 15:47:55 -04002316 return ValidateGetUniformBase(context, program, location);
2317}
2318
Geoff Langb1196682014-07-23 13:47:29 -04002319static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002320{
2321 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002322 {
Jamie Madill78f41802014-08-25 15:47:55 -04002323 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002324 }
2325
Jamie Madilla502c742014-08-28 17:19:13 -04002326 gl::Program *programObject = context->getProgram(program);
2327 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002328
Jamie Madill78f41802014-08-25 15:47:55 -04002329 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002330 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2331 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002332 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002333 {
Jamie Madill437fa652016-05-03 15:13:24 -04002334 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002335 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002336 }
2337
2338 return true;
2339}
2340
Geoff Langb1196682014-07-23 13:47:29 -04002341bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002342{
Jamie Madill78f41802014-08-25 15:47:55 -04002343 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002344}
2345
Geoff Langb1196682014-07-23 13:47:29 -04002346bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002347{
Jamie Madill78f41802014-08-25 15:47:55 -04002348 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002349}
2350
Austin Kinross08332632015-05-05 13:35:47 -07002351bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2352 const GLenum *attachments, bool defaultFramebuffer)
2353{
2354 if (numAttachments < 0)
2355 {
Jamie Madill437fa652016-05-03 15:13:24 -04002356 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002357 return false;
2358 }
2359
2360 for (GLsizei i = 0; i < numAttachments; ++i)
2361 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002362 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002363 {
2364 if (defaultFramebuffer)
2365 {
Jamie Madill437fa652016-05-03 15:13:24 -04002366 context->handleError(Error(
2367 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002368 return false;
2369 }
2370
2371 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2372 {
Jamie Madill437fa652016-05-03 15:13:24 -04002373 context->handleError(Error(GL_INVALID_OPERATION,
2374 "Requested color attachment is greater than the maximum "
2375 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002376 return false;
2377 }
2378 }
2379 else
2380 {
2381 switch (attachments[i])
2382 {
2383 case GL_DEPTH_ATTACHMENT:
2384 case GL_STENCIL_ATTACHMENT:
2385 case GL_DEPTH_STENCIL_ATTACHMENT:
2386 if (defaultFramebuffer)
2387 {
Jamie Madill437fa652016-05-03 15:13:24 -04002388 context->handleError(
2389 Error(GL_INVALID_ENUM,
2390 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002391 return false;
2392 }
2393 break;
2394 case GL_COLOR:
2395 case GL_DEPTH:
2396 case GL_STENCIL:
2397 if (!defaultFramebuffer)
2398 {
Jamie Madill437fa652016-05-03 15:13:24 -04002399 context->handleError(
2400 Error(GL_INVALID_ENUM,
2401 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002402 return false;
2403 }
2404 break;
2405 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002406 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002407 return false;
2408 }
2409 }
2410 }
2411
2412 return true;
2413}
2414
Austin Kinross6ee1e782015-05-29 17:05:37 -07002415bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2416{
2417 // Note that debug marker calls must not set error state
2418
2419 if (length < 0)
2420 {
2421 return false;
2422 }
2423
2424 if (marker == nullptr)
2425 {
2426 return false;
2427 }
2428
2429 return true;
2430}
2431
2432bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2433{
2434 // Note that debug marker calls must not set error state
2435
2436 if (length < 0)
2437 {
2438 return false;
2439 }
2440
2441 if (length > 0 && marker == nullptr)
2442 {
2443 return false;
2444 }
2445
2446 return true;
2447}
2448
Geoff Langdcab33b2015-07-21 13:03:16 -04002449bool ValidateEGLImageTargetTexture2DOES(Context *context,
2450 egl::Display *display,
2451 GLenum target,
2452 egl::Image *image)
2453{
Geoff Langa8406172015-07-21 16:53:39 -04002454 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2455 {
Jamie Madill437fa652016-05-03 15:13:24 -04002456 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002457 return false;
2458 }
2459
2460 switch (target)
2461 {
2462 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002463 if (!context->getExtensions().eglImage)
2464 {
2465 context->handleError(Error(
2466 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2467 }
2468 break;
2469
2470 case GL_TEXTURE_EXTERNAL_OES:
2471 if (!context->getExtensions().eglImageExternal)
2472 {
2473 context->handleError(Error(
2474 GL_INVALID_ENUM,
2475 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2476 }
Geoff Langa8406172015-07-21 16:53:39 -04002477 break;
2478
2479 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002480 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002481 return false;
2482 }
2483
2484 if (!display->isValidImage(image))
2485 {
Jamie Madill437fa652016-05-03 15:13:24 -04002486 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002487 return false;
2488 }
2489
2490 if (image->getSamples() > 0)
2491 {
Jamie Madill437fa652016-05-03 15:13:24 -04002492 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002493 "cannot create a 2D texture from a multisampled EGL image."));
2494 return false;
2495 }
2496
Jamie Madilla3944d42016-07-22 22:13:26 -04002497 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002498 if (!textureCaps.texturable)
2499 {
Jamie Madill437fa652016-05-03 15:13:24 -04002500 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002501 "EGL image internal format is not supported as a texture."));
2502 return false;
2503 }
2504
Geoff Langdcab33b2015-07-21 13:03:16 -04002505 return true;
2506}
2507
2508bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2509 egl::Display *display,
2510 GLenum target,
2511 egl::Image *image)
2512{
Geoff Langa8406172015-07-21 16:53:39 -04002513 if (!context->getExtensions().eglImage)
2514 {
Jamie Madill437fa652016-05-03 15:13:24 -04002515 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002516 return false;
2517 }
2518
2519 switch (target)
2520 {
2521 case GL_RENDERBUFFER:
2522 break;
2523
2524 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002525 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002526 return false;
2527 }
2528
2529 if (!display->isValidImage(image))
2530 {
Jamie Madill437fa652016-05-03 15:13:24 -04002531 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002532 return false;
2533 }
2534
Jamie Madilla3944d42016-07-22 22:13:26 -04002535 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002536 if (!textureCaps.renderable)
2537 {
Jamie Madill437fa652016-05-03 15:13:24 -04002538 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002539 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2540 return false;
2541 }
2542
Geoff Langdcab33b2015-07-21 13:03:16 -04002543 return true;
2544}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002545
2546bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2547{
Geoff Lang36167ab2015-12-07 10:27:14 -05002548 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002549 {
2550 // The default VAO should always exist
2551 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002552 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002553 return false;
2554 }
2555
2556 return true;
2557}
2558
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002559bool ValidateLinkProgram(Context *context, GLuint program)
2560{
2561 if (context->hasActiveTransformFeedback(program))
2562 {
2563 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002564 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002565 "Cannot link program while program is associated with an active "
2566 "transform feedback object."));
2567 return false;
2568 }
2569 return true;
2570}
2571
Geoff Langc5629752015-12-07 16:29:04 -05002572bool ValidateProgramBinaryBase(Context *context,
2573 GLuint program,
2574 GLenum binaryFormat,
2575 const void *binary,
2576 GLint length)
2577{
2578 Program *programObject = GetValidProgram(context, program);
2579 if (programObject == nullptr)
2580 {
2581 return false;
2582 }
2583
2584 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2585 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2586 programBinaryFormats.end())
2587 {
Jamie Madill437fa652016-05-03 15:13:24 -04002588 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002589 return false;
2590 }
2591
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002592 if (context->hasActiveTransformFeedback(program))
2593 {
2594 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002595 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002596 "Cannot change program binary while program is associated with "
2597 "an active transform feedback object."));
2598 return false;
2599 }
2600
Geoff Langc5629752015-12-07 16:29:04 -05002601 return true;
2602}
2603
2604bool ValidateGetProgramBinaryBase(Context *context,
2605 GLuint program,
2606 GLsizei bufSize,
2607 GLsizei *length,
2608 GLenum *binaryFormat,
2609 void *binary)
2610{
2611 Program *programObject = GetValidProgram(context, program);
2612 if (programObject == nullptr)
2613 {
2614 return false;
2615 }
2616
2617 if (!programObject->isLinked())
2618 {
Jamie Madill437fa652016-05-03 15:13:24 -04002619 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002620 return false;
2621 }
2622
2623 return true;
2624}
Jamie Madillc29968b2016-01-20 11:17:23 -05002625
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002626bool ValidateUseProgram(Context *context, GLuint program)
2627{
2628 if (program != 0)
2629 {
2630 Program *programObject = context->getProgram(program);
2631 if (!programObject)
2632 {
2633 // ES 3.1.0 section 7.3 page 72
2634 if (context->getShader(program))
2635 {
Jamie Madill437fa652016-05-03 15:13:24 -04002636 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002637 Error(GL_INVALID_OPERATION,
2638 "Attempted to use a single shader instead of a shader program."));
2639 return false;
2640 }
2641 else
2642 {
Jamie Madill437fa652016-05-03 15:13:24 -04002643 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002644 return false;
2645 }
2646 }
2647 if (!programObject->isLinked())
2648 {
Jamie Madill437fa652016-05-03 15:13:24 -04002649 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002650 return false;
2651 }
2652 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002653 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002654 {
2655 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002656 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002657 Error(GL_INVALID_OPERATION,
2658 "Cannot change active program while transform feedback is unpaused."));
2659 return false;
2660 }
2661
2662 return true;
2663}
2664
Jamie Madillc29968b2016-01-20 11:17:23 -05002665bool ValidateCopyTexImage2D(ValidationContext *context,
2666 GLenum target,
2667 GLint level,
2668 GLenum internalformat,
2669 GLint x,
2670 GLint y,
2671 GLsizei width,
2672 GLsizei height,
2673 GLint border)
2674{
Martin Radev1be913c2016-07-11 17:59:16 +03002675 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002676 {
2677 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2678 0, x, y, width, height, border);
2679 }
2680
Martin Radev1be913c2016-07-11 17:59:16 +03002681 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002682 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2683 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002684}
Jamie Madillc29968b2016-01-20 11:17:23 -05002685
2686bool ValidateFramebufferRenderbuffer(Context *context,
2687 GLenum target,
2688 GLenum attachment,
2689 GLenum renderbuffertarget,
2690 GLuint renderbuffer)
2691{
2692 if (!ValidFramebufferTarget(target) ||
2693 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2694 {
Jamie Madill437fa652016-05-03 15:13:24 -04002695 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002696 return false;
2697 }
2698
2699 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2700 renderbuffertarget, renderbuffer);
2701}
2702
2703bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2704{
2705 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2706 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2707 {
Jamie Madill437fa652016-05-03 15:13:24 -04002708 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002709 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2710 return false;
2711 }
2712
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002713 ASSERT(context->getGLState().getDrawFramebuffer());
2714 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002715 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2716
2717 // This should come first before the check for the default frame buffer
2718 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2719 // rather than INVALID_OPERATION
2720 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2721 {
2722 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2723
2724 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002725 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2726 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002727 {
2728 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002729 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2730 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2731 // 3.1 is still a bit ambiguous about the error, but future specs are
2732 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002733 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002734 return false;
2735 }
2736 else if (bufs[colorAttachment] >= maxColorAttachment)
2737 {
Jamie Madill437fa652016-05-03 15:13:24 -04002738 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002739 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002740 return false;
2741 }
2742 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2743 frameBufferId != 0)
2744 {
2745 // INVALID_OPERATION-GL is bound to buffer and ith argument
2746 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002747 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002748 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2749 return false;
2750 }
2751 }
2752
2753 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2754 // and n is not 1 or bufs is bound to value other than BACK and NONE
2755 if (frameBufferId == 0)
2756 {
2757 if (n != 1)
2758 {
Jamie Madill437fa652016-05-03 15:13:24 -04002759 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002760 "n must be 1 when GL is bound to the default framebuffer"));
2761 return false;
2762 }
2763
2764 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2765 {
Jamie Madill437fa652016-05-03 15:13:24 -04002766 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002767 GL_INVALID_OPERATION,
2768 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2769 return false;
2770 }
2771 }
2772
2773 return true;
2774}
2775
2776bool ValidateCopyTexSubImage2D(Context *context,
2777 GLenum target,
2778 GLint level,
2779 GLint xoffset,
2780 GLint yoffset,
2781 GLint x,
2782 GLint y,
2783 GLsizei width,
2784 GLsizei height)
2785{
Martin Radev1be913c2016-07-11 17:59:16 +03002786 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002787 {
2788 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2789 yoffset, x, y, width, height, 0);
2790 }
2791
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002792 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2793 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002794}
2795
Olli Etuaho4f667482016-03-30 15:56:35 +03002796bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2797{
2798 if (!ValidBufferTarget(context, target))
2799 {
Jamie Madill437fa652016-05-03 15:13:24 -04002800 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002801 return false;
2802 }
2803
2804 if (pname != GL_BUFFER_MAP_POINTER)
2805 {
Jamie Madill437fa652016-05-03 15:13:24 -04002806 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002807 return false;
2808 }
2809
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002810 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002811
2812 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2813 // target bound to zero generate an INVALID_OPERATION error."
2814 // GLES 3.1 section 6.6 explicitly specifies this error.
2815 if (!buffer)
2816 {
Jamie Madill437fa652016-05-03 15:13:24 -04002817 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002818 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2819 return false;
2820 }
2821
2822 return true;
2823}
2824
2825bool ValidateUnmapBufferBase(Context *context, GLenum target)
2826{
2827 if (!ValidBufferTarget(context, target))
2828 {
Jamie Madill437fa652016-05-03 15:13:24 -04002829 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002830 return false;
2831 }
2832
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002833 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002834
2835 if (buffer == nullptr || !buffer->isMapped())
2836 {
Jamie Madill437fa652016-05-03 15:13:24 -04002837 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002838 return false;
2839 }
2840
2841 return true;
2842}
2843
2844bool ValidateMapBufferRangeBase(Context *context,
2845 GLenum target,
2846 GLintptr offset,
2847 GLsizeiptr length,
2848 GLbitfield access)
2849{
2850 if (!ValidBufferTarget(context, target))
2851 {
Jamie Madill437fa652016-05-03 15:13:24 -04002852 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002853 return false;
2854 }
2855
2856 if (offset < 0 || length < 0)
2857 {
Jamie Madill437fa652016-05-03 15:13:24 -04002858 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002859 return false;
2860 }
2861
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002862 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002863
2864 if (!buffer)
2865 {
Jamie Madill437fa652016-05-03 15:13:24 -04002866 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002867 return false;
2868 }
2869
2870 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002871 CheckedNumeric<size_t> checkedOffset(offset);
2872 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002873
Jamie Madille2e406c2016-06-02 13:04:10 -04002874 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002875 {
Jamie Madill437fa652016-05-03 15:13:24 -04002876 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002877 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2878 return false;
2879 }
2880
2881 // Check for invalid bits in the mask
2882 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2883 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2884 GL_MAP_UNSYNCHRONIZED_BIT;
2885
2886 if (access & ~(allAccessBits))
2887 {
Jamie Madill437fa652016-05-03 15:13:24 -04002888 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002889 return false;
2890 }
2891
2892 if (length == 0)
2893 {
Jamie Madill437fa652016-05-03 15:13:24 -04002894 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002895 return false;
2896 }
2897
2898 if (buffer->isMapped())
2899 {
Jamie Madill437fa652016-05-03 15:13:24 -04002900 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002901 return false;
2902 }
2903
2904 // Check for invalid bit combinations
2905 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2906 {
Jamie Madill437fa652016-05-03 15:13:24 -04002907 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002908 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2909 return false;
2910 }
2911
2912 GLbitfield writeOnlyBits =
2913 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2914
2915 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2916 {
Jamie Madill437fa652016-05-03 15:13:24 -04002917 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002918 "Invalid access bits when mapping buffer for reading: 0x%X.",
2919 access));
2920 return false;
2921 }
2922
2923 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2924 {
Jamie Madill437fa652016-05-03 15:13:24 -04002925 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002926 GL_INVALID_OPERATION,
2927 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2928 return false;
2929 }
2930 return true;
2931}
2932
2933bool ValidateFlushMappedBufferRangeBase(Context *context,
2934 GLenum target,
2935 GLintptr offset,
2936 GLsizeiptr length)
2937{
2938 if (offset < 0 || length < 0)
2939 {
Jamie Madill437fa652016-05-03 15:13:24 -04002940 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002941 return false;
2942 }
2943
2944 if (!ValidBufferTarget(context, target))
2945 {
Jamie Madill437fa652016-05-03 15:13:24 -04002946 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002947 return false;
2948 }
2949
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002950 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002951
2952 if (buffer == nullptr)
2953 {
Jamie Madill437fa652016-05-03 15:13:24 -04002954 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002955 return false;
2956 }
2957
2958 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2959 {
Jamie Madill437fa652016-05-03 15:13:24 -04002960 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002961 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2962 return false;
2963 }
2964
2965 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002966 CheckedNumeric<size_t> checkedOffset(offset);
2967 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002968
Jamie Madille2e406c2016-06-02 13:04:10 -04002969 if (!checkedSize.IsValid() ||
2970 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002971 {
Jamie Madill437fa652016-05-03 15:13:24 -04002972 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002973 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2974 return false;
2975 }
2976
2977 return true;
2978}
2979
Olli Etuaho0f2b1562016-05-13 16:15:35 +03002980bool ValidateGenerateMipmap(Context *context, GLenum target)
2981{
2982 if (!ValidTextureTarget(context, target))
2983 {
2984 context->handleError(Error(GL_INVALID_ENUM));
2985 return false;
2986 }
2987
2988 Texture *texture = context->getTargetTexture(target);
2989
2990 if (texture == nullptr)
2991 {
2992 context->handleError(Error(GL_INVALID_OPERATION));
2993 return false;
2994 }
2995
2996 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
2997
2998 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
2999 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
3000 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3001 {
3002 context->handleError(Error(GL_INVALID_OPERATION));
3003 return false;
3004 }
3005
Jamie Madilla3944d42016-07-22 22:13:26 -04003006 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
3007 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
3008 const TextureCaps &formatCaps = context->getTextureCaps().get(format.asSized());
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003009
3010 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
3011 // unsized formats or that are color renderable and filterable. Since we do not track if
3012 // the texture was created with sized or unsized format (only sized formats are stored),
3013 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
3014 // be able to) because they aren't color renderable. Simply do a special case for LUMA
3015 // textures since they're the only texture format that can be created with unsized formats
3016 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
3017 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04003018 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
3019 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003020 {
3021 context->handleError(Error(GL_INVALID_OPERATION));
3022 return false;
3023 }
3024
3025 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04003026 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003027 {
3028 context->handleError(Error(GL_INVALID_OPERATION));
3029 return false;
3030 }
3031
3032 // Non-power of 2 ES2 check
3033 if (!context->getExtensions().textureNPOT &&
3034 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3035 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3036 {
Martin Radev1be913c2016-07-11 17:59:16 +03003037 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003038 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3039 context->handleError(Error(GL_INVALID_OPERATION));
3040 return false;
3041 }
3042
3043 // Cube completeness check
3044 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3045 {
3046 context->handleError(Error(GL_INVALID_OPERATION));
3047 return false;
3048 }
3049
3050 return true;
3051}
3052
Olli Etuaho41997e72016-03-10 13:38:39 +02003053bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3054{
3055 return ValidateGenOrDelete(context, n);
3056}
3057
3058bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3059{
3060 return ValidateGenOrDelete(context, n);
3061}
3062
3063bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3064{
3065 return ValidateGenOrDelete(context, n);
3066}
3067
3068bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3069{
3070 return ValidateGenOrDelete(context, n);
3071}
3072
3073bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3074{
3075 return ValidateGenOrDelete(context, n);
3076}
3077
3078bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3079{
3080 return ValidateGenOrDelete(context, n);
3081}
3082
3083bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3084{
3085 return ValidateGenOrDelete(context, n);
3086}
3087
3088bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3089{
3090 return ValidateGenOrDelete(context, n);
3091}
3092
3093bool ValidateGenOrDelete(Context *context, GLint n)
3094{
3095 if (n < 0)
3096 {
Jamie Madill437fa652016-05-03 15:13:24 -04003097 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003098 return false;
3099 }
3100 return true;
3101}
3102
Jamie Madillc29968b2016-01-20 11:17:23 -05003103} // namespace gl