blob: 09471a7a5e3d015daa1fc5e6cdfddafb22b9ec12 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040071 GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
Jamie Madill1ca74672015-07-21 15:14:11 -040072
73 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
74 // We can return INVALID_OPERATION if our vertex attribute does not have
75 // enough backing data.
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040076 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040077 {
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040078 context->recordError(
79 Error(GL_INVALID_OPERATION,
80 "Vertex buffer is not big enough for the draw call"));
Jamie Madill1ca74672015-07-21 15:14:11 -040081 return false;
82 }
83 }
84 }
85 else if (attrib.pointer == NULL)
86 {
87 // This is an application error that would normally result in a crash,
88 // but we catch it and return an error
89 context->recordError(Error(
90 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
91 return false;
92 }
93 }
94 }
95
96 return true;
97}
98
99} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400100
Geoff Lang0550d032014-01-30 11:29:07 -0500101bool ValidCap(const Context *context, GLenum cap)
102{
103 switch (cap)
104 {
105 case GL_CULL_FACE:
106 case GL_POLYGON_OFFSET_FILL:
107 case GL_SAMPLE_ALPHA_TO_COVERAGE:
108 case GL_SAMPLE_COVERAGE:
109 case GL_SCISSOR_TEST:
110 case GL_STENCIL_TEST:
111 case GL_DEPTH_TEST:
112 case GL_BLEND:
113 case GL_DITHER:
114 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500115
Geoff Lang0550d032014-01-30 11:29:07 -0500116 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
117 case GL_RASTERIZER_DISCARD:
118 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500119
120 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
121 case GL_DEBUG_OUTPUT:
122 return context->getExtensions().debug;
123
Geoff Lang0550d032014-01-30 11:29:07 -0500124 default:
125 return false;
126 }
127}
128
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500129bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400130{
Jamie Madilld7460c72014-01-21 16:38:14 -0500131 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400132 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500133 case GL_TEXTURE_2D:
134 case GL_TEXTURE_CUBE_MAP:
135 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400136
Jamie Madilld7460c72014-01-21 16:38:14 -0500137 case GL_TEXTURE_3D:
138 case GL_TEXTURE_2D_ARRAY:
139 return (context->getClientVersion() >= 3);
140
141 default:
142 return false;
143 }
Jamie Madill35d15012013-10-07 10:46:37 -0400144}
145
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500146bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
147{
148 switch (target)
149 {
150 case GL_TEXTURE_2D:
151 case GL_TEXTURE_CUBE_MAP:
152 return true;
153
154 default:
155 return false;
156 }
157}
158
159bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
160{
161 switch (target)
162 {
163 case GL_TEXTURE_3D:
164 case GL_TEXTURE_2D_ARRAY:
165 return (context->getClientVersion() >= 3);
166
167 default:
168 return false;
169 }
170}
171
Shannon Woods4dfed832014-03-17 20:03:39 -0400172// This function differs from ValidTextureTarget in that the target must be
173// usable as the destination of a 2D operation-- so a cube face is valid, but
174// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400175// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500176bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400177{
178 switch (target)
179 {
180 case GL_TEXTURE_2D:
181 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
182 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
183 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
184 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
185 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
186 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
187 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500188 default:
189 return false;
190 }
191}
192
193bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
194{
195 switch (target)
196 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400197 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500198 case GL_TEXTURE_2D_ARRAY:
199 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400200 default:
201 return false;
202 }
203}
204
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500205bool ValidFramebufferTarget(GLenum target)
206{
Geoff Langd4475812015-03-18 10:53:05 -0400207 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
208 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500209
210 switch (target)
211 {
212 case GL_FRAMEBUFFER: return true;
213 case GL_READ_FRAMEBUFFER: return true;
214 case GL_DRAW_FRAMEBUFFER: return true;
215 default: return false;
216 }
217}
218
Jamie Madill8c96d582014-03-05 15:01:23 -0500219bool ValidBufferTarget(const Context *context, GLenum target)
220{
221 switch (target)
222 {
223 case GL_ARRAY_BUFFER:
224 case GL_ELEMENT_ARRAY_BUFFER:
225 return true;
226
Jamie Madill8c96d582014-03-05 15:01:23 -0500227 case GL_PIXEL_PACK_BUFFER:
228 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400229 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400230
Shannon Woodsb3801742014-03-27 14:59:19 -0400231 case GL_COPY_READ_BUFFER:
232 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500233 case GL_TRANSFORM_FEEDBACK_BUFFER:
234 case GL_UNIFORM_BUFFER:
235 return (context->getClientVersion() >= 3);
236
237 default:
238 return false;
239 }
240}
241
Jamie Madill70656a62014-03-05 15:01:26 -0500242bool ValidBufferParameter(const Context *context, GLenum pname)
243{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400244 const Extensions &extensions = context->getExtensions();
245
Jamie Madill70656a62014-03-05 15:01:26 -0500246 switch (pname)
247 {
248 case GL_BUFFER_USAGE:
249 case GL_BUFFER_SIZE:
250 return true;
251
Geoff Langcc6f55d2015-03-20 13:01:02 -0400252 case GL_BUFFER_ACCESS_OES:
253 return extensions.mapBuffer;
254
255 case GL_BUFFER_MAPPED:
256 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
257 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
258
Jamie Madill70656a62014-03-05 15:01:26 -0500259 // GL_BUFFER_MAP_POINTER is a special case, and may only be
260 // queried with GetBufferPointerv
261 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500262 case GL_BUFFER_MAP_OFFSET:
263 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400264 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500265
266 default:
267 return false;
268 }
269}
270
Jamie Madillc29968b2016-01-20 11:17:23 -0500271bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400272{
Jamie Madillc29968b2016-01-20 11:17:23 -0500273 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400274 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400275 switch (target)
276 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500277 case GL_TEXTURE_2D:
278 maxDimension = caps.max2DTextureSize;
279 break;
Geoff Langce635692013-09-24 13:56:32 -0400280 case GL_TEXTURE_CUBE_MAP:
281 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
282 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
283 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
284 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
285 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500286 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
287 maxDimension = caps.maxCubeMapTextureSize;
288 break;
289 case GL_TEXTURE_3D:
290 maxDimension = caps.max3DTextureSize;
291 break;
292 case GL_TEXTURE_2D_ARRAY:
293 maxDimension = caps.max2DTextureSize;
294 break;
Geoff Langce635692013-09-24 13:56:32 -0400295 default: UNREACHABLE();
296 }
297
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700298 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400299}
300
Austin Kinross08528e12015-10-07 16:24:40 -0700301bool ValidImageSizeParameters(const Context *context,
302 GLenum target,
303 GLint level,
304 GLsizei width,
305 GLsizei height,
306 GLsizei depth,
307 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400308{
309 if (level < 0 || width < 0 || height < 0 || depth < 0)
310 {
311 return false;
312 }
313
Austin Kinross08528e12015-10-07 16:24:40 -0700314 // TexSubImage parameters can be NPOT without textureNPOT extension,
315 // as long as the destination texture is POT.
316 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400317 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400318 {
319 return false;
320 }
321
322 if (!ValidMipLevel(context, target, level))
323 {
324 return false;
325 }
326
327 return true;
328}
329
Geoff Lang0d8b7242015-09-09 14:56:53 -0400330bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
331{
332 // List of compressed format that require that the texture size is smaller than or a multiple of
333 // the compressed block size.
334 switch (internalFormat)
335 {
336 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
337 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
338 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
339 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800340 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400341 return true;
342
343 default:
344 return false;
345 }
346}
347
Jamie Madillc29968b2016-01-20 11:17:23 -0500348bool ValidCompressedImageSize(const ValidationContext *context,
349 GLenum internalFormat,
350 GLsizei width,
351 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400352{
Geoff Lang5d601382014-07-22 15:14:06 -0400353 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
354 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400355 {
356 return false;
357 }
358
Geoff Lang0d8b7242015-09-09 14:56:53 -0400359 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400360 {
361 return false;
362 }
363
Geoff Lang0d8b7242015-09-09 14:56:53 -0400364 if (CompressedTextureFormatRequiresExactSize(internalFormat))
365 {
366 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
367 width % formatInfo.compressedBlockWidth != 0) ||
368 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
369 height % formatInfo.compressedBlockHeight != 0))
370 {
371 return false;
372 }
373 }
374
Geoff Langd4f180b2013-09-24 13:57:44 -0400375 return true;
376}
377
Geoff Lang37dde692014-01-31 16:34:54 -0500378bool ValidQueryType(const Context *context, GLenum queryType)
379{
Geoff Langd4475812015-03-18 10:53:05 -0400380 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
381 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500382
383 switch (queryType)
384 {
385 case GL_ANY_SAMPLES_PASSED:
386 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
387 return true;
388 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
389 return (context->getClientVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500390 case GL_TIME_ELAPSED_EXT:
391 return context->getExtensions().disjointTimerQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500392 default:
393 return false;
394 }
395}
396
Dian Xiang769769a2015-09-09 15:20:08 -0700397Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500398{
399 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
400 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
401 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
402
Dian Xiang769769a2015-09-09 15:20:08 -0700403 Program *validProgram = context->getProgram(id);
404
405 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500406 {
Dian Xiang769769a2015-09-09 15:20:08 -0700407 if (context->getShader(id))
408 {
409 context->recordError(
410 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
411 }
412 else
413 {
414 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
415 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500416 }
Dian Xiang769769a2015-09-09 15:20:08 -0700417
418 return validProgram;
419}
420
421Shader *GetValidShader(Context *context, GLuint id)
422{
423 // See ValidProgram for spec details.
424
425 Shader *validShader = context->getShader(id);
426
427 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500428 {
Dian Xiang769769a2015-09-09 15:20:08 -0700429 if (context->getProgram(id))
430 {
431 context->recordError(
432 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
433 }
434 else
435 {
436 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
437 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500438 }
Dian Xiang769769a2015-09-09 15:20:08 -0700439
440 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500441}
442
Geoff Langb1196682014-07-23 13:47:29 -0400443bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400444{
445 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
446 {
447 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
448
Geoff Langaae65a42014-05-26 12:43:44 -0400449 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400450 {
Geoff Langb1196682014-07-23 13:47:29 -0400451 context->recordError(Error(GL_INVALID_VALUE));
452 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400453 }
454 }
455 else
456 {
457 switch (attachment)
458 {
459 case GL_DEPTH_ATTACHMENT:
460 case GL_STENCIL_ATTACHMENT:
461 break;
462
463 case GL_DEPTH_STENCIL_ATTACHMENT:
464 if (context->getClientVersion() < 3)
465 {
Geoff Langb1196682014-07-23 13:47:29 -0400466 context->recordError(Error(GL_INVALID_ENUM));
467 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400468 }
469 break;
470
471 default:
Geoff Langb1196682014-07-23 13:47:29 -0400472 context->recordError(Error(GL_INVALID_ENUM));
473 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400474 }
475 }
476
477 return true;
478}
479
Corentin Walleze0902642014-11-04 12:32:15 -0800480bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
481 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400482{
483 switch (target)
484 {
485 case GL_RENDERBUFFER:
486 break;
487 default:
Geoff Langb1196682014-07-23 13:47:29 -0400488 context->recordError(Error(GL_INVALID_ENUM));
489 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400490 }
491
492 if (width < 0 || height < 0 || samples < 0)
493 {
Geoff Langb1196682014-07-23 13:47:29 -0400494 context->recordError(Error(GL_INVALID_VALUE));
495 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400496 }
497
Geoff Langd87878e2014-09-19 15:42:59 -0400498 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
499 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500 {
Geoff Langb1196682014-07-23 13:47:29 -0400501 context->recordError(Error(GL_INVALID_ENUM));
502 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400503 }
504
505 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
506 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800507 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400508 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400509 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400510 {
Geoff Langb1196682014-07-23 13:47:29 -0400511 context->recordError(Error(GL_INVALID_ENUM));
512 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 }
514
Geoff Langaae65a42014-05-26 12:43:44 -0400515 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 {
Geoff Langb1196682014-07-23 13:47:29 -0400517 context->recordError(Error(GL_INVALID_VALUE));
518 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 }
520
Shannon Woods53a94a82014-06-24 15:20:36 -0400521 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 if (handle == 0)
523 {
Geoff Langb1196682014-07-23 13:47:29 -0400524 context->recordError(Error(GL_INVALID_OPERATION));
525 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400526 }
527
528 return true;
529}
530
Corentin Walleze0902642014-11-04 12:32:15 -0800531bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
532 GLenum internalformat, GLsizei width, GLsizei height)
533{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800534 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800535
536 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400537 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800538 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400539 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800540 {
541 context->recordError(Error(GL_INVALID_VALUE));
542 return false;
543 }
544
545 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
546 // the specified storage. This is different than ES 3.0 in which a sample number higher
547 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800548 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
549 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800550 {
Geoff Langa4903b72015-03-02 16:02:48 -0800551 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
552 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
553 {
554 context->recordError(Error(GL_OUT_OF_MEMORY));
555 return false;
556 }
Corentin Walleze0902642014-11-04 12:32:15 -0800557 }
558
559 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
560}
561
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500562bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
563 GLenum renderbuffertarget, GLuint renderbuffer)
564{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400565 if (!ValidFramebufferTarget(target))
566 {
Geoff Langb1196682014-07-23 13:47:29 -0400567 context->recordError(Error(GL_INVALID_ENUM));
568 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400569 }
570
Shannon Woods53a94a82014-06-24 15:20:36 -0400571 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500572
Jamie Madill84115c92015-04-23 15:00:07 -0400573 ASSERT(framebuffer);
574 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500575 {
Jamie Madill84115c92015-04-23 15:00:07 -0400576 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400577 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500578 }
579
Jamie Madillb4472272014-07-03 10:38:55 -0400580 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500581 {
Jamie Madillb4472272014-07-03 10:38:55 -0400582 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500583 }
584
Jamie Madillab9d82c2014-01-21 16:38:14 -0500585 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
586 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
587 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
588 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
589 if (renderbuffer != 0)
590 {
591 if (!context->getRenderbuffer(renderbuffer))
592 {
Geoff Langb1196682014-07-23 13:47:29 -0400593 context->recordError(Error(GL_INVALID_OPERATION));
594 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500595 }
596 }
597
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500598 return true;
599}
600
Jamie Madillc29968b2016-01-20 11:17:23 -0500601bool ValidateBlitFramebufferParameters(gl::Context *context,
602 GLint srcX0,
603 GLint srcY0,
604 GLint srcX1,
605 GLint srcY1,
606 GLint dstX0,
607 GLint dstY0,
608 GLint dstX1,
609 GLint dstY1,
610 GLbitfield mask,
611 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612{
613 switch (filter)
614 {
615 case GL_NEAREST:
616 break;
617 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400618 break;
619 default:
Geoff Langb1196682014-07-23 13:47:29 -0400620 context->recordError(Error(GL_INVALID_ENUM));
621 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622 }
623
624 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
625 {
Geoff Langb1196682014-07-23 13:47:29 -0400626 context->recordError(Error(GL_INVALID_VALUE));
627 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400628 }
629
630 if (mask == 0)
631 {
632 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
633 // buffers are copied.
634 return false;
635 }
636
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
638 // color buffer, leaving only nearest being unfiltered from above
639 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
640 {
Geoff Langb1196682014-07-23 13:47:29 -0400641 context->recordError(Error(GL_INVALID_OPERATION));
642 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400643 }
644
Shannon Woods53a94a82014-06-24 15:20:36 -0400645 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400646 {
Geoff Langb1196682014-07-23 13:47:29 -0400647 context->recordError(Error(GL_INVALID_OPERATION));
648 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649 }
650
Jamie Madille3ef7152015-04-28 16:55:17 +0000651 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
652 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500653
654 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 {
Geoff Langb1196682014-07-23 13:47:29 -0400656 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
657 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400658 }
659
Geoff Lang748f74e2014-12-01 11:25:34 -0500660 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500661 {
662 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
663 return false;
664 }
665
Geoff Lang748f74e2014-12-01 11:25:34 -0500666 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500667 {
668 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
669 return false;
670 }
671
672 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 {
Geoff Langb1196682014-07-23 13:47:29 -0400674 context->recordError(Error(GL_INVALID_OPERATION));
675 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400676 }
677
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400678 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
679
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400680 if (mask & GL_COLOR_BUFFER_BIT)
681 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400682 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
683 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500684 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400685
686 if (readColorBuffer && drawColorBuffer)
687 {
Geoff Langd8a22582014-12-17 15:28:23 -0500688 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400689 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690
Geoff Langa15472a2015-08-11 11:48:03 -0400691 for (size_t drawbufferIdx = 0;
692 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 {
Geoff Langa15472a2015-08-11 11:48:03 -0400694 const FramebufferAttachment *attachment =
695 drawFramebuffer->getDrawBuffer(drawbufferIdx);
696 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697 {
Geoff Langa15472a2015-08-11 11:48:03 -0400698 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400699 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700
Geoff Langb2f3d052013-08-13 12:49:27 -0400701 // The GL ES 3.0.2 spec (pg 193) states that:
702 // 1) If the read buffer is fixed point format, the draw buffer must be as well
703 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
704 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500705 // Changes with EXT_color_buffer_float:
706 // Case 1) is changed to fixed point OR floating point
707 GLenum readComponentType = readFormatInfo.componentType;
708 GLenum drawComponentType = drawFormatInfo.componentType;
709 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
710 readComponentType == GL_SIGNED_NORMALIZED);
711 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
712 drawComponentType == GL_SIGNED_NORMALIZED);
713
714 if (extensions.colorBufferFloat)
715 {
716 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
717 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
718
719 if (readFixedOrFloat != drawFixedOrFloat)
720 {
721 context->recordError(Error(GL_INVALID_OPERATION,
722 "If the read buffer contains fixed-point or "
723 "floating-point values, the draw buffer "
724 "must as well."));
725 return false;
726 }
727 }
728 else if (readFixedPoint != drawFixedPoint)
729 {
730 context->recordError(Error(GL_INVALID_OPERATION,
731 "If the read buffer contains fixed-point "
732 "values, the draw buffer must as well."));
733 return false;
734 }
735
736 if (readComponentType == GL_UNSIGNED_INT &&
737 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400738 {
Geoff Langb1196682014-07-23 13:47:29 -0400739 context->recordError(Error(GL_INVALID_OPERATION));
740 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741 }
742
Jamie Madill6163c752015-12-07 16:32:59 -0500743 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400744 {
Geoff Langb1196682014-07-23 13:47:29 -0400745 context->recordError(Error(GL_INVALID_OPERATION));
746 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400747 }
748
Geoff Langb2f3d052013-08-13 12:49:27 -0400749 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400750 {
Geoff Langb1196682014-07-23 13:47:29 -0400751 context->recordError(Error(GL_INVALID_OPERATION));
752 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400753 }
754 }
755 }
756
Geoff Lang5d601382014-07-22 15:14:06 -0400757 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400758 {
Geoff Langb1196682014-07-23 13:47:29 -0400759 context->recordError(Error(GL_INVALID_OPERATION));
760 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 }
763 }
764
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200765 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
766 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
767 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200769 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400771 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
772 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200774 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775 {
Geoff Langd8a22582014-12-17 15:28:23 -0500776 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 {
Geoff Langb1196682014-07-23 13:47:29 -0400778 context->recordError(Error(GL_INVALID_OPERATION));
779 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400781
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200782 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400783 {
Geoff Langb1196682014-07-23 13:47:29 -0400784 context->recordError(Error(GL_INVALID_OPERATION));
785 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400786 }
787 }
788 }
789 }
790
791 return true;
792}
793
Geoff Langb1196682014-07-23 13:47:29 -0400794bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795{
796 switch (pname)
797 {
798 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
799 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
800 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
801 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
802 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
803 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
804 case GL_CURRENT_VERTEX_ATTRIB:
805 return true;
806
807 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
808 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
809 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400810 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
811 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400812 return true;
813
814 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400815 if (context->getClientVersion() < 3)
816 {
817 context->recordError(Error(GL_INVALID_ENUM));
818 return false;
819 }
820 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400821
822 default:
Geoff Langb1196682014-07-23 13:47:29 -0400823 context->recordError(Error(GL_INVALID_ENUM));
824 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400825 }
826}
827
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400828bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829{
830 switch (pname)
831 {
832 case GL_TEXTURE_WRAP_R:
833 case GL_TEXTURE_SWIZZLE_R:
834 case GL_TEXTURE_SWIZZLE_G:
835 case GL_TEXTURE_SWIZZLE_B:
836 case GL_TEXTURE_SWIZZLE_A:
837 case GL_TEXTURE_BASE_LEVEL:
838 case GL_TEXTURE_MAX_LEVEL:
839 case GL_TEXTURE_COMPARE_MODE:
840 case GL_TEXTURE_COMPARE_FUNC:
841 case GL_TEXTURE_MIN_LOD:
842 case GL_TEXTURE_MAX_LOD:
843 if (context->getClientVersion() < 3)
844 {
Geoff Langb1196682014-07-23 13:47:29 -0400845 context->recordError(Error(GL_INVALID_ENUM));
846 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400847 }
848 break;
849
850 default: break;
851 }
852
853 switch (pname)
854 {
855 case GL_TEXTURE_WRAP_S:
856 case GL_TEXTURE_WRAP_T:
857 case GL_TEXTURE_WRAP_R:
858 switch (param)
859 {
860 case GL_REPEAT:
861 case GL_CLAMP_TO_EDGE:
862 case GL_MIRRORED_REPEAT:
863 return true;
864 default:
Geoff Langb1196682014-07-23 13:47:29 -0400865 context->recordError(Error(GL_INVALID_ENUM));
866 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400867 }
868
869 case GL_TEXTURE_MIN_FILTER:
870 switch (param)
871 {
872 case GL_NEAREST:
873 case GL_LINEAR:
874 case GL_NEAREST_MIPMAP_NEAREST:
875 case GL_LINEAR_MIPMAP_NEAREST:
876 case GL_NEAREST_MIPMAP_LINEAR:
877 case GL_LINEAR_MIPMAP_LINEAR:
878 return true;
879 default:
Geoff Langb1196682014-07-23 13:47:29 -0400880 context->recordError(Error(GL_INVALID_ENUM));
881 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 }
883 break;
884
885 case GL_TEXTURE_MAG_FILTER:
886 switch (param)
887 {
888 case GL_NEAREST:
889 case GL_LINEAR:
890 return true;
891 default:
Geoff Langb1196682014-07-23 13:47:29 -0400892 context->recordError(Error(GL_INVALID_ENUM));
893 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400894 }
895 break;
896
897 case GL_TEXTURE_USAGE_ANGLE:
898 switch (param)
899 {
900 case GL_NONE:
901 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
902 return true;
903 default:
Geoff Langb1196682014-07-23 13:47:29 -0400904 context->recordError(Error(GL_INVALID_ENUM));
905 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400906 }
907 break;
908
909 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400910 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400911 {
Geoff Langb1196682014-07-23 13:47:29 -0400912 context->recordError(Error(GL_INVALID_ENUM));
913 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400914 }
915
916 // we assume the parameter passed to this validation method is truncated, not rounded
917 if (param < 1)
918 {
Geoff Langb1196682014-07-23 13:47:29 -0400919 context->recordError(Error(GL_INVALID_VALUE));
920 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400921 }
922 return true;
923
924 case GL_TEXTURE_MIN_LOD:
925 case GL_TEXTURE_MAX_LOD:
926 // any value is permissible
927 return true;
928
929 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400930 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400931 switch (param)
932 {
933 case GL_NONE:
934 case GL_COMPARE_REF_TO_TEXTURE:
935 return true;
936 default:
Geoff Langb1196682014-07-23 13:47:29 -0400937 context->recordError(Error(GL_INVALID_ENUM));
938 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 }
940 break;
941
942 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400943 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400944 switch (param)
945 {
946 case GL_LEQUAL:
947 case GL_GEQUAL:
948 case GL_LESS:
949 case GL_GREATER:
950 case GL_EQUAL:
951 case GL_NOTEQUAL:
952 case GL_ALWAYS:
953 case GL_NEVER:
954 return true;
955 default:
Geoff Langb1196682014-07-23 13:47:29 -0400956 context->recordError(Error(GL_INVALID_ENUM));
957 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400958 }
959 break;
960
961 case GL_TEXTURE_SWIZZLE_R:
962 case GL_TEXTURE_SWIZZLE_G:
963 case GL_TEXTURE_SWIZZLE_B:
964 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400965 switch (param)
966 {
967 case GL_RED:
968 case GL_GREEN:
969 case GL_BLUE:
970 case GL_ALPHA:
971 case GL_ZERO:
972 case GL_ONE:
973 return true;
974 default:
Geoff Langb1196682014-07-23 13:47:29 -0400975 context->recordError(Error(GL_INVALID_ENUM));
976 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400977 }
978 break;
979
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400980 case GL_TEXTURE_BASE_LEVEL:
981 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400982 if (param < 0)
983 {
Geoff Langb1196682014-07-23 13:47:29 -0400984 context->recordError(Error(GL_INVALID_VALUE));
985 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400986 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400987 return true;
988
989 default:
Geoff Langb1196682014-07-23 13:47:29 -0400990 context->recordError(Error(GL_INVALID_ENUM));
991 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400992 }
993}
994
Geoff Langb1196682014-07-23 13:47:29 -0400995bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400996{
997 switch (pname)
998 {
999 case GL_TEXTURE_MIN_FILTER:
1000 case GL_TEXTURE_MAG_FILTER:
1001 case GL_TEXTURE_WRAP_S:
1002 case GL_TEXTURE_WRAP_T:
1003 case GL_TEXTURE_WRAP_R:
1004 case GL_TEXTURE_MIN_LOD:
1005 case GL_TEXTURE_MAX_LOD:
1006 case GL_TEXTURE_COMPARE_MODE:
1007 case GL_TEXTURE_COMPARE_FUNC:
1008 return true;
1009
1010 default:
Geoff Langb1196682014-07-23 13:47:29 -04001011 context->recordError(Error(GL_INVALID_ENUM));
1012 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001013 }
1014}
1015
Jamie Madillc29968b2016-01-20 11:17:23 -05001016bool ValidateReadPixels(Context *context,
1017 GLint x,
1018 GLint y,
1019 GLsizei width,
1020 GLsizei height,
1021 GLenum format,
1022 GLenum type,
1023 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001024{
Jamie Madillc29968b2016-01-20 11:17:23 -05001025 if (width < 0 || height < 0)
1026 {
1027 context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
1028 return false;
1029 }
1030
1031 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001032 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001033
Geoff Lang748f74e2014-12-01 11:25:34 -05001034 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001035 {
Geoff Langb1196682014-07-23 13:47:29 -04001036 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1037 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001038 }
1039
Jamie Madill48faf802014-11-06 15:27:22 -05001040 if (context->getState().getReadFramebuffer()->id() != 0 &&
1041 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001042 {
Geoff Langb1196682014-07-23 13:47:29 -04001043 context->recordError(Error(GL_INVALID_OPERATION));
1044 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001045 }
1046
Geoff Langbce529e2014-12-01 12:48:41 -05001047 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1048 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001049 {
Geoff Langb1196682014-07-23 13:47:29 -04001050 context->recordError(Error(GL_INVALID_OPERATION));
1051 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001052 }
1053
Geoff Langbce529e2014-12-01 12:48:41 -05001054 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1055 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001056 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001057 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001058
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001059 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1060 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001061
1062 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1063 {
Geoff Langb1196682014-07-23 13:47:29 -04001064 context->recordError(Error(GL_INVALID_OPERATION));
1065 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001066 }
1067
Jamie Madillc29968b2016-01-20 11:17:23 -05001068 return true;
1069}
1070
1071bool ValidateReadnPixelsEXT(Context *context,
1072 GLint x,
1073 GLint y,
1074 GLsizei width,
1075 GLsizei height,
1076 GLenum format,
1077 GLenum type,
1078 GLsizei bufSize,
1079 GLvoid *pixels)
1080{
1081 if (bufSize < 0)
1082 {
1083 context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
1084 return false;
1085 }
1086
Geoff Lang5d601382014-07-22 15:14:06 -04001087 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1088 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001089
Minmin Gongadff67b2015-10-14 10:34:45 -04001090 GLsizei outputPitch =
1091 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1092 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001093 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001094 int requiredSize = outputPitch * height;
1095 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001096 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001097 context->recordError(Error(GL_INVALID_OPERATION));
1098 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001099 }
1100
Jamie Madillc29968b2016-01-20 11:17:23 -05001101 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001102}
1103
Olli Etuaho41997e72016-03-10 13:38:39 +02001104bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001105{
1106 if (!context->getExtensions().occlusionQueryBoolean &&
1107 !context->getExtensions().disjointTimerQuery)
1108 {
1109 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1110 return false;
1111 }
1112
Olli Etuaho41997e72016-03-10 13:38:39 +02001113 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001114}
1115
Olli Etuaho41997e72016-03-10 13:38:39 +02001116bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001117{
1118 if (!context->getExtensions().occlusionQueryBoolean &&
1119 !context->getExtensions().disjointTimerQuery)
1120 {
1121 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1122 return false;
1123 }
1124
Olli Etuaho41997e72016-03-10 13:38:39 +02001125 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001126}
1127
1128bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001129{
1130 if (!ValidQueryType(context, target))
1131 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001132 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001133 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001134 }
1135
1136 if (id == 0)
1137 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001138 context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001139 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001140 }
1141
1142 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1143 // of zero, if the active query object name for <target> is non-zero (for the
1144 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1145 // the active query for either target is non-zero), if <id> is the name of an
1146 // existing query object whose type does not match <target>, or if <id> is the
1147 // active query object name for any query type, the error INVALID_OPERATION is
1148 // generated.
1149
1150 // Ensure no other queries are active
1151 // NOTE: If other queries than occlusion are supported, we will need to check
1152 // separately that:
1153 // a) The query ID passed is not the current active query for any target/type
1154 // b) There are no active queries for the requested target (and in the case
1155 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1156 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001157
1158 // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
1159 // same time
Shannon Woods53a94a82014-06-24 15:20:36 -04001160 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001161 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001162 context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001163 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001164 }
1165
1166 Query *queryObject = context->getQuery(id, true, target);
1167
1168 // check that name was obtained with glGenQueries
1169 if (!queryObject)
1170 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001171 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001172 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001173 }
1174
1175 // check for type mismatch
1176 if (queryObject->getType() != target)
1177 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001178 context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001179 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001180 }
1181
1182 return true;
1183}
1184
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001185bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1186{
1187 if (!context->getExtensions().occlusionQueryBoolean &&
1188 !context->getExtensions().disjointTimerQuery)
1189 {
1190 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1191 return false;
1192 }
1193
1194 return ValidateBeginQueryBase(context, target, id);
1195}
1196
1197bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001198{
1199 if (!ValidQueryType(context, target))
1200 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001201 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001202 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001203 }
1204
Shannon Woods53a94a82014-06-24 15:20:36 -04001205 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001206
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001207 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001208 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001209 context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001210 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001211 }
1212
Jamie Madill45c785d2014-05-13 14:09:34 -04001213 return true;
1214}
1215
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001216bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1217{
1218 if (!context->getExtensions().occlusionQueryBoolean &&
1219 !context->getExtensions().disjointTimerQuery)
1220 {
1221 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1222 return false;
1223 }
1224
1225 return ValidateEndQueryBase(context, target);
1226}
1227
1228bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1229{
1230 if (!context->getExtensions().disjointTimerQuery)
1231 {
1232 context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
1233 return false;
1234 }
1235
1236 if (target != GL_TIMESTAMP_EXT)
1237 {
1238 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
1239 return false;
1240 }
1241
1242 Query *queryObject = context->getQuery(id, true, target);
1243 if (queryObject == nullptr)
1244 {
1245 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
1246 return false;
1247 }
1248
1249 if (context->getState().isQueryActive(queryObject))
1250 {
1251 context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
1252 return false;
1253 }
1254
1255 return true;
1256}
1257
1258bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1259{
1260 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1261 {
1262 context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
1263 return false;
1264 }
1265
1266 switch (pname)
1267 {
1268 case GL_CURRENT_QUERY_EXT:
1269 if (target == GL_TIMESTAMP_EXT)
1270 {
1271 context->recordError(
1272 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1273 return false;
1274 }
1275 break;
1276 case GL_QUERY_COUNTER_BITS_EXT:
1277 if (!context->getExtensions().disjointTimerQuery ||
1278 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1279 {
1280 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1281 return false;
1282 }
1283 break;
1284 default:
1285 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1286 return false;
1287 }
1288
1289 return true;
1290}
1291
1292bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1293{
1294 if (!context->getExtensions().occlusionQueryBoolean &&
1295 !context->getExtensions().disjointTimerQuery)
1296 {
1297 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1298 return false;
1299 }
1300
1301 return ValidateGetQueryivBase(context, target, pname);
1302}
1303
1304bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1305{
1306 Query *queryObject = context->getQuery(id, false, GL_NONE);
1307
1308 if (!queryObject)
1309 {
1310 context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
1311 return false;
1312 }
1313
1314 if (context->getState().isQueryActive(queryObject))
1315 {
1316 context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
1317 return false;
1318 }
1319
1320 switch (pname)
1321 {
1322 case GL_QUERY_RESULT_EXT:
1323 case GL_QUERY_RESULT_AVAILABLE_EXT:
1324 break;
1325
1326 default:
1327 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
1328 return false;
1329 }
1330
1331 return true;
1332}
1333
1334bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1335{
1336 if (!context->getExtensions().disjointTimerQuery)
1337 {
1338 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1339 return false;
1340 }
1341 return ValidateGetQueryObjectValueBase(context, id, pname);
1342}
1343
1344bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1345{
1346 if (!context->getExtensions().disjointTimerQuery &&
1347 !context->getExtensions().occlusionQueryBoolean)
1348 {
1349 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1350 return false;
1351 }
1352 return ValidateGetQueryObjectValueBase(context, id, pname);
1353}
1354
1355bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1356{
1357 if (!context->getExtensions().disjointTimerQuery)
1358 {
1359 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1360 return false;
1361 }
1362 return ValidateGetQueryObjectValueBase(context, id, pname);
1363}
1364
1365bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1366{
1367 if (!context->getExtensions().disjointTimerQuery)
1368 {
1369 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1370 return false;
1371 }
1372 return ValidateGetQueryObjectValueBase(context, id, pname);
1373}
1374
Jamie Madill62d31cb2015-09-11 13:25:51 -04001375static bool ValidateUniformCommonBase(gl::Context *context,
1376 GLenum targetUniformType,
1377 GLint location,
1378 GLsizei count,
1379 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001380{
1381 if (count < 0)
1382 {
Geoff Langb1196682014-07-23 13:47:29 -04001383 context->recordError(Error(GL_INVALID_VALUE));
1384 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001385 }
1386
Geoff Lang7dd2e102014-11-10 15:19:26 -05001387 gl::Program *program = context->getState().getProgram();
1388 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001389 {
Geoff Langb1196682014-07-23 13:47:29 -04001390 context->recordError(Error(GL_INVALID_OPERATION));
1391 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001392 }
1393
1394 if (location == -1)
1395 {
1396 // Silently ignore the uniform command
1397 return false;
1398 }
1399
Geoff Lang7dd2e102014-11-10 15:19:26 -05001400 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001401 {
Geoff Langb1196682014-07-23 13:47:29 -04001402 context->recordError(Error(GL_INVALID_OPERATION));
1403 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001404 }
1405
Jamie Madill62d31cb2015-09-11 13:25:51 -04001406 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001407
1408 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001409 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001410 {
Geoff Langb1196682014-07-23 13:47:29 -04001411 context->recordError(Error(GL_INVALID_OPERATION));
1412 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001413 }
1414
Jamie Madill62d31cb2015-09-11 13:25:51 -04001415 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001416 return true;
1417}
1418
Jamie Madillaa981bd2014-05-20 10:55:55 -04001419bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1420{
1421 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001422 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001423 {
Geoff Langb1196682014-07-23 13:47:29 -04001424 context->recordError(Error(GL_INVALID_OPERATION));
1425 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001426 }
1427
Jamie Madill62d31cb2015-09-11 13:25:51 -04001428 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001429 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1430 {
1431 return false;
1432 }
1433
Jamie Madillf2575982014-06-25 16:04:54 -04001434 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001435 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001436 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1437 {
Geoff Langb1196682014-07-23 13:47:29 -04001438 context->recordError(Error(GL_INVALID_OPERATION));
1439 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001440 }
1441
1442 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001443}
1444
1445bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1446 GLboolean transpose)
1447{
1448 // Check for ES3 uniform entry points
1449 int rows = VariableRowCount(matrixType);
1450 int cols = VariableColumnCount(matrixType);
1451 if (rows != cols && context->getClientVersion() < 3)
1452 {
Geoff Langb1196682014-07-23 13:47:29 -04001453 context->recordError(Error(GL_INVALID_OPERATION));
1454 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001455 }
1456
1457 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1458 {
Geoff Langb1196682014-07-23 13:47:29 -04001459 context->recordError(Error(GL_INVALID_VALUE));
1460 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001461 }
1462
Jamie Madill62d31cb2015-09-11 13:25:51 -04001463 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001464 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1465 {
1466 return false;
1467 }
1468
1469 if (uniform->type != matrixType)
1470 {
Geoff Langb1196682014-07-23 13:47:29 -04001471 context->recordError(Error(GL_INVALID_OPERATION));
1472 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001473 }
1474
1475 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001476}
1477
Jamie Madill893ab082014-05-16 16:56:10 -04001478bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1479{
1480 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1481 {
Geoff Langb1196682014-07-23 13:47:29 -04001482 context->recordError(Error(GL_INVALID_ENUM));
1483 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001484 }
1485
Jamie Madill0af26e12015-03-05 19:54:33 -05001486 const Caps &caps = context->getCaps();
1487
Jamie Madill893ab082014-05-16 16:56:10 -04001488 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1489 {
1490 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1491
Jamie Madill0af26e12015-03-05 19:54:33 -05001492 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001493 {
Geoff Langb1196682014-07-23 13:47:29 -04001494 context->recordError(Error(GL_INVALID_OPERATION));
1495 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001496 }
1497 }
1498
1499 switch (pname)
1500 {
1501 case GL_TEXTURE_BINDING_2D:
1502 case GL_TEXTURE_BINDING_CUBE_MAP:
1503 case GL_TEXTURE_BINDING_3D:
1504 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001505 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001506 {
Geoff Langb1196682014-07-23 13:47:29 -04001507 context->recordError(Error(GL_INVALID_OPERATION));
1508 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001509 }
1510 break;
1511
1512 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1513 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1514 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001515 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001516 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001517 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001518 {
Geoff Langb1196682014-07-23 13:47:29 -04001519 context->recordError(Error(GL_INVALID_OPERATION));
1520 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001521 }
1522
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001523 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001524 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001525 {
Geoff Langb1196682014-07-23 13:47:29 -04001526 context->recordError(Error(GL_INVALID_OPERATION));
1527 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001528 }
1529 }
1530 break;
1531
1532 default:
1533 break;
1534 }
1535
1536 // pname is valid, but there are no parameters to return
1537 if (numParams == 0)
1538 {
1539 return false;
1540 }
1541
1542 return true;
1543}
1544
Jamie Madillc29968b2016-01-20 11:17:23 -05001545bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1546 GLenum target,
1547 GLint level,
1548 GLenum internalformat,
1549 bool isSubImage,
1550 GLint xoffset,
1551 GLint yoffset,
1552 GLint zoffset,
1553 GLint x,
1554 GLint y,
1555 GLsizei width,
1556 GLsizei height,
1557 GLint border,
1558 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001559{
Jamie Madill560a8d82014-05-21 13:06:20 -04001560 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1561 {
Geoff Langb1196682014-07-23 13:47:29 -04001562 context->recordError(Error(GL_INVALID_VALUE));
1563 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001564 }
1565
1566 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1567 {
Geoff Langb1196682014-07-23 13:47:29 -04001568 context->recordError(Error(GL_INVALID_VALUE));
1569 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001570 }
1571
1572 if (border != 0)
1573 {
Geoff Langb1196682014-07-23 13:47:29 -04001574 context->recordError(Error(GL_INVALID_VALUE));
1575 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001576 }
1577
1578 if (!ValidMipLevel(context, target, level))
1579 {
Geoff Langb1196682014-07-23 13:47:29 -04001580 context->recordError(Error(GL_INVALID_VALUE));
1581 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001582 }
1583
Jamie Madillc29968b2016-01-20 11:17:23 -05001584 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001585 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001586 {
Geoff Langb1196682014-07-23 13:47:29 -04001587 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1588 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001589 }
1590
Jamie Madillc29968b2016-01-20 11:17:23 -05001591 const auto &state = context->getState();
1592 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001593 {
Geoff Langb1196682014-07-23 13:47:29 -04001594 context->recordError(Error(GL_INVALID_OPERATION));
1595 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001596 }
1597
Geoff Langaae65a42014-05-26 12:43:44 -04001598 const gl::Caps &caps = context->getCaps();
1599
Geoff Langaae65a42014-05-26 12:43:44 -04001600 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001601 switch (target)
1602 {
1603 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001604 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001605 break;
1606
1607 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1608 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1609 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1610 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1611 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1612 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001613 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001614 break;
1615
1616 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001617 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001618 break;
1619
1620 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001621 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001622 break;
1623
1624 default:
Geoff Langb1196682014-07-23 13:47:29 -04001625 context->recordError(Error(GL_INVALID_ENUM));
1626 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001627 }
1628
Jamie Madillc29968b2016-01-20 11:17:23 -05001629 gl::Texture *texture =
1630 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001631 if (!texture)
1632 {
Geoff Langb1196682014-07-23 13:47:29 -04001633 context->recordError(Error(GL_INVALID_OPERATION));
1634 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001635 }
1636
Geoff Lang69cce582015-09-17 13:20:36 -04001637 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001638 {
Geoff Langb1196682014-07-23 13:47:29 -04001639 context->recordError(Error(GL_INVALID_OPERATION));
1640 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001641 }
1642
Geoff Lang5d601382014-07-22 15:14:06 -04001643 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1644
1645 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001646 {
Geoff Langb1196682014-07-23 13:47:29 -04001647 context->recordError(Error(GL_INVALID_OPERATION));
1648 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001649 }
1650
Geoff Langa9be0dc2014-12-17 12:34:40 -05001651 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001652 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001653 context->recordError(Error(GL_INVALID_OPERATION));
1654 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001655 }
1656
1657 if (isSubImage)
1658 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001659 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1660 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1661 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001662 {
Geoff Langb1196682014-07-23 13:47:29 -04001663 context->recordError(Error(GL_INVALID_VALUE));
1664 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001665 }
1666 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001667 else
1668 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001669 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001670 {
Geoff Langb1196682014-07-23 13:47:29 -04001671 context->recordError(Error(GL_INVALID_VALUE));
1672 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001673 }
1674
Geoff Lang5d601382014-07-22 15:14:06 -04001675 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001676 {
Geoff Langb1196682014-07-23 13:47:29 -04001677 context->recordError(Error(GL_INVALID_ENUM));
1678 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001679 }
1680
1681 int maxLevelDimension = (maxDimension >> level);
1682 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1683 {
Geoff Langb1196682014-07-23 13:47:29 -04001684 context->recordError(Error(GL_INVALID_VALUE));
1685 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001686 }
1687 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001688
Geoff Langa9be0dc2014-12-17 12:34:40 -05001689 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001690 return true;
1691}
1692
Jamie Madillf25855c2015-11-03 11:06:18 -05001693static bool ValidateDrawBase(ValidationContext *context,
1694 GLenum mode,
1695 GLsizei count,
1696 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001697{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001698 switch (mode)
1699 {
1700 case GL_POINTS:
1701 case GL_LINES:
1702 case GL_LINE_LOOP:
1703 case GL_LINE_STRIP:
1704 case GL_TRIANGLES:
1705 case GL_TRIANGLE_STRIP:
1706 case GL_TRIANGLE_FAN:
1707 break;
1708 default:
Geoff Langb1196682014-07-23 13:47:29 -04001709 context->recordError(Error(GL_INVALID_ENUM));
1710 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001711 }
1712
Jamie Madill250d33f2014-06-06 17:09:03 -04001713 if (count < 0)
1714 {
Geoff Langb1196682014-07-23 13:47:29 -04001715 context->recordError(Error(GL_INVALID_VALUE));
1716 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001717 }
1718
Geoff Langb1196682014-07-23 13:47:29 -04001719 const State &state = context->getState();
1720
Jamie Madill250d33f2014-06-06 17:09:03 -04001721 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001722 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001723 {
Geoff Langb1196682014-07-23 13:47:29 -04001724 context->recordError(Error(GL_INVALID_OPERATION));
1725 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001726 }
1727
Geoff Lang3a86ad32015-09-01 11:47:05 -04001728 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001729 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001730 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1731 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1732 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1733 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1734 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1735 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1736 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001737 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001738 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1739 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001740 {
1741 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1742 // Section 6.10 of the WebGL 1.0 spec
1743 ERR(
1744 "This ANGLE implementation does not support separate front/back stencil "
1745 "writemasks, reference values, or stencil mask values.");
1746 context->recordError(Error(GL_INVALID_OPERATION));
1747 return false;
1748 }
Jamie Madillac528012014-06-20 13:21:23 -04001749 }
1750
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001751 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001752 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001753 {
Geoff Langb1196682014-07-23 13:47:29 -04001754 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1755 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001756 }
1757
Geoff Lang7dd2e102014-11-10 15:19:26 -05001758 gl::Program *program = state.getProgram();
1759 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001760 {
Geoff Langb1196682014-07-23 13:47:29 -04001761 context->recordError(Error(GL_INVALID_OPERATION));
1762 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001763 }
1764
Geoff Lang7dd2e102014-11-10 15:19:26 -05001765 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001766 {
Geoff Langb1196682014-07-23 13:47:29 -04001767 context->recordError(Error(GL_INVALID_OPERATION));
1768 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001769 }
1770
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001771 // Uniform buffer validation
1772 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1773 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001774 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001775 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001776 const OffsetBindingPointer<Buffer> &uniformBuffer =
1777 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001778
Geoff Lang5d124a62015-09-15 13:03:27 -04001779 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001780 {
1781 // undefined behaviour
1782 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1783 return false;
1784 }
1785
Geoff Lang5d124a62015-09-15 13:03:27 -04001786 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001787 if (uniformBufferSize == 0)
1788 {
1789 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001790 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001791 }
1792
Jamie Madill62d31cb2015-09-11 13:25:51 -04001793 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001794 {
1795 // undefined behaviour
1796 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1797 return false;
1798 }
1799 }
1800
Jamie Madill250d33f2014-06-06 17:09:03 -04001801 // No-op if zero count
1802 return (count > 0);
1803}
1804
Geoff Langb1196682014-07-23 13:47:29 -04001805bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001806{
Jamie Madillfd716582014-06-06 17:09:04 -04001807 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001808 {
Geoff Langb1196682014-07-23 13:47:29 -04001809 context->recordError(Error(GL_INVALID_VALUE));
1810 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001811 }
1812
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001813 const State &state = context->getState();
1814 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001815 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1816 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001817 {
1818 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1819 // that does not match the current transform feedback object's draw mode (if transform feedback
1820 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001821 context->recordError(Error(GL_INVALID_OPERATION));
1822 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001823 }
1824
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001825 if (!ValidateDrawBase(context, mode, count, primcount))
1826 {
1827 return false;
1828 }
1829
1830 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001831 {
1832 return false;
1833 }
1834
1835 return true;
1836}
1837
Geoff Langb1196682014-07-23 13:47:29 -04001838bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001839{
1840 if (primcount < 0)
1841 {
Geoff Langb1196682014-07-23 13:47:29 -04001842 context->recordError(Error(GL_INVALID_VALUE));
1843 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001844 }
1845
Jamie Madill2b976812014-08-25 15:47:49 -04001846 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001847 {
1848 return false;
1849 }
1850
1851 // No-op if zero primitive count
1852 return (primcount > 0);
1853}
1854
Geoff Lang87a93302014-09-16 13:29:43 -04001855static bool ValidateDrawInstancedANGLE(Context *context)
1856{
1857 // Verify there is at least one active attribute with a divisor of zero
1858 const gl::State& state = context->getState();
1859
Geoff Lang7dd2e102014-11-10 15:19:26 -05001860 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001861
1862 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001863 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001864 {
1865 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001866 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001867 {
1868 return true;
1869 }
1870 }
1871
1872 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1873 "has a divisor of zero."));
1874 return false;
1875}
1876
1877bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1878{
1879 if (!ValidateDrawInstancedANGLE(context))
1880 {
1881 return false;
1882 }
1883
1884 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1885}
1886
Jamie Madillf25855c2015-11-03 11:06:18 -05001887bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001888 GLenum mode,
1889 GLsizei count,
1890 GLenum type,
1891 const GLvoid *indices,
1892 GLsizei primcount,
1893 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001894{
Jamie Madill250d33f2014-06-06 17:09:03 -04001895 switch (type)
1896 {
1897 case GL_UNSIGNED_BYTE:
1898 case GL_UNSIGNED_SHORT:
1899 break;
1900 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001901 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001902 {
Geoff Langb1196682014-07-23 13:47:29 -04001903 context->recordError(Error(GL_INVALID_ENUM));
1904 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001905 }
1906 break;
1907 default:
Geoff Langb1196682014-07-23 13:47:29 -04001908 context->recordError(Error(GL_INVALID_ENUM));
1909 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001910 }
1911
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001912 const State &state = context->getState();
1913
1914 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001915 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001916 {
1917 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1918 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001919 context->recordError(Error(GL_INVALID_OPERATION));
1920 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001921 }
1922
1923 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001924 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001925 {
Geoff Langb1196682014-07-23 13:47:29 -04001926 context->recordError(Error(GL_INVALID_OPERATION));
1927 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001928 }
1929
Jamie Madill2b976812014-08-25 15:47:49 -04001930 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001931 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001932 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001933 {
Geoff Langb1196682014-07-23 13:47:29 -04001934 context->recordError(Error(GL_INVALID_OPERATION));
1935 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001936 }
1937
Jamie Madillae3000b2014-08-25 15:47:51 -04001938 if (elementArrayBuffer)
1939 {
1940 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1941
1942 GLint64 offset = reinterpret_cast<GLint64>(indices);
1943 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1944
1945 // check for integer overflows
1946 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1947 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1948 {
Geoff Langb1196682014-07-23 13:47:29 -04001949 context->recordError(Error(GL_OUT_OF_MEMORY));
1950 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001951 }
1952
1953 // Check for reading past the end of the bound buffer object
1954 if (byteCount > elementArrayBuffer->getSize())
1955 {
Geoff Langb1196682014-07-23 13:47:29 -04001956 context->recordError(Error(GL_INVALID_OPERATION));
1957 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001958 }
1959 }
1960 else if (!indices)
1961 {
1962 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001963 context->recordError(Error(GL_INVALID_OPERATION));
1964 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001965 }
1966
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001967 if (!ValidateDrawBase(context, mode, count, primcount))
1968 {
1969 return false;
1970 }
1971
Jamie Madill2b976812014-08-25 15:47:49 -04001972 // Use max index to validate if our vertex buffers are large enough for the pull.
1973 // TODO: offer fast path, with disabled index validation.
1974 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1975 if (elementArrayBuffer)
1976 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001977 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001978 Error error =
1979 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1980 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001981 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001982 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001983 context->recordError(error);
1984 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001985 }
1986 }
1987 else
1988 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001989 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001990 }
1991
Jamie Madille79b1e12015-11-04 16:36:37 -05001992 // If we use an index greater than our maximum supported index range, return an error.
1993 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1994 // return an error if possible here.
1995 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1996 {
1997 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1998 return false;
1999 }
2000
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002001 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002002 {
2003 return false;
2004 }
2005
Geoff Lang3edfe032015-09-04 16:38:24 -04002006 // No op if there are no real indices in the index data (all are primitive restart).
2007 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002008}
2009
Geoff Langb1196682014-07-23 13:47:29 -04002010bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002011 GLenum mode,
2012 GLsizei count,
2013 GLenum type,
2014 const GLvoid *indices,
2015 GLsizei primcount,
2016 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002017{
2018 if (primcount < 0)
2019 {
Geoff Langb1196682014-07-23 13:47:29 -04002020 context->recordError(Error(GL_INVALID_VALUE));
2021 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002022 }
2023
Jamie Madill2b976812014-08-25 15:47:49 -04002024 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002025 {
2026 return false;
2027 }
2028
2029 // No-op zero primitive count
2030 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002031}
2032
Geoff Lang3edfe032015-09-04 16:38:24 -04002033bool ValidateDrawElementsInstancedANGLE(Context *context,
2034 GLenum mode,
2035 GLsizei count,
2036 GLenum type,
2037 const GLvoid *indices,
2038 GLsizei primcount,
2039 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002040{
2041 if (!ValidateDrawInstancedANGLE(context))
2042 {
2043 return false;
2044 }
2045
2046 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2047}
2048
Geoff Langb1196682014-07-23 13:47:29 -04002049bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002050 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002051{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002052 if (!ValidFramebufferTarget(target))
2053 {
Geoff Langb1196682014-07-23 13:47:29 -04002054 context->recordError(Error(GL_INVALID_ENUM));
2055 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002056 }
2057
2058 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002059 {
2060 return false;
2061 }
2062
Jamie Madill55ec3b12014-07-03 10:38:57 -04002063 if (texture != 0)
2064 {
2065 gl::Texture *tex = context->getTexture(texture);
2066
2067 if (tex == NULL)
2068 {
Geoff Langb1196682014-07-23 13:47:29 -04002069 context->recordError(Error(GL_INVALID_OPERATION));
2070 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002071 }
2072
2073 if (level < 0)
2074 {
Geoff Langb1196682014-07-23 13:47:29 -04002075 context->recordError(Error(GL_INVALID_VALUE));
2076 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002077 }
2078 }
2079
Shannon Woods53a94a82014-06-24 15:20:36 -04002080 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002081 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002082
Jamie Madill84115c92015-04-23 15:00:07 -04002083 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002084 {
Jamie Madill84115c92015-04-23 15:00:07 -04002085 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002086 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002087 }
2088
2089 return true;
2090}
2091
Geoff Langb1196682014-07-23 13:47:29 -04002092bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002093 GLenum textarget, GLuint texture, GLint level)
2094{
Geoff Lang95663912015-04-02 15:54:45 -04002095 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2096 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002097 {
Geoff Langb1196682014-07-23 13:47:29 -04002098 context->recordError(Error(GL_INVALID_VALUE));
2099 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002100 }
2101
2102 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002103 {
2104 return false;
2105 }
2106
Jamie Madill55ec3b12014-07-03 10:38:57 -04002107 if (texture != 0)
2108 {
2109 gl::Texture *tex = context->getTexture(texture);
2110 ASSERT(tex);
2111
Jamie Madill2a6564e2014-07-11 09:53:19 -04002112 const gl::Caps &caps = context->getCaps();
2113
Jamie Madill55ec3b12014-07-03 10:38:57 -04002114 switch (textarget)
2115 {
2116 case GL_TEXTURE_2D:
2117 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002118 if (level > gl::log2(caps.max2DTextureSize))
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 if (tex->getTarget() != GL_TEXTURE_2D)
2124 {
Geoff Langb1196682014-07-23 13:47:29 -04002125 context->recordError(Error(GL_INVALID_OPERATION));
2126 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002127 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002128 }
2129 break;
2130
2131 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2132 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2133 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2134 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2135 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2136 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2137 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002138 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002139 {
Geoff Langb1196682014-07-23 13:47:29 -04002140 context->recordError(Error(GL_INVALID_VALUE));
2141 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002142 }
2143 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2144 {
Geoff Langb1196682014-07-23 13:47:29 -04002145 context->recordError(Error(GL_INVALID_OPERATION));
2146 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002147 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002148 }
2149 break;
2150
2151 default:
Geoff Langb1196682014-07-23 13:47:29 -04002152 context->recordError(Error(GL_INVALID_ENUM));
2153 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002154 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002155
2156 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2157 if (internalFormatInfo.compressed)
2158 {
2159 context->recordError(Error(GL_INVALID_OPERATION));
2160 return false;
2161 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002162 }
2163
Jamie Madill570f7c82014-07-03 10:38:54 -04002164 return true;
2165}
2166
Geoff Langb1196682014-07-23 13:47:29 -04002167bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002168{
2169 if (program == 0)
2170 {
Geoff Langb1196682014-07-23 13:47:29 -04002171 context->recordError(Error(GL_INVALID_VALUE));
2172 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002173 }
2174
Dian Xiang769769a2015-09-09 15:20:08 -07002175 gl::Program *programObject = GetValidProgram(context, program);
2176 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002177 {
2178 return false;
2179 }
2180
Jamie Madill0063c512014-08-25 15:47:53 -04002181 if (!programObject || !programObject->isLinked())
2182 {
Geoff Langb1196682014-07-23 13:47:29 -04002183 context->recordError(Error(GL_INVALID_OPERATION));
2184 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002185 }
2186
Geoff Lang7dd2e102014-11-10 15:19:26 -05002187 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002188 {
Geoff Langb1196682014-07-23 13:47:29 -04002189 context->recordError(Error(GL_INVALID_OPERATION));
2190 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002191 }
2192
Jamie Madill0063c512014-08-25 15:47:53 -04002193 return true;
2194}
2195
Geoff Langb1196682014-07-23 13:47:29 -04002196bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002197{
2198 return ValidateGetUniformBase(context, program, location);
2199}
2200
Geoff Langb1196682014-07-23 13:47:29 -04002201bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002202{
Jamie Madill78f41802014-08-25 15:47:55 -04002203 return ValidateGetUniformBase(context, program, location);
2204}
2205
Geoff Langb1196682014-07-23 13:47:29 -04002206static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002207{
2208 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002209 {
Jamie Madill78f41802014-08-25 15:47:55 -04002210 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002211 }
2212
Jamie Madilla502c742014-08-28 17:19:13 -04002213 gl::Program *programObject = context->getProgram(program);
2214 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002215
Jamie Madill78f41802014-08-25 15:47:55 -04002216 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002217 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2218 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002219 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002220 {
Geoff Langb1196682014-07-23 13:47:29 -04002221 context->recordError(Error(GL_INVALID_OPERATION));
2222 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002223 }
2224
2225 return true;
2226}
2227
Geoff Langb1196682014-07-23 13:47:29 -04002228bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002229{
Jamie Madill78f41802014-08-25 15:47:55 -04002230 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002231}
2232
Geoff Langb1196682014-07-23 13:47:29 -04002233bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002234{
Jamie Madill78f41802014-08-25 15:47:55 -04002235 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002236}
2237
Austin Kinross08332632015-05-05 13:35:47 -07002238bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2239 const GLenum *attachments, bool defaultFramebuffer)
2240{
2241 if (numAttachments < 0)
2242 {
2243 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2244 return false;
2245 }
2246
2247 for (GLsizei i = 0; i < numAttachments; ++i)
2248 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002249 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002250 {
2251 if (defaultFramebuffer)
2252 {
2253 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2254 return false;
2255 }
2256
2257 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2258 {
2259 context->recordError(Error(GL_INVALID_OPERATION,
2260 "Requested color attachment is greater than the maximum supported color attachments"));
2261 return false;
2262 }
2263 }
2264 else
2265 {
2266 switch (attachments[i])
2267 {
2268 case GL_DEPTH_ATTACHMENT:
2269 case GL_STENCIL_ATTACHMENT:
2270 case GL_DEPTH_STENCIL_ATTACHMENT:
2271 if (defaultFramebuffer)
2272 {
2273 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2274 return false;
2275 }
2276 break;
2277 case GL_COLOR:
2278 case GL_DEPTH:
2279 case GL_STENCIL:
2280 if (!defaultFramebuffer)
2281 {
2282 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2283 return false;
2284 }
2285 break;
2286 default:
2287 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2288 return false;
2289 }
2290 }
2291 }
2292
2293 return true;
2294}
2295
Austin Kinross6ee1e782015-05-29 17:05:37 -07002296bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2297{
2298 // Note that debug marker calls must not set error state
2299
2300 if (length < 0)
2301 {
2302 return false;
2303 }
2304
2305 if (marker == nullptr)
2306 {
2307 return false;
2308 }
2309
2310 return true;
2311}
2312
2313bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2314{
2315 // Note that debug marker calls must not set error state
2316
2317 if (length < 0)
2318 {
2319 return false;
2320 }
2321
2322 if (length > 0 && marker == nullptr)
2323 {
2324 return false;
2325 }
2326
2327 return true;
2328}
2329
Geoff Langdcab33b2015-07-21 13:03:16 -04002330bool ValidateEGLImageTargetTexture2DOES(Context *context,
2331 egl::Display *display,
2332 GLenum target,
2333 egl::Image *image)
2334{
Geoff Langa8406172015-07-21 16:53:39 -04002335 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2336 {
2337 context->recordError(Error(GL_INVALID_OPERATION));
2338 return false;
2339 }
2340
2341 switch (target)
2342 {
2343 case GL_TEXTURE_2D:
2344 break;
2345
2346 default:
2347 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2348 return false;
2349 }
2350
2351 if (!display->isValidImage(image))
2352 {
2353 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2354 return false;
2355 }
2356
2357 if (image->getSamples() > 0)
2358 {
2359 context->recordError(Error(GL_INVALID_OPERATION,
2360 "cannot create a 2D texture from a multisampled EGL image."));
2361 return false;
2362 }
2363
2364 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2365 if (!textureCaps.texturable)
2366 {
2367 context->recordError(Error(GL_INVALID_OPERATION,
2368 "EGL image internal format is not supported as a texture."));
2369 return false;
2370 }
2371
Geoff Langdcab33b2015-07-21 13:03:16 -04002372 return true;
2373}
2374
2375bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2376 egl::Display *display,
2377 GLenum target,
2378 egl::Image *image)
2379{
Geoff Langa8406172015-07-21 16:53:39 -04002380 if (!context->getExtensions().eglImage)
2381 {
2382 context->recordError(Error(GL_INVALID_OPERATION));
2383 return false;
2384 }
2385
2386 switch (target)
2387 {
2388 case GL_RENDERBUFFER:
2389 break;
2390
2391 default:
2392 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2393 return false;
2394 }
2395
2396 if (!display->isValidImage(image))
2397 {
2398 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2399 return false;
2400 }
2401
2402 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2403 if (!textureCaps.renderable)
2404 {
2405 context->recordError(Error(
2406 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2407 return false;
2408 }
2409
Geoff Langdcab33b2015-07-21 13:03:16 -04002410 return true;
2411}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002412
2413bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2414{
Geoff Lang36167ab2015-12-07 10:27:14 -05002415 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002416 {
2417 // The default VAO should always exist
2418 ASSERT(array != 0);
2419 context->recordError(Error(GL_INVALID_OPERATION));
2420 return false;
2421 }
2422
2423 return true;
2424}
2425
Geoff Langc5629752015-12-07 16:29:04 -05002426bool ValidateProgramBinaryBase(Context *context,
2427 GLuint program,
2428 GLenum binaryFormat,
2429 const void *binary,
2430 GLint length)
2431{
2432 Program *programObject = GetValidProgram(context, program);
2433 if (programObject == nullptr)
2434 {
2435 return false;
2436 }
2437
2438 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2439 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2440 programBinaryFormats.end())
2441 {
2442 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2443 return false;
2444 }
2445
2446 return true;
2447}
2448
2449bool ValidateGetProgramBinaryBase(Context *context,
2450 GLuint program,
2451 GLsizei bufSize,
2452 GLsizei *length,
2453 GLenum *binaryFormat,
2454 void *binary)
2455{
2456 Program *programObject = GetValidProgram(context, program);
2457 if (programObject == nullptr)
2458 {
2459 return false;
2460 }
2461
2462 if (!programObject->isLinked())
2463 {
2464 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2465 return false;
2466 }
2467
2468 return true;
2469}
Jamie Madillc29968b2016-01-20 11:17:23 -05002470
2471bool ValidateCopyTexImage2D(ValidationContext *context,
2472 GLenum target,
2473 GLint level,
2474 GLenum internalformat,
2475 GLint x,
2476 GLint y,
2477 GLsizei width,
2478 GLsizei height,
2479 GLint border)
2480{
2481 if (context->getClientVersion() < 3)
2482 {
2483 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2484 0, x, y, width, height, border);
2485 }
2486
2487 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002488 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2489 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002490}
Jamie Madillc29968b2016-01-20 11:17:23 -05002491
2492bool ValidateFramebufferRenderbuffer(Context *context,
2493 GLenum target,
2494 GLenum attachment,
2495 GLenum renderbuffertarget,
2496 GLuint renderbuffer)
2497{
2498 if (!ValidFramebufferTarget(target) ||
2499 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2500 {
2501 context->recordError(Error(GL_INVALID_ENUM));
2502 return false;
2503 }
2504
2505 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2506 renderbuffertarget, renderbuffer);
2507}
2508
2509bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2510{
2511 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2512 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2513 {
2514 context->recordError(
2515 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2516 return false;
2517 }
2518
2519 ASSERT(context->getState().getDrawFramebuffer());
2520 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2521 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2522
2523 // This should come first before the check for the default frame buffer
2524 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2525 // rather than INVALID_OPERATION
2526 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2527 {
2528 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2529
2530 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002531 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2532 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002533 {
2534 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002535 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2536 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2537 // 3.1 is still a bit ambiguous about the error, but future specs are
2538 // expected to clarify that GL_INVALID_ENUM is the correct error.
2539 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
2540 return false;
2541 }
2542 else if (bufs[colorAttachment] >= maxColorAttachment)
2543 {
2544 context->recordError(
2545 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002546 return false;
2547 }
2548 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2549 frameBufferId != 0)
2550 {
2551 // INVALID_OPERATION-GL is bound to buffer and ith argument
2552 // is not COLOR_ATTACHMENTi or NONE
2553 context->recordError(
2554 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2555 return false;
2556 }
2557 }
2558
2559 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2560 // and n is not 1 or bufs is bound to value other than BACK and NONE
2561 if (frameBufferId == 0)
2562 {
2563 if (n != 1)
2564 {
2565 context->recordError(Error(GL_INVALID_OPERATION,
2566 "n must be 1 when GL is bound to the default framebuffer"));
2567 return false;
2568 }
2569
2570 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2571 {
2572 context->recordError(Error(
2573 GL_INVALID_OPERATION,
2574 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2575 return false;
2576 }
2577 }
2578
2579 return true;
2580}
2581
2582bool ValidateCopyTexSubImage2D(Context *context,
2583 GLenum target,
2584 GLint level,
2585 GLint xoffset,
2586 GLint yoffset,
2587 GLint x,
2588 GLint y,
2589 GLsizei width,
2590 GLsizei height)
2591{
2592 if (context->getClientVersion() < 3)
2593 {
2594 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2595 yoffset, x, y, width, height, 0);
2596 }
2597
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002598 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2599 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002600}
2601
Olli Etuaho41997e72016-03-10 13:38:39 +02002602bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2603{
2604 return ValidateGenOrDelete(context, n);
2605}
2606
2607bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2608{
2609 return ValidateGenOrDelete(context, n);
2610}
2611
2612bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2613{
2614 return ValidateGenOrDelete(context, n);
2615}
2616
2617bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2618{
2619 return ValidateGenOrDelete(context, n);
2620}
2621
2622bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2623{
2624 return ValidateGenOrDelete(context, n);
2625}
2626
2627bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2628{
2629 return ValidateGenOrDelete(context, n);
2630}
2631
2632bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2633{
2634 return ValidateGenOrDelete(context, n);
2635}
2636
2637bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2638{
2639 return ValidateGenOrDelete(context, n);
2640}
2641
2642bool ValidateGenOrDelete(Context *context, GLint n)
2643{
2644 if (n < 0)
2645 {
2646 context->recordError(Error(GL_INVALID_VALUE, "n < 0"));
2647 return false;
2648 }
2649 return true;
2650}
2651
Jamie Madillc29968b2016-01-20 11:17:23 -05002652} // namespace gl