blob: 3ab4f6bffd33492d7706c2f27d27440c1fb98e1b [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
Geoff Langf607c602016-09-21 11:46:48 -0400102bool ValidReadPixelsFormatType(ValidationContext *context,
103 GLenum framebufferComponentType,
104 GLenum format,
105 GLenum type)
106{
107 switch (framebufferComponentType)
108 {
109 case GL_UNSIGNED_NORMALIZED:
110 // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
111 // ReadPixels with BGRA even if the extension is not present
112 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) ||
113 (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT &&
114 type == GL_UNSIGNED_BYTE);
115
116 case GL_SIGNED_NORMALIZED:
117 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE);
118
119 case GL_INT:
120 return (format == GL_RGBA_INTEGER && type == GL_INT);
121
122 case GL_UNSIGNED_INT:
123 return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
124
125 case GL_FLOAT:
126 return (format == GL_RGBA && type == GL_FLOAT);
127
128 default:
129 UNREACHABLE();
130 return false;
131 }
132}
133
Geoff Langf41a7152016-09-19 15:11:17 -0400134bool ValidCap(const Context *context, GLenum cap, bool queryOnly)
Geoff Lang0550d032014-01-30 11:29:07 -0500135{
136 switch (cap)
137 {
Geoff Langf41a7152016-09-19 15:11:17 -0400138 // EXT_multisample_compatibility
139 case GL_MULTISAMPLE_EXT:
140 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
141 return context->getExtensions().multisampleCompatibility;
Sami Väisänen74c23472016-05-09 17:30:30 +0300142
Geoff Langf41a7152016-09-19 15:11:17 -0400143 case GL_CULL_FACE:
144 case GL_POLYGON_OFFSET_FILL:
145 case GL_SAMPLE_ALPHA_TO_COVERAGE:
146 case GL_SAMPLE_COVERAGE:
147 case GL_SCISSOR_TEST:
148 case GL_STENCIL_TEST:
149 case GL_DEPTH_TEST:
150 case GL_BLEND:
151 case GL_DITHER:
152 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500153
Geoff Langf41a7152016-09-19 15:11:17 -0400154 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
155 case GL_RASTERIZER_DISCARD:
156 return (context->getClientMajorVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500157
Geoff Langf41a7152016-09-19 15:11:17 -0400158 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
159 case GL_DEBUG_OUTPUT:
160 return context->getExtensions().debug;
Geoff Lang70d0f492015-12-10 17:45:46 -0500161
Geoff Langf41a7152016-09-19 15:11:17 -0400162 case GL_BIND_GENERATES_RESOURCE_CHROMIUM:
163 return queryOnly && context->getExtensions().bindGeneratesResource;
164
165 default:
166 return false;
Geoff Lang0550d032014-01-30 11:29:07 -0500167 }
168}
169
Geoff Langf41a7152016-09-19 15:11:17 -0400170} // anonymous namespace
171
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500172bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400173{
Jamie Madilld7460c72014-01-21 16:38:14 -0500174 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400175 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500176 case GL_TEXTURE_2D:
177 case GL_TEXTURE_CUBE_MAP:
178 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400179
Jamie Madilld7460c72014-01-21 16:38:14 -0500180 case GL_TEXTURE_3D:
181 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300182 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500183
184 default:
185 return false;
186 }
Jamie Madill35d15012013-10-07 10:46:37 -0400187}
188
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500189bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
190{
191 switch (target)
192 {
193 case GL_TEXTURE_2D:
194 case GL_TEXTURE_CUBE_MAP:
195 return true;
196
197 default:
198 return false;
199 }
200}
201
202bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
203{
204 switch (target)
205 {
206 case GL_TEXTURE_3D:
207 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300208 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500209
210 default:
211 return false;
212 }
213}
214
Ian Ewellbda75592016-04-18 17:25:54 -0400215// Most texture GL calls are not compatible with external textures, so we have a separate validation
216// function for use in the GL calls that do
217bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
218{
219 return (target == GL_TEXTURE_EXTERNAL_OES) &&
220 (context->getExtensions().eglImageExternal ||
221 context->getExtensions().eglStreamConsumerExternal);
222}
223
Shannon Woods4dfed832014-03-17 20:03:39 -0400224// This function differs from ValidTextureTarget in that the target must be
225// usable as the destination of a 2D operation-- so a cube face is valid, but
226// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400227// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500228bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400229{
230 switch (target)
231 {
232 case GL_TEXTURE_2D:
233 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
234 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
235 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
236 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
237 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
238 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
239 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500240 default:
241 return false;
242 }
243}
244
245bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
246{
247 switch (target)
248 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400249 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500250 case GL_TEXTURE_2D_ARRAY:
251 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400252 default:
253 return false;
254 }
255}
256
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500257bool ValidFramebufferTarget(GLenum target)
258{
Geoff Langd4475812015-03-18 10:53:05 -0400259 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
260 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500261
262 switch (target)
263 {
264 case GL_FRAMEBUFFER: return true;
265 case GL_READ_FRAMEBUFFER: return true;
266 case GL_DRAW_FRAMEBUFFER: return true;
267 default: return false;
268 }
269}
270
Jamie Madill29639852016-09-02 15:00:09 -0400271bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -0500272{
273 switch (target)
274 {
275 case GL_ARRAY_BUFFER:
276 case GL_ELEMENT_ARRAY_BUFFER:
277 return true;
278
Jamie Madill8c96d582014-03-05 15:01:23 -0500279 case GL_PIXEL_PACK_BUFFER:
280 case GL_PIXEL_UNPACK_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300281 return (context->getExtensions().pixelBufferObject ||
282 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400283
Shannon Woodsb3801742014-03-27 14:59:19 -0400284 case GL_COPY_READ_BUFFER:
285 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500286 case GL_TRANSFORM_FEEDBACK_BUFFER:
287 case GL_UNIFORM_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300288 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500289
290 default:
291 return false;
292 }
293}
294
Jamie Madill70656a62014-03-05 15:01:26 -0500295bool ValidBufferParameter(const Context *context, GLenum pname)
296{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400297 const Extensions &extensions = context->getExtensions();
298
Jamie Madill70656a62014-03-05 15:01:26 -0500299 switch (pname)
300 {
301 case GL_BUFFER_USAGE:
302 case GL_BUFFER_SIZE:
303 return true;
304
Geoff Langcc6f55d2015-03-20 13:01:02 -0400305 case GL_BUFFER_ACCESS_OES:
306 return extensions.mapBuffer;
307
308 case GL_BUFFER_MAPPED:
309 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
Martin Radev1be913c2016-07-11 17:59:16 +0300310 return (context->getClientMajorVersion() >= 3) || extensions.mapBuffer ||
311 extensions.mapBufferRange;
Geoff Langcc6f55d2015-03-20 13:01:02 -0400312
Jamie Madill70656a62014-03-05 15:01:26 -0500313 // GL_BUFFER_MAP_POINTER is a special case, and may only be
314 // queried with GetBufferPointerv
315 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500316 case GL_BUFFER_MAP_OFFSET:
317 case GL_BUFFER_MAP_LENGTH:
Martin Radev1be913c2016-07-11 17:59:16 +0300318 return (context->getClientMajorVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500319
320 default:
321 return false;
322 }
323}
324
Jamie Madillc29968b2016-01-20 11:17:23 -0500325bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400326{
Jamie Madillc29968b2016-01-20 11:17:23 -0500327 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400328 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400329 switch (target)
330 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500331 case GL_TEXTURE_2D:
332 maxDimension = caps.max2DTextureSize;
333 break;
Geoff Langce635692013-09-24 13:56:32 -0400334 case GL_TEXTURE_CUBE_MAP:
335 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
336 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
337 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
338 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
339 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500340 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
341 maxDimension = caps.maxCubeMapTextureSize;
342 break;
343 case GL_TEXTURE_3D:
344 maxDimension = caps.max3DTextureSize;
345 break;
346 case GL_TEXTURE_2D_ARRAY:
347 maxDimension = caps.max2DTextureSize;
348 break;
Geoff Langce635692013-09-24 13:56:32 -0400349 default: UNREACHABLE();
350 }
351
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700352 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400353}
354
Austin Kinross08528e12015-10-07 16:24:40 -0700355bool ValidImageSizeParameters(const Context *context,
356 GLenum target,
357 GLint level,
358 GLsizei width,
359 GLsizei height,
360 GLsizei depth,
361 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400362{
363 if (level < 0 || width < 0 || height < 0 || depth < 0)
364 {
365 return false;
366 }
367
Austin Kinross08528e12015-10-07 16:24:40 -0700368 // TexSubImage parameters can be NPOT without textureNPOT extension,
369 // as long as the destination texture is POT.
370 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400371 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400372 {
373 return false;
374 }
375
376 if (!ValidMipLevel(context, target, level))
377 {
378 return false;
379 }
380
381 return true;
382}
383
Geoff Lang0d8b7242015-09-09 14:56:53 -0400384bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
385{
386 // List of compressed format that require that the texture size is smaller than or a multiple of
387 // the compressed block size.
388 switch (internalFormat)
389 {
390 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
391 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
392 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
393 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800394 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400395 return true;
396
397 default:
398 return false;
399 }
400}
401
Jamie Madillc29968b2016-01-20 11:17:23 -0500402bool ValidCompressedImageSize(const ValidationContext *context,
403 GLenum internalFormat,
404 GLsizei width,
405 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400406{
Geoff Lang5d601382014-07-22 15:14:06 -0400407 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
408 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400409 {
410 return false;
411 }
412
Geoff Lang0d8b7242015-09-09 14:56:53 -0400413 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400414 {
415 return false;
416 }
417
Geoff Lang0d8b7242015-09-09 14:56:53 -0400418 if (CompressedTextureFormatRequiresExactSize(internalFormat))
419 {
420 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
421 width % formatInfo.compressedBlockWidth != 0) ||
422 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
423 height % formatInfo.compressedBlockHeight != 0))
424 {
425 return false;
426 }
427 }
428
Geoff Langd4f180b2013-09-24 13:57:44 -0400429 return true;
430}
431
Geoff Lang37dde692014-01-31 16:34:54 -0500432bool ValidQueryType(const Context *context, GLenum queryType)
433{
Geoff Langd4475812015-03-18 10:53:05 -0400434 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
435 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 -0500436
437 switch (queryType)
438 {
439 case GL_ANY_SAMPLES_PASSED:
440 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
441 return true;
442 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
Martin Radev1be913c2016-07-11 17:59:16 +0300443 return (context->getClientMajorVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500444 case GL_TIME_ELAPSED_EXT:
445 return context->getExtensions().disjointTimerQuery;
Geoff Lang2b4ce802016-04-28 13:34:50 -0400446 case GL_COMMANDS_COMPLETED_CHROMIUM:
447 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500448 default:
449 return false;
450 }
451}
452
Dian Xiang769769a2015-09-09 15:20:08 -0700453Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500454{
455 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
456 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
457 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
458
Dian Xiang769769a2015-09-09 15:20:08 -0700459 Program *validProgram = context->getProgram(id);
460
461 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500462 {
Dian Xiang769769a2015-09-09 15:20:08 -0700463 if (context->getShader(id))
464 {
Jamie Madill437fa652016-05-03 15:13:24 -0400465 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700466 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
467 }
468 else
469 {
Jamie Madill437fa652016-05-03 15:13:24 -0400470 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700471 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500472 }
Dian Xiang769769a2015-09-09 15:20:08 -0700473
474 return validProgram;
475}
476
477Shader *GetValidShader(Context *context, GLuint id)
478{
479 // See ValidProgram for spec details.
480
481 Shader *validShader = context->getShader(id);
482
483 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500484 {
Dian Xiang769769a2015-09-09 15:20:08 -0700485 if (context->getProgram(id))
486 {
Jamie Madill437fa652016-05-03 15:13:24 -0400487 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700488 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
489 }
490 else
491 {
Jamie Madill437fa652016-05-03 15:13:24 -0400492 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700493 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500494 }
Dian Xiang769769a2015-09-09 15:20:08 -0700495
496 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500497}
498
Geoff Langb1196682014-07-23 13:47:29 -0400499bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400500{
501 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
502 {
503 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
504
Geoff Langaae65a42014-05-26 12:43:44 -0400505 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400506 {
Jamie Madill437fa652016-05-03 15:13:24 -0400507 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400508 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400509 }
510 }
511 else
512 {
513 switch (attachment)
514 {
515 case GL_DEPTH_ATTACHMENT:
516 case GL_STENCIL_ATTACHMENT:
Martin Radev1be913c2016-07-11 17:59:16 +0300517 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400518
519 case GL_DEPTH_STENCIL_ATTACHMENT:
Geoff Langc287ea62016-09-16 14:46:51 -0400520 if (!context->getExtensions().webglCompatibility &&
521 context->getClientMajorVersion() < 3)
Martin Radev1be913c2016-07-11 17:59:16 +0300522 {
523 context->handleError(Error(GL_INVALID_ENUM));
524 return false;
525 }
526 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400527
528 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400529 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300530 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400531 }
532 }
533
534 return true;
535}
536
Corentin Walleze0902642014-11-04 12:32:15 -0800537bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
538 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400539{
540 switch (target)
541 {
542 case GL_RENDERBUFFER:
543 break;
544 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400545 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400546 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400547 }
548
549 if (width < 0 || height < 0 || samples < 0)
550 {
Jamie Madill437fa652016-05-03 15:13:24 -0400551 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400552 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400553 }
554
Geoff Langd87878e2014-09-19 15:42:59 -0400555 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
556 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400557 {
Jamie Madill437fa652016-05-03 15:13:24 -0400558 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400559 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400560 }
561
562 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
563 // 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 -0800564 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400565 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400566 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 {
Jamie Madill437fa652016-05-03 15:13:24 -0400568 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400569 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400570 }
571
Geoff Langaae65a42014-05-26 12:43:44 -0400572 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400573 {
Jamie Madill437fa652016-05-03 15:13:24 -0400574 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400575 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400576 }
577
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700578 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400579 if (handle == 0)
580 {
Jamie Madill437fa652016-05-03 15:13:24 -0400581 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400582 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400583 }
584
585 return true;
586}
587
Corentin Walleze0902642014-11-04 12:32:15 -0800588bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
589 GLenum internalformat, GLsizei width, GLsizei height)
590{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800591 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800592
593 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400594 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800595 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400596 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800597 {
Jamie Madill437fa652016-05-03 15:13:24 -0400598 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800599 return false;
600 }
601
602 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
603 // the specified storage. This is different than ES 3.0 in which a sample number higher
604 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800605 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
Martin Radev1be913c2016-07-11 17:59:16 +0300606 if (context->getClientMajorVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800607 {
Geoff Langa4903b72015-03-02 16:02:48 -0800608 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
609 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
610 {
Jamie Madill437fa652016-05-03 15:13:24 -0400611 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800612 return false;
613 }
Corentin Walleze0902642014-11-04 12:32:15 -0800614 }
615
616 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
617}
618
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500619bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
620 GLenum renderbuffertarget, GLuint renderbuffer)
621{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400622 if (!ValidFramebufferTarget(target))
623 {
Jamie Madill437fa652016-05-03 15:13:24 -0400624 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400625 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400626 }
627
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700628 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500629
Jamie Madill84115c92015-04-23 15:00:07 -0400630 ASSERT(framebuffer);
631 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500632 {
Jamie Madill437fa652016-05-03 15:13:24 -0400633 context->handleError(
634 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400635 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500636 }
637
Jamie Madillb4472272014-07-03 10:38:55 -0400638 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500639 {
Jamie Madillb4472272014-07-03 10:38:55 -0400640 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500641 }
642
Jamie Madillab9d82c2014-01-21 16:38:14 -0500643 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
644 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
645 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
646 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
647 if (renderbuffer != 0)
648 {
649 if (!context->getRenderbuffer(renderbuffer))
650 {
Jamie Madill437fa652016-05-03 15:13:24 -0400651 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400652 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500653 }
654 }
655
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500656 return true;
657}
658
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700659bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500660 GLint srcX0,
661 GLint srcY0,
662 GLint srcX1,
663 GLint srcY1,
664 GLint dstX0,
665 GLint dstY0,
666 GLint dstX1,
667 GLint dstY1,
668 GLbitfield mask,
669 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670{
671 switch (filter)
672 {
673 case GL_NEAREST:
674 break;
675 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400676 break;
677 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400678 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400679 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400680 }
681
682 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
683 {
Jamie Madill437fa652016-05-03 15:13:24 -0400684 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400685 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400686 }
687
688 if (mask == 0)
689 {
690 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
691 // buffers are copied.
692 return false;
693 }
694
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400695 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
696 // color buffer, leaving only nearest being unfiltered from above
697 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
698 {
Jamie Madill437fa652016-05-03 15:13:24 -0400699 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400700 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400701 }
702
Jamie Madill51f40ec2016-06-15 14:06:00 -0400703 const auto &glState = context->getGLState();
704 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
705 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500706
707 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400708 {
Jamie Madill437fa652016-05-03 15:13:24 -0400709 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400710 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400711 }
712
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700713 if (readFramebuffer->id() == drawFramebuffer->id())
714 {
715 context->handleError(Error(GL_INVALID_OPERATION));
716 return false;
717 }
718
Jamie Madill51f40ec2016-06-15 14:06:00 -0400719 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500720 {
Jamie Madill437fa652016-05-03 15:13:24 -0400721 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500722 return false;
723 }
724
Jamie Madill51f40ec2016-06-15 14:06:00 -0400725 if (drawFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500726 {
Jamie Madill437fa652016-05-03 15:13:24 -0400727 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500728 return false;
729 }
730
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700731 if (drawFramebuffer->getSamples(context->getContextState()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 {
Jamie Madill437fa652016-05-03 15:13:24 -0400733 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400734 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400735 }
736
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400737 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
738
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400739 if (mask & GL_COLOR_BUFFER_BIT)
740 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400741 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
742 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500743 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400744
745 if (readColorBuffer && drawColorBuffer)
746 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400747 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748
Geoff Langa15472a2015-08-11 11:48:03 -0400749 for (size_t drawbufferIdx = 0;
750 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400751 {
Geoff Langa15472a2015-08-11 11:48:03 -0400752 const FramebufferAttachment *attachment =
753 drawFramebuffer->getDrawBuffer(drawbufferIdx);
754 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400755 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400756 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400757
Geoff Langb2f3d052013-08-13 12:49:27 -0400758 // The GL ES 3.0.2 spec (pg 193) states that:
759 // 1) If the read buffer is fixed point format, the draw buffer must be as well
760 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
761 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500762 // Changes with EXT_color_buffer_float:
763 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -0400764 GLenum readComponentType = readFormat.info->componentType;
765 GLenum drawComponentType = drawFormat.info->componentType;
Jamie Madill6163c752015-12-07 16:32:59 -0500766 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
767 readComponentType == GL_SIGNED_NORMALIZED);
768 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
769 drawComponentType == GL_SIGNED_NORMALIZED);
770
771 if (extensions.colorBufferFloat)
772 {
773 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
774 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
775
776 if (readFixedOrFloat != drawFixedOrFloat)
777 {
Jamie Madill437fa652016-05-03 15:13:24 -0400778 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500779 "If the read buffer contains fixed-point or "
780 "floating-point values, the draw buffer "
781 "must as well."));
782 return false;
783 }
784 }
785 else if (readFixedPoint != drawFixedPoint)
786 {
Jamie Madill437fa652016-05-03 15:13:24 -0400787 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500788 "If the read buffer contains fixed-point "
789 "values, the draw buffer must as well."));
790 return false;
791 }
792
793 if (readComponentType == GL_UNSIGNED_INT &&
794 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 {
Jamie Madill437fa652016-05-03 15:13:24 -0400796 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400797 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798 }
799
Jamie Madill6163c752015-12-07 16:32:59 -0500800 if (readComponentType == GL_INT && drawComponentType != GL_INT)
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 }
805
Jamie Madilla3944d42016-07-22 22:13:26 -0400806 if (readColorBuffer->getSamples() > 0 &&
807 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400808 {
Jamie Madill437fa652016-05-03 15:13:24 -0400809 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400810 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400811 }
812 }
813 }
814
Jamie Madilla3944d42016-07-22 22:13:26 -0400815 if ((readFormat.info->componentType == GL_INT ||
816 readFormat.info->componentType == GL_UNSIGNED_INT) &&
817 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400818 {
Jamie Madill437fa652016-05-03 15:13:24 -0400819 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400820 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400821 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400822 }
823 }
824
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200825 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
826 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
827 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400828 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200829 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400830 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400831 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
832 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400833
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200834 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400835 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400836 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400837 {
Jamie Madill437fa652016-05-03 15:13:24 -0400838 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400839 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400840 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400841
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200842 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400843 {
Jamie Madill437fa652016-05-03 15:13:24 -0400844 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400845 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846 }
847 }
848 }
849 }
850
851 return true;
852}
853
Geoff Langb1196682014-07-23 13:47:29 -0400854bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400855{
856 switch (pname)
857 {
858 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
859 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
860 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
861 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
862 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
863 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
864 case GL_CURRENT_VERTEX_ATTRIB:
Martin Radev1be913c2016-07-11 17:59:16 +0300865 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400866
867 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
Martin Radev1be913c2016-07-11 17:59:16 +0300868 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
869 // the same constant.
870 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
871 "ANGLE extension enums not equal to GL enums.");
872 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400873
874 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Martin Radev1be913c2016-07-11 17:59:16 +0300875 if (context->getClientMajorVersion() < 3)
876 {
877 context->handleError(Error(GL_INVALID_ENUM));
878 return false;
879 }
880 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400881
882 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400883 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300884 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400885 }
886}
887
Ian Ewellbda75592016-04-18 17:25:54 -0400888bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400889{
890 switch (pname)
891 {
892 case GL_TEXTURE_WRAP_R:
893 case GL_TEXTURE_SWIZZLE_R:
894 case GL_TEXTURE_SWIZZLE_G:
895 case GL_TEXTURE_SWIZZLE_B:
896 case GL_TEXTURE_SWIZZLE_A:
897 case GL_TEXTURE_BASE_LEVEL:
898 case GL_TEXTURE_MAX_LEVEL:
899 case GL_TEXTURE_COMPARE_MODE:
900 case GL_TEXTURE_COMPARE_FUNC:
901 case GL_TEXTURE_MIN_LOD:
902 case GL_TEXTURE_MAX_LOD:
Martin Radev1be913c2016-07-11 17:59:16 +0300903 if (context->getClientMajorVersion() < 3)
904 {
905 context->handleError(Error(GL_INVALID_ENUM));
906 return false;
907 }
908 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
909 {
910 context->handleError(Error(GL_INVALID_ENUM,
911 "ES3 texture parameters are not available without "
912 "GL_OES_EGL_image_external_essl3."));
913 return false;
914 }
915 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400916
917 default: break;
918 }
919
920 switch (pname)
921 {
922 case GL_TEXTURE_WRAP_S:
923 case GL_TEXTURE_WRAP_T:
924 case GL_TEXTURE_WRAP_R:
925 switch (param)
926 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000927 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400928 return true;
929 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400930 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300931 if (target == GL_TEXTURE_EXTERNAL_OES)
932 {
933 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400934 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300935 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
936 return false;
937 }
938 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 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
944 case GL_TEXTURE_MIN_FILTER:
945 switch (param)
946 {
947 case GL_NEAREST:
948 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400949 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400950 case GL_NEAREST_MIPMAP_NEAREST:
951 case GL_LINEAR_MIPMAP_NEAREST:
952 case GL_NEAREST_MIPMAP_LINEAR:
953 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300954 if (target == GL_TEXTURE_EXTERNAL_OES)
955 {
956 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400957 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300958 Error(GL_INVALID_ENUM,
959 "external textures only support NEAREST and LINEAR filtering"));
960 return false;
961 }
962 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400963 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400964 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400965 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400966 }
967 break;
968
969 case GL_TEXTURE_MAG_FILTER:
970 switch (param)
971 {
972 case GL_NEAREST:
973 case GL_LINEAR:
974 return true;
975 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400976 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400977 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400978 }
979 break;
980
981 case GL_TEXTURE_USAGE_ANGLE:
982 switch (param)
983 {
984 case GL_NONE:
985 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
986 return true;
987 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400988 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400989 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400990 }
991 break;
992
993 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400994 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400995 {
Jamie Madill437fa652016-05-03 15:13:24 -0400996 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400997 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400998 }
999
1000 // we assume the parameter passed to this validation method is truncated, not rounded
1001 if (param < 1)
1002 {
Jamie Madill437fa652016-05-03 15:13:24 -04001003 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001004 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001005 }
1006 return true;
1007
1008 case GL_TEXTURE_MIN_LOD:
1009 case GL_TEXTURE_MAX_LOD:
1010 // any value is permissible
1011 return true;
1012
1013 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -04001014 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001015 switch (param)
1016 {
1017 case GL_NONE:
1018 case GL_COMPARE_REF_TO_TEXTURE:
1019 return true;
1020 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001021 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001022 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001023 }
1024 break;
1025
1026 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -04001027 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001028 switch (param)
1029 {
1030 case GL_LEQUAL:
1031 case GL_GEQUAL:
1032 case GL_LESS:
1033 case GL_GREATER:
1034 case GL_EQUAL:
1035 case GL_NOTEQUAL:
1036 case GL_ALWAYS:
1037 case GL_NEVER:
1038 return true;
1039 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001040 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001041 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001042 }
1043 break;
1044
1045 case GL_TEXTURE_SWIZZLE_R:
1046 case GL_TEXTURE_SWIZZLE_G:
1047 case GL_TEXTURE_SWIZZLE_B:
1048 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001049 switch (param)
1050 {
1051 case GL_RED:
1052 case GL_GREEN:
1053 case GL_BLUE:
1054 case GL_ALPHA:
1055 case GL_ZERO:
1056 case GL_ONE:
1057 return true;
1058 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001059 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001060 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001061 }
1062 break;
1063
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001064 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001065 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001066 {
Geoff Langb66a9092016-05-16 15:59:14 -04001067 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001068 return false;
1069 }
Geoff Langb66a9092016-05-16 15:59:14 -04001070 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1071 {
1072 context->handleError(
1073 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1074 return false;
1075 }
1076 return true;
1077
1078 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001079 if (param < 0)
1080 {
1081 context->handleError(Error(GL_INVALID_VALUE));
1082 return false;
1083 }
1084 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001085 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001086 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001087 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001088 }
1089}
1090
Geoff Langb1196682014-07-23 13:47:29 -04001091bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001092{
1093 switch (pname)
1094 {
1095 case GL_TEXTURE_MIN_FILTER:
1096 case GL_TEXTURE_MAG_FILTER:
1097 case GL_TEXTURE_WRAP_S:
1098 case GL_TEXTURE_WRAP_T:
1099 case GL_TEXTURE_WRAP_R:
1100 case GL_TEXTURE_MIN_LOD:
1101 case GL_TEXTURE_MAX_LOD:
1102 case GL_TEXTURE_COMPARE_MODE:
1103 case GL_TEXTURE_COMPARE_FUNC:
1104 return true;
1105
1106 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001107 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001108 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001109 }
1110}
1111
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001112bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001113 GLint x,
1114 GLint y,
1115 GLsizei width,
1116 GLsizei height,
1117 GLenum format,
1118 GLenum type,
1119 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001120{
Jamie Madillc29968b2016-01-20 11:17:23 -05001121 if (width < 0 || height < 0)
1122 {
Jamie Madill437fa652016-05-03 15:13:24 -04001123 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001124 return false;
1125 }
1126
Jamie Madill51f40ec2016-06-15 14:06:00 -04001127 auto readFramebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill26e91952014-03-05 15:01:27 -05001128
Jamie Madill51f40ec2016-06-15 14:06:00 -04001129 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001130 {
Jamie Madill437fa652016-05-03 15:13:24 -04001131 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001132 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001133 }
1134
Jamie Madill51f40ec2016-06-15 14:06:00 -04001135 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001136 {
Jamie Madill437fa652016-05-03 15:13:24 -04001137 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001138 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001139 }
1140
Jamie Madill51f40ec2016-06-15 14:06:00 -04001141 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1142 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001143
1144 if (framebuffer->getReadBufferState() == GL_NONE)
1145 {
1146 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1147 return false;
1148 }
1149
Geoff Langbce529e2014-12-01 12:48:41 -05001150 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1151 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001152 {
Jamie Madill437fa652016-05-03 15:13:24 -04001153 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001154 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001155 }
1156
Geoff Langbce529e2014-12-01 12:48:41 -05001157 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1158 GLenum currentType = framebuffer->getImplementationColorReadType();
Jamie Madilla3944d42016-07-22 22:13:26 -04001159 GLenum currentInternalFormat = readBuffer->getFormat().asSized();
Jamie Madill26e91952014-03-05 15:01:27 -05001160
Geoff Langf607c602016-09-21 11:46:48 -04001161 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(currentInternalFormat);
1162 bool validFormatTypeCombination =
1163 ValidReadPixelsFormatType(context, internalFormatInfo.componentType, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001164
Geoff Langf607c602016-09-21 11:46:48 -04001165 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
Jamie Madill26e91952014-03-05 15:01:27 -05001166 {
Jamie Madill437fa652016-05-03 15:13:24 -04001167 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001168 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001169 }
1170
Jamie Madillc29968b2016-01-20 11:17:23 -05001171 return true;
1172}
1173
1174bool ValidateReadnPixelsEXT(Context *context,
1175 GLint x,
1176 GLint y,
1177 GLsizei width,
1178 GLsizei height,
1179 GLenum format,
1180 GLenum type,
1181 GLsizei bufSize,
1182 GLvoid *pixels)
1183{
1184 if (bufSize < 0)
1185 {
Jamie Madill437fa652016-05-03 15:13:24 -04001186 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001187 return false;
1188 }
1189
Geoff Lang5d601382014-07-22 15:14:06 -04001190 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1191 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001192
Jamie Madille2e406c2016-06-02 13:04:10 -04001193 auto outputPitchOrErr =
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001194 sizedFormatInfo.computeRowPitch(type, width, context->getGLState().getPackAlignment(),
1195 context->getGLState().getPackRowLength());
Jamie Madille2e406c2016-06-02 13:04:10 -04001196
1197 if (outputPitchOrErr.isError())
1198 {
1199 context->handleError(outputPitchOrErr.getError());
1200 return false;
1201 }
1202
1203 CheckedNumeric<GLuint> checkedOutputPitch(outputPitchOrErr.getResult());
1204 auto checkedRequiredSize = checkedOutputPitch * height;
1205 if (!checkedRequiredSize.IsValid())
1206 {
1207 context->handleError(Error(GL_INVALID_OPERATION, "Unsigned multiplication overflow."));
1208 return false;
1209 }
1210
Jamie Madill26e91952014-03-05 15:01:27 -05001211 // sized query sanity check
Jamie Madille2e406c2016-06-02 13:04:10 -04001212 if (checkedRequiredSize.ValueOrDie() > static_cast<GLuint>(bufSize))
Jamie Madill26e91952014-03-05 15:01:27 -05001213 {
Jamie Madill437fa652016-05-03 15:13:24 -04001214 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001215 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001216 }
1217
Jamie Madillc29968b2016-01-20 11:17:23 -05001218 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001219}
1220
Olli Etuaho41997e72016-03-10 13:38:39 +02001221bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001222{
1223 if (!context->getExtensions().occlusionQueryBoolean &&
1224 !context->getExtensions().disjointTimerQuery)
1225 {
Jamie Madill437fa652016-05-03 15:13:24 -04001226 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001227 return false;
1228 }
1229
Olli Etuaho41997e72016-03-10 13:38:39 +02001230 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001231}
1232
Olli Etuaho41997e72016-03-10 13:38:39 +02001233bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001234{
1235 if (!context->getExtensions().occlusionQueryBoolean &&
1236 !context->getExtensions().disjointTimerQuery)
1237 {
Jamie Madill437fa652016-05-03 15:13:24 -04001238 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001239 return false;
1240 }
1241
Olli Etuaho41997e72016-03-10 13:38:39 +02001242 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001243}
1244
1245bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001246{
1247 if (!ValidQueryType(context, target))
1248 {
Jamie Madill437fa652016-05-03 15:13:24 -04001249 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001250 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001251 }
1252
1253 if (id == 0)
1254 {
Jamie Madill437fa652016-05-03 15:13:24 -04001255 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001256 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001257 }
1258
1259 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1260 // of zero, if the active query object name for <target> is non-zero (for the
1261 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1262 // the active query for either target is non-zero), if <id> is the name of an
1263 // existing query object whose type does not match <target>, or if <id> is the
1264 // active query object name for any query type, the error INVALID_OPERATION is
1265 // generated.
1266
1267 // Ensure no other queries are active
1268 // NOTE: If other queries than occlusion are supported, we will need to check
1269 // separately that:
1270 // a) The query ID passed is not the current active query for any target/type
1271 // b) There are no active queries for the requested target (and in the case
1272 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1273 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001274
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001275 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001276 {
Jamie Madill437fa652016-05-03 15:13:24 -04001277 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001278 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001279 }
1280
1281 Query *queryObject = context->getQuery(id, true, target);
1282
1283 // check that name was obtained with glGenQueries
1284 if (!queryObject)
1285 {
Jamie Madill437fa652016-05-03 15:13:24 -04001286 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001287 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001288 }
1289
1290 // check for type mismatch
1291 if (queryObject->getType() != target)
1292 {
Jamie Madill437fa652016-05-03 15:13:24 -04001293 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001294 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001295 }
1296
1297 return true;
1298}
1299
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001300bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1301{
1302 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001303 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001304 {
Jamie Madill437fa652016-05-03 15:13:24 -04001305 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001306 return false;
1307 }
1308
1309 return ValidateBeginQueryBase(context, target, id);
1310}
1311
1312bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001313{
1314 if (!ValidQueryType(context, target))
1315 {
Jamie Madill437fa652016-05-03 15:13:24 -04001316 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001317 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001318 }
1319
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001320 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001321
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001322 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001323 {
Jamie Madill437fa652016-05-03 15:13:24 -04001324 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001325 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001326 }
1327
Jamie Madill45c785d2014-05-13 14:09:34 -04001328 return true;
1329}
1330
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001331bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1332{
1333 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001334 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001335 {
Jamie Madill437fa652016-05-03 15:13:24 -04001336 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001337 return false;
1338 }
1339
1340 return ValidateEndQueryBase(context, target);
1341}
1342
1343bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1344{
1345 if (!context->getExtensions().disjointTimerQuery)
1346 {
Jamie Madill437fa652016-05-03 15:13:24 -04001347 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001348 return false;
1349 }
1350
1351 if (target != GL_TIMESTAMP_EXT)
1352 {
Jamie Madill437fa652016-05-03 15:13:24 -04001353 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001354 return false;
1355 }
1356
1357 Query *queryObject = context->getQuery(id, true, target);
1358 if (queryObject == nullptr)
1359 {
Jamie Madill437fa652016-05-03 15:13:24 -04001360 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001361 return false;
1362 }
1363
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001364 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001365 {
Jamie Madill437fa652016-05-03 15:13:24 -04001366 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001367 return false;
1368 }
1369
1370 return true;
1371}
1372
1373bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1374{
1375 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1376 {
Jamie Madill437fa652016-05-03 15:13:24 -04001377 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001378 return false;
1379 }
1380
1381 switch (pname)
1382 {
1383 case GL_CURRENT_QUERY_EXT:
1384 if (target == GL_TIMESTAMP_EXT)
1385 {
Jamie Madill437fa652016-05-03 15:13:24 -04001386 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001387 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1388 return false;
1389 }
1390 break;
1391 case GL_QUERY_COUNTER_BITS_EXT:
1392 if (!context->getExtensions().disjointTimerQuery ||
1393 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1394 {
Jamie Madill437fa652016-05-03 15:13:24 -04001395 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001396 return false;
1397 }
1398 break;
1399 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001400 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001401 return false;
1402 }
1403
1404 return true;
1405}
1406
1407bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1408{
1409 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001410 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001411 {
Jamie Madill437fa652016-05-03 15:13:24 -04001412 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001413 return false;
1414 }
1415
1416 return ValidateGetQueryivBase(context, target, pname);
1417}
1418
1419bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1420{
1421 Query *queryObject = context->getQuery(id, false, GL_NONE);
1422
1423 if (!queryObject)
1424 {
Jamie Madill437fa652016-05-03 15:13:24 -04001425 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001426 return false;
1427 }
1428
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001429 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001430 {
Jamie Madill437fa652016-05-03 15:13:24 -04001431 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001432 return false;
1433 }
1434
1435 switch (pname)
1436 {
1437 case GL_QUERY_RESULT_EXT:
1438 case GL_QUERY_RESULT_AVAILABLE_EXT:
1439 break;
1440
1441 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001442 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001443 return false;
1444 }
1445
1446 return true;
1447}
1448
1449bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1450{
1451 if (!context->getExtensions().disjointTimerQuery)
1452 {
Jamie Madill437fa652016-05-03 15:13:24 -04001453 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001454 return false;
1455 }
1456 return ValidateGetQueryObjectValueBase(context, id, pname);
1457}
1458
1459bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1460{
1461 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001462 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001463 {
Jamie Madill437fa652016-05-03 15:13:24 -04001464 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001465 return false;
1466 }
1467 return ValidateGetQueryObjectValueBase(context, id, pname);
1468}
1469
1470bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1471{
1472 if (!context->getExtensions().disjointTimerQuery)
1473 {
Jamie Madill437fa652016-05-03 15:13:24 -04001474 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001475 return false;
1476 }
1477 return ValidateGetQueryObjectValueBase(context, id, pname);
1478}
1479
1480bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1481{
1482 if (!context->getExtensions().disjointTimerQuery)
1483 {
Jamie Madill437fa652016-05-03 15:13:24 -04001484 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001485 return false;
1486 }
1487 return ValidateGetQueryObjectValueBase(context, id, pname);
1488}
1489
Jamie Madill62d31cb2015-09-11 13:25:51 -04001490static bool ValidateUniformCommonBase(gl::Context *context,
1491 GLenum targetUniformType,
1492 GLint location,
1493 GLsizei count,
1494 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001495{
1496 if (count < 0)
1497 {
Jamie Madill437fa652016-05-03 15:13:24 -04001498 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001499 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001500 }
1501
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001502 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001503 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001504 {
Jamie Madill437fa652016-05-03 15:13:24 -04001505 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001506 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001507 }
1508
Geoff Langd8605522016-04-13 10:19:12 -04001509 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001510 {
1511 // Silently ignore the uniform command
1512 return false;
1513 }
1514
Geoff Lang7dd2e102014-11-10 15:19:26 -05001515 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001516 {
Jamie Madill437fa652016-05-03 15:13:24 -04001517 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001518 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001519 }
1520
Jamie Madill62d31cb2015-09-11 13:25:51 -04001521 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001522
1523 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001524 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001525 {
Jamie Madill437fa652016-05-03 15:13:24 -04001526 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001527 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001528 }
1529
Jamie Madill62d31cb2015-09-11 13:25:51 -04001530 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001531 return true;
1532}
1533
Jamie Madillaa981bd2014-05-20 10:55:55 -04001534bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1535{
1536 // Check for ES3 uniform entry points
Martin Radev1be913c2016-07-11 17:59:16 +03001537 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT &&
1538 context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001539 {
Jamie Madill437fa652016-05-03 15:13:24 -04001540 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001541 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001542 }
1543
Jamie Madill62d31cb2015-09-11 13:25:51 -04001544 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001545 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1546 {
1547 return false;
1548 }
1549
Jamie Madillf2575982014-06-25 16:04:54 -04001550 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001551 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001552 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1553 {
Jamie Madill437fa652016-05-03 15:13:24 -04001554 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001555 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001556 }
1557
1558 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001559}
1560
1561bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1562 GLboolean transpose)
1563{
1564 // Check for ES3 uniform entry points
1565 int rows = VariableRowCount(matrixType);
1566 int cols = VariableColumnCount(matrixType);
Martin Radev1be913c2016-07-11 17:59:16 +03001567 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001568 {
Jamie Madill437fa652016-05-03 15:13:24 -04001569 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001570 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001571 }
1572
Martin Radev1be913c2016-07-11 17:59:16 +03001573 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001574 {
Jamie Madill437fa652016-05-03 15:13:24 -04001575 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001576 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001577 }
1578
Jamie Madill62d31cb2015-09-11 13:25:51 -04001579 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001580 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1581 {
1582 return false;
1583 }
1584
1585 if (uniform->type != matrixType)
1586 {
Jamie Madill437fa652016-05-03 15:13:24 -04001587 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001588 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001589 }
1590
1591 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001592}
1593
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001594bool ValidateStateQuery(ValidationContext *context,
1595 GLenum pname,
1596 GLenum *nativeType,
1597 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001598{
1599 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1600 {
Jamie Madill437fa652016-05-03 15:13:24 -04001601 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001602 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001603 }
1604
Jamie Madill0af26e12015-03-05 19:54:33 -05001605 const Caps &caps = context->getCaps();
1606
Jamie Madill893ab082014-05-16 16:56:10 -04001607 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1608 {
1609 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1610
Jamie Madill0af26e12015-03-05 19:54:33 -05001611 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001612 {
Jamie Madill437fa652016-05-03 15:13:24 -04001613 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001614 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001615 }
1616 }
1617
1618 switch (pname)
1619 {
1620 case GL_TEXTURE_BINDING_2D:
1621 case GL_TEXTURE_BINDING_CUBE_MAP:
1622 case GL_TEXTURE_BINDING_3D:
1623 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001624 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001625 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1626 if (!context->getExtensions().eglStreamConsumerExternal)
1627 {
Jamie Madill437fa652016-05-03 15:13:24 -04001628 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001629 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1630 return false;
1631 }
1632 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001633
1634 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1635 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1636 {
Jamie Madill51f40ec2016-06-15 14:06:00 -04001637 if (context->getGLState().getReadFramebuffer()->checkStatus(
1638 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001639 {
Jamie Madill437fa652016-05-03 15:13:24 -04001640 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001641 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001642 }
1643
Jamie Madill51f40ec2016-06-15 14:06:00 -04001644 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1645 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001646
1647 if (framebuffer->getReadBufferState() == GL_NONE)
1648 {
1649 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1650 return false;
1651 }
1652
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001653 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001654 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001655 {
Jamie Madill437fa652016-05-03 15:13:24 -04001656 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001657 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001658 }
1659 }
1660 break;
1661
1662 default:
1663 break;
1664 }
1665
1666 // pname is valid, but there are no parameters to return
1667 if (numParams == 0)
1668 {
1669 return false;
1670 }
1671
1672 return true;
1673}
1674
Jamie Madillc29968b2016-01-20 11:17:23 -05001675bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1676 GLenum target,
1677 GLint level,
1678 GLenum internalformat,
1679 bool isSubImage,
1680 GLint xoffset,
1681 GLint yoffset,
1682 GLint zoffset,
1683 GLint x,
1684 GLint y,
1685 GLsizei width,
1686 GLsizei height,
1687 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04001688 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001689{
Jamie Madill560a8d82014-05-21 13:06:20 -04001690 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1691 {
Jamie Madill437fa652016-05-03 15:13:24 -04001692 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001693 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001694 }
1695
1696 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1697 {
Jamie Madill437fa652016-05-03 15:13:24 -04001698 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001699 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001700 }
1701
1702 if (border != 0)
1703 {
Jamie Madill437fa652016-05-03 15:13:24 -04001704 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001705 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001706 }
1707
1708 if (!ValidMipLevel(context, target, level))
1709 {
Jamie Madill437fa652016-05-03 15:13:24 -04001710 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001711 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001712 }
1713
Jamie Madill51f40ec2016-06-15 14:06:00 -04001714 const auto &state = context->getGLState();
1715 auto readFramebuffer = state.getReadFramebuffer();
1716 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001717 {
Jamie Madill437fa652016-05-03 15:13:24 -04001718 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001719 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001720 }
1721
Jamie Madill51f40ec2016-06-15 14:06:00 -04001722 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001723 {
Jamie Madill437fa652016-05-03 15:13:24 -04001724 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001725 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001726 }
1727
Martin Radev138064f2016-07-15 12:03:41 +03001728 if (readFramebuffer->getReadBufferState() == GL_NONE)
1729 {
1730 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1731 return false;
1732 }
1733
Geoff Langaae65a42014-05-26 12:43:44 -04001734 const gl::Caps &caps = context->getCaps();
1735
Geoff Langaae65a42014-05-26 12:43:44 -04001736 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001737 switch (target)
1738 {
1739 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001740 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001741 break;
1742
1743 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1744 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1745 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1746 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1747 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1748 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001749 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001750 break;
1751
1752 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001753 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001754 break;
1755
1756 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001757 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001758 break;
1759
1760 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001761 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001762 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001763 }
1764
Jamie Madillc29968b2016-01-20 11:17:23 -05001765 gl::Texture *texture =
1766 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001767 if (!texture)
1768 {
Jamie Madill437fa652016-05-03 15:13:24 -04001769 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001770 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001771 }
1772
Geoff Lang69cce582015-09-17 13:20:36 -04001773 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001774 {
Jamie Madill437fa652016-05-03 15:13:24 -04001775 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001776 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001777 }
1778
Geoff Lang5d601382014-07-22 15:14:06 -04001779 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1780
1781 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001782 {
Jamie Madill437fa652016-05-03 15:13:24 -04001783 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001784 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001785 }
1786
Geoff Langa9be0dc2014-12-17 12:34:40 -05001787 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001788 {
Jamie Madill437fa652016-05-03 15:13:24 -04001789 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001790 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001791 }
1792
1793 if (isSubImage)
1794 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001795 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1796 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1797 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001798 {
Jamie Madill437fa652016-05-03 15:13:24 -04001799 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001800 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001801 }
1802 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001803 else
1804 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001805 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001806 {
Jamie Madill437fa652016-05-03 15:13:24 -04001807 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001808 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001809 }
1810
Martin Radev1be913c2016-07-11 17:59:16 +03001811 if (!formatInfo.textureSupport(context->getClientMajorVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001812 {
Jamie Madill437fa652016-05-03 15:13:24 -04001813 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001814 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001815 }
1816
1817 int maxLevelDimension = (maxDimension >> level);
1818 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1819 {
Jamie Madill437fa652016-05-03 15:13:24 -04001820 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001821 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001822 }
1823 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001824
Jamie Madill0c8abca2016-07-22 20:21:26 -04001825 if (textureFormatOut)
1826 {
1827 *textureFormatOut = texture->getFormat(target, level);
1828 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001829 return true;
1830}
1831
Jamie Madillf25855c2015-11-03 11:06:18 -05001832static bool ValidateDrawBase(ValidationContext *context,
1833 GLenum mode,
1834 GLsizei count,
1835 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001836{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001837 switch (mode)
1838 {
1839 case GL_POINTS:
1840 case GL_LINES:
1841 case GL_LINE_LOOP:
1842 case GL_LINE_STRIP:
1843 case GL_TRIANGLES:
1844 case GL_TRIANGLE_STRIP:
1845 case GL_TRIANGLE_FAN:
1846 break;
1847 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001848 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001849 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001850 }
1851
Jamie Madill250d33f2014-06-06 17:09:03 -04001852 if (count < 0)
1853 {
Jamie Madill437fa652016-05-03 15:13:24 -04001854 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001855 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001856 }
1857
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001858 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001859
Jamie Madill250d33f2014-06-06 17:09:03 -04001860 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001861 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -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 Madill250d33f2014-06-06 17:09:03 -04001865 }
1866
Jamie Madill51f40ec2016-06-15 14:06:00 -04001867 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001868 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001869 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001870 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1871 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1872 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1873 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1874 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1875 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001876 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001877 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1878 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001879 {
1880 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1881 // Section 6.10 of the WebGL 1.0 spec
1882 ERR(
1883 "This ANGLE implementation does not support separate front/back stencil "
1884 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001885 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001886 return false;
1887 }
Jamie Madillac528012014-06-20 13:21:23 -04001888 }
1889
Jamie Madill51f40ec2016-06-15 14:06:00 -04001890 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001891 {
Jamie Madill437fa652016-05-03 15:13:24 -04001892 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001893 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001894 }
1895
Geoff Lang7dd2e102014-11-10 15:19:26 -05001896 gl::Program *program = state.getProgram();
1897 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001898 {
Jamie Madill437fa652016-05-03 15:13:24 -04001899 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001900 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001901 }
1902
Geoff Lang7dd2e102014-11-10 15:19:26 -05001903 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001904 {
Jamie Madill437fa652016-05-03 15:13:24 -04001905 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001906 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001907 }
1908
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001909 // Uniform buffer validation
1910 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1911 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001912 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001913 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001914 const OffsetBindingPointer<Buffer> &uniformBuffer =
1915 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001916
Geoff Lang5d124a62015-09-15 13:03:27 -04001917 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001918 {
1919 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001920 context->handleError(
1921 Error(GL_INVALID_OPERATION,
1922 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001923 return false;
1924 }
1925
Geoff Lang5d124a62015-09-15 13:03:27 -04001926 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001927 if (uniformBufferSize == 0)
1928 {
1929 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001930 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001931 }
1932
Jamie Madill62d31cb2015-09-11 13:25:51 -04001933 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001934 {
1935 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001936 context->handleError(
1937 Error(GL_INVALID_OPERATION,
1938 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001939 return false;
1940 }
1941 }
1942
Jamie Madill250d33f2014-06-06 17:09:03 -04001943 // No-op if zero count
1944 return (count > 0);
1945}
1946
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001947bool ValidateDrawArrays(ValidationContext *context,
1948 GLenum mode,
1949 GLint first,
1950 GLsizei count,
1951 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001952{
Jamie Madillfd716582014-06-06 17:09:04 -04001953 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001954 {
Jamie Madill437fa652016-05-03 15:13:24 -04001955 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001956 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001957 }
1958
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001959 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001960 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001961 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1962 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001963 {
1964 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1965 // that does not match the current transform feedback object's draw mode (if transform feedback
1966 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001967 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001968 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001969 }
1970
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001971 if (!ValidateDrawBase(context, mode, count, primcount))
1972 {
1973 return false;
1974 }
1975
1976 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001977 {
1978 return false;
1979 }
1980
1981 return true;
1982}
1983
Geoff Langb1196682014-07-23 13:47:29 -04001984bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001985{
1986 if (primcount < 0)
1987 {
Jamie Madill437fa652016-05-03 15:13:24 -04001988 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001989 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001990 }
1991
Jamie Madill2b976812014-08-25 15:47:49 -04001992 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001993 {
1994 return false;
1995 }
1996
1997 // No-op if zero primitive count
1998 return (primcount > 0);
1999}
2000
Geoff Lang87a93302014-09-16 13:29:43 -04002001static bool ValidateDrawInstancedANGLE(Context *context)
2002{
2003 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002004 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04002005
Geoff Lang7dd2e102014-11-10 15:19:26 -05002006 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04002007
2008 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04002009 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04002010 {
2011 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04002012 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04002013 {
2014 return true;
2015 }
2016 }
2017
Jamie Madill437fa652016-05-03 15:13:24 -04002018 context->handleError(Error(GL_INVALID_OPERATION,
2019 "ANGLE_instanced_arrays requires that at least one active attribute"
2020 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04002021 return false;
2022}
2023
2024bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
2025{
2026 if (!ValidateDrawInstancedANGLE(context))
2027 {
2028 return false;
2029 }
2030
2031 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
2032}
2033
Jamie Madillf25855c2015-11-03 11:06:18 -05002034bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002035 GLenum mode,
2036 GLsizei count,
2037 GLenum type,
2038 const GLvoid *indices,
2039 GLsizei primcount,
2040 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002041{
Jamie Madill250d33f2014-06-06 17:09:03 -04002042 switch (type)
2043 {
2044 case GL_UNSIGNED_BYTE:
2045 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03002046 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002047 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03002048 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2049 {
2050 context->handleError(Error(GL_INVALID_ENUM));
2051 return false;
2052 }
2053 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002054 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002055 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03002056 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002057 }
2058
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002059 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002060
2061 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002062 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002063 {
2064 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2065 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002066 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002067 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002068 }
2069
2070 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002071 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002072 {
Jamie Madill437fa652016-05-03 15:13:24 -04002073 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002074 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002075 }
2076
Jamie Madill2b976812014-08-25 15:47:49 -04002077 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002078 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002079 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002080 {
Jamie Madill437fa652016-05-03 15:13:24 -04002081 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002082 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002083 }
2084
Jamie Madillae3000b2014-08-25 15:47:51 -04002085 if (elementArrayBuffer)
2086 {
2087 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2088
2089 GLint64 offset = reinterpret_cast<GLint64>(indices);
2090 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2091
2092 // check for integer overflows
2093 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2094 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2095 {
Jamie Madill437fa652016-05-03 15:13:24 -04002096 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002097 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002098 }
2099
2100 // Check for reading past the end of the bound buffer object
2101 if (byteCount > elementArrayBuffer->getSize())
2102 {
Jamie Madill437fa652016-05-03 15:13:24 -04002103 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002104 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002105 }
2106 }
2107 else if (!indices)
2108 {
2109 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002110 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002111 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002112 }
2113
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002114 if (!ValidateDrawBase(context, mode, count, primcount))
2115 {
2116 return false;
2117 }
2118
Jamie Madill2b976812014-08-25 15:47:49 -04002119 // Use max index to validate if our vertex buffers are large enough for the pull.
2120 // TODO: offer fast path, with disabled index validation.
2121 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2122 if (elementArrayBuffer)
2123 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002124 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002125 Error error =
2126 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2127 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002128 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002129 {
Jamie Madill437fa652016-05-03 15:13:24 -04002130 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002131 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002132 }
2133 }
2134 else
2135 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002136 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002137 }
2138
Jamie Madille79b1e12015-11-04 16:36:37 -05002139 // If we use an index greater than our maximum supported index range, return an error.
2140 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2141 // return an error if possible here.
2142 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2143 {
Jamie Madill437fa652016-05-03 15:13:24 -04002144 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002145 return false;
2146 }
2147
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002148 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002149 {
2150 return false;
2151 }
2152
Geoff Lang3edfe032015-09-04 16:38:24 -04002153 // No op if there are no real indices in the index data (all are primitive restart).
2154 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002155}
2156
Geoff Langb1196682014-07-23 13:47:29 -04002157bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002158 GLenum mode,
2159 GLsizei count,
2160 GLenum type,
2161 const GLvoid *indices,
2162 GLsizei primcount,
2163 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002164{
2165 if (primcount < 0)
2166 {
Jamie Madill437fa652016-05-03 15:13:24 -04002167 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002168 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002169 }
2170
Jamie Madill2b976812014-08-25 15:47:49 -04002171 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002172 {
2173 return false;
2174 }
2175
2176 // No-op zero primitive count
2177 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002178}
2179
Geoff Lang3edfe032015-09-04 16:38:24 -04002180bool ValidateDrawElementsInstancedANGLE(Context *context,
2181 GLenum mode,
2182 GLsizei count,
2183 GLenum type,
2184 const GLvoid *indices,
2185 GLsizei primcount,
2186 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002187{
2188 if (!ValidateDrawInstancedANGLE(context))
2189 {
2190 return false;
2191 }
2192
2193 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2194}
2195
Geoff Langb1196682014-07-23 13:47:29 -04002196bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002197 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002198{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002199 if (!ValidFramebufferTarget(target))
2200 {
Jamie Madill437fa652016-05-03 15:13:24 -04002201 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002202 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002203 }
2204
2205 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002206 {
2207 return false;
2208 }
2209
Jamie Madill55ec3b12014-07-03 10:38:57 -04002210 if (texture != 0)
2211 {
2212 gl::Texture *tex = context->getTexture(texture);
2213
2214 if (tex == NULL)
2215 {
Jamie Madill437fa652016-05-03 15:13:24 -04002216 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002217 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002218 }
2219
2220 if (level < 0)
2221 {
Jamie Madill437fa652016-05-03 15:13:24 -04002222 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002223 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002224 }
2225 }
2226
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002227 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002228 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002229
Jamie Madill84115c92015-04-23 15:00:07 -04002230 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002231 {
Jamie Madill437fa652016-05-03 15:13:24 -04002232 context->handleError(
2233 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002234 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002235 }
2236
2237 return true;
2238}
2239
Geoff Langb1196682014-07-23 13:47:29 -04002240bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002241 GLenum textarget, GLuint texture, GLint level)
2242{
Geoff Lang95663912015-04-02 15:54:45 -04002243 // 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 +03002244 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2245 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002246 {
Jamie Madill437fa652016-05-03 15:13:24 -04002247 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002248 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002249 }
2250
2251 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002252 {
2253 return false;
2254 }
2255
Jamie Madill55ec3b12014-07-03 10:38:57 -04002256 if (texture != 0)
2257 {
2258 gl::Texture *tex = context->getTexture(texture);
2259 ASSERT(tex);
2260
Jamie Madill2a6564e2014-07-11 09:53:19 -04002261 const gl::Caps &caps = context->getCaps();
2262
Jamie Madill55ec3b12014-07-03 10:38:57 -04002263 switch (textarget)
2264 {
2265 case GL_TEXTURE_2D:
2266 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002267 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002268 {
Jamie Madill437fa652016-05-03 15:13:24 -04002269 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002270 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002271 }
2272 if (tex->getTarget() != GL_TEXTURE_2D)
2273 {
Jamie Madill437fa652016-05-03 15:13:24 -04002274 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002275 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002276 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002277 }
2278 break;
2279
2280 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2281 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2282 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2283 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2284 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2285 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2286 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002287 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002288 {
Jamie Madill437fa652016-05-03 15:13:24 -04002289 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002290 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002291 }
2292 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2293 {
Jamie Madill437fa652016-05-03 15:13:24 -04002294 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002295 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002296 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002297 }
2298 break;
2299
2300 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002301 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002302 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002303 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002304
Jamie Madilla3944d42016-07-22 22:13:26 -04002305 const Format &format = tex->getFormat(textarget, level);
2306 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05002307 {
Jamie Madill437fa652016-05-03 15:13:24 -04002308 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002309 return false;
2310 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002311 }
2312
Jamie Madill570f7c82014-07-03 10:38:54 -04002313 return true;
2314}
2315
Geoff Langb1196682014-07-23 13:47:29 -04002316bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002317{
2318 if (program == 0)
2319 {
Jamie Madill437fa652016-05-03 15:13:24 -04002320 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002321 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002322 }
2323
Dian Xiang769769a2015-09-09 15:20:08 -07002324 gl::Program *programObject = GetValidProgram(context, program);
2325 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002326 {
2327 return false;
2328 }
2329
Jamie Madill0063c512014-08-25 15:47:53 -04002330 if (!programObject || !programObject->isLinked())
2331 {
Jamie Madill437fa652016-05-03 15:13:24 -04002332 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002333 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002334 }
2335
Geoff Lang7dd2e102014-11-10 15:19:26 -05002336 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002337 {
Jamie Madill437fa652016-05-03 15:13:24 -04002338 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002339 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002340 }
2341
Jamie Madill0063c512014-08-25 15:47:53 -04002342 return true;
2343}
2344
Geoff Langb1196682014-07-23 13:47:29 -04002345bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002346{
2347 return ValidateGetUniformBase(context, program, location);
2348}
2349
Geoff Langb1196682014-07-23 13:47:29 -04002350bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002351{
Jamie Madill78f41802014-08-25 15:47:55 -04002352 return ValidateGetUniformBase(context, program, location);
2353}
2354
Geoff Langb1196682014-07-23 13:47:29 -04002355static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002356{
2357 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002358 {
Jamie Madill78f41802014-08-25 15:47:55 -04002359 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002360 }
2361
Jamie Madilla502c742014-08-28 17:19:13 -04002362 gl::Program *programObject = context->getProgram(program);
2363 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002364
Jamie Madill78f41802014-08-25 15:47:55 -04002365 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002366 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2367 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002368 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002369 {
Jamie Madill437fa652016-05-03 15:13:24 -04002370 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002371 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002372 }
2373
2374 return true;
2375}
2376
Geoff Langb1196682014-07-23 13:47:29 -04002377bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002378{
Jamie Madill78f41802014-08-25 15:47:55 -04002379 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002380}
2381
Geoff Langb1196682014-07-23 13:47:29 -04002382bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002383{
Jamie Madill78f41802014-08-25 15:47:55 -04002384 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002385}
2386
Austin Kinross08332632015-05-05 13:35:47 -07002387bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2388 const GLenum *attachments, bool defaultFramebuffer)
2389{
2390 if (numAttachments < 0)
2391 {
Jamie Madill437fa652016-05-03 15:13:24 -04002392 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002393 return false;
2394 }
2395
2396 for (GLsizei i = 0; i < numAttachments; ++i)
2397 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002398 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002399 {
2400 if (defaultFramebuffer)
2401 {
Jamie Madill437fa652016-05-03 15:13:24 -04002402 context->handleError(Error(
2403 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002404 return false;
2405 }
2406
2407 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2408 {
Jamie Madill437fa652016-05-03 15:13:24 -04002409 context->handleError(Error(GL_INVALID_OPERATION,
2410 "Requested color attachment is greater than the maximum "
2411 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002412 return false;
2413 }
2414 }
2415 else
2416 {
2417 switch (attachments[i])
2418 {
2419 case GL_DEPTH_ATTACHMENT:
2420 case GL_STENCIL_ATTACHMENT:
2421 case GL_DEPTH_STENCIL_ATTACHMENT:
2422 if (defaultFramebuffer)
2423 {
Jamie Madill437fa652016-05-03 15:13:24 -04002424 context->handleError(
2425 Error(GL_INVALID_ENUM,
2426 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002427 return false;
2428 }
2429 break;
2430 case GL_COLOR:
2431 case GL_DEPTH:
2432 case GL_STENCIL:
2433 if (!defaultFramebuffer)
2434 {
Jamie Madill437fa652016-05-03 15:13:24 -04002435 context->handleError(
2436 Error(GL_INVALID_ENUM,
2437 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002438 return false;
2439 }
2440 break;
2441 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002442 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002443 return false;
2444 }
2445 }
2446 }
2447
2448 return true;
2449}
2450
Austin Kinross6ee1e782015-05-29 17:05:37 -07002451bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2452{
2453 // Note that debug marker calls must not set error state
2454
2455 if (length < 0)
2456 {
2457 return false;
2458 }
2459
2460 if (marker == nullptr)
2461 {
2462 return false;
2463 }
2464
2465 return true;
2466}
2467
2468bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2469{
2470 // Note that debug marker calls must not set error state
2471
2472 if (length < 0)
2473 {
2474 return false;
2475 }
2476
2477 if (length > 0 && marker == nullptr)
2478 {
2479 return false;
2480 }
2481
2482 return true;
2483}
2484
Geoff Langdcab33b2015-07-21 13:03:16 -04002485bool ValidateEGLImageTargetTexture2DOES(Context *context,
2486 egl::Display *display,
2487 GLenum target,
2488 egl::Image *image)
2489{
Geoff Langa8406172015-07-21 16:53:39 -04002490 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2491 {
Jamie Madill437fa652016-05-03 15:13:24 -04002492 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002493 return false;
2494 }
2495
2496 switch (target)
2497 {
2498 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002499 if (!context->getExtensions().eglImage)
2500 {
2501 context->handleError(Error(
2502 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2503 }
2504 break;
2505
2506 case GL_TEXTURE_EXTERNAL_OES:
2507 if (!context->getExtensions().eglImageExternal)
2508 {
2509 context->handleError(Error(
2510 GL_INVALID_ENUM,
2511 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2512 }
Geoff Langa8406172015-07-21 16:53:39 -04002513 break;
2514
2515 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002516 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002517 return false;
2518 }
2519
2520 if (!display->isValidImage(image))
2521 {
Jamie Madill437fa652016-05-03 15:13:24 -04002522 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002523 return false;
2524 }
2525
2526 if (image->getSamples() > 0)
2527 {
Jamie Madill437fa652016-05-03 15:13:24 -04002528 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002529 "cannot create a 2D texture from a multisampled EGL image."));
2530 return false;
2531 }
2532
Jamie Madilla3944d42016-07-22 22:13:26 -04002533 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002534 if (!textureCaps.texturable)
2535 {
Jamie Madill437fa652016-05-03 15:13:24 -04002536 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002537 "EGL image internal format is not supported as a texture."));
2538 return false;
2539 }
2540
Geoff Langdcab33b2015-07-21 13:03:16 -04002541 return true;
2542}
2543
2544bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2545 egl::Display *display,
2546 GLenum target,
2547 egl::Image *image)
2548{
Geoff Langa8406172015-07-21 16:53:39 -04002549 if (!context->getExtensions().eglImage)
2550 {
Jamie Madill437fa652016-05-03 15:13:24 -04002551 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002552 return false;
2553 }
2554
2555 switch (target)
2556 {
2557 case GL_RENDERBUFFER:
2558 break;
2559
2560 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002561 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002562 return false;
2563 }
2564
2565 if (!display->isValidImage(image))
2566 {
Jamie Madill437fa652016-05-03 15:13:24 -04002567 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002568 return false;
2569 }
2570
Jamie Madilla3944d42016-07-22 22:13:26 -04002571 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002572 if (!textureCaps.renderable)
2573 {
Jamie Madill437fa652016-05-03 15:13:24 -04002574 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002575 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2576 return false;
2577 }
2578
Geoff Langdcab33b2015-07-21 13:03:16 -04002579 return true;
2580}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002581
2582bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2583{
Geoff Lang36167ab2015-12-07 10:27:14 -05002584 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002585 {
2586 // The default VAO should always exist
2587 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002588 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002589 return false;
2590 }
2591
2592 return true;
2593}
2594
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002595bool ValidateLinkProgram(Context *context, GLuint program)
2596{
2597 if (context->hasActiveTransformFeedback(program))
2598 {
2599 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002600 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002601 "Cannot link program while program is associated with an active "
2602 "transform feedback object."));
2603 return false;
2604 }
2605 return true;
2606}
2607
Geoff Langc5629752015-12-07 16:29:04 -05002608bool ValidateProgramBinaryBase(Context *context,
2609 GLuint program,
2610 GLenum binaryFormat,
2611 const void *binary,
2612 GLint length)
2613{
2614 Program *programObject = GetValidProgram(context, program);
2615 if (programObject == nullptr)
2616 {
2617 return false;
2618 }
2619
2620 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2621 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2622 programBinaryFormats.end())
2623 {
Jamie Madill437fa652016-05-03 15:13:24 -04002624 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002625 return false;
2626 }
2627
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002628 if (context->hasActiveTransformFeedback(program))
2629 {
2630 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002631 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002632 "Cannot change program binary while program is associated with "
2633 "an active transform feedback object."));
2634 return false;
2635 }
2636
Geoff Langc5629752015-12-07 16:29:04 -05002637 return true;
2638}
2639
2640bool ValidateGetProgramBinaryBase(Context *context,
2641 GLuint program,
2642 GLsizei bufSize,
2643 GLsizei *length,
2644 GLenum *binaryFormat,
2645 void *binary)
2646{
2647 Program *programObject = GetValidProgram(context, program);
2648 if (programObject == nullptr)
2649 {
2650 return false;
2651 }
2652
2653 if (!programObject->isLinked())
2654 {
Jamie Madill437fa652016-05-03 15:13:24 -04002655 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002656 return false;
2657 }
2658
2659 return true;
2660}
Jamie Madillc29968b2016-01-20 11:17:23 -05002661
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002662bool ValidateUseProgram(Context *context, GLuint program)
2663{
2664 if (program != 0)
2665 {
2666 Program *programObject = context->getProgram(program);
2667 if (!programObject)
2668 {
2669 // ES 3.1.0 section 7.3 page 72
2670 if (context->getShader(program))
2671 {
Jamie Madill437fa652016-05-03 15:13:24 -04002672 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002673 Error(GL_INVALID_OPERATION,
2674 "Attempted to use a single shader instead of a shader program."));
2675 return false;
2676 }
2677 else
2678 {
Jamie Madill437fa652016-05-03 15:13:24 -04002679 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002680 return false;
2681 }
2682 }
2683 if (!programObject->isLinked())
2684 {
Jamie Madill437fa652016-05-03 15:13:24 -04002685 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002686 return false;
2687 }
2688 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002689 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002690 {
2691 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002692 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002693 Error(GL_INVALID_OPERATION,
2694 "Cannot change active program while transform feedback is unpaused."));
2695 return false;
2696 }
2697
2698 return true;
2699}
2700
Jamie Madillc29968b2016-01-20 11:17:23 -05002701bool ValidateCopyTexImage2D(ValidationContext *context,
2702 GLenum target,
2703 GLint level,
2704 GLenum internalformat,
2705 GLint x,
2706 GLint y,
2707 GLsizei width,
2708 GLsizei height,
2709 GLint border)
2710{
Martin Radev1be913c2016-07-11 17:59:16 +03002711 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002712 {
2713 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2714 0, x, y, width, height, border);
2715 }
2716
Martin Radev1be913c2016-07-11 17:59:16 +03002717 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002718 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2719 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002720}
Jamie Madillc29968b2016-01-20 11:17:23 -05002721
2722bool ValidateFramebufferRenderbuffer(Context *context,
2723 GLenum target,
2724 GLenum attachment,
2725 GLenum renderbuffertarget,
2726 GLuint renderbuffer)
2727{
2728 if (!ValidFramebufferTarget(target) ||
2729 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2730 {
Jamie Madill437fa652016-05-03 15:13:24 -04002731 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002732 return false;
2733 }
2734
2735 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2736 renderbuffertarget, renderbuffer);
2737}
2738
2739bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2740{
2741 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2742 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2743 {
Jamie Madill437fa652016-05-03 15:13:24 -04002744 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002745 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2746 return false;
2747 }
2748
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002749 ASSERT(context->getGLState().getDrawFramebuffer());
2750 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002751 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2752
2753 // This should come first before the check for the default frame buffer
2754 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2755 // rather than INVALID_OPERATION
2756 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2757 {
2758 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2759
2760 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002761 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2762 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002763 {
2764 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002765 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2766 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2767 // 3.1 is still a bit ambiguous about the error, but future specs are
2768 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002769 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002770 return false;
2771 }
2772 else if (bufs[colorAttachment] >= maxColorAttachment)
2773 {
Jamie Madill437fa652016-05-03 15:13:24 -04002774 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002775 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002776 return false;
2777 }
2778 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2779 frameBufferId != 0)
2780 {
2781 // INVALID_OPERATION-GL is bound to buffer and ith argument
2782 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002783 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002784 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2785 return false;
2786 }
2787 }
2788
2789 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2790 // and n is not 1 or bufs is bound to value other than BACK and NONE
2791 if (frameBufferId == 0)
2792 {
2793 if (n != 1)
2794 {
Jamie Madill437fa652016-05-03 15:13:24 -04002795 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002796 "n must be 1 when GL is bound to the default framebuffer"));
2797 return false;
2798 }
2799
2800 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2801 {
Jamie Madill437fa652016-05-03 15:13:24 -04002802 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002803 GL_INVALID_OPERATION,
2804 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2805 return false;
2806 }
2807 }
2808
2809 return true;
2810}
2811
2812bool ValidateCopyTexSubImage2D(Context *context,
2813 GLenum target,
2814 GLint level,
2815 GLint xoffset,
2816 GLint yoffset,
2817 GLint x,
2818 GLint y,
2819 GLsizei width,
2820 GLsizei height)
2821{
Martin Radev1be913c2016-07-11 17:59:16 +03002822 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002823 {
2824 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2825 yoffset, x, y, width, height, 0);
2826 }
2827
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002828 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2829 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002830}
2831
Olli Etuaho4f667482016-03-30 15:56:35 +03002832bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2833{
2834 if (!ValidBufferTarget(context, target))
2835 {
Jamie Madill437fa652016-05-03 15:13:24 -04002836 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002837 return false;
2838 }
2839
2840 if (pname != GL_BUFFER_MAP_POINTER)
2841 {
Jamie Madill437fa652016-05-03 15:13:24 -04002842 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002843 return false;
2844 }
2845
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002846 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002847
2848 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2849 // target bound to zero generate an INVALID_OPERATION error."
2850 // GLES 3.1 section 6.6 explicitly specifies this error.
2851 if (!buffer)
2852 {
Jamie Madill437fa652016-05-03 15:13:24 -04002853 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002854 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2855 return false;
2856 }
2857
2858 return true;
2859}
2860
2861bool ValidateUnmapBufferBase(Context *context, GLenum target)
2862{
2863 if (!ValidBufferTarget(context, target))
2864 {
Jamie Madill437fa652016-05-03 15:13:24 -04002865 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002866 return false;
2867 }
2868
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002869 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002870
2871 if (buffer == nullptr || !buffer->isMapped())
2872 {
Jamie Madill437fa652016-05-03 15:13:24 -04002873 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002874 return false;
2875 }
2876
2877 return true;
2878}
2879
2880bool ValidateMapBufferRangeBase(Context *context,
2881 GLenum target,
2882 GLintptr offset,
2883 GLsizeiptr length,
2884 GLbitfield access)
2885{
2886 if (!ValidBufferTarget(context, target))
2887 {
Jamie Madill437fa652016-05-03 15:13:24 -04002888 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002889 return false;
2890 }
2891
2892 if (offset < 0 || length < 0)
2893 {
Jamie Madill437fa652016-05-03 15:13:24 -04002894 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002895 return false;
2896 }
2897
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002898 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002899
2900 if (!buffer)
2901 {
Jamie Madill437fa652016-05-03 15:13:24 -04002902 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002903 return false;
2904 }
2905
2906 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002907 CheckedNumeric<size_t> checkedOffset(offset);
2908 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002909
Jamie Madille2e406c2016-06-02 13:04:10 -04002910 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002911 {
Jamie Madill437fa652016-05-03 15:13:24 -04002912 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002913 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2914 return false;
2915 }
2916
2917 // Check for invalid bits in the mask
2918 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2919 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2920 GL_MAP_UNSYNCHRONIZED_BIT;
2921
2922 if (access & ~(allAccessBits))
2923 {
Jamie Madill437fa652016-05-03 15:13:24 -04002924 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002925 return false;
2926 }
2927
2928 if (length == 0)
2929 {
Jamie Madill437fa652016-05-03 15:13:24 -04002930 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002931 return false;
2932 }
2933
2934 if (buffer->isMapped())
2935 {
Jamie Madill437fa652016-05-03 15:13:24 -04002936 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002937 return false;
2938 }
2939
2940 // Check for invalid bit combinations
2941 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2942 {
Jamie Madill437fa652016-05-03 15:13:24 -04002943 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002944 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2945 return false;
2946 }
2947
2948 GLbitfield writeOnlyBits =
2949 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2950
2951 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2952 {
Jamie Madill437fa652016-05-03 15:13:24 -04002953 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002954 "Invalid access bits when mapping buffer for reading: 0x%X.",
2955 access));
2956 return false;
2957 }
2958
2959 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2960 {
Jamie Madill437fa652016-05-03 15:13:24 -04002961 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002962 GL_INVALID_OPERATION,
2963 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2964 return false;
2965 }
2966 return true;
2967}
2968
2969bool ValidateFlushMappedBufferRangeBase(Context *context,
2970 GLenum target,
2971 GLintptr offset,
2972 GLsizeiptr length)
2973{
2974 if (offset < 0 || length < 0)
2975 {
Jamie Madill437fa652016-05-03 15:13:24 -04002976 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002977 return false;
2978 }
2979
2980 if (!ValidBufferTarget(context, target))
2981 {
Jamie Madill437fa652016-05-03 15:13:24 -04002982 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002983 return false;
2984 }
2985
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002986 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002987
2988 if (buffer == nullptr)
2989 {
Jamie Madill437fa652016-05-03 15:13:24 -04002990 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002991 return false;
2992 }
2993
2994 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2995 {
Jamie Madill437fa652016-05-03 15:13:24 -04002996 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002997 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2998 return false;
2999 }
3000
3001 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003002 CheckedNumeric<size_t> checkedOffset(offset);
3003 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003004
Jamie Madille2e406c2016-06-02 13:04:10 -04003005 if (!checkedSize.IsValid() ||
3006 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003007 {
Jamie Madill437fa652016-05-03 15:13:24 -04003008 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003009 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
3010 return false;
3011 }
3012
3013 return true;
3014}
3015
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003016bool ValidateGenerateMipmap(Context *context, GLenum target)
3017{
3018 if (!ValidTextureTarget(context, target))
3019 {
3020 context->handleError(Error(GL_INVALID_ENUM));
3021 return false;
3022 }
3023
3024 Texture *texture = context->getTargetTexture(target);
3025
3026 if (texture == nullptr)
3027 {
3028 context->handleError(Error(GL_INVALID_OPERATION));
3029 return false;
3030 }
3031
3032 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
3033
3034 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
3035 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
3036 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3037 {
3038 context->handleError(Error(GL_INVALID_OPERATION));
3039 return false;
3040 }
3041
Jamie Madilla3944d42016-07-22 22:13:26 -04003042 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
3043 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
3044 const TextureCaps &formatCaps = context->getTextureCaps().get(format.asSized());
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003045
3046 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
3047 // unsized formats or that are color renderable and filterable. Since we do not track if
3048 // the texture was created with sized or unsized format (only sized formats are stored),
3049 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
3050 // be able to) because they aren't color renderable. Simply do a special case for LUMA
3051 // textures since they're the only texture format that can be created with unsized formats
3052 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
3053 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04003054 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
3055 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003056 {
3057 context->handleError(Error(GL_INVALID_OPERATION));
3058 return false;
3059 }
3060
3061 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04003062 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003063 {
3064 context->handleError(Error(GL_INVALID_OPERATION));
3065 return false;
3066 }
3067
3068 // Non-power of 2 ES2 check
3069 if (!context->getExtensions().textureNPOT &&
3070 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3071 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3072 {
Martin Radev1be913c2016-07-11 17:59:16 +03003073 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003074 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3075 context->handleError(Error(GL_INVALID_OPERATION));
3076 return false;
3077 }
3078
3079 // Cube completeness check
3080 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3081 {
3082 context->handleError(Error(GL_INVALID_OPERATION));
3083 return false;
3084 }
3085
3086 return true;
3087}
3088
Olli Etuaho41997e72016-03-10 13:38:39 +02003089bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3090{
3091 return ValidateGenOrDelete(context, n);
3092}
3093
3094bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3095{
3096 return ValidateGenOrDelete(context, n);
3097}
3098
3099bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3100{
3101 return ValidateGenOrDelete(context, n);
3102}
3103
3104bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3105{
3106 return ValidateGenOrDelete(context, n);
3107}
3108
3109bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3110{
3111 return ValidateGenOrDelete(context, n);
3112}
3113
3114bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3115{
3116 return ValidateGenOrDelete(context, n);
3117}
3118
3119bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3120{
3121 return ValidateGenOrDelete(context, n);
3122}
3123
3124bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3125{
3126 return ValidateGenOrDelete(context, n);
3127}
3128
3129bool ValidateGenOrDelete(Context *context, GLint n)
3130{
3131 if (n < 0)
3132 {
Jamie Madill437fa652016-05-03 15:13:24 -04003133 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003134 return false;
3135 }
3136 return true;
3137}
3138
Geoff Langf41a7152016-09-19 15:11:17 -04003139bool ValidateEnable(Context *context, GLenum cap)
3140{
3141 if (!ValidCap(context, cap, false))
3142 {
3143 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3144 return false;
3145 }
3146
3147 if (context->getLimitations().noSampleAlphaToCoverageSupport &&
3148 cap == GL_SAMPLE_ALPHA_TO_COVERAGE)
3149 {
3150 const char *errorMessage = "Current renderer doesn't support alpha-to-coverage";
3151 context->handleError(Error(GL_INVALID_OPERATION, errorMessage));
3152
3153 // We also output an error message to the debugger window if tracing is active, so that
3154 // developers can see the error message.
3155 ERR("%s", errorMessage);
3156
3157 return false;
3158 }
3159
3160 return true;
3161}
3162
3163bool ValidateDisable(Context *context, GLenum cap)
3164{
3165 if (!ValidCap(context, cap, false))
3166 {
3167 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3168 return false;
3169 }
3170
3171 return true;
3172}
3173
3174bool ValidateIsEnabled(Context *context, GLenum cap)
3175{
3176 if (!ValidCap(context, cap, true))
3177 {
3178 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3179 return false;
3180 }
3181
3182 return true;
3183}
3184
Jamie Madillc29968b2016-01-20 11:17:23 -05003185} // namespace gl