blob: c06eb7a11b7114d27ba8c38556d9f2084645e17c [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 Madillfb57c042016-03-10 11:35:17 -050071 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 Madillfb57c042016-03-10 11:35:17 -050076 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040077 {
Jamie Madillfb57c042016-03-10 11:35:17 -050078 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
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001104bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
1105{
1106 if (n < 0)
1107 {
1108 context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
1109 return false;
1110 }
1111
1112 return true;
1113}
1114
1115bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
1116{
1117 if (!context->getExtensions().occlusionQueryBoolean &&
1118 !context->getExtensions().disjointTimerQuery)
1119 {
1120 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1121 return false;
1122 }
1123
1124 return ValidateGenQueriesBase(context, n, ids);
1125}
1126
1127bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
1128{
1129 if (n < 0)
1130 {
1131 context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
1132 return false;
1133 }
1134
1135 return true;
1136}
1137
1138bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
1139{
1140 if (!context->getExtensions().occlusionQueryBoolean &&
1141 !context->getExtensions().disjointTimerQuery)
1142 {
1143 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1144 return false;
1145 }
1146
1147 return ValidateDeleteQueriesBase(context, n, ids);
1148}
1149
1150bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001151{
1152 if (!ValidQueryType(context, target))
1153 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001154 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001155 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001156 }
1157
1158 if (id == 0)
1159 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001160 context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001161 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001162 }
1163
1164 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1165 // of zero, if the active query object name for <target> is non-zero (for the
1166 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1167 // the active query for either target is non-zero), if <id> is the name of an
1168 // existing query object whose type does not match <target>, or if <id> is the
1169 // active query object name for any query type, the error INVALID_OPERATION is
1170 // generated.
1171
1172 // Ensure no other queries are active
1173 // NOTE: If other queries than occlusion are supported, we will need to check
1174 // separately that:
1175 // a) The query ID passed is not the current active query for any target/type
1176 // b) There are no active queries for the requested target (and in the case
1177 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1178 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001179
1180 // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
1181 // same time
Shannon Woods53a94a82014-06-24 15:20:36 -04001182 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001183 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001184 context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001185 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001186 }
1187
1188 Query *queryObject = context->getQuery(id, true, target);
1189
1190 // check that name was obtained with glGenQueries
1191 if (!queryObject)
1192 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001193 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001194 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001195 }
1196
1197 // check for type mismatch
1198 if (queryObject->getType() != target)
1199 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001200 context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001201 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001202 }
1203
1204 return true;
1205}
1206
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001207bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1208{
1209 if (!context->getExtensions().occlusionQueryBoolean &&
1210 !context->getExtensions().disjointTimerQuery)
1211 {
1212 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1213 return false;
1214 }
1215
1216 return ValidateBeginQueryBase(context, target, id);
1217}
1218
1219bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001220{
1221 if (!ValidQueryType(context, target))
1222 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001223 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001224 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001225 }
1226
Shannon Woods53a94a82014-06-24 15:20:36 -04001227 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001228
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001229 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001230 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001231 context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001232 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001233 }
1234
Jamie Madill45c785d2014-05-13 14:09:34 -04001235 return true;
1236}
1237
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001238bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1239{
1240 if (!context->getExtensions().occlusionQueryBoolean &&
1241 !context->getExtensions().disjointTimerQuery)
1242 {
1243 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1244 return false;
1245 }
1246
1247 return ValidateEndQueryBase(context, target);
1248}
1249
1250bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1251{
1252 if (!context->getExtensions().disjointTimerQuery)
1253 {
1254 context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
1255 return false;
1256 }
1257
1258 if (target != GL_TIMESTAMP_EXT)
1259 {
1260 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
1261 return false;
1262 }
1263
1264 Query *queryObject = context->getQuery(id, true, target);
1265 if (queryObject == nullptr)
1266 {
1267 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
1268 return false;
1269 }
1270
1271 if (context->getState().isQueryActive(queryObject))
1272 {
1273 context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
1274 return false;
1275 }
1276
1277 return true;
1278}
1279
1280bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1281{
1282 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1283 {
1284 context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
1285 return false;
1286 }
1287
1288 switch (pname)
1289 {
1290 case GL_CURRENT_QUERY_EXT:
1291 if (target == GL_TIMESTAMP_EXT)
1292 {
1293 context->recordError(
1294 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1295 return false;
1296 }
1297 break;
1298 case GL_QUERY_COUNTER_BITS_EXT:
1299 if (!context->getExtensions().disjointTimerQuery ||
1300 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1301 {
1302 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1303 return false;
1304 }
1305 break;
1306 default:
1307 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1308 return false;
1309 }
1310
1311 return true;
1312}
1313
1314bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1315{
1316 if (!context->getExtensions().occlusionQueryBoolean &&
1317 !context->getExtensions().disjointTimerQuery)
1318 {
1319 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1320 return false;
1321 }
1322
1323 return ValidateGetQueryivBase(context, target, pname);
1324}
1325
1326bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1327{
1328 Query *queryObject = context->getQuery(id, false, GL_NONE);
1329
1330 if (!queryObject)
1331 {
1332 context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
1333 return false;
1334 }
1335
1336 if (context->getState().isQueryActive(queryObject))
1337 {
1338 context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
1339 return false;
1340 }
1341
1342 switch (pname)
1343 {
1344 case GL_QUERY_RESULT_EXT:
1345 case GL_QUERY_RESULT_AVAILABLE_EXT:
1346 break;
1347
1348 default:
1349 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
1350 return false;
1351 }
1352
1353 return true;
1354}
1355
1356bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1357{
1358 if (!context->getExtensions().disjointTimerQuery)
1359 {
1360 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1361 return false;
1362 }
1363 return ValidateGetQueryObjectValueBase(context, id, pname);
1364}
1365
1366bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1367{
1368 if (!context->getExtensions().disjointTimerQuery &&
1369 !context->getExtensions().occlusionQueryBoolean)
1370 {
1371 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1372 return false;
1373 }
1374 return ValidateGetQueryObjectValueBase(context, id, pname);
1375}
1376
1377bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1378{
1379 if (!context->getExtensions().disjointTimerQuery)
1380 {
1381 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1382 return false;
1383 }
1384 return ValidateGetQueryObjectValueBase(context, id, pname);
1385}
1386
1387bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1388{
1389 if (!context->getExtensions().disjointTimerQuery)
1390 {
1391 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1392 return false;
1393 }
1394 return ValidateGetQueryObjectValueBase(context, id, pname);
1395}
1396
Jamie Madill62d31cb2015-09-11 13:25:51 -04001397static bool ValidateUniformCommonBase(gl::Context *context,
1398 GLenum targetUniformType,
1399 GLint location,
1400 GLsizei count,
1401 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001402{
1403 if (count < 0)
1404 {
Geoff Langb1196682014-07-23 13:47:29 -04001405 context->recordError(Error(GL_INVALID_VALUE));
1406 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001407 }
1408
Geoff Lang7dd2e102014-11-10 15:19:26 -05001409 gl::Program *program = context->getState().getProgram();
1410 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001411 {
Geoff Langb1196682014-07-23 13:47:29 -04001412 context->recordError(Error(GL_INVALID_OPERATION));
1413 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001414 }
1415
1416 if (location == -1)
1417 {
1418 // Silently ignore the uniform command
1419 return false;
1420 }
1421
Geoff Lang7dd2e102014-11-10 15:19:26 -05001422 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001423 {
Geoff Langb1196682014-07-23 13:47:29 -04001424 context->recordError(Error(GL_INVALID_OPERATION));
1425 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001426 }
1427
Jamie Madill62d31cb2015-09-11 13:25:51 -04001428 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001429
1430 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001431 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001432 {
Geoff Langb1196682014-07-23 13:47:29 -04001433 context->recordError(Error(GL_INVALID_OPERATION));
1434 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001435 }
1436
Jamie Madill62d31cb2015-09-11 13:25:51 -04001437 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001438 return true;
1439}
1440
Jamie Madillaa981bd2014-05-20 10:55:55 -04001441bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1442{
1443 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001444 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001445 {
Geoff Langb1196682014-07-23 13:47:29 -04001446 context->recordError(Error(GL_INVALID_OPERATION));
1447 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001448 }
1449
Jamie Madill62d31cb2015-09-11 13:25:51 -04001450 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001451 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1452 {
1453 return false;
1454 }
1455
Jamie Madillf2575982014-06-25 16:04:54 -04001456 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001457 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001458 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1459 {
Geoff Langb1196682014-07-23 13:47:29 -04001460 context->recordError(Error(GL_INVALID_OPERATION));
1461 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001462 }
1463
1464 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001465}
1466
1467bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1468 GLboolean transpose)
1469{
1470 // Check for ES3 uniform entry points
1471 int rows = VariableRowCount(matrixType);
1472 int cols = VariableColumnCount(matrixType);
1473 if (rows != cols && context->getClientVersion() < 3)
1474 {
Geoff Langb1196682014-07-23 13:47:29 -04001475 context->recordError(Error(GL_INVALID_OPERATION));
1476 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001477 }
1478
1479 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1480 {
Geoff Langb1196682014-07-23 13:47:29 -04001481 context->recordError(Error(GL_INVALID_VALUE));
1482 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001483 }
1484
Jamie Madill62d31cb2015-09-11 13:25:51 -04001485 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001486 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1487 {
1488 return false;
1489 }
1490
1491 if (uniform->type != matrixType)
1492 {
Geoff Langb1196682014-07-23 13:47:29 -04001493 context->recordError(Error(GL_INVALID_OPERATION));
1494 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001495 }
1496
1497 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001498}
1499
Jamie Madill893ab082014-05-16 16:56:10 -04001500bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1501{
1502 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1503 {
Geoff Langb1196682014-07-23 13:47:29 -04001504 context->recordError(Error(GL_INVALID_ENUM));
1505 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001506 }
1507
Jamie Madill0af26e12015-03-05 19:54:33 -05001508 const Caps &caps = context->getCaps();
1509
Jamie Madill893ab082014-05-16 16:56:10 -04001510 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1511 {
1512 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1513
Jamie Madill0af26e12015-03-05 19:54:33 -05001514 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001515 {
Geoff Langb1196682014-07-23 13:47:29 -04001516 context->recordError(Error(GL_INVALID_OPERATION));
1517 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001518 }
1519 }
1520
1521 switch (pname)
1522 {
1523 case GL_TEXTURE_BINDING_2D:
1524 case GL_TEXTURE_BINDING_CUBE_MAP:
1525 case GL_TEXTURE_BINDING_3D:
1526 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001527 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
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 break;
1533
1534 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1535 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1536 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001537 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001538 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001539 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001540 {
Geoff Langb1196682014-07-23 13:47:29 -04001541 context->recordError(Error(GL_INVALID_OPERATION));
1542 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001543 }
1544
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001545 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001546 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001547 {
Geoff Langb1196682014-07-23 13:47:29 -04001548 context->recordError(Error(GL_INVALID_OPERATION));
1549 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001550 }
1551 }
1552 break;
1553
1554 default:
1555 break;
1556 }
1557
1558 // pname is valid, but there are no parameters to return
1559 if (numParams == 0)
1560 {
1561 return false;
1562 }
1563
1564 return true;
1565}
1566
Jamie Madillc29968b2016-01-20 11:17:23 -05001567bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1568 GLenum target,
1569 GLint level,
1570 GLenum internalformat,
1571 bool isSubImage,
1572 GLint xoffset,
1573 GLint yoffset,
1574 GLint zoffset,
1575 GLint x,
1576 GLint y,
1577 GLsizei width,
1578 GLsizei height,
1579 GLint border,
1580 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001581{
Jamie Madill560a8d82014-05-21 13:06:20 -04001582 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1583 {
Geoff Langb1196682014-07-23 13:47:29 -04001584 context->recordError(Error(GL_INVALID_VALUE));
1585 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001586 }
1587
1588 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1589 {
Geoff Langb1196682014-07-23 13:47:29 -04001590 context->recordError(Error(GL_INVALID_VALUE));
1591 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001592 }
1593
1594 if (border != 0)
1595 {
Geoff Langb1196682014-07-23 13:47:29 -04001596 context->recordError(Error(GL_INVALID_VALUE));
1597 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001598 }
1599
1600 if (!ValidMipLevel(context, target, level))
1601 {
Geoff Langb1196682014-07-23 13:47:29 -04001602 context->recordError(Error(GL_INVALID_VALUE));
1603 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001604 }
1605
Jamie Madillc29968b2016-01-20 11:17:23 -05001606 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001607 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001608 {
Geoff Langb1196682014-07-23 13:47:29 -04001609 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1610 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001611 }
1612
Jamie Madillc29968b2016-01-20 11:17:23 -05001613 const auto &state = context->getState();
1614 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001615 {
Geoff Langb1196682014-07-23 13:47:29 -04001616 context->recordError(Error(GL_INVALID_OPERATION));
1617 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001618 }
1619
Geoff Langaae65a42014-05-26 12:43:44 -04001620 const gl::Caps &caps = context->getCaps();
1621
Geoff Langaae65a42014-05-26 12:43:44 -04001622 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001623 switch (target)
1624 {
1625 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001626 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001627 break;
1628
1629 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1630 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1631 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1632 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1633 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1634 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001635 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001636 break;
1637
1638 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001639 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001640 break;
1641
1642 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001643 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001644 break;
1645
1646 default:
Geoff Langb1196682014-07-23 13:47:29 -04001647 context->recordError(Error(GL_INVALID_ENUM));
1648 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001649 }
1650
Jamie Madillc29968b2016-01-20 11:17:23 -05001651 gl::Texture *texture =
1652 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001653 if (!texture)
1654 {
Geoff Langb1196682014-07-23 13:47:29 -04001655 context->recordError(Error(GL_INVALID_OPERATION));
1656 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001657 }
1658
Geoff Lang69cce582015-09-17 13:20:36 -04001659 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001660 {
Geoff Langb1196682014-07-23 13:47:29 -04001661 context->recordError(Error(GL_INVALID_OPERATION));
1662 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001663 }
1664
Geoff Lang5d601382014-07-22 15:14:06 -04001665 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1666
1667 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001668 {
Geoff Langb1196682014-07-23 13:47:29 -04001669 context->recordError(Error(GL_INVALID_OPERATION));
1670 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001671 }
1672
Geoff Langa9be0dc2014-12-17 12:34:40 -05001673 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001674 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001675 context->recordError(Error(GL_INVALID_OPERATION));
1676 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001677 }
1678
1679 if (isSubImage)
1680 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001681 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1682 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1683 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001684 {
Geoff Langb1196682014-07-23 13:47:29 -04001685 context->recordError(Error(GL_INVALID_VALUE));
1686 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001687 }
1688 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001689 else
1690 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001691 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001692 {
Geoff Langb1196682014-07-23 13:47:29 -04001693 context->recordError(Error(GL_INVALID_VALUE));
1694 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001695 }
1696
Geoff Lang5d601382014-07-22 15:14:06 -04001697 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001698 {
Geoff Langb1196682014-07-23 13:47:29 -04001699 context->recordError(Error(GL_INVALID_ENUM));
1700 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001701 }
1702
1703 int maxLevelDimension = (maxDimension >> level);
1704 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1705 {
Geoff Langb1196682014-07-23 13:47:29 -04001706 context->recordError(Error(GL_INVALID_VALUE));
1707 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001708 }
1709 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001710
Geoff Langa9be0dc2014-12-17 12:34:40 -05001711 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001712 return true;
1713}
1714
Jamie Madillf25855c2015-11-03 11:06:18 -05001715static bool ValidateDrawBase(ValidationContext *context,
1716 GLenum mode,
1717 GLsizei count,
1718 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001719{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001720 switch (mode)
1721 {
1722 case GL_POINTS:
1723 case GL_LINES:
1724 case GL_LINE_LOOP:
1725 case GL_LINE_STRIP:
1726 case GL_TRIANGLES:
1727 case GL_TRIANGLE_STRIP:
1728 case GL_TRIANGLE_FAN:
1729 break;
1730 default:
Geoff Langb1196682014-07-23 13:47:29 -04001731 context->recordError(Error(GL_INVALID_ENUM));
1732 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001733 }
1734
Jamie Madill250d33f2014-06-06 17:09:03 -04001735 if (count < 0)
1736 {
Geoff Langb1196682014-07-23 13:47:29 -04001737 context->recordError(Error(GL_INVALID_VALUE));
1738 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001739 }
1740
Geoff Langb1196682014-07-23 13:47:29 -04001741 const State &state = context->getState();
1742
Jamie Madill250d33f2014-06-06 17:09:03 -04001743 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001744 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001745 {
Geoff Langb1196682014-07-23 13:47:29 -04001746 context->recordError(Error(GL_INVALID_OPERATION));
1747 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001748 }
1749
Geoff Lang3a86ad32015-09-01 11:47:05 -04001750 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001751 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001752 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1753 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1754 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1755 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1756 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1757 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1758 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001759 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001760 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1761 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001762 {
1763 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1764 // Section 6.10 of the WebGL 1.0 spec
1765 ERR(
1766 "This ANGLE implementation does not support separate front/back stencil "
1767 "writemasks, reference values, or stencil mask values.");
1768 context->recordError(Error(GL_INVALID_OPERATION));
1769 return false;
1770 }
Jamie Madillac528012014-06-20 13:21:23 -04001771 }
1772
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001773 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001774 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001775 {
Geoff Langb1196682014-07-23 13:47:29 -04001776 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1777 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001778 }
1779
Geoff Lang7dd2e102014-11-10 15:19:26 -05001780 gl::Program *program = state.getProgram();
1781 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001782 {
Geoff Langb1196682014-07-23 13:47:29 -04001783 context->recordError(Error(GL_INVALID_OPERATION));
1784 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001785 }
1786
Geoff Lang7dd2e102014-11-10 15:19:26 -05001787 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001788 {
Geoff Langb1196682014-07-23 13:47:29 -04001789 context->recordError(Error(GL_INVALID_OPERATION));
1790 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001791 }
1792
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001793 // Uniform buffer validation
1794 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1795 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001796 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001797 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001798 const OffsetBindingPointer<Buffer> &uniformBuffer =
1799 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001800
Geoff Lang5d124a62015-09-15 13:03:27 -04001801 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001802 {
1803 // undefined behaviour
1804 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1805 return false;
1806 }
1807
Geoff Lang5d124a62015-09-15 13:03:27 -04001808 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001809 if (uniformBufferSize == 0)
1810 {
1811 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001812 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001813 }
1814
Jamie Madill62d31cb2015-09-11 13:25:51 -04001815 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001816 {
1817 // undefined behaviour
1818 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1819 return false;
1820 }
1821 }
1822
Jamie Madill250d33f2014-06-06 17:09:03 -04001823 // No-op if zero count
1824 return (count > 0);
1825}
1826
Geoff Langb1196682014-07-23 13:47:29 -04001827bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001828{
Jamie Madillfd716582014-06-06 17:09:04 -04001829 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001830 {
Geoff Langb1196682014-07-23 13:47:29 -04001831 context->recordError(Error(GL_INVALID_VALUE));
1832 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001833 }
1834
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001835 const State &state = context->getState();
1836 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001837 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1838 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001839 {
1840 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1841 // that does not match the current transform feedback object's draw mode (if transform feedback
1842 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001843 context->recordError(Error(GL_INVALID_OPERATION));
1844 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001845 }
1846
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001847 if (!ValidateDrawBase(context, mode, count, primcount))
1848 {
1849 return false;
1850 }
1851
1852 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001853 {
1854 return false;
1855 }
1856
1857 return true;
1858}
1859
Geoff Langb1196682014-07-23 13:47:29 -04001860bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001861{
1862 if (primcount < 0)
1863 {
Geoff Langb1196682014-07-23 13:47:29 -04001864 context->recordError(Error(GL_INVALID_VALUE));
1865 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001866 }
1867
Jamie Madill2b976812014-08-25 15:47:49 -04001868 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001869 {
1870 return false;
1871 }
1872
1873 // No-op if zero primitive count
1874 return (primcount > 0);
1875}
1876
Geoff Lang87a93302014-09-16 13:29:43 -04001877static bool ValidateDrawInstancedANGLE(Context *context)
1878{
1879 // Verify there is at least one active attribute with a divisor of zero
1880 const gl::State& state = context->getState();
1881
Geoff Lang7dd2e102014-11-10 15:19:26 -05001882 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001883
1884 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001885 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001886 {
1887 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001888 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001889 {
1890 return true;
1891 }
1892 }
1893
1894 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1895 "has a divisor of zero."));
1896 return false;
1897}
1898
1899bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1900{
1901 if (!ValidateDrawInstancedANGLE(context))
1902 {
1903 return false;
1904 }
1905
1906 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1907}
1908
Jamie Madillf25855c2015-11-03 11:06:18 -05001909bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001910 GLenum mode,
1911 GLsizei count,
1912 GLenum type,
1913 const GLvoid *indices,
1914 GLsizei primcount,
1915 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001916{
Jamie Madill250d33f2014-06-06 17:09:03 -04001917 switch (type)
1918 {
1919 case GL_UNSIGNED_BYTE:
1920 case GL_UNSIGNED_SHORT:
1921 break;
1922 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001923 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001924 {
Geoff Langb1196682014-07-23 13:47:29 -04001925 context->recordError(Error(GL_INVALID_ENUM));
1926 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001927 }
1928 break;
1929 default:
Geoff Langb1196682014-07-23 13:47:29 -04001930 context->recordError(Error(GL_INVALID_ENUM));
1931 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001932 }
1933
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001934 const State &state = context->getState();
1935
1936 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001937 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001938 {
1939 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1940 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001941 context->recordError(Error(GL_INVALID_OPERATION));
1942 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001943 }
1944
1945 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001946 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001947 {
Geoff Langb1196682014-07-23 13:47:29 -04001948 context->recordError(Error(GL_INVALID_OPERATION));
1949 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001950 }
1951
Jamie Madill2b976812014-08-25 15:47:49 -04001952 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001953 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001954 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001955 {
Geoff Langb1196682014-07-23 13:47:29 -04001956 context->recordError(Error(GL_INVALID_OPERATION));
1957 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001958 }
1959
Jamie Madillae3000b2014-08-25 15:47:51 -04001960 if (elementArrayBuffer)
1961 {
1962 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1963
1964 GLint64 offset = reinterpret_cast<GLint64>(indices);
1965 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1966
1967 // check for integer overflows
1968 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1969 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1970 {
Geoff Langb1196682014-07-23 13:47:29 -04001971 context->recordError(Error(GL_OUT_OF_MEMORY));
1972 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001973 }
1974
1975 // Check for reading past the end of the bound buffer object
1976 if (byteCount > elementArrayBuffer->getSize())
1977 {
Geoff Langb1196682014-07-23 13:47:29 -04001978 context->recordError(Error(GL_INVALID_OPERATION));
1979 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001980 }
1981 }
1982 else if (!indices)
1983 {
1984 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001985 context->recordError(Error(GL_INVALID_OPERATION));
1986 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001987 }
1988
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001989 if (!ValidateDrawBase(context, mode, count, primcount))
1990 {
1991 return false;
1992 }
1993
Jamie Madill2b976812014-08-25 15:47:49 -04001994 // Use max index to validate if our vertex buffers are large enough for the pull.
1995 // TODO: offer fast path, with disabled index validation.
1996 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1997 if (elementArrayBuffer)
1998 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001999 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002000 Error error =
2001 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2002 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002003 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002004 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04002005 context->recordError(error);
2006 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002007 }
2008 }
2009 else
2010 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002011 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002012 }
2013
Jamie Madille79b1e12015-11-04 16:36:37 -05002014 // If we use an index greater than our maximum supported index range, return an error.
2015 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2016 // return an error if possible here.
2017 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2018 {
2019 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
2020 return false;
2021 }
2022
Jamie Madillfb57c042016-03-10 11:35:17 -05002023 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002024 {
2025 return false;
2026 }
2027
Geoff Lang3edfe032015-09-04 16:38:24 -04002028 // No op if there are no real indices in the index data (all are primitive restart).
2029 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002030}
2031
Geoff Langb1196682014-07-23 13:47:29 -04002032bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002033 GLenum mode,
2034 GLsizei count,
2035 GLenum type,
2036 const GLvoid *indices,
2037 GLsizei primcount,
2038 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002039{
2040 if (primcount < 0)
2041 {
Geoff Langb1196682014-07-23 13:47:29 -04002042 context->recordError(Error(GL_INVALID_VALUE));
2043 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002044 }
2045
Jamie Madill2b976812014-08-25 15:47:49 -04002046 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002047 {
2048 return false;
2049 }
2050
2051 // No-op zero primitive count
2052 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002053}
2054
Geoff Lang3edfe032015-09-04 16:38:24 -04002055bool ValidateDrawElementsInstancedANGLE(Context *context,
2056 GLenum mode,
2057 GLsizei count,
2058 GLenum type,
2059 const GLvoid *indices,
2060 GLsizei primcount,
2061 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002062{
2063 if (!ValidateDrawInstancedANGLE(context))
2064 {
2065 return false;
2066 }
2067
2068 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2069}
2070
Geoff Langb1196682014-07-23 13:47:29 -04002071bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002072 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002073{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002074 if (!ValidFramebufferTarget(target))
2075 {
Geoff Langb1196682014-07-23 13:47:29 -04002076 context->recordError(Error(GL_INVALID_ENUM));
2077 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002078 }
2079
2080 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002081 {
2082 return false;
2083 }
2084
Jamie Madill55ec3b12014-07-03 10:38:57 -04002085 if (texture != 0)
2086 {
2087 gl::Texture *tex = context->getTexture(texture);
2088
2089 if (tex == NULL)
2090 {
Geoff Langb1196682014-07-23 13:47:29 -04002091 context->recordError(Error(GL_INVALID_OPERATION));
2092 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002093 }
2094
2095 if (level < 0)
2096 {
Geoff Langb1196682014-07-23 13:47:29 -04002097 context->recordError(Error(GL_INVALID_VALUE));
2098 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002099 }
2100 }
2101
Shannon Woods53a94a82014-06-24 15:20:36 -04002102 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002103 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002104
Jamie Madill84115c92015-04-23 15:00:07 -04002105 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002106 {
Jamie Madill84115c92015-04-23 15:00:07 -04002107 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002108 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002109 }
2110
2111 return true;
2112}
2113
Geoff Langb1196682014-07-23 13:47:29 -04002114bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002115 GLenum textarget, GLuint texture, GLint level)
2116{
Geoff Lang95663912015-04-02 15:54:45 -04002117 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2118 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002119 {
Geoff Langb1196682014-07-23 13:47:29 -04002120 context->recordError(Error(GL_INVALID_VALUE));
2121 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002122 }
2123
2124 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002125 {
2126 return false;
2127 }
2128
Jamie Madill55ec3b12014-07-03 10:38:57 -04002129 if (texture != 0)
2130 {
2131 gl::Texture *tex = context->getTexture(texture);
2132 ASSERT(tex);
2133
Jamie Madill2a6564e2014-07-11 09:53:19 -04002134 const gl::Caps &caps = context->getCaps();
2135
Jamie Madill55ec3b12014-07-03 10:38:57 -04002136 switch (textarget)
2137 {
2138 case GL_TEXTURE_2D:
2139 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002140 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002141 {
Geoff Langb1196682014-07-23 13:47:29 -04002142 context->recordError(Error(GL_INVALID_VALUE));
2143 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002144 }
2145 if (tex->getTarget() != GL_TEXTURE_2D)
2146 {
Geoff Langb1196682014-07-23 13:47:29 -04002147 context->recordError(Error(GL_INVALID_OPERATION));
2148 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002149 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002150 }
2151 break;
2152
2153 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2154 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2155 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2156 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2157 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2158 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2159 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002160 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002161 {
Geoff Langb1196682014-07-23 13:47:29 -04002162 context->recordError(Error(GL_INVALID_VALUE));
2163 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002164 }
2165 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2166 {
Geoff Langb1196682014-07-23 13:47:29 -04002167 context->recordError(Error(GL_INVALID_OPERATION));
2168 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002169 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002170 }
2171 break;
2172
2173 default:
Geoff Langb1196682014-07-23 13:47:29 -04002174 context->recordError(Error(GL_INVALID_ENUM));
2175 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002176 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002177
2178 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2179 if (internalFormatInfo.compressed)
2180 {
2181 context->recordError(Error(GL_INVALID_OPERATION));
2182 return false;
2183 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002184 }
2185
Jamie Madill570f7c82014-07-03 10:38:54 -04002186 return true;
2187}
2188
Geoff Langb1196682014-07-23 13:47:29 -04002189bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002190{
2191 if (program == 0)
2192 {
Geoff Langb1196682014-07-23 13:47:29 -04002193 context->recordError(Error(GL_INVALID_VALUE));
2194 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002195 }
2196
Dian Xiang769769a2015-09-09 15:20:08 -07002197 gl::Program *programObject = GetValidProgram(context, program);
2198 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002199 {
2200 return false;
2201 }
2202
Jamie Madill0063c512014-08-25 15:47:53 -04002203 if (!programObject || !programObject->isLinked())
2204 {
Geoff Langb1196682014-07-23 13:47:29 -04002205 context->recordError(Error(GL_INVALID_OPERATION));
2206 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002207 }
2208
Geoff Lang7dd2e102014-11-10 15:19:26 -05002209 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002210 {
Geoff Langb1196682014-07-23 13:47:29 -04002211 context->recordError(Error(GL_INVALID_OPERATION));
2212 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002213 }
2214
Jamie Madill0063c512014-08-25 15:47:53 -04002215 return true;
2216}
2217
Geoff Langb1196682014-07-23 13:47:29 -04002218bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002219{
2220 return ValidateGetUniformBase(context, program, location);
2221}
2222
Geoff Langb1196682014-07-23 13:47:29 -04002223bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002224{
Jamie Madill78f41802014-08-25 15:47:55 -04002225 return ValidateGetUniformBase(context, program, location);
2226}
2227
Geoff Langb1196682014-07-23 13:47:29 -04002228static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002229{
2230 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002231 {
Jamie Madill78f41802014-08-25 15:47:55 -04002232 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002233 }
2234
Jamie Madilla502c742014-08-28 17:19:13 -04002235 gl::Program *programObject = context->getProgram(program);
2236 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002237
Jamie Madill78f41802014-08-25 15:47:55 -04002238 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002239 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2240 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002241 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002242 {
Geoff Langb1196682014-07-23 13:47:29 -04002243 context->recordError(Error(GL_INVALID_OPERATION));
2244 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002245 }
2246
2247 return true;
2248}
2249
Geoff Langb1196682014-07-23 13:47:29 -04002250bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002251{
Jamie Madill78f41802014-08-25 15:47:55 -04002252 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002253}
2254
Geoff Langb1196682014-07-23 13:47:29 -04002255bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002256{
Jamie Madill78f41802014-08-25 15:47:55 -04002257 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002258}
2259
Austin Kinross08332632015-05-05 13:35:47 -07002260bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2261 const GLenum *attachments, bool defaultFramebuffer)
2262{
2263 if (numAttachments < 0)
2264 {
2265 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2266 return false;
2267 }
2268
2269 for (GLsizei i = 0; i < numAttachments; ++i)
2270 {
2271 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2272 {
2273 if (defaultFramebuffer)
2274 {
2275 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2276 return false;
2277 }
2278
2279 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2280 {
2281 context->recordError(Error(GL_INVALID_OPERATION,
2282 "Requested color attachment is greater than the maximum supported color attachments"));
2283 return false;
2284 }
2285 }
2286 else
2287 {
2288 switch (attachments[i])
2289 {
2290 case GL_DEPTH_ATTACHMENT:
2291 case GL_STENCIL_ATTACHMENT:
2292 case GL_DEPTH_STENCIL_ATTACHMENT:
2293 if (defaultFramebuffer)
2294 {
2295 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2296 return false;
2297 }
2298 break;
2299 case GL_COLOR:
2300 case GL_DEPTH:
2301 case GL_STENCIL:
2302 if (!defaultFramebuffer)
2303 {
2304 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2305 return false;
2306 }
2307 break;
2308 default:
2309 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2310 return false;
2311 }
2312 }
2313 }
2314
2315 return true;
2316}
2317
Austin Kinross6ee1e782015-05-29 17:05:37 -07002318bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2319{
2320 // Note that debug marker calls must not set error state
2321
2322 if (length < 0)
2323 {
2324 return false;
2325 }
2326
2327 if (marker == nullptr)
2328 {
2329 return false;
2330 }
2331
2332 return true;
2333}
2334
2335bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2336{
2337 // Note that debug marker calls must not set error state
2338
2339 if (length < 0)
2340 {
2341 return false;
2342 }
2343
2344 if (length > 0 && marker == nullptr)
2345 {
2346 return false;
2347 }
2348
2349 return true;
2350}
2351
Geoff Langdcab33b2015-07-21 13:03:16 -04002352bool ValidateEGLImageTargetTexture2DOES(Context *context,
2353 egl::Display *display,
2354 GLenum target,
2355 egl::Image *image)
2356{
Geoff Langa8406172015-07-21 16:53:39 -04002357 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2358 {
2359 context->recordError(Error(GL_INVALID_OPERATION));
2360 return false;
2361 }
2362
2363 switch (target)
2364 {
2365 case GL_TEXTURE_2D:
2366 break;
2367
2368 default:
2369 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2370 return false;
2371 }
2372
2373 if (!display->isValidImage(image))
2374 {
2375 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2376 return false;
2377 }
2378
2379 if (image->getSamples() > 0)
2380 {
2381 context->recordError(Error(GL_INVALID_OPERATION,
2382 "cannot create a 2D texture from a multisampled EGL image."));
2383 return false;
2384 }
2385
2386 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2387 if (!textureCaps.texturable)
2388 {
2389 context->recordError(Error(GL_INVALID_OPERATION,
2390 "EGL image internal format is not supported as a texture."));
2391 return false;
2392 }
2393
Geoff Langdcab33b2015-07-21 13:03:16 -04002394 return true;
2395}
2396
2397bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2398 egl::Display *display,
2399 GLenum target,
2400 egl::Image *image)
2401{
Geoff Langa8406172015-07-21 16:53:39 -04002402 if (!context->getExtensions().eglImage)
2403 {
2404 context->recordError(Error(GL_INVALID_OPERATION));
2405 return false;
2406 }
2407
2408 switch (target)
2409 {
2410 case GL_RENDERBUFFER:
2411 break;
2412
2413 default:
2414 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2415 return false;
2416 }
2417
2418 if (!display->isValidImage(image))
2419 {
2420 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2421 return false;
2422 }
2423
2424 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2425 if (!textureCaps.renderable)
2426 {
2427 context->recordError(Error(
2428 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2429 return false;
2430 }
2431
Geoff Langdcab33b2015-07-21 13:03:16 -04002432 return true;
2433}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002434
2435bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2436{
Geoff Lang36167ab2015-12-07 10:27:14 -05002437 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002438 {
2439 // The default VAO should always exist
2440 ASSERT(array != 0);
2441 context->recordError(Error(GL_INVALID_OPERATION));
2442 return false;
2443 }
2444
2445 return true;
2446}
2447
2448bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2449{
2450 if (n < 0)
2451 {
2452 context->recordError(Error(GL_INVALID_VALUE));
2453 return false;
2454 }
2455
2456 return true;
2457}
2458
2459bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2460{
2461 if (n < 0)
2462 {
2463 context->recordError(Error(GL_INVALID_VALUE));
2464 return false;
2465 }
2466
2467 return true;
2468}
Geoff Langc5629752015-12-07 16:29:04 -05002469
2470bool ValidateProgramBinaryBase(Context *context,
2471 GLuint program,
2472 GLenum binaryFormat,
2473 const void *binary,
2474 GLint length)
2475{
2476 Program *programObject = GetValidProgram(context, program);
2477 if (programObject == nullptr)
2478 {
2479 return false;
2480 }
2481
2482 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2483 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2484 programBinaryFormats.end())
2485 {
2486 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2487 return false;
2488 }
2489
2490 return true;
2491}
2492
2493bool ValidateGetProgramBinaryBase(Context *context,
2494 GLuint program,
2495 GLsizei bufSize,
2496 GLsizei *length,
2497 GLenum *binaryFormat,
2498 void *binary)
2499{
2500 Program *programObject = GetValidProgram(context, program);
2501 if (programObject == nullptr)
2502 {
2503 return false;
2504 }
2505
2506 if (!programObject->isLinked())
2507 {
2508 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2509 return false;
2510 }
2511
2512 return true;
2513}
Jamie Madillc29968b2016-01-20 11:17:23 -05002514
2515bool ValidateCopyTexImage2D(ValidationContext *context,
2516 GLenum target,
2517 GLint level,
2518 GLenum internalformat,
2519 GLint x,
2520 GLint y,
2521 GLsizei width,
2522 GLsizei height,
2523 GLint border)
2524{
2525 if (context->getClientVersion() < 3)
2526 {
2527 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2528 0, x, y, width, height, border);
2529 }
2530
2531 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002532 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2533 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002534}
Jamie Madillc29968b2016-01-20 11:17:23 -05002535
2536bool ValidateFramebufferRenderbuffer(Context *context,
2537 GLenum target,
2538 GLenum attachment,
2539 GLenum renderbuffertarget,
2540 GLuint renderbuffer)
2541{
2542 if (!ValidFramebufferTarget(target) ||
2543 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2544 {
2545 context->recordError(Error(GL_INVALID_ENUM));
2546 return false;
2547 }
2548
2549 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2550 renderbuffertarget, renderbuffer);
2551}
2552
2553bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2554{
2555 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2556 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2557 {
2558 context->recordError(
2559 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2560 return false;
2561 }
2562
2563 ASSERT(context->getState().getDrawFramebuffer());
2564 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2565 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2566
2567 // This should come first before the check for the default frame buffer
2568 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2569 // rather than INVALID_OPERATION
2570 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2571 {
2572 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2573
2574 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
2575 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
2576 bufs[colorAttachment] >= maxColorAttachment))
2577 {
2578 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
2579 // In the 3.0 specs, the error should return GL_INVALID_OPERATION.
2580 // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
2581 context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
2582 return false;
2583 }
2584 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2585 frameBufferId != 0)
2586 {
2587 // INVALID_OPERATION-GL is bound to buffer and ith argument
2588 // is not COLOR_ATTACHMENTi or NONE
2589 context->recordError(
2590 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2591 return false;
2592 }
2593 }
2594
2595 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2596 // and n is not 1 or bufs is bound to value other than BACK and NONE
2597 if (frameBufferId == 0)
2598 {
2599 if (n != 1)
2600 {
2601 context->recordError(Error(GL_INVALID_OPERATION,
2602 "n must be 1 when GL is bound to the default framebuffer"));
2603 return false;
2604 }
2605
2606 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2607 {
2608 context->recordError(Error(
2609 GL_INVALID_OPERATION,
2610 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2611 return false;
2612 }
2613 }
2614
2615 return true;
2616}
2617
2618bool ValidateCopyTexSubImage2D(Context *context,
2619 GLenum target,
2620 GLint level,
2621 GLint xoffset,
2622 GLint yoffset,
2623 GLint x,
2624 GLint y,
2625 GLsizei width,
2626 GLsizei height)
2627{
2628 if (context->getClientVersion() < 3)
2629 {
2630 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2631 yoffset, x, y, width, height, 0);
2632 }
2633
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002634 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2635 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002636}
2637
2638} // namespace gl