blob: 9d015b65b503fe17a7453bb56fbcb3ba6997867a [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;
71
72 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
73 // We can return INVALID_OPERATION if our vertex attribute does not have
74 // enough backing data.
Jamie Madillc979aab2016-03-12 00:26:44 +000075 if (attribDataSize > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040076 {
Jamie Madillc979aab2016-03-12 00:26:44 +000077 context->recordError(Error(GL_INVALID_OPERATION));
Jamie Madill1ca74672015-07-21 15:14:11 -040078 return false;
79 }
80 }
81 }
82 else if (attrib.pointer == NULL)
83 {
84 // This is an application error that would normally result in a crash,
85 // but we catch it and return an error
86 context->recordError(Error(
87 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
88 return false;
89 }
90 }
91 }
92
93 return true;
94}
95
96} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040097
Geoff Lang0550d032014-01-30 11:29:07 -050098bool ValidCap(const Context *context, GLenum cap)
99{
100 switch (cap)
101 {
102 case GL_CULL_FACE:
103 case GL_POLYGON_OFFSET_FILL:
104 case GL_SAMPLE_ALPHA_TO_COVERAGE:
105 case GL_SAMPLE_COVERAGE:
106 case GL_SCISSOR_TEST:
107 case GL_STENCIL_TEST:
108 case GL_DEPTH_TEST:
109 case GL_BLEND:
110 case GL_DITHER:
111 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500112
Geoff Lang0550d032014-01-30 11:29:07 -0500113 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
114 case GL_RASTERIZER_DISCARD:
115 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500116
117 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
118 case GL_DEBUG_OUTPUT:
119 return context->getExtensions().debug;
120
Geoff Lang0550d032014-01-30 11:29:07 -0500121 default:
122 return false;
123 }
124}
125
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500126bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400127{
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400129 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500130 case GL_TEXTURE_2D:
131 case GL_TEXTURE_CUBE_MAP:
132 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400133
Jamie Madilld7460c72014-01-21 16:38:14 -0500134 case GL_TEXTURE_3D:
135 case GL_TEXTURE_2D_ARRAY:
136 return (context->getClientVersion() >= 3);
137
138 default:
139 return false;
140 }
Jamie Madill35d15012013-10-07 10:46:37 -0400141}
142
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500143bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
144{
145 switch (target)
146 {
147 case GL_TEXTURE_2D:
148 case GL_TEXTURE_CUBE_MAP:
149 return true;
150
151 default:
152 return false;
153 }
154}
155
156bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
157{
158 switch (target)
159 {
160 case GL_TEXTURE_3D:
161 case GL_TEXTURE_2D_ARRAY:
162 return (context->getClientVersion() >= 3);
163
164 default:
165 return false;
166 }
167}
168
Shannon Woods4dfed832014-03-17 20:03:39 -0400169// This function differs from ValidTextureTarget in that the target must be
170// usable as the destination of a 2D operation-- so a cube face is valid, but
171// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400172// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500173bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400174{
175 switch (target)
176 {
177 case GL_TEXTURE_2D:
178 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
179 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
180 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
181 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
182 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
183 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
184 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500185 default:
186 return false;
187 }
188}
189
190bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
191{
192 switch (target)
193 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400194 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500195 case GL_TEXTURE_2D_ARRAY:
196 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400197 default:
198 return false;
199 }
200}
201
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500202bool ValidFramebufferTarget(GLenum target)
203{
Geoff Langd4475812015-03-18 10:53:05 -0400204 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
205 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500206
207 switch (target)
208 {
209 case GL_FRAMEBUFFER: return true;
210 case GL_READ_FRAMEBUFFER: return true;
211 case GL_DRAW_FRAMEBUFFER: return true;
212 default: return false;
213 }
214}
215
Jamie Madill8c96d582014-03-05 15:01:23 -0500216bool ValidBufferTarget(const Context *context, GLenum target)
217{
218 switch (target)
219 {
220 case GL_ARRAY_BUFFER:
221 case GL_ELEMENT_ARRAY_BUFFER:
222 return true;
223
Jamie Madill8c96d582014-03-05 15:01:23 -0500224 case GL_PIXEL_PACK_BUFFER:
225 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400226 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400227
Shannon Woodsb3801742014-03-27 14:59:19 -0400228 case GL_COPY_READ_BUFFER:
229 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500230 case GL_TRANSFORM_FEEDBACK_BUFFER:
231 case GL_UNIFORM_BUFFER:
232 return (context->getClientVersion() >= 3);
233
234 default:
235 return false;
236 }
237}
238
Jamie Madill70656a62014-03-05 15:01:26 -0500239bool ValidBufferParameter(const Context *context, GLenum pname)
240{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400241 const Extensions &extensions = context->getExtensions();
242
Jamie Madill70656a62014-03-05 15:01:26 -0500243 switch (pname)
244 {
245 case GL_BUFFER_USAGE:
246 case GL_BUFFER_SIZE:
247 return true;
248
Geoff Langcc6f55d2015-03-20 13:01:02 -0400249 case GL_BUFFER_ACCESS_OES:
250 return extensions.mapBuffer;
251
252 case GL_BUFFER_MAPPED:
253 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
254 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
255
Jamie Madill70656a62014-03-05 15:01:26 -0500256 // GL_BUFFER_MAP_POINTER is a special case, and may only be
257 // queried with GetBufferPointerv
258 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500259 case GL_BUFFER_MAP_OFFSET:
260 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400261 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500262
263 default:
264 return false;
265 }
266}
267
Jamie Madillc29968b2016-01-20 11:17:23 -0500268bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400269{
Jamie Madillc29968b2016-01-20 11:17:23 -0500270 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400271 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400272 switch (target)
273 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500274 case GL_TEXTURE_2D:
275 maxDimension = caps.max2DTextureSize;
276 break;
Geoff Langce635692013-09-24 13:56:32 -0400277 case GL_TEXTURE_CUBE_MAP:
278 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
279 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
280 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
281 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
282 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500283 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
284 maxDimension = caps.maxCubeMapTextureSize;
285 break;
286 case GL_TEXTURE_3D:
287 maxDimension = caps.max3DTextureSize;
288 break;
289 case GL_TEXTURE_2D_ARRAY:
290 maxDimension = caps.max2DTextureSize;
291 break;
Geoff Langce635692013-09-24 13:56:32 -0400292 default: UNREACHABLE();
293 }
294
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700295 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400296}
297
Austin Kinross08528e12015-10-07 16:24:40 -0700298bool ValidImageSizeParameters(const Context *context,
299 GLenum target,
300 GLint level,
301 GLsizei width,
302 GLsizei height,
303 GLsizei depth,
304 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400305{
306 if (level < 0 || width < 0 || height < 0 || depth < 0)
307 {
308 return false;
309 }
310
Austin Kinross08528e12015-10-07 16:24:40 -0700311 // TexSubImage parameters can be NPOT without textureNPOT extension,
312 // as long as the destination texture is POT.
313 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400314 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400315 {
316 return false;
317 }
318
319 if (!ValidMipLevel(context, target, level))
320 {
321 return false;
322 }
323
324 return true;
325}
326
Geoff Lang0d8b7242015-09-09 14:56:53 -0400327bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
328{
329 // List of compressed format that require that the texture size is smaller than or a multiple of
330 // the compressed block size.
331 switch (internalFormat)
332 {
333 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
334 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
335 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
336 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800337 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400338 return true;
339
340 default:
341 return false;
342 }
343}
344
Jamie Madillc29968b2016-01-20 11:17:23 -0500345bool ValidCompressedImageSize(const ValidationContext *context,
346 GLenum internalFormat,
347 GLsizei width,
348 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400349{
Geoff Lang5d601382014-07-22 15:14:06 -0400350 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
351 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400352 {
353 return false;
354 }
355
Geoff Lang0d8b7242015-09-09 14:56:53 -0400356 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400357 {
358 return false;
359 }
360
Geoff Lang0d8b7242015-09-09 14:56:53 -0400361 if (CompressedTextureFormatRequiresExactSize(internalFormat))
362 {
363 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
364 width % formatInfo.compressedBlockWidth != 0) ||
365 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
366 height % formatInfo.compressedBlockHeight != 0))
367 {
368 return false;
369 }
370 }
371
Geoff Langd4f180b2013-09-24 13:57:44 -0400372 return true;
373}
374
Geoff Lang37dde692014-01-31 16:34:54 -0500375bool ValidQueryType(const Context *context, GLenum queryType)
376{
Geoff Langd4475812015-03-18 10:53:05 -0400377 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
378 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 -0500379
380 switch (queryType)
381 {
382 case GL_ANY_SAMPLES_PASSED:
383 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
384 return true;
385 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
386 return (context->getClientVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500387 case GL_TIME_ELAPSED_EXT:
388 return context->getExtensions().disjointTimerQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500389 default:
390 return false;
391 }
392}
393
Dian Xiang769769a2015-09-09 15:20:08 -0700394Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500395{
396 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
397 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
398 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
399
Dian Xiang769769a2015-09-09 15:20:08 -0700400 Program *validProgram = context->getProgram(id);
401
402 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500403 {
Dian Xiang769769a2015-09-09 15:20:08 -0700404 if (context->getShader(id))
405 {
406 context->recordError(
407 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
408 }
409 else
410 {
411 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
412 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500413 }
Dian Xiang769769a2015-09-09 15:20:08 -0700414
415 return validProgram;
416}
417
418Shader *GetValidShader(Context *context, GLuint id)
419{
420 // See ValidProgram for spec details.
421
422 Shader *validShader = context->getShader(id);
423
424 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500425 {
Dian Xiang769769a2015-09-09 15:20:08 -0700426 if (context->getProgram(id))
427 {
428 context->recordError(
429 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
430 }
431 else
432 {
433 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
434 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500435 }
Dian Xiang769769a2015-09-09 15:20:08 -0700436
437 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500438}
439
Geoff Langb1196682014-07-23 13:47:29 -0400440bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400441{
442 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
443 {
444 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
445
Geoff Langaae65a42014-05-26 12:43:44 -0400446 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400447 {
Geoff Langb1196682014-07-23 13:47:29 -0400448 context->recordError(Error(GL_INVALID_VALUE));
449 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400450 }
451 }
452 else
453 {
454 switch (attachment)
455 {
456 case GL_DEPTH_ATTACHMENT:
457 case GL_STENCIL_ATTACHMENT:
458 break;
459
460 case GL_DEPTH_STENCIL_ATTACHMENT:
461 if (context->getClientVersion() < 3)
462 {
Geoff Langb1196682014-07-23 13:47:29 -0400463 context->recordError(Error(GL_INVALID_ENUM));
464 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400465 }
466 break;
467
468 default:
Geoff Langb1196682014-07-23 13:47:29 -0400469 context->recordError(Error(GL_INVALID_ENUM));
470 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400471 }
472 }
473
474 return true;
475}
476
Corentin Walleze0902642014-11-04 12:32:15 -0800477bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
478 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400479{
480 switch (target)
481 {
482 case GL_RENDERBUFFER:
483 break;
484 default:
Geoff Langb1196682014-07-23 13:47:29 -0400485 context->recordError(Error(GL_INVALID_ENUM));
486 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400487 }
488
489 if (width < 0 || height < 0 || samples < 0)
490 {
Geoff Langb1196682014-07-23 13:47:29 -0400491 context->recordError(Error(GL_INVALID_VALUE));
492 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400493 }
494
Geoff Langd87878e2014-09-19 15:42:59 -0400495 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
496 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400497 {
Geoff Langb1196682014-07-23 13:47:29 -0400498 context->recordError(Error(GL_INVALID_ENUM));
499 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500 }
501
502 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
503 // 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 -0800504 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400505 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400506 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400507 {
Geoff Langb1196682014-07-23 13:47:29 -0400508 context->recordError(Error(GL_INVALID_ENUM));
509 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400510 }
511
Geoff Langaae65a42014-05-26 12:43:44 -0400512 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 {
Geoff Langb1196682014-07-23 13:47:29 -0400514 context->recordError(Error(GL_INVALID_VALUE));
515 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 }
517
Shannon Woods53a94a82014-06-24 15:20:36 -0400518 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 if (handle == 0)
520 {
Geoff Langb1196682014-07-23 13:47:29 -0400521 context->recordError(Error(GL_INVALID_OPERATION));
522 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400523 }
524
525 return true;
526}
527
Corentin Walleze0902642014-11-04 12:32:15 -0800528bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
529 GLenum internalformat, GLsizei width, GLsizei height)
530{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800531 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800532
533 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400534 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800535 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400536 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800537 {
538 context->recordError(Error(GL_INVALID_VALUE));
539 return false;
540 }
541
542 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
543 // the specified storage. This is different than ES 3.0 in which a sample number higher
544 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800545 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
546 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800547 {
Geoff Langa4903b72015-03-02 16:02:48 -0800548 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
549 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
550 {
551 context->recordError(Error(GL_OUT_OF_MEMORY));
552 return false;
553 }
Corentin Walleze0902642014-11-04 12:32:15 -0800554 }
555
556 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
557}
558
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500559bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
560 GLenum renderbuffertarget, GLuint renderbuffer)
561{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400562 if (!ValidFramebufferTarget(target))
563 {
Geoff Langb1196682014-07-23 13:47:29 -0400564 context->recordError(Error(GL_INVALID_ENUM));
565 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400566 }
567
Shannon Woods53a94a82014-06-24 15:20:36 -0400568 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500569
Jamie Madill84115c92015-04-23 15:00:07 -0400570 ASSERT(framebuffer);
571 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500572 {
Jamie Madill84115c92015-04-23 15:00:07 -0400573 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400574 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500575 }
576
Jamie Madillb4472272014-07-03 10:38:55 -0400577 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500578 {
Jamie Madillb4472272014-07-03 10:38:55 -0400579 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500580 }
581
Jamie Madillab9d82c2014-01-21 16:38:14 -0500582 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
583 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
584 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
585 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
586 if (renderbuffer != 0)
587 {
588 if (!context->getRenderbuffer(renderbuffer))
589 {
Geoff Langb1196682014-07-23 13:47:29 -0400590 context->recordError(Error(GL_INVALID_OPERATION));
591 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500592 }
593 }
594
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500595 return true;
596}
597
Jamie Madillc29968b2016-01-20 11:17:23 -0500598bool ValidateBlitFramebufferParameters(gl::Context *context,
599 GLint srcX0,
600 GLint srcY0,
601 GLint srcX1,
602 GLint srcY1,
603 GLint dstX0,
604 GLint dstY0,
605 GLint dstX1,
606 GLint dstY1,
607 GLbitfield mask,
608 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400609{
610 switch (filter)
611 {
612 case GL_NEAREST:
613 break;
614 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400615 break;
616 default:
Geoff Langb1196682014-07-23 13:47:29 -0400617 context->recordError(Error(GL_INVALID_ENUM));
618 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400619 }
620
621 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
622 {
Geoff Langb1196682014-07-23 13:47:29 -0400623 context->recordError(Error(GL_INVALID_VALUE));
624 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400625 }
626
627 if (mask == 0)
628 {
629 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
630 // buffers are copied.
631 return false;
632 }
633
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
635 // color buffer, leaving only nearest being unfiltered from above
636 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
637 {
Geoff Langb1196682014-07-23 13:47:29 -0400638 context->recordError(Error(GL_INVALID_OPERATION));
639 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640 }
641
Shannon Woods53a94a82014-06-24 15:20:36 -0400642 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400643 {
Geoff Langb1196682014-07-23 13:47:29 -0400644 context->recordError(Error(GL_INVALID_OPERATION));
645 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400646 }
647
Jamie Madille3ef7152015-04-28 16:55:17 +0000648 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
649 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500650
651 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652 {
Geoff Langb1196682014-07-23 13:47:29 -0400653 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
654 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 }
656
Geoff Lang748f74e2014-12-01 11:25:34 -0500657 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500658 {
659 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
660 return false;
661 }
662
Geoff Lang748f74e2014-12-01 11:25:34 -0500663 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500664 {
665 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
666 return false;
667 }
668
669 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670 {
Geoff Langb1196682014-07-23 13:47:29 -0400671 context->recordError(Error(GL_INVALID_OPERATION));
672 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 }
674
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
676
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400677 if (mask & GL_COLOR_BUFFER_BIT)
678 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400679 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
680 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500681 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400682
683 if (readColorBuffer && drawColorBuffer)
684 {
Geoff Langd8a22582014-12-17 15:28:23 -0500685 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400686 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400687
Geoff Langa15472a2015-08-11 11:48:03 -0400688 for (size_t drawbufferIdx = 0;
689 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690 {
Geoff Langa15472a2015-08-11 11:48:03 -0400691 const FramebufferAttachment *attachment =
692 drawFramebuffer->getDrawBuffer(drawbufferIdx);
693 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694 {
Geoff Langa15472a2015-08-11 11:48:03 -0400695 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400696 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697
Geoff Langb2f3d052013-08-13 12:49:27 -0400698 // The GL ES 3.0.2 spec (pg 193) states that:
699 // 1) If the read buffer is fixed point format, the draw buffer must be as well
700 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
701 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500702 // Changes with EXT_color_buffer_float:
703 // Case 1) is changed to fixed point OR floating point
704 GLenum readComponentType = readFormatInfo.componentType;
705 GLenum drawComponentType = drawFormatInfo.componentType;
706 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
707 readComponentType == GL_SIGNED_NORMALIZED);
708 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
709 drawComponentType == GL_SIGNED_NORMALIZED);
710
711 if (extensions.colorBufferFloat)
712 {
713 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
714 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
715
716 if (readFixedOrFloat != drawFixedOrFloat)
717 {
718 context->recordError(Error(GL_INVALID_OPERATION,
719 "If the read buffer contains fixed-point or "
720 "floating-point values, the draw buffer "
721 "must as well."));
722 return false;
723 }
724 }
725 else if (readFixedPoint != drawFixedPoint)
726 {
727 context->recordError(Error(GL_INVALID_OPERATION,
728 "If the read buffer contains fixed-point "
729 "values, the draw buffer must as well."));
730 return false;
731 }
732
733 if (readComponentType == GL_UNSIGNED_INT &&
734 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400735 {
Geoff Langb1196682014-07-23 13:47:29 -0400736 context->recordError(Error(GL_INVALID_OPERATION));
737 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400738 }
739
Jamie Madill6163c752015-12-07 16:32:59 -0500740 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741 {
Geoff Langb1196682014-07-23 13:47:29 -0400742 context->recordError(Error(GL_INVALID_OPERATION));
743 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400744 }
745
Geoff Langb2f3d052013-08-13 12:49:27 -0400746 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400747 {
Geoff Langb1196682014-07-23 13:47:29 -0400748 context->recordError(Error(GL_INVALID_OPERATION));
749 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400750 }
751 }
752 }
753
Geoff Lang5d601382014-07-22 15:14:06 -0400754 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400755 {
Geoff Langb1196682014-07-23 13:47:29 -0400756 context->recordError(Error(GL_INVALID_OPERATION));
757 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400758 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 }
760 }
761
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200762 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
763 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
764 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400765 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200766 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400768 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
769 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200771 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400772 {
Geoff Langd8a22582014-12-17 15:28:23 -0500773 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 {
Geoff Langb1196682014-07-23 13:47:29 -0400775 context->recordError(Error(GL_INVALID_OPERATION));
776 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400778
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200779 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 {
Geoff Langb1196682014-07-23 13:47:29 -0400781 context->recordError(Error(GL_INVALID_OPERATION));
782 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400783 }
784 }
785 }
786 }
787
788 return true;
789}
790
Geoff Langb1196682014-07-23 13:47:29 -0400791bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400792{
793 switch (pname)
794 {
795 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
796 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
797 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
798 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
799 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
800 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
801 case GL_CURRENT_VERTEX_ATTRIB:
802 return true;
803
804 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
805 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
806 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400807 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
808 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400809 return true;
810
811 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400812 if (context->getClientVersion() < 3)
813 {
814 context->recordError(Error(GL_INVALID_ENUM));
815 return false;
816 }
817 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400818
819 default:
Geoff Langb1196682014-07-23 13:47:29 -0400820 context->recordError(Error(GL_INVALID_ENUM));
821 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400822 }
823}
824
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400825bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400826{
827 switch (pname)
828 {
829 case GL_TEXTURE_WRAP_R:
830 case GL_TEXTURE_SWIZZLE_R:
831 case GL_TEXTURE_SWIZZLE_G:
832 case GL_TEXTURE_SWIZZLE_B:
833 case GL_TEXTURE_SWIZZLE_A:
834 case GL_TEXTURE_BASE_LEVEL:
835 case GL_TEXTURE_MAX_LEVEL:
836 case GL_TEXTURE_COMPARE_MODE:
837 case GL_TEXTURE_COMPARE_FUNC:
838 case GL_TEXTURE_MIN_LOD:
839 case GL_TEXTURE_MAX_LOD:
840 if (context->getClientVersion() < 3)
841 {
Geoff Langb1196682014-07-23 13:47:29 -0400842 context->recordError(Error(GL_INVALID_ENUM));
843 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400844 }
845 break;
846
847 default: break;
848 }
849
850 switch (pname)
851 {
852 case GL_TEXTURE_WRAP_S:
853 case GL_TEXTURE_WRAP_T:
854 case GL_TEXTURE_WRAP_R:
855 switch (param)
856 {
857 case GL_REPEAT:
858 case GL_CLAMP_TO_EDGE:
859 case GL_MIRRORED_REPEAT:
860 return true;
861 default:
Geoff Langb1196682014-07-23 13:47:29 -0400862 context->recordError(Error(GL_INVALID_ENUM));
863 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400864 }
865
866 case GL_TEXTURE_MIN_FILTER:
867 switch (param)
868 {
869 case GL_NEAREST:
870 case GL_LINEAR:
871 case GL_NEAREST_MIPMAP_NEAREST:
872 case GL_LINEAR_MIPMAP_NEAREST:
873 case GL_NEAREST_MIPMAP_LINEAR:
874 case GL_LINEAR_MIPMAP_LINEAR:
875 return true;
876 default:
Geoff Langb1196682014-07-23 13:47:29 -0400877 context->recordError(Error(GL_INVALID_ENUM));
878 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400879 }
880 break;
881
882 case GL_TEXTURE_MAG_FILTER:
883 switch (param)
884 {
885 case GL_NEAREST:
886 case GL_LINEAR:
887 return true;
888 default:
Geoff Langb1196682014-07-23 13:47:29 -0400889 context->recordError(Error(GL_INVALID_ENUM));
890 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400891 }
892 break;
893
894 case GL_TEXTURE_USAGE_ANGLE:
895 switch (param)
896 {
897 case GL_NONE:
898 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
899 return true;
900 default:
Geoff Langb1196682014-07-23 13:47:29 -0400901 context->recordError(Error(GL_INVALID_ENUM));
902 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400903 }
904 break;
905
906 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400907 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400908 {
Geoff Langb1196682014-07-23 13:47:29 -0400909 context->recordError(Error(GL_INVALID_ENUM));
910 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400911 }
912
913 // we assume the parameter passed to this validation method is truncated, not rounded
914 if (param < 1)
915 {
Geoff Langb1196682014-07-23 13:47:29 -0400916 context->recordError(Error(GL_INVALID_VALUE));
917 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400918 }
919 return true;
920
921 case GL_TEXTURE_MIN_LOD:
922 case GL_TEXTURE_MAX_LOD:
923 // any value is permissible
924 return true;
925
926 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400927 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400928 switch (param)
929 {
930 case GL_NONE:
931 case GL_COMPARE_REF_TO_TEXTURE:
932 return true;
933 default:
Geoff Langb1196682014-07-23 13:47:29 -0400934 context->recordError(Error(GL_INVALID_ENUM));
935 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400936 }
937 break;
938
939 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400940 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400941 switch (param)
942 {
943 case GL_LEQUAL:
944 case GL_GEQUAL:
945 case GL_LESS:
946 case GL_GREATER:
947 case GL_EQUAL:
948 case GL_NOTEQUAL:
949 case GL_ALWAYS:
950 case GL_NEVER:
951 return true;
952 default:
Geoff Langb1196682014-07-23 13:47:29 -0400953 context->recordError(Error(GL_INVALID_ENUM));
954 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400955 }
956 break;
957
958 case GL_TEXTURE_SWIZZLE_R:
959 case GL_TEXTURE_SWIZZLE_G:
960 case GL_TEXTURE_SWIZZLE_B:
961 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400962 switch (param)
963 {
964 case GL_RED:
965 case GL_GREEN:
966 case GL_BLUE:
967 case GL_ALPHA:
968 case GL_ZERO:
969 case GL_ONE:
970 return true;
971 default:
Geoff Langb1196682014-07-23 13:47:29 -0400972 context->recordError(Error(GL_INVALID_ENUM));
973 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400974 }
975 break;
976
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400977 case GL_TEXTURE_BASE_LEVEL:
978 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400979 if (param < 0)
980 {
Geoff Langb1196682014-07-23 13:47:29 -0400981 context->recordError(Error(GL_INVALID_VALUE));
982 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400983 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400984 return true;
985
986 default:
Geoff Langb1196682014-07-23 13:47:29 -0400987 context->recordError(Error(GL_INVALID_ENUM));
988 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400989 }
990}
991
Geoff Langb1196682014-07-23 13:47:29 -0400992bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400993{
994 switch (pname)
995 {
996 case GL_TEXTURE_MIN_FILTER:
997 case GL_TEXTURE_MAG_FILTER:
998 case GL_TEXTURE_WRAP_S:
999 case GL_TEXTURE_WRAP_T:
1000 case GL_TEXTURE_WRAP_R:
1001 case GL_TEXTURE_MIN_LOD:
1002 case GL_TEXTURE_MAX_LOD:
1003 case GL_TEXTURE_COMPARE_MODE:
1004 case GL_TEXTURE_COMPARE_FUNC:
1005 return true;
1006
1007 default:
Geoff Langb1196682014-07-23 13:47:29 -04001008 context->recordError(Error(GL_INVALID_ENUM));
1009 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001010 }
1011}
1012
Jamie Madillc29968b2016-01-20 11:17:23 -05001013bool ValidateReadPixels(Context *context,
1014 GLint x,
1015 GLint y,
1016 GLsizei width,
1017 GLsizei height,
1018 GLenum format,
1019 GLenum type,
1020 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001021{
Jamie Madillc29968b2016-01-20 11:17:23 -05001022 if (width < 0 || height < 0)
1023 {
1024 context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
1025 return false;
1026 }
1027
1028 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001029 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001030
Geoff Lang748f74e2014-12-01 11:25:34 -05001031 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001032 {
Geoff Langb1196682014-07-23 13:47:29 -04001033 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1034 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001035 }
1036
Jamie Madill48faf802014-11-06 15:27:22 -05001037 if (context->getState().getReadFramebuffer()->id() != 0 &&
1038 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001039 {
Geoff Langb1196682014-07-23 13:47:29 -04001040 context->recordError(Error(GL_INVALID_OPERATION));
1041 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001042 }
1043
Geoff Langbce529e2014-12-01 12:48:41 -05001044 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1045 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001046 {
Geoff Langb1196682014-07-23 13:47:29 -04001047 context->recordError(Error(GL_INVALID_OPERATION));
1048 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001049 }
1050
Geoff Langbce529e2014-12-01 12:48:41 -05001051 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1052 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001053 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001054 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001055
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001056 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1057 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001058
1059 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1060 {
Geoff Langb1196682014-07-23 13:47:29 -04001061 context->recordError(Error(GL_INVALID_OPERATION));
1062 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001063 }
1064
Jamie Madillc29968b2016-01-20 11:17:23 -05001065 return true;
1066}
1067
1068bool ValidateReadnPixelsEXT(Context *context,
1069 GLint x,
1070 GLint y,
1071 GLsizei width,
1072 GLsizei height,
1073 GLenum format,
1074 GLenum type,
1075 GLsizei bufSize,
1076 GLvoid *pixels)
1077{
1078 if (bufSize < 0)
1079 {
1080 context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
1081 return false;
1082 }
1083
Geoff Lang5d601382014-07-22 15:14:06 -04001084 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1085 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001086
Minmin Gongadff67b2015-10-14 10:34:45 -04001087 GLsizei outputPitch =
1088 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1089 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001090 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001091 int requiredSize = outputPitch * height;
1092 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001093 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001094 context->recordError(Error(GL_INVALID_OPERATION));
1095 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001096 }
1097
Jamie Madillc29968b2016-01-20 11:17:23 -05001098 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001099}
1100
Olli Etuaho41997e72016-03-10 13:38:39 +02001101bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001102{
1103 if (!context->getExtensions().occlusionQueryBoolean &&
1104 !context->getExtensions().disjointTimerQuery)
1105 {
1106 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1107 return false;
1108 }
1109
Olli Etuaho41997e72016-03-10 13:38:39 +02001110 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001111}
1112
Olli Etuaho41997e72016-03-10 13:38:39 +02001113bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001114{
1115 if (!context->getExtensions().occlusionQueryBoolean &&
1116 !context->getExtensions().disjointTimerQuery)
1117 {
1118 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1119 return false;
1120 }
1121
Olli Etuaho41997e72016-03-10 13:38:39 +02001122 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001123}
1124
1125bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001126{
1127 if (!ValidQueryType(context, target))
1128 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001129 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001130 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001131 }
1132
1133 if (id == 0)
1134 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001135 context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001136 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001137 }
1138
1139 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1140 // of zero, if the active query object name for <target> is non-zero (for the
1141 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1142 // the active query for either target is non-zero), if <id> is the name of an
1143 // existing query object whose type does not match <target>, or if <id> is the
1144 // active query object name for any query type, the error INVALID_OPERATION is
1145 // generated.
1146
1147 // Ensure no other queries are active
1148 // NOTE: If other queries than occlusion are supported, we will need to check
1149 // separately that:
1150 // a) The query ID passed is not the current active query for any target/type
1151 // b) There are no active queries for the requested target (and in the case
1152 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1153 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001154
1155 // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
1156 // same time
Shannon Woods53a94a82014-06-24 15:20:36 -04001157 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001158 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001159 context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001160 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001161 }
1162
1163 Query *queryObject = context->getQuery(id, true, target);
1164
1165 // check that name was obtained with glGenQueries
1166 if (!queryObject)
1167 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001168 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001169 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001170 }
1171
1172 // check for type mismatch
1173 if (queryObject->getType() != target)
1174 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001175 context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001176 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001177 }
1178
1179 return true;
1180}
1181
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001182bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1183{
1184 if (!context->getExtensions().occlusionQueryBoolean &&
1185 !context->getExtensions().disjointTimerQuery)
1186 {
1187 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1188 return false;
1189 }
1190
1191 return ValidateBeginQueryBase(context, target, id);
1192}
1193
1194bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001195{
1196 if (!ValidQueryType(context, target))
1197 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001198 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001199 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001200 }
1201
Shannon Woods53a94a82014-06-24 15:20:36 -04001202 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001203
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001204 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001205 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001206 context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001207 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001208 }
1209
Jamie Madill45c785d2014-05-13 14:09:34 -04001210 return true;
1211}
1212
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001213bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1214{
1215 if (!context->getExtensions().occlusionQueryBoolean &&
1216 !context->getExtensions().disjointTimerQuery)
1217 {
1218 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1219 return false;
1220 }
1221
1222 return ValidateEndQueryBase(context, target);
1223}
1224
1225bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1226{
1227 if (!context->getExtensions().disjointTimerQuery)
1228 {
1229 context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
1230 return false;
1231 }
1232
1233 if (target != GL_TIMESTAMP_EXT)
1234 {
1235 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
1236 return false;
1237 }
1238
1239 Query *queryObject = context->getQuery(id, true, target);
1240 if (queryObject == nullptr)
1241 {
1242 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
1243 return false;
1244 }
1245
1246 if (context->getState().isQueryActive(queryObject))
1247 {
1248 context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
1249 return false;
1250 }
1251
1252 return true;
1253}
1254
1255bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1256{
1257 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1258 {
1259 context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
1260 return false;
1261 }
1262
1263 switch (pname)
1264 {
1265 case GL_CURRENT_QUERY_EXT:
1266 if (target == GL_TIMESTAMP_EXT)
1267 {
1268 context->recordError(
1269 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1270 return false;
1271 }
1272 break;
1273 case GL_QUERY_COUNTER_BITS_EXT:
1274 if (!context->getExtensions().disjointTimerQuery ||
1275 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1276 {
1277 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1278 return false;
1279 }
1280 break;
1281 default:
1282 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1283 return false;
1284 }
1285
1286 return true;
1287}
1288
1289bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1290{
1291 if (!context->getExtensions().occlusionQueryBoolean &&
1292 !context->getExtensions().disjointTimerQuery)
1293 {
1294 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1295 return false;
1296 }
1297
1298 return ValidateGetQueryivBase(context, target, pname);
1299}
1300
1301bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1302{
1303 Query *queryObject = context->getQuery(id, false, GL_NONE);
1304
1305 if (!queryObject)
1306 {
1307 context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
1308 return false;
1309 }
1310
1311 if (context->getState().isQueryActive(queryObject))
1312 {
1313 context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
1314 return false;
1315 }
1316
1317 switch (pname)
1318 {
1319 case GL_QUERY_RESULT_EXT:
1320 case GL_QUERY_RESULT_AVAILABLE_EXT:
1321 break;
1322
1323 default:
1324 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
1325 return false;
1326 }
1327
1328 return true;
1329}
1330
1331bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1332{
1333 if (!context->getExtensions().disjointTimerQuery)
1334 {
1335 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1336 return false;
1337 }
1338 return ValidateGetQueryObjectValueBase(context, id, pname);
1339}
1340
1341bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1342{
1343 if (!context->getExtensions().disjointTimerQuery &&
1344 !context->getExtensions().occlusionQueryBoolean)
1345 {
1346 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1347 return false;
1348 }
1349 return ValidateGetQueryObjectValueBase(context, id, pname);
1350}
1351
1352bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1353{
1354 if (!context->getExtensions().disjointTimerQuery)
1355 {
1356 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1357 return false;
1358 }
1359 return ValidateGetQueryObjectValueBase(context, id, pname);
1360}
1361
1362bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1363{
1364 if (!context->getExtensions().disjointTimerQuery)
1365 {
1366 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1367 return false;
1368 }
1369 return ValidateGetQueryObjectValueBase(context, id, pname);
1370}
1371
Jamie Madill62d31cb2015-09-11 13:25:51 -04001372static bool ValidateUniformCommonBase(gl::Context *context,
1373 GLenum targetUniformType,
1374 GLint location,
1375 GLsizei count,
1376 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001377{
1378 if (count < 0)
1379 {
Geoff Langb1196682014-07-23 13:47:29 -04001380 context->recordError(Error(GL_INVALID_VALUE));
1381 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001382 }
1383
Geoff Lang7dd2e102014-11-10 15:19:26 -05001384 gl::Program *program = context->getState().getProgram();
1385 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001386 {
Geoff Langb1196682014-07-23 13:47:29 -04001387 context->recordError(Error(GL_INVALID_OPERATION));
1388 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001389 }
1390
1391 if (location == -1)
1392 {
1393 // Silently ignore the uniform command
1394 return false;
1395 }
1396
Geoff Lang7dd2e102014-11-10 15:19:26 -05001397 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001398 {
Geoff Langb1196682014-07-23 13:47:29 -04001399 context->recordError(Error(GL_INVALID_OPERATION));
1400 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001401 }
1402
Jamie Madill62d31cb2015-09-11 13:25:51 -04001403 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001404
1405 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001406 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001407 {
Geoff Langb1196682014-07-23 13:47:29 -04001408 context->recordError(Error(GL_INVALID_OPERATION));
1409 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001410 }
1411
Jamie Madill62d31cb2015-09-11 13:25:51 -04001412 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001413 return true;
1414}
1415
Jamie Madillaa981bd2014-05-20 10:55:55 -04001416bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1417{
1418 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001419 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001420 {
Geoff Langb1196682014-07-23 13:47:29 -04001421 context->recordError(Error(GL_INVALID_OPERATION));
1422 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001423 }
1424
Jamie Madill62d31cb2015-09-11 13:25:51 -04001425 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001426 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1427 {
1428 return false;
1429 }
1430
Jamie Madillf2575982014-06-25 16:04:54 -04001431 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001432 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001433 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1434 {
Geoff Langb1196682014-07-23 13:47:29 -04001435 context->recordError(Error(GL_INVALID_OPERATION));
1436 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001437 }
1438
1439 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001440}
1441
1442bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1443 GLboolean transpose)
1444{
1445 // Check for ES3 uniform entry points
1446 int rows = VariableRowCount(matrixType);
1447 int cols = VariableColumnCount(matrixType);
1448 if (rows != cols && context->getClientVersion() < 3)
1449 {
Geoff Langb1196682014-07-23 13:47:29 -04001450 context->recordError(Error(GL_INVALID_OPERATION));
1451 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001452 }
1453
1454 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1455 {
Geoff Langb1196682014-07-23 13:47:29 -04001456 context->recordError(Error(GL_INVALID_VALUE));
1457 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001458 }
1459
Jamie Madill62d31cb2015-09-11 13:25:51 -04001460 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001461 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1462 {
1463 return false;
1464 }
1465
1466 if (uniform->type != matrixType)
1467 {
Geoff Langb1196682014-07-23 13:47:29 -04001468 context->recordError(Error(GL_INVALID_OPERATION));
1469 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001470 }
1471
1472 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001473}
1474
Jamie Madill893ab082014-05-16 16:56:10 -04001475bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1476{
1477 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1478 {
Geoff Langb1196682014-07-23 13:47:29 -04001479 context->recordError(Error(GL_INVALID_ENUM));
1480 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001481 }
1482
Jamie Madill0af26e12015-03-05 19:54:33 -05001483 const Caps &caps = context->getCaps();
1484
Jamie Madill893ab082014-05-16 16:56:10 -04001485 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1486 {
1487 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1488
Jamie Madill0af26e12015-03-05 19:54:33 -05001489 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001490 {
Geoff Langb1196682014-07-23 13:47:29 -04001491 context->recordError(Error(GL_INVALID_OPERATION));
1492 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001493 }
1494 }
1495
1496 switch (pname)
1497 {
1498 case GL_TEXTURE_BINDING_2D:
1499 case GL_TEXTURE_BINDING_CUBE_MAP:
1500 case GL_TEXTURE_BINDING_3D:
1501 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001502 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001503 {
Geoff Langb1196682014-07-23 13:47:29 -04001504 context->recordError(Error(GL_INVALID_OPERATION));
1505 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001506 }
1507 break;
1508
1509 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1510 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1511 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001512 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001513 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001514 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001515 {
Geoff Langb1196682014-07-23 13:47:29 -04001516 context->recordError(Error(GL_INVALID_OPERATION));
1517 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001518 }
1519
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001520 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001521 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001522 {
Geoff Langb1196682014-07-23 13:47:29 -04001523 context->recordError(Error(GL_INVALID_OPERATION));
1524 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001525 }
1526 }
1527 break;
1528
1529 default:
1530 break;
1531 }
1532
1533 // pname is valid, but there are no parameters to return
1534 if (numParams == 0)
1535 {
1536 return false;
1537 }
1538
1539 return true;
1540}
1541
Jamie Madillc29968b2016-01-20 11:17:23 -05001542bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1543 GLenum target,
1544 GLint level,
1545 GLenum internalformat,
1546 bool isSubImage,
1547 GLint xoffset,
1548 GLint yoffset,
1549 GLint zoffset,
1550 GLint x,
1551 GLint y,
1552 GLsizei width,
1553 GLsizei height,
1554 GLint border,
1555 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001556{
Jamie Madill560a8d82014-05-21 13:06:20 -04001557 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1558 {
Geoff Langb1196682014-07-23 13:47:29 -04001559 context->recordError(Error(GL_INVALID_VALUE));
1560 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001561 }
1562
1563 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1564 {
Geoff Langb1196682014-07-23 13:47:29 -04001565 context->recordError(Error(GL_INVALID_VALUE));
1566 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001567 }
1568
1569 if (border != 0)
1570 {
Geoff Langb1196682014-07-23 13:47:29 -04001571 context->recordError(Error(GL_INVALID_VALUE));
1572 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001573 }
1574
1575 if (!ValidMipLevel(context, target, level))
1576 {
Geoff Langb1196682014-07-23 13:47:29 -04001577 context->recordError(Error(GL_INVALID_VALUE));
1578 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001579 }
1580
Jamie Madillc29968b2016-01-20 11:17:23 -05001581 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001582 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001583 {
Geoff Langb1196682014-07-23 13:47:29 -04001584 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1585 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001586 }
1587
Jamie Madillc29968b2016-01-20 11:17:23 -05001588 const auto &state = context->getState();
1589 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001590 {
Geoff Langb1196682014-07-23 13:47:29 -04001591 context->recordError(Error(GL_INVALID_OPERATION));
1592 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001593 }
1594
Geoff Langaae65a42014-05-26 12:43:44 -04001595 const gl::Caps &caps = context->getCaps();
1596
Geoff Langaae65a42014-05-26 12:43:44 -04001597 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001598 switch (target)
1599 {
1600 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001601 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001602 break;
1603
1604 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1605 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1606 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1607 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1608 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1609 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001610 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001611 break;
1612
1613 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001614 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001615 break;
1616
1617 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001618 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001619 break;
1620
1621 default:
Geoff Langb1196682014-07-23 13:47:29 -04001622 context->recordError(Error(GL_INVALID_ENUM));
1623 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001624 }
1625
Jamie Madillc29968b2016-01-20 11:17:23 -05001626 gl::Texture *texture =
1627 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001628 if (!texture)
1629 {
Geoff Langb1196682014-07-23 13:47:29 -04001630 context->recordError(Error(GL_INVALID_OPERATION));
1631 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001632 }
1633
Geoff Lang69cce582015-09-17 13:20:36 -04001634 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001635 {
Geoff Langb1196682014-07-23 13:47:29 -04001636 context->recordError(Error(GL_INVALID_OPERATION));
1637 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001638 }
1639
Geoff Lang5d601382014-07-22 15:14:06 -04001640 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1641
1642 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001643 {
Geoff Langb1196682014-07-23 13:47:29 -04001644 context->recordError(Error(GL_INVALID_OPERATION));
1645 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001646 }
1647
Geoff Langa9be0dc2014-12-17 12:34:40 -05001648 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001649 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001650 context->recordError(Error(GL_INVALID_OPERATION));
1651 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001652 }
1653
1654 if (isSubImage)
1655 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001656 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1657 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1658 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001659 {
Geoff Langb1196682014-07-23 13:47:29 -04001660 context->recordError(Error(GL_INVALID_VALUE));
1661 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001662 }
1663 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001664 else
1665 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001666 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001667 {
Geoff Langb1196682014-07-23 13:47:29 -04001668 context->recordError(Error(GL_INVALID_VALUE));
1669 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001670 }
1671
Geoff Lang5d601382014-07-22 15:14:06 -04001672 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001673 {
Geoff Langb1196682014-07-23 13:47:29 -04001674 context->recordError(Error(GL_INVALID_ENUM));
1675 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001676 }
1677
1678 int maxLevelDimension = (maxDimension >> level);
1679 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1680 {
Geoff Langb1196682014-07-23 13:47:29 -04001681 context->recordError(Error(GL_INVALID_VALUE));
1682 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001683 }
1684 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001685
Geoff Langa9be0dc2014-12-17 12:34:40 -05001686 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001687 return true;
1688}
1689
Jamie Madillf25855c2015-11-03 11:06:18 -05001690static bool ValidateDrawBase(ValidationContext *context,
1691 GLenum mode,
1692 GLsizei count,
1693 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001694{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001695 switch (mode)
1696 {
1697 case GL_POINTS:
1698 case GL_LINES:
1699 case GL_LINE_LOOP:
1700 case GL_LINE_STRIP:
1701 case GL_TRIANGLES:
1702 case GL_TRIANGLE_STRIP:
1703 case GL_TRIANGLE_FAN:
1704 break;
1705 default:
Geoff Langb1196682014-07-23 13:47:29 -04001706 context->recordError(Error(GL_INVALID_ENUM));
1707 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001708 }
1709
Jamie Madill250d33f2014-06-06 17:09:03 -04001710 if (count < 0)
1711 {
Geoff Langb1196682014-07-23 13:47:29 -04001712 context->recordError(Error(GL_INVALID_VALUE));
1713 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001714 }
1715
Geoff Langb1196682014-07-23 13:47:29 -04001716 const State &state = context->getState();
1717
Jamie Madill250d33f2014-06-06 17:09:03 -04001718 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001719 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001720 {
Geoff Langb1196682014-07-23 13:47:29 -04001721 context->recordError(Error(GL_INVALID_OPERATION));
1722 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001723 }
1724
Geoff Lang3a86ad32015-09-01 11:47:05 -04001725 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001726 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001727 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1728 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1729 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1730 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1731 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1732 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1733 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001734 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001735 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1736 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001737 {
1738 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1739 // Section 6.10 of the WebGL 1.0 spec
1740 ERR(
1741 "This ANGLE implementation does not support separate front/back stencil "
1742 "writemasks, reference values, or stencil mask values.");
1743 context->recordError(Error(GL_INVALID_OPERATION));
1744 return false;
1745 }
Jamie Madillac528012014-06-20 13:21:23 -04001746 }
1747
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001748 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001749 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001750 {
Geoff Langb1196682014-07-23 13:47:29 -04001751 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1752 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001753 }
1754
Geoff Lang7dd2e102014-11-10 15:19:26 -05001755 gl::Program *program = state.getProgram();
1756 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001757 {
Geoff Langb1196682014-07-23 13:47:29 -04001758 context->recordError(Error(GL_INVALID_OPERATION));
1759 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001760 }
1761
Geoff Lang7dd2e102014-11-10 15:19:26 -05001762 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001763 {
Geoff Langb1196682014-07-23 13:47:29 -04001764 context->recordError(Error(GL_INVALID_OPERATION));
1765 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001766 }
1767
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001768 // Uniform buffer validation
1769 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1770 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001771 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001772 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001773 const OffsetBindingPointer<Buffer> &uniformBuffer =
1774 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001775
Geoff Lang5d124a62015-09-15 13:03:27 -04001776 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001777 {
1778 // undefined behaviour
1779 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1780 return false;
1781 }
1782
Geoff Lang5d124a62015-09-15 13:03:27 -04001783 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001784 if (uniformBufferSize == 0)
1785 {
1786 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001787 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001788 }
1789
Jamie Madill62d31cb2015-09-11 13:25:51 -04001790 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001791 {
1792 // undefined behaviour
1793 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1794 return false;
1795 }
1796 }
1797
Jamie Madill250d33f2014-06-06 17:09:03 -04001798 // No-op if zero count
1799 return (count > 0);
1800}
1801
Geoff Langb1196682014-07-23 13:47:29 -04001802bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001803{
Jamie Madillfd716582014-06-06 17:09:04 -04001804 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001805 {
Geoff Langb1196682014-07-23 13:47:29 -04001806 context->recordError(Error(GL_INVALID_VALUE));
1807 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001808 }
1809
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001810 const State &state = context->getState();
1811 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001812 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1813 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001814 {
1815 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1816 // that does not match the current transform feedback object's draw mode (if transform feedback
1817 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001818 context->recordError(Error(GL_INVALID_OPERATION));
1819 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001820 }
1821
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001822 if (!ValidateDrawBase(context, mode, count, primcount))
1823 {
1824 return false;
1825 }
1826
1827 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001828 {
1829 return false;
1830 }
1831
1832 return true;
1833}
1834
Geoff Langb1196682014-07-23 13:47:29 -04001835bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001836{
1837 if (primcount < 0)
1838 {
Geoff Langb1196682014-07-23 13:47:29 -04001839 context->recordError(Error(GL_INVALID_VALUE));
1840 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001841 }
1842
Jamie Madill2b976812014-08-25 15:47:49 -04001843 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001844 {
1845 return false;
1846 }
1847
1848 // No-op if zero primitive count
1849 return (primcount > 0);
1850}
1851
Geoff Lang87a93302014-09-16 13:29:43 -04001852static bool ValidateDrawInstancedANGLE(Context *context)
1853{
1854 // Verify there is at least one active attribute with a divisor of zero
1855 const gl::State& state = context->getState();
1856
Geoff Lang7dd2e102014-11-10 15:19:26 -05001857 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001858
1859 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001860 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001861 {
1862 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001863 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001864 {
1865 return true;
1866 }
1867 }
1868
1869 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1870 "has a divisor of zero."));
1871 return false;
1872}
1873
1874bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1875{
1876 if (!ValidateDrawInstancedANGLE(context))
1877 {
1878 return false;
1879 }
1880
1881 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1882}
1883
Jamie Madillf25855c2015-11-03 11:06:18 -05001884bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001885 GLenum mode,
1886 GLsizei count,
1887 GLenum type,
1888 const GLvoid *indices,
1889 GLsizei primcount,
1890 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001891{
Jamie Madill250d33f2014-06-06 17:09:03 -04001892 switch (type)
1893 {
1894 case GL_UNSIGNED_BYTE:
1895 case GL_UNSIGNED_SHORT:
1896 break;
1897 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001898 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001899 {
Geoff Langb1196682014-07-23 13:47:29 -04001900 context->recordError(Error(GL_INVALID_ENUM));
1901 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001902 }
1903 break;
1904 default:
Geoff Langb1196682014-07-23 13:47:29 -04001905 context->recordError(Error(GL_INVALID_ENUM));
1906 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001907 }
1908
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001909 const State &state = context->getState();
1910
1911 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001912 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001913 {
1914 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1915 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001916 context->recordError(Error(GL_INVALID_OPERATION));
1917 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001918 }
1919
1920 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001921 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001922 {
Geoff Langb1196682014-07-23 13:47:29 -04001923 context->recordError(Error(GL_INVALID_OPERATION));
1924 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001925 }
1926
Jamie Madill2b976812014-08-25 15:47:49 -04001927 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001928 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001929 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001930 {
Geoff Langb1196682014-07-23 13:47:29 -04001931 context->recordError(Error(GL_INVALID_OPERATION));
1932 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001933 }
1934
Jamie Madillae3000b2014-08-25 15:47:51 -04001935 if (elementArrayBuffer)
1936 {
1937 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1938
1939 GLint64 offset = reinterpret_cast<GLint64>(indices);
1940 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1941
1942 // check for integer overflows
1943 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1944 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1945 {
Geoff Langb1196682014-07-23 13:47:29 -04001946 context->recordError(Error(GL_OUT_OF_MEMORY));
1947 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001948 }
1949
1950 // Check for reading past the end of the bound buffer object
1951 if (byteCount > elementArrayBuffer->getSize())
1952 {
Geoff Langb1196682014-07-23 13:47:29 -04001953 context->recordError(Error(GL_INVALID_OPERATION));
1954 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001955 }
1956 }
1957 else if (!indices)
1958 {
1959 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001960 context->recordError(Error(GL_INVALID_OPERATION));
1961 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001962 }
1963
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001964 if (!ValidateDrawBase(context, mode, count, primcount))
1965 {
1966 return false;
1967 }
1968
Jamie Madill2b976812014-08-25 15:47:49 -04001969 // Use max index to validate if our vertex buffers are large enough for the pull.
1970 // TODO: offer fast path, with disabled index validation.
1971 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1972 if (elementArrayBuffer)
1973 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001974 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001975 Error error =
1976 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1977 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001978 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001979 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001980 context->recordError(error);
1981 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001982 }
1983 }
1984 else
1985 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001986 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001987 }
1988
Jamie Madille79b1e12015-11-04 16:36:37 -05001989 // If we use an index greater than our maximum supported index range, return an error.
1990 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1991 // return an error if possible here.
1992 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1993 {
1994 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1995 return false;
1996 }
1997
Jamie Madillc979aab2016-03-12 00:26:44 +00001998 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001999 {
2000 return false;
2001 }
2002
Geoff Lang3edfe032015-09-04 16:38:24 -04002003 // No op if there are no real indices in the index data (all are primitive restart).
2004 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002005}
2006
Geoff Langb1196682014-07-23 13:47:29 -04002007bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002008 GLenum mode,
2009 GLsizei count,
2010 GLenum type,
2011 const GLvoid *indices,
2012 GLsizei primcount,
2013 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002014{
2015 if (primcount < 0)
2016 {
Geoff Langb1196682014-07-23 13:47:29 -04002017 context->recordError(Error(GL_INVALID_VALUE));
2018 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002019 }
2020
Jamie Madill2b976812014-08-25 15:47:49 -04002021 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002022 {
2023 return false;
2024 }
2025
2026 // No-op zero primitive count
2027 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002028}
2029
Geoff Lang3edfe032015-09-04 16:38:24 -04002030bool ValidateDrawElementsInstancedANGLE(Context *context,
2031 GLenum mode,
2032 GLsizei count,
2033 GLenum type,
2034 const GLvoid *indices,
2035 GLsizei primcount,
2036 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002037{
2038 if (!ValidateDrawInstancedANGLE(context))
2039 {
2040 return false;
2041 }
2042
2043 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2044}
2045
Geoff Langb1196682014-07-23 13:47:29 -04002046bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002047 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002048{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002049 if (!ValidFramebufferTarget(target))
2050 {
Geoff Langb1196682014-07-23 13:47:29 -04002051 context->recordError(Error(GL_INVALID_ENUM));
2052 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002053 }
2054
2055 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002056 {
2057 return false;
2058 }
2059
Jamie Madill55ec3b12014-07-03 10:38:57 -04002060 if (texture != 0)
2061 {
2062 gl::Texture *tex = context->getTexture(texture);
2063
2064 if (tex == NULL)
2065 {
Geoff Langb1196682014-07-23 13:47:29 -04002066 context->recordError(Error(GL_INVALID_OPERATION));
2067 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002068 }
2069
2070 if (level < 0)
2071 {
Geoff Langb1196682014-07-23 13:47:29 -04002072 context->recordError(Error(GL_INVALID_VALUE));
2073 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002074 }
2075 }
2076
Shannon Woods53a94a82014-06-24 15:20:36 -04002077 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002078 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002079
Jamie Madill84115c92015-04-23 15:00:07 -04002080 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002081 {
Jamie Madill84115c92015-04-23 15:00:07 -04002082 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002083 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002084 }
2085
2086 return true;
2087}
2088
Geoff Langb1196682014-07-23 13:47:29 -04002089bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002090 GLenum textarget, GLuint texture, GLint level)
2091{
Geoff Lang95663912015-04-02 15:54:45 -04002092 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2093 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002094 {
Geoff Langb1196682014-07-23 13:47:29 -04002095 context->recordError(Error(GL_INVALID_VALUE));
2096 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002097 }
2098
2099 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002100 {
2101 return false;
2102 }
2103
Jamie Madill55ec3b12014-07-03 10:38:57 -04002104 if (texture != 0)
2105 {
2106 gl::Texture *tex = context->getTexture(texture);
2107 ASSERT(tex);
2108
Jamie Madill2a6564e2014-07-11 09:53:19 -04002109 const gl::Caps &caps = context->getCaps();
2110
Jamie Madill55ec3b12014-07-03 10:38:57 -04002111 switch (textarget)
2112 {
2113 case GL_TEXTURE_2D:
2114 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002115 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002116 {
Geoff Langb1196682014-07-23 13:47:29 -04002117 context->recordError(Error(GL_INVALID_VALUE));
2118 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002119 }
2120 if (tex->getTarget() != GL_TEXTURE_2D)
2121 {
Geoff Langb1196682014-07-23 13:47:29 -04002122 context->recordError(Error(GL_INVALID_OPERATION));
2123 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002124 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002125 }
2126 break;
2127
2128 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2129 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2130 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2131 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2132 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2133 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2134 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002135 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002136 {
Geoff Langb1196682014-07-23 13:47:29 -04002137 context->recordError(Error(GL_INVALID_VALUE));
2138 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002139 }
2140 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2141 {
Geoff Langb1196682014-07-23 13:47:29 -04002142 context->recordError(Error(GL_INVALID_OPERATION));
2143 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002144 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002145 }
2146 break;
2147
2148 default:
Geoff Langb1196682014-07-23 13:47:29 -04002149 context->recordError(Error(GL_INVALID_ENUM));
2150 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002151 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002152
2153 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2154 if (internalFormatInfo.compressed)
2155 {
2156 context->recordError(Error(GL_INVALID_OPERATION));
2157 return false;
2158 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002159 }
2160
Jamie Madill570f7c82014-07-03 10:38:54 -04002161 return true;
2162}
2163
Geoff Langb1196682014-07-23 13:47:29 -04002164bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002165{
2166 if (program == 0)
2167 {
Geoff Langb1196682014-07-23 13:47:29 -04002168 context->recordError(Error(GL_INVALID_VALUE));
2169 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002170 }
2171
Dian Xiang769769a2015-09-09 15:20:08 -07002172 gl::Program *programObject = GetValidProgram(context, program);
2173 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002174 {
2175 return false;
2176 }
2177
Jamie Madill0063c512014-08-25 15:47:53 -04002178 if (!programObject || !programObject->isLinked())
2179 {
Geoff Langb1196682014-07-23 13:47:29 -04002180 context->recordError(Error(GL_INVALID_OPERATION));
2181 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002182 }
2183
Geoff Lang7dd2e102014-11-10 15:19:26 -05002184 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002185 {
Geoff Langb1196682014-07-23 13:47:29 -04002186 context->recordError(Error(GL_INVALID_OPERATION));
2187 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002188 }
2189
Jamie Madill0063c512014-08-25 15:47:53 -04002190 return true;
2191}
2192
Geoff Langb1196682014-07-23 13:47:29 -04002193bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002194{
2195 return ValidateGetUniformBase(context, program, location);
2196}
2197
Geoff Langb1196682014-07-23 13:47:29 -04002198bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002199{
Jamie Madill78f41802014-08-25 15:47:55 -04002200 return ValidateGetUniformBase(context, program, location);
2201}
2202
Geoff Langb1196682014-07-23 13:47:29 -04002203static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002204{
2205 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002206 {
Jamie Madill78f41802014-08-25 15:47:55 -04002207 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002208 }
2209
Jamie Madilla502c742014-08-28 17:19:13 -04002210 gl::Program *programObject = context->getProgram(program);
2211 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002212
Jamie Madill78f41802014-08-25 15:47:55 -04002213 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002214 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2215 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002216 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002217 {
Geoff Langb1196682014-07-23 13:47:29 -04002218 context->recordError(Error(GL_INVALID_OPERATION));
2219 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002220 }
2221
2222 return true;
2223}
2224
Geoff Langb1196682014-07-23 13:47:29 -04002225bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002226{
Jamie Madill78f41802014-08-25 15:47:55 -04002227 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002228}
2229
Geoff Langb1196682014-07-23 13:47:29 -04002230bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002231{
Jamie Madill78f41802014-08-25 15:47:55 -04002232 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002233}
2234
Austin Kinross08332632015-05-05 13:35:47 -07002235bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2236 const GLenum *attachments, bool defaultFramebuffer)
2237{
2238 if (numAttachments < 0)
2239 {
2240 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2241 return false;
2242 }
2243
2244 for (GLsizei i = 0; i < numAttachments; ++i)
2245 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002246 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002247 {
2248 if (defaultFramebuffer)
2249 {
2250 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2251 return false;
2252 }
2253
2254 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2255 {
2256 context->recordError(Error(GL_INVALID_OPERATION,
2257 "Requested color attachment is greater than the maximum supported color attachments"));
2258 return false;
2259 }
2260 }
2261 else
2262 {
2263 switch (attachments[i])
2264 {
2265 case GL_DEPTH_ATTACHMENT:
2266 case GL_STENCIL_ATTACHMENT:
2267 case GL_DEPTH_STENCIL_ATTACHMENT:
2268 if (defaultFramebuffer)
2269 {
2270 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2271 return false;
2272 }
2273 break;
2274 case GL_COLOR:
2275 case GL_DEPTH:
2276 case GL_STENCIL:
2277 if (!defaultFramebuffer)
2278 {
2279 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2280 return false;
2281 }
2282 break;
2283 default:
2284 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2285 return false;
2286 }
2287 }
2288 }
2289
2290 return true;
2291}
2292
Austin Kinross6ee1e782015-05-29 17:05:37 -07002293bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2294{
2295 // Note that debug marker calls must not set error state
2296
2297 if (length < 0)
2298 {
2299 return false;
2300 }
2301
2302 if (marker == nullptr)
2303 {
2304 return false;
2305 }
2306
2307 return true;
2308}
2309
2310bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2311{
2312 // Note that debug marker calls must not set error state
2313
2314 if (length < 0)
2315 {
2316 return false;
2317 }
2318
2319 if (length > 0 && marker == nullptr)
2320 {
2321 return false;
2322 }
2323
2324 return true;
2325}
2326
Geoff Langdcab33b2015-07-21 13:03:16 -04002327bool ValidateEGLImageTargetTexture2DOES(Context *context,
2328 egl::Display *display,
2329 GLenum target,
2330 egl::Image *image)
2331{
Geoff Langa8406172015-07-21 16:53:39 -04002332 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2333 {
2334 context->recordError(Error(GL_INVALID_OPERATION));
2335 return false;
2336 }
2337
2338 switch (target)
2339 {
2340 case GL_TEXTURE_2D:
2341 break;
2342
2343 default:
2344 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2345 return false;
2346 }
2347
2348 if (!display->isValidImage(image))
2349 {
2350 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2351 return false;
2352 }
2353
2354 if (image->getSamples() > 0)
2355 {
2356 context->recordError(Error(GL_INVALID_OPERATION,
2357 "cannot create a 2D texture from a multisampled EGL image."));
2358 return false;
2359 }
2360
2361 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2362 if (!textureCaps.texturable)
2363 {
2364 context->recordError(Error(GL_INVALID_OPERATION,
2365 "EGL image internal format is not supported as a texture."));
2366 return false;
2367 }
2368
Geoff Langdcab33b2015-07-21 13:03:16 -04002369 return true;
2370}
2371
2372bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2373 egl::Display *display,
2374 GLenum target,
2375 egl::Image *image)
2376{
Geoff Langa8406172015-07-21 16:53:39 -04002377 if (!context->getExtensions().eglImage)
2378 {
2379 context->recordError(Error(GL_INVALID_OPERATION));
2380 return false;
2381 }
2382
2383 switch (target)
2384 {
2385 case GL_RENDERBUFFER:
2386 break;
2387
2388 default:
2389 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2390 return false;
2391 }
2392
2393 if (!display->isValidImage(image))
2394 {
2395 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2396 return false;
2397 }
2398
2399 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2400 if (!textureCaps.renderable)
2401 {
2402 context->recordError(Error(
2403 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2404 return false;
2405 }
2406
Geoff Langdcab33b2015-07-21 13:03:16 -04002407 return true;
2408}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002409
2410bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2411{
Geoff Lang36167ab2015-12-07 10:27:14 -05002412 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002413 {
2414 // The default VAO should always exist
2415 ASSERT(array != 0);
2416 context->recordError(Error(GL_INVALID_OPERATION));
2417 return false;
2418 }
2419
2420 return true;
2421}
2422
Geoff Langc5629752015-12-07 16:29:04 -05002423bool ValidateProgramBinaryBase(Context *context,
2424 GLuint program,
2425 GLenum binaryFormat,
2426 const void *binary,
2427 GLint length)
2428{
2429 Program *programObject = GetValidProgram(context, program);
2430 if (programObject == nullptr)
2431 {
2432 return false;
2433 }
2434
2435 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2436 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2437 programBinaryFormats.end())
2438 {
2439 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2440 return false;
2441 }
2442
2443 return true;
2444}
2445
2446bool ValidateGetProgramBinaryBase(Context *context,
2447 GLuint program,
2448 GLsizei bufSize,
2449 GLsizei *length,
2450 GLenum *binaryFormat,
2451 void *binary)
2452{
2453 Program *programObject = GetValidProgram(context, program);
2454 if (programObject == nullptr)
2455 {
2456 return false;
2457 }
2458
2459 if (!programObject->isLinked())
2460 {
2461 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2462 return false;
2463 }
2464
2465 return true;
2466}
Jamie Madillc29968b2016-01-20 11:17:23 -05002467
2468bool ValidateCopyTexImage2D(ValidationContext *context,
2469 GLenum target,
2470 GLint level,
2471 GLenum internalformat,
2472 GLint x,
2473 GLint y,
2474 GLsizei width,
2475 GLsizei height,
2476 GLint border)
2477{
2478 if (context->getClientVersion() < 3)
2479 {
2480 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2481 0, x, y, width, height, border);
2482 }
2483
2484 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002485 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2486 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002487}
Jamie Madillc29968b2016-01-20 11:17:23 -05002488
2489bool ValidateFramebufferRenderbuffer(Context *context,
2490 GLenum target,
2491 GLenum attachment,
2492 GLenum renderbuffertarget,
2493 GLuint renderbuffer)
2494{
2495 if (!ValidFramebufferTarget(target) ||
2496 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2497 {
2498 context->recordError(Error(GL_INVALID_ENUM));
2499 return false;
2500 }
2501
2502 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2503 renderbuffertarget, renderbuffer);
2504}
2505
2506bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2507{
2508 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2509 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2510 {
2511 context->recordError(
2512 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2513 return false;
2514 }
2515
2516 ASSERT(context->getState().getDrawFramebuffer());
2517 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2518 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2519
2520 // This should come first before the check for the default frame buffer
2521 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2522 // rather than INVALID_OPERATION
2523 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2524 {
2525 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2526
2527 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02002528 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
2529 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05002530 {
2531 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02002532 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
2533 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
2534 // 3.1 is still a bit ambiguous about the error, but future specs are
2535 // expected to clarify that GL_INVALID_ENUM is the correct error.
2536 context->recordError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
2537 return false;
2538 }
2539 else if (bufs[colorAttachment] >= maxColorAttachment)
2540 {
2541 context->recordError(
2542 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002543 return false;
2544 }
2545 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2546 frameBufferId != 0)
2547 {
2548 // INVALID_OPERATION-GL is bound to buffer and ith argument
2549 // is not COLOR_ATTACHMENTi or NONE
2550 context->recordError(
2551 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2552 return false;
2553 }
2554 }
2555
2556 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2557 // and n is not 1 or bufs is bound to value other than BACK and NONE
2558 if (frameBufferId == 0)
2559 {
2560 if (n != 1)
2561 {
2562 context->recordError(Error(GL_INVALID_OPERATION,
2563 "n must be 1 when GL is bound to the default framebuffer"));
2564 return false;
2565 }
2566
2567 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2568 {
2569 context->recordError(Error(
2570 GL_INVALID_OPERATION,
2571 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2572 return false;
2573 }
2574 }
2575
2576 return true;
2577}
2578
2579bool ValidateCopyTexSubImage2D(Context *context,
2580 GLenum target,
2581 GLint level,
2582 GLint xoffset,
2583 GLint yoffset,
2584 GLint x,
2585 GLint y,
2586 GLsizei width,
2587 GLsizei height)
2588{
2589 if (context->getClientVersion() < 3)
2590 {
2591 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2592 yoffset, x, y, width, height, 0);
2593 }
2594
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002595 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2596 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002597}
2598
Olli Etuaho41997e72016-03-10 13:38:39 +02002599bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
2600{
2601 return ValidateGenOrDelete(context, n);
2602}
2603
2604bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
2605{
2606 return ValidateGenOrDelete(context, n);
2607}
2608
2609bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
2610{
2611 return ValidateGenOrDelete(context, n);
2612}
2613
2614bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
2615{
2616 return ValidateGenOrDelete(context, n);
2617}
2618
2619bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
2620{
2621 return ValidateGenOrDelete(context, n);
2622}
2623
2624bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
2625{
2626 return ValidateGenOrDelete(context, n);
2627}
2628
2629bool ValidateGenTextures(Context *context, GLint n, GLuint *)
2630{
2631 return ValidateGenOrDelete(context, n);
2632}
2633
2634bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
2635{
2636 return ValidateGenOrDelete(context, n);
2637}
2638
2639bool ValidateGenOrDelete(Context *context, GLint n)
2640{
2641 if (n < 0)
2642 {
2643 context->recordError(Error(GL_INVALID_VALUE, "n < 0"));
2644 return false;
2645 }
2646 return true;
2647}
2648
Jamie Madillc29968b2016-01-20 11:17:23 -05002649} // namespace gl