blob: d204d6767617db41903a9e637445306d05ffd1cd [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
Jamie Madill1ca74672015-07-21 15:14:11 -0400134} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400135
Geoff Lang0550d032014-01-30 11:29:07 -0500136bool ValidCap(const Context *context, GLenum cap)
137{
138 switch (cap)
139 {
Sami Väisänen74c23472016-05-09 17:30:30 +0300140 // EXT_multisample_compatibility
141 case GL_MULTISAMPLE_EXT:
142 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
143 return context->getExtensions().multisampleCompatibility;
144
Geoff Lang0550d032014-01-30 11:29:07 -0500145 case GL_CULL_FACE:
146 case GL_POLYGON_OFFSET_FILL:
147 case GL_SAMPLE_ALPHA_TO_COVERAGE:
148 case GL_SAMPLE_COVERAGE:
149 case GL_SCISSOR_TEST:
150 case GL_STENCIL_TEST:
151 case GL_DEPTH_TEST:
152 case GL_BLEND:
153 case GL_DITHER:
154 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500155
Geoff Lang0550d032014-01-30 11:29:07 -0500156 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
157 case GL_RASTERIZER_DISCARD:
Martin Radev1be913c2016-07-11 17:59:16 +0300158 return (context->getClientMajorVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500159
160 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
161 case GL_DEBUG_OUTPUT:
162 return context->getExtensions().debug;
163
Geoff Lang0550d032014-01-30 11:29:07 -0500164 default:
165 return false;
166 }
167}
168
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500169bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400170{
Jamie Madilld7460c72014-01-21 16:38:14 -0500171 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400172 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500173 case GL_TEXTURE_2D:
174 case GL_TEXTURE_CUBE_MAP:
175 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400176
Jamie Madilld7460c72014-01-21 16:38:14 -0500177 case GL_TEXTURE_3D:
178 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300179 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500180
181 default:
182 return false;
183 }
Jamie Madill35d15012013-10-07 10:46:37 -0400184}
185
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500186bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
187{
188 switch (target)
189 {
190 case GL_TEXTURE_2D:
191 case GL_TEXTURE_CUBE_MAP:
192 return true;
193
194 default:
195 return false;
196 }
197}
198
199bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
200{
201 switch (target)
202 {
203 case GL_TEXTURE_3D:
204 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300205 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500206
207 default:
208 return false;
209 }
210}
211
Ian Ewellbda75592016-04-18 17:25:54 -0400212// Most texture GL calls are not compatible with external textures, so we have a separate validation
213// function for use in the GL calls that do
214bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
215{
216 return (target == GL_TEXTURE_EXTERNAL_OES) &&
217 (context->getExtensions().eglImageExternal ||
218 context->getExtensions().eglStreamConsumerExternal);
219}
220
Shannon Woods4dfed832014-03-17 20:03:39 -0400221// This function differs from ValidTextureTarget in that the target must be
222// usable as the destination of a 2D operation-- so a cube face is valid, but
223// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400224// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500225bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400226{
227 switch (target)
228 {
229 case GL_TEXTURE_2D:
230 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
231 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
232 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
233 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
235 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
236 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500237 default:
238 return false;
239 }
240}
241
242bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
243{
244 switch (target)
245 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400246 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500247 case GL_TEXTURE_2D_ARRAY:
248 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400249 default:
250 return false;
251 }
252}
253
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500254bool ValidFramebufferTarget(GLenum target)
255{
Geoff Langd4475812015-03-18 10:53:05 -0400256 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
257 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500258
259 switch (target)
260 {
261 case GL_FRAMEBUFFER: return true;
262 case GL_READ_FRAMEBUFFER: return true;
263 case GL_DRAW_FRAMEBUFFER: return true;
264 default: return false;
265 }
266}
267
Jamie Madill29639852016-09-02 15:00:09 -0400268bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -0500269{
270 switch (target)
271 {
272 case GL_ARRAY_BUFFER:
273 case GL_ELEMENT_ARRAY_BUFFER:
274 return true;
275
Jamie Madill8c96d582014-03-05 15:01:23 -0500276 case GL_PIXEL_PACK_BUFFER:
277 case GL_PIXEL_UNPACK_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300278 return (context->getExtensions().pixelBufferObject ||
279 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400280
Shannon Woodsb3801742014-03-27 14:59:19 -0400281 case GL_COPY_READ_BUFFER:
282 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500283 case GL_TRANSFORM_FEEDBACK_BUFFER:
284 case GL_UNIFORM_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300285 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500286
287 default:
288 return false;
289 }
290}
291
Jamie Madill70656a62014-03-05 15:01:26 -0500292bool ValidBufferParameter(const Context *context, GLenum pname)
293{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400294 const Extensions &extensions = context->getExtensions();
295
Jamie Madill70656a62014-03-05 15:01:26 -0500296 switch (pname)
297 {
298 case GL_BUFFER_USAGE:
299 case GL_BUFFER_SIZE:
300 return true;
301
Geoff Langcc6f55d2015-03-20 13:01:02 -0400302 case GL_BUFFER_ACCESS_OES:
303 return extensions.mapBuffer;
304
305 case GL_BUFFER_MAPPED:
306 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
Martin Radev1be913c2016-07-11 17:59:16 +0300307 return (context->getClientMajorVersion() >= 3) || extensions.mapBuffer ||
308 extensions.mapBufferRange;
Geoff Langcc6f55d2015-03-20 13:01:02 -0400309
Jamie Madill70656a62014-03-05 15:01:26 -0500310 // GL_BUFFER_MAP_POINTER is a special case, and may only be
311 // queried with GetBufferPointerv
312 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500313 case GL_BUFFER_MAP_OFFSET:
314 case GL_BUFFER_MAP_LENGTH:
Martin Radev1be913c2016-07-11 17:59:16 +0300315 return (context->getClientMajorVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500316
317 default:
318 return false;
319 }
320}
321
Jamie Madillc29968b2016-01-20 11:17:23 -0500322bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400323{
Jamie Madillc29968b2016-01-20 11:17:23 -0500324 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400325 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400326 switch (target)
327 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500328 case GL_TEXTURE_2D:
329 maxDimension = caps.max2DTextureSize;
330 break;
Geoff Langce635692013-09-24 13:56:32 -0400331 case GL_TEXTURE_CUBE_MAP:
332 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
333 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
334 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
335 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
336 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500337 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
338 maxDimension = caps.maxCubeMapTextureSize;
339 break;
340 case GL_TEXTURE_3D:
341 maxDimension = caps.max3DTextureSize;
342 break;
343 case GL_TEXTURE_2D_ARRAY:
344 maxDimension = caps.max2DTextureSize;
345 break;
Geoff Langce635692013-09-24 13:56:32 -0400346 default: UNREACHABLE();
347 }
348
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700349 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400350}
351
Austin Kinross08528e12015-10-07 16:24:40 -0700352bool ValidImageSizeParameters(const Context *context,
353 GLenum target,
354 GLint level,
355 GLsizei width,
356 GLsizei height,
357 GLsizei depth,
358 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400359{
360 if (level < 0 || width < 0 || height < 0 || depth < 0)
361 {
362 return false;
363 }
364
Austin Kinross08528e12015-10-07 16:24:40 -0700365 // TexSubImage parameters can be NPOT without textureNPOT extension,
366 // as long as the destination texture is POT.
367 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400368 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400369 {
370 return false;
371 }
372
373 if (!ValidMipLevel(context, target, level))
374 {
375 return false;
376 }
377
378 return true;
379}
380
Geoff Lang0d8b7242015-09-09 14:56:53 -0400381bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
382{
383 // List of compressed format that require that the texture size is smaller than or a multiple of
384 // the compressed block size.
385 switch (internalFormat)
386 {
387 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
388 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
389 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
390 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800391 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400392 return true;
393
394 default:
395 return false;
396 }
397}
398
Jamie Madillc29968b2016-01-20 11:17:23 -0500399bool ValidCompressedImageSize(const ValidationContext *context,
400 GLenum internalFormat,
401 GLsizei width,
402 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400403{
Geoff Lang5d601382014-07-22 15:14:06 -0400404 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
405 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400406 {
407 return false;
408 }
409
Geoff Lang0d8b7242015-09-09 14:56:53 -0400410 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400411 {
412 return false;
413 }
414
Geoff Lang0d8b7242015-09-09 14:56:53 -0400415 if (CompressedTextureFormatRequiresExactSize(internalFormat))
416 {
417 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
418 width % formatInfo.compressedBlockWidth != 0) ||
419 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
420 height % formatInfo.compressedBlockHeight != 0))
421 {
422 return false;
423 }
424 }
425
Geoff Langd4f180b2013-09-24 13:57:44 -0400426 return true;
427}
428
Geoff Lang37dde692014-01-31 16:34:54 -0500429bool ValidQueryType(const Context *context, GLenum queryType)
430{
Geoff Langd4475812015-03-18 10:53:05 -0400431 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
432 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 -0500433
434 switch (queryType)
435 {
436 case GL_ANY_SAMPLES_PASSED:
437 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
438 return true;
439 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
Martin Radev1be913c2016-07-11 17:59:16 +0300440 return (context->getClientMajorVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500441 case GL_TIME_ELAPSED_EXT:
442 return context->getExtensions().disjointTimerQuery;
Geoff Lang2b4ce802016-04-28 13:34:50 -0400443 case GL_COMMANDS_COMPLETED_CHROMIUM:
444 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500445 default:
446 return false;
447 }
448}
449
Dian Xiang769769a2015-09-09 15:20:08 -0700450Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500451{
452 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
453 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
454 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
455
Dian Xiang769769a2015-09-09 15:20:08 -0700456 Program *validProgram = context->getProgram(id);
457
458 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500459 {
Dian Xiang769769a2015-09-09 15:20:08 -0700460 if (context->getShader(id))
461 {
Jamie Madill437fa652016-05-03 15:13:24 -0400462 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700463 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
464 }
465 else
466 {
Jamie Madill437fa652016-05-03 15:13:24 -0400467 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700468 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500469 }
Dian Xiang769769a2015-09-09 15:20:08 -0700470
471 return validProgram;
472}
473
474Shader *GetValidShader(Context *context, GLuint id)
475{
476 // See ValidProgram for spec details.
477
478 Shader *validShader = context->getShader(id);
479
480 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500481 {
Dian Xiang769769a2015-09-09 15:20:08 -0700482 if (context->getProgram(id))
483 {
Jamie Madill437fa652016-05-03 15:13:24 -0400484 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700485 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
486 }
487 else
488 {
Jamie Madill437fa652016-05-03 15:13:24 -0400489 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700490 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500491 }
Dian Xiang769769a2015-09-09 15:20:08 -0700492
493 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500494}
495
Geoff Langb1196682014-07-23 13:47:29 -0400496bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400497{
498 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
499 {
500 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
501
Geoff Langaae65a42014-05-26 12:43:44 -0400502 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400503 {
Jamie Madill437fa652016-05-03 15:13:24 -0400504 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400505 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400506 }
507 }
508 else
509 {
510 switch (attachment)
511 {
512 case GL_DEPTH_ATTACHMENT:
513 case GL_STENCIL_ATTACHMENT:
Martin Radev1be913c2016-07-11 17:59:16 +0300514 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400515
516 case GL_DEPTH_STENCIL_ATTACHMENT:
Geoff Langc287ea62016-09-16 14:46:51 -0400517 if (!context->getExtensions().webglCompatibility &&
518 context->getClientMajorVersion() < 3)
Martin Radev1be913c2016-07-11 17:59:16 +0300519 {
520 context->handleError(Error(GL_INVALID_ENUM));
521 return false;
522 }
523 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400524
525 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400526 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300527 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400528 }
529 }
530
531 return true;
532}
533
Corentin Walleze0902642014-11-04 12:32:15 -0800534bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
535 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400536{
537 switch (target)
538 {
539 case GL_RENDERBUFFER:
540 break;
541 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400542 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400543 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400544 }
545
546 if (width < 0 || height < 0 || samples < 0)
547 {
Jamie Madill437fa652016-05-03 15:13:24 -0400548 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400549 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400550 }
551
Geoff Langd87878e2014-09-19 15:42:59 -0400552 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
553 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400554 {
Jamie Madill437fa652016-05-03 15:13:24 -0400555 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400556 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400557 }
558
559 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
560 // 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 -0800561 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400562 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400563 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400564 {
Jamie Madill437fa652016-05-03 15:13:24 -0400565 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400566 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 }
568
Geoff Langaae65a42014-05-26 12:43:44 -0400569 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400570 {
Jamie Madill437fa652016-05-03 15:13:24 -0400571 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400572 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400573 }
574
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700575 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400576 if (handle == 0)
577 {
Jamie Madill437fa652016-05-03 15:13:24 -0400578 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400579 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400580 }
581
582 return true;
583}
584
Corentin Walleze0902642014-11-04 12:32:15 -0800585bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
586 GLenum internalformat, GLsizei width, GLsizei height)
587{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800588 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800589
590 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400591 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800592 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400593 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800594 {
Jamie Madill437fa652016-05-03 15:13:24 -0400595 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800596 return false;
597 }
598
599 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
600 // the specified storage. This is different than ES 3.0 in which a sample number higher
601 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800602 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
Martin Radev1be913c2016-07-11 17:59:16 +0300603 if (context->getClientMajorVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800604 {
Geoff Langa4903b72015-03-02 16:02:48 -0800605 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
606 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
607 {
Jamie Madill437fa652016-05-03 15:13:24 -0400608 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800609 return false;
610 }
Corentin Walleze0902642014-11-04 12:32:15 -0800611 }
612
613 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
614}
615
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500616bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
617 GLenum renderbuffertarget, GLuint renderbuffer)
618{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400619 if (!ValidFramebufferTarget(target))
620 {
Jamie Madill437fa652016-05-03 15:13:24 -0400621 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400622 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400623 }
624
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700625 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500626
Jamie Madill84115c92015-04-23 15:00:07 -0400627 ASSERT(framebuffer);
628 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500629 {
Jamie Madill437fa652016-05-03 15:13:24 -0400630 context->handleError(
631 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400632 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500633 }
634
Jamie Madillb4472272014-07-03 10:38:55 -0400635 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500636 {
Jamie Madillb4472272014-07-03 10:38:55 -0400637 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500638 }
639
Jamie Madillab9d82c2014-01-21 16:38:14 -0500640 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
641 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
642 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
643 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
644 if (renderbuffer != 0)
645 {
646 if (!context->getRenderbuffer(renderbuffer))
647 {
Jamie Madill437fa652016-05-03 15:13:24 -0400648 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400649 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500650 }
651 }
652
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500653 return true;
654}
655
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700656bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500657 GLint srcX0,
658 GLint srcY0,
659 GLint srcX1,
660 GLint srcY1,
661 GLint dstX0,
662 GLint dstY0,
663 GLint dstX1,
664 GLint dstY1,
665 GLbitfield mask,
666 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667{
668 switch (filter)
669 {
670 case GL_NEAREST:
671 break;
672 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 break;
674 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400675 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400676 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400677 }
678
679 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
680 {
Jamie Madill437fa652016-05-03 15:13:24 -0400681 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400682 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400683 }
684
685 if (mask == 0)
686 {
687 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
688 // buffers are copied.
689 return false;
690 }
691
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400692 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
693 // color buffer, leaving only nearest being unfiltered from above
694 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
695 {
Jamie Madill437fa652016-05-03 15:13:24 -0400696 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400697 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400698 }
699
Jamie Madill51f40ec2016-06-15 14:06:00 -0400700 const auto &glState = context->getGLState();
701 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
702 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500703
704 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400705 {
Jamie Madill437fa652016-05-03 15:13:24 -0400706 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400707 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400708 }
709
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700710 if (readFramebuffer->id() == drawFramebuffer->id())
711 {
712 context->handleError(Error(GL_INVALID_OPERATION));
713 return false;
714 }
715
Jamie Madill51f40ec2016-06-15 14:06:00 -0400716 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500717 {
Jamie Madill437fa652016-05-03 15:13:24 -0400718 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500719 return false;
720 }
721
Jamie Madill51f40ec2016-06-15 14:06:00 -0400722 if (drawFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -0500723 {
Jamie Madill437fa652016-05-03 15:13:24 -0400724 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -0500725 return false;
726 }
727
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700728 if (drawFramebuffer->getSamples(context->getContextState()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400729 {
Jamie Madill437fa652016-05-03 15:13:24 -0400730 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400731 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 }
733
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400734 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
735
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400736 if (mask & GL_COLOR_BUFFER_BIT)
737 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400738 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
739 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500740 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741
742 if (readColorBuffer && drawColorBuffer)
743 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400744 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400745
Geoff Langa15472a2015-08-11 11:48:03 -0400746 for (size_t drawbufferIdx = 0;
747 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748 {
Geoff Langa15472a2015-08-11 11:48:03 -0400749 const FramebufferAttachment *attachment =
750 drawFramebuffer->getDrawBuffer(drawbufferIdx);
751 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400752 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400753 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754
Geoff Langb2f3d052013-08-13 12:49:27 -0400755 // The GL ES 3.0.2 spec (pg 193) states that:
756 // 1) If the read buffer is fixed point format, the draw buffer must be as well
757 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
758 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500759 // Changes with EXT_color_buffer_float:
760 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -0400761 GLenum readComponentType = readFormat.info->componentType;
762 GLenum drawComponentType = drawFormat.info->componentType;
Jamie Madill6163c752015-12-07 16:32:59 -0500763 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
764 readComponentType == GL_SIGNED_NORMALIZED);
765 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
766 drawComponentType == GL_SIGNED_NORMALIZED);
767
768 if (extensions.colorBufferFloat)
769 {
770 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
771 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
772
773 if (readFixedOrFloat != drawFixedOrFloat)
774 {
Jamie Madill437fa652016-05-03 15:13:24 -0400775 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500776 "If the read buffer contains fixed-point or "
777 "floating-point values, the draw buffer "
778 "must as well."));
779 return false;
780 }
781 }
782 else if (readFixedPoint != drawFixedPoint)
783 {
Jamie Madill437fa652016-05-03 15:13:24 -0400784 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -0500785 "If the read buffer contains fixed-point "
786 "values, the draw buffer must as well."));
787 return false;
788 }
789
790 if (readComponentType == GL_UNSIGNED_INT &&
791 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400792 {
Jamie Madill437fa652016-05-03 15:13:24 -0400793 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400794 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 }
796
Jamie Madill6163c752015-12-07 16:32:59 -0500797 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798 {
Jamie Madill437fa652016-05-03 15:13:24 -0400799 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400800 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400801 }
802
Jamie Madilla3944d42016-07-22 22:13:26 -0400803 if (readColorBuffer->getSamples() > 0 &&
804 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805 {
Jamie Madill437fa652016-05-03 15:13:24 -0400806 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400807 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400808 }
809 }
810 }
811
Jamie Madilla3944d42016-07-22 22:13:26 -0400812 if ((readFormat.info->componentType == GL_INT ||
813 readFormat.info->componentType == GL_UNSIGNED_INT) &&
814 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400815 {
Jamie Madill437fa652016-05-03 15:13:24 -0400816 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400817 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400818 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400819 }
820 }
821
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200822 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
823 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
824 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400825 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200826 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400827 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400828 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
829 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400830
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200831 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400832 {
Jamie Madilla3944d42016-07-22 22:13:26 -0400833 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400834 {
Jamie Madill437fa652016-05-03 15:13:24 -0400835 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400836 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400837 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200839 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400840 {
Jamie Madill437fa652016-05-03 15:13:24 -0400841 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400842 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400843 }
844 }
845 }
846 }
847
848 return true;
849}
850
Geoff Langb1196682014-07-23 13:47:29 -0400851bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400852{
853 switch (pname)
854 {
855 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
856 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
857 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
858 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
859 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
860 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
861 case GL_CURRENT_VERTEX_ATTRIB:
Martin Radev1be913c2016-07-11 17:59:16 +0300862 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400863
864 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
Martin Radev1be913c2016-07-11 17:59:16 +0300865 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
866 // the same constant.
867 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
868 "ANGLE extension enums not equal to GL enums.");
869 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400870
871 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Martin Radev1be913c2016-07-11 17:59:16 +0300872 if (context->getClientMajorVersion() < 3)
873 {
874 context->handleError(Error(GL_INVALID_ENUM));
875 return false;
876 }
877 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400878
879 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400880 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300881 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 }
883}
884
Ian Ewellbda75592016-04-18 17:25:54 -0400885bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400886{
887 switch (pname)
888 {
889 case GL_TEXTURE_WRAP_R:
890 case GL_TEXTURE_SWIZZLE_R:
891 case GL_TEXTURE_SWIZZLE_G:
892 case GL_TEXTURE_SWIZZLE_B:
893 case GL_TEXTURE_SWIZZLE_A:
894 case GL_TEXTURE_BASE_LEVEL:
895 case GL_TEXTURE_MAX_LEVEL:
896 case GL_TEXTURE_COMPARE_MODE:
897 case GL_TEXTURE_COMPARE_FUNC:
898 case GL_TEXTURE_MIN_LOD:
899 case GL_TEXTURE_MAX_LOD:
Martin Radev1be913c2016-07-11 17:59:16 +0300900 if (context->getClientMajorVersion() < 3)
901 {
902 context->handleError(Error(GL_INVALID_ENUM));
903 return false;
904 }
905 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
906 {
907 context->handleError(Error(GL_INVALID_ENUM,
908 "ES3 texture parameters are not available without "
909 "GL_OES_EGL_image_external_essl3."));
910 return false;
911 }
912 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400913
914 default: break;
915 }
916
917 switch (pname)
918 {
919 case GL_TEXTURE_WRAP_S:
920 case GL_TEXTURE_WRAP_T:
921 case GL_TEXTURE_WRAP_R:
922 switch (param)
923 {
Corentin Wallez9670b032016-04-29 09:47:47 +0000924 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -0400925 return true;
926 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400927 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +0300928 if (target == GL_TEXTURE_EXTERNAL_OES)
929 {
930 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400931 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +0300932 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
933 return false;
934 }
935 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400936 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400937 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400938 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 }
940
941 case GL_TEXTURE_MIN_FILTER:
942 switch (param)
943 {
944 case GL_NEAREST:
945 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -0400946 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400947 case GL_NEAREST_MIPMAP_NEAREST:
948 case GL_LINEAR_MIPMAP_NEAREST:
949 case GL_NEAREST_MIPMAP_LINEAR:
950 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +0300951 if (target == GL_TEXTURE_EXTERNAL_OES)
952 {
953 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -0400954 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +0300955 Error(GL_INVALID_ENUM,
956 "external textures only support NEAREST and LINEAR filtering"));
957 return false;
958 }
959 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400960 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400961 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400962 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400963 }
964 break;
965
966 case GL_TEXTURE_MAG_FILTER:
967 switch (param)
968 {
969 case GL_NEAREST:
970 case GL_LINEAR:
971 return true;
972 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400973 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400974 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400975 }
976 break;
977
978 case GL_TEXTURE_USAGE_ANGLE:
979 switch (param)
980 {
981 case GL_NONE:
982 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
983 return true;
984 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400985 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400986 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400987 }
988 break;
989
990 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400991 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400992 {
Jamie Madill437fa652016-05-03 15:13:24 -0400993 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400994 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400995 }
996
997 // we assume the parameter passed to this validation method is truncated, not rounded
998 if (param < 1)
999 {
Jamie Madill437fa652016-05-03 15:13:24 -04001000 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001001 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001002 }
1003 return true;
1004
1005 case GL_TEXTURE_MIN_LOD:
1006 case GL_TEXTURE_MAX_LOD:
1007 // any value is permissible
1008 return true;
1009
1010 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -04001011 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001012 switch (param)
1013 {
1014 case GL_NONE:
1015 case GL_COMPARE_REF_TO_TEXTURE:
1016 return true;
1017 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001018 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001019 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001020 }
1021 break;
1022
1023 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -04001024 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001025 switch (param)
1026 {
1027 case GL_LEQUAL:
1028 case GL_GEQUAL:
1029 case GL_LESS:
1030 case GL_GREATER:
1031 case GL_EQUAL:
1032 case GL_NOTEQUAL:
1033 case GL_ALWAYS:
1034 case GL_NEVER:
1035 return true;
1036 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001037 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001038 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001039 }
1040 break;
1041
1042 case GL_TEXTURE_SWIZZLE_R:
1043 case GL_TEXTURE_SWIZZLE_G:
1044 case GL_TEXTURE_SWIZZLE_B:
1045 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001046 switch (param)
1047 {
1048 case GL_RED:
1049 case GL_GREEN:
1050 case GL_BLUE:
1051 case GL_ALPHA:
1052 case GL_ZERO:
1053 case GL_ONE:
1054 return true;
1055 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001056 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001057 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001058 }
1059 break;
1060
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001061 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001062 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001063 {
Geoff Langb66a9092016-05-16 15:59:14 -04001064 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001065 return false;
1066 }
Geoff Langb66a9092016-05-16 15:59:14 -04001067 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1068 {
1069 context->handleError(
1070 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1071 return false;
1072 }
1073 return true;
1074
1075 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001076 if (param < 0)
1077 {
1078 context->handleError(Error(GL_INVALID_VALUE));
1079 return false;
1080 }
1081 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001082 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001083 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001084 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001085 }
1086}
1087
Geoff Langb1196682014-07-23 13:47:29 -04001088bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001089{
1090 switch (pname)
1091 {
1092 case GL_TEXTURE_MIN_FILTER:
1093 case GL_TEXTURE_MAG_FILTER:
1094 case GL_TEXTURE_WRAP_S:
1095 case GL_TEXTURE_WRAP_T:
1096 case GL_TEXTURE_WRAP_R:
1097 case GL_TEXTURE_MIN_LOD:
1098 case GL_TEXTURE_MAX_LOD:
1099 case GL_TEXTURE_COMPARE_MODE:
1100 case GL_TEXTURE_COMPARE_FUNC:
1101 return true;
1102
1103 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001104 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001105 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001106 }
1107}
1108
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001109bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001110 GLint x,
1111 GLint y,
1112 GLsizei width,
1113 GLsizei height,
1114 GLenum format,
1115 GLenum type,
1116 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001117{
Jamie Madillc29968b2016-01-20 11:17:23 -05001118 if (width < 0 || height < 0)
1119 {
Jamie Madill437fa652016-05-03 15:13:24 -04001120 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001121 return false;
1122 }
1123
Jamie Madill51f40ec2016-06-15 14:06:00 -04001124 auto readFramebuffer = context->getGLState().getReadFramebuffer();
Jamie Madill26e91952014-03-05 15:01:27 -05001125
Jamie Madill51f40ec2016-06-15 14:06:00 -04001126 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001127 {
Jamie Madill437fa652016-05-03 15:13:24 -04001128 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001129 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001130 }
1131
Jamie Madill51f40ec2016-06-15 14:06:00 -04001132 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001133 {
Jamie Madill437fa652016-05-03 15:13:24 -04001134 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001135 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001136 }
1137
Jamie Madill51f40ec2016-06-15 14:06:00 -04001138 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1139 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001140
1141 if (framebuffer->getReadBufferState() == GL_NONE)
1142 {
1143 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1144 return false;
1145 }
1146
Geoff Langbce529e2014-12-01 12:48:41 -05001147 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1148 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001149 {
Jamie Madill437fa652016-05-03 15:13:24 -04001150 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001151 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001152 }
1153
Geoff Langbce529e2014-12-01 12:48:41 -05001154 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1155 GLenum currentType = framebuffer->getImplementationColorReadType();
Jamie Madilla3944d42016-07-22 22:13:26 -04001156 GLenum currentInternalFormat = readBuffer->getFormat().asSized();
Jamie Madill26e91952014-03-05 15:01:27 -05001157
Geoff Langf607c602016-09-21 11:46:48 -04001158 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(currentInternalFormat);
1159 bool validFormatTypeCombination =
1160 ValidReadPixelsFormatType(context, internalFormatInfo.componentType, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001161
Geoff Langf607c602016-09-21 11:46:48 -04001162 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
Jamie Madill26e91952014-03-05 15:01:27 -05001163 {
Jamie Madill437fa652016-05-03 15:13:24 -04001164 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001165 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001166 }
1167
Jamie Madillc29968b2016-01-20 11:17:23 -05001168 return true;
1169}
1170
1171bool ValidateReadnPixelsEXT(Context *context,
1172 GLint x,
1173 GLint y,
1174 GLsizei width,
1175 GLsizei height,
1176 GLenum format,
1177 GLenum type,
1178 GLsizei bufSize,
1179 GLvoid *pixels)
1180{
1181 if (bufSize < 0)
1182 {
Jamie Madill437fa652016-05-03 15:13:24 -04001183 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001184 return false;
1185 }
1186
Geoff Lang5d601382014-07-22 15:14:06 -04001187 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1188 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001189
Jamie Madille2e406c2016-06-02 13:04:10 -04001190 auto outputPitchOrErr =
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001191 sizedFormatInfo.computeRowPitch(type, width, context->getGLState().getPackAlignment(),
1192 context->getGLState().getPackRowLength());
Jamie Madille2e406c2016-06-02 13:04:10 -04001193
1194 if (outputPitchOrErr.isError())
1195 {
1196 context->handleError(outputPitchOrErr.getError());
1197 return false;
1198 }
1199
1200 CheckedNumeric<GLuint> checkedOutputPitch(outputPitchOrErr.getResult());
1201 auto checkedRequiredSize = checkedOutputPitch * height;
1202 if (!checkedRequiredSize.IsValid())
1203 {
1204 context->handleError(Error(GL_INVALID_OPERATION, "Unsigned multiplication overflow."));
1205 return false;
1206 }
1207
Jamie Madill26e91952014-03-05 15:01:27 -05001208 // sized query sanity check
Jamie Madille2e406c2016-06-02 13:04:10 -04001209 if (checkedRequiredSize.ValueOrDie() > static_cast<GLuint>(bufSize))
Jamie Madill26e91952014-03-05 15:01:27 -05001210 {
Jamie Madill437fa652016-05-03 15:13:24 -04001211 context->handleError(Error(GL_INVALID_OPERATION));
Jamie Madillc29968b2016-01-20 11:17:23 -05001212 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001213 }
1214
Jamie Madillc29968b2016-01-20 11:17:23 -05001215 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001216}
1217
Olli Etuaho41997e72016-03-10 13:38:39 +02001218bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001219{
1220 if (!context->getExtensions().occlusionQueryBoolean &&
1221 !context->getExtensions().disjointTimerQuery)
1222 {
Jamie Madill437fa652016-05-03 15:13:24 -04001223 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001224 return false;
1225 }
1226
Olli Etuaho41997e72016-03-10 13:38:39 +02001227 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001228}
1229
Olli Etuaho41997e72016-03-10 13:38:39 +02001230bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001231{
1232 if (!context->getExtensions().occlusionQueryBoolean &&
1233 !context->getExtensions().disjointTimerQuery)
1234 {
Jamie Madill437fa652016-05-03 15:13:24 -04001235 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001236 return false;
1237 }
1238
Olli Etuaho41997e72016-03-10 13:38:39 +02001239 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001240}
1241
1242bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001243{
1244 if (!ValidQueryType(context, target))
1245 {
Jamie Madill437fa652016-05-03 15:13:24 -04001246 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001247 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001248 }
1249
1250 if (id == 0)
1251 {
Jamie Madill437fa652016-05-03 15:13:24 -04001252 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001253 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001254 }
1255
1256 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1257 // of zero, if the active query object name for <target> is non-zero (for the
1258 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1259 // the active query for either target is non-zero), if <id> is the name of an
1260 // existing query object whose type does not match <target>, or if <id> is the
1261 // active query object name for any query type, the error INVALID_OPERATION is
1262 // generated.
1263
1264 // Ensure no other queries are active
1265 // NOTE: If other queries than occlusion are supported, we will need to check
1266 // separately that:
1267 // a) The query ID passed is not the current active query for any target/type
1268 // b) There are no active queries for the requested target (and in the case
1269 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1270 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001271
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001272 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001273 {
Jamie Madill437fa652016-05-03 15:13:24 -04001274 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001275 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001276 }
1277
1278 Query *queryObject = context->getQuery(id, true, target);
1279
1280 // check that name was obtained with glGenQueries
1281 if (!queryObject)
1282 {
Jamie Madill437fa652016-05-03 15:13:24 -04001283 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001284 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001285 }
1286
1287 // check for type mismatch
1288 if (queryObject->getType() != target)
1289 {
Jamie Madill437fa652016-05-03 15:13:24 -04001290 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001291 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001292 }
1293
1294 return true;
1295}
1296
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001297bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1298{
1299 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001300 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001301 {
Jamie Madill437fa652016-05-03 15:13:24 -04001302 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001303 return false;
1304 }
1305
1306 return ValidateBeginQueryBase(context, target, id);
1307}
1308
1309bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001310{
1311 if (!ValidQueryType(context, target))
1312 {
Jamie Madill437fa652016-05-03 15:13:24 -04001313 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001314 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001315 }
1316
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001317 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001318
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001319 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001320 {
Jamie Madill437fa652016-05-03 15:13:24 -04001321 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001322 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001323 }
1324
Jamie Madill45c785d2014-05-13 14:09:34 -04001325 return true;
1326}
1327
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001328bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
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 ValidateEndQueryBase(context, target);
1338}
1339
1340bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1341{
1342 if (!context->getExtensions().disjointTimerQuery)
1343 {
Jamie Madill437fa652016-05-03 15:13:24 -04001344 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001345 return false;
1346 }
1347
1348 if (target != GL_TIMESTAMP_EXT)
1349 {
Jamie Madill437fa652016-05-03 15:13:24 -04001350 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001351 return false;
1352 }
1353
1354 Query *queryObject = context->getQuery(id, true, target);
1355 if (queryObject == nullptr)
1356 {
Jamie Madill437fa652016-05-03 15:13:24 -04001357 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001358 return false;
1359 }
1360
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001361 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001362 {
Jamie Madill437fa652016-05-03 15:13:24 -04001363 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001364 return false;
1365 }
1366
1367 return true;
1368}
1369
1370bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1371{
1372 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1373 {
Jamie Madill437fa652016-05-03 15:13:24 -04001374 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001375 return false;
1376 }
1377
1378 switch (pname)
1379 {
1380 case GL_CURRENT_QUERY_EXT:
1381 if (target == GL_TIMESTAMP_EXT)
1382 {
Jamie Madill437fa652016-05-03 15:13:24 -04001383 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001384 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1385 return false;
1386 }
1387 break;
1388 case GL_QUERY_COUNTER_BITS_EXT:
1389 if (!context->getExtensions().disjointTimerQuery ||
1390 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1391 {
Jamie Madill437fa652016-05-03 15:13:24 -04001392 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001393 return false;
1394 }
1395 break;
1396 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001397 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001398 return false;
1399 }
1400
1401 return true;
1402}
1403
1404bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1405{
1406 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001407 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001408 {
Jamie Madill437fa652016-05-03 15:13:24 -04001409 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001410 return false;
1411 }
1412
1413 return ValidateGetQueryivBase(context, target, pname);
1414}
1415
1416bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1417{
1418 Query *queryObject = context->getQuery(id, false, GL_NONE);
1419
1420 if (!queryObject)
1421 {
Jamie Madill437fa652016-05-03 15:13:24 -04001422 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001423 return false;
1424 }
1425
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001426 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001427 {
Jamie Madill437fa652016-05-03 15:13:24 -04001428 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001429 return false;
1430 }
1431
1432 switch (pname)
1433 {
1434 case GL_QUERY_RESULT_EXT:
1435 case GL_QUERY_RESULT_AVAILABLE_EXT:
1436 break;
1437
1438 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001439 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001440 return false;
1441 }
1442
1443 return true;
1444}
1445
1446bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1447{
1448 if (!context->getExtensions().disjointTimerQuery)
1449 {
Jamie Madill437fa652016-05-03 15:13:24 -04001450 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001451 return false;
1452 }
1453 return ValidateGetQueryObjectValueBase(context, id, pname);
1454}
1455
1456bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1457{
1458 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001459 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001460 {
Jamie Madill437fa652016-05-03 15:13:24 -04001461 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001462 return false;
1463 }
1464 return ValidateGetQueryObjectValueBase(context, id, pname);
1465}
1466
1467bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1468{
1469 if (!context->getExtensions().disjointTimerQuery)
1470 {
Jamie Madill437fa652016-05-03 15:13:24 -04001471 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001472 return false;
1473 }
1474 return ValidateGetQueryObjectValueBase(context, id, pname);
1475}
1476
1477bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *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
Jamie Madill62d31cb2015-09-11 13:25:51 -04001487static bool ValidateUniformCommonBase(gl::Context *context,
1488 GLenum targetUniformType,
1489 GLint location,
1490 GLsizei count,
1491 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001492{
1493 if (count < 0)
1494 {
Jamie Madill437fa652016-05-03 15:13:24 -04001495 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001496 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001497 }
1498
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001499 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001500 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001501 {
Jamie Madill437fa652016-05-03 15:13:24 -04001502 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001503 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001504 }
1505
Geoff Langd8605522016-04-13 10:19:12 -04001506 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001507 {
1508 // Silently ignore the uniform command
1509 return false;
1510 }
1511
Geoff Lang7dd2e102014-11-10 15:19:26 -05001512 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001513 {
Jamie Madill437fa652016-05-03 15:13:24 -04001514 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001515 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001516 }
1517
Jamie Madill62d31cb2015-09-11 13:25:51 -04001518 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001519
1520 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001521 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001522 {
Jamie Madill437fa652016-05-03 15:13:24 -04001523 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001524 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001525 }
1526
Jamie Madill62d31cb2015-09-11 13:25:51 -04001527 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001528 return true;
1529}
1530
Jamie Madillaa981bd2014-05-20 10:55:55 -04001531bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1532{
1533 // Check for ES3 uniform entry points
Martin Radev1be913c2016-07-11 17:59:16 +03001534 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT &&
1535 context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001536 {
Jamie Madill437fa652016-05-03 15:13:24 -04001537 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001538 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001539 }
1540
Jamie Madill62d31cb2015-09-11 13:25:51 -04001541 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001542 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1543 {
1544 return false;
1545 }
1546
Jamie Madillf2575982014-06-25 16:04:54 -04001547 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001548 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001549 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1550 {
Jamie Madill437fa652016-05-03 15:13:24 -04001551 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001552 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001553 }
1554
1555 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001556}
1557
1558bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1559 GLboolean transpose)
1560{
1561 // Check for ES3 uniform entry points
1562 int rows = VariableRowCount(matrixType);
1563 int cols = VariableColumnCount(matrixType);
Martin Radev1be913c2016-07-11 17:59:16 +03001564 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001565 {
Jamie Madill437fa652016-05-03 15:13:24 -04001566 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001567 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001568 }
1569
Martin Radev1be913c2016-07-11 17:59:16 +03001570 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001571 {
Jamie Madill437fa652016-05-03 15:13:24 -04001572 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001573 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001574 }
1575
Jamie Madill62d31cb2015-09-11 13:25:51 -04001576 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001577 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1578 {
1579 return false;
1580 }
1581
1582 if (uniform->type != matrixType)
1583 {
Jamie Madill437fa652016-05-03 15:13:24 -04001584 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001585 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001586 }
1587
1588 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001589}
1590
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001591bool ValidateStateQuery(ValidationContext *context,
1592 GLenum pname,
1593 GLenum *nativeType,
1594 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001595{
1596 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1597 {
Jamie Madill437fa652016-05-03 15:13:24 -04001598 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001599 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001600 }
1601
Jamie Madill0af26e12015-03-05 19:54:33 -05001602 const Caps &caps = context->getCaps();
1603
Jamie Madill893ab082014-05-16 16:56:10 -04001604 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1605 {
1606 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1607
Jamie Madill0af26e12015-03-05 19:54:33 -05001608 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001609 {
Jamie Madill437fa652016-05-03 15:13:24 -04001610 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001611 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001612 }
1613 }
1614
1615 switch (pname)
1616 {
1617 case GL_TEXTURE_BINDING_2D:
1618 case GL_TEXTURE_BINDING_CUBE_MAP:
1619 case GL_TEXTURE_BINDING_3D:
1620 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001621 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001622 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1623 if (!context->getExtensions().eglStreamConsumerExternal)
1624 {
Jamie Madill437fa652016-05-03 15:13:24 -04001625 context->handleError(
Ian Ewell54f87462016-03-10 13:47:21 -05001626 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1627 return false;
1628 }
1629 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001630
1631 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1632 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1633 {
Jamie Madill51f40ec2016-06-15 14:06:00 -04001634 if (context->getGLState().getReadFramebuffer()->checkStatus(
1635 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001636 {
Jamie Madill437fa652016-05-03 15:13:24 -04001637 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001638 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001639 }
1640
Jamie Madill51f40ec2016-06-15 14:06:00 -04001641 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1642 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001643
1644 if (framebuffer->getReadBufferState() == GL_NONE)
1645 {
1646 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1647 return false;
1648 }
1649
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001650 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001651 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001652 {
Jamie Madill437fa652016-05-03 15:13:24 -04001653 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001654 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001655 }
1656 }
1657 break;
1658
1659 default:
1660 break;
1661 }
1662
1663 // pname is valid, but there are no parameters to return
1664 if (numParams == 0)
1665 {
1666 return false;
1667 }
1668
1669 return true;
1670}
1671
Jamie Madillc29968b2016-01-20 11:17:23 -05001672bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1673 GLenum target,
1674 GLint level,
1675 GLenum internalformat,
1676 bool isSubImage,
1677 GLint xoffset,
1678 GLint yoffset,
1679 GLint zoffset,
1680 GLint x,
1681 GLint y,
1682 GLsizei width,
1683 GLsizei height,
1684 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04001685 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001686{
Jamie Madill560a8d82014-05-21 13:06:20 -04001687 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1688 {
Jamie Madill437fa652016-05-03 15:13:24 -04001689 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001690 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001691 }
1692
1693 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1694 {
Jamie Madill437fa652016-05-03 15:13:24 -04001695 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001696 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001697 }
1698
1699 if (border != 0)
1700 {
Jamie Madill437fa652016-05-03 15:13:24 -04001701 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001702 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001703 }
1704
1705 if (!ValidMipLevel(context, target, level))
1706 {
Jamie Madill437fa652016-05-03 15:13:24 -04001707 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001708 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001709 }
1710
Jamie Madill51f40ec2016-06-15 14:06:00 -04001711 const auto &state = context->getGLState();
1712 auto readFramebuffer = state.getReadFramebuffer();
1713 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001714 {
Jamie Madill437fa652016-05-03 15:13:24 -04001715 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001716 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001717 }
1718
Jamie Madill51f40ec2016-06-15 14:06:00 -04001719 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001720 {
Jamie Madill437fa652016-05-03 15:13:24 -04001721 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001722 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001723 }
1724
Martin Radev138064f2016-07-15 12:03:41 +03001725 if (readFramebuffer->getReadBufferState() == GL_NONE)
1726 {
1727 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1728 return false;
1729 }
1730
Geoff Langaae65a42014-05-26 12:43:44 -04001731 const gl::Caps &caps = context->getCaps();
1732
Geoff Langaae65a42014-05-26 12:43:44 -04001733 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001734 switch (target)
1735 {
1736 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001737 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001738 break;
1739
1740 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1741 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1742 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1743 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1744 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1745 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001746 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001747 break;
1748
1749 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001750 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001751 break;
1752
1753 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001754 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001755 break;
1756
1757 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001758 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001759 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001760 }
1761
Jamie Madillc29968b2016-01-20 11:17:23 -05001762 gl::Texture *texture =
1763 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001764 if (!texture)
1765 {
Jamie Madill437fa652016-05-03 15:13:24 -04001766 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001767 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001768 }
1769
Geoff Lang69cce582015-09-17 13:20:36 -04001770 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001771 {
Jamie Madill437fa652016-05-03 15:13:24 -04001772 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001773 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001774 }
1775
Geoff Lang5d601382014-07-22 15:14:06 -04001776 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1777
1778 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001779 {
Jamie Madill437fa652016-05-03 15:13:24 -04001780 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001781 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001782 }
1783
Geoff Langa9be0dc2014-12-17 12:34:40 -05001784 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001785 {
Jamie Madill437fa652016-05-03 15:13:24 -04001786 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05001787 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001788 }
1789
1790 if (isSubImage)
1791 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001792 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1793 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1794 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001795 {
Jamie Madill437fa652016-05-03 15:13:24 -04001796 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001797 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001798 }
1799 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001800 else
1801 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001802 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001803 {
Jamie Madill437fa652016-05-03 15:13:24 -04001804 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001805 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001806 }
1807
Martin Radev1be913c2016-07-11 17:59:16 +03001808 if (!formatInfo.textureSupport(context->getClientMajorVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001809 {
Jamie Madill437fa652016-05-03 15:13:24 -04001810 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001811 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001812 }
1813
1814 int maxLevelDimension = (maxDimension >> level);
1815 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1816 {
Jamie Madill437fa652016-05-03 15:13:24 -04001817 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001818 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001819 }
1820 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001821
Jamie Madill0c8abca2016-07-22 20:21:26 -04001822 if (textureFormatOut)
1823 {
1824 *textureFormatOut = texture->getFormat(target, level);
1825 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001826 return true;
1827}
1828
Jamie Madillf25855c2015-11-03 11:06:18 -05001829static bool ValidateDrawBase(ValidationContext *context,
1830 GLenum mode,
1831 GLsizei count,
1832 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001833{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001834 switch (mode)
1835 {
1836 case GL_POINTS:
1837 case GL_LINES:
1838 case GL_LINE_LOOP:
1839 case GL_LINE_STRIP:
1840 case GL_TRIANGLES:
1841 case GL_TRIANGLE_STRIP:
1842 case GL_TRIANGLE_FAN:
1843 break;
1844 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001845 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001846 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001847 }
1848
Jamie Madill250d33f2014-06-06 17:09:03 -04001849 if (count < 0)
1850 {
Jamie Madill437fa652016-05-03 15:13:24 -04001851 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001852 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001853 }
1854
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001855 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04001856
Jamie Madill250d33f2014-06-06 17:09:03 -04001857 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001858 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001859 {
Jamie Madill437fa652016-05-03 15:13:24 -04001860 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001861 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001862 }
1863
Jamie Madill51f40ec2016-06-15 14:06:00 -04001864 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04001865 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001866 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001867 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1868 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1869 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1870 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1871 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1872 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001873 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001874 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1875 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001876 {
1877 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1878 // Section 6.10 of the WebGL 1.0 spec
1879 ERR(
1880 "This ANGLE implementation does not support separate front/back stencil "
1881 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04001882 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04001883 return false;
1884 }
Jamie Madillac528012014-06-20 13:21:23 -04001885 }
1886
Jamie Madill51f40ec2016-06-15 14:06:00 -04001887 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001888 {
Jamie Madill437fa652016-05-03 15:13:24 -04001889 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001890 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001891 }
1892
Geoff Lang7dd2e102014-11-10 15:19:26 -05001893 gl::Program *program = state.getProgram();
1894 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001895 {
Jamie Madill437fa652016-05-03 15:13:24 -04001896 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001897 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001898 }
1899
Geoff Lang7dd2e102014-11-10 15:19:26 -05001900 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001901 {
Jamie Madill437fa652016-05-03 15:13:24 -04001902 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001903 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001904 }
1905
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001906 // Uniform buffer validation
1907 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1908 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001909 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001910 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001911 const OffsetBindingPointer<Buffer> &uniformBuffer =
1912 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001913
Geoff Lang5d124a62015-09-15 13:03:27 -04001914 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001915 {
1916 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001917 context->handleError(
1918 Error(GL_INVALID_OPERATION,
1919 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001920 return false;
1921 }
1922
Geoff Lang5d124a62015-09-15 13:03:27 -04001923 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001924 if (uniformBufferSize == 0)
1925 {
1926 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001927 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001928 }
1929
Jamie Madill62d31cb2015-09-11 13:25:51 -04001930 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001931 {
1932 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04001933 context->handleError(
1934 Error(GL_INVALID_OPERATION,
1935 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001936 return false;
1937 }
1938 }
1939
Jamie Madill250d33f2014-06-06 17:09:03 -04001940 // No-op if zero count
1941 return (count > 0);
1942}
1943
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001944bool ValidateDrawArrays(ValidationContext *context,
1945 GLenum mode,
1946 GLint first,
1947 GLsizei count,
1948 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001949{
Jamie Madillfd716582014-06-06 17:09:04 -04001950 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001951 {
Jamie Madill437fa652016-05-03 15:13:24 -04001952 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001953 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001954 }
1955
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001956 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001957 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001958 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1959 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001960 {
1961 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1962 // that does not match the current transform feedback object's draw mode (if transform feedback
1963 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04001964 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001965 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001966 }
1967
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001968 if (!ValidateDrawBase(context, mode, count, primcount))
1969 {
1970 return false;
1971 }
1972
1973 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001974 {
1975 return false;
1976 }
1977
1978 return true;
1979}
1980
Geoff Langb1196682014-07-23 13:47:29 -04001981bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001982{
1983 if (primcount < 0)
1984 {
Jamie Madill437fa652016-05-03 15:13:24 -04001985 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001986 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001987 }
1988
Jamie Madill2b976812014-08-25 15:47:49 -04001989 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001990 {
1991 return false;
1992 }
1993
1994 // No-op if zero primitive count
1995 return (primcount > 0);
1996}
1997
Geoff Lang87a93302014-09-16 13:29:43 -04001998static bool ValidateDrawInstancedANGLE(Context *context)
1999{
2000 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002001 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04002002
Geoff Lang7dd2e102014-11-10 15:19:26 -05002003 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04002004
2005 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04002006 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04002007 {
2008 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04002009 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04002010 {
2011 return true;
2012 }
2013 }
2014
Jamie Madill437fa652016-05-03 15:13:24 -04002015 context->handleError(Error(GL_INVALID_OPERATION,
2016 "ANGLE_instanced_arrays requires that at least one active attribute"
2017 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04002018 return false;
2019}
2020
2021bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
2022{
2023 if (!ValidateDrawInstancedANGLE(context))
2024 {
2025 return false;
2026 }
2027
2028 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
2029}
2030
Jamie Madillf25855c2015-11-03 11:06:18 -05002031bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002032 GLenum mode,
2033 GLsizei count,
2034 GLenum type,
2035 const GLvoid *indices,
2036 GLsizei primcount,
2037 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002038{
Jamie Madill250d33f2014-06-06 17:09:03 -04002039 switch (type)
2040 {
2041 case GL_UNSIGNED_BYTE:
2042 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03002043 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002044 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03002045 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2046 {
2047 context->handleError(Error(GL_INVALID_ENUM));
2048 return false;
2049 }
2050 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002051 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002052 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03002053 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002054 }
2055
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002056 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002057
2058 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002059 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002060 {
2061 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2062 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002063 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002064 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002065 }
2066
2067 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002068 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002069 {
Jamie Madill437fa652016-05-03 15:13:24 -04002070 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002071 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002072 }
2073
Jamie Madill2b976812014-08-25 15:47:49 -04002074 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002075 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002076 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002077 {
Jamie Madill437fa652016-05-03 15:13:24 -04002078 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002079 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002080 }
2081
Jamie Madillae3000b2014-08-25 15:47:51 -04002082 if (elementArrayBuffer)
2083 {
2084 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2085
2086 GLint64 offset = reinterpret_cast<GLint64>(indices);
2087 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2088
2089 // check for integer overflows
2090 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2091 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2092 {
Jamie Madill437fa652016-05-03 15:13:24 -04002093 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002094 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002095 }
2096
2097 // Check for reading past the end of the bound buffer object
2098 if (byteCount > elementArrayBuffer->getSize())
2099 {
Jamie Madill437fa652016-05-03 15:13:24 -04002100 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002101 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002102 }
2103 }
2104 else if (!indices)
2105 {
2106 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002107 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002108 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002109 }
2110
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002111 if (!ValidateDrawBase(context, mode, count, primcount))
2112 {
2113 return false;
2114 }
2115
Jamie Madill2b976812014-08-25 15:47:49 -04002116 // Use max index to validate if our vertex buffers are large enough for the pull.
2117 // TODO: offer fast path, with disabled index validation.
2118 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2119 if (elementArrayBuffer)
2120 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002121 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002122 Error error =
2123 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2124 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002125 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002126 {
Jamie Madill437fa652016-05-03 15:13:24 -04002127 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002128 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002129 }
2130 }
2131 else
2132 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002133 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002134 }
2135
Jamie Madille79b1e12015-11-04 16:36:37 -05002136 // If we use an index greater than our maximum supported index range, return an error.
2137 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2138 // return an error if possible here.
2139 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2140 {
Jamie Madill437fa652016-05-03 15:13:24 -04002141 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002142 return false;
2143 }
2144
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002145 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002146 {
2147 return false;
2148 }
2149
Geoff Lang3edfe032015-09-04 16:38:24 -04002150 // No op if there are no real indices in the index data (all are primitive restart).
2151 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002152}
2153
Geoff Langb1196682014-07-23 13:47:29 -04002154bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002155 GLenum mode,
2156 GLsizei count,
2157 GLenum type,
2158 const GLvoid *indices,
2159 GLsizei primcount,
2160 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002161{
2162 if (primcount < 0)
2163 {
Jamie Madill437fa652016-05-03 15:13:24 -04002164 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002165 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002166 }
2167
Jamie Madill2b976812014-08-25 15:47:49 -04002168 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002169 {
2170 return false;
2171 }
2172
2173 // No-op zero primitive count
2174 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002175}
2176
Geoff Lang3edfe032015-09-04 16:38:24 -04002177bool ValidateDrawElementsInstancedANGLE(Context *context,
2178 GLenum mode,
2179 GLsizei count,
2180 GLenum type,
2181 const GLvoid *indices,
2182 GLsizei primcount,
2183 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002184{
2185 if (!ValidateDrawInstancedANGLE(context))
2186 {
2187 return false;
2188 }
2189
2190 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2191}
2192
Geoff Langb1196682014-07-23 13:47:29 -04002193bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002194 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002195{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002196 if (!ValidFramebufferTarget(target))
2197 {
Jamie Madill437fa652016-05-03 15:13:24 -04002198 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002199 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002200 }
2201
2202 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002203 {
2204 return false;
2205 }
2206
Jamie Madill55ec3b12014-07-03 10:38:57 -04002207 if (texture != 0)
2208 {
2209 gl::Texture *tex = context->getTexture(texture);
2210
2211 if (tex == NULL)
2212 {
Jamie Madill437fa652016-05-03 15:13:24 -04002213 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002214 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002215 }
2216
2217 if (level < 0)
2218 {
Jamie Madill437fa652016-05-03 15:13:24 -04002219 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002220 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002221 }
2222 }
2223
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002224 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002225 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002226
Jamie Madill84115c92015-04-23 15:00:07 -04002227 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002228 {
Jamie Madill437fa652016-05-03 15:13:24 -04002229 context->handleError(
2230 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002231 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002232 }
2233
2234 return true;
2235}
2236
Geoff Langb1196682014-07-23 13:47:29 -04002237bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002238 GLenum textarget, GLuint texture, GLint level)
2239{
Geoff Lang95663912015-04-02 15:54:45 -04002240 // 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 +03002241 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2242 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002243 {
Jamie Madill437fa652016-05-03 15:13:24 -04002244 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002245 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002246 }
2247
2248 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002249 {
2250 return false;
2251 }
2252
Jamie Madill55ec3b12014-07-03 10:38:57 -04002253 if (texture != 0)
2254 {
2255 gl::Texture *tex = context->getTexture(texture);
2256 ASSERT(tex);
2257
Jamie Madill2a6564e2014-07-11 09:53:19 -04002258 const gl::Caps &caps = context->getCaps();
2259
Jamie Madill55ec3b12014-07-03 10:38:57 -04002260 switch (textarget)
2261 {
2262 case GL_TEXTURE_2D:
2263 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002264 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002265 {
Jamie Madill437fa652016-05-03 15:13:24 -04002266 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002267 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002268 }
2269 if (tex->getTarget() != GL_TEXTURE_2D)
2270 {
Jamie Madill437fa652016-05-03 15:13:24 -04002271 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002272 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002273 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002274 }
2275 break;
2276
2277 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2278 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2279 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2280 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2281 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2282 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2283 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002284 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002285 {
Jamie Madill437fa652016-05-03 15:13:24 -04002286 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002287 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002288 }
2289 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2290 {
Jamie Madill437fa652016-05-03 15:13:24 -04002291 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002292 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002293 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002294 }
2295 break;
2296
2297 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002298 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002299 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002300 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002301
Jamie Madilla3944d42016-07-22 22:13:26 -04002302 const Format &format = tex->getFormat(textarget, level);
2303 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05002304 {
Jamie Madill437fa652016-05-03 15:13:24 -04002305 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002306 return false;
2307 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002308 }
2309
Jamie Madill570f7c82014-07-03 10:38:54 -04002310 return true;
2311}
2312
Geoff Langb1196682014-07-23 13:47:29 -04002313bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002314{
2315 if (program == 0)
2316 {
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 Madill0063c512014-08-25 15:47:53 -04002319 }
2320
Dian Xiang769769a2015-09-09 15:20:08 -07002321 gl::Program *programObject = GetValidProgram(context, program);
2322 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002323 {
2324 return false;
2325 }
2326
Jamie Madill0063c512014-08-25 15:47:53 -04002327 if (!programObject || !programObject->isLinked())
2328 {
Jamie Madill437fa652016-05-03 15:13:24 -04002329 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002330 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002331 }
2332
Geoff Lang7dd2e102014-11-10 15:19:26 -05002333 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002334 {
Jamie Madill437fa652016-05-03 15:13:24 -04002335 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002336 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002337 }
2338
Jamie Madill0063c512014-08-25 15:47:53 -04002339 return true;
2340}
2341
Geoff Langb1196682014-07-23 13:47:29 -04002342bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002343{
2344 return ValidateGetUniformBase(context, program, location);
2345}
2346
Geoff Langb1196682014-07-23 13:47:29 -04002347bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002348{
Jamie Madill78f41802014-08-25 15:47:55 -04002349 return ValidateGetUniformBase(context, program, location);
2350}
2351
Geoff Langb1196682014-07-23 13:47:29 -04002352static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002353{
2354 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002355 {
Jamie Madill78f41802014-08-25 15:47:55 -04002356 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002357 }
2358
Jamie Madilla502c742014-08-28 17:19:13 -04002359 gl::Program *programObject = context->getProgram(program);
2360 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002361
Jamie Madill78f41802014-08-25 15:47:55 -04002362 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002363 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2364 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002365 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002366 {
Jamie Madill437fa652016-05-03 15:13:24 -04002367 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002368 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002369 }
2370
2371 return true;
2372}
2373
Geoff Langb1196682014-07-23 13:47:29 -04002374bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002375{
Jamie Madill78f41802014-08-25 15:47:55 -04002376 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002377}
2378
Geoff Langb1196682014-07-23 13:47:29 -04002379bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002380{
Jamie Madill78f41802014-08-25 15:47:55 -04002381 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002382}
2383
Austin Kinross08332632015-05-05 13:35:47 -07002384bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2385 const GLenum *attachments, bool defaultFramebuffer)
2386{
2387 if (numAttachments < 0)
2388 {
Jamie Madill437fa652016-05-03 15:13:24 -04002389 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002390 return false;
2391 }
2392
2393 for (GLsizei i = 0; i < numAttachments; ++i)
2394 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002395 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002396 {
2397 if (defaultFramebuffer)
2398 {
Jamie Madill437fa652016-05-03 15:13:24 -04002399 context->handleError(Error(
2400 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002401 return false;
2402 }
2403
2404 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2405 {
Jamie Madill437fa652016-05-03 15:13:24 -04002406 context->handleError(Error(GL_INVALID_OPERATION,
2407 "Requested color attachment is greater than the maximum "
2408 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002409 return false;
2410 }
2411 }
2412 else
2413 {
2414 switch (attachments[i])
2415 {
2416 case GL_DEPTH_ATTACHMENT:
2417 case GL_STENCIL_ATTACHMENT:
2418 case GL_DEPTH_STENCIL_ATTACHMENT:
2419 if (defaultFramebuffer)
2420 {
Jamie Madill437fa652016-05-03 15:13:24 -04002421 context->handleError(
2422 Error(GL_INVALID_ENUM,
2423 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002424 return false;
2425 }
2426 break;
2427 case GL_COLOR:
2428 case GL_DEPTH:
2429 case GL_STENCIL:
2430 if (!defaultFramebuffer)
2431 {
Jamie Madill437fa652016-05-03 15:13:24 -04002432 context->handleError(
2433 Error(GL_INVALID_ENUM,
2434 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002435 return false;
2436 }
2437 break;
2438 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002439 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002440 return false;
2441 }
2442 }
2443 }
2444
2445 return true;
2446}
2447
Austin Kinross6ee1e782015-05-29 17:05:37 -07002448bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2449{
2450 // Note that debug marker calls must not set error state
2451
2452 if (length < 0)
2453 {
2454 return false;
2455 }
2456
2457 if (marker == nullptr)
2458 {
2459 return false;
2460 }
2461
2462 return true;
2463}
2464
2465bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2466{
2467 // Note that debug marker calls must not set error state
2468
2469 if (length < 0)
2470 {
2471 return false;
2472 }
2473
2474 if (length > 0 && marker == nullptr)
2475 {
2476 return false;
2477 }
2478
2479 return true;
2480}
2481
Geoff Langdcab33b2015-07-21 13:03:16 -04002482bool ValidateEGLImageTargetTexture2DOES(Context *context,
2483 egl::Display *display,
2484 GLenum target,
2485 egl::Image *image)
2486{
Geoff Langa8406172015-07-21 16:53:39 -04002487 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2488 {
Jamie Madill437fa652016-05-03 15:13:24 -04002489 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002490 return false;
2491 }
2492
2493 switch (target)
2494 {
2495 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002496 if (!context->getExtensions().eglImage)
2497 {
2498 context->handleError(Error(
2499 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2500 }
2501 break;
2502
2503 case GL_TEXTURE_EXTERNAL_OES:
2504 if (!context->getExtensions().eglImageExternal)
2505 {
2506 context->handleError(Error(
2507 GL_INVALID_ENUM,
2508 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2509 }
Geoff Langa8406172015-07-21 16:53:39 -04002510 break;
2511
2512 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002513 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002514 return false;
2515 }
2516
2517 if (!display->isValidImage(image))
2518 {
Jamie Madill437fa652016-05-03 15:13:24 -04002519 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002520 return false;
2521 }
2522
2523 if (image->getSamples() > 0)
2524 {
Jamie Madill437fa652016-05-03 15:13:24 -04002525 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002526 "cannot create a 2D texture from a multisampled EGL image."));
2527 return false;
2528 }
2529
Jamie Madilla3944d42016-07-22 22:13:26 -04002530 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002531 if (!textureCaps.texturable)
2532 {
Jamie Madill437fa652016-05-03 15:13:24 -04002533 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002534 "EGL image internal format is not supported as a texture."));
2535 return false;
2536 }
2537
Geoff Langdcab33b2015-07-21 13:03:16 -04002538 return true;
2539}
2540
2541bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2542 egl::Display *display,
2543 GLenum target,
2544 egl::Image *image)
2545{
Geoff Langa8406172015-07-21 16:53:39 -04002546 if (!context->getExtensions().eglImage)
2547 {
Jamie Madill437fa652016-05-03 15:13:24 -04002548 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002549 return false;
2550 }
2551
2552 switch (target)
2553 {
2554 case GL_RENDERBUFFER:
2555 break;
2556
2557 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002558 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002559 return false;
2560 }
2561
2562 if (!display->isValidImage(image))
2563 {
Jamie Madill437fa652016-05-03 15:13:24 -04002564 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002565 return false;
2566 }
2567
Jamie Madilla3944d42016-07-22 22:13:26 -04002568 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002569 if (!textureCaps.renderable)
2570 {
Jamie Madill437fa652016-05-03 15:13:24 -04002571 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002572 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2573 return false;
2574 }
2575
Geoff Langdcab33b2015-07-21 13:03:16 -04002576 return true;
2577}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002578
2579bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2580{
Geoff Lang36167ab2015-12-07 10:27:14 -05002581 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002582 {
2583 // The default VAO should always exist
2584 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002585 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002586 return false;
2587 }
2588
2589 return true;
2590}
2591
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002592bool ValidateLinkProgram(Context *context, GLuint program)
2593{
2594 if (context->hasActiveTransformFeedback(program))
2595 {
2596 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002597 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002598 "Cannot link program while program is associated with an active "
2599 "transform feedback object."));
2600 return false;
2601 }
2602 return true;
2603}
2604
Geoff Langc5629752015-12-07 16:29:04 -05002605bool ValidateProgramBinaryBase(Context *context,
2606 GLuint program,
2607 GLenum binaryFormat,
2608 const void *binary,
2609 GLint length)
2610{
2611 Program *programObject = GetValidProgram(context, program);
2612 if (programObject == nullptr)
2613 {
2614 return false;
2615 }
2616
2617 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2618 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2619 programBinaryFormats.end())
2620 {
Jamie Madill437fa652016-05-03 15:13:24 -04002621 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05002622 return false;
2623 }
2624
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002625 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 change program binary while program is associated with "
2630 "an active transform feedback object."));
2631 return false;
2632 }
2633
Geoff Langc5629752015-12-07 16:29:04 -05002634 return true;
2635}
2636
2637bool ValidateGetProgramBinaryBase(Context *context,
2638 GLuint program,
2639 GLsizei bufSize,
2640 GLsizei *length,
2641 GLenum *binaryFormat,
2642 void *binary)
2643{
2644 Program *programObject = GetValidProgram(context, program);
2645 if (programObject == nullptr)
2646 {
2647 return false;
2648 }
2649
2650 if (!programObject->isLinked())
2651 {
Jamie Madill437fa652016-05-03 15:13:24 -04002652 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05002653 return false;
2654 }
2655
2656 return true;
2657}
Jamie Madillc29968b2016-01-20 11:17:23 -05002658
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002659bool ValidateUseProgram(Context *context, GLuint program)
2660{
2661 if (program != 0)
2662 {
2663 Program *programObject = context->getProgram(program);
2664 if (!programObject)
2665 {
2666 // ES 3.1.0 section 7.3 page 72
2667 if (context->getShader(program))
2668 {
Jamie Madill437fa652016-05-03 15:13:24 -04002669 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002670 Error(GL_INVALID_OPERATION,
2671 "Attempted to use a single shader instead of a shader program."));
2672 return false;
2673 }
2674 else
2675 {
Jamie Madill437fa652016-05-03 15:13:24 -04002676 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002677 return false;
2678 }
2679 }
2680 if (!programObject->isLinked())
2681 {
Jamie Madill437fa652016-05-03 15:13:24 -04002682 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002683 return false;
2684 }
2685 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002686 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002687 {
2688 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002689 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002690 Error(GL_INVALID_OPERATION,
2691 "Cannot change active program while transform feedback is unpaused."));
2692 return false;
2693 }
2694
2695 return true;
2696}
2697
Jamie Madillc29968b2016-01-20 11:17:23 -05002698bool ValidateCopyTexImage2D(ValidationContext *context,
2699 GLenum target,
2700 GLint level,
2701 GLenum internalformat,
2702 GLint x,
2703 GLint y,
2704 GLsizei width,
2705 GLsizei height,
2706 GLint border)
2707{
Martin Radev1be913c2016-07-11 17:59:16 +03002708 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002709 {
2710 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2711 0, x, y, width, height, border);
2712 }
2713
Martin Radev1be913c2016-07-11 17:59:16 +03002714 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002715 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2716 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002717}
Jamie Madillc29968b2016-01-20 11:17:23 -05002718
2719bool ValidateFramebufferRenderbuffer(Context *context,
2720 GLenum target,
2721 GLenum attachment,
2722 GLenum renderbuffertarget,
2723 GLuint renderbuffer)
2724{
2725 if (!ValidFramebufferTarget(target) ||
2726 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2727 {
Jamie Madill437fa652016-05-03 15:13:24 -04002728 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05002729 return false;
2730 }
2731
2732 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2733 renderbuffertarget, renderbuffer);
2734}
2735
2736bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2737{
2738 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2739 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2740 {
Jamie Madill437fa652016-05-03 15:13:24 -04002741 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002742 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2743 return false;
2744 }
2745
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002746 ASSERT(context->getGLState().getDrawFramebuffer());
2747 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05002748 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2749
2750 // This should come first before the check for the default frame buffer
2751 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2752 // rather than INVALID_OPERATION
2753 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2754 {
2755 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2756
2757 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002758 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2759 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002760 {
2761 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002762 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2763 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2764 // 3.1 is still a bit ambiguous about the error, but future specs are
2765 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04002766 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02002767 return false;
2768 }
2769 else if (bufs[colorAttachment] >= maxColorAttachment)
2770 {
Jamie Madill437fa652016-05-03 15:13:24 -04002771 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02002772 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002773 return false;
2774 }
2775 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2776 frameBufferId != 0)
2777 {
2778 // INVALID_OPERATION-GL is bound to buffer and ith argument
2779 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04002780 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05002781 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2782 return false;
2783 }
2784 }
2785
2786 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2787 // and n is not 1 or bufs is bound to value other than BACK and NONE
2788 if (frameBufferId == 0)
2789 {
2790 if (n != 1)
2791 {
Jamie Madill437fa652016-05-03 15:13:24 -04002792 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05002793 "n must be 1 when GL is bound to the default framebuffer"));
2794 return false;
2795 }
2796
2797 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2798 {
Jamie Madill437fa652016-05-03 15:13:24 -04002799 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05002800 GL_INVALID_OPERATION,
2801 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2802 return false;
2803 }
2804 }
2805
2806 return true;
2807}
2808
2809bool ValidateCopyTexSubImage2D(Context *context,
2810 GLenum target,
2811 GLint level,
2812 GLint xoffset,
2813 GLint yoffset,
2814 GLint x,
2815 GLint y,
2816 GLsizei width,
2817 GLsizei height)
2818{
Martin Radev1be913c2016-07-11 17:59:16 +03002819 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05002820 {
2821 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2822 yoffset, x, y, width, height, 0);
2823 }
2824
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002825 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2826 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002827}
2828
Olli Etuaho4f667482016-03-30 15:56:35 +03002829bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2830{
2831 if (!ValidBufferTarget(context, target))
2832 {
Jamie Madill437fa652016-05-03 15:13:24 -04002833 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03002834 return false;
2835 }
2836
2837 if (pname != GL_BUFFER_MAP_POINTER)
2838 {
Jamie Madill437fa652016-05-03 15:13:24 -04002839 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03002840 return false;
2841 }
2842
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002843 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002844
2845 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2846 // target bound to zero generate an INVALID_OPERATION error."
2847 // GLES 3.1 section 6.6 explicitly specifies this error.
2848 if (!buffer)
2849 {
Jamie Madill437fa652016-05-03 15:13:24 -04002850 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002851 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2852 return false;
2853 }
2854
2855 return true;
2856}
2857
2858bool ValidateUnmapBufferBase(Context *context, GLenum target)
2859{
2860 if (!ValidBufferTarget(context, target))
2861 {
Jamie Madill437fa652016-05-03 15:13:24 -04002862 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002863 return false;
2864 }
2865
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002866 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002867
2868 if (buffer == nullptr || !buffer->isMapped())
2869 {
Jamie Madill437fa652016-05-03 15:13:24 -04002870 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002871 return false;
2872 }
2873
2874 return true;
2875}
2876
2877bool ValidateMapBufferRangeBase(Context *context,
2878 GLenum target,
2879 GLintptr offset,
2880 GLsizeiptr length,
2881 GLbitfield access)
2882{
2883 if (!ValidBufferTarget(context, target))
2884 {
Jamie Madill437fa652016-05-03 15:13:24 -04002885 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002886 return false;
2887 }
2888
2889 if (offset < 0 || length < 0)
2890 {
Jamie Madill437fa652016-05-03 15:13:24 -04002891 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002892 return false;
2893 }
2894
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002895 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002896
2897 if (!buffer)
2898 {
Jamie Madill437fa652016-05-03 15:13:24 -04002899 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002900 return false;
2901 }
2902
2903 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002904 CheckedNumeric<size_t> checkedOffset(offset);
2905 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03002906
Jamie Madille2e406c2016-06-02 13:04:10 -04002907 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03002908 {
Jamie Madill437fa652016-05-03 15:13:24 -04002909 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002910 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2911 return false;
2912 }
2913
2914 // Check for invalid bits in the mask
2915 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2916 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2917 GL_MAP_UNSYNCHRONIZED_BIT;
2918
2919 if (access & ~(allAccessBits))
2920 {
Jamie Madill437fa652016-05-03 15:13:24 -04002921 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03002922 return false;
2923 }
2924
2925 if (length == 0)
2926 {
Jamie Madill437fa652016-05-03 15:13:24 -04002927 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002928 return false;
2929 }
2930
2931 if (buffer->isMapped())
2932 {
Jamie Madill437fa652016-05-03 15:13:24 -04002933 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002934 return false;
2935 }
2936
2937 // Check for invalid bit combinations
2938 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2939 {
Jamie Madill437fa652016-05-03 15:13:24 -04002940 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03002941 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2942 return false;
2943 }
2944
2945 GLbitfield writeOnlyBits =
2946 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2947
2948 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2949 {
Jamie Madill437fa652016-05-03 15:13:24 -04002950 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03002951 "Invalid access bits when mapping buffer for reading: 0x%X.",
2952 access));
2953 return false;
2954 }
2955
2956 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2957 {
Jamie Madill437fa652016-05-03 15:13:24 -04002958 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002959 GL_INVALID_OPERATION,
2960 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2961 return false;
2962 }
2963 return true;
2964}
2965
2966bool ValidateFlushMappedBufferRangeBase(Context *context,
2967 GLenum target,
2968 GLintptr offset,
2969 GLsizeiptr length)
2970{
2971 if (offset < 0 || length < 0)
2972 {
Jamie Madill437fa652016-05-03 15:13:24 -04002973 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002974 return false;
2975 }
2976
2977 if (!ValidBufferTarget(context, target))
2978 {
Jamie Madill437fa652016-05-03 15:13:24 -04002979 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002980 return false;
2981 }
2982
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002983 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03002984
2985 if (buffer == nullptr)
2986 {
Jamie Madill437fa652016-05-03 15:13:24 -04002987 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03002988 return false;
2989 }
2990
2991 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2992 {
Jamie Madill437fa652016-05-03 15:13:24 -04002993 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03002994 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2995 return false;
2996 }
2997
2998 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04002999 CheckedNumeric<size_t> checkedOffset(offset);
3000 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003001
Jamie Madille2e406c2016-06-02 13:04:10 -04003002 if (!checkedSize.IsValid() ||
3003 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003004 {
Jamie Madill437fa652016-05-03 15:13:24 -04003005 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003006 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
3007 return false;
3008 }
3009
3010 return true;
3011}
3012
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003013bool ValidateGenerateMipmap(Context *context, GLenum target)
3014{
3015 if (!ValidTextureTarget(context, target))
3016 {
3017 context->handleError(Error(GL_INVALID_ENUM));
3018 return false;
3019 }
3020
3021 Texture *texture = context->getTargetTexture(target);
3022
3023 if (texture == nullptr)
3024 {
3025 context->handleError(Error(GL_INVALID_OPERATION));
3026 return false;
3027 }
3028
3029 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
3030
3031 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
3032 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
3033 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3034 {
3035 context->handleError(Error(GL_INVALID_OPERATION));
3036 return false;
3037 }
3038
Jamie Madilla3944d42016-07-22 22:13:26 -04003039 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
3040 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
3041 const TextureCaps &formatCaps = context->getTextureCaps().get(format.asSized());
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003042
3043 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
3044 // unsized formats or that are color renderable and filterable. Since we do not track if
3045 // the texture was created with sized or unsized format (only sized formats are stored),
3046 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
3047 // be able to) because they aren't color renderable. Simply do a special case for LUMA
3048 // textures since they're the only texture format that can be created with unsized formats
3049 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
3050 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04003051 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
3052 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003053 {
3054 context->handleError(Error(GL_INVALID_OPERATION));
3055 return false;
3056 }
3057
3058 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04003059 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003060 {
3061 context->handleError(Error(GL_INVALID_OPERATION));
3062 return false;
3063 }
3064
3065 // Non-power of 2 ES2 check
3066 if (!context->getExtensions().textureNPOT &&
3067 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3068 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3069 {
Martin Radev1be913c2016-07-11 17:59:16 +03003070 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003071 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3072 context->handleError(Error(GL_INVALID_OPERATION));
3073 return false;
3074 }
3075
3076 // Cube completeness check
3077 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3078 {
3079 context->handleError(Error(GL_INVALID_OPERATION));
3080 return false;
3081 }
3082
3083 return true;
3084}
3085
Olli Etuaho41997e72016-03-10 13:38:39 +02003086bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3087{
3088 return ValidateGenOrDelete(context, n);
3089}
3090
3091bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3092{
3093 return ValidateGenOrDelete(context, n);
3094}
3095
3096bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3097{
3098 return ValidateGenOrDelete(context, n);
3099}
3100
3101bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3102{
3103 return ValidateGenOrDelete(context, n);
3104}
3105
3106bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3107{
3108 return ValidateGenOrDelete(context, n);
3109}
3110
3111bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3112{
3113 return ValidateGenOrDelete(context, n);
3114}
3115
3116bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3117{
3118 return ValidateGenOrDelete(context, n);
3119}
3120
3121bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3122{
3123 return ValidateGenOrDelete(context, n);
3124}
3125
3126bool ValidateGenOrDelete(Context *context, GLint n)
3127{
3128 if (n < 0)
3129 {
Jamie Madill437fa652016-05-03 15:13:24 -04003130 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003131 return false;
3132 }
3133 return true;
3134}
3135
Jamie Madillc29968b2016-01-20 11:17:23 -05003136} // namespace gl