blob: 0a14d12eeb915d9b52e8746c87358c5af12d6dbd [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:
337 return true;
338
339 default:
340 return false;
341 }
342}
343
Jamie Madillc29968b2016-01-20 11:17:23 -0500344bool ValidCompressedImageSize(const ValidationContext *context,
345 GLenum internalFormat,
346 GLsizei width,
347 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400348{
Geoff Lang5d601382014-07-22 15:14:06 -0400349 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
350 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400351 {
352 return false;
353 }
354
Geoff Lang0d8b7242015-09-09 14:56:53 -0400355 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400356 {
357 return false;
358 }
359
Geoff Lang0d8b7242015-09-09 14:56:53 -0400360 if (CompressedTextureFormatRequiresExactSize(internalFormat))
361 {
362 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
363 width % formatInfo.compressedBlockWidth != 0) ||
364 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
365 height % formatInfo.compressedBlockHeight != 0))
366 {
367 return false;
368 }
369 }
370
Geoff Langd4f180b2013-09-24 13:57:44 -0400371 return true;
372}
373
Geoff Lang37dde692014-01-31 16:34:54 -0500374bool ValidQueryType(const Context *context, GLenum queryType)
375{
Geoff Langd4475812015-03-18 10:53:05 -0400376 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
377 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 -0500378
379 switch (queryType)
380 {
381 case GL_ANY_SAMPLES_PASSED:
382 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
383 return true;
384 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
385 return (context->getClientVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500386 case GL_TIME_ELAPSED_EXT:
387 return context->getExtensions().disjointTimerQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500388 default:
389 return false;
390 }
391}
392
Dian Xiang769769a2015-09-09 15:20:08 -0700393Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500394{
395 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
396 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
397 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
398
Dian Xiang769769a2015-09-09 15:20:08 -0700399 Program *validProgram = context->getProgram(id);
400
401 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500402 {
Dian Xiang769769a2015-09-09 15:20:08 -0700403 if (context->getShader(id))
404 {
405 context->recordError(
406 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
407 }
408 else
409 {
410 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
411 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500412 }
Dian Xiang769769a2015-09-09 15:20:08 -0700413
414 return validProgram;
415}
416
417Shader *GetValidShader(Context *context, GLuint id)
418{
419 // See ValidProgram for spec details.
420
421 Shader *validShader = context->getShader(id);
422
423 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500424 {
Dian Xiang769769a2015-09-09 15:20:08 -0700425 if (context->getProgram(id))
426 {
427 context->recordError(
428 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
429 }
430 else
431 {
432 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
433 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500434 }
Dian Xiang769769a2015-09-09 15:20:08 -0700435
436 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500437}
438
Geoff Langb1196682014-07-23 13:47:29 -0400439bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400440{
441 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
442 {
443 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
444
Geoff Langaae65a42014-05-26 12:43:44 -0400445 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400446 {
Geoff Langb1196682014-07-23 13:47:29 -0400447 context->recordError(Error(GL_INVALID_VALUE));
448 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400449 }
450 }
451 else
452 {
453 switch (attachment)
454 {
455 case GL_DEPTH_ATTACHMENT:
456 case GL_STENCIL_ATTACHMENT:
457 break;
458
459 case GL_DEPTH_STENCIL_ATTACHMENT:
460 if (context->getClientVersion() < 3)
461 {
Geoff Langb1196682014-07-23 13:47:29 -0400462 context->recordError(Error(GL_INVALID_ENUM));
463 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400464 }
465 break;
466
467 default:
Geoff Langb1196682014-07-23 13:47:29 -0400468 context->recordError(Error(GL_INVALID_ENUM));
469 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400470 }
471 }
472
473 return true;
474}
475
Corentin Walleze0902642014-11-04 12:32:15 -0800476bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
477 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400478{
479 switch (target)
480 {
481 case GL_RENDERBUFFER:
482 break;
483 default:
Geoff Langb1196682014-07-23 13:47:29 -0400484 context->recordError(Error(GL_INVALID_ENUM));
485 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400486 }
487
488 if (width < 0 || height < 0 || samples < 0)
489 {
Geoff Langb1196682014-07-23 13:47:29 -0400490 context->recordError(Error(GL_INVALID_VALUE));
491 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400492 }
493
Geoff Langd87878e2014-09-19 15:42:59 -0400494 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
495 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400496 {
Geoff Langb1196682014-07-23 13:47:29 -0400497 context->recordError(Error(GL_INVALID_ENUM));
498 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400499 }
500
501 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
502 // 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 -0800503 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400504 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400505 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400506 {
Geoff Langb1196682014-07-23 13:47:29 -0400507 context->recordError(Error(GL_INVALID_ENUM));
508 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400509 }
510
Geoff Langaae65a42014-05-26 12:43:44 -0400511 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400512 {
Geoff Langb1196682014-07-23 13:47:29 -0400513 context->recordError(Error(GL_INVALID_VALUE));
514 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400515 }
516
Shannon Woods53a94a82014-06-24 15:20:36 -0400517 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400518 if (handle == 0)
519 {
Geoff Langb1196682014-07-23 13:47:29 -0400520 context->recordError(Error(GL_INVALID_OPERATION));
521 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 }
523
524 return true;
525}
526
Corentin Walleze0902642014-11-04 12:32:15 -0800527bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
528 GLenum internalformat, GLsizei width, GLsizei height)
529{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800530 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800531
532 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400533 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800534 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400535 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800536 {
537 context->recordError(Error(GL_INVALID_VALUE));
538 return false;
539 }
540
541 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
542 // the specified storage. This is different than ES 3.0 in which a sample number higher
543 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800544 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
545 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800546 {
Geoff Langa4903b72015-03-02 16:02:48 -0800547 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
548 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
549 {
550 context->recordError(Error(GL_OUT_OF_MEMORY));
551 return false;
552 }
Corentin Walleze0902642014-11-04 12:32:15 -0800553 }
554
555 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
556}
557
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500558bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
559 GLenum renderbuffertarget, GLuint renderbuffer)
560{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400561 if (!ValidFramebufferTarget(target))
562 {
Geoff Langb1196682014-07-23 13:47:29 -0400563 context->recordError(Error(GL_INVALID_ENUM));
564 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400565 }
566
Shannon Woods53a94a82014-06-24 15:20:36 -0400567 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500568
Jamie Madill84115c92015-04-23 15:00:07 -0400569 ASSERT(framebuffer);
570 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500571 {
Jamie Madill84115c92015-04-23 15:00:07 -0400572 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400573 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500574 }
575
Jamie Madillb4472272014-07-03 10:38:55 -0400576 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500577 {
Jamie Madillb4472272014-07-03 10:38:55 -0400578 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500579 }
580
Jamie Madillab9d82c2014-01-21 16:38:14 -0500581 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
582 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
583 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
584 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
585 if (renderbuffer != 0)
586 {
587 if (!context->getRenderbuffer(renderbuffer))
588 {
Geoff Langb1196682014-07-23 13:47:29 -0400589 context->recordError(Error(GL_INVALID_OPERATION));
590 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500591 }
592 }
593
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500594 return true;
595}
596
Jamie Madillc29968b2016-01-20 11:17:23 -0500597bool ValidateBlitFramebufferParameters(gl::Context *context,
598 GLint srcX0,
599 GLint srcY0,
600 GLint srcX1,
601 GLint srcY1,
602 GLint dstX0,
603 GLint dstY0,
604 GLint dstX1,
605 GLint dstY1,
606 GLbitfield mask,
607 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400608{
609 switch (filter)
610 {
611 case GL_NEAREST:
612 break;
613 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400614 break;
615 default:
Geoff Langb1196682014-07-23 13:47:29 -0400616 context->recordError(Error(GL_INVALID_ENUM));
617 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400618 }
619
620 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
621 {
Geoff Langb1196682014-07-23 13:47:29 -0400622 context->recordError(Error(GL_INVALID_VALUE));
623 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624 }
625
626 if (mask == 0)
627 {
628 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
629 // buffers are copied.
630 return false;
631 }
632
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400633 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
634 // color buffer, leaving only nearest being unfiltered from above
635 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
636 {
Geoff Langb1196682014-07-23 13:47:29 -0400637 context->recordError(Error(GL_INVALID_OPERATION));
638 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639 }
640
Shannon Woods53a94a82014-06-24 15:20:36 -0400641 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400642 {
Geoff Langb1196682014-07-23 13:47:29 -0400643 context->recordError(Error(GL_INVALID_OPERATION));
644 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645 }
646
Jamie Madille3ef7152015-04-28 16:55:17 +0000647 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
648 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500649
650 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400651 {
Geoff Langb1196682014-07-23 13:47:29 -0400652 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
653 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400654 }
655
Geoff Lang748f74e2014-12-01 11:25:34 -0500656 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500657 {
658 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
659 return false;
660 }
661
Geoff Lang748f74e2014-12-01 11:25:34 -0500662 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500663 {
664 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
665 return false;
666 }
667
668 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400669 {
Geoff Langb1196682014-07-23 13:47:29 -0400670 context->recordError(Error(GL_INVALID_OPERATION));
671 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 }
673
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400674 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
675
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400676 if (mask & GL_COLOR_BUFFER_BIT)
677 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400678 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
679 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500680 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400681
682 if (readColorBuffer && drawColorBuffer)
683 {
Geoff Langd8a22582014-12-17 15:28:23 -0500684 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400685 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400686
Geoff Langa15472a2015-08-11 11:48:03 -0400687 for (size_t drawbufferIdx = 0;
688 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400689 {
Geoff Langa15472a2015-08-11 11:48:03 -0400690 const FramebufferAttachment *attachment =
691 drawFramebuffer->getDrawBuffer(drawbufferIdx);
692 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 {
Geoff Langa15472a2015-08-11 11:48:03 -0400694 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400695 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696
Geoff Langb2f3d052013-08-13 12:49:27 -0400697 // The GL ES 3.0.2 spec (pg 193) states that:
698 // 1) If the read buffer is fixed point format, the draw buffer must be as well
699 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
700 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500701 // Changes with EXT_color_buffer_float:
702 // Case 1) is changed to fixed point OR floating point
703 GLenum readComponentType = readFormatInfo.componentType;
704 GLenum drawComponentType = drawFormatInfo.componentType;
705 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
706 readComponentType == GL_SIGNED_NORMALIZED);
707 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
708 drawComponentType == GL_SIGNED_NORMALIZED);
709
710 if (extensions.colorBufferFloat)
711 {
712 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
713 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
714
715 if (readFixedOrFloat != drawFixedOrFloat)
716 {
717 context->recordError(Error(GL_INVALID_OPERATION,
718 "If the read buffer contains fixed-point or "
719 "floating-point values, the draw buffer "
720 "must as well."));
721 return false;
722 }
723 }
724 else if (readFixedPoint != drawFixedPoint)
725 {
726 context->recordError(Error(GL_INVALID_OPERATION,
727 "If the read buffer contains fixed-point "
728 "values, the draw buffer must as well."));
729 return false;
730 }
731
732 if (readComponentType == GL_UNSIGNED_INT &&
733 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400734 {
Geoff Langb1196682014-07-23 13:47:29 -0400735 context->recordError(Error(GL_INVALID_OPERATION));
736 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400737 }
738
Jamie Madill6163c752015-12-07 16:32:59 -0500739 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400740 {
Geoff Langb1196682014-07-23 13:47:29 -0400741 context->recordError(Error(GL_INVALID_OPERATION));
742 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400743 }
744
Geoff Langb2f3d052013-08-13 12:49:27 -0400745 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400746 {
Geoff Langb1196682014-07-23 13:47:29 -0400747 context->recordError(Error(GL_INVALID_OPERATION));
748 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400749 }
750 }
751 }
752
Geoff Lang5d601382014-07-22 15:14:06 -0400753 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754 {
Geoff Langb1196682014-07-23 13:47:29 -0400755 context->recordError(Error(GL_INVALID_OPERATION));
756 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400757 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400758 }
759 }
760
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200761 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
762 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
763 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200765 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400766 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400767 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
768 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400769
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200770 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 {
Geoff Langd8a22582014-12-17 15:28:23 -0500772 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773 {
Geoff Langb1196682014-07-23 13:47:29 -0400774 context->recordError(Error(GL_INVALID_OPERATION));
775 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400776 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200778 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400779 {
Geoff Langb1196682014-07-23 13:47:29 -0400780 context->recordError(Error(GL_INVALID_OPERATION));
781 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400782 }
783 }
784 }
785 }
786
787 return true;
788}
789
Geoff Langb1196682014-07-23 13:47:29 -0400790bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791{
792 switch (pname)
793 {
794 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
795 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
796 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
797 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
798 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
799 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
800 case GL_CURRENT_VERTEX_ATTRIB:
801 return true;
802
803 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
804 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
805 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400806 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
807 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400808 return true;
809
810 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400811 if (context->getClientVersion() < 3)
812 {
813 context->recordError(Error(GL_INVALID_ENUM));
814 return false;
815 }
816 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400817
818 default:
Geoff Langb1196682014-07-23 13:47:29 -0400819 context->recordError(Error(GL_INVALID_ENUM));
820 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400821 }
822}
823
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400824bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400825{
826 switch (pname)
827 {
828 case GL_TEXTURE_WRAP_R:
829 case GL_TEXTURE_SWIZZLE_R:
830 case GL_TEXTURE_SWIZZLE_G:
831 case GL_TEXTURE_SWIZZLE_B:
832 case GL_TEXTURE_SWIZZLE_A:
833 case GL_TEXTURE_BASE_LEVEL:
834 case GL_TEXTURE_MAX_LEVEL:
835 case GL_TEXTURE_COMPARE_MODE:
836 case GL_TEXTURE_COMPARE_FUNC:
837 case GL_TEXTURE_MIN_LOD:
838 case GL_TEXTURE_MAX_LOD:
839 if (context->getClientVersion() < 3)
840 {
Geoff Langb1196682014-07-23 13:47:29 -0400841 context->recordError(Error(GL_INVALID_ENUM));
842 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400843 }
844 break;
845
846 default: break;
847 }
848
849 switch (pname)
850 {
851 case GL_TEXTURE_WRAP_S:
852 case GL_TEXTURE_WRAP_T:
853 case GL_TEXTURE_WRAP_R:
854 switch (param)
855 {
856 case GL_REPEAT:
857 case GL_CLAMP_TO_EDGE:
858 case GL_MIRRORED_REPEAT:
859 return true;
860 default:
Geoff Langb1196682014-07-23 13:47:29 -0400861 context->recordError(Error(GL_INVALID_ENUM));
862 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400863 }
864
865 case GL_TEXTURE_MIN_FILTER:
866 switch (param)
867 {
868 case GL_NEAREST:
869 case GL_LINEAR:
870 case GL_NEAREST_MIPMAP_NEAREST:
871 case GL_LINEAR_MIPMAP_NEAREST:
872 case GL_NEAREST_MIPMAP_LINEAR:
873 case GL_LINEAR_MIPMAP_LINEAR:
874 return true;
875 default:
Geoff Langb1196682014-07-23 13:47:29 -0400876 context->recordError(Error(GL_INVALID_ENUM));
877 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400878 }
879 break;
880
881 case GL_TEXTURE_MAG_FILTER:
882 switch (param)
883 {
884 case GL_NEAREST:
885 case GL_LINEAR:
886 return true;
887 default:
Geoff Langb1196682014-07-23 13:47:29 -0400888 context->recordError(Error(GL_INVALID_ENUM));
889 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400890 }
891 break;
892
893 case GL_TEXTURE_USAGE_ANGLE:
894 switch (param)
895 {
896 case GL_NONE:
897 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
898 return true;
899 default:
Geoff Langb1196682014-07-23 13:47:29 -0400900 context->recordError(Error(GL_INVALID_ENUM));
901 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400902 }
903 break;
904
905 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400906 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400907 {
Geoff Langb1196682014-07-23 13:47:29 -0400908 context->recordError(Error(GL_INVALID_ENUM));
909 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400910 }
911
912 // we assume the parameter passed to this validation method is truncated, not rounded
913 if (param < 1)
914 {
Geoff Langb1196682014-07-23 13:47:29 -0400915 context->recordError(Error(GL_INVALID_VALUE));
916 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400917 }
918 return true;
919
920 case GL_TEXTURE_MIN_LOD:
921 case GL_TEXTURE_MAX_LOD:
922 // any value is permissible
923 return true;
924
925 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400926 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400927 switch (param)
928 {
929 case GL_NONE:
930 case GL_COMPARE_REF_TO_TEXTURE:
931 return true;
932 default:
Geoff Langb1196682014-07-23 13:47:29 -0400933 context->recordError(Error(GL_INVALID_ENUM));
934 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400935 }
936 break;
937
938 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400939 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400940 switch (param)
941 {
942 case GL_LEQUAL:
943 case GL_GEQUAL:
944 case GL_LESS:
945 case GL_GREATER:
946 case GL_EQUAL:
947 case GL_NOTEQUAL:
948 case GL_ALWAYS:
949 case GL_NEVER:
950 return true;
951 default:
Geoff Langb1196682014-07-23 13:47:29 -0400952 context->recordError(Error(GL_INVALID_ENUM));
953 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400954 }
955 break;
956
957 case GL_TEXTURE_SWIZZLE_R:
958 case GL_TEXTURE_SWIZZLE_G:
959 case GL_TEXTURE_SWIZZLE_B:
960 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400961 switch (param)
962 {
963 case GL_RED:
964 case GL_GREEN:
965 case GL_BLUE:
966 case GL_ALPHA:
967 case GL_ZERO:
968 case GL_ONE:
969 return true;
970 default:
Geoff Langb1196682014-07-23 13:47:29 -0400971 context->recordError(Error(GL_INVALID_ENUM));
972 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400973 }
974 break;
975
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400976 case GL_TEXTURE_BASE_LEVEL:
977 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400978 if (param < 0)
979 {
Geoff Langb1196682014-07-23 13:47:29 -0400980 context->recordError(Error(GL_INVALID_VALUE));
981 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400982 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400983 return true;
984
985 default:
Geoff Langb1196682014-07-23 13:47:29 -0400986 context->recordError(Error(GL_INVALID_ENUM));
987 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400988 }
989}
990
Geoff Langb1196682014-07-23 13:47:29 -0400991bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400992{
993 switch (pname)
994 {
995 case GL_TEXTURE_MIN_FILTER:
996 case GL_TEXTURE_MAG_FILTER:
997 case GL_TEXTURE_WRAP_S:
998 case GL_TEXTURE_WRAP_T:
999 case GL_TEXTURE_WRAP_R:
1000 case GL_TEXTURE_MIN_LOD:
1001 case GL_TEXTURE_MAX_LOD:
1002 case GL_TEXTURE_COMPARE_MODE:
1003 case GL_TEXTURE_COMPARE_FUNC:
1004 return true;
1005
1006 default:
Geoff Langb1196682014-07-23 13:47:29 -04001007 context->recordError(Error(GL_INVALID_ENUM));
1008 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001009 }
1010}
1011
Jamie Madillc29968b2016-01-20 11:17:23 -05001012bool ValidateReadPixels(Context *context,
1013 GLint x,
1014 GLint y,
1015 GLsizei width,
1016 GLsizei height,
1017 GLenum format,
1018 GLenum type,
1019 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001020{
Jamie Madillc29968b2016-01-20 11:17:23 -05001021 if (width < 0 || height < 0)
1022 {
1023 context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
1024 return false;
1025 }
1026
1027 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001028 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001029
Geoff Lang748f74e2014-12-01 11:25:34 -05001030 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001031 {
Geoff Langb1196682014-07-23 13:47:29 -04001032 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1033 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001034 }
1035
Jamie Madill48faf802014-11-06 15:27:22 -05001036 if (context->getState().getReadFramebuffer()->id() != 0 &&
1037 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001038 {
Geoff Langb1196682014-07-23 13:47:29 -04001039 context->recordError(Error(GL_INVALID_OPERATION));
1040 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001041 }
1042
Geoff Langbce529e2014-12-01 12:48:41 -05001043 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1044 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001045 {
Geoff Langb1196682014-07-23 13:47:29 -04001046 context->recordError(Error(GL_INVALID_OPERATION));
1047 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001048 }
1049
Geoff Langbce529e2014-12-01 12:48:41 -05001050 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1051 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001052 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001053 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001054
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001055 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1056 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001057
1058 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1059 {
Geoff Langb1196682014-07-23 13:47:29 -04001060 context->recordError(Error(GL_INVALID_OPERATION));
1061 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001062 }
1063
Jamie Madillc29968b2016-01-20 11:17:23 -05001064 return true;
1065}
1066
1067bool ValidateReadnPixelsEXT(Context *context,
1068 GLint x,
1069 GLint y,
1070 GLsizei width,
1071 GLsizei height,
1072 GLenum format,
1073 GLenum type,
1074 GLsizei bufSize,
1075 GLvoid *pixels)
1076{
1077 if (bufSize < 0)
1078 {
1079 context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
1080 return false;
1081 }
1082
Geoff Lang5d601382014-07-22 15:14:06 -04001083 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1084 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001085
Minmin Gongadff67b2015-10-14 10:34:45 -04001086 GLsizei outputPitch =
1087 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1088 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001089 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001090 int requiredSize = outputPitch * height;
1091 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001092 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001093 context->recordError(Error(GL_INVALID_OPERATION));
1094 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001095 }
1096
Jamie Madillc29968b2016-01-20 11:17:23 -05001097 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001098}
1099
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001100bool ValidateGenQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
1101{
1102 if (n < 0)
1103 {
1104 context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
1105 return false;
1106 }
1107
1108 return true;
1109}
1110
1111bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
1112{
1113 if (!context->getExtensions().occlusionQueryBoolean &&
1114 !context->getExtensions().disjointTimerQuery)
1115 {
1116 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1117 return false;
1118 }
1119
1120 return ValidateGenQueriesBase(context, n, ids);
1121}
1122
1123bool ValidateDeleteQueriesBase(gl::Context *context, GLsizei n, const GLuint *ids)
1124{
1125 if (n < 0)
1126 {
1127 context->recordError(Error(GL_INVALID_VALUE, "Query count < 0"));
1128 return false;
1129 }
1130
1131 return true;
1132}
1133
1134bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n, const GLuint *ids)
1135{
1136 if (!context->getExtensions().occlusionQueryBoolean &&
1137 !context->getExtensions().disjointTimerQuery)
1138 {
1139 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1140 return false;
1141 }
1142
1143 return ValidateDeleteQueriesBase(context, n, ids);
1144}
1145
1146bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001147{
1148 if (!ValidQueryType(context, target))
1149 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001150 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001151 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001152 }
1153
1154 if (id == 0)
1155 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001156 context->recordError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001157 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001158 }
1159
1160 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1161 // of zero, if the active query object name for <target> is non-zero (for the
1162 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1163 // the active query for either target is non-zero), if <id> is the name of an
1164 // existing query object whose type does not match <target>, or if <id> is the
1165 // active query object name for any query type, the error INVALID_OPERATION is
1166 // generated.
1167
1168 // Ensure no other queries are active
1169 // NOTE: If other queries than occlusion are supported, we will need to check
1170 // separately that:
1171 // a) The query ID passed is not the current active query for any target/type
1172 // b) There are no active queries for the requested target (and in the case
1173 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1174 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001175
1176 // TODO(ewell): I think this needs to be changed for timer and occlusion queries to work at the
1177 // same time
Shannon Woods53a94a82014-06-24 15:20:36 -04001178 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001179 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001180 context->recordError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001181 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001182 }
1183
1184 Query *queryObject = context->getQuery(id, true, target);
1185
1186 // check that name was obtained with glGenQueries
1187 if (!queryObject)
1188 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001189 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001190 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001191 }
1192
1193 // check for type mismatch
1194 if (queryObject->getType() != target)
1195 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001196 context->recordError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001197 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001198 }
1199
1200 return true;
1201}
1202
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001203bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1204{
1205 if (!context->getExtensions().occlusionQueryBoolean &&
1206 !context->getExtensions().disjointTimerQuery)
1207 {
1208 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1209 return false;
1210 }
1211
1212 return ValidateBeginQueryBase(context, target, id);
1213}
1214
1215bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001216{
1217 if (!ValidQueryType(context, target))
1218 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001219 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001220 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001221 }
1222
Shannon Woods53a94a82014-06-24 15:20:36 -04001223 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001224
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001225 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001226 {
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001227 context->recordError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001228 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001229 }
1230
Jamie Madill45c785d2014-05-13 14:09:34 -04001231 return true;
1232}
1233
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001234bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1235{
1236 if (!context->getExtensions().occlusionQueryBoolean &&
1237 !context->getExtensions().disjointTimerQuery)
1238 {
1239 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1240 return false;
1241 }
1242
1243 return ValidateEndQueryBase(context, target);
1244}
1245
1246bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1247{
1248 if (!context->getExtensions().disjointTimerQuery)
1249 {
1250 context->recordError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
1251 return false;
1252 }
1253
1254 if (target != GL_TIMESTAMP_EXT)
1255 {
1256 context->recordError(Error(GL_INVALID_ENUM, "Invalid query target"));
1257 return false;
1258 }
1259
1260 Query *queryObject = context->getQuery(id, true, target);
1261 if (queryObject == nullptr)
1262 {
1263 context->recordError(Error(GL_INVALID_OPERATION, "Invalid query id"));
1264 return false;
1265 }
1266
1267 if (context->getState().isQueryActive(queryObject))
1268 {
1269 context->recordError(Error(GL_INVALID_OPERATION, "Query is active"));
1270 return false;
1271 }
1272
1273 return true;
1274}
1275
1276bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1277{
1278 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1279 {
1280 context->recordError(Error(GL_INVALID_ENUM, "Invalid query type"));
1281 return false;
1282 }
1283
1284 switch (pname)
1285 {
1286 case GL_CURRENT_QUERY_EXT:
1287 if (target == GL_TIMESTAMP_EXT)
1288 {
1289 context->recordError(
1290 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1291 return false;
1292 }
1293 break;
1294 case GL_QUERY_COUNTER_BITS_EXT:
1295 if (!context->getExtensions().disjointTimerQuery ||
1296 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1297 {
1298 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1299 return false;
1300 }
1301 break;
1302 default:
1303 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname"));
1304 return false;
1305 }
1306
1307 return true;
1308}
1309
1310bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1311{
1312 if (!context->getExtensions().occlusionQueryBoolean &&
1313 !context->getExtensions().disjointTimerQuery)
1314 {
1315 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1316 return false;
1317 }
1318
1319 return ValidateGetQueryivBase(context, target, pname);
1320}
1321
1322bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1323{
1324 Query *queryObject = context->getQuery(id, false, GL_NONE);
1325
1326 if (!queryObject)
1327 {
1328 context->recordError(Error(GL_INVALID_OPERATION, "Query does not exist"));
1329 return false;
1330 }
1331
1332 if (context->getState().isQueryActive(queryObject))
1333 {
1334 context->recordError(Error(GL_INVALID_OPERATION, "Query currently active"));
1335 return false;
1336 }
1337
1338 switch (pname)
1339 {
1340 case GL_QUERY_RESULT_EXT:
1341 case GL_QUERY_RESULT_AVAILABLE_EXT:
1342 break;
1343
1344 default:
1345 context->recordError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
1346 return false;
1347 }
1348
1349 return true;
1350}
1351
1352bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1353{
1354 if (!context->getExtensions().disjointTimerQuery)
1355 {
1356 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1357 return false;
1358 }
1359 return ValidateGetQueryObjectValueBase(context, id, pname);
1360}
1361
1362bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1363{
1364 if (!context->getExtensions().disjointTimerQuery &&
1365 !context->getExtensions().occlusionQueryBoolean)
1366 {
1367 context->recordError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
1368 return false;
1369 }
1370 return ValidateGetQueryObjectValueBase(context, id, pname);
1371}
1372
1373bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1374{
1375 if (!context->getExtensions().disjointTimerQuery)
1376 {
1377 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1378 return false;
1379 }
1380 return ValidateGetQueryObjectValueBase(context, id, pname);
1381}
1382
1383bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1384{
1385 if (!context->getExtensions().disjointTimerQuery)
1386 {
1387 context->recordError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
1388 return false;
1389 }
1390 return ValidateGetQueryObjectValueBase(context, id, pname);
1391}
1392
Jamie Madill62d31cb2015-09-11 13:25:51 -04001393static bool ValidateUniformCommonBase(gl::Context *context,
1394 GLenum targetUniformType,
1395 GLint location,
1396 GLsizei count,
1397 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001398{
1399 if (count < 0)
1400 {
Geoff Langb1196682014-07-23 13:47:29 -04001401 context->recordError(Error(GL_INVALID_VALUE));
1402 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001403 }
1404
Geoff Lang7dd2e102014-11-10 15:19:26 -05001405 gl::Program *program = context->getState().getProgram();
1406 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001407 {
Geoff Langb1196682014-07-23 13:47:29 -04001408 context->recordError(Error(GL_INVALID_OPERATION));
1409 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001410 }
1411
1412 if (location == -1)
1413 {
1414 // Silently ignore the uniform command
1415 return false;
1416 }
1417
Geoff Lang7dd2e102014-11-10 15:19:26 -05001418 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001419 {
Geoff Langb1196682014-07-23 13:47:29 -04001420 context->recordError(Error(GL_INVALID_OPERATION));
1421 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001422 }
1423
Jamie Madill62d31cb2015-09-11 13:25:51 -04001424 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001425
1426 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001427 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001428 {
Geoff Langb1196682014-07-23 13:47:29 -04001429 context->recordError(Error(GL_INVALID_OPERATION));
1430 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001431 }
1432
Jamie Madill62d31cb2015-09-11 13:25:51 -04001433 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001434 return true;
1435}
1436
Jamie Madillaa981bd2014-05-20 10:55:55 -04001437bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1438{
1439 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001440 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001441 {
Geoff Langb1196682014-07-23 13:47:29 -04001442 context->recordError(Error(GL_INVALID_OPERATION));
1443 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001444 }
1445
Jamie Madill62d31cb2015-09-11 13:25:51 -04001446 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001447 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1448 {
1449 return false;
1450 }
1451
Jamie Madillf2575982014-06-25 16:04:54 -04001452 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001453 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001454 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1455 {
Geoff Langb1196682014-07-23 13:47:29 -04001456 context->recordError(Error(GL_INVALID_OPERATION));
1457 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001458 }
1459
1460 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001461}
1462
1463bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1464 GLboolean transpose)
1465{
1466 // Check for ES3 uniform entry points
1467 int rows = VariableRowCount(matrixType);
1468 int cols = VariableColumnCount(matrixType);
1469 if (rows != cols && context->getClientVersion() < 3)
1470 {
Geoff Langb1196682014-07-23 13:47:29 -04001471 context->recordError(Error(GL_INVALID_OPERATION));
1472 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001473 }
1474
1475 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1476 {
Geoff Langb1196682014-07-23 13:47:29 -04001477 context->recordError(Error(GL_INVALID_VALUE));
1478 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001479 }
1480
Jamie Madill62d31cb2015-09-11 13:25:51 -04001481 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001482 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1483 {
1484 return false;
1485 }
1486
1487 if (uniform->type != matrixType)
1488 {
Geoff Langb1196682014-07-23 13:47:29 -04001489 context->recordError(Error(GL_INVALID_OPERATION));
1490 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001491 }
1492
1493 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001494}
1495
Jamie Madill893ab082014-05-16 16:56:10 -04001496bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1497{
1498 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1499 {
Geoff Langb1196682014-07-23 13:47:29 -04001500 context->recordError(Error(GL_INVALID_ENUM));
1501 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001502 }
1503
Jamie Madill0af26e12015-03-05 19:54:33 -05001504 const Caps &caps = context->getCaps();
1505
Jamie Madill893ab082014-05-16 16:56:10 -04001506 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1507 {
1508 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1509
Jamie Madill0af26e12015-03-05 19:54:33 -05001510 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001511 {
Geoff Langb1196682014-07-23 13:47:29 -04001512 context->recordError(Error(GL_INVALID_OPERATION));
1513 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001514 }
1515 }
1516
1517 switch (pname)
1518 {
1519 case GL_TEXTURE_BINDING_2D:
1520 case GL_TEXTURE_BINDING_CUBE_MAP:
1521 case GL_TEXTURE_BINDING_3D:
1522 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001523 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001524 {
Geoff Langb1196682014-07-23 13:47:29 -04001525 context->recordError(Error(GL_INVALID_OPERATION));
1526 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001527 }
1528 break;
1529
1530 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1531 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1532 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001533 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001534 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001535 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001536 {
Geoff Langb1196682014-07-23 13:47:29 -04001537 context->recordError(Error(GL_INVALID_OPERATION));
1538 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001539 }
1540
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001541 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001542 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001543 {
Geoff Langb1196682014-07-23 13:47:29 -04001544 context->recordError(Error(GL_INVALID_OPERATION));
1545 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001546 }
1547 }
1548 break;
1549
1550 default:
1551 break;
1552 }
1553
1554 // pname is valid, but there are no parameters to return
1555 if (numParams == 0)
1556 {
1557 return false;
1558 }
1559
1560 return true;
1561}
1562
Jamie Madillc29968b2016-01-20 11:17:23 -05001563bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1564 GLenum target,
1565 GLint level,
1566 GLenum internalformat,
1567 bool isSubImage,
1568 GLint xoffset,
1569 GLint yoffset,
1570 GLint zoffset,
1571 GLint x,
1572 GLint y,
1573 GLsizei width,
1574 GLsizei height,
1575 GLint border,
1576 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001577{
Jamie Madill560a8d82014-05-21 13:06:20 -04001578 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1579 {
Geoff Langb1196682014-07-23 13:47:29 -04001580 context->recordError(Error(GL_INVALID_VALUE));
1581 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001582 }
1583
1584 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1585 {
Geoff Langb1196682014-07-23 13:47:29 -04001586 context->recordError(Error(GL_INVALID_VALUE));
1587 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001588 }
1589
1590 if (border != 0)
1591 {
Geoff Langb1196682014-07-23 13:47:29 -04001592 context->recordError(Error(GL_INVALID_VALUE));
1593 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001594 }
1595
1596 if (!ValidMipLevel(context, target, level))
1597 {
Geoff Langb1196682014-07-23 13:47:29 -04001598 context->recordError(Error(GL_INVALID_VALUE));
1599 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001600 }
1601
Jamie Madillc29968b2016-01-20 11:17:23 -05001602 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001603 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001604 {
Geoff Langb1196682014-07-23 13:47:29 -04001605 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1606 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001607 }
1608
Jamie Madillc29968b2016-01-20 11:17:23 -05001609 const auto &state = context->getState();
1610 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001611 {
Geoff Langb1196682014-07-23 13:47:29 -04001612 context->recordError(Error(GL_INVALID_OPERATION));
1613 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001614 }
1615
Geoff Langaae65a42014-05-26 12:43:44 -04001616 const gl::Caps &caps = context->getCaps();
1617
Geoff Langaae65a42014-05-26 12:43:44 -04001618 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001619 switch (target)
1620 {
1621 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001622 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001623 break;
1624
1625 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1626 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1627 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1628 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1629 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1630 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001631 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001632 break;
1633
1634 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001635 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001636 break;
1637
1638 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001639 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001640 break;
1641
1642 default:
Geoff Langb1196682014-07-23 13:47:29 -04001643 context->recordError(Error(GL_INVALID_ENUM));
1644 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001645 }
1646
Jamie Madillc29968b2016-01-20 11:17:23 -05001647 gl::Texture *texture =
1648 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001649 if (!texture)
1650 {
Geoff Langb1196682014-07-23 13:47:29 -04001651 context->recordError(Error(GL_INVALID_OPERATION));
1652 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001653 }
1654
Geoff Lang69cce582015-09-17 13:20:36 -04001655 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001656 {
Geoff Langb1196682014-07-23 13:47:29 -04001657 context->recordError(Error(GL_INVALID_OPERATION));
1658 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001659 }
1660
Geoff Lang5d601382014-07-22 15:14:06 -04001661 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1662
1663 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001664 {
Geoff Langb1196682014-07-23 13:47:29 -04001665 context->recordError(Error(GL_INVALID_OPERATION));
1666 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001667 }
1668
Geoff Langa9be0dc2014-12-17 12:34:40 -05001669 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001670 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001671 context->recordError(Error(GL_INVALID_OPERATION));
1672 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001673 }
1674
1675 if (isSubImage)
1676 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001677 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1678 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1679 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001680 {
Geoff Langb1196682014-07-23 13:47:29 -04001681 context->recordError(Error(GL_INVALID_VALUE));
1682 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001683 }
1684 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001685 else
1686 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001687 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001688 {
Geoff Langb1196682014-07-23 13:47:29 -04001689 context->recordError(Error(GL_INVALID_VALUE));
1690 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001691 }
1692
Geoff Lang5d601382014-07-22 15:14:06 -04001693 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001694 {
Geoff Langb1196682014-07-23 13:47:29 -04001695 context->recordError(Error(GL_INVALID_ENUM));
1696 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001697 }
1698
1699 int maxLevelDimension = (maxDimension >> level);
1700 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1701 {
Geoff Langb1196682014-07-23 13:47:29 -04001702 context->recordError(Error(GL_INVALID_VALUE));
1703 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001704 }
1705 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001706
Geoff Langa9be0dc2014-12-17 12:34:40 -05001707 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001708 return true;
1709}
1710
Jamie Madillf25855c2015-11-03 11:06:18 -05001711static bool ValidateDrawBase(ValidationContext *context,
1712 GLenum mode,
1713 GLsizei count,
1714 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001715{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001716 switch (mode)
1717 {
1718 case GL_POINTS:
1719 case GL_LINES:
1720 case GL_LINE_LOOP:
1721 case GL_LINE_STRIP:
1722 case GL_TRIANGLES:
1723 case GL_TRIANGLE_STRIP:
1724 case GL_TRIANGLE_FAN:
1725 break;
1726 default:
Geoff Langb1196682014-07-23 13:47:29 -04001727 context->recordError(Error(GL_INVALID_ENUM));
1728 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001729 }
1730
Jamie Madill250d33f2014-06-06 17:09:03 -04001731 if (count < 0)
1732 {
Geoff Langb1196682014-07-23 13:47:29 -04001733 context->recordError(Error(GL_INVALID_VALUE));
1734 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001735 }
1736
Geoff Langb1196682014-07-23 13:47:29 -04001737 const State &state = context->getState();
1738
Jamie Madill250d33f2014-06-06 17:09:03 -04001739 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001740 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001741 {
Geoff Langb1196682014-07-23 13:47:29 -04001742 context->recordError(Error(GL_INVALID_OPERATION));
1743 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001744 }
1745
Geoff Lang3a86ad32015-09-01 11:47:05 -04001746 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001747 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001748 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1749 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1750 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1751 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1752 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1753 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1754 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001755 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001756 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1757 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001758 {
1759 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1760 // Section 6.10 of the WebGL 1.0 spec
1761 ERR(
1762 "This ANGLE implementation does not support separate front/back stencil "
1763 "writemasks, reference values, or stencil mask values.");
1764 context->recordError(Error(GL_INVALID_OPERATION));
1765 return false;
1766 }
Jamie Madillac528012014-06-20 13:21:23 -04001767 }
1768
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001769 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001770 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001771 {
Geoff Langb1196682014-07-23 13:47:29 -04001772 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1773 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001774 }
1775
Geoff Lang7dd2e102014-11-10 15:19:26 -05001776 gl::Program *program = state.getProgram();
1777 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001778 {
Geoff Langb1196682014-07-23 13:47:29 -04001779 context->recordError(Error(GL_INVALID_OPERATION));
1780 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001781 }
1782
Geoff Lang7dd2e102014-11-10 15:19:26 -05001783 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001784 {
Geoff Langb1196682014-07-23 13:47:29 -04001785 context->recordError(Error(GL_INVALID_OPERATION));
1786 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001787 }
1788
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001789 // Uniform buffer validation
1790 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1791 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001792 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001793 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001794 const OffsetBindingPointer<Buffer> &uniformBuffer =
1795 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001796
Geoff Lang5d124a62015-09-15 13:03:27 -04001797 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001798 {
1799 // undefined behaviour
1800 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1801 return false;
1802 }
1803
Geoff Lang5d124a62015-09-15 13:03:27 -04001804 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001805 if (uniformBufferSize == 0)
1806 {
1807 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001808 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001809 }
1810
Jamie Madill62d31cb2015-09-11 13:25:51 -04001811 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001812 {
1813 // undefined behaviour
1814 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1815 return false;
1816 }
1817 }
1818
Jamie Madill250d33f2014-06-06 17:09:03 -04001819 // No-op if zero count
1820 return (count > 0);
1821}
1822
Geoff Langb1196682014-07-23 13:47:29 -04001823bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001824{
Jamie Madillfd716582014-06-06 17:09:04 -04001825 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001826 {
Geoff Langb1196682014-07-23 13:47:29 -04001827 context->recordError(Error(GL_INVALID_VALUE));
1828 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001829 }
1830
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001831 const State &state = context->getState();
1832 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001833 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1834 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001835 {
1836 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1837 // that does not match the current transform feedback object's draw mode (if transform feedback
1838 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001839 context->recordError(Error(GL_INVALID_OPERATION));
1840 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001841 }
1842
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001843 if (!ValidateDrawBase(context, mode, count, primcount))
1844 {
1845 return false;
1846 }
1847
1848 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001849 {
1850 return false;
1851 }
1852
1853 return true;
1854}
1855
Geoff Langb1196682014-07-23 13:47:29 -04001856bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001857{
1858 if (primcount < 0)
1859 {
Geoff Langb1196682014-07-23 13:47:29 -04001860 context->recordError(Error(GL_INVALID_VALUE));
1861 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001862 }
1863
Jamie Madill2b976812014-08-25 15:47:49 -04001864 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001865 {
1866 return false;
1867 }
1868
1869 // No-op if zero primitive count
1870 return (primcount > 0);
1871}
1872
Geoff Lang87a93302014-09-16 13:29:43 -04001873static bool ValidateDrawInstancedANGLE(Context *context)
1874{
1875 // Verify there is at least one active attribute with a divisor of zero
1876 const gl::State& state = context->getState();
1877
Geoff Lang7dd2e102014-11-10 15:19:26 -05001878 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001879
1880 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001881 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001882 {
1883 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001884 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001885 {
1886 return true;
1887 }
1888 }
1889
1890 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1891 "has a divisor of zero."));
1892 return false;
1893}
1894
1895bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1896{
1897 if (!ValidateDrawInstancedANGLE(context))
1898 {
1899 return false;
1900 }
1901
1902 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1903}
1904
Jamie Madillf25855c2015-11-03 11:06:18 -05001905bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001906 GLenum mode,
1907 GLsizei count,
1908 GLenum type,
1909 const GLvoid *indices,
1910 GLsizei primcount,
1911 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001912{
Jamie Madill250d33f2014-06-06 17:09:03 -04001913 switch (type)
1914 {
1915 case GL_UNSIGNED_BYTE:
1916 case GL_UNSIGNED_SHORT:
1917 break;
1918 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001919 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001920 {
Geoff Langb1196682014-07-23 13:47:29 -04001921 context->recordError(Error(GL_INVALID_ENUM));
1922 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001923 }
1924 break;
1925 default:
Geoff Langb1196682014-07-23 13:47:29 -04001926 context->recordError(Error(GL_INVALID_ENUM));
1927 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001928 }
1929
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001930 const State &state = context->getState();
1931
1932 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001933 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001934 {
1935 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1936 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001937 context->recordError(Error(GL_INVALID_OPERATION));
1938 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001939 }
1940
1941 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001942 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001943 {
Geoff Langb1196682014-07-23 13:47:29 -04001944 context->recordError(Error(GL_INVALID_OPERATION));
1945 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001946 }
1947
Jamie Madill2b976812014-08-25 15:47:49 -04001948 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001949 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001950 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001951 {
Geoff Langb1196682014-07-23 13:47:29 -04001952 context->recordError(Error(GL_INVALID_OPERATION));
1953 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001954 }
1955
Jamie Madillae3000b2014-08-25 15:47:51 -04001956 if (elementArrayBuffer)
1957 {
1958 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1959
1960 GLint64 offset = reinterpret_cast<GLint64>(indices);
1961 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1962
1963 // check for integer overflows
1964 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1965 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1966 {
Geoff Langb1196682014-07-23 13:47:29 -04001967 context->recordError(Error(GL_OUT_OF_MEMORY));
1968 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001969 }
1970
1971 // Check for reading past the end of the bound buffer object
1972 if (byteCount > elementArrayBuffer->getSize())
1973 {
Geoff Langb1196682014-07-23 13:47:29 -04001974 context->recordError(Error(GL_INVALID_OPERATION));
1975 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001976 }
1977 }
1978 else if (!indices)
1979 {
1980 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001981 context->recordError(Error(GL_INVALID_OPERATION));
1982 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001983 }
1984
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001985 if (!ValidateDrawBase(context, mode, count, primcount))
1986 {
1987 return false;
1988 }
1989
Jamie Madill2b976812014-08-25 15:47:49 -04001990 // Use max index to validate if our vertex buffers are large enough for the pull.
1991 // TODO: offer fast path, with disabled index validation.
1992 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1993 if (elementArrayBuffer)
1994 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001995 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001996 Error error =
1997 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1998 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001999 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002000 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04002001 context->recordError(error);
2002 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002003 }
2004 }
2005 else
2006 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002007 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002008 }
2009
Jamie Madille79b1e12015-11-04 16:36:37 -05002010 // If we use an index greater than our maximum supported index range, return an error.
2011 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2012 // return an error if possible here.
2013 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2014 {
2015 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
2016 return false;
2017 }
2018
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002019 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04002020 {
2021 return false;
2022 }
2023
Geoff Lang3edfe032015-09-04 16:38:24 -04002024 // No op if there are no real indices in the index data (all are primitive restart).
2025 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002026}
2027
Geoff Langb1196682014-07-23 13:47:29 -04002028bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002029 GLenum mode,
2030 GLsizei count,
2031 GLenum type,
2032 const GLvoid *indices,
2033 GLsizei primcount,
2034 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002035{
2036 if (primcount < 0)
2037 {
Geoff Langb1196682014-07-23 13:47:29 -04002038 context->recordError(Error(GL_INVALID_VALUE));
2039 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002040 }
2041
Jamie Madill2b976812014-08-25 15:47:49 -04002042 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002043 {
2044 return false;
2045 }
2046
2047 // No-op zero primitive count
2048 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002049}
2050
Geoff Lang3edfe032015-09-04 16:38:24 -04002051bool ValidateDrawElementsInstancedANGLE(Context *context,
2052 GLenum mode,
2053 GLsizei count,
2054 GLenum type,
2055 const GLvoid *indices,
2056 GLsizei primcount,
2057 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002058{
2059 if (!ValidateDrawInstancedANGLE(context))
2060 {
2061 return false;
2062 }
2063
2064 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2065}
2066
Geoff Langb1196682014-07-23 13:47:29 -04002067bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002068 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002069{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002070 if (!ValidFramebufferTarget(target))
2071 {
Geoff Langb1196682014-07-23 13:47:29 -04002072 context->recordError(Error(GL_INVALID_ENUM));
2073 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002074 }
2075
2076 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002077 {
2078 return false;
2079 }
2080
Jamie Madill55ec3b12014-07-03 10:38:57 -04002081 if (texture != 0)
2082 {
2083 gl::Texture *tex = context->getTexture(texture);
2084
2085 if (tex == NULL)
2086 {
Geoff Langb1196682014-07-23 13:47:29 -04002087 context->recordError(Error(GL_INVALID_OPERATION));
2088 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002089 }
2090
2091 if (level < 0)
2092 {
Geoff Langb1196682014-07-23 13:47:29 -04002093 context->recordError(Error(GL_INVALID_VALUE));
2094 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002095 }
2096 }
2097
Shannon Woods53a94a82014-06-24 15:20:36 -04002098 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002099 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002100
Jamie Madill84115c92015-04-23 15:00:07 -04002101 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002102 {
Jamie Madill84115c92015-04-23 15:00:07 -04002103 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002104 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002105 }
2106
2107 return true;
2108}
2109
Geoff Langb1196682014-07-23 13:47:29 -04002110bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002111 GLenum textarget, GLuint texture, GLint level)
2112{
Geoff Lang95663912015-04-02 15:54:45 -04002113 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
2114 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002115 {
Geoff Langb1196682014-07-23 13:47:29 -04002116 context->recordError(Error(GL_INVALID_VALUE));
2117 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002118 }
2119
2120 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002121 {
2122 return false;
2123 }
2124
Jamie Madill55ec3b12014-07-03 10:38:57 -04002125 if (texture != 0)
2126 {
2127 gl::Texture *tex = context->getTexture(texture);
2128 ASSERT(tex);
2129
Jamie Madill2a6564e2014-07-11 09:53:19 -04002130 const gl::Caps &caps = context->getCaps();
2131
Jamie Madill55ec3b12014-07-03 10:38:57 -04002132 switch (textarget)
2133 {
2134 case GL_TEXTURE_2D:
2135 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002136 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002137 {
Geoff Langb1196682014-07-23 13:47:29 -04002138 context->recordError(Error(GL_INVALID_VALUE));
2139 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002140 }
2141 if (tex->getTarget() != GL_TEXTURE_2D)
2142 {
Geoff Langb1196682014-07-23 13:47:29 -04002143 context->recordError(Error(GL_INVALID_OPERATION));
2144 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002145 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002146 }
2147 break;
2148
2149 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2150 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2151 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2152 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2153 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2154 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2155 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002156 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002157 {
Geoff Langb1196682014-07-23 13:47:29 -04002158 context->recordError(Error(GL_INVALID_VALUE));
2159 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002160 }
2161 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2162 {
Geoff Langb1196682014-07-23 13:47:29 -04002163 context->recordError(Error(GL_INVALID_OPERATION));
2164 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002165 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002166 }
2167 break;
2168
2169 default:
Geoff Langb1196682014-07-23 13:47:29 -04002170 context->recordError(Error(GL_INVALID_ENUM));
2171 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002172 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002173
2174 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
2175 if (internalFormatInfo.compressed)
2176 {
2177 context->recordError(Error(GL_INVALID_OPERATION));
2178 return false;
2179 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002180 }
2181
Jamie Madill570f7c82014-07-03 10:38:54 -04002182 return true;
2183}
2184
Geoff Langb1196682014-07-23 13:47:29 -04002185bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002186{
2187 if (program == 0)
2188 {
Geoff Langb1196682014-07-23 13:47:29 -04002189 context->recordError(Error(GL_INVALID_VALUE));
2190 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002191 }
2192
Dian Xiang769769a2015-09-09 15:20:08 -07002193 gl::Program *programObject = GetValidProgram(context, program);
2194 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002195 {
2196 return false;
2197 }
2198
Jamie Madill0063c512014-08-25 15:47:53 -04002199 if (!programObject || !programObject->isLinked())
2200 {
Geoff Langb1196682014-07-23 13:47:29 -04002201 context->recordError(Error(GL_INVALID_OPERATION));
2202 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002203 }
2204
Geoff Lang7dd2e102014-11-10 15:19:26 -05002205 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002206 {
Geoff Langb1196682014-07-23 13:47:29 -04002207 context->recordError(Error(GL_INVALID_OPERATION));
2208 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002209 }
2210
Jamie Madill0063c512014-08-25 15:47:53 -04002211 return true;
2212}
2213
Geoff Langb1196682014-07-23 13:47:29 -04002214bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002215{
2216 return ValidateGetUniformBase(context, program, location);
2217}
2218
Geoff Langb1196682014-07-23 13:47:29 -04002219bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002220{
Jamie Madill78f41802014-08-25 15:47:55 -04002221 return ValidateGetUniformBase(context, program, location);
2222}
2223
Geoff Langb1196682014-07-23 13:47:29 -04002224static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002225{
2226 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002227 {
Jamie Madill78f41802014-08-25 15:47:55 -04002228 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002229 }
2230
Jamie Madilla502c742014-08-28 17:19:13 -04002231 gl::Program *programObject = context->getProgram(program);
2232 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002233
Jamie Madill78f41802014-08-25 15:47:55 -04002234 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002235 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2236 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002237 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002238 {
Geoff Langb1196682014-07-23 13:47:29 -04002239 context->recordError(Error(GL_INVALID_OPERATION));
2240 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002241 }
2242
2243 return true;
2244}
2245
Geoff Langb1196682014-07-23 13:47:29 -04002246bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002247{
Jamie Madill78f41802014-08-25 15:47:55 -04002248 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002249}
2250
Geoff Langb1196682014-07-23 13:47:29 -04002251bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002252{
Jamie Madill78f41802014-08-25 15:47:55 -04002253 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002254}
2255
Austin Kinross08332632015-05-05 13:35:47 -07002256bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2257 const GLenum *attachments, bool defaultFramebuffer)
2258{
2259 if (numAttachments < 0)
2260 {
2261 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2262 return false;
2263 }
2264
2265 for (GLsizei i = 0; i < numAttachments; ++i)
2266 {
2267 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2268 {
2269 if (defaultFramebuffer)
2270 {
2271 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2272 return false;
2273 }
2274
2275 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2276 {
2277 context->recordError(Error(GL_INVALID_OPERATION,
2278 "Requested color attachment is greater than the maximum supported color attachments"));
2279 return false;
2280 }
2281 }
2282 else
2283 {
2284 switch (attachments[i])
2285 {
2286 case GL_DEPTH_ATTACHMENT:
2287 case GL_STENCIL_ATTACHMENT:
2288 case GL_DEPTH_STENCIL_ATTACHMENT:
2289 if (defaultFramebuffer)
2290 {
2291 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2292 return false;
2293 }
2294 break;
2295 case GL_COLOR:
2296 case GL_DEPTH:
2297 case GL_STENCIL:
2298 if (!defaultFramebuffer)
2299 {
2300 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2301 return false;
2302 }
2303 break;
2304 default:
2305 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2306 return false;
2307 }
2308 }
2309 }
2310
2311 return true;
2312}
2313
Austin Kinross6ee1e782015-05-29 17:05:37 -07002314bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2315{
2316 // Note that debug marker calls must not set error state
2317
2318 if (length < 0)
2319 {
2320 return false;
2321 }
2322
2323 if (marker == nullptr)
2324 {
2325 return false;
2326 }
2327
2328 return true;
2329}
2330
2331bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2332{
2333 // Note that debug marker calls must not set error state
2334
2335 if (length < 0)
2336 {
2337 return false;
2338 }
2339
2340 if (length > 0 && marker == nullptr)
2341 {
2342 return false;
2343 }
2344
2345 return true;
2346}
2347
Geoff Langdcab33b2015-07-21 13:03:16 -04002348bool ValidateEGLImageTargetTexture2DOES(Context *context,
2349 egl::Display *display,
2350 GLenum target,
2351 egl::Image *image)
2352{
Geoff Langa8406172015-07-21 16:53:39 -04002353 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2354 {
2355 context->recordError(Error(GL_INVALID_OPERATION));
2356 return false;
2357 }
2358
2359 switch (target)
2360 {
2361 case GL_TEXTURE_2D:
2362 break;
2363
2364 default:
2365 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2366 return false;
2367 }
2368
2369 if (!display->isValidImage(image))
2370 {
2371 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2372 return false;
2373 }
2374
2375 if (image->getSamples() > 0)
2376 {
2377 context->recordError(Error(GL_INVALID_OPERATION,
2378 "cannot create a 2D texture from a multisampled EGL image."));
2379 return false;
2380 }
2381
2382 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2383 if (!textureCaps.texturable)
2384 {
2385 context->recordError(Error(GL_INVALID_OPERATION,
2386 "EGL image internal format is not supported as a texture."));
2387 return false;
2388 }
2389
Geoff Langdcab33b2015-07-21 13:03:16 -04002390 return true;
2391}
2392
2393bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2394 egl::Display *display,
2395 GLenum target,
2396 egl::Image *image)
2397{
Geoff Langa8406172015-07-21 16:53:39 -04002398 if (!context->getExtensions().eglImage)
2399 {
2400 context->recordError(Error(GL_INVALID_OPERATION));
2401 return false;
2402 }
2403
2404 switch (target)
2405 {
2406 case GL_RENDERBUFFER:
2407 break;
2408
2409 default:
2410 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2411 return false;
2412 }
2413
2414 if (!display->isValidImage(image))
2415 {
2416 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2417 return false;
2418 }
2419
2420 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2421 if (!textureCaps.renderable)
2422 {
2423 context->recordError(Error(
2424 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2425 return false;
2426 }
2427
Geoff Langdcab33b2015-07-21 13:03:16 -04002428 return true;
2429}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002430
2431bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2432{
Geoff Lang36167ab2015-12-07 10:27:14 -05002433 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002434 {
2435 // The default VAO should always exist
2436 ASSERT(array != 0);
2437 context->recordError(Error(GL_INVALID_OPERATION));
2438 return false;
2439 }
2440
2441 return true;
2442}
2443
2444bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2445{
2446 if (n < 0)
2447 {
2448 context->recordError(Error(GL_INVALID_VALUE));
2449 return false;
2450 }
2451
2452 return true;
2453}
2454
2455bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2456{
2457 if (n < 0)
2458 {
2459 context->recordError(Error(GL_INVALID_VALUE));
2460 return false;
2461 }
2462
2463 return true;
2464}
Geoff Langc5629752015-12-07 16:29:04 -05002465
2466bool ValidateProgramBinaryBase(Context *context,
2467 GLuint program,
2468 GLenum binaryFormat,
2469 const void *binary,
2470 GLint length)
2471{
2472 Program *programObject = GetValidProgram(context, program);
2473 if (programObject == nullptr)
2474 {
2475 return false;
2476 }
2477
2478 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2479 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2480 programBinaryFormats.end())
2481 {
2482 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2483 return false;
2484 }
2485
2486 return true;
2487}
2488
2489bool ValidateGetProgramBinaryBase(Context *context,
2490 GLuint program,
2491 GLsizei bufSize,
2492 GLsizei *length,
2493 GLenum *binaryFormat,
2494 void *binary)
2495{
2496 Program *programObject = GetValidProgram(context, program);
2497 if (programObject == nullptr)
2498 {
2499 return false;
2500 }
2501
2502 if (!programObject->isLinked())
2503 {
2504 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2505 return false;
2506 }
2507
2508 return true;
2509}
Jamie Madillc29968b2016-01-20 11:17:23 -05002510
2511bool ValidateCopyTexImage2D(ValidationContext *context,
2512 GLenum target,
2513 GLint level,
2514 GLenum internalformat,
2515 GLint x,
2516 GLint y,
2517 GLsizei width,
2518 GLsizei height,
2519 GLint border)
2520{
2521 if (context->getClientVersion() < 3)
2522 {
2523 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2524 0, x, y, width, height, border);
2525 }
2526
2527 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002528 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2529 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002530}
Jamie Madillc29968b2016-01-20 11:17:23 -05002531
2532bool ValidateFramebufferRenderbuffer(Context *context,
2533 GLenum target,
2534 GLenum attachment,
2535 GLenum renderbuffertarget,
2536 GLuint renderbuffer)
2537{
2538 if (!ValidFramebufferTarget(target) ||
2539 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2540 {
2541 context->recordError(Error(GL_INVALID_ENUM));
2542 return false;
2543 }
2544
2545 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2546 renderbuffertarget, renderbuffer);
2547}
2548
2549bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2550{
2551 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2552 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2553 {
2554 context->recordError(
2555 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2556 return false;
2557 }
2558
2559 ASSERT(context->getState().getDrawFramebuffer());
2560 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2561 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2562
2563 // This should come first before the check for the default frame buffer
2564 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2565 // rather than INVALID_OPERATION
2566 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2567 {
2568 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2569
2570 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
2571 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
2572 bufs[colorAttachment] >= maxColorAttachment))
2573 {
2574 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
2575 // In the 3.0 specs, the error should return GL_INVALID_OPERATION.
2576 // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
2577 context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
2578 return false;
2579 }
2580 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2581 frameBufferId != 0)
2582 {
2583 // INVALID_OPERATION-GL is bound to buffer and ith argument
2584 // is not COLOR_ATTACHMENTi or NONE
2585 context->recordError(
2586 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2587 return false;
2588 }
2589 }
2590
2591 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2592 // and n is not 1 or bufs is bound to value other than BACK and NONE
2593 if (frameBufferId == 0)
2594 {
2595 if (n != 1)
2596 {
2597 context->recordError(Error(GL_INVALID_OPERATION,
2598 "n must be 1 when GL is bound to the default framebuffer"));
2599 return false;
2600 }
2601
2602 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2603 {
2604 context->recordError(Error(
2605 GL_INVALID_OPERATION,
2606 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2607 return false;
2608 }
2609 }
2610
2611 return true;
2612}
2613
2614bool ValidateCopyTexSubImage2D(Context *context,
2615 GLenum target,
2616 GLint level,
2617 GLint xoffset,
2618 GLint yoffset,
2619 GLint x,
2620 GLint y,
2621 GLsizei width,
2622 GLsizei height)
2623{
2624 if (context->getClientVersion() < 3)
2625 {
2626 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2627 yoffset, x, y, width, height, 0);
2628 }
2629
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002630 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2631 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002632}
2633
2634} // namespace gl