blob: d3efd918097711214530c7b447d07fc8aa2a4554 [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"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040071 GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
Jamie Madill1ca74672015-07-21 15:14:11 -040072
73 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
74 // We can return INVALID_OPERATION if our vertex attribute does not have
75 // enough backing data.
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040076 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040077 {
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040078 context->recordError(
79 Error(GL_INVALID_OPERATION,
80 "Vertex buffer is not big enough for the draw call"));
Jamie Madill1ca74672015-07-21 15:14:11 -040081 return false;
82 }
83 }
84 }
85 else if (attrib.pointer == NULL)
86 {
87 // This is an application error that would normally result in a crash,
88 // but we catch it and return an error
89 context->recordError(Error(
90 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
91 return false;
92 }
93 }
94 }
95
96 return true;
97}
98
99} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400100
Geoff Lang0550d032014-01-30 11:29:07 -0500101bool ValidCap(const Context *context, GLenum cap)
102{
103 switch (cap)
104 {
105 case GL_CULL_FACE:
106 case GL_POLYGON_OFFSET_FILL:
107 case GL_SAMPLE_ALPHA_TO_COVERAGE:
108 case GL_SAMPLE_COVERAGE:
109 case GL_SCISSOR_TEST:
110 case GL_STENCIL_TEST:
111 case GL_DEPTH_TEST:
112 case GL_BLEND:
113 case GL_DITHER:
114 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500115
Geoff Lang0550d032014-01-30 11:29:07 -0500116 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
117 case GL_RASTERIZER_DISCARD:
118 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500119
120 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
121 case GL_DEBUG_OUTPUT:
122 return context->getExtensions().debug;
123
Geoff Lang0550d032014-01-30 11:29:07 -0500124 default:
125 return false;
126 }
127}
128
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500129bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400130{
Jamie Madilld7460c72014-01-21 16:38:14 -0500131 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400132 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500133 case GL_TEXTURE_2D:
134 case GL_TEXTURE_CUBE_MAP:
135 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400136
Jamie Madilld7460c72014-01-21 16:38:14 -0500137 case GL_TEXTURE_3D:
138 case GL_TEXTURE_2D_ARRAY:
139 return (context->getClientVersion() >= 3);
140
141 default:
142 return false;
143 }
Jamie Madill35d15012013-10-07 10:46:37 -0400144}
145
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500146bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
147{
148 switch (target)
149 {
150 case GL_TEXTURE_2D:
151 case GL_TEXTURE_CUBE_MAP:
152 return true;
153
154 default:
155 return false;
156 }
157}
158
159bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
160{
161 switch (target)
162 {
163 case GL_TEXTURE_3D:
164 case GL_TEXTURE_2D_ARRAY:
165 return (context->getClientVersion() >= 3);
166
167 default:
168 return false;
169 }
170}
171
Shannon Woods4dfed832014-03-17 20:03:39 -0400172// This function differs from ValidTextureTarget in that the target must be
173// usable as the destination of a 2D operation-- so a cube face is valid, but
174// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400175// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500176bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400177{
178 switch (target)
179 {
180 case GL_TEXTURE_2D:
181 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
182 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
183 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
184 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
185 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
186 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
187 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500188 default:
189 return false;
190 }
191}
192
193bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
194{
195 switch (target)
196 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400197 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500198 case GL_TEXTURE_2D_ARRAY:
199 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400200 default:
201 return false;
202 }
203}
204
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500205bool ValidFramebufferTarget(GLenum target)
206{
Geoff Langd4475812015-03-18 10:53:05 -0400207 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
208 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500209
210 switch (target)
211 {
212 case GL_FRAMEBUFFER: return true;
213 case GL_READ_FRAMEBUFFER: return true;
214 case GL_DRAW_FRAMEBUFFER: return true;
215 default: return false;
216 }
217}
218
Jamie Madill8c96d582014-03-05 15:01:23 -0500219bool ValidBufferTarget(const Context *context, GLenum target)
220{
221 switch (target)
222 {
223 case GL_ARRAY_BUFFER:
224 case GL_ELEMENT_ARRAY_BUFFER:
225 return true;
226
Jamie Madill8c96d582014-03-05 15:01:23 -0500227 case GL_PIXEL_PACK_BUFFER:
228 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400229 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400230
Shannon Woodsb3801742014-03-27 14:59:19 -0400231 case GL_COPY_READ_BUFFER:
232 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500233 case GL_TRANSFORM_FEEDBACK_BUFFER:
234 case GL_UNIFORM_BUFFER:
235 return (context->getClientVersion() >= 3);
236
237 default:
238 return false;
239 }
240}
241
Jamie Madill70656a62014-03-05 15:01:26 -0500242bool ValidBufferParameter(const Context *context, GLenum pname)
243{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400244 const Extensions &extensions = context->getExtensions();
245
Jamie Madill70656a62014-03-05 15:01:26 -0500246 switch (pname)
247 {
248 case GL_BUFFER_USAGE:
249 case GL_BUFFER_SIZE:
250 return true;
251
Geoff Langcc6f55d2015-03-20 13:01:02 -0400252 case GL_BUFFER_ACCESS_OES:
253 return extensions.mapBuffer;
254
255 case GL_BUFFER_MAPPED:
256 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
257 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
258
Jamie Madill70656a62014-03-05 15:01:26 -0500259 // GL_BUFFER_MAP_POINTER is a special case, and may only be
260 // queried with GetBufferPointerv
261 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500262 case GL_BUFFER_MAP_OFFSET:
263 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400264 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500265
266 default:
267 return false;
268 }
269}
270
Jamie Madillc29968b2016-01-20 11:17:23 -0500271bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400272{
Jamie Madillc29968b2016-01-20 11:17:23 -0500273 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400274 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400275 switch (target)
276 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500277 case GL_TEXTURE_2D:
278 maxDimension = caps.max2DTextureSize;
279 break;
Geoff Langce635692013-09-24 13:56:32 -0400280 case GL_TEXTURE_CUBE_MAP:
281 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
282 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
283 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
284 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
285 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500286 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
287 maxDimension = caps.maxCubeMapTextureSize;
288 break;
289 case GL_TEXTURE_3D:
290 maxDimension = caps.max3DTextureSize;
291 break;
292 case GL_TEXTURE_2D_ARRAY:
293 maxDimension = caps.max2DTextureSize;
294 break;
Geoff Langce635692013-09-24 13:56:32 -0400295 default: UNREACHABLE();
296 }
297
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700298 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400299}
300
Austin Kinross08528e12015-10-07 16:24:40 -0700301bool ValidImageSizeParameters(const Context *context,
302 GLenum target,
303 GLint level,
304 GLsizei width,
305 GLsizei height,
306 GLsizei depth,
307 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400308{
309 if (level < 0 || width < 0 || height < 0 || depth < 0)
310 {
311 return false;
312 }
313
Austin Kinross08528e12015-10-07 16:24:40 -0700314 // TexSubImage parameters can be NPOT without textureNPOT extension,
315 // as long as the destination texture is POT.
316 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400317 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400318 {
319 return false;
320 }
321
322 if (!ValidMipLevel(context, target, level))
323 {
324 return false;
325 }
326
327 return true;
328}
329
Geoff Lang0d8b7242015-09-09 14:56:53 -0400330bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
331{
332 // List of compressed format that require that the texture size is smaller than or a multiple of
333 // the compressed block size.
334 switch (internalFormat)
335 {
336 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
337 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
338 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
339 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800340 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400341 return true;
342
343 default:
344 return false;
345 }
346}
347
Jamie Madillc29968b2016-01-20 11:17:23 -0500348bool ValidCompressedImageSize(const ValidationContext *context,
349 GLenum internalFormat,
350 GLsizei width,
351 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400352{
Geoff Lang5d601382014-07-22 15:14:06 -0400353 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
354 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400355 {
356 return false;
357 }
358
Geoff Lang0d8b7242015-09-09 14:56:53 -0400359 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400360 {
361 return false;
362 }
363
Geoff Lang0d8b7242015-09-09 14:56:53 -0400364 if (CompressedTextureFormatRequiresExactSize(internalFormat))
365 {
366 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
367 width % formatInfo.compressedBlockWidth != 0) ||
368 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
369 height % formatInfo.compressedBlockHeight != 0))
370 {
371 return false;
372 }
373 }
374
Geoff Langd4f180b2013-09-24 13:57:44 -0400375 return true;
376}
377
Geoff Lang37dde692014-01-31 16:34:54 -0500378bool ValidQueryType(const Context *context, GLenum queryType)
379{
Geoff Langd4475812015-03-18 10:53:05 -0400380 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
381 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 -0500382
383 switch (queryType)
384 {
385 case GL_ANY_SAMPLES_PASSED:
386 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
387 return true;
388 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
389 return (context->getClientVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500390 case GL_TIME_ELAPSED_EXT:
391 return context->getExtensions().disjointTimerQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500392 default:
393 return false;
394 }
395}
396
Dian Xiang769769a2015-09-09 15:20:08 -0700397Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500398{
399 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
400 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
401 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
402
Dian Xiang769769a2015-09-09 15:20:08 -0700403 Program *validProgram = context->getProgram(id);
404
405 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500406 {
Dian Xiang769769a2015-09-09 15:20:08 -0700407 if (context->getShader(id))
408 {
409 context->recordError(
410 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
411 }
412 else
413 {
414 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
415 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500416 }
Dian Xiang769769a2015-09-09 15:20:08 -0700417
418 return validProgram;
419}
420
421Shader *GetValidShader(Context *context, GLuint id)
422{
423 // See ValidProgram for spec details.
424
425 Shader *validShader = context->getShader(id);
426
427 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500428 {
Dian Xiang769769a2015-09-09 15:20:08 -0700429 if (context->getProgram(id))
430 {
431 context->recordError(
432 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
433 }
434 else
435 {
436 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
437 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500438 }
Dian Xiang769769a2015-09-09 15:20:08 -0700439
440 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500441}
442
Geoff Langb1196682014-07-23 13:47:29 -0400443bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400444{
445 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
446 {
447 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
448
Geoff Langaae65a42014-05-26 12:43:44 -0400449 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400450 {
Geoff Langb1196682014-07-23 13:47:29 -0400451 context->recordError(Error(GL_INVALID_VALUE));
452 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400453 }
454 }
455 else
456 {
457 switch (attachment)
458 {
459 case GL_DEPTH_ATTACHMENT:
460 case GL_STENCIL_ATTACHMENT:
461 break;
462
463 case GL_DEPTH_STENCIL_ATTACHMENT:
464 if (context->getClientVersion() < 3)
465 {
Geoff Langb1196682014-07-23 13:47:29 -0400466 context->recordError(Error(GL_INVALID_ENUM));
467 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400468 }
469 break;
470
471 default:
Geoff Langb1196682014-07-23 13:47:29 -0400472 context->recordError(Error(GL_INVALID_ENUM));
473 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400474 }
475 }
476
477 return true;
478}
479
Corentin Walleze0902642014-11-04 12:32:15 -0800480bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
481 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400482{
483 switch (target)
484 {
485 case GL_RENDERBUFFER:
486 break;
487 default:
Geoff Langb1196682014-07-23 13:47:29 -0400488 context->recordError(Error(GL_INVALID_ENUM));
489 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400490 }
491
492 if (width < 0 || height < 0 || samples < 0)
493 {
Geoff Langb1196682014-07-23 13:47:29 -0400494 context->recordError(Error(GL_INVALID_VALUE));
495 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400496 }
497
Geoff Langd87878e2014-09-19 15:42:59 -0400498 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
499 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500 {
Geoff Langb1196682014-07-23 13:47:29 -0400501 context->recordError(Error(GL_INVALID_ENUM));
502 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400503 }
504
505 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
506 // 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 -0800507 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400508 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400509 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400510 {
Geoff Langb1196682014-07-23 13:47:29 -0400511 context->recordError(Error(GL_INVALID_ENUM));
512 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 }
514
Geoff Langaae65a42014-05-26 12:43:44 -0400515 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 {
Geoff Langb1196682014-07-23 13:47:29 -0400517 context->recordError(Error(GL_INVALID_VALUE));
518 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 }
520
Shannon Woods53a94a82014-06-24 15:20:36 -0400521 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 if (handle == 0)
523 {
Geoff Langb1196682014-07-23 13:47:29 -0400524 context->recordError(Error(GL_INVALID_OPERATION));
525 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400526 }
527
528 return true;
529}
530
Corentin Walleze0902642014-11-04 12:32:15 -0800531bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
532 GLenum internalformat, GLsizei width, GLsizei height)
533{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800534 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800535
536 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400537 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800538 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400539 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800540 {
541 context->recordError(Error(GL_INVALID_VALUE));
542 return false;
543 }
544
545 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
546 // the specified storage. This is different than ES 3.0 in which a sample number higher
547 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800548 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
549 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800550 {
Geoff Langa4903b72015-03-02 16:02:48 -0800551 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
552 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
553 {
554 context->recordError(Error(GL_OUT_OF_MEMORY));
555 return false;
556 }
Corentin Walleze0902642014-11-04 12:32:15 -0800557 }
558
559 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
560}
561
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500562bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
563 GLenum renderbuffertarget, GLuint renderbuffer)
564{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400565 if (!ValidFramebufferTarget(target))
566 {
Geoff Langb1196682014-07-23 13:47:29 -0400567 context->recordError(Error(GL_INVALID_ENUM));
568 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400569 }
570
Shannon Woods53a94a82014-06-24 15:20:36 -0400571 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500572
Jamie Madill84115c92015-04-23 15:00:07 -0400573 ASSERT(framebuffer);
574 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500575 {
Jamie Madill84115c92015-04-23 15:00:07 -0400576 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400577 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500578 }
579
Jamie Madillb4472272014-07-03 10:38:55 -0400580 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500581 {
Jamie Madillb4472272014-07-03 10:38:55 -0400582 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500583 }
584
Jamie Madillab9d82c2014-01-21 16:38:14 -0500585 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
586 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
587 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
588 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
589 if (renderbuffer != 0)
590 {
591 if (!context->getRenderbuffer(renderbuffer))
592 {
Geoff Langb1196682014-07-23 13:47:29 -0400593 context->recordError(Error(GL_INVALID_OPERATION));
594 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500595 }
596 }
597
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500598 return true;
599}
600
Jamie Madillc29968b2016-01-20 11:17:23 -0500601bool ValidateBlitFramebufferParameters(gl::Context *context,
602 GLint srcX0,
603 GLint srcY0,
604 GLint srcX1,
605 GLint srcY1,
606 GLint dstX0,
607 GLint dstY0,
608 GLint dstX1,
609 GLint dstY1,
610 GLbitfield mask,
611 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612{
613 switch (filter)
614 {
615 case GL_NEAREST:
616 break;
617 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400618 break;
619 default:
Geoff Langb1196682014-07-23 13:47:29 -0400620 context->recordError(Error(GL_INVALID_ENUM));
621 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622 }
623
624 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
625 {
Geoff Langb1196682014-07-23 13:47:29 -0400626 context->recordError(Error(GL_INVALID_VALUE));
627 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400628 }
629
630 if (mask == 0)
631 {
632 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
633 // buffers are copied.
634 return false;
635 }
636
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
638 // color buffer, leaving only nearest being unfiltered from above
639 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
640 {
Geoff Langb1196682014-07-23 13:47:29 -0400641 context->recordError(Error(GL_INVALID_OPERATION));
642 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400643 }
644
Shannon Woods53a94a82014-06-24 15:20:36 -0400645 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400646 {
Geoff Langb1196682014-07-23 13:47:29 -0400647 context->recordError(Error(GL_INVALID_OPERATION));
648 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649 }
650
Jamie Madille3ef7152015-04-28 16:55:17 +0000651 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
652 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500653
654 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 {
Geoff Langb1196682014-07-23 13:47:29 -0400656 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
657 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400658 }
659
Geoff Lang748f74e2014-12-01 11:25:34 -0500660 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500661 {
662 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
663 return false;
664 }
665
Geoff Lang748f74e2014-12-01 11:25:34 -0500666 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500667 {
668 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
669 return false;
670 }
671
672 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 {
Geoff Langb1196682014-07-23 13:47:29 -0400674 context->recordError(Error(GL_INVALID_OPERATION));
675 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400676 }
677
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400678 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
679
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400680 if (mask & GL_COLOR_BUFFER_BIT)
681 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400682 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
683 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500684 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400685
686 if (readColorBuffer && drawColorBuffer)
687 {
Geoff Langd8a22582014-12-17 15:28:23 -0500688 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400689 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690
Geoff Langa15472a2015-08-11 11:48:03 -0400691 for (size_t drawbufferIdx = 0;
692 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 {
Geoff Langa15472a2015-08-11 11:48:03 -0400694 const FramebufferAttachment *attachment =
695 drawFramebuffer->getDrawBuffer(drawbufferIdx);
696 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697 {
Geoff Langa15472a2015-08-11 11:48:03 -0400698 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400699 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700
Geoff Langb2f3d052013-08-13 12:49:27 -0400701 // The GL ES 3.0.2 spec (pg 193) states that:
702 // 1) If the read buffer is fixed point format, the draw buffer must be as well
703 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
704 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500705 // Changes with EXT_color_buffer_float:
706 // Case 1) is changed to fixed point OR floating point
707 GLenum readComponentType = readFormatInfo.componentType;
708 GLenum drawComponentType = drawFormatInfo.componentType;
709 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
710 readComponentType == GL_SIGNED_NORMALIZED);
711 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
712 drawComponentType == GL_SIGNED_NORMALIZED);
713
714 if (extensions.colorBufferFloat)
715 {
716 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
717 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
718
719 if (readFixedOrFloat != drawFixedOrFloat)
720 {
721 context->recordError(Error(GL_INVALID_OPERATION,
722 "If the read buffer contains fixed-point or "
723 "floating-point values, the draw buffer "
724 "must as well."));
725 return false;
726 }
727 }
728 else if (readFixedPoint != drawFixedPoint)
729 {
730 context->recordError(Error(GL_INVALID_OPERATION,
731 "If the read buffer contains fixed-point "
732 "values, the draw buffer must as well."));
733 return false;
734 }
735
736 if (readComponentType == GL_UNSIGNED_INT &&
737 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400738 {
Geoff Langb1196682014-07-23 13:47:29 -0400739 context->recordError(Error(GL_INVALID_OPERATION));
740 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741 }
742
Jamie Madill6163c752015-12-07 16:32:59 -0500743 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400744 {
Geoff Langb1196682014-07-23 13:47:29 -0400745 context->recordError(Error(GL_INVALID_OPERATION));
746 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400747 }
748
Geoff Langb2f3d052013-08-13 12:49:27 -0400749 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400750 {
Geoff Langb1196682014-07-23 13:47:29 -0400751 context->recordError(Error(GL_INVALID_OPERATION));
752 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400753 }
754 }
755 }
756
Geoff Lang5d601382014-07-22 15:14:06 -0400757 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400758 {
Geoff Langb1196682014-07-23 13:47:29 -0400759 context->recordError(Error(GL_INVALID_OPERATION));
760 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 }
763 }
764
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200765 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
766 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
767 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200769 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400771 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
772 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200774 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775 {
Geoff Langd8a22582014-12-17 15:28:23 -0500776 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 {
Geoff Langb1196682014-07-23 13:47:29 -0400778 context->recordError(Error(GL_INVALID_OPERATION));
779 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400781
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200782 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400783 {
Geoff Langb1196682014-07-23 13:47:29 -0400784 context->recordError(Error(GL_INVALID_OPERATION));
785 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400786 }
787 }
788 }
789 }
790
791 return true;
792}
793
Geoff Langb1196682014-07-23 13:47:29 -0400794bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795{
796 switch (pname)
797 {
798 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
799 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
800 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
801 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
802 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
803 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
804 case GL_CURRENT_VERTEX_ATTRIB:
805 return true;
806
807 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
808 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
809 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400810 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
811 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400812 return true;
813
814 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400815 if (context->getClientVersion() < 3)
816 {
817 context->recordError(Error(GL_INVALID_ENUM));
818 return false;
819 }
820 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400821
822 default:
Geoff Langb1196682014-07-23 13:47:29 -0400823 context->recordError(Error(GL_INVALID_ENUM));
824 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400825 }
826}
827
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400828bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829{
830 switch (pname)
831 {
832 case GL_TEXTURE_WRAP_R:
833 case GL_TEXTURE_SWIZZLE_R:
834 case GL_TEXTURE_SWIZZLE_G:
835 case GL_TEXTURE_SWIZZLE_B:
836 case GL_TEXTURE_SWIZZLE_A:
837 case GL_TEXTURE_BASE_LEVEL:
838 case GL_TEXTURE_MAX_LEVEL:
839 case GL_TEXTURE_COMPARE_MODE:
840 case GL_TEXTURE_COMPARE_FUNC:
841 case GL_TEXTURE_MIN_LOD:
842 case GL_TEXTURE_MAX_LOD:
843 if (context->getClientVersion() < 3)
844 {
Geoff Langb1196682014-07-23 13:47:29 -0400845 context->recordError(Error(GL_INVALID_ENUM));
846 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400847 }
848 break;
849
850 default: break;
851 }
852
853 switch (pname)
854 {
855 case GL_TEXTURE_WRAP_S:
856 case GL_TEXTURE_WRAP_T:
857 case GL_TEXTURE_WRAP_R:
858 switch (param)
859 {
860 case GL_REPEAT:
861 case GL_CLAMP_TO_EDGE:
862 case GL_MIRRORED_REPEAT:
863 return true;
864 default:
Geoff Langb1196682014-07-23 13:47:29 -0400865 context->recordError(Error(GL_INVALID_ENUM));
866 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400867 }
868
869 case GL_TEXTURE_MIN_FILTER:
870 switch (param)
871 {
872 case GL_NEAREST:
873 case GL_LINEAR:
874 case GL_NEAREST_MIPMAP_NEAREST:
875 case GL_LINEAR_MIPMAP_NEAREST:
876 case GL_NEAREST_MIPMAP_LINEAR:
877 case GL_LINEAR_MIPMAP_LINEAR:
878 return true;
879 default:
Geoff Langb1196682014-07-23 13:47:29 -0400880 context->recordError(Error(GL_INVALID_ENUM));
881 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 }
883 break;
884
885 case GL_TEXTURE_MAG_FILTER:
886 switch (param)
887 {
888 case GL_NEAREST:
889 case GL_LINEAR:
890 return true;
891 default:
Geoff Langb1196682014-07-23 13:47:29 -0400892 context->recordError(Error(GL_INVALID_ENUM));
893 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400894 }
895 break;
896
897 case GL_TEXTURE_USAGE_ANGLE:
898 switch (param)
899 {
900 case GL_NONE:
901 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
902 return true;
903 default:
Geoff Langb1196682014-07-23 13:47:29 -0400904 context->recordError(Error(GL_INVALID_ENUM));
905 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400906 }
907 break;
908
909 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400910 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400911 {
Geoff Langb1196682014-07-23 13:47:29 -0400912 context->recordError(Error(GL_INVALID_ENUM));
913 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400914 }
915
916 // we assume the parameter passed to this validation method is truncated, not rounded
917 if (param < 1)
918 {
Geoff Langb1196682014-07-23 13:47:29 -0400919 context->recordError(Error(GL_INVALID_VALUE));
920 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400921 }
922 return true;
923
924 case GL_TEXTURE_MIN_LOD:
925 case GL_TEXTURE_MAX_LOD:
926 // any value is permissible
927 return true;
928
929 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400930 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400931 switch (param)
932 {
933 case GL_NONE:
934 case GL_COMPARE_REF_TO_TEXTURE:
935 return true;
936 default:
Geoff Langb1196682014-07-23 13:47:29 -0400937 context->recordError(Error(GL_INVALID_ENUM));
938 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 }
940 break;
941
942 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400943 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400944 switch (param)
945 {
946 case GL_LEQUAL:
947 case GL_GEQUAL:
948 case GL_LESS:
949 case GL_GREATER:
950 case GL_EQUAL:
951 case GL_NOTEQUAL:
952 case GL_ALWAYS:
953 case GL_NEVER:
954 return true;
955 default:
Geoff Langb1196682014-07-23 13:47:29 -0400956 context->recordError(Error(GL_INVALID_ENUM));
957 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400958 }
959 break;
960
961 case GL_TEXTURE_SWIZZLE_R:
962 case GL_TEXTURE_SWIZZLE_G:
963 case GL_TEXTURE_SWIZZLE_B:
964 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400965 switch (param)
966 {
967 case GL_RED:
968 case GL_GREEN:
969 case GL_BLUE:
970 case GL_ALPHA:
971 case GL_ZERO:
972 case GL_ONE:
973 return true;
974 default:
Geoff Langb1196682014-07-23 13:47:29 -0400975 context->recordError(Error(GL_INVALID_ENUM));
976 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400977 }
978 break;
979
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400980 case GL_TEXTURE_BASE_LEVEL:
981 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400982 if (param < 0)
983 {
Geoff Langb1196682014-07-23 13:47:29 -0400984 context->recordError(Error(GL_INVALID_VALUE));
985 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400986 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400987 return true;
988
989 default:
Geoff Langb1196682014-07-23 13:47:29 -0400990 context->recordError(Error(GL_INVALID_ENUM));
991 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400992 }
993}
994
Geoff Langb1196682014-07-23 13:47:29 -0400995bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400996{
997 switch (pname)
998 {
999 case GL_TEXTURE_MIN_FILTER:
1000 case GL_TEXTURE_MAG_FILTER:
1001 case GL_TEXTURE_WRAP_S:
1002 case GL_TEXTURE_WRAP_T:
1003 case GL_TEXTURE_WRAP_R:
1004 case GL_TEXTURE_MIN_LOD:
1005 case GL_TEXTURE_MAX_LOD:
1006 case GL_TEXTURE_COMPARE_MODE:
1007 case GL_TEXTURE_COMPARE_FUNC:
1008 return true;
1009
1010 default:
Geoff Langb1196682014-07-23 13:47:29 -04001011 context->recordError(Error(GL_INVALID_ENUM));
1012 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001013 }
1014}
1015
Jamie Madillc29968b2016-01-20 11:17:23 -05001016bool ValidateReadPixels(Context *context,
1017 GLint x,
1018 GLint y,
1019 GLsizei width,
1020 GLsizei height,
1021 GLenum format,
1022 GLenum type,
1023 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001024{
Jamie Madillc29968b2016-01-20 11:17:23 -05001025 if (width < 0 || height < 0)
1026 {
1027 context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
1028 return false;
1029 }
1030
1031 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001032 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001033
Geoff Lang748f74e2014-12-01 11:25:34 -05001034 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001035 {
Geoff Langb1196682014-07-23 13:47:29 -04001036 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1037 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001038 }
1039
Jamie Madill48faf802014-11-06 15:27:22 -05001040 if (context->getState().getReadFramebuffer()->id() != 0 &&
1041 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001042 {
Geoff Langb1196682014-07-23 13:47:29 -04001043 context->recordError(Error(GL_INVALID_OPERATION));
1044 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001045 }
1046
Geoff Langbce529e2014-12-01 12:48:41 -05001047 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1048 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001049 {
Geoff Langb1196682014-07-23 13:47:29 -04001050 context->recordError(Error(GL_INVALID_OPERATION));
1051 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001052 }
1053
Geoff Langbce529e2014-12-01 12:48:41 -05001054 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1055 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001056 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001057 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001058
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001059 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1060 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001061
1062 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1063 {
Geoff Langb1196682014-07-23 13:47:29 -04001064 context->recordError(Error(GL_INVALID_OPERATION));
1065 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001066 }
1067
Jamie Madillc29968b2016-01-20 11:17:23 -05001068 return true;
1069}
1070
1071bool ValidateReadnPixelsEXT(Context *context,
1072 GLint x,
1073 GLint y,
1074 GLsizei width,
1075 GLsizei height,
1076 GLenum format,
1077 GLenum type,
1078 GLsizei bufSize,
1079 GLvoid *pixels)
1080{
1081 if (bufSize < 0)
1082 {
1083 context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
1084 return false;
1085 }
1086
Geoff Lang5d601382014-07-22 15:14:06 -04001087 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1088 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001089
Minmin Gongadff67b2015-10-14 10:34:45 -04001090 GLsizei outputPitch =
1091 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1092 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001093 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001094 int requiredSize = outputPitch * height;
1095 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001096 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001097 context->recordError(Error(GL_INVALID_OPERATION));
1098 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001099 }
1100
Jamie Madillc29968b2016-01-20 11:17:23 -05001101 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001102}
1103
Olli Etuaho41997e72016-03-10 13:38:39 +02001104bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001105{
1106 if (!context->getExtensions().occlusionQueryBoolean &&
1107 !context->getExtensions().disjointTimerQuery)
1108 {
1109 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1110 return false;
1111 }
1112
Olli Etuaho41997e72016-03-10 13:38:39 +02001113 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001114}
1115
Olli Etuaho41997e72016-03-10 13:38:39 +02001116bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001117{
1118 if (!context->getExtensions().occlusionQueryBoolean &&
1119 !context->getExtensions().disjointTimerQuery)
1120 {
1121 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1122 return false;
1123 }
1124
Olli Etuaho41997e72016-03-10 13:38:39 +02001125 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001126}
1127
1128bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001129{
1130 if (!ValidQueryType(context, target))
1131 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001132 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001133 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001134 }
1135
1136 if (id == 0)
1137 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001138 context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001139 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001140 }
1141
1142 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1143 // of zero, if the active query object name for <target> is non-zero (for the
1144 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1145 // the active query for either target is non-zero), if <id> is the name of an
1146 // existing query object whose type does not match <target>, or if <id> is the
1147 // active query object name for any query type, the error INVALID_OPERATION is
1148 // generated.
1149
1150 // Ensure no other queries are active
1151 // NOTE: If other queries than occlusion are supported, we will need to check
1152 // separately that:
1153 // a) The query ID passed is not the current active query for any target/type
1154 // b) There are no active queries for the requested target (and in the case
1155 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1156 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001157
1158 // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
1159 // same time
Shannon Woods53a94a82014-06-24 15:20:36 -04001160 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001161 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001162 context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001163 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001164 }
1165
1166 Query *queryObject = context->getQuery(id, true, target);
1167
1168 // check that name was obtained with glGenQueries
1169 if (!queryObject)
1170 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001171 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001172 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001173 }
1174
1175 // check for type mismatch
1176 if (queryObject->getType() != target)
1177 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001178 context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001179 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001180 }
1181
1182 return true;
1183}
1184
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001185bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1186{
1187 if (!context->getExtensions().occlusionQueryBoolean &&
1188 !context->getExtensions().disjointTimerQuery)
1189 {
1190 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1191 return false;
1192 }
1193
1194 return ValidateBeginQueryBase(context, target, id);
1195}
1196
1197bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001198{
1199 if (!ValidQueryType(context, target))
1200 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001201 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001202 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001203 }
1204
Shannon Woods53a94a82014-06-24 15:20:36 -04001205 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001206
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001207 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001208 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001209 context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001210 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001211 }
1212
Jamie Madill45c785d2014-05-13 14:09:34 -04001213 return true;
1214}
1215
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001216bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1217{
1218 if (!context->getExtensions().occlusionQueryBoolean &&
1219 !context->getExtensions().disjointTimerQuery)
1220 {
1221 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1222 return false;
1223 }
1224
1225 return ValidateEndQueryBase(context, target);
1226}
1227
1228bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1229{
1230 if (!context->getExtensions().disjointTimerQuery)
1231 {
1232 context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
1233 return false;
1234 }
1235
1236 if (target != GL_TIMESTAMP_EXT)
1237 {
1238 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
1239 return false;
1240 }
1241
1242 Query *queryObject = context->getQuery(id, true, target);
1243 if (queryObject == nullptr)
1244 {
1245 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
1246 return false;
1247 }
1248
1249 if (context->getState().isQueryActive(queryObject))
1250 {
1251 context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
1252 return false;
1253 }
1254
1255 return true;
1256}
1257
1258bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1259{
1260 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1261 {
1262 context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
1263 return false;
1264 }
1265
1266 switch (pname)
1267 {
1268 case GL_CURRENT_QUERY_EXT:
1269 if (target == GL_TIMESTAMP_EXT)
1270 {
1271 context->recordError(
1272 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1273 return false;
1274 }
1275 break;
1276 case GL_QUERY_COUNTER_BITS_EXT:
1277 if (!context->getExtensions().disjointTimerQuery ||
1278 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1279 {
1280 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1281 return false;
1282 }
1283 break;
1284 default:
1285 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1286 return false;
1287 }
1288
1289 return true;
1290}
1291
1292bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1293{
1294 if (!context->getExtensions().occlusionQueryBoolean &&
1295 !context->getExtensions().disjointTimerQuery)
1296 {
1297 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1298 return false;
1299 }
1300
1301 return ValidateGetQueryivBase(context, target, pname);
1302}
1303
1304bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1305{
1306 Query *queryObject = context->getQuery(id, false, GL_NONE);
1307
1308 if (!queryObject)
1309 {
1310 context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
1311 return false;
1312 }
1313
1314 if (context->getState().isQueryActive(queryObject))
1315 {
1316 context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
1317 return false;
1318 }
1319
1320 switch (pname)
1321 {
1322 case GL_QUERY_RESULT_EXT:
1323 case GL_QUERY_RESULT_AVAILABLE_EXT:
1324 break;
1325
1326 default:
1327 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
1328 return false;
1329 }
1330
1331 return true;
1332}
1333
1334bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1335{
1336 if (!context->getExtensions().disjointTimerQuery)
1337 {
1338 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1339 return false;
1340 }
1341 return ValidateGetQueryObjectValueBase(context, id, pname);
1342}
1343
1344bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1345{
1346 if (!context->getExtensions().disjointTimerQuery &&
1347 !context->getExtensions().occlusionQueryBoolean)
1348 {
1349 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1350 return false;
1351 }
1352 return ValidateGetQueryObjectValueBase(context, id, pname);
1353}
1354
1355bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1356{
1357 if (!context->getExtensions().disjointTimerQuery)
1358 {
1359 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1360 return false;
1361 }
1362 return ValidateGetQueryObjectValueBase(context, id, pname);
1363}
1364
1365bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1366{
1367 if (!context->getExtensions().disjointTimerQuery)
1368 {
1369 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1370 return false;
1371 }
1372 return ValidateGetQueryObjectValueBase(context, id, pname);
1373}
1374
Jamie Madill62d31cb2015-09-11 13:25:51 -04001375static bool ValidateUniformCommonBase(gl::Context *context,
1376 GLenum targetUniformType,
1377 GLint location,
1378 GLsizei count,
1379 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001380{
1381 if (count < 0)
1382 {
Geoff Langb1196682014-07-23 13:47:29 -04001383 context->recordError(Error(GL_INVALID_VALUE));
1384 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001385 }
1386
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387 gl::Program *program = context->getState().getProgram();
1388 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001389 {
Geoff Langb1196682014-07-23 13:47:29 -04001390 context->recordError(Error(GL_INVALID_OPERATION));
1391 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001392 }
1393
1394 if (location == -1)
1395 {
1396 // Silently ignore the uniform command
1397 return false;
1398 }
1399
Geoff Lang7dd2e102014-11-10 15:19:26 -05001400 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001401 {
Geoff Langb1196682014-07-23 13:47:29 -04001402 context->recordError(Error(GL_INVALID_OPERATION));
1403 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001404 }
1405
Jamie Madill62d31cb2015-09-11 13:25:51 -04001406 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001407
1408 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001409 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001410 {
Geoff Langb1196682014-07-23 13:47:29 -04001411 context->recordError(Error(GL_INVALID_OPERATION));
1412 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001413 }
1414
Jamie Madill62d31cb2015-09-11 13:25:51 -04001415 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001416 return true;
1417}
1418
Jamie Madillaa981bd2014-05-20 10:55:55 -04001419bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1420{
1421 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001422 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001423 {
Geoff Langb1196682014-07-23 13:47:29 -04001424 context->recordError(Error(GL_INVALID_OPERATION));
1425 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001426 }
1427
Jamie Madill62d31cb2015-09-11 13:25:51 -04001428 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001429 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1430 {
1431 return false;
1432 }
1433
Jamie Madillf2575982014-06-25 16:04:54 -04001434 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001435 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001436 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1437 {
Geoff Langb1196682014-07-23 13:47:29 -04001438 context->recordError(Error(GL_INVALID_OPERATION));
1439 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001440 }
1441
1442 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001443}
1444
1445bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1446 GLboolean transpose)
1447{
1448 // Check for ES3 uniform entry points
1449 int rows = VariableRowCount(matrixType);
1450 int cols = VariableColumnCount(matrixType);
1451 if (rows != cols && context->getClientVersion() < 3)
1452 {
Geoff Langb1196682014-07-23 13:47:29 -04001453 context->recordError(Error(GL_INVALID_OPERATION));
1454 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001455 }
1456
1457 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1458 {
Geoff Langb1196682014-07-23 13:47:29 -04001459 context->recordError(Error(GL_INVALID_VALUE));
1460 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001461 }
1462
Jamie Madill62d31cb2015-09-11 13:25:51 -04001463 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001464 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1465 {
1466 return false;
1467 }
1468
1469 if (uniform->type != matrixType)
1470 {
Geoff Langb1196682014-07-23 13:47:29 -04001471 context->recordError(Error(GL_INVALID_OPERATION));
1472 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001473 }
1474
1475 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001476}
1477
Jamie Madill893ab082014-05-16 16:56:10 -04001478bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1479{
1480 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1481 {
Geoff Langb1196682014-07-23 13:47:29 -04001482 context->recordError(Error(GL_INVALID_ENUM));
1483 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001484 }
1485
Jamie Madill0af26e12015-03-05 19:54:33 -05001486 const Caps &caps = context->getCaps();
1487
Jamie Madill893ab082014-05-16 16:56:10 -04001488 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1489 {
1490 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1491
Jamie Madill0af26e12015-03-05 19:54:33 -05001492 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001493 {
Geoff Langb1196682014-07-23 13:47:29 -04001494 context->recordError(Error(GL_INVALID_OPERATION));
1495 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001496 }
1497 }
1498
1499 switch (pname)
1500 {
1501 case GL_TEXTURE_BINDING_2D:
1502 case GL_TEXTURE_BINDING_CUBE_MAP:
1503 case GL_TEXTURE_BINDING_3D:
1504 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001505 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001506 case GL_TEXTURE_BINDING_EXTERNAL_OES:
1507 if (!context->getExtensions().eglStreamConsumerExternal)
1508 {
1509 context->recordError(
1510 Error(GL_INVALID_ENUM, "NV_EGL_stream_consumer_external extension not enabled"));
1511 return false;
1512 }
1513 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001514
1515 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1516 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1517 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001518 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001519 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001520 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001521 {
Geoff Langb1196682014-07-23 13:47:29 -04001522 context->recordError(Error(GL_INVALID_OPERATION));
1523 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001524 }
1525
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001526 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001527 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001528 {
Geoff Langb1196682014-07-23 13:47:29 -04001529 context->recordError(Error(GL_INVALID_OPERATION));
1530 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001531 }
1532 }
1533 break;
1534
1535 default:
1536 break;
1537 }
1538
1539 // pname is valid, but there are no parameters to return
1540 if (numParams == 0)
1541 {
1542 return false;
1543 }
1544
1545 return true;
1546}
1547
Jamie Madillc29968b2016-01-20 11:17:23 -05001548bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1549 GLenum target,
1550 GLint level,
1551 GLenum internalformat,
1552 bool isSubImage,
1553 GLint xoffset,
1554 GLint yoffset,
1555 GLint zoffset,
1556 GLint x,
1557 GLint y,
1558 GLsizei width,
1559 GLsizei height,
1560 GLint border,
1561 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001562{
Jamie Madill560a8d82014-05-21 13:06:20 -04001563 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1564 {
Geoff Langb1196682014-07-23 13:47:29 -04001565 context->recordError(Error(GL_INVALID_VALUE));
1566 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001567 }
1568
1569 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1570 {
Geoff Langb1196682014-07-23 13:47:29 -04001571 context->recordError(Error(GL_INVALID_VALUE));
1572 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001573 }
1574
1575 if (border != 0)
1576 {
Geoff Langb1196682014-07-23 13:47:29 -04001577 context->recordError(Error(GL_INVALID_VALUE));
1578 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001579 }
1580
1581 if (!ValidMipLevel(context, target, level))
1582 {
Geoff Langb1196682014-07-23 13:47:29 -04001583 context->recordError(Error(GL_INVALID_VALUE));
1584 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001585 }
1586
Jamie Madillc29968b2016-01-20 11:17:23 -05001587 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001588 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001589 {
Geoff Langb1196682014-07-23 13:47:29 -04001590 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1591 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001592 }
1593
Jamie Madillc29968b2016-01-20 11:17:23 -05001594 const auto &state = context->getState();
1595 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001596 {
Geoff Langb1196682014-07-23 13:47:29 -04001597 context->recordError(Error(GL_INVALID_OPERATION));
1598 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001599 }
1600
Geoff Langaae65a42014-05-26 12:43:44 -04001601 const gl::Caps &caps = context->getCaps();
1602
Geoff Langaae65a42014-05-26 12:43:44 -04001603 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001604 switch (target)
1605 {
1606 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001607 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001608 break;
1609
1610 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1611 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1612 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1613 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1614 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1615 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001616 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001617 break;
1618
1619 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001620 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001621 break;
1622
1623 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001624 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001625 break;
1626
1627 default:
Geoff Langb1196682014-07-23 13:47:29 -04001628 context->recordError(Error(GL_INVALID_ENUM));
1629 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001630 }
1631
Jamie Madillc29968b2016-01-20 11:17:23 -05001632 gl::Texture *texture =
1633 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001634 if (!texture)
1635 {
Geoff Langb1196682014-07-23 13:47:29 -04001636 context->recordError(Error(GL_INVALID_OPERATION));
1637 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001638 }
1639
Geoff Lang69cce582015-09-17 13:20:36 -04001640 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001641 {
Geoff Langb1196682014-07-23 13:47:29 -04001642 context->recordError(Error(GL_INVALID_OPERATION));
1643 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001644 }
1645
Geoff Lang5d601382014-07-22 15:14:06 -04001646 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1647
1648 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001649 {
Geoff Langb1196682014-07-23 13:47:29 -04001650 context->recordError(Error(GL_INVALID_OPERATION));
1651 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001652 }
1653
Geoff Langa9be0dc2014-12-17 12:34:40 -05001654 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001655 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001656 context->recordError(Error(GL_INVALID_OPERATION));
1657 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001658 }
1659
1660 if (isSubImage)
1661 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001662 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1663 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1664 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001665 {
Geoff Langb1196682014-07-23 13:47:29 -04001666 context->recordError(Error(GL_INVALID_VALUE));
1667 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001668 }
1669 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001670 else
1671 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001672 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001673 {
Geoff Langb1196682014-07-23 13:47:29 -04001674 context->recordError(Error(GL_INVALID_VALUE));
1675 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001676 }
1677
Geoff Lang5d601382014-07-22 15:14:06 -04001678 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001679 {
Geoff Langb1196682014-07-23 13:47:29 -04001680 context->recordError(Error(GL_INVALID_ENUM));
1681 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001682 }
1683
1684 int maxLevelDimension = (maxDimension >> level);
1685 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1686 {
Geoff Langb1196682014-07-23 13:47:29 -04001687 context->recordError(Error(GL_INVALID_VALUE));
1688 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001689 }
1690 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001691
Geoff Langa9be0dc2014-12-17 12:34:40 -05001692 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001693 return true;
1694}
1695
Jamie Madillf25855c2015-11-03 11:06:18 -05001696static bool ValidateDrawBase(ValidationContext *context,
1697 GLenum mode,
1698 GLsizei count,
1699 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001700{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001701 switch (mode)
1702 {
1703 case GL_POINTS:
1704 case GL_LINES:
1705 case GL_LINE_LOOP:
1706 case GL_LINE_STRIP:
1707 case GL_TRIANGLES:
1708 case GL_TRIANGLE_STRIP:
1709 case GL_TRIANGLE_FAN:
1710 break;
1711 default:
Geoff Langb1196682014-07-23 13:47:29 -04001712 context->recordError(Error(GL_INVALID_ENUM));
1713 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001714 }
1715
Jamie Madill250d33f2014-06-06 17:09:03 -04001716 if (count < 0)
1717 {
Geoff Langb1196682014-07-23 13:47:29 -04001718 context->recordError(Error(GL_INVALID_VALUE));
1719 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001720 }
1721
Geoff Langb1196682014-07-23 13:47:29 -04001722 const State &state = context->getState();
1723
Jamie Madill250d33f2014-06-06 17:09:03 -04001724 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001725 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001726 {
Geoff Langb1196682014-07-23 13:47:29 -04001727 context->recordError(Error(GL_INVALID_OPERATION));
1728 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001729 }
1730
Geoff Lang3a86ad32015-09-01 11:47:05 -04001731 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001732 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001733 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1734 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1735 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1736 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1737 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1738 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1739 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001740 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001741 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1742 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001743 {
1744 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1745 // Section 6.10 of the WebGL 1.0 spec
1746 ERR(
1747 "This ANGLE implementation does not support separate front/back stencil "
1748 "writemasks, reference values, or stencil mask values.");
1749 context->recordError(Error(GL_INVALID_OPERATION));
1750 return false;
1751 }
Jamie Madillac528012014-06-20 13:21:23 -04001752 }
1753
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001754 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001755 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001756 {
Geoff Langb1196682014-07-23 13:47:29 -04001757 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1758 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001759 }
1760
Geoff Lang7dd2e102014-11-10 15:19:26 -05001761 gl::Program *program = state.getProgram();
1762 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001763 {
Geoff Langb1196682014-07-23 13:47:29 -04001764 context->recordError(Error(GL_INVALID_OPERATION));
1765 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001766 }
1767
Geoff Lang7dd2e102014-11-10 15:19:26 -05001768 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001769 {
Geoff Langb1196682014-07-23 13:47:29 -04001770 context->recordError(Error(GL_INVALID_OPERATION));
1771 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001772 }
1773
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001774 // Uniform buffer validation
1775 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1776 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001777 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001778 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001779 const OffsetBindingPointer<Buffer> &uniformBuffer =
1780 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001781
Geoff Lang5d124a62015-09-15 13:03:27 -04001782 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001783 {
1784 // undefined behaviour
1785 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1786 return false;
1787 }
1788
Geoff Lang5d124a62015-09-15 13:03:27 -04001789 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001790 if (uniformBufferSize == 0)
1791 {
1792 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001793 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001794 }
1795
Jamie Madill62d31cb2015-09-11 13:25:51 -04001796 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001797 {
1798 // undefined behaviour
1799 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1800 return false;
1801 }
1802 }
1803
Jamie Madill250d33f2014-06-06 17:09:03 -04001804 // No-op if zero count
1805 return (count > 0);
1806}
1807
Geoff Langb1196682014-07-23 13:47:29 -04001808bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001809{
Jamie Madillfd716582014-06-06 17:09:04 -04001810 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001811 {
Geoff Langb1196682014-07-23 13:47:29 -04001812 context->recordError(Error(GL_INVALID_VALUE));
1813 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001814 }
1815
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001816 const State &state = context->getState();
1817 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001818 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1819 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001820 {
1821 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1822 // that does not match the current transform feedback object's draw mode (if transform feedback
1823 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001824 context->recordError(Error(GL_INVALID_OPERATION));
1825 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001826 }
1827
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001828 if (!ValidateDrawBase(context, mode, count, primcount))
1829 {
1830 return false;
1831 }
1832
1833 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001834 {
1835 return false;
1836 }
1837
1838 return true;
1839}
1840
Geoff Langb1196682014-07-23 13:47:29 -04001841bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001842{
1843 if (primcount < 0)
1844 {
Geoff Langb1196682014-07-23 13:47:29 -04001845 context->recordError(Error(GL_INVALID_VALUE));
1846 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001847 }
1848
Jamie Madill2b976812014-08-25 15:47:49 -04001849 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001850 {
1851 return false;
1852 }
1853
1854 // No-op if zero primitive count
1855 return (primcount > 0);
1856}
1857
Geoff Lang87a93302014-09-16 13:29:43 -04001858static bool ValidateDrawInstancedANGLE(Context *context)
1859{
1860 // Verify there is at least one active attribute with a divisor of zero
1861 const gl::State& state = context->getState();
1862
Geoff Lang7dd2e102014-11-10 15:19:26 -05001863 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001864
1865 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001866 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001867 {
1868 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001869 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001870 {
1871 return true;
1872 }
1873 }
1874
1875 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1876 "has a divisor of zero."));
1877 return false;
1878}
1879
1880bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1881{
1882 if (!ValidateDrawInstancedANGLE(context))
1883 {
1884 return false;
1885 }
1886
1887 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1888}
1889
Jamie Madillf25855c2015-11-03 11:06:18 -05001890bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001891 GLenum mode,
1892 GLsizei count,
1893 GLenum type,
1894 const GLvoid *indices,
1895 GLsizei primcount,
1896 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001897{
Jamie Madill250d33f2014-06-06 17:09:03 -04001898 switch (type)
1899 {
1900 case GL_UNSIGNED_BYTE:
1901 case GL_UNSIGNED_SHORT:
1902 break;
1903 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001904 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001905 {
Geoff Langb1196682014-07-23 13:47:29 -04001906 context->recordError(Error(GL_INVALID_ENUM));
1907 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001908 }
1909 break;
1910 default:
Geoff Langb1196682014-07-23 13:47:29 -04001911 context->recordError(Error(GL_INVALID_ENUM));
1912 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001913 }
1914
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001915 const State &state = context->getState();
1916
1917 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001918 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001919 {
1920 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1921 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001922 context->recordError(Error(GL_INVALID_OPERATION));
1923 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001924 }
1925
1926 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001927 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001928 {
Geoff Langb1196682014-07-23 13:47:29 -04001929 context->recordError(Error(GL_INVALID_OPERATION));
1930 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001931 }
1932
Jamie Madill2b976812014-08-25 15:47:49 -04001933 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001934 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001935 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001936 {
Geoff Langb1196682014-07-23 13:47:29 -04001937 context->recordError(Error(GL_INVALID_OPERATION));
1938 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001939 }
1940
Jamie Madillae3000b2014-08-25 15:47:51 -04001941 if (elementArrayBuffer)
1942 {
1943 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1944
1945 GLint64 offset = reinterpret_cast<GLint64>(indices);
1946 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1947
1948 // check for integer overflows
1949 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1950 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1951 {
Geoff Langb1196682014-07-23 13:47:29 -04001952 context->recordError(Error(GL_OUT_OF_MEMORY));
1953 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001954 }
1955
1956 // Check for reading past the end of the bound buffer object
1957 if (byteCount > elementArrayBuffer->getSize())
1958 {
Geoff Langb1196682014-07-23 13:47:29 -04001959 context->recordError(Error(GL_INVALID_OPERATION));
1960 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001961 }
1962 }
1963 else if (!indices)
1964 {
1965 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001966 context->recordError(Error(GL_INVALID_OPERATION));
1967 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001968 }
1969
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001970 if (!ValidateDrawBase(context, mode, count, primcount))
1971 {
1972 return false;
1973 }
1974
Jamie Madill2b976812014-08-25 15:47:49 -04001975 // Use max index to validate if our vertex buffers are large enough for the pull.
1976 // TODO: offer fast path, with disabled index validation.
1977 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1978 if (elementArrayBuffer)
1979 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001980 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001981 Error error =
1982 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1983 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001984 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001985 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001986 context->recordError(error);
1987 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001988 }
1989 }
1990 else
1991 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001992 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001993 }
1994
Jamie Madille79b1e12015-11-04 16:36:37 -05001995 // If we use an index greater than our maximum supported index range, return an error.
1996 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1997 // return an error if possible here.
1998 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1999 {
2000 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
2001 return false;
2002 }
2003
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002004 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002005 {
2006 return false;
2007 }
2008
Geoff Lang3edfe032015-09-04 16:38:24 -04002009 // No op if there are no real indices in the index data (all are primitive restart).
2010 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002011}
2012
Geoff Langb1196682014-07-23 13:47:29 -04002013bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002014 GLenum mode,
2015 GLsizei count,
2016 GLenum type,
2017 const GLvoid *indices,
2018 GLsizei primcount,
2019 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002020{
2021 if (primcount < 0)
2022 {
Geoff Langb1196682014-07-23 13:47:29 -04002023 context->recordError(Error(GL_INVALID_VALUE));
2024 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002025 }
2026
Jamie Madill2b976812014-08-25 15:47:49 -04002027 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002028 {
2029 return false;
2030 }
2031
2032 // No-op zero primitive count
2033 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002034}
2035
Geoff Lang3edfe032015-09-04 16:38:24 -04002036bool ValidateDrawElementsInstancedANGLE(Context *context,
2037 GLenum mode,
2038 GLsizei count,
2039 GLenum type,
2040 const GLvoid *indices,
2041 GLsizei primcount,
2042 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002043{
2044 if (!ValidateDrawInstancedANGLE(context))
2045 {
2046 return false;
2047 }
2048
2049 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2050}
2051
Geoff Langb1196682014-07-23 13:47:29 -04002052bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002053 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002054{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002055 if (!ValidFramebufferTarget(target))
2056 {
Geoff Langb1196682014-07-23 13:47:29 -04002057 context->recordError(Error(GL_INVALID_ENUM));
2058 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002059 }
2060
2061 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002062 {
2063 return false;
2064 }
2065
Jamie Madill55ec3b12014-07-03 10:38:57 -04002066 if (texture != 0)
2067 {
2068 gl::Texture *tex = context->getTexture(texture);
2069
2070 if (tex == NULL)
2071 {
Geoff Langb1196682014-07-23 13:47:29 -04002072 context->recordError(Error(GL_INVALID_OPERATION));
2073 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002074 }
2075
2076 if (level < 0)
2077 {
Geoff Langb1196682014-07-23 13:47:29 -04002078 context->recordError(Error(GL_INVALID_VALUE));
2079 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002080 }
2081 }
2082
Shannon Woods53a94a82014-06-24 15:20:36 -04002083 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002084 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002085
Jamie Madill84115c92015-04-23 15:00:07 -04002086 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002087 {
Jamie Madill84115c92015-04-23 15:00:07 -04002088 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002089 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002090 }
2091
2092 return true;
2093}
2094
Geoff Langb1196682014-07-23 13:47:29 -04002095bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002096 GLenum textarget, GLuint texture, GLint level)
2097{
Geoff Lang95663912015-04-02 15:54:45 -04002098 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2099 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002100 {
Geoff Langb1196682014-07-23 13:47:29 -04002101 context->recordError(Error(GL_INVALID_VALUE));
2102 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002103 }
2104
2105 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002106 {
2107 return false;
2108 }
2109
Jamie Madill55ec3b12014-07-03 10:38:57 -04002110 if (texture != 0)
2111 {
2112 gl::Texture *tex = context->getTexture(texture);
2113 ASSERT(tex);
2114
Jamie Madill2a6564e2014-07-11 09:53:19 -04002115 const gl::Caps &caps = context->getCaps();
2116
Jamie Madill55ec3b12014-07-03 10:38:57 -04002117 switch (textarget)
2118 {
2119 case GL_TEXTURE_2D:
2120 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002121 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002122 {
Geoff Langb1196682014-07-23 13:47:29 -04002123 context->recordError(Error(GL_INVALID_VALUE));
2124 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002125 }
2126 if (tex->getTarget() != GL_TEXTURE_2D)
2127 {
Geoff Langb1196682014-07-23 13:47:29 -04002128 context->recordError(Error(GL_INVALID_OPERATION));
2129 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002130 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002131 }
2132 break;
2133
2134 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2135 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2136 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2137 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2138 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2139 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2140 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002141 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002142 {
Geoff Langb1196682014-07-23 13:47:29 -04002143 context->recordError(Error(GL_INVALID_VALUE));
2144 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002145 }
2146 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2147 {
Geoff Langb1196682014-07-23 13:47:29 -04002148 context->recordError(Error(GL_INVALID_OPERATION));
2149 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002150 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002151 }
2152 break;
2153
2154 default:
Geoff Langb1196682014-07-23 13:47:29 -04002155 context->recordError(Error(GL_INVALID_ENUM));
2156 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002157 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002158
2159 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2160 if (internalFormatInfo.compressed)
2161 {
2162 context->recordError(Error(GL_INVALID_OPERATION));
2163 return false;
2164 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002165 }
2166
Jamie Madill570f7c82014-07-03 10:38:54 -04002167 return true;
2168}
2169
Geoff Langb1196682014-07-23 13:47:29 -04002170bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002171{
2172 if (program == 0)
2173 {
Geoff Langb1196682014-07-23 13:47:29 -04002174 context->recordError(Error(GL_INVALID_VALUE));
2175 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002176 }
2177
Dian Xiang769769a2015-09-09 15:20:08 -07002178 gl::Program *programObject = GetValidProgram(context, program);
2179 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002180 {
2181 return false;
2182 }
2183
Jamie Madill0063c512014-08-25 15:47:53 -04002184 if (!programObject || !programObject->isLinked())
2185 {
Geoff Langb1196682014-07-23 13:47:29 -04002186 context->recordError(Error(GL_INVALID_OPERATION));
2187 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002188 }
2189
Geoff Lang7dd2e102014-11-10 15:19:26 -05002190 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002191 {
Geoff Langb1196682014-07-23 13:47:29 -04002192 context->recordError(Error(GL_INVALID_OPERATION));
2193 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002194 }
2195
Jamie Madill0063c512014-08-25 15:47:53 -04002196 return true;
2197}
2198
Geoff Langb1196682014-07-23 13:47:29 -04002199bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002200{
2201 return ValidateGetUniformBase(context, program, location);
2202}
2203
Geoff Langb1196682014-07-23 13:47:29 -04002204bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002205{
Jamie Madill78f41802014-08-25 15:47:55 -04002206 return ValidateGetUniformBase(context, program, location);
2207}
2208
Geoff Langb1196682014-07-23 13:47:29 -04002209static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002210{
2211 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002212 {
Jamie Madill78f41802014-08-25 15:47:55 -04002213 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002214 }
2215
Jamie Madilla502c742014-08-28 17:19:13 -04002216 gl::Program *programObject = context->getProgram(program);
2217 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002218
Jamie Madill78f41802014-08-25 15:47:55 -04002219 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002220 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2221 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002222 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002223 {
Geoff Langb1196682014-07-23 13:47:29 -04002224 context->recordError(Error(GL_INVALID_OPERATION));
2225 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002226 }
2227
2228 return true;
2229}
2230
Geoff Langb1196682014-07-23 13:47:29 -04002231bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002232{
Jamie Madill78f41802014-08-25 15:47:55 -04002233 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002234}
2235
Geoff Langb1196682014-07-23 13:47:29 -04002236bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002237{
Jamie Madill78f41802014-08-25 15:47:55 -04002238 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002239}
2240
Austin Kinross08332632015-05-05 13:35:47 -07002241bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2242 const GLenum *attachments, bool defaultFramebuffer)
2243{
2244 if (numAttachments < 0)
2245 {
2246 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2247 return false;
2248 }
2249
2250 for (GLsizei i = 0; i < numAttachments; ++i)
2251 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002252 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002253 {
2254 if (defaultFramebuffer)
2255 {
2256 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2257 return false;
2258 }
2259
2260 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2261 {
2262 context->recordError(Error(GL_INVALID_OPERATION,
2263 "Requested color attachment is greater than the maximum supported color attachments"));
2264 return false;
2265 }
2266 }
2267 else
2268 {
2269 switch (attachments[i])
2270 {
2271 case GL_DEPTH_ATTACHMENT:
2272 case GL_STENCIL_ATTACHMENT:
2273 case GL_DEPTH_STENCIL_ATTACHMENT:
2274 if (defaultFramebuffer)
2275 {
2276 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2277 return false;
2278 }
2279 break;
2280 case GL_COLOR:
2281 case GL_DEPTH:
2282 case GL_STENCIL:
2283 if (!defaultFramebuffer)
2284 {
2285 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2286 return false;
2287 }
2288 break;
2289 default:
2290 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2291 return false;
2292 }
2293 }
2294 }
2295
2296 return true;
2297}
2298
Austin Kinross6ee1e782015-05-29 17:05:37 -07002299bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2300{
2301 // Note that debug marker calls must not set error state
2302
2303 if (length < 0)
2304 {
2305 return false;
2306 }
2307
2308 if (marker == nullptr)
2309 {
2310 return false;
2311 }
2312
2313 return true;
2314}
2315
2316bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2317{
2318 // Note that debug marker calls must not set error state
2319
2320 if (length < 0)
2321 {
2322 return false;
2323 }
2324
2325 if (length > 0 && marker == nullptr)
2326 {
2327 return false;
2328 }
2329
2330 return true;
2331}
2332
Geoff Langdcab33b2015-07-21 13:03:16 -04002333bool ValidateEGLImageTargetTexture2DOES(Context *context,
2334 egl::Display *display,
2335 GLenum target,
2336 egl::Image *image)
2337{
Geoff Langa8406172015-07-21 16:53:39 -04002338 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2339 {
2340 context->recordError(Error(GL_INVALID_OPERATION));
2341 return false;
2342 }
2343
2344 switch (target)
2345 {
2346 case GL_TEXTURE_2D:
2347 break;
2348
2349 default:
2350 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2351 return false;
2352 }
2353
2354 if (!display->isValidImage(image))
2355 {
2356 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2357 return false;
2358 }
2359
2360 if (image->getSamples() > 0)
2361 {
2362 context->recordError(Error(GL_INVALID_OPERATION,
2363 "cannot create a 2D texture from a multisampled EGL image."));
2364 return false;
2365 }
2366
2367 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2368 if (!textureCaps.texturable)
2369 {
2370 context->recordError(Error(GL_INVALID_OPERATION,
2371 "EGL image internal format is not supported as a texture."));
2372 return false;
2373 }
2374
Geoff Langdcab33b2015-07-21 13:03:16 -04002375 return true;
2376}
2377
2378bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2379 egl::Display *display,
2380 GLenum target,
2381 egl::Image *image)
2382{
Geoff Langa8406172015-07-21 16:53:39 -04002383 if (!context->getExtensions().eglImage)
2384 {
2385 context->recordError(Error(GL_INVALID_OPERATION));
2386 return false;
2387 }
2388
2389 switch (target)
2390 {
2391 case GL_RENDERBUFFER:
2392 break;
2393
2394 default:
2395 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2396 return false;
2397 }
2398
2399 if (!display->isValidImage(image))
2400 {
2401 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2402 return false;
2403 }
2404
2405 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2406 if (!textureCaps.renderable)
2407 {
2408 context->recordError(Error(
2409 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2410 return false;
2411 }
2412
Geoff Langdcab33b2015-07-21 13:03:16 -04002413 return true;
2414}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002415
2416bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2417{
Geoff Lang36167ab2015-12-07 10:27:14 -05002418 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002419 {
2420 // The default VAO should always exist
2421 ASSERT(array != 0);
2422 context->recordError(Error(GL_INVALID_OPERATION));
2423 return false;
2424 }
2425
2426 return true;
2427}
2428
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002429bool ValidateLinkProgram(Context *context, GLuint program)
2430{
2431 if (context->hasActiveTransformFeedback(program))
2432 {
2433 // ES 3.0.4 section 2.15 page 91
2434 context->recordError(Error(GL_INVALID_OPERATION,
2435 "Cannot link program while program is associated with an active "
2436 "transform feedback object."));
2437 return false;
2438 }
2439 return true;
2440}
2441
Geoff Langc5629752015-12-07 16:29:04 -05002442bool ValidateProgramBinaryBase(Context *context,
2443 GLuint program,
2444 GLenum binaryFormat,
2445 const void *binary,
2446 GLint length)
2447{
2448 Program *programObject = GetValidProgram(context, program);
2449 if (programObject == nullptr)
2450 {
2451 return false;
2452 }
2453
2454 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2455 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2456 programBinaryFormats.end())
2457 {
2458 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2459 return false;
2460 }
2461
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002462 if (context->hasActiveTransformFeedback(program))
2463 {
2464 // ES 3.0.4 section 2.15 page 91
2465 context->recordError(Error(GL_INVALID_OPERATION,
2466 "Cannot change program binary while program is associated with "
2467 "an active transform feedback object."));
2468 return false;
2469 }
2470
Geoff Langc5629752015-12-07 16:29:04 -05002471 return true;
2472}
2473
2474bool ValidateGetProgramBinaryBase(Context *context,
2475 GLuint program,
2476 GLsizei bufSize,
2477 GLsizei *length,
2478 GLenum *binaryFormat,
2479 void *binary)
2480{
2481 Program *programObject = GetValidProgram(context, program);
2482 if (programObject == nullptr)
2483 {
2484 return false;
2485 }
2486
2487 if (!programObject->isLinked())
2488 {
2489 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2490 return false;
2491 }
2492
2493 return true;
2494}
Jamie Madillc29968b2016-01-20 11:17:23 -05002495
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002496bool ValidateUseProgram(Context *context, GLuint program)
2497{
2498 if (program != 0)
2499 {
2500 Program *programObject = context->getProgram(program);
2501 if (!programObject)
2502 {
2503 // ES 3.1.0 section 7.3 page 72
2504 if (context->getShader(program))
2505 {
2506 context->recordError(
2507 Error(GL_INVALID_OPERATION,
2508 "Attempted to use a single shader instead of a shader program."));
2509 return false;
2510 }
2511 else
2512 {
2513 context->recordError(Error(GL_INVALID_VALUE, "Program invalid."));
2514 return false;
2515 }
2516 }
2517 if (!programObject->isLinked())
2518 {
2519 context->recordError(Error(GL_INVALID_OPERATION, "Program not linked."));
2520 return false;
2521 }
2522 }
2523 if (context->getState().isTransformFeedbackActiveUnpaused())
2524 {
2525 // ES 3.0.4 section 2.15 page 91
2526 context->recordError(
2527 Error(GL_INVALID_OPERATION,
2528 "Cannot change active program while transform feedback is unpaused."));
2529 return false;
2530 }
2531
2532 return true;
2533}
2534
Jamie Madillc29968b2016-01-20 11:17:23 -05002535bool ValidateCopyTexImage2D(ValidationContext *context,
2536 GLenum target,
2537 GLint level,
2538 GLenum internalformat,
2539 GLint x,
2540 GLint y,
2541 GLsizei width,
2542 GLsizei height,
2543 GLint border)
2544{
2545 if (context->getClientVersion() < 3)
2546 {
2547 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2548 0, x, y, width, height, border);
2549 }
2550
2551 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002552 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2553 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002554}
Jamie Madillc29968b2016-01-20 11:17:23 -05002555
2556bool ValidateFramebufferRenderbuffer(Context *context,
2557 GLenum target,
2558 GLenum attachment,
2559 GLenum renderbuffertarget,
2560 GLuint renderbuffer)
2561{
2562 if (!ValidFramebufferTarget(target) ||
2563 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2564 {
2565 context->recordError(Error(GL_INVALID_ENUM));
2566 return false;
2567 }
2568
2569 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2570 renderbuffertarget, renderbuffer);
2571}
2572
2573bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2574{
2575 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2576 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2577 {
2578 context->recordError(
2579 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2580 return false;
2581 }
2582
2583 ASSERT(context->getState().getDrawFramebuffer());
2584 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2585 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2586
2587 // This should come first before the check for the default frame buffer
2588 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2589 // rather than INVALID_OPERATION
2590 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2591 {
2592 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2593
2594 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002595 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2596 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002597 {
2598 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002599 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2600 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2601 // 3.1 is still a bit ambiguous about the error, but future specs are
2602 // expected to clarify that GL_INVALID_ENUM is the correct error.
2603 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
2604 return false;
2605 }
2606 else if (bufs[colorAttachment] >= maxColorAttachment)
2607 {
2608 context->recordError(
2609 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002610 return false;
2611 }
2612 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2613 frameBufferId != 0)
2614 {
2615 // INVALID_OPERATION-GL is bound to buffer and ith argument
2616 // is not COLOR_ATTACHMENTi or NONE
2617 context->recordError(
2618 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2619 return false;
2620 }
2621 }
2622
2623 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2624 // and n is not 1 or bufs is bound to value other than BACK and NONE
2625 if (frameBufferId == 0)
2626 {
2627 if (n != 1)
2628 {
2629 context->recordError(Error(GL_INVALID_OPERATION,
2630 "n must be 1 when GL is bound to the default framebuffer"));
2631 return false;
2632 }
2633
2634 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2635 {
2636 context->recordError(Error(
2637 GL_INVALID_OPERATION,
2638 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2639 return false;
2640 }
2641 }
2642
2643 return true;
2644}
2645
2646bool ValidateCopyTexSubImage2D(Context *context,
2647 GLenum target,
2648 GLint level,
2649 GLint xoffset,
2650 GLint yoffset,
2651 GLint x,
2652 GLint y,
2653 GLsizei width,
2654 GLsizei height)
2655{
2656 if (context->getClientVersion() < 3)
2657 {
2658 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2659 yoffset, x, y, width, height, 0);
2660 }
2661
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002662 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2663 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002664}
2665
Olli Etuaho4f667482016-03-30 15:56:35 +03002666bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
2667{
2668 if (!ValidBufferTarget(context, target))
2669 {
2670 context->recordError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
2671 return false;
2672 }
2673
2674 if (pname != GL_BUFFER_MAP_POINTER)
2675 {
2676 context->recordError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
2677 return false;
2678 }
2679
2680 Buffer *buffer = context->getState().getTargetBuffer(target);
2681
2682 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
2683 // target bound to zero generate an INVALID_OPERATION error."
2684 // GLES 3.1 section 6.6 explicitly specifies this error.
2685 if (!buffer)
2686 {
2687 context->recordError(
2688 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
2689 return false;
2690 }
2691
2692 return true;
2693}
2694
2695bool ValidateUnmapBufferBase(Context *context, GLenum target)
2696{
2697 if (!ValidBufferTarget(context, target))
2698 {
2699 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2700 return false;
2701 }
2702
2703 Buffer *buffer = context->getState().getTargetBuffer(target);
2704
2705 if (buffer == nullptr || !buffer->isMapped())
2706 {
2707 context->recordError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
2708 return false;
2709 }
2710
2711 return true;
2712}
2713
2714bool ValidateMapBufferRangeBase(Context *context,
2715 GLenum target,
2716 GLintptr offset,
2717 GLsizeiptr length,
2718 GLbitfield access)
2719{
2720 if (!ValidBufferTarget(context, target))
2721 {
2722 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2723 return false;
2724 }
2725
2726 if (offset < 0 || length < 0)
2727 {
2728 context->recordError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
2729 return false;
2730 }
2731
2732 Buffer *buffer = context->getState().getTargetBuffer(target);
2733
2734 if (!buffer)
2735 {
2736 context->recordError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
2737 return false;
2738 }
2739
2740 // Check for buffer overflow
2741 size_t offsetSize = static_cast<size_t>(offset);
2742 size_t lengthSize = static_cast<size_t>(length);
2743
2744 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2745 offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
2746 {
2747 context->recordError(
2748 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
2749 return false;
2750 }
2751
2752 // Check for invalid bits in the mask
2753 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
2754 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
2755 GL_MAP_UNSYNCHRONIZED_BIT;
2756
2757 if (access & ~(allAccessBits))
2758 {
2759 context->recordError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
2760 return false;
2761 }
2762
2763 if (length == 0)
2764 {
2765 context->recordError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
2766 return false;
2767 }
2768
2769 if (buffer->isMapped())
2770 {
2771 context->recordError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
2772 return false;
2773 }
2774
2775 // Check for invalid bit combinations
2776 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
2777 {
2778 context->recordError(
2779 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
2780 return false;
2781 }
2782
2783 GLbitfield writeOnlyBits =
2784 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
2785
2786 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
2787 {
2788 context->recordError(Error(GL_INVALID_OPERATION,
2789 "Invalid access bits when mapping buffer for reading: 0x%X.",
2790 access));
2791 return false;
2792 }
2793
2794 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
2795 {
2796 context->recordError(Error(
2797 GL_INVALID_OPERATION,
2798 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
2799 return false;
2800 }
2801 return true;
2802}
2803
2804bool ValidateFlushMappedBufferRangeBase(Context *context,
2805 GLenum target,
2806 GLintptr offset,
2807 GLsizeiptr length)
2808{
2809 if (offset < 0 || length < 0)
2810 {
2811 context->recordError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
2812 return false;
2813 }
2814
2815 if (!ValidBufferTarget(context, target))
2816 {
2817 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
2818 return false;
2819 }
2820
2821 Buffer *buffer = context->getState().getTargetBuffer(target);
2822
2823 if (buffer == nullptr)
2824 {
2825 context->recordError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
2826 return false;
2827 }
2828
2829 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
2830 {
2831 context->recordError(Error(
2832 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
2833 return false;
2834 }
2835
2836 // Check for buffer overflow
2837 size_t offsetSize = static_cast<size_t>(offset);
2838 size_t lengthSize = static_cast<size_t>(length);
2839
2840 if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
2841 offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
2842 {
2843 context->recordError(
2844 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
2845 return false;
2846 }
2847
2848 return true;
2849}
2850
Olli Etuaho41997e72016-03-10 13:38:39 +02002851bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2852{
2853 return ValidateGenOrDelete(context, n);
2854}
2855
2856bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2857{
2858 return ValidateGenOrDelete(context, n);
2859}
2860
2861bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2862{
2863 return ValidateGenOrDelete(context, n);
2864}
2865
2866bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2867{
2868 return ValidateGenOrDelete(context, n);
2869}
2870
2871bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2872{
2873 return ValidateGenOrDelete(context, n);
2874}
2875
2876bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2877{
2878 return ValidateGenOrDelete(context, n);
2879}
2880
2881bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2882{
2883 return ValidateGenOrDelete(context, n);
2884}
2885
2886bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2887{
2888 return ValidateGenOrDelete(context, n);
2889}
2890
2891bool ValidateGenOrDelete(Context *context, GLint n)
2892{
2893 if (n < 0)
2894 {
2895 context->recordError(Error(GL_INVALID_VALUE, "n < 0"));
2896 return false;
2897 }
2898 return true;
2899}
2900
Jamie Madillc29968b2016-01-20 11:17:23 -05002901} // namespace gl