blob: 12c76120bd4f7173607e2665ad75acff7b21f59f [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.
75 if (attribDataSize > buffer->getSize())
76 {
77 context->recordError(Error(GL_INVALID_OPERATION));
78 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
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001101bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
1102{
1103 if (n < 0)
1104 {
1105 context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
1106 return false;
1107 }
1108
1109 return true;
1110}
1111
1112bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
1113{
1114 if (!context->getExtensions().occlusionQueryBoolean &&
1115 !context->getExtensions().disjointTimerQuery)
1116 {
1117 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1118 return false;
1119 }
1120
1121 return ValidateGenQueriesBase(context, n, ids);
1122}
1123
1124bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
1125{
1126 if (n < 0)
1127 {
1128 context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
1129 return false;
1130 }
1131
1132 return true;
1133}
1134
1135bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
1136{
1137 if (!context->getExtensions().occlusionQueryBoolean &&
1138 !context->getExtensions().disjointTimerQuery)
1139 {
1140 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1141 return false;
1142 }
1143
1144 return ValidateDeleteQueriesBase(context, n, ids);
1145}
1146
1147bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001148{
1149 if (!ValidQueryType(context, target))
1150 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001151 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001152 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001153 }
1154
1155 if (id == 0)
1156 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001157 context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001158 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001159 }
1160
1161 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1162 // of zero, if the active query object name for <target> is non-zero (for the
1163 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1164 // the active query for either target is non-zero), if <id> is the name of an
1165 // existing query object whose type does not match <target>, or if <id> is the
1166 // active query object name for any query type, the error INVALID_OPERATION is
1167 // generated.
1168
1169 // Ensure no other queries are active
1170 // NOTE: If other queries than occlusion are supported, we will need to check
1171 // separately that:
1172 // a) The query ID passed is not the current active query for any target/type
1173 // b) There are no active queries for the requested target (and in the case
1174 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1175 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001176
1177 // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
1178 // same time
Shannon Woods53a94a82014-06-24 15:20:36 -04001179 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001180 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001181 context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001182 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001183 }
1184
1185 Query *queryObject = context->getQuery(id, true, target);
1186
1187 // check that name was obtained with glGenQueries
1188 if (!queryObject)
1189 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001190 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001191 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001192 }
1193
1194 // check for type mismatch
1195 if (queryObject->getType() != target)
1196 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001197 context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001198 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001199 }
1200
1201 return true;
1202}
1203
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001204bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1205{
1206 if (!context->getExtensions().occlusionQueryBoolean &&
1207 !context->getExtensions().disjointTimerQuery)
1208 {
1209 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1210 return false;
1211 }
1212
1213 return ValidateBeginQueryBase(context, target, id);
1214}
1215
1216bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001217{
1218 if (!ValidQueryType(context, target))
1219 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001220 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001221 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001222 }
1223
Shannon Woods53a94a82014-06-24 15:20:36 -04001224 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001225
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001226 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001227 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001228 context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001229 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001230 }
1231
Jamie Madill45c785d2014-05-13 14:09:34 -04001232 return true;
1233}
1234
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001235bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1236{
1237 if (!context->getExtensions().occlusionQueryBoolean &&
1238 !context->getExtensions().disjointTimerQuery)
1239 {
1240 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1241 return false;
1242 }
1243
1244 return ValidateEndQueryBase(context, target);
1245}
1246
1247bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1248{
1249 if (!context->getExtensions().disjointTimerQuery)
1250 {
1251 context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
1252 return false;
1253 }
1254
1255 if (target != GL_TIMESTAMP_EXT)
1256 {
1257 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
1258 return false;
1259 }
1260
1261 Query *queryObject = context->getQuery(id, true, target);
1262 if (queryObject == nullptr)
1263 {
1264 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
1265 return false;
1266 }
1267
1268 if (context->getState().isQueryActive(queryObject))
1269 {
1270 context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
1271 return false;
1272 }
1273
1274 return true;
1275}
1276
1277bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1278{
1279 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1280 {
1281 context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
1282 return false;
1283 }
1284
1285 switch (pname)
1286 {
1287 case GL_CURRENT_QUERY_EXT:
1288 if (target == GL_TIMESTAMP_EXT)
1289 {
1290 context->recordError(
1291 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1292 return false;
1293 }
1294 break;
1295 case GL_QUERY_COUNTER_BITS_EXT:
1296 if (!context->getExtensions().disjointTimerQuery ||
1297 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1298 {
1299 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1300 return false;
1301 }
1302 break;
1303 default:
1304 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1305 return false;
1306 }
1307
1308 return true;
1309}
1310
1311bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1312{
1313 if (!context->getExtensions().occlusionQueryBoolean &&
1314 !context->getExtensions().disjointTimerQuery)
1315 {
1316 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1317 return false;
1318 }
1319
1320 return ValidateGetQueryivBase(context, target, pname);
1321}
1322
1323bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1324{
1325 Query *queryObject = context->getQuery(id, false, GL_NONE);
1326
1327 if (!queryObject)
1328 {
1329 context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
1330 return false;
1331 }
1332
1333 if (context->getState().isQueryActive(queryObject))
1334 {
1335 context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
1336 return false;
1337 }
1338
1339 switch (pname)
1340 {
1341 case GL_QUERY_RESULT_EXT:
1342 case GL_QUERY_RESULT_AVAILABLE_EXT:
1343 break;
1344
1345 default:
1346 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
1347 return false;
1348 }
1349
1350 return true;
1351}
1352
1353bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1354{
1355 if (!context->getExtensions().disjointTimerQuery)
1356 {
1357 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1358 return false;
1359 }
1360 return ValidateGetQueryObjectValueBase(context, id, pname);
1361}
1362
1363bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1364{
1365 if (!context->getExtensions().disjointTimerQuery &&
1366 !context->getExtensions().occlusionQueryBoolean)
1367 {
1368 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1369 return false;
1370 }
1371 return ValidateGetQueryObjectValueBase(context, id, pname);
1372}
1373
1374bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1375{
1376 if (!context->getExtensions().disjointTimerQuery)
1377 {
1378 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1379 return false;
1380 }
1381 return ValidateGetQueryObjectValueBase(context, id, pname);
1382}
1383
1384bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1385{
1386 if (!context->getExtensions().disjointTimerQuery)
1387 {
1388 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1389 return false;
1390 }
1391 return ValidateGetQueryObjectValueBase(context, id, pname);
1392}
1393
Jamie Madill62d31cb2015-09-11 13:25:51 -04001394static bool ValidateUniformCommonBase(gl::Context *context,
1395 GLenum targetUniformType,
1396 GLint location,
1397 GLsizei count,
1398 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001399{
1400 if (count < 0)
1401 {
Geoff Langb1196682014-07-23 13:47:29 -04001402 context->recordError(Error(GL_INVALID_VALUE));
1403 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001404 }
1405
Geoff Lang7dd2e102014-11-10 15:19:26 -05001406 gl::Program *program = context->getState().getProgram();
1407 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001408 {
Geoff Langb1196682014-07-23 13:47:29 -04001409 context->recordError(Error(GL_INVALID_OPERATION));
1410 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001411 }
1412
1413 if (location == -1)
1414 {
1415 // Silently ignore the uniform command
1416 return false;
1417 }
1418
Geoff Lang7dd2e102014-11-10 15:19:26 -05001419 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001420 {
Geoff Langb1196682014-07-23 13:47:29 -04001421 context->recordError(Error(GL_INVALID_OPERATION));
1422 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001423 }
1424
Jamie Madill62d31cb2015-09-11 13:25:51 -04001425 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001426
1427 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001428 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001429 {
Geoff Langb1196682014-07-23 13:47:29 -04001430 context->recordError(Error(GL_INVALID_OPERATION));
1431 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001432 }
1433
Jamie Madill62d31cb2015-09-11 13:25:51 -04001434 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001435 return true;
1436}
1437
Jamie Madillaa981bd2014-05-20 10:55:55 -04001438bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1439{
1440 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001441 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001442 {
Geoff Langb1196682014-07-23 13:47:29 -04001443 context->recordError(Error(GL_INVALID_OPERATION));
1444 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001445 }
1446
Jamie Madill62d31cb2015-09-11 13:25:51 -04001447 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001448 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1449 {
1450 return false;
1451 }
1452
Jamie Madillf2575982014-06-25 16:04:54 -04001453 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001454 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001455 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1456 {
Geoff Langb1196682014-07-23 13:47:29 -04001457 context->recordError(Error(GL_INVALID_OPERATION));
1458 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001459 }
1460
1461 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001462}
1463
1464bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1465 GLboolean transpose)
1466{
1467 // Check for ES3 uniform entry points
1468 int rows = VariableRowCount(matrixType);
1469 int cols = VariableColumnCount(matrixType);
1470 if (rows != cols && context->getClientVersion() < 3)
1471 {
Geoff Langb1196682014-07-23 13:47:29 -04001472 context->recordError(Error(GL_INVALID_OPERATION));
1473 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001474 }
1475
1476 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1477 {
Geoff Langb1196682014-07-23 13:47:29 -04001478 context->recordError(Error(GL_INVALID_VALUE));
1479 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001480 }
1481
Jamie Madill62d31cb2015-09-11 13:25:51 -04001482 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001483 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1484 {
1485 return false;
1486 }
1487
1488 if (uniform->type != matrixType)
1489 {
Geoff Langb1196682014-07-23 13:47:29 -04001490 context->recordError(Error(GL_INVALID_OPERATION));
1491 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001492 }
1493
1494 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001495}
1496
Jamie Madill893ab082014-05-16 16:56:10 -04001497bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1498{
1499 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1500 {
Geoff Langb1196682014-07-23 13:47:29 -04001501 context->recordError(Error(GL_INVALID_ENUM));
1502 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001503 }
1504
Jamie Madill0af26e12015-03-05 19:54:33 -05001505 const Caps &caps = context->getCaps();
1506
Jamie Madill893ab082014-05-16 16:56:10 -04001507 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1508 {
1509 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1510
Jamie Madill0af26e12015-03-05 19:54:33 -05001511 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001512 {
Geoff Langb1196682014-07-23 13:47:29 -04001513 context->recordError(Error(GL_INVALID_OPERATION));
1514 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001515 }
1516 }
1517
1518 switch (pname)
1519 {
1520 case GL_TEXTURE_BINDING_2D:
1521 case GL_TEXTURE_BINDING_CUBE_MAP:
1522 case GL_TEXTURE_BINDING_3D:
1523 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001524 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001525 {
Geoff Langb1196682014-07-23 13:47:29 -04001526 context->recordError(Error(GL_INVALID_OPERATION));
1527 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001528 }
1529 break;
1530
1531 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1532 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1533 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001534 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001535 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001536 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001537 {
Geoff Langb1196682014-07-23 13:47:29 -04001538 context->recordError(Error(GL_INVALID_OPERATION));
1539 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001540 }
1541
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001542 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001543 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001544 {
Geoff Langb1196682014-07-23 13:47:29 -04001545 context->recordError(Error(GL_INVALID_OPERATION));
1546 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001547 }
1548 }
1549 break;
1550
1551 default:
1552 break;
1553 }
1554
1555 // pname is valid, but there are no parameters to return
1556 if (numParams == 0)
1557 {
1558 return false;
1559 }
1560
1561 return true;
1562}
1563
Jamie Madillc29968b2016-01-20 11:17:23 -05001564bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1565 GLenum target,
1566 GLint level,
1567 GLenum internalformat,
1568 bool isSubImage,
1569 GLint xoffset,
1570 GLint yoffset,
1571 GLint zoffset,
1572 GLint x,
1573 GLint y,
1574 GLsizei width,
1575 GLsizei height,
1576 GLint border,
1577 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001578{
Jamie Madill560a8d82014-05-21 13:06:20 -04001579 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1580 {
Geoff Langb1196682014-07-23 13:47:29 -04001581 context->recordError(Error(GL_INVALID_VALUE));
1582 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001583 }
1584
1585 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1586 {
Geoff Langb1196682014-07-23 13:47:29 -04001587 context->recordError(Error(GL_INVALID_VALUE));
1588 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001589 }
1590
1591 if (border != 0)
1592 {
Geoff Langb1196682014-07-23 13:47:29 -04001593 context->recordError(Error(GL_INVALID_VALUE));
1594 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001595 }
1596
1597 if (!ValidMipLevel(context, target, level))
1598 {
Geoff Langb1196682014-07-23 13:47:29 -04001599 context->recordError(Error(GL_INVALID_VALUE));
1600 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001601 }
1602
Jamie Madillc29968b2016-01-20 11:17:23 -05001603 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001604 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001605 {
Geoff Langb1196682014-07-23 13:47:29 -04001606 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1607 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001608 }
1609
Jamie Madillc29968b2016-01-20 11:17:23 -05001610 const auto &state = context->getState();
1611 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001612 {
Geoff Langb1196682014-07-23 13:47:29 -04001613 context->recordError(Error(GL_INVALID_OPERATION));
1614 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001615 }
1616
Geoff Langaae65a42014-05-26 12:43:44 -04001617 const gl::Caps &caps = context->getCaps();
1618
Geoff Langaae65a42014-05-26 12:43:44 -04001619 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001620 switch (target)
1621 {
1622 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001623 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001624 break;
1625
1626 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1627 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1628 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1629 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1630 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1631 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001632 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001633 break;
1634
1635 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001636 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001637 break;
1638
1639 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001640 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001641 break;
1642
1643 default:
Geoff Langb1196682014-07-23 13:47:29 -04001644 context->recordError(Error(GL_INVALID_ENUM));
1645 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001646 }
1647
Jamie Madillc29968b2016-01-20 11:17:23 -05001648 gl::Texture *texture =
1649 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001650 if (!texture)
1651 {
Geoff Langb1196682014-07-23 13:47:29 -04001652 context->recordError(Error(GL_INVALID_OPERATION));
1653 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001654 }
1655
Geoff Lang69cce582015-09-17 13:20:36 -04001656 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001657 {
Geoff Langb1196682014-07-23 13:47:29 -04001658 context->recordError(Error(GL_INVALID_OPERATION));
1659 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001660 }
1661
Geoff Lang5d601382014-07-22 15:14:06 -04001662 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1663
1664 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001665 {
Geoff Langb1196682014-07-23 13:47:29 -04001666 context->recordError(Error(GL_INVALID_OPERATION));
1667 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001668 }
1669
Geoff Langa9be0dc2014-12-17 12:34:40 -05001670 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001671 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001672 context->recordError(Error(GL_INVALID_OPERATION));
1673 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001674 }
1675
1676 if (isSubImage)
1677 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001678 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1679 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1680 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001681 {
Geoff Langb1196682014-07-23 13:47:29 -04001682 context->recordError(Error(GL_INVALID_VALUE));
1683 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001684 }
1685 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001686 else
1687 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001688 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001689 {
Geoff Langb1196682014-07-23 13:47:29 -04001690 context->recordError(Error(GL_INVALID_VALUE));
1691 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001692 }
1693
Geoff Lang5d601382014-07-22 15:14:06 -04001694 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001695 {
Geoff Langb1196682014-07-23 13:47:29 -04001696 context->recordError(Error(GL_INVALID_ENUM));
1697 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001698 }
1699
1700 int maxLevelDimension = (maxDimension >> level);
1701 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1702 {
Geoff Langb1196682014-07-23 13:47:29 -04001703 context->recordError(Error(GL_INVALID_VALUE));
1704 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001705 }
1706 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001707
Geoff Langa9be0dc2014-12-17 12:34:40 -05001708 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001709 return true;
1710}
1711
Jamie Madillf25855c2015-11-03 11:06:18 -05001712static bool ValidateDrawBase(ValidationContext *context,
1713 GLenum mode,
1714 GLsizei count,
1715 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001716{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001717 switch (mode)
1718 {
1719 case GL_POINTS:
1720 case GL_LINES:
1721 case GL_LINE_LOOP:
1722 case GL_LINE_STRIP:
1723 case GL_TRIANGLES:
1724 case GL_TRIANGLE_STRIP:
1725 case GL_TRIANGLE_FAN:
1726 break;
1727 default:
Geoff Langb1196682014-07-23 13:47:29 -04001728 context->recordError(Error(GL_INVALID_ENUM));
1729 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001730 }
1731
Jamie Madill250d33f2014-06-06 17:09:03 -04001732 if (count < 0)
1733 {
Geoff Langb1196682014-07-23 13:47:29 -04001734 context->recordError(Error(GL_INVALID_VALUE));
1735 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001736 }
1737
Geoff Langb1196682014-07-23 13:47:29 -04001738 const State &state = context->getState();
1739
Jamie Madill250d33f2014-06-06 17:09:03 -04001740 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001741 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001742 {
Geoff Langb1196682014-07-23 13:47:29 -04001743 context->recordError(Error(GL_INVALID_OPERATION));
1744 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001745 }
1746
Geoff Lang3a86ad32015-09-01 11:47:05 -04001747 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001748 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001749 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1750 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1751 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1752 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1753 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1754 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1755 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001756 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001757 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1758 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001759 {
1760 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1761 // Section 6.10 of the WebGL 1.0 spec
1762 ERR(
1763 "This ANGLE implementation does not support separate front/back stencil "
1764 "writemasks, reference values, or stencil mask values.");
1765 context->recordError(Error(GL_INVALID_OPERATION));
1766 return false;
1767 }
Jamie Madillac528012014-06-20 13:21:23 -04001768 }
1769
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001770 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001771 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001772 {
Geoff Langb1196682014-07-23 13:47:29 -04001773 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1774 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001775 }
1776
Geoff Lang7dd2e102014-11-10 15:19:26 -05001777 gl::Program *program = state.getProgram();
1778 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001779 {
Geoff Langb1196682014-07-23 13:47:29 -04001780 context->recordError(Error(GL_INVALID_OPERATION));
1781 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001782 }
1783
Geoff Lang7dd2e102014-11-10 15:19:26 -05001784 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001785 {
Geoff Langb1196682014-07-23 13:47:29 -04001786 context->recordError(Error(GL_INVALID_OPERATION));
1787 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001788 }
1789
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001790 // Uniform buffer validation
1791 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1792 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001793 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001794 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001795 const OffsetBindingPointer<Buffer> &uniformBuffer =
1796 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001797
Geoff Lang5d124a62015-09-15 13:03:27 -04001798 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001799 {
1800 // undefined behaviour
1801 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1802 return false;
1803 }
1804
Geoff Lang5d124a62015-09-15 13:03:27 -04001805 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001806 if (uniformBufferSize == 0)
1807 {
1808 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001809 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001810 }
1811
Jamie Madill62d31cb2015-09-11 13:25:51 -04001812 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001813 {
1814 // undefined behaviour
1815 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1816 return false;
1817 }
1818 }
1819
Jamie Madill250d33f2014-06-06 17:09:03 -04001820 // No-op if zero count
1821 return (count > 0);
1822}
1823
Geoff Langb1196682014-07-23 13:47:29 -04001824bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001825{
Jamie Madillfd716582014-06-06 17:09:04 -04001826 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001827 {
Geoff Langb1196682014-07-23 13:47:29 -04001828 context->recordError(Error(GL_INVALID_VALUE));
1829 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001830 }
1831
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001832 const State &state = context->getState();
1833 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001834 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1835 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001836 {
1837 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1838 // that does not match the current transform feedback object's draw mode (if transform feedback
1839 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001840 context->recordError(Error(GL_INVALID_OPERATION));
1841 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001842 }
1843
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001844 if (!ValidateDrawBase(context, mode, count, primcount))
1845 {
1846 return false;
1847 }
1848
1849 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001850 {
1851 return false;
1852 }
1853
1854 return true;
1855}
1856
Geoff Langb1196682014-07-23 13:47:29 -04001857bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001858{
1859 if (primcount < 0)
1860 {
Geoff Langb1196682014-07-23 13:47:29 -04001861 context->recordError(Error(GL_INVALID_VALUE));
1862 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001863 }
1864
Jamie Madill2b976812014-08-25 15:47:49 -04001865 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001866 {
1867 return false;
1868 }
1869
1870 // No-op if zero primitive count
1871 return (primcount > 0);
1872}
1873
Geoff Lang87a93302014-09-16 13:29:43 -04001874static bool ValidateDrawInstancedANGLE(Context *context)
1875{
1876 // Verify there is at least one active attribute with a divisor of zero
1877 const gl::State& state = context->getState();
1878
Geoff Lang7dd2e102014-11-10 15:19:26 -05001879 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001880
1881 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001882 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001883 {
1884 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001885 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001886 {
1887 return true;
1888 }
1889 }
1890
1891 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1892 "has a divisor of zero."));
1893 return false;
1894}
1895
1896bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1897{
1898 if (!ValidateDrawInstancedANGLE(context))
1899 {
1900 return false;
1901 }
1902
1903 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1904}
1905
Jamie Madillf25855c2015-11-03 11:06:18 -05001906bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001907 GLenum mode,
1908 GLsizei count,
1909 GLenum type,
1910 const GLvoid *indices,
1911 GLsizei primcount,
1912 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001913{
Jamie Madill250d33f2014-06-06 17:09:03 -04001914 switch (type)
1915 {
1916 case GL_UNSIGNED_BYTE:
1917 case GL_UNSIGNED_SHORT:
1918 break;
1919 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001920 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001921 {
Geoff Langb1196682014-07-23 13:47:29 -04001922 context->recordError(Error(GL_INVALID_ENUM));
1923 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001924 }
1925 break;
1926 default:
Geoff Langb1196682014-07-23 13:47:29 -04001927 context->recordError(Error(GL_INVALID_ENUM));
1928 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001929 }
1930
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001931 const State &state = context->getState();
1932
1933 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001934 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001935 {
1936 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1937 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001938 context->recordError(Error(GL_INVALID_OPERATION));
1939 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001940 }
1941
1942 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001943 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001944 {
Geoff Langb1196682014-07-23 13:47:29 -04001945 context->recordError(Error(GL_INVALID_OPERATION));
1946 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001947 }
1948
Jamie Madill2b976812014-08-25 15:47:49 -04001949 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001950 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001951 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001952 {
Geoff Langb1196682014-07-23 13:47:29 -04001953 context->recordError(Error(GL_INVALID_OPERATION));
1954 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001955 }
1956
Jamie Madillae3000b2014-08-25 15:47:51 -04001957 if (elementArrayBuffer)
1958 {
1959 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1960
1961 GLint64 offset = reinterpret_cast<GLint64>(indices);
1962 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1963
1964 // check for integer overflows
1965 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1966 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1967 {
Geoff Langb1196682014-07-23 13:47:29 -04001968 context->recordError(Error(GL_OUT_OF_MEMORY));
1969 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001970 }
1971
1972 // Check for reading past the end of the bound buffer object
1973 if (byteCount > elementArrayBuffer->getSize())
1974 {
Geoff Langb1196682014-07-23 13:47:29 -04001975 context->recordError(Error(GL_INVALID_OPERATION));
1976 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001977 }
1978 }
1979 else if (!indices)
1980 {
1981 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001982 context->recordError(Error(GL_INVALID_OPERATION));
1983 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001984 }
1985
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001986 if (!ValidateDrawBase(context, mode, count, primcount))
1987 {
1988 return false;
1989 }
1990
Jamie Madill2b976812014-08-25 15:47:49 -04001991 // Use max index to validate if our vertex buffers are large enough for the pull.
1992 // TODO: offer fast path, with disabled index validation.
1993 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1994 if (elementArrayBuffer)
1995 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001996 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001997 Error error =
1998 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1999 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002000 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002001 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04002002 context->recordError(error);
2003 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002004 }
2005 }
2006 else
2007 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002008 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002009 }
2010
Jamie Madille79b1e12015-11-04 16:36:37 -05002011 // If we use an index greater than our maximum supported index range, return an error.
2012 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2013 // return an error if possible here.
2014 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2015 {
2016 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
2017 return false;
2018 }
2019
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002020 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04002021 {
2022 return false;
2023 }
2024
Geoff Lang3edfe032015-09-04 16:38:24 -04002025 // No op if there are no real indices in the index data (all are primitive restart).
2026 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002027}
2028
Geoff Langb1196682014-07-23 13:47:29 -04002029bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002030 GLenum mode,
2031 GLsizei count,
2032 GLenum type,
2033 const GLvoid *indices,
2034 GLsizei primcount,
2035 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002036{
2037 if (primcount < 0)
2038 {
Geoff Langb1196682014-07-23 13:47:29 -04002039 context->recordError(Error(GL_INVALID_VALUE));
2040 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002041 }
2042
Jamie Madill2b976812014-08-25 15:47:49 -04002043 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002044 {
2045 return false;
2046 }
2047
2048 // No-op zero primitive count
2049 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002050}
2051
Geoff Lang3edfe032015-09-04 16:38:24 -04002052bool ValidateDrawElementsInstancedANGLE(Context *context,
2053 GLenum mode,
2054 GLsizei count,
2055 GLenum type,
2056 const GLvoid *indices,
2057 GLsizei primcount,
2058 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002059{
2060 if (!ValidateDrawInstancedANGLE(context))
2061 {
2062 return false;
2063 }
2064
2065 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2066}
2067
Geoff Langb1196682014-07-23 13:47:29 -04002068bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002069 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002070{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002071 if (!ValidFramebufferTarget(target))
2072 {
Geoff Langb1196682014-07-23 13:47:29 -04002073 context->recordError(Error(GL_INVALID_ENUM));
2074 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002075 }
2076
2077 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002078 {
2079 return false;
2080 }
2081
Jamie Madill55ec3b12014-07-03 10:38:57 -04002082 if (texture != 0)
2083 {
2084 gl::Texture *tex = context->getTexture(texture);
2085
2086 if (tex == NULL)
2087 {
Geoff Langb1196682014-07-23 13:47:29 -04002088 context->recordError(Error(GL_INVALID_OPERATION));
2089 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002090 }
2091
2092 if (level < 0)
2093 {
Geoff Langb1196682014-07-23 13:47:29 -04002094 context->recordError(Error(GL_INVALID_VALUE));
2095 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002096 }
2097 }
2098
Shannon Woods53a94a82014-06-24 15:20:36 -04002099 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002100 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002101
Jamie Madill84115c92015-04-23 15:00:07 -04002102 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002103 {
Jamie Madill84115c92015-04-23 15:00:07 -04002104 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002105 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002106 }
2107
2108 return true;
2109}
2110
Geoff Langb1196682014-07-23 13:47:29 -04002111bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002112 GLenum textarget, GLuint texture, GLint level)
2113{
Geoff Lang95663912015-04-02 15:54:45 -04002114 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2115 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
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
2121 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002122 {
2123 return false;
2124 }
2125
Jamie Madill55ec3b12014-07-03 10:38:57 -04002126 if (texture != 0)
2127 {
2128 gl::Texture *tex = context->getTexture(texture);
2129 ASSERT(tex);
2130
Jamie Madill2a6564e2014-07-11 09:53:19 -04002131 const gl::Caps &caps = context->getCaps();
2132
Jamie Madill55ec3b12014-07-03 10:38:57 -04002133 switch (textarget)
2134 {
2135 case GL_TEXTURE_2D:
2136 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002137 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002138 {
Geoff Langb1196682014-07-23 13:47:29 -04002139 context->recordError(Error(GL_INVALID_VALUE));
2140 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002141 }
2142 if (tex->getTarget() != GL_TEXTURE_2D)
2143 {
Geoff Langb1196682014-07-23 13:47:29 -04002144 context->recordError(Error(GL_INVALID_OPERATION));
2145 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002146 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002147 }
2148 break;
2149
2150 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2151 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2152 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2153 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2154 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2155 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2156 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002157 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002158 {
Geoff Langb1196682014-07-23 13:47:29 -04002159 context->recordError(Error(GL_INVALID_VALUE));
2160 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002161 }
2162 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2163 {
Geoff Langb1196682014-07-23 13:47:29 -04002164 context->recordError(Error(GL_INVALID_OPERATION));
2165 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002166 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002167 }
2168 break;
2169
2170 default:
Geoff Langb1196682014-07-23 13:47:29 -04002171 context->recordError(Error(GL_INVALID_ENUM));
2172 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002173 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002174
2175 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2176 if (internalFormatInfo.compressed)
2177 {
2178 context->recordError(Error(GL_INVALID_OPERATION));
2179 return false;
2180 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002181 }
2182
Jamie Madill570f7c82014-07-03 10:38:54 -04002183 return true;
2184}
2185
Geoff Langb1196682014-07-23 13:47:29 -04002186bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002187{
2188 if (program == 0)
2189 {
Geoff Langb1196682014-07-23 13:47:29 -04002190 context->recordError(Error(GL_INVALID_VALUE));
2191 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002192 }
2193
Dian Xiang769769a2015-09-09 15:20:08 -07002194 gl::Program *programObject = GetValidProgram(context, program);
2195 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002196 {
2197 return false;
2198 }
2199
Jamie Madill0063c512014-08-25 15:47:53 -04002200 if (!programObject || !programObject->isLinked())
2201 {
Geoff Langb1196682014-07-23 13:47:29 -04002202 context->recordError(Error(GL_INVALID_OPERATION));
2203 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002204 }
2205
Geoff Lang7dd2e102014-11-10 15:19:26 -05002206 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002207 {
Geoff Langb1196682014-07-23 13:47:29 -04002208 context->recordError(Error(GL_INVALID_OPERATION));
2209 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002210 }
2211
Jamie Madill0063c512014-08-25 15:47:53 -04002212 return true;
2213}
2214
Geoff Langb1196682014-07-23 13:47:29 -04002215bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002216{
2217 return ValidateGetUniformBase(context, program, location);
2218}
2219
Geoff Langb1196682014-07-23 13:47:29 -04002220bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002221{
Jamie Madill78f41802014-08-25 15:47:55 -04002222 return ValidateGetUniformBase(context, program, location);
2223}
2224
Geoff Langb1196682014-07-23 13:47:29 -04002225static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002226{
2227 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002228 {
Jamie Madill78f41802014-08-25 15:47:55 -04002229 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002230 }
2231
Jamie Madilla502c742014-08-28 17:19:13 -04002232 gl::Program *programObject = context->getProgram(program);
2233 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002234
Jamie Madill78f41802014-08-25 15:47:55 -04002235 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002236 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2237 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002238 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002239 {
Geoff Langb1196682014-07-23 13:47:29 -04002240 context->recordError(Error(GL_INVALID_OPERATION));
2241 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002242 }
2243
2244 return true;
2245}
2246
Geoff Langb1196682014-07-23 13:47:29 -04002247bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002248{
Jamie Madill78f41802014-08-25 15:47:55 -04002249 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002250}
2251
Geoff Langb1196682014-07-23 13:47:29 -04002252bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002253{
Jamie Madill78f41802014-08-25 15:47:55 -04002254 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002255}
2256
Austin Kinross08332632015-05-05 13:35:47 -07002257bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2258 const GLenum *attachments, bool defaultFramebuffer)
2259{
2260 if (numAttachments < 0)
2261 {
2262 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2263 return false;
2264 }
2265
2266 for (GLsizei i = 0; i < numAttachments; ++i)
2267 {
2268 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2269 {
2270 if (defaultFramebuffer)
2271 {
2272 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2273 return false;
2274 }
2275
2276 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2277 {
2278 context->recordError(Error(GL_INVALID_OPERATION,
2279 "Requested color attachment is greater than the maximum supported color attachments"));
2280 return false;
2281 }
2282 }
2283 else
2284 {
2285 switch (attachments[i])
2286 {
2287 case GL_DEPTH_ATTACHMENT:
2288 case GL_STENCIL_ATTACHMENT:
2289 case GL_DEPTH_STENCIL_ATTACHMENT:
2290 if (defaultFramebuffer)
2291 {
2292 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2293 return false;
2294 }
2295 break;
2296 case GL_COLOR:
2297 case GL_DEPTH:
2298 case GL_STENCIL:
2299 if (!defaultFramebuffer)
2300 {
2301 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2302 return false;
2303 }
2304 break;
2305 default:
2306 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2307 return false;
2308 }
2309 }
2310 }
2311
2312 return true;
2313}
2314
Austin Kinross6ee1e782015-05-29 17:05:37 -07002315bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2316{
2317 // Note that debug marker calls must not set error state
2318
2319 if (length < 0)
2320 {
2321 return false;
2322 }
2323
2324 if (marker == nullptr)
2325 {
2326 return false;
2327 }
2328
2329 return true;
2330}
2331
2332bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2333{
2334 // Note that debug marker calls must not set error state
2335
2336 if (length < 0)
2337 {
2338 return false;
2339 }
2340
2341 if (length > 0 && marker == nullptr)
2342 {
2343 return false;
2344 }
2345
2346 return true;
2347}
2348
Geoff Langdcab33b2015-07-21 13:03:16 -04002349bool ValidateEGLImageTargetTexture2DOES(Context *context,
2350 egl::Display *display,
2351 GLenum target,
2352 egl::Image *image)
2353{
Geoff Langa8406172015-07-21 16:53:39 -04002354 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2355 {
2356 context->recordError(Error(GL_INVALID_OPERATION));
2357 return false;
2358 }
2359
2360 switch (target)
2361 {
2362 case GL_TEXTURE_2D:
2363 break;
2364
2365 default:
2366 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2367 return false;
2368 }
2369
2370 if (!display->isValidImage(image))
2371 {
2372 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2373 return false;
2374 }
2375
2376 if (image->getSamples() > 0)
2377 {
2378 context->recordError(Error(GL_INVALID_OPERATION,
2379 "cannot create a 2D texture from a multisampled EGL image."));
2380 return false;
2381 }
2382
2383 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2384 if (!textureCaps.texturable)
2385 {
2386 context->recordError(Error(GL_INVALID_OPERATION,
2387 "EGL image internal format is not supported as a texture."));
2388 return false;
2389 }
2390
Geoff Langdcab33b2015-07-21 13:03:16 -04002391 return true;
2392}
2393
2394bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2395 egl::Display *display,
2396 GLenum target,
2397 egl::Image *image)
2398{
Geoff Langa8406172015-07-21 16:53:39 -04002399 if (!context->getExtensions().eglImage)
2400 {
2401 context->recordError(Error(GL_INVALID_OPERATION));
2402 return false;
2403 }
2404
2405 switch (target)
2406 {
2407 case GL_RENDERBUFFER:
2408 break;
2409
2410 default:
2411 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2412 return false;
2413 }
2414
2415 if (!display->isValidImage(image))
2416 {
2417 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2418 return false;
2419 }
2420
2421 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2422 if (!textureCaps.renderable)
2423 {
2424 context->recordError(Error(
2425 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2426 return false;
2427 }
2428
Geoff Langdcab33b2015-07-21 13:03:16 -04002429 return true;
2430}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002431
2432bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2433{
Geoff Lang36167ab2015-12-07 10:27:14 -05002434 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002435 {
2436 // The default VAO should always exist
2437 ASSERT(array != 0);
2438 context->recordError(Error(GL_INVALID_OPERATION));
2439 return false;
2440 }
2441
2442 return true;
2443}
2444
2445bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2446{
2447 if (n < 0)
2448 {
2449 context->recordError(Error(GL_INVALID_VALUE));
2450 return false;
2451 }
2452
2453 return true;
2454}
2455
2456bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2457{
2458 if (n < 0)
2459 {
2460 context->recordError(Error(GL_INVALID_VALUE));
2461 return false;
2462 }
2463
2464 return true;
2465}
Geoff Langc5629752015-12-07 16:29:04 -05002466
2467bool ValidateProgramBinaryBase(Context *context,
2468 GLuint program,
2469 GLenum binaryFormat,
2470 const void *binary,
2471 GLint length)
2472{
2473 Program *programObject = GetValidProgram(context, program);
2474 if (programObject == nullptr)
2475 {
2476 return false;
2477 }
2478
2479 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2480 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2481 programBinaryFormats.end())
2482 {
2483 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2484 return false;
2485 }
2486
2487 return true;
2488}
2489
2490bool ValidateGetProgramBinaryBase(Context *context,
2491 GLuint program,
2492 GLsizei bufSize,
2493 GLsizei *length,
2494 GLenum *binaryFormat,
2495 void *binary)
2496{
2497 Program *programObject = GetValidProgram(context, program);
2498 if (programObject == nullptr)
2499 {
2500 return false;
2501 }
2502
2503 if (!programObject->isLinked())
2504 {
2505 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2506 return false;
2507 }
2508
2509 return true;
2510}
Jamie Madillc29968b2016-01-20 11:17:23 -05002511
2512bool ValidateCopyTexImage2D(ValidationContext *context,
2513 GLenum target,
2514 GLint level,
2515 GLenum internalformat,
2516 GLint x,
2517 GLint y,
2518 GLsizei width,
2519 GLsizei height,
2520 GLint border)
2521{
2522 if (context->getClientVersion() < 3)
2523 {
2524 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2525 0, x, y, width, height, border);
2526 }
2527
2528 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002529 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2530 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002531}
Jamie Madillc29968b2016-01-20 11:17:23 -05002532
2533bool ValidateFramebufferRenderbuffer(Context *context,
2534 GLenum target,
2535 GLenum attachment,
2536 GLenum renderbuffertarget,
2537 GLuint renderbuffer)
2538{
2539 if (!ValidFramebufferTarget(target) ||
2540 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2541 {
2542 context->recordError(Error(GL_INVALID_ENUM));
2543 return false;
2544 }
2545
2546 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2547 renderbuffertarget, renderbuffer);
2548}
2549
2550bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2551{
2552 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2553 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2554 {
2555 context->recordError(
2556 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2557 return false;
2558 }
2559
2560 ASSERT(context->getState().getDrawFramebuffer());
2561 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2562 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2563
2564 // This should come first before the check for the default frame buffer
2565 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2566 // rather than INVALID_OPERATION
2567 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2568 {
2569 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2570
2571 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
2572 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
2573 bufs[colorAttachment] >= maxColorAttachment))
2574 {
2575 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
2576 // In the 3.0 specs, the error should return GL_INVALID_OPERATION.
2577 // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
2578 context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
2579 return false;
2580 }
2581 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2582 frameBufferId != 0)
2583 {
2584 // INVALID_OPERATION-GL is bound to buffer and ith argument
2585 // is not COLOR_ATTACHMENTi or NONE
2586 context->recordError(
2587 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2588 return false;
2589 }
2590 }
2591
2592 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2593 // and n is not 1 or bufs is bound to value other than BACK and NONE
2594 if (frameBufferId == 0)
2595 {
2596 if (n != 1)
2597 {
2598 context->recordError(Error(GL_INVALID_OPERATION,
2599 "n must be 1 when GL is bound to the default framebuffer"));
2600 return false;
2601 }
2602
2603 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2604 {
2605 context->recordError(Error(
2606 GL_INVALID_OPERATION,
2607 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2608 return false;
2609 }
2610 }
2611
2612 return true;
2613}
2614
2615bool ValidateCopyTexSubImage2D(Context *context,
2616 GLenum target,
2617 GLint level,
2618 GLint xoffset,
2619 GLint yoffset,
2620 GLint x,
2621 GLint y,
2622 GLsizei width,
2623 GLsizei height)
2624{
2625 if (context->getClientVersion() < 3)
2626 {
2627 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2628 yoffset, x, y, width, height, 0);
2629 }
2630
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002631 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2632 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002633}
2634
2635} // namespace gl