blob: 7daa549bae95efc19e719e45baadd7d9288fe6c9 [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
Corentin Wallezece7c5a2016-09-21 15:28:23 -04001171 // Check for pixel pack buffer related API errors
1172 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
1173 if (pixelPackBuffer != nullptr)
1174 {
1175 // .. the data would be packed to the buffer object such that the memory writes required
1176 // would exceed the data store size.
1177 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1178 const InternalFormat &formatInfo = GetInternalFormatInfo(sizedInternalFormat);
1179 const gl::Extents size(width, height, 1);
1180 const auto &pack = context->getGLState().getPackState();
1181
Corentin Wallez886de362016-09-27 10:49:35 -04001182 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
Corentin Wallezece7c5a2016-09-21 15:28:23 -04001183 if (endByteOrErr.isError())
1184 {
1185 context->handleError(endByteOrErr.getError());
1186 return false;
1187 }
1188
1189 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
1190 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
1191 checkedEndByte += checkedOffset;
1192
1193 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
1194 {
1195 // Overflow past the end of the buffer
1196 context->handleError(
1197 Error(GL_INVALID_OPERATION, "Writes would overflow the pixel pack buffer."));
1198 return false;
1199 }
1200
1201 // ...the buffer object's data store is currently mapped.
1202 if (pixelPackBuffer->isMapped())
1203 {
1204 context->handleError(Error(GL_INVALID_OPERATION, "Pixel pack buffer is mapped."));
1205 return false;
1206 }
1207 }
1208
Jamie Madillc29968b2016-01-20 11:17:23 -05001209 return true;
1210}
1211
1212bool ValidateReadnPixelsEXT(Context *context,
1213 GLint x,
1214 GLint y,
1215 GLsizei width,
1216 GLsizei height,
1217 GLenum format,
1218 GLenum type,
1219 GLsizei bufSize,
1220 GLvoid *pixels)
1221{
1222 if (bufSize < 0)
1223 {
Jamie Madill437fa652016-05-03 15:13:24 -04001224 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001225 return false;
1226 }
1227
Geoff Lang5d601382014-07-22 15:14:06 -04001228 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
Corentin Wallezece7c5a2016-09-21 15:28:23 -04001229 const InternalFormat &formatInfo = GetInternalFormatInfo(sizedInternalFormat);
1230 const gl::Extents size(width, height, 1);
1231 const auto &pack = context->getGLState().getPackState();
Jamie Madill26e91952014-03-05 15:01:27 -05001232
Corentin Wallez886de362016-09-27 10:49:35 -04001233 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
Corentin Wallezece7c5a2016-09-21 15:28:23 -04001234 if (endByteOrErr.isError())
Jamie Madille2e406c2016-06-02 13:04:10 -04001235 {
Corentin Wallezece7c5a2016-09-21 15:28:23 -04001236 context->handleError(endByteOrErr.getError());
Jamie Madille2e406c2016-06-02 13:04:10 -04001237 return false;
1238 }
1239
Corentin Wallezece7c5a2016-09-21 15:28:23 -04001240 if (endByteOrErr.getResult() > static_cast<GLuint>(bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04001241 {
Corentin Wallezece7c5a2016-09-21 15:28:23 -04001242 context->handleError(Error(GL_INVALID_OPERATION, "Writes would overflow past bufSize."));
Jamie Madillc29968b2016-01-20 11:17:23 -05001243 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001244 }
1245
Jamie Madillc29968b2016-01-20 11:17:23 -05001246 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001247}
1248
Olli Etuaho41997e72016-03-10 13:38:39 +02001249bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001250{
1251 if (!context->getExtensions().occlusionQueryBoolean &&
1252 !context->getExtensions().disjointTimerQuery)
1253 {
Jamie Madill437fa652016-05-03 15:13:24 -04001254 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001255 return false;
1256 }
1257
Olli Etuaho41997e72016-03-10 13:38:39 +02001258 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001259}
1260
Olli Etuaho41997e72016-03-10 13:38:39 +02001261bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001262{
1263 if (!context->getExtensions().occlusionQueryBoolean &&
1264 !context->getExtensions().disjointTimerQuery)
1265 {
Jamie Madill437fa652016-05-03 15:13:24 -04001266 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001267 return false;
1268 }
1269
Olli Etuaho41997e72016-03-10 13:38:39 +02001270 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001271}
1272
1273bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001274{
1275 if (!ValidQueryType(context, target))
1276 {
Jamie Madill437fa652016-05-03 15:13:24 -04001277 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001278 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001279 }
1280
1281 if (id == 0)
1282 {
Jamie Madill437fa652016-05-03 15:13:24 -04001283 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001284 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001285 }
1286
1287 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1288 // of zero, if the active query object name for <target> is non-zero (for the
1289 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1290 // the active query for either target is non-zero), if <id> is the name of an
1291 // existing query object whose type does not match <target>, or if <id> is the
1292 // active query object name for any query type, the error INVALID_OPERATION is
1293 // generated.
1294
1295 // Ensure no other queries are active
1296 // NOTE: If other queries than occlusion are supported, we will need to check
1297 // separately that:
1298 // a) The query ID passed is not the current active query for any target/type
1299 // b) There are no active queries for the requested target (and in the case
1300 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1301 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001302
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001303 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001304 {
Jamie Madill437fa652016-05-03 15:13:24 -04001305 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001306 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001307 }
1308
1309 Query *queryObject = context->getQuery(id, true, target);
1310
1311 // check that name was obtained with glGenQueries
1312 if (!queryObject)
1313 {
Jamie Madill437fa652016-05-03 15:13:24 -04001314 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001315 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001316 }
1317
1318 // check for type mismatch
1319 if (queryObject->getType() != target)
1320 {
Jamie Madill437fa652016-05-03 15:13:24 -04001321 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001322 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001323 }
1324
1325 return true;
1326}
1327
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001328bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1329{
1330 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001331 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001332 {
Jamie Madill437fa652016-05-03 15:13:24 -04001333 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001334 return false;
1335 }
1336
1337 return ValidateBeginQueryBase(context, target, id);
1338}
1339
1340bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001341{
1342 if (!ValidQueryType(context, target))
1343 {
Jamie Madill437fa652016-05-03 15:13:24 -04001344 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001345 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001346 }
1347
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001348 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001349
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001350 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001351 {
Jamie Madill437fa652016-05-03 15:13:24 -04001352 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001353 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001354 }
1355
Jamie Madill45c785d2014-05-13 14:09:34 -04001356 return true;
1357}
1358
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001359bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1360{
1361 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001362 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001363 {
Jamie Madill437fa652016-05-03 15:13:24 -04001364 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001365 return false;
1366 }
1367
1368 return ValidateEndQueryBase(context, target);
1369}
1370
1371bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1372{
1373 if (!context->getExtensions().disjointTimerQuery)
1374 {
Jamie Madill437fa652016-05-03 15:13:24 -04001375 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001376 return false;
1377 }
1378
1379 if (target != GL_TIMESTAMP_EXT)
1380 {
Jamie Madill437fa652016-05-03 15:13:24 -04001381 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001382 return false;
1383 }
1384
1385 Query *queryObject = context->getQuery(id, true, target);
1386 if (queryObject == nullptr)
1387 {
Jamie Madill437fa652016-05-03 15:13:24 -04001388 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001389 return false;
1390 }
1391
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001392 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001393 {
Jamie Madill437fa652016-05-03 15:13:24 -04001394 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001395 return false;
1396 }
1397
1398 return true;
1399}
1400
1401bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1402{
1403 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1404 {
Jamie Madill437fa652016-05-03 15:13:24 -04001405 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001406 return false;
1407 }
1408
1409 switch (pname)
1410 {
1411 case GL_CURRENT_QUERY_EXT:
1412 if (target == GL_TIMESTAMP_EXT)
1413 {
Jamie Madill437fa652016-05-03 15:13:24 -04001414 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001415 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1416 return false;
1417 }
1418 break;
1419 case GL_QUERY_COUNTER_BITS_EXT:
1420 if (!context->getExtensions().disjointTimerQuery ||
1421 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1422 {
Jamie Madill437fa652016-05-03 15:13:24 -04001423 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001424 return false;
1425 }
1426 break;
1427 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001428 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001429 return false;
1430 }
1431
1432 return true;
1433}
1434
1435bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1436{
1437 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001438 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001439 {
Jamie Madill437fa652016-05-03 15:13:24 -04001440 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001441 return false;
1442 }
1443
1444 return ValidateGetQueryivBase(context, target, pname);
1445}
1446
1447bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1448{
1449 Query *queryObject = context->getQuery(id, false, GL_NONE);
1450
1451 if (!queryObject)
1452 {
Jamie Madill437fa652016-05-03 15:13:24 -04001453 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001454 return false;
1455 }
1456
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001457 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001458 {
Jamie Madill437fa652016-05-03 15:13:24 -04001459 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001460 return false;
1461 }
1462
1463 switch (pname)
1464 {
1465 case GL_QUERY_RESULT_EXT:
1466 case GL_QUERY_RESULT_AVAILABLE_EXT:
1467 break;
1468
1469 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001470 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001471 return false;
1472 }
1473
1474 return true;
1475}
1476
1477bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1478{
1479 if (!context->getExtensions().disjointTimerQuery)
1480 {
Jamie Madill437fa652016-05-03 15:13:24 -04001481 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001482 return false;
1483 }
1484 return ValidateGetQueryObjectValueBase(context, id, pname);
1485}
1486
1487bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1488{
1489 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001490 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001491 {
Jamie Madill437fa652016-05-03 15:13:24 -04001492 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001493 return false;
1494 }
1495 return ValidateGetQueryObjectValueBase(context, id, pname);
1496}
1497
1498bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1499{
1500 if (!context->getExtensions().disjointTimerQuery)
1501 {
Jamie Madill437fa652016-05-03 15:13:24 -04001502 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001503 return false;
1504 }
1505 return ValidateGetQueryObjectValueBase(context, id, pname);
1506}
1507
1508bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1509{
1510 if (!context->getExtensions().disjointTimerQuery)
1511 {
Jamie Madill437fa652016-05-03 15:13:24 -04001512 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001513 return false;
1514 }
1515 return ValidateGetQueryObjectValueBase(context, id, pname);
1516}
1517
Jamie Madill62d31cb2015-09-11 13:25:51 -04001518static bool ValidateUniformCommonBase(gl::Context *context,
1519 GLenum targetUniformType,
1520 GLint location,
1521 GLsizei count,
1522 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001523{
1524 if (count < 0)
1525 {
Jamie Madill437fa652016-05-03 15:13:24 -04001526 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001527 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001528 }
1529
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001530 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001531 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001532 {
Jamie Madill437fa652016-05-03 15:13:24 -04001533 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001534 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001535 }
1536
Geoff Langd8605522016-04-13 10:19:12 -04001537 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001538 {
1539 // Silently ignore the uniform command
1540 return false;
1541 }
1542
Geoff Lang7dd2e102014-11-10 15:19:26 -05001543 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001544 {
Jamie Madill437fa652016-05-03 15:13:24 -04001545 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001546 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001547 }
1548
Jamie Madill62d31cb2015-09-11 13:25:51 -04001549 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001550
1551 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001552 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001553 {
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
Jamie Madill62d31cb2015-09-11 13:25:51 -04001558 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001559 return true;
1560}
1561
Jamie Madillaa981bd2014-05-20 10:55:55 -04001562bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1563{
1564 // Check for ES3 uniform entry points
Martin Radev1be913c2016-07-11 17:59:16 +03001565 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT &&
1566 context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001567 {
Jamie Madill437fa652016-05-03 15:13:24 -04001568 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001569 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001570 }
1571
Jamie Madill62d31cb2015-09-11 13:25:51 -04001572 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001573 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1574 {
1575 return false;
1576 }
1577
Jamie Madillf2575982014-06-25 16:04:54 -04001578 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001579 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001580 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1581 {
Jamie Madill437fa652016-05-03 15:13:24 -04001582 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001583 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001584 }
1585
1586 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001587}
1588
1589bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1590 GLboolean transpose)
1591{
1592 // Check for ES3 uniform entry points
1593 int rows = VariableRowCount(matrixType);
1594 int cols = VariableColumnCount(matrixType);
Martin Radev1be913c2016-07-11 17:59:16 +03001595 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001596 {
Jamie Madill437fa652016-05-03 15:13:24 -04001597 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001598 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001599 }
1600
Martin Radev1be913c2016-07-11 17:59:16 +03001601 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001602 {
Jamie Madill437fa652016-05-03 15:13:24 -04001603 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001604 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001605 }
1606
Jamie Madill62d31cb2015-09-11 13:25:51 -04001607 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001608 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1609 {
1610 return false;
1611 }
1612
1613 if (uniform->type != matrixType)
1614 {
Jamie Madill437fa652016-05-03 15:13:24 -04001615 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001616 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001617 }
1618
1619 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001620}
1621
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001622bool ValidateStateQuery(ValidationContext *context,
1623 GLenum pname,
1624 GLenum *nativeType,
1625 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001626{
1627 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1628 {
Jamie Madill437fa652016-05-03 15:13:24 -04001629 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001630 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001631 }
1632
Jamie Madill0af26e12015-03-05 19:54:33 -05001633 const Caps &caps = context->getCaps();
1634
Jamie Madill893ab082014-05-16 16:56:10 -04001635 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1636 {
1637 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1638
Jamie Madill0af26e12015-03-05 19:54:33 -05001639 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001640 {
Jamie Madill437fa652016-05-03 15:13:24 -04001641 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001642 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001643 }
1644 }
1645
1646 switch (pname)
1647 {
1648 case GL_TEXTURE_BINDING_2D:
1649 case GL_TEXTURE_BINDING_CUBE_MAP:
1650 case GL_TEXTURE_BINDING_3D:
1651 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001652 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001653 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1654 if (!context->getExtensions().eglStreamConsumerExternal)
1655 {
Jamie Madill437fa652016-05-03 15:13:24 -04001656 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001657 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1658 return false;
1659 }
1660 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001661
1662 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1663 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1664 {
Jamie Madill51f40ec2016-06-15 14:06:00 -04001665 if (context->getGLState().getReadFramebuffer()->checkStatus(
1666 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001667 {
Jamie Madill437fa652016-05-03 15:13:24 -04001668 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001669 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001670 }
1671
Jamie Madill51f40ec2016-06-15 14:06:00 -04001672 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1673 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001674
1675 if (framebuffer->getReadBufferState() == GL_NONE)
1676 {
1677 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1678 return false;
1679 }
1680
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001681 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001682 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001683 {
Jamie Madill437fa652016-05-03 15:13:24 -04001684 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001685 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001686 }
1687 }
1688 break;
1689
1690 default:
1691 break;
1692 }
1693
1694 // pname is valid, but there are no parameters to return
1695 if (numParams == 0)
1696 {
1697 return false;
1698 }
1699
1700 return true;
1701}
1702
Jamie Madillc29968b2016-01-20 11:17:23 -05001703bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1704 GLenum target,
1705 GLint level,
1706 GLenum internalformat,
1707 bool isSubImage,
1708 GLint xoffset,
1709 GLint yoffset,
1710 GLint zoffset,
1711 GLint x,
1712 GLint y,
1713 GLsizei width,
1714 GLsizei height,
1715 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04001716 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001717{
Jamie Madill560a8d82014-05-21 13:06:20 -04001718 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1719 {
Jamie Madill437fa652016-05-03 15:13:24 -04001720 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001721 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001722 }
1723
1724 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1725 {
Jamie Madill437fa652016-05-03 15:13:24 -04001726 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001727 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001728 }
1729
1730 if (border != 0)
1731 {
Jamie Madill437fa652016-05-03 15:13:24 -04001732 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001733 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001734 }
1735
1736 if (!ValidMipLevel(context, target, level))
1737 {
Jamie Madill437fa652016-05-03 15:13:24 -04001738 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001739 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001740 }
1741
Jamie Madill51f40ec2016-06-15 14:06:00 -04001742 const auto &state = context->getGLState();
1743 auto readFramebuffer = state.getReadFramebuffer();
1744 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001745 {
Jamie Madill437fa652016-05-03 15:13:24 -04001746 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001747 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001748 }
1749
Jamie Madill51f40ec2016-06-15 14:06:00 -04001750 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001751 {
Jamie Madill437fa652016-05-03 15:13:24 -04001752 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001753 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001754 }
1755
Martin Radev138064f2016-07-15 12:03:41 +03001756 if (readFramebuffer->getReadBufferState() == GL_NONE)
1757 {
1758 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1759 return false;
1760 }
1761
Geoff Langaae65a42014-05-26 12:43:44 -04001762 const gl::Caps &caps = context->getCaps();
1763
Geoff Langaae65a42014-05-26 12:43:44 -04001764 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001765 switch (target)
1766 {
1767 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001768 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001769 break;
1770
1771 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1772 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1773 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1774 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1775 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1776 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001777 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001778 break;
1779
1780 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001781 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001782 break;
1783
1784 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001785 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001786 break;
1787
1788 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001789 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001790 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001791 }
1792
Jamie Madillc29968b2016-01-20 11:17:23 -05001793 gl::Texture *texture =
1794 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001795 if (!texture)
1796 {
Jamie Madill437fa652016-05-03 15:13:24 -04001797 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001798 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001799 }
1800
Geoff Lang69cce582015-09-17 13:20:36 -04001801 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001802 {
Jamie Madill437fa652016-05-03 15:13:24 -04001803 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001804 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001805 }
1806
Geoff Lang5d601382014-07-22 15:14:06 -04001807 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1808
1809 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001810 {
Jamie Madill437fa652016-05-03 15:13:24 -04001811 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001812 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001813 }
1814
Geoff Langa9be0dc2014-12-17 12:34:40 -05001815 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001816 {
Jamie Madill437fa652016-05-03 15:13:24 -04001817 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001818 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001819 }
1820
1821 if (isSubImage)
1822 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001823 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1824 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1825 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001826 {
Jamie Madill437fa652016-05-03 15:13:24 -04001827 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001828 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001829 }
1830 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001831 else
1832 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001833 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001834 {
Jamie Madill437fa652016-05-03 15:13:24 -04001835 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001836 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001837 }
1838
Martin Radev1be913c2016-07-11 17:59:16 +03001839 if (!formatInfo.textureSupport(context->getClientMajorVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001840 {
Jamie Madill437fa652016-05-03 15:13:24 -04001841 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001842 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001843 }
1844
1845 int maxLevelDimension = (maxDimension >> level);
1846 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1847 {
Jamie Madill437fa652016-05-03 15:13:24 -04001848 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001849 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001850 }
1851 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001852
Jamie Madill0c8abca2016-07-22 20:21:26 -04001853 if (textureFormatOut)
1854 {
1855 *textureFormatOut = texture->getFormat(target, level);
1856 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001857 return true;
1858}
1859
Jamie Madillf25855c2015-11-03 11:06:18 -05001860static bool ValidateDrawBase(ValidationContext *context,
1861 GLenum mode,
1862 GLsizei count,
1863 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001864{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001865 switch (mode)
1866 {
1867 case GL_POINTS:
1868 case GL_LINES:
1869 case GL_LINE_LOOP:
1870 case GL_LINE_STRIP:
1871 case GL_TRIANGLES:
1872 case GL_TRIANGLE_STRIP:
1873 case GL_TRIANGLE_FAN:
1874 break;
1875 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001876 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001877 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001878 }
1879
Jamie Madill250d33f2014-06-06 17:09:03 -04001880 if (count < 0)
1881 {
Jamie Madill437fa652016-05-03 15:13:24 -04001882 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001883 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001884 }
1885
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001886 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001887
Jamie Madill250d33f2014-06-06 17:09:03 -04001888 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001889 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001890 {
Jamie Madill437fa652016-05-03 15:13:24 -04001891 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001892 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001893 }
1894
Jamie Madill51f40ec2016-06-15 14:06:00 -04001895 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001896 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001897 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001898 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1899 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1900 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1901 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1902 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1903 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001904 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001905 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1906 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001907 {
1908 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1909 // Section 6.10 of the WebGL 1.0 spec
1910 ERR(
1911 "This ANGLE implementation does not support separate front/back stencil "
1912 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001913 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001914 return false;
1915 }
Jamie Madillac528012014-06-20 13:21:23 -04001916 }
1917
Jamie Madill51f40ec2016-06-15 14:06:00 -04001918 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001919 {
Jamie Madill437fa652016-05-03 15:13:24 -04001920 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001921 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001922 }
1923
Geoff Lang7dd2e102014-11-10 15:19:26 -05001924 gl::Program *program = state.getProgram();
1925 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001926 {
Jamie Madill437fa652016-05-03 15:13:24 -04001927 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001928 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001929 }
1930
Geoff Lang7dd2e102014-11-10 15:19:26 -05001931 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001932 {
Jamie Madill437fa652016-05-03 15:13:24 -04001933 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001934 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001935 }
1936
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001937 // Uniform buffer validation
1938 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1939 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001940 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001941 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001942 const OffsetBindingPointer<Buffer> &uniformBuffer =
1943 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001944
Geoff Lang5d124a62015-09-15 13:03:27 -04001945 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001946 {
1947 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001948 context->handleError(
1949 Error(GL_INVALID_OPERATION,
1950 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001951 return false;
1952 }
1953
Geoff Lang5d124a62015-09-15 13:03:27 -04001954 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001955 if (uniformBufferSize == 0)
1956 {
1957 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001958 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001959 }
1960
Jamie Madill62d31cb2015-09-11 13:25:51 -04001961 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001962 {
1963 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001964 context->handleError(
1965 Error(GL_INVALID_OPERATION,
1966 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001967 return false;
1968 }
1969 }
1970
Jamie Madill250d33f2014-06-06 17:09:03 -04001971 // No-op if zero count
1972 return (count > 0);
1973}
1974
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001975bool ValidateDrawArrays(ValidationContext *context,
1976 GLenum mode,
1977 GLint first,
1978 GLsizei count,
1979 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001980{
Jamie Madillfd716582014-06-06 17:09:04 -04001981 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001982 {
Jamie Madill437fa652016-05-03 15:13:24 -04001983 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001984 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001985 }
1986
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001987 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001988 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001989 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1990 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001991 {
1992 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1993 // that does not match the current transform feedback object's draw mode (if transform feedback
1994 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001995 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001996 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001997 }
1998
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001999 if (!ValidateDrawBase(context, mode, count, primcount))
2000 {
2001 return false;
2002 }
2003
2004 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04002005 {
2006 return false;
2007 }
2008
2009 return true;
2010}
2011
Geoff Langb1196682014-07-23 13:47:29 -04002012bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04002013{
2014 if (primcount < 0)
2015 {
Jamie Madill437fa652016-05-03 15:13:24 -04002016 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002017 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002018 }
2019
Jamie Madill2b976812014-08-25 15:47:49 -04002020 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04002021 {
2022 return false;
2023 }
2024
2025 // No-op if zero primitive count
2026 return (primcount > 0);
2027}
2028
Geoff Lang87a93302014-09-16 13:29:43 -04002029static bool ValidateDrawInstancedANGLE(Context *context)
2030{
2031 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002032 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04002033
Geoff Lang7dd2e102014-11-10 15:19:26 -05002034 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04002035
2036 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04002037 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04002038 {
2039 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04002040 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04002041 {
2042 return true;
2043 }
2044 }
2045
Jamie Madill437fa652016-05-03 15:13:24 -04002046 context->handleError(Error(GL_INVALID_OPERATION,
2047 "ANGLE_instanced_arrays requires that at least one active attribute"
2048 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04002049 return false;
2050}
2051
2052bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
2053{
2054 if (!ValidateDrawInstancedANGLE(context))
2055 {
2056 return false;
2057 }
2058
2059 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
2060}
2061
Jamie Madillf25855c2015-11-03 11:06:18 -05002062bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002063 GLenum mode,
2064 GLsizei count,
2065 GLenum type,
2066 const GLvoid *indices,
2067 GLsizei primcount,
2068 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002069{
Jamie Madill250d33f2014-06-06 17:09:03 -04002070 switch (type)
2071 {
2072 case GL_UNSIGNED_BYTE:
2073 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03002074 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002075 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03002076 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2077 {
2078 context->handleError(Error(GL_INVALID_ENUM));
2079 return false;
2080 }
2081 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002082 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002083 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03002084 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002085 }
2086
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002087 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002088
2089 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002090 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002091 {
2092 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2093 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002094 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002095 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002096 }
2097
2098 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002099 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002100 {
Jamie Madill437fa652016-05-03 15:13:24 -04002101 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002102 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002103 }
2104
Jamie Madill2b976812014-08-25 15:47:49 -04002105 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002106 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002107 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002108 {
Jamie Madill437fa652016-05-03 15:13:24 -04002109 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002110 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002111 }
2112
Jamie Madillae3000b2014-08-25 15:47:51 -04002113 if (elementArrayBuffer)
2114 {
2115 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2116
2117 GLint64 offset = reinterpret_cast<GLint64>(indices);
2118 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2119
2120 // check for integer overflows
2121 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2122 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2123 {
Jamie Madill437fa652016-05-03 15:13:24 -04002124 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002125 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002126 }
2127
2128 // Check for reading past the end of the bound buffer object
2129 if (byteCount > elementArrayBuffer->getSize())
2130 {
Jamie Madill437fa652016-05-03 15:13:24 -04002131 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002132 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002133 }
2134 }
2135 else if (!indices)
2136 {
2137 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002138 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002139 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002140 }
2141
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002142 if (!ValidateDrawBase(context, mode, count, primcount))
2143 {
2144 return false;
2145 }
2146
Jamie Madill2b976812014-08-25 15:47:49 -04002147 // Use max index to validate if our vertex buffers are large enough for the pull.
2148 // TODO: offer fast path, with disabled index validation.
2149 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2150 if (elementArrayBuffer)
2151 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002152 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002153 Error error =
2154 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2155 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002156 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002157 {
Jamie Madill437fa652016-05-03 15:13:24 -04002158 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002159 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002160 }
2161 }
2162 else
2163 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002164 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002165 }
2166
Jamie Madille79b1e12015-11-04 16:36:37 -05002167 // If we use an index greater than our maximum supported index range, return an error.
2168 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2169 // return an error if possible here.
2170 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2171 {
Jamie Madill437fa652016-05-03 15:13:24 -04002172 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002173 return false;
2174 }
2175
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002176 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002177 {
2178 return false;
2179 }
2180
Geoff Lang3edfe032015-09-04 16:38:24 -04002181 // No op if there are no real indices in the index data (all are primitive restart).
2182 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002183}
2184
Geoff Langb1196682014-07-23 13:47:29 -04002185bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002186 GLenum mode,
2187 GLsizei count,
2188 GLenum type,
2189 const GLvoid *indices,
2190 GLsizei primcount,
2191 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002192{
2193 if (primcount < 0)
2194 {
Jamie Madill437fa652016-05-03 15:13:24 -04002195 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002196 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002197 }
2198
Jamie Madill2b976812014-08-25 15:47:49 -04002199 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002200 {
2201 return false;
2202 }
2203
2204 // No-op zero primitive count
2205 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002206}
2207
Geoff Lang3edfe032015-09-04 16:38:24 -04002208bool ValidateDrawElementsInstancedANGLE(Context *context,
2209 GLenum mode,
2210 GLsizei count,
2211 GLenum type,
2212 const GLvoid *indices,
2213 GLsizei primcount,
2214 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002215{
2216 if (!ValidateDrawInstancedANGLE(context))
2217 {
2218 return false;
2219 }
2220
2221 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2222}
2223
Geoff Langb1196682014-07-23 13:47:29 -04002224bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002225 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002226{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002227 if (!ValidFramebufferTarget(target))
2228 {
Jamie Madill437fa652016-05-03 15:13:24 -04002229 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002230 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002231 }
2232
2233 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002234 {
2235 return false;
2236 }
2237
Jamie Madill55ec3b12014-07-03 10:38:57 -04002238 if (texture != 0)
2239 {
2240 gl::Texture *tex = context->getTexture(texture);
2241
2242 if (tex == NULL)
2243 {
Jamie Madill437fa652016-05-03 15:13:24 -04002244 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002245 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002246 }
2247
2248 if (level < 0)
2249 {
Jamie Madill437fa652016-05-03 15:13:24 -04002250 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002251 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002252 }
2253 }
2254
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002255 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002256 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002257
Jamie Madill84115c92015-04-23 15:00:07 -04002258 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002259 {
Jamie Madill437fa652016-05-03 15:13:24 -04002260 context->handleError(
2261 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002262 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002263 }
2264
2265 return true;
2266}
2267
Geoff Langb1196682014-07-23 13:47:29 -04002268bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002269 GLenum textarget, GLuint texture, GLint level)
2270{
Geoff Lang95663912015-04-02 15:54:45 -04002271 // 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 +03002272 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2273 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002274 {
Jamie Madill437fa652016-05-03 15:13:24 -04002275 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002276 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002277 }
2278
2279 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002280 {
2281 return false;
2282 }
2283
Jamie Madill55ec3b12014-07-03 10:38:57 -04002284 if (texture != 0)
2285 {
2286 gl::Texture *tex = context->getTexture(texture);
2287 ASSERT(tex);
2288
Jamie Madill2a6564e2014-07-11 09:53:19 -04002289 const gl::Caps &caps = context->getCaps();
2290
Jamie Madill55ec3b12014-07-03 10:38:57 -04002291 switch (textarget)
2292 {
2293 case GL_TEXTURE_2D:
2294 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002295 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002296 {
Jamie Madill437fa652016-05-03 15:13:24 -04002297 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002298 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002299 }
2300 if (tex->getTarget() != GL_TEXTURE_2D)
2301 {
Jamie Madill437fa652016-05-03 15:13:24 -04002302 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002303 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002304 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002305 }
2306 break;
2307
2308 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2309 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2310 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2311 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2312 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2313 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2314 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002315 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002316 {
Jamie Madill437fa652016-05-03 15:13:24 -04002317 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002318 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002319 }
2320 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2321 {
Jamie Madill437fa652016-05-03 15:13:24 -04002322 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002323 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002324 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002325 }
2326 break;
2327
2328 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002329 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002330 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002331 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002332
Jamie Madilla3944d42016-07-22 22:13:26 -04002333 const Format &format = tex->getFormat(textarget, level);
2334 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05002335 {
Jamie Madill437fa652016-05-03 15:13:24 -04002336 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002337 return false;
2338 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002339 }
2340
Jamie Madill570f7c82014-07-03 10:38:54 -04002341 return true;
2342}
2343
Geoff Langb1196682014-07-23 13:47:29 -04002344bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002345{
2346 if (program == 0)
2347 {
Jamie Madill437fa652016-05-03 15:13:24 -04002348 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002349 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002350 }
2351
Dian Xiang769769a2015-09-09 15:20:08 -07002352 gl::Program *programObject = GetValidProgram(context, program);
2353 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002354 {
2355 return false;
2356 }
2357
Jamie Madill0063c512014-08-25 15:47:53 -04002358 if (!programObject || !programObject->isLinked())
2359 {
Jamie Madill437fa652016-05-03 15:13:24 -04002360 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002361 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002362 }
2363
Geoff Lang7dd2e102014-11-10 15:19:26 -05002364 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002365 {
Jamie Madill437fa652016-05-03 15:13:24 -04002366 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002367 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002368 }
2369
Jamie Madill0063c512014-08-25 15:47:53 -04002370 return true;
2371}
2372
Geoff Langb1196682014-07-23 13:47:29 -04002373bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002374{
2375 return ValidateGetUniformBase(context, program, location);
2376}
2377
Geoff Langb1196682014-07-23 13:47:29 -04002378bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002379{
Jamie Madill78f41802014-08-25 15:47:55 -04002380 return ValidateGetUniformBase(context, program, location);
2381}
2382
Geoff Langb1196682014-07-23 13:47:29 -04002383static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002384{
2385 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002386 {
Jamie Madill78f41802014-08-25 15:47:55 -04002387 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002388 }
2389
Jamie Madilla502c742014-08-28 17:19:13 -04002390 gl::Program *programObject = context->getProgram(program);
2391 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002392
Jamie Madill78f41802014-08-25 15:47:55 -04002393 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002394 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2395 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002396 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002397 {
Jamie Madill437fa652016-05-03 15:13:24 -04002398 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002399 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002400 }
2401
2402 return true;
2403}
2404
Geoff Langb1196682014-07-23 13:47:29 -04002405bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002406{
Jamie Madill78f41802014-08-25 15:47:55 -04002407 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002408}
2409
Geoff Langb1196682014-07-23 13:47:29 -04002410bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002411{
Jamie Madill78f41802014-08-25 15:47:55 -04002412 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002413}
2414
Austin Kinross08332632015-05-05 13:35:47 -07002415bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2416 const GLenum *attachments, bool defaultFramebuffer)
2417{
2418 if (numAttachments < 0)
2419 {
Jamie Madill437fa652016-05-03 15:13:24 -04002420 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002421 return false;
2422 }
2423
2424 for (GLsizei i = 0; i < numAttachments; ++i)
2425 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002426 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002427 {
2428 if (defaultFramebuffer)
2429 {
Jamie Madill437fa652016-05-03 15:13:24 -04002430 context->handleError(Error(
2431 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002432 return false;
2433 }
2434
2435 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2436 {
Jamie Madill437fa652016-05-03 15:13:24 -04002437 context->handleError(Error(GL_INVALID_OPERATION,
2438 "Requested color attachment is greater than the maximum "
2439 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002440 return false;
2441 }
2442 }
2443 else
2444 {
2445 switch (attachments[i])
2446 {
2447 case GL_DEPTH_ATTACHMENT:
2448 case GL_STENCIL_ATTACHMENT:
2449 case GL_DEPTH_STENCIL_ATTACHMENT:
2450 if (defaultFramebuffer)
2451 {
Jamie Madill437fa652016-05-03 15:13:24 -04002452 context->handleError(
2453 Error(GL_INVALID_ENUM,
2454 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002455 return false;
2456 }
2457 break;
2458 case GL_COLOR:
2459 case GL_DEPTH:
2460 case GL_STENCIL:
2461 if (!defaultFramebuffer)
2462 {
Jamie Madill437fa652016-05-03 15:13:24 -04002463 context->handleError(
2464 Error(GL_INVALID_ENUM,
2465 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002466 return false;
2467 }
2468 break;
2469 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002470 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002471 return false;
2472 }
2473 }
2474 }
2475
2476 return true;
2477}
2478
Austin Kinross6ee1e782015-05-29 17:05:37 -07002479bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2480{
2481 // Note that debug marker calls must not set error state
2482
2483 if (length < 0)
2484 {
2485 return false;
2486 }
2487
2488 if (marker == nullptr)
2489 {
2490 return false;
2491 }
2492
2493 return true;
2494}
2495
2496bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2497{
2498 // Note that debug marker calls must not set error state
2499
2500 if (length < 0)
2501 {
2502 return false;
2503 }
2504
2505 if (length > 0 && marker == nullptr)
2506 {
2507 return false;
2508 }
2509
2510 return true;
2511}
2512
Geoff Langdcab33b2015-07-21 13:03:16 -04002513bool ValidateEGLImageTargetTexture2DOES(Context *context,
2514 egl::Display *display,
2515 GLenum target,
2516 egl::Image *image)
2517{
Geoff Langa8406172015-07-21 16:53:39 -04002518 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2519 {
Jamie Madill437fa652016-05-03 15:13:24 -04002520 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002521 return false;
2522 }
2523
2524 switch (target)
2525 {
2526 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002527 if (!context->getExtensions().eglImage)
2528 {
2529 context->handleError(Error(
2530 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2531 }
2532 break;
2533
2534 case GL_TEXTURE_EXTERNAL_OES:
2535 if (!context->getExtensions().eglImageExternal)
2536 {
2537 context->handleError(Error(
2538 GL_INVALID_ENUM,
2539 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2540 }
Geoff Langa8406172015-07-21 16:53:39 -04002541 break;
2542
2543 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002544 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002545 return false;
2546 }
2547
2548 if (!display->isValidImage(image))
2549 {
Jamie Madill437fa652016-05-03 15:13:24 -04002550 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002551 return false;
2552 }
2553
2554 if (image->getSamples() > 0)
2555 {
Jamie Madill437fa652016-05-03 15:13:24 -04002556 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002557 "cannot create a 2D texture from a multisampled EGL image."));
2558 return false;
2559 }
2560
Jamie Madilla3944d42016-07-22 22:13:26 -04002561 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002562 if (!textureCaps.texturable)
2563 {
Jamie Madill437fa652016-05-03 15:13:24 -04002564 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002565 "EGL image internal format is not supported as a texture."));
2566 return false;
2567 }
2568
Geoff Langdcab33b2015-07-21 13:03:16 -04002569 return true;
2570}
2571
2572bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2573 egl::Display *display,
2574 GLenum target,
2575 egl::Image *image)
2576{
Geoff Langa8406172015-07-21 16:53:39 -04002577 if (!context->getExtensions().eglImage)
2578 {
Jamie Madill437fa652016-05-03 15:13:24 -04002579 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002580 return false;
2581 }
2582
2583 switch (target)
2584 {
2585 case GL_RENDERBUFFER:
2586 break;
2587
2588 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002589 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002590 return false;
2591 }
2592
2593 if (!display->isValidImage(image))
2594 {
Jamie Madill437fa652016-05-03 15:13:24 -04002595 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002596 return false;
2597 }
2598
Jamie Madilla3944d42016-07-22 22:13:26 -04002599 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002600 if (!textureCaps.renderable)
2601 {
Jamie Madill437fa652016-05-03 15:13:24 -04002602 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002603 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2604 return false;
2605 }
2606
Geoff Langdcab33b2015-07-21 13:03:16 -04002607 return true;
2608}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002609
2610bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2611{
Geoff Lang36167ab2015-12-07 10:27:14 -05002612 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002613 {
2614 // The default VAO should always exist
2615 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002616 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002617 return false;
2618 }
2619
2620 return true;
2621}
2622
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002623bool ValidateLinkProgram(Context *context, GLuint program)
2624{
2625 if (context->hasActiveTransformFeedback(program))
2626 {
2627 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002628 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002629 "Cannot link program while program is associated with an active "
2630 "transform feedback object."));
2631 return false;
2632 }
2633 return true;
2634}
2635
Geoff Langc5629752015-12-07 16:29:04 -05002636bool ValidateProgramBinaryBase(Context *context,
2637 GLuint program,
2638 GLenum binaryFormat,
2639 const void *binary,
2640 GLint length)
2641{
2642 Program *programObject = GetValidProgram(context, program);
2643 if (programObject == nullptr)
2644 {
2645 return false;
2646 }
2647
2648 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2649 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2650 programBinaryFormats.end())
2651 {
Jamie Madill437fa652016-05-03 15:13:24 -04002652 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002653 return false;
2654 }
2655
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002656 if (context->hasActiveTransformFeedback(program))
2657 {
2658 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002659 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002660 "Cannot change program binary while program is associated with "
2661 "an active transform feedback object."));
2662 return false;
2663 }
2664
Geoff Langc5629752015-12-07 16:29:04 -05002665 return true;
2666}
2667
2668bool ValidateGetProgramBinaryBase(Context *context,
2669 GLuint program,
2670 GLsizei bufSize,
2671 GLsizei *length,
2672 GLenum *binaryFormat,
2673 void *binary)
2674{
2675 Program *programObject = GetValidProgram(context, program);
2676 if (programObject == nullptr)
2677 {
2678 return false;
2679 }
2680
2681 if (!programObject->isLinked())
2682 {
Jamie Madill437fa652016-05-03 15:13:24 -04002683 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002684 return false;
2685 }
2686
2687 return true;
2688}
Jamie Madillc29968b2016-01-20 11:17:23 -05002689
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002690bool ValidateUseProgram(Context *context, GLuint program)
2691{
2692 if (program != 0)
2693 {
2694 Program *programObject = context->getProgram(program);
2695 if (!programObject)
2696 {
2697 // ES 3.1.0 section 7.3 page 72
2698 if (context->getShader(program))
2699 {
Jamie Madill437fa652016-05-03 15:13:24 -04002700 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002701 Error(GL_INVALID_OPERATION,
2702 "Attempted to use a single shader instead of a shader program."));
2703 return false;
2704 }
2705 else
2706 {
Jamie Madill437fa652016-05-03 15:13:24 -04002707 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002708 return false;
2709 }
2710 }
2711 if (!programObject->isLinked())
2712 {
Jamie Madill437fa652016-05-03 15:13:24 -04002713 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002714 return false;
2715 }
2716 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002717 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002718 {
2719 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002720 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002721 Error(GL_INVALID_OPERATION,
2722 "Cannot change active program while transform feedback is unpaused."));
2723 return false;
2724 }
2725
2726 return true;
2727}
2728
Jamie Madillc29968b2016-01-20 11:17:23 -05002729bool ValidateCopyTexImage2D(ValidationContext *context,
2730 GLenum target,
2731 GLint level,
2732 GLenum internalformat,
2733 GLint x,
2734 GLint y,
2735 GLsizei width,
2736 GLsizei height,
2737 GLint border)
2738{
Martin Radev1be913c2016-07-11 17:59:16 +03002739 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002740 {
2741 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2742 0, x, y, width, height, border);
2743 }
2744
Martin Radev1be913c2016-07-11 17:59:16 +03002745 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002746 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2747 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002748}
Jamie Madillc29968b2016-01-20 11:17:23 -05002749
2750bool ValidateFramebufferRenderbuffer(Context *context,
2751 GLenum target,
2752 GLenum attachment,
2753 GLenum renderbuffertarget,
2754 GLuint renderbuffer)
2755{
2756 if (!ValidFramebufferTarget(target) ||
2757 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2758 {
Jamie Madill437fa652016-05-03 15:13:24 -04002759 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002760 return false;
2761 }
2762
2763 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2764 renderbuffertarget, renderbuffer);
2765}
2766
2767bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2768{
2769 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2770 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2771 {
Jamie Madill437fa652016-05-03 15:13:24 -04002772 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002773 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2774 return false;
2775 }
2776
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002777 ASSERT(context->getGLState().getDrawFramebuffer());
2778 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002779 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2780
2781 // This should come first before the check for the default frame buffer
2782 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2783 // rather than INVALID_OPERATION
2784 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2785 {
2786 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2787
2788 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002789 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2790 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002791 {
2792 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002793 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2794 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2795 // 3.1 is still a bit ambiguous about the error, but future specs are
2796 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002797 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002798 return false;
2799 }
2800 else if (bufs[colorAttachment] >= maxColorAttachment)
2801 {
Jamie Madill437fa652016-05-03 15:13:24 -04002802 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002803 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002804 return false;
2805 }
2806 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2807 frameBufferId != 0)
2808 {
2809 // INVALID_OPERATION-GL is bound to buffer and ith argument
2810 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002811 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002812 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2813 return false;
2814 }
2815 }
2816
2817 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2818 // and n is not 1 or bufs is bound to value other than BACK and NONE
2819 if (frameBufferId == 0)
2820 {
2821 if (n != 1)
2822 {
Jamie Madill437fa652016-05-03 15:13:24 -04002823 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002824 "n must be 1 when GL is bound to the default framebuffer"));
2825 return false;
2826 }
2827
2828 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2829 {
Jamie Madill437fa652016-05-03 15:13:24 -04002830 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002831 GL_INVALID_OPERATION,
2832 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2833 return false;
2834 }
2835 }
2836
2837 return true;
2838}
2839
2840bool ValidateCopyTexSubImage2D(Context *context,
2841 GLenum target,
2842 GLint level,
2843 GLint xoffset,
2844 GLint yoffset,
2845 GLint x,
2846 GLint y,
2847 GLsizei width,
2848 GLsizei height)
2849{
Martin Radev1be913c2016-07-11 17:59:16 +03002850 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002851 {
2852 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2853 yoffset, x, y, width, height, 0);
2854 }
2855
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002856 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2857 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002858}
2859
Olli Etuaho4f667482016-03-30 15:56:35 +03002860bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2861{
2862 if (!ValidBufferTarget(context, target))
2863 {
Jamie Madill437fa652016-05-03 15:13:24 -04002864 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002865 return false;
2866 }
2867
2868 if (pname != GL_BUFFER_MAP_POINTER)
2869 {
Jamie Madill437fa652016-05-03 15:13:24 -04002870 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002871 return false;
2872 }
2873
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002874 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002875
2876 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2877 // target bound to zero generate an INVALID_OPERATION error."
2878 // GLES 3.1 section 6.6 explicitly specifies this error.
2879 if (!buffer)
2880 {
Jamie Madill437fa652016-05-03 15:13:24 -04002881 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002882 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2883 return false;
2884 }
2885
2886 return true;
2887}
2888
2889bool ValidateUnmapBufferBase(Context *context, GLenum target)
2890{
2891 if (!ValidBufferTarget(context, target))
2892 {
Jamie Madill437fa652016-05-03 15:13:24 -04002893 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002894 return false;
2895 }
2896
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002897 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002898
2899 if (buffer == nullptr || !buffer->isMapped())
2900 {
Jamie Madill437fa652016-05-03 15:13:24 -04002901 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002902 return false;
2903 }
2904
2905 return true;
2906}
2907
2908bool ValidateMapBufferRangeBase(Context *context,
2909 GLenum target,
2910 GLintptr offset,
2911 GLsizeiptr length,
2912 GLbitfield access)
2913{
2914 if (!ValidBufferTarget(context, target))
2915 {
Jamie Madill437fa652016-05-03 15:13:24 -04002916 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002917 return false;
2918 }
2919
2920 if (offset < 0 || length < 0)
2921 {
Jamie Madill437fa652016-05-03 15:13:24 -04002922 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002923 return false;
2924 }
2925
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002926 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002927
2928 if (!buffer)
2929 {
Jamie Madill437fa652016-05-03 15:13:24 -04002930 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002931 return false;
2932 }
2933
2934 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002935 CheckedNumeric<size_t> checkedOffset(offset);
2936 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002937
Jamie Madille2e406c2016-06-02 13:04:10 -04002938 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002939 {
Jamie Madill437fa652016-05-03 15:13:24 -04002940 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002941 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2942 return false;
2943 }
2944
2945 // Check for invalid bits in the mask
2946 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2947 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2948 GL_MAP_UNSYNCHRONIZED_BIT;
2949
2950 if (access & ~(allAccessBits))
2951 {
Jamie Madill437fa652016-05-03 15:13:24 -04002952 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002953 return false;
2954 }
2955
2956 if (length == 0)
2957 {
Jamie Madill437fa652016-05-03 15:13:24 -04002958 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002959 return false;
2960 }
2961
2962 if (buffer->isMapped())
2963 {
Jamie Madill437fa652016-05-03 15:13:24 -04002964 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002965 return false;
2966 }
2967
2968 // Check for invalid bit combinations
2969 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2970 {
Jamie Madill437fa652016-05-03 15:13:24 -04002971 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002972 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2973 return false;
2974 }
2975
2976 GLbitfield writeOnlyBits =
2977 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2978
2979 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2980 {
Jamie Madill437fa652016-05-03 15:13:24 -04002981 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002982 "Invalid access bits when mapping buffer for reading: 0x%X.",
2983 access));
2984 return false;
2985 }
2986
2987 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2988 {
Jamie Madill437fa652016-05-03 15:13:24 -04002989 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002990 GL_INVALID_OPERATION,
2991 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2992 return false;
2993 }
2994 return true;
2995}
2996
2997bool ValidateFlushMappedBufferRangeBase(Context *context,
2998 GLenum target,
2999 GLintptr offset,
3000 GLsizeiptr length)
3001{
3002 if (offset < 0 || length < 0)
3003 {
Jamie Madill437fa652016-05-03 15:13:24 -04003004 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003005 return false;
3006 }
3007
3008 if (!ValidBufferTarget(context, target))
3009 {
Jamie Madill437fa652016-05-03 15:13:24 -04003010 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003011 return false;
3012 }
3013
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003014 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003015
3016 if (buffer == nullptr)
3017 {
Jamie Madill437fa652016-05-03 15:13:24 -04003018 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003019 return false;
3020 }
3021
3022 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
3023 {
Jamie Madill437fa652016-05-03 15:13:24 -04003024 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003025 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
3026 return false;
3027 }
3028
3029 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003030 CheckedNumeric<size_t> checkedOffset(offset);
3031 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003032
Jamie Madille2e406c2016-06-02 13:04:10 -04003033 if (!checkedSize.IsValid() ||
3034 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003035 {
Jamie Madill437fa652016-05-03 15:13:24 -04003036 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003037 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
3038 return false;
3039 }
3040
3041 return true;
3042}
3043
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003044bool ValidateGenerateMipmap(Context *context, GLenum target)
3045{
3046 if (!ValidTextureTarget(context, target))
3047 {
3048 context->handleError(Error(GL_INVALID_ENUM));
3049 return false;
3050 }
3051
3052 Texture *texture = context->getTargetTexture(target);
3053
3054 if (texture == nullptr)
3055 {
3056 context->handleError(Error(GL_INVALID_OPERATION));
3057 return false;
3058 }
3059
3060 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
3061
3062 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
3063 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
3064 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3065 {
3066 context->handleError(Error(GL_INVALID_OPERATION));
3067 return false;
3068 }
3069
Jamie Madilla3944d42016-07-22 22:13:26 -04003070 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
3071 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
3072 const TextureCaps &formatCaps = context->getTextureCaps().get(format.asSized());
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003073
3074 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
3075 // unsized formats or that are color renderable and filterable. Since we do not track if
3076 // the texture was created with sized or unsized format (only sized formats are stored),
3077 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
3078 // be able to) because they aren't color renderable. Simply do a special case for LUMA
3079 // textures since they're the only texture format that can be created with unsized formats
3080 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
3081 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04003082 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
3083 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003084 {
3085 context->handleError(Error(GL_INVALID_OPERATION));
3086 return false;
3087 }
3088
3089 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04003090 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003091 {
3092 context->handleError(Error(GL_INVALID_OPERATION));
3093 return false;
3094 }
3095
3096 // Non-power of 2 ES2 check
3097 if (!context->getExtensions().textureNPOT &&
3098 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3099 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3100 {
Martin Radev1be913c2016-07-11 17:59:16 +03003101 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003102 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3103 context->handleError(Error(GL_INVALID_OPERATION));
3104 return false;
3105 }
3106
3107 // Cube completeness check
3108 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3109 {
3110 context->handleError(Error(GL_INVALID_OPERATION));
3111 return false;
3112 }
3113
3114 return true;
3115}
3116
Olli Etuaho41997e72016-03-10 13:38:39 +02003117bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3118{
3119 return ValidateGenOrDelete(context, n);
3120}
3121
3122bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3123{
3124 return ValidateGenOrDelete(context, n);
3125}
3126
3127bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3128{
3129 return ValidateGenOrDelete(context, n);
3130}
3131
3132bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3133{
3134 return ValidateGenOrDelete(context, n);
3135}
3136
3137bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3138{
3139 return ValidateGenOrDelete(context, n);
3140}
3141
3142bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3143{
3144 return ValidateGenOrDelete(context, n);
3145}
3146
3147bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3148{
3149 return ValidateGenOrDelete(context, n);
3150}
3151
3152bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3153{
3154 return ValidateGenOrDelete(context, n);
3155}
3156
3157bool ValidateGenOrDelete(Context *context, GLint n)
3158{
3159 if (n < 0)
3160 {
Jamie Madill437fa652016-05-03 15:13:24 -04003161 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003162 return false;
3163 }
3164 return true;
3165}
3166
Geoff Langf41a7152016-09-19 15:11:17 -04003167bool ValidateEnable(Context *context, GLenum cap)
3168{
3169 if (!ValidCap(context, cap, false))
3170 {
3171 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3172 return false;
3173 }
3174
3175 if (context->getLimitations().noSampleAlphaToCoverageSupport &&
3176 cap == GL_SAMPLE_ALPHA_TO_COVERAGE)
3177 {
3178 const char *errorMessage = "Current renderer doesn't support alpha-to-coverage";
3179 context->handleError(Error(GL_INVALID_OPERATION, errorMessage));
3180
3181 // We also output an error message to the debugger window if tracing is active, so that
3182 // developers can see the error message.
3183 ERR("%s", errorMessage);
3184
3185 return false;
3186 }
3187
3188 return true;
3189}
3190
3191bool ValidateDisable(Context *context, GLenum cap)
3192{
3193 if (!ValidCap(context, cap, false))
3194 {
3195 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3196 return false;
3197 }
3198
3199 return true;
3200}
3201
3202bool ValidateIsEnabled(Context *context, GLenum cap)
3203{
3204 if (!ValidCap(context, cap, true))
3205 {
3206 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3207 return false;
3208 }
3209
3210 return true;
3211}
3212
Jamie Madillc29968b2016-01-20 11:17:23 -05003213} // namespace gl