1 //
2 // Copyright 2013 The ANGLE Project Authors. All rights reserved.
3 // 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
9 #include "libANGLE/validationES.h"
10
11 #include "libANGLE/Context.h"
12 #include "libANGLE/Display.h"
13 #include "libANGLE/ErrorStrings.h"
14 #include "libANGLE/Framebuffer.h"
15 #include "libANGLE/FramebufferAttachment.h"
16 #include "libANGLE/Image.h"
17 #include "libANGLE/Program.h"
18 #include "libANGLE/Query.h"
19 #include "libANGLE/Texture.h"
20 #include "libANGLE/TransformFeedback.h"
21 #include "libANGLE/angletypes.h"
22 #include "libANGLE/formatutils.h"
23 #include "libANGLE/queryconversions.h"
24 #include "libANGLE/queryutils.h"
25 #include "libANGLE/validationES2.h"
26 #include "libANGLE/validationES3.h"
27
28 #include "common/mathutil.h"
29 #include "common/utilities.h"
30
31 using namespace angle;
32
33 namespace gl
34 {
35 using namespace err;
36
37 namespace
38 {
CompressedTextureFormatRequiresExactSize(GLenum internalFormat)39 bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
40 {
41 // List of compressed format that require that the texture size is smaller than or a multiple of
42 // the compressed block size.
43 switch (internalFormat)
44 {
45 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
46 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
47 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
48 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
49 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
50 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
51 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
52 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
53 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
54 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
55 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
56 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
57 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
58 case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
59 case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
60 case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT:
61 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:
62 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT:
63 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT:
64 return true;
65
66 default:
67 return false;
68 }
69 }
CompressedSubTextureFormatRequiresExactSize(GLenum internalFormat)70 bool CompressedSubTextureFormatRequiresExactSize(GLenum internalFormat)
71 {
72 // Compressed sub textures have additional formats that requires exact size.
73 // ES 3.1, Section 8.7, Page 171
74 return CompressedTextureFormatRequiresExactSize(internalFormat) ||
75 IsETC2EACFormat(internalFormat);
76 }
77
DifferenceCanOverflow(GLint a,GLint b)78 bool DifferenceCanOverflow(GLint a, GLint b)
79 {
80 CheckedNumeric<GLint> checkedA(a);
81 checkedA -= b;
82 // Use negation to make sure that the difference can't overflow regardless of the order.
83 checkedA = -checkedA;
84 return !checkedA.IsValid();
85 }
86
ValidReadPixelsTypeEnum(Context * context,GLenum type)87 bool ValidReadPixelsTypeEnum(Context *context, GLenum type)
88 {
89 switch (type)
90 {
91 // Types referenced in Table 3.4 of the ES 2.0.25 spec
92 case GL_UNSIGNED_BYTE:
93 case GL_UNSIGNED_SHORT_4_4_4_4:
94 case GL_UNSIGNED_SHORT_5_5_5_1:
95 case GL_UNSIGNED_SHORT_5_6_5:
96 return context->getClientVersion() >= ES_2_0;
97
98 // Types referenced in Table 3.2 of the ES 3.0.5 spec (Except depth stencil)
99 case GL_BYTE:
100 case GL_INT:
101 case GL_SHORT:
102 case GL_UNSIGNED_INT:
103 case GL_UNSIGNED_INT_10F_11F_11F_REV:
104 case GL_UNSIGNED_INT_24_8:
105 case GL_UNSIGNED_INT_2_10_10_10_REV:
106 case GL_UNSIGNED_INT_5_9_9_9_REV:
107 case GL_UNSIGNED_SHORT:
108 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
109 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
110 return context->getClientVersion() >= ES_3_0;
111
112 case GL_FLOAT:
113 return context->getClientVersion() >= ES_3_0 || context->getExtensions().textureFloat ||
114 context->getExtensions().colorBufferHalfFloat;
115
116 case GL_HALF_FLOAT:
117 return context->getClientVersion() >= ES_3_0 ||
118 context->getExtensions().textureHalfFloat;
119
120 case GL_HALF_FLOAT_OES:
121 return context->getExtensions().colorBufferHalfFloat;
122
123 default:
124 return false;
125 }
126 }
127
ValidReadPixelsFormatEnum(Context * context,GLenum format)128 bool ValidReadPixelsFormatEnum(Context *context, GLenum format)
129 {
130 switch (format)
131 {
132 // Formats referenced in Table 3.4 of the ES 2.0.25 spec (Except luminance)
133 case GL_RGBA:
134 case GL_RGB:
135 case GL_ALPHA:
136 return context->getClientVersion() >= ES_2_0;
137
138 // Formats referenced in Table 3.2 of the ES 3.0.5 spec
139 case GL_RG:
140 case GL_RED:
141 case GL_RGBA_INTEGER:
142 case GL_RGB_INTEGER:
143 case GL_RG_INTEGER:
144 case GL_RED_INTEGER:
145 return context->getClientVersion() >= ES_3_0;
146
147 case GL_SRGB_ALPHA_EXT:
148 case GL_SRGB_EXT:
149 return context->getExtensions().sRGB;
150
151 case GL_BGRA_EXT:
152 return context->getExtensions().readFormatBGRA;
153
154 default:
155 return false;
156 }
157 }
158
ValidReadPixelsFormatType(Context * context,GLenum framebufferComponentType,GLenum format,GLenum type)159 bool ValidReadPixelsFormatType(Context *context,
160 GLenum framebufferComponentType,
161 GLenum format,
162 GLenum type)
163 {
164 switch (framebufferComponentType)
165 {
166 case GL_UNSIGNED_NORMALIZED:
167 // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
168 // ReadPixels with BGRA even if the extension is not present
169 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) ||
170 (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT &&
171 type == GL_UNSIGNED_BYTE);
172
173 case GL_SIGNED_NORMALIZED:
174 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE);
175
176 case GL_INT:
177 return (format == GL_RGBA_INTEGER && type == GL_INT);
178
179 case GL_UNSIGNED_INT:
180 return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
181
182 case GL_FLOAT:
183 return (format == GL_RGBA && type == GL_FLOAT);
184
185 default:
186 UNREACHABLE();
187 return false;
188 }
189 }
190
191 template <typename ParamType>
ValidateTextureWrapModeValue(Context * context,const ParamType * params,bool restrictedWrapModes)192 bool ValidateTextureWrapModeValue(Context *context,
193 const ParamType *params,
194 bool restrictedWrapModes)
195 {
196 switch (ConvertToGLenum(params[0]))
197 {
198 case GL_CLAMP_TO_EDGE:
199 break;
200
201 case GL_CLAMP_TO_BORDER:
202 if (!context->getExtensions().textureBorderClamp)
203 {
204 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
205 return false;
206 }
207 break;
208
209 case GL_REPEAT:
210 case GL_MIRRORED_REPEAT:
211 if (restrictedWrapModes)
212 {
213 // OES_EGL_image_external and ANGLE_texture_rectangle specifies this error.
214 context->validationError(GL_INVALID_ENUM, kInvalidWrapModeTexture);
215 return false;
216 }
217 break;
218
219 default:
220 context->validationError(GL_INVALID_ENUM, kInvalidTextureWrap);
221 return false;
222 }
223
224 return true;
225 }
226
227 template <typename ParamType>
ValidateTextureMinFilterValue(Context * context,const ParamType * params,bool restrictedMinFilter)228 bool ValidateTextureMinFilterValue(Context *context,
229 const ParamType *params,
230 bool restrictedMinFilter)
231 {
232 switch (ConvertToGLenum(params[0]))
233 {
234 case GL_NEAREST:
235 case GL_LINEAR:
236 break;
237
238 case GL_NEAREST_MIPMAP_NEAREST:
239 case GL_LINEAR_MIPMAP_NEAREST:
240 case GL_NEAREST_MIPMAP_LINEAR:
241 case GL_LINEAR_MIPMAP_LINEAR:
242 if (restrictedMinFilter)
243 {
244 // OES_EGL_image_external specifies this error.
245 context->validationError(GL_INVALID_ENUM, kInvalidFilterTexture);
246 return false;
247 }
248 break;
249
250 default:
251 context->validationError(GL_INVALID_ENUM, kInvalidTextureFilterParam);
252 return false;
253 }
254
255 return true;
256 }
257
258 template <typename ParamType>
ValidateTextureMagFilterValue(Context * context,const ParamType * params)259 bool ValidateTextureMagFilterValue(Context *context, const ParamType *params)
260 {
261 switch (ConvertToGLenum(params[0]))
262 {
263 case GL_NEAREST:
264 case GL_LINEAR:
265 break;
266
267 default:
268 context->validationError(GL_INVALID_ENUM, kInvalidTextureFilterParam);
269 return false;
270 }
271
272 return true;
273 }
274
275 template <typename ParamType>
ValidateTextureCompareModeValue(Context * context,const ParamType * params)276 bool ValidateTextureCompareModeValue(Context *context, const ParamType *params)
277 {
278 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
279 switch (ConvertToGLenum(params[0]))
280 {
281 case GL_NONE:
282 case GL_COMPARE_REF_TO_TEXTURE:
283 break;
284
285 default:
286 context->validationError(GL_INVALID_ENUM, kUnknownParameter);
287 return false;
288 }
289
290 return true;
291 }
292
293 template <typename ParamType>
ValidateTextureCompareFuncValue(Context * context,const ParamType * params)294 bool ValidateTextureCompareFuncValue(Context *context, const ParamType *params)
295 {
296 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
297 switch (ConvertToGLenum(params[0]))
298 {
299 case GL_LEQUAL:
300 case GL_GEQUAL:
301 case GL_LESS:
302 case GL_GREATER:
303 case GL_EQUAL:
304 case GL_NOTEQUAL:
305 case GL_ALWAYS:
306 case GL_NEVER:
307 break;
308
309 default:
310 context->validationError(GL_INVALID_ENUM, kUnknownParameter);
311 return false;
312 }
313
314 return true;
315 }
316
317 template <typename ParamType>
ValidateTextureSRGBDecodeValue(Context * context,const ParamType * params)318 bool ValidateTextureSRGBDecodeValue(Context *context, const ParamType *params)
319 {
320 if (!context->getExtensions().textureSRGBDecode)
321 {
322 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
323 return false;
324 }
325
326 switch (ConvertToGLenum(params[0]))
327 {
328 case GL_DECODE_EXT:
329 case GL_SKIP_DECODE_EXT:
330 break;
331
332 default:
333 context->validationError(GL_INVALID_ENUM, kUnknownParameter);
334 return false;
335 }
336
337 return true;
338 }
339
ValidateTextureMaxAnisotropyExtensionEnabled(Context * context)340 bool ValidateTextureMaxAnisotropyExtensionEnabled(Context *context)
341 {
342 if (!context->getExtensions().textureFilterAnisotropic)
343 {
344 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
345 return false;
346 }
347
348 return true;
349 }
350
ValidateTextureMaxAnisotropyValue(Context * context,GLfloat paramValue)351 bool ValidateTextureMaxAnisotropyValue(Context *context, GLfloat paramValue)
352 {
353 if (!ValidateTextureMaxAnisotropyExtensionEnabled(context))
354 {
355 return false;
356 }
357
358 GLfloat largest = context->getExtensions().maxTextureAnisotropy;
359
360 if (paramValue < 1 || paramValue > largest)
361 {
362 context->validationError(GL_INVALID_VALUE, kOutsideOfBounds);
363 return false;
364 }
365
366 return true;
367 }
368
ValidateFragmentShaderColorBufferMaskMatch(Context * context)369 bool ValidateFragmentShaderColorBufferMaskMatch(Context *context)
370 {
371 const Program *program = context->getState().getLinkedProgram(context);
372 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
373
374 auto drawBufferMask = framebuffer->getDrawBufferMask().to_ulong();
375 auto fragmentOutputMask = program->getActiveOutputVariables().to_ulong();
376
377 return drawBufferMask == (drawBufferMask & fragmentOutputMask);
378 }
379
ValidateFragmentShaderColorBufferTypeMatch(Context * context)380 bool ValidateFragmentShaderColorBufferTypeMatch(Context *context)
381 {
382 const Program *program = context->getState().getLinkedProgram(context);
383 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
384
385 return ValidateComponentTypeMasks(program->getDrawBufferTypeMask().to_ulong(),
386 framebuffer->getDrawBufferTypeMask().to_ulong(),
387 program->getActiveOutputVariables().to_ulong(),
388 framebuffer->getDrawBufferMask().to_ulong());
389 }
390
ValidateVertexShaderAttributeTypeMatch(Context * context)391 bool ValidateVertexShaderAttributeTypeMatch(Context *context)
392 {
393 const auto &glState = context->getState();
394 const Program *program = context->getState().getLinkedProgram(context);
395 const VertexArray *vao = context->getState().getVertexArray();
396
397 unsigned long stateCurrentValuesTypeBits = glState.getCurrentValuesTypeMask().to_ulong();
398 unsigned long vaoAttribTypeBits = vao->getAttributesTypeMask().to_ulong();
399 unsigned long vaoAttribEnabledMask = vao->getAttributesMask().to_ulong();
400
401 vaoAttribEnabledMask |= vaoAttribEnabledMask << kMaxComponentTypeMaskIndex;
402 vaoAttribTypeBits = (vaoAttribEnabledMask & vaoAttribTypeBits);
403 vaoAttribTypeBits |= (~vaoAttribEnabledMask & stateCurrentValuesTypeBits);
404
405 return ValidateComponentTypeMasks(program->getAttributesTypeMask().to_ulong(),
406 vaoAttribTypeBits, program->getAttributesMask().to_ulong(),
407 0xFFFF);
408 }
409
IsCompatibleDrawModeWithGeometryShader(PrimitiveMode drawMode,PrimitiveMode geometryShaderInputPrimitiveType)410 bool IsCompatibleDrawModeWithGeometryShader(PrimitiveMode drawMode,
411 PrimitiveMode geometryShaderInputPrimitiveType)
412 {
413 // [EXT_geometry_shader] Section 11.1gs.1, Geometry Shader Input Primitives
414 switch (drawMode)
415 {
416 case PrimitiveMode::Points:
417 return geometryShaderInputPrimitiveType == PrimitiveMode::Points;
418 case PrimitiveMode::Lines:
419 case PrimitiveMode::LineStrip:
420 case PrimitiveMode::LineLoop:
421 return geometryShaderInputPrimitiveType == PrimitiveMode::Lines;
422 case PrimitiveMode::LinesAdjacency:
423 case PrimitiveMode::LineStripAdjacency:
424 return geometryShaderInputPrimitiveType == PrimitiveMode::LinesAdjacency;
425 case PrimitiveMode::Triangles:
426 case PrimitiveMode::TriangleFan:
427 case PrimitiveMode::TriangleStrip:
428 return geometryShaderInputPrimitiveType == PrimitiveMode::Triangles;
429 case PrimitiveMode::TrianglesAdjacency:
430 case PrimitiveMode::TriangleStripAdjacency:
431 return geometryShaderInputPrimitiveType == PrimitiveMode::TrianglesAdjacency;
432 default:
433 UNREACHABLE();
434 return false;
435 }
436 }
437
438 // GLES1 texture parameters are a small subset of the others
IsValidGLES1TextureParameter(GLenum pname)439 bool IsValidGLES1TextureParameter(GLenum pname)
440 {
441 switch (pname)
442 {
443 case GL_TEXTURE_MAG_FILTER:
444 case GL_TEXTURE_MIN_FILTER:
445 case GL_TEXTURE_WRAP_S:
446 case GL_TEXTURE_WRAP_T:
447 case GL_TEXTURE_WRAP_R:
448 case GL_GENERATE_MIPMAP:
449 case GL_TEXTURE_CROP_RECT_OES:
450 return true;
451 default:
452 return false;
453 }
454 }
455
GetSamplerParameterCount(GLenum pname)456 unsigned int GetSamplerParameterCount(GLenum pname)
457 {
458 return pname == GL_TEXTURE_BORDER_COLOR ? 4 : 1;
459 }
460
461 } // anonymous namespace
462
SetRobustLengthParam(GLsizei * length,GLsizei value)463 void SetRobustLengthParam(GLsizei *length, GLsizei value)
464 {
465 if (length)
466 {
467 *length = value;
468 }
469 }
470
IsETC2EACFormat(const GLenum format)471 bool IsETC2EACFormat(const GLenum format)
472 {
473 // ES 3.1, Table 8.19
474 switch (format)
475 {
476 case GL_COMPRESSED_R11_EAC:
477 case GL_COMPRESSED_SIGNED_R11_EAC:
478 case GL_COMPRESSED_RG11_EAC:
479 case GL_COMPRESSED_SIGNED_RG11_EAC:
480 case GL_COMPRESSED_RGB8_ETC2:
481 case GL_COMPRESSED_SRGB8_ETC2:
482 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
483 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
484 case GL_COMPRESSED_RGBA8_ETC2_EAC:
485 case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
486 return true;
487
488 default:
489 return false;
490 }
491 }
492
ValidTextureTarget(const Context * context,TextureType type)493 bool ValidTextureTarget(const Context *context, TextureType type)
494 {
495 switch (type)
496 {
497 case TextureType::_2D:
498 case TextureType::CubeMap:
499 return true;
500
501 case TextureType::Rectangle:
502 return context->getExtensions().textureRectangle;
503
504 case TextureType::_3D:
505 return ((context->getClientMajorVersion() >= 3) ||
506 context->getExtensions().texture3DOES);
507
508 case TextureType::_2DArray:
509 return (context->getClientMajorVersion() >= 3);
510
511 case TextureType::_2DMultisample:
512 return (context->getClientVersion() >= Version(3, 1) ||
513 context->getExtensions().textureMultisample);
514 case TextureType::_2DMultisampleArray:
515 return context->getExtensions().textureStorageMultisample2DArray;
516
517 default:
518 return false;
519 }
520 }
521
ValidTexture2DTarget(const Context * context,TextureType type)522 bool ValidTexture2DTarget(const Context *context, TextureType type)
523 {
524 switch (type)
525 {
526 case TextureType::_2D:
527 case TextureType::CubeMap:
528 return true;
529
530 case TextureType::Rectangle:
531 return context->getExtensions().textureRectangle;
532
533 default:
534 return false;
535 }
536 }
537
ValidTexture3DTarget(const Context * context,TextureType target)538 bool ValidTexture3DTarget(const Context *context, TextureType target)
539 {
540 switch (target)
541 {
542 case TextureType::_3D:
543 case TextureType::_2DArray:
544 return (context->getClientMajorVersion() >= 3);
545
546 default:
547 return false;
548 }
549 }
550
551 // Most texture GL calls are not compatible with external textures, so we have a separate validation
552 // function for use in the GL calls that do
ValidTextureExternalTarget(const Context * context,TextureType target)553 bool ValidTextureExternalTarget(const Context *context, TextureType target)
554 {
555 return (target == TextureType::External) &&
556 (context->getExtensions().eglImageExternal ||
557 context->getExtensions().eglStreamConsumerExternal);
558 }
559
ValidTextureExternalTarget(const Context * context,TextureTarget target)560 bool ValidTextureExternalTarget(const Context *context, TextureTarget target)
561 {
562 return (target == TextureTarget::External) &&
563 ValidTextureExternalTarget(context, TextureType::External);
564 }
565
566 // This function differs from ValidTextureTarget in that the target must be
567 // usable as the destination of a 2D operation-- so a cube face is valid, but
568 // GL_TEXTURE_CUBE_MAP is not.
569 // Note: duplicate of IsInternalTextureTarget
ValidTexture2DDestinationTarget(const Context * context,TextureTarget target)570 bool ValidTexture2DDestinationTarget(const Context *context, TextureTarget target)
571 {
572 switch (target)
573 {
574 case TextureTarget::_2D:
575 case TextureTarget::CubeMapNegativeX:
576 case TextureTarget::CubeMapNegativeY:
577 case TextureTarget::CubeMapNegativeZ:
578 case TextureTarget::CubeMapPositiveX:
579 case TextureTarget::CubeMapPositiveY:
580 case TextureTarget::CubeMapPositiveZ:
581 return true;
582 case TextureTarget::Rectangle:
583 return context->getExtensions().textureRectangle;
584 default:
585 return false;
586 }
587 }
588
ValidateTransformFeedbackPrimitiveMode(const Context * context,PrimitiveMode transformFeedbackPrimitiveMode,PrimitiveMode renderPrimitiveMode)589 bool ValidateTransformFeedbackPrimitiveMode(const Context *context,
590 PrimitiveMode transformFeedbackPrimitiveMode,
591 PrimitiveMode renderPrimitiveMode)
592 {
593 ASSERT(context);
594
595 if (!context->getExtensions().geometryShader)
596 {
597 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
598 // that does not match the current transform feedback object's draw mode (if transform
599 // feedback is active), (3.0.2, section 2.14, pg 86)
600 return transformFeedbackPrimitiveMode == renderPrimitiveMode;
601 }
602
603 // [GL_EXT_geometry_shader] Table 12.1gs
604 switch (renderPrimitiveMode)
605 {
606 case PrimitiveMode::Points:
607 return transformFeedbackPrimitiveMode == PrimitiveMode::Points;
608 case PrimitiveMode::Lines:
609 case PrimitiveMode::LineStrip:
610 case PrimitiveMode::LineLoop:
611 return transformFeedbackPrimitiveMode == PrimitiveMode::Lines;
612 case PrimitiveMode::Triangles:
613 case PrimitiveMode::TriangleFan:
614 case PrimitiveMode::TriangleStrip:
615 return transformFeedbackPrimitiveMode == PrimitiveMode::Triangles;
616 default:
617 UNREACHABLE();
618 return false;
619 }
620 }
621
ValidateDrawElementsInstancedBase(Context * context,PrimitiveMode mode,GLsizei count,DrawElementsType type,const GLvoid * indices,GLsizei primcount)622 bool ValidateDrawElementsInstancedBase(Context *context,
623 PrimitiveMode mode,
624 GLsizei count,
625 DrawElementsType type,
626 const GLvoid *indices,
627 GLsizei primcount)
628 {
629 if (primcount <= 0)
630 {
631 if (primcount < 0)
632 {
633 context->validationError(GL_INVALID_VALUE, kNegativePrimcount);
634 return false;
635 }
636
637 // Early exit.
638 return ValidateDrawElementsCommon(context, mode, count, type, indices, primcount);
639 }
640
641 if (!ValidateDrawElementsCommon(context, mode, count, type, indices, primcount))
642 {
643 return false;
644 }
645
646 if (count == 0)
647 {
648 // Early exit.
649 return true;
650 }
651
652 return ValidateDrawInstancedAttribs(context, primcount);
653 }
654
ValidateDrawArraysInstancedBase(Context * context,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)655 bool ValidateDrawArraysInstancedBase(Context *context,
656 PrimitiveMode mode,
657 GLint first,
658 GLsizei count,
659 GLsizei primcount)
660 {
661 if (primcount <= 0)
662 {
663 if (primcount < 0)
664 {
665 context->validationError(GL_INVALID_VALUE, kNegativePrimcount);
666 return false;
667 }
668
669 // Early exit.
670 return ValidateDrawArraysCommon(context, mode, first, count, primcount);
671 }
672
673 if (!ValidateDrawArraysCommon(context, mode, first, count, primcount))
674 {
675 return false;
676 }
677
678 if (count == 0)
679 {
680 // Early exit.
681 return true;
682 }
683
684 return ValidateDrawInstancedAttribs(context, primcount);
685 }
686
ValidateDrawInstancedANGLE(Context * context)687 bool ValidateDrawInstancedANGLE(Context *context)
688 {
689 // Verify there is at least one active attribute with a divisor of zero
690 const State &state = context->getState();
691
692 Program *program = state.getLinkedProgram(context);
693
694 const auto &attribs = state.getVertexArray()->getVertexAttributes();
695 const auto &bindings = state.getVertexArray()->getVertexBindings();
696 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
697 {
698 const VertexAttribute &attrib = attribs[attributeIndex];
699 const VertexBinding &binding = bindings[attrib.bindingIndex];
700 if (program->isAttribLocationActive(attributeIndex) && binding.getDivisor() == 0)
701 {
702 return true;
703 }
704 }
705
706 context->validationError(GL_INVALID_OPERATION, kNoZeroDivisor);
707 return false;
708 }
709
ValidTexture3DDestinationTarget(const Context * context,TextureTarget target)710 bool ValidTexture3DDestinationTarget(const Context *context, TextureTarget target)
711 {
712 switch (target)
713 {
714 case TextureTarget::_3D:
715 case TextureTarget::_2DArray:
716 return true;
717 default:
718 return false;
719 }
720 }
721
ValidTexLevelDestinationTarget(const Context * context,TextureType type)722 bool ValidTexLevelDestinationTarget(const Context *context, TextureType type)
723 {
724 switch (type)
725 {
726 case TextureType::_2D:
727 case TextureType::_2DArray:
728 case TextureType::_2DMultisample:
729 case TextureType::CubeMap:
730 case TextureType::_3D:
731 return true;
732 case TextureType::Rectangle:
733 return context->getExtensions().textureRectangle;
734 case TextureType::_2DMultisampleArray:
735 return context->getExtensions().textureStorageMultisample2DArray;
736 default:
737 return false;
738 }
739 }
740
ValidFramebufferTarget(const Context * context,GLenum target)741 bool ValidFramebufferTarget(const Context *context, GLenum target)
742 {
743 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER &&
744 GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
745 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
746
747 switch (target)
748 {
749 case GL_FRAMEBUFFER:
750 return true;
751
752 case GL_READ_FRAMEBUFFER:
753 case GL_DRAW_FRAMEBUFFER:
754 return (context->getExtensions().framebufferBlit ||
755 context->getClientMajorVersion() >= 3);
756
757 default:
758 return false;
759 }
760 }
761
ValidMipLevel(const Context * context,TextureType type,GLint level)762 bool ValidMipLevel(const Context *context, TextureType type, GLint level)
763 {
764 const auto &caps = context->getCaps();
765 size_t maxDimension = 0;
766 switch (type)
767 {
768 case TextureType::_2D:
769 case TextureType::_2DArray:
770 case TextureType::_2DMultisample:
771 case TextureType::_2DMultisampleArray:
772 // TODO(http://anglebug.com/2775): It's a bit unclear what the "maximum allowable
773 // level-of-detail" for multisample textures should be. Could maybe make it zero.
774 maxDimension = caps.max2DTextureSize;
775 break;
776
777 case TextureType::CubeMap:
778 maxDimension = caps.maxCubeMapTextureSize;
779 break;
780
781 case TextureType::External:
782 case TextureType::Rectangle:
783 return level == 0;
784
785 case TextureType::_3D:
786 maxDimension = caps.max3DTextureSize;
787 break;
788
789 default:
790 UNREACHABLE();
791 }
792
793 return level <= log2(static_cast<int>(maxDimension)) && level >= 0;
794 }
795
ValidImageSizeParameters(Context * context,TextureType target,GLint level,GLsizei width,GLsizei height,GLsizei depth,bool isSubImage)796 bool ValidImageSizeParameters(Context *context,
797 TextureType target,
798 GLint level,
799 GLsizei width,
800 GLsizei height,
801 GLsizei depth,
802 bool isSubImage)
803 {
804 if (width < 0 || height < 0 || depth < 0)
805 {
806 context->validationError(GL_INVALID_VALUE, kNegativeSize);
807 return false;
808 }
809 // TexSubImage parameters can be NPOT without textureNPOT extension,
810 // as long as the destination texture is POT.
811 bool hasNPOTSupport =
812 context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0);
813 if (!isSubImage && !hasNPOTSupport &&
814 (level != 0 && (!isPow2(width) || !isPow2(height) || !isPow2(depth))))
815 {
816 context->validationError(GL_INVALID_VALUE, kTextureNotPow2);
817 return false;
818 }
819
820 if (!ValidMipLevel(context, target, level))
821 {
822 context->validationError(GL_INVALID_VALUE, kInvalidMipLevel);
823 return false;
824 }
825
826 return true;
827 }
828
ValidCompressedDimension(GLsizei size,GLuint blockSize,bool smallerThanBlockSizeAllowed)829 bool ValidCompressedDimension(GLsizei size, GLuint blockSize, bool smallerThanBlockSizeAllowed)
830 {
831 return (smallerThanBlockSizeAllowed && (size > 0) && (blockSize % size == 0)) ||
832 (size % blockSize == 0);
833 }
834
ValidCompressedImageSize(const Context * context,GLenum internalFormat,GLint level,GLsizei width,GLsizei height,GLsizei depth)835 bool ValidCompressedImageSize(const Context *context,
836 GLenum internalFormat,
837 GLint level,
838 GLsizei width,
839 GLsizei height,
840 GLsizei depth)
841 {
842 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
843 if (!formatInfo.compressed)
844 {
845 return false;
846 }
847
848 if (width < 0 || height < 0)
849 {
850 return false;
851 }
852
853 if (CompressedTextureFormatRequiresExactSize(internalFormat))
854 {
855 // The ANGLE extensions allow specifying compressed textures with sizes smaller than the
856 // block size for level 0 but WebGL disallows this.
857 bool smallerThanBlockSizeAllowed =
858 level > 0 || !context->getExtensions().webglCompatibility;
859
860 if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth,
861 smallerThanBlockSizeAllowed) ||
862 !ValidCompressedDimension(height, formatInfo.compressedBlockHeight,
863 smallerThanBlockSizeAllowed) ||
864 !ValidCompressedDimension(depth, formatInfo.compressedBlockDepth,
865 smallerThanBlockSizeAllowed))
866 {
867 return false;
868 }
869 }
870
871 return true;
872 }
873
ValidCompressedSubImageSize(const Context * context,GLenum internalFormat,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,size_t textureWidth,size_t textureHeight,size_t textureDepth)874 bool ValidCompressedSubImageSize(const Context *context,
875 GLenum internalFormat,
876 GLint xoffset,
877 GLint yoffset,
878 GLint zoffset,
879 GLsizei width,
880 GLsizei height,
881 GLsizei depth,
882 size_t textureWidth,
883 size_t textureHeight,
884 size_t textureDepth)
885 {
886 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
887 if (!formatInfo.compressed)
888 {
889 return false;
890 }
891
892 if (xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0 || depth < 0)
893 {
894 return false;
895 }
896
897 if (CompressedSubTextureFormatRequiresExactSize(internalFormat))
898 {
899 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
900 yoffset % formatInfo.compressedBlockHeight != 0 ||
901 zoffset % formatInfo.compressedBlockDepth != 0)
902 {
903 return false;
904 }
905
906 // Allowed to either have data that is a multiple of block size or is smaller than the block
907 // size but fills the entire mip
908 bool fillsEntireMip = xoffset == 0 && yoffset == 0 &&
909 static_cast<size_t>(width) == textureWidth &&
910 static_cast<size_t>(height) == textureHeight &&
911 static_cast<size_t>(depth) == textureDepth;
912 bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 &&
913 (height % formatInfo.compressedBlockHeight) == 0 &&
914 (depth % formatInfo.compressedBlockDepth) == 0;
915 if (!sizeMultipleOfBlockSize && !fillsEntireMip)
916 {
917 return false;
918 }
919 }
920
921 return true;
922 }
923
ValidImageDataSize(Context * context,TextureType texType,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const void * pixels,GLsizei imageSize)924 bool ValidImageDataSize(Context *context,
925 TextureType texType,
926 GLsizei width,
927 GLsizei height,
928 GLsizei depth,
929 GLenum format,
930 GLenum type,
931 const void *pixels,
932 GLsizei imageSize)
933 {
934 Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
935 if (pixelUnpackBuffer == nullptr && imageSize < 0)
936 {
937 // Checks are not required
938 return true;
939 }
940
941 // ...the data would be unpacked from the buffer object such that the memory reads required
942 // would exceed the data store size.
943 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
944 ASSERT(formatInfo.internalFormat != GL_NONE);
945 const Extents size(width, height, depth);
946 const auto &unpack = context->getState().getUnpackState();
947
948 bool targetIs3D = texType == TextureType::_3D || texType == TextureType::_2DArray;
949 GLuint endByte = 0;
950 if (!formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D, &endByte))
951 {
952 context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
953 return false;
954 }
955
956 if (pixelUnpackBuffer)
957 {
958 CheckedNumeric<size_t> checkedEndByte(endByte);
959 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
960 checkedEndByte += checkedOffset;
961
962 if (!checkedEndByte.IsValid() ||
963 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
964 {
965 // Overflow past the end of the buffer
966 context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
967 return false;
968 }
969 if (context->getExtensions().webglCompatibility &&
970 pixelUnpackBuffer->isBoundForTransformFeedbackAndOtherUse())
971 {
972 context->validationError(GL_INVALID_OPERATION,
973 kPixelUnpackBufferBoundForTransformFeedback);
974 return false;
975 }
976 }
977 else
978 {
979 ASSERT(imageSize >= 0);
980 if (pixels == nullptr && imageSize != 0)
981 {
982 context->validationError(GL_INVALID_OPERATION, kImageSizeMustBeZero);
983 return false;
984 }
985
986 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
987 {
988 context->validationError(GL_INVALID_OPERATION, kImageSizeTooSmall);
989 return false;
990 }
991 }
992
993 return true;
994 }
995
ValidQueryType(const Context * context,QueryType queryType)996 bool ValidQueryType(const Context *context, QueryType queryType)
997 {
998 switch (queryType)
999 {
1000 case QueryType::AnySamples:
1001 case QueryType::AnySamplesConservative:
1002 return context->getClientMajorVersion() >= 3 ||
1003 context->getExtensions().occlusionQueryBoolean;
1004 case QueryType::TransformFeedbackPrimitivesWritten:
1005 return (context->getClientMajorVersion() >= 3);
1006 case QueryType::TimeElapsed:
1007 return context->getExtensions().disjointTimerQuery;
1008 case QueryType::CommandsCompleted:
1009 return context->getExtensions().syncQuery;
1010 case QueryType::PrimitivesGenerated:
1011 return context->getExtensions().geometryShader;
1012 default:
1013 return false;
1014 }
1015 }
1016
ValidateWebGLVertexAttribPointer(Context * context,VertexAttribType type,GLboolean normalized,GLsizei stride,const void * ptr,bool pureInteger)1017 bool ValidateWebGLVertexAttribPointer(Context *context,
1018 VertexAttribType type,
1019 GLboolean normalized,
1020 GLsizei stride,
1021 const void *ptr,
1022 bool pureInteger)
1023 {
1024 ASSERT(context->getExtensions().webglCompatibility);
1025 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
1026 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
1027 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
1028 // parameter exceeds 255.
1029 constexpr GLsizei kMaxWebGLStride = 255;
1030 if (stride > kMaxWebGLStride)
1031 {
1032 context->validationError(GL_INVALID_VALUE, kStrideExceedsWebGLLimit);
1033 return false;
1034 }
1035
1036 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
1037 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
1038 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
1039 // or an INVALID_OPERATION error is generated.
1040 angle::FormatID internalType = GetVertexFormatID(type, normalized, 1, pureInteger);
1041 size_t typeSize = GetVertexFormatSize(internalType);
1042
1043 ASSERT(isPow2(typeSize) && typeSize > 0);
1044 size_t sizeMask = (typeSize - 1);
1045 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
1046 {
1047 context->validationError(GL_INVALID_OPERATION, kOffsetMustBeMultipleOfType);
1048 return false;
1049 }
1050
1051 if ((stride & sizeMask) != 0)
1052 {
1053 context->validationError(GL_INVALID_OPERATION, kStrideMustBeMultipleOfType);
1054 return false;
1055 }
1056
1057 return true;
1058 }
1059
GetValidProgramNoResolve(Context * context,GLuint id)1060 Program *GetValidProgramNoResolve(Context *context, GLuint id)
1061 {
1062 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
1063 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
1064 // or program object and INVALID_OPERATION if the provided name identifies an object
1065 // that is not the expected type."
1066
1067 Program *validProgram = context->getProgramNoResolveLink(id);
1068
1069 if (!validProgram)
1070 {
1071 if (context->getShader(id))
1072 {
1073 context->validationError(GL_INVALID_OPERATION, kExpectedProgramName);
1074 }
1075 else
1076 {
1077 context->validationError(GL_INVALID_VALUE, kInvalidProgramName);
1078 }
1079 }
1080
1081 return validProgram;
1082 }
1083
GetValidProgram(Context * context,GLuint id)1084 Program *GetValidProgram(Context *context, GLuint id)
1085 {
1086 Program *program = GetValidProgramNoResolve(context, id);
1087 if (program)
1088 {
1089 program->resolveLink(context);
1090 }
1091 return program;
1092 }
1093
GetValidShader(Context * context,GLuint id)1094 Shader *GetValidShader(Context *context, GLuint id)
1095 {
1096 // See ValidProgram for spec details.
1097
1098 Shader *validShader = context->getShader(id);
1099
1100 if (!validShader)
1101 {
1102 if (context->getProgramNoResolveLink(id))
1103 {
1104 context->validationError(GL_INVALID_OPERATION, kExpectedShaderName);
1105 }
1106 else
1107 {
1108 context->validationError(GL_INVALID_VALUE, kInvalidShaderName);
1109 }
1110 }
1111
1112 return validShader;
1113 }
1114
ValidateAttachmentTarget(Context * context,GLenum attachment)1115 bool ValidateAttachmentTarget(Context *context, GLenum attachment)
1116 {
1117 if (attachment >= GL_COLOR_ATTACHMENT1_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
1118 {
1119 if (context->getClientMajorVersion() < 3 && !context->getExtensions().drawBuffers)
1120 {
1121 context->validationError(GL_INVALID_ENUM, kInvalidAttachment);
1122 return false;
1123 }
1124
1125 // Color attachment 0 is validated below because it is always valid
1126 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
1127 if (colorAttachment >= context->getCaps().maxColorAttachments)
1128 {
1129 context->validationError(GL_INVALID_OPERATION, kInvalidAttachment);
1130 return false;
1131 }
1132 }
1133 else
1134 {
1135 switch (attachment)
1136 {
1137 case GL_COLOR_ATTACHMENT0:
1138 case GL_DEPTH_ATTACHMENT:
1139 case GL_STENCIL_ATTACHMENT:
1140 break;
1141
1142 case GL_DEPTH_STENCIL_ATTACHMENT:
1143 if (!context->getExtensions().webglCompatibility &&
1144 context->getClientMajorVersion() < 3)
1145 {
1146 context->validationError(GL_INVALID_ENUM, kInvalidAttachment);
1147 return false;
1148 }
1149 break;
1150
1151 default:
1152 context->validationError(GL_INVALID_ENUM, kInvalidAttachment);
1153 return false;
1154 }
1155 }
1156
1157 return true;
1158 }
1159
ValidateRenderbufferStorageParametersBase(Context * context,GLenum target,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height)1160 bool ValidateRenderbufferStorageParametersBase(Context *context,
1161 GLenum target,
1162 GLsizei samples,
1163 GLenum internalformat,
1164 GLsizei width,
1165 GLsizei height)
1166 {
1167 switch (target)
1168 {
1169 case GL_RENDERBUFFER:
1170 break;
1171 default:
1172 context->validationError(GL_INVALID_ENUM, kInvalidRenderbufferTarget);
1173 return false;
1174 }
1175
1176 if (width < 0 || height < 0 || samples < 0)
1177 {
1178 context->validationError(GL_INVALID_VALUE, kInvalidRenderbufferWidthHeight);
1179 return false;
1180 }
1181
1182 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
1183 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
1184
1185 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
1186 if (!formatCaps.renderbuffer)
1187 {
1188 context->validationError(GL_INVALID_ENUM, kInvalidRenderbufferInternalFormat);
1189 return false;
1190 }
1191
1192 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
1193 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
1194 // only sized internal formats.
1195 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(convertedInternalFormat);
1196 if (formatInfo.internalFormat == GL_NONE)
1197 {
1198 context->validationError(GL_INVALID_ENUM, kInvalidRenderbufferInternalFormat);
1199 return false;
1200 }
1201
1202 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
1203 {
1204 context->validationError(GL_INVALID_VALUE, kResourceMaxRenderbufferSize);
1205 return false;
1206 }
1207
1208 GLuint handle = context->getState().getRenderbufferId();
1209 if (handle == 0)
1210 {
1211 context->validationError(GL_INVALID_OPERATION, kInvalidRenderbufferTarget);
1212 return false;
1213 }
1214
1215 return true;
1216 }
1217
ValidateFramebufferRenderbufferParameters(Context * context,GLenum target,GLenum attachment,GLenum renderbuffertarget,RenderbufferID renderbuffer)1218 bool ValidateFramebufferRenderbufferParameters(Context *context,
1219 GLenum target,
1220 GLenum attachment,
1221 GLenum renderbuffertarget,
1222 RenderbufferID renderbuffer)
1223 {
1224 if (!ValidFramebufferTarget(context, target))
1225 {
1226 context->validationError(GL_INVALID_ENUM, kInvalidFramebufferTarget);
1227 return false;
1228 }
1229
1230 Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1231
1232 ASSERT(framebuffer);
1233 if (framebuffer->id() == 0)
1234 {
1235 context->validationError(GL_INVALID_OPERATION, kDefaultFramebufferTarget);
1236 return false;
1237 }
1238
1239 if (!ValidateAttachmentTarget(context, attachment))
1240 {
1241 return false;
1242 }
1243
1244 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
1245 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
1246 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
1247 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
1248 if (renderbuffer.value != 0)
1249 {
1250 if (!context->getRenderbuffer(renderbuffer))
1251 {
1252 context->validationError(GL_INVALID_OPERATION, kInvalidRenderbufferTarget);
1253 return false;
1254 }
1255 }
1256
1257 return true;
1258 }
1259
ValidateBlitFramebufferParameters(Context * context,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)1260 bool ValidateBlitFramebufferParameters(Context *context,
1261 GLint srcX0,
1262 GLint srcY0,
1263 GLint srcX1,
1264 GLint srcY1,
1265 GLint dstX0,
1266 GLint dstY0,
1267 GLint dstX1,
1268 GLint dstY1,
1269 GLbitfield mask,
1270 GLenum filter)
1271 {
1272 switch (filter)
1273 {
1274 case GL_NEAREST:
1275 break;
1276 case GL_LINEAR:
1277 break;
1278 default:
1279 context->validationError(GL_INVALID_ENUM, kBlitInvalidFilter);
1280 return false;
1281 }
1282
1283 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
1284 {
1285 context->validationError(GL_INVALID_VALUE, kBlitInvalidMask);
1286 return false;
1287 }
1288
1289 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
1290 // color buffer, leaving only nearest being unfiltered from above
1291 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
1292 {
1293 context->validationError(GL_INVALID_OPERATION, kBlitOnlyNearestForNonColor);
1294 return false;
1295 }
1296
1297 const auto &glState = context->getState();
1298 Framebuffer *readFramebuffer = glState.getReadFramebuffer();
1299 Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
1300
1301 if (!readFramebuffer || !drawFramebuffer)
1302 {
1303 context->validationError(GL_INVALID_FRAMEBUFFER_OPERATION, kBlitFramebufferMissing);
1304 return false;
1305 }
1306
1307 if (!ValidateFramebufferComplete(context, readFramebuffer))
1308 {
1309 return false;
1310 }
1311
1312 if (!ValidateFramebufferComplete(context, drawFramebuffer))
1313 {
1314 return false;
1315 }
1316
1317 if (readFramebuffer->id() == drawFramebuffer->id())
1318 {
1319 context->validationError(GL_INVALID_OPERATION, kBlitFeedbackLoop);
1320 return false;
1321 }
1322
1323 if (!ValidateFramebufferNotMultisampled(context, drawFramebuffer))
1324 {
1325 return false;
1326 }
1327
1328 // This validation is specified in the WebGL 2.0 spec and not in the GLES 3.0.5 spec, but we
1329 // always run it in order to avoid triggering driver bugs.
1330 if (DifferenceCanOverflow(srcX0, srcX1) || DifferenceCanOverflow(srcY0, srcY1) ||
1331 DifferenceCanOverflow(dstX0, dstX1) || DifferenceCanOverflow(dstY0, dstY1))
1332 {
1333 context->validationError(GL_INVALID_VALUE, kBlitDimensionsOutOfRange);
1334 return false;
1335 }
1336
1337 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
1338
1339 if (mask & GL_COLOR_BUFFER_BIT)
1340 {
1341 const FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorAttachment();
1342 const Extensions &extensions = context->getExtensions();
1343
1344 if (readColorBuffer)
1345 {
1346 const Format &readFormat = readColorBuffer->getFormat();
1347
1348 for (size_t drawbufferIdx = 0;
1349 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
1350 {
1351 const FramebufferAttachment *attachment =
1352 drawFramebuffer->getDrawBuffer(drawbufferIdx);
1353 if (attachment)
1354 {
1355 const Format &drawFormat = attachment->getFormat();
1356
1357 // The GL ES 3.0.2 spec (pg 193) states that:
1358 // 1) If the read buffer is fixed point format, the draw buffer must be as well
1359 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
1360 // as well
1361 // 3) If the read buffer is a signed integer format, the draw buffer must be as
1362 // well
1363 // Changes with EXT_color_buffer_float:
1364 // Case 1) is changed to fixed point OR floating point
1365 GLenum readComponentType = readFormat.info->componentType;
1366 GLenum drawComponentType = drawFormat.info->componentType;
1367 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
1368 readComponentType == GL_SIGNED_NORMALIZED);
1369 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
1370 drawComponentType == GL_SIGNED_NORMALIZED);
1371
1372 if (extensions.colorBufferFloat)
1373 {
1374 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
1375 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
1376
1377 if (readFixedOrFloat != drawFixedOrFloat)
1378 {
1379 context->validationError(GL_INVALID_OPERATION,
1380 kBlitTypeMismatchFixedOrFloat);
1381 return false;
1382 }
1383 }
1384 else if (readFixedPoint != drawFixedPoint)
1385 {
1386 context->validationError(GL_INVALID_OPERATION, kBlitTypeMismatchFixedPoint);
1387 return false;
1388 }
1389
1390 if (readComponentType == GL_UNSIGNED_INT &&
1391 drawComponentType != GL_UNSIGNED_INT)
1392 {
1393 context->validationError(GL_INVALID_OPERATION,
1394 kBlitTypeMismatchUnsignedInteger);
1395 return false;
1396 }
1397
1398 if (readComponentType == GL_INT && drawComponentType != GL_INT)
1399 {
1400 context->validationError(GL_INVALID_OPERATION,
1401 kBlitTypeMismatchSignedInteger);
1402 return false;
1403 }
1404
1405 if (readColorBuffer->getSamples() > 0 &&
1406 (!Format::EquivalentForBlit(readFormat, drawFormat) || !sameBounds))
1407 {
1408 context->validationError(GL_INVALID_OPERATION,
1409 kBlitMultisampledFormatOrBoundsMismatch);
1410 return false;
1411 }
1412
1413 if (context->getExtensions().webglCompatibility &&
1414 *readColorBuffer == *attachment)
1415 {
1416 context->validationError(GL_INVALID_OPERATION, kBlitSameImageColor);
1417 return false;
1418 }
1419 }
1420 }
1421
1422 if (readFormat.info->isInt() && filter == GL_LINEAR)
1423 {
1424 context->validationError(GL_INVALID_OPERATION, kBlitIntegerWithLinearFilter);
1425 return false;
1426 }
1427 }
1428 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1429 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
1430 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
1431 // situation is an application error that would lead to a crash in ANGLE.
1432 else if (drawFramebuffer->hasEnabledDrawBuffer())
1433 {
1434 context->validationError(GL_INVALID_OPERATION, kBlitMissingColor);
1435 return false;
1436 }
1437 }
1438
1439 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
1440 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
1441 for (size_t i = 0; i < 2; i++)
1442 {
1443 if (mask & masks[i])
1444 {
1445 const FramebufferAttachment *readBuffer =
1446 readFramebuffer->getAttachment(context, attachments[i]);
1447 const FramebufferAttachment *drawBuffer =
1448 drawFramebuffer->getAttachment(context, attachments[i]);
1449
1450 if (readBuffer && drawBuffer)
1451 {
1452 if (!Format::EquivalentForBlit(readBuffer->getFormat(), drawBuffer->getFormat()))
1453 {
1454 context->validationError(GL_INVALID_OPERATION,
1455 kBlitDepthOrStencilFormatMismatch);
1456 return false;
1457 }
1458
1459 if (readBuffer->getSamples() > 0 && !sameBounds)
1460 {
1461 context->validationError(GL_INVALID_OPERATION, kBlitMultisampledBoundsMismatch);
1462 return false;
1463 }
1464
1465 if (context->getExtensions().webglCompatibility && *readBuffer == *drawBuffer)
1466 {
1467 context->validationError(GL_INVALID_OPERATION, kBlitSameImageDepthOrStencil);
1468 return false;
1469 }
1470 }
1471 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1472 else if (drawBuffer)
1473 {
1474 context->validationError(GL_INVALID_OPERATION, kBlitMissingDepthOrStencil);
1475 return false;
1476 }
1477 }
1478 }
1479
1480 // OVR_multiview2:
1481 // Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the
1482 // current draw framebuffer isMultiview() or the number of
1483 // views in the current read framebuffer is more than one.
1484 if (readFramebuffer->readDisallowedByMultiview())
1485 {
1486 context->validationError(GL_INVALID_FRAMEBUFFER_OPERATION, kBlitFromMultiview);
1487 return false;
1488 }
1489 if (drawFramebuffer->isMultiview())
1490 {
1491 context->validationError(GL_INVALID_FRAMEBUFFER_OPERATION, kBlitToMultiview);
1492 return false;
1493 }
1494
1495 return true;
1496 }
1497
ValidateReadPixelsRobustANGLE(Context * context,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,GLsizei * length,GLsizei * columns,GLsizei * rows,void * pixels)1498 bool ValidateReadPixelsRobustANGLE(Context *context,
1499 GLint x,
1500 GLint y,
1501 GLsizei width,
1502 GLsizei height,
1503 GLenum format,
1504 GLenum type,
1505 GLsizei bufSize,
1506 GLsizei *length,
1507 GLsizei *columns,
1508 GLsizei *rows,
1509 void *pixels)
1510 {
1511 if (!ValidateRobustEntryPoint(context, bufSize))
1512 {
1513 return false;
1514 }
1515
1516 GLsizei writeLength = 0;
1517 GLsizei writeColumns = 0;
1518 GLsizei writeRows = 0;
1519
1520 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, &writeLength,
1521 &writeColumns, &writeRows, pixels))
1522 {
1523 return false;
1524 }
1525
1526 if (!ValidateRobustBufferSize(context, bufSize, writeLength))
1527 {
1528 return false;
1529 }
1530
1531 SetRobustLengthParam(length, writeLength);
1532 SetRobustLengthParam(columns, writeColumns);
1533 SetRobustLengthParam(rows, writeRows);
1534
1535 return true;
1536 }
1537
ValidateReadnPixelsEXT(Context * context,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,void * pixels)1538 bool ValidateReadnPixelsEXT(Context *context,
1539 GLint x,
1540 GLint y,
1541 GLsizei width,
1542 GLsizei height,
1543 GLenum format,
1544 GLenum type,
1545 GLsizei bufSize,
1546 void *pixels)
1547 {
1548 if (bufSize < 0)
1549 {
1550 context->validationError(GL_INVALID_VALUE, kNegativeBufferSize);
1551 return false;
1552 }
1553
1554 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
1555 nullptr, nullptr, pixels);
1556 }
1557
ValidateReadnPixelsRobustANGLE(Context * context,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,GLsizei * length,GLsizei * columns,GLsizei * rows,void * data)1558 bool ValidateReadnPixelsRobustANGLE(Context *context,
1559 GLint x,
1560 GLint y,
1561 GLsizei width,
1562 GLsizei height,
1563 GLenum format,
1564 GLenum type,
1565 GLsizei bufSize,
1566 GLsizei *length,
1567 GLsizei *columns,
1568 GLsizei *rows,
1569 void *data)
1570 {
1571 GLsizei writeLength = 0;
1572 GLsizei writeColumns = 0;
1573 GLsizei writeRows = 0;
1574
1575 if (!ValidateRobustEntryPoint(context, bufSize))
1576 {
1577 return false;
1578 }
1579
1580 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, &writeLength,
1581 &writeColumns, &writeRows, data))
1582 {
1583 return false;
1584 }
1585
1586 if (!ValidateRobustBufferSize(context, bufSize, writeLength))
1587 {
1588 return false;
1589 }
1590
1591 SetRobustLengthParam(length, writeLength);
1592 SetRobustLengthParam(columns, writeColumns);
1593 SetRobustLengthParam(rows, writeRows);
1594
1595 return true;
1596 }
1597
ValidateGenQueriesEXT(Context * context,GLsizei n,GLuint * ids)1598 bool ValidateGenQueriesEXT(Context *context, GLsizei n, GLuint *ids)
1599 {
1600 if (!context->getExtensions().occlusionQueryBoolean &&
1601 !context->getExtensions().disjointTimerQuery)
1602 {
1603 context->validationError(GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
1604 return false;
1605 }
1606
1607 return ValidateGenOrDelete(context, n);
1608 }
1609
ValidateDeleteQueriesEXT(Context * context,GLsizei n,const GLuint * ids)1610 bool ValidateDeleteQueriesEXT(Context *context, GLsizei n, const GLuint *ids)
1611 {
1612 if (!context->getExtensions().occlusionQueryBoolean &&
1613 !context->getExtensions().disjointTimerQuery)
1614 {
1615 context->validationError(GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
1616 return false;
1617 }
1618
1619 return ValidateGenOrDelete(context, n);
1620 }
1621
ValidateIsQueryEXT(Context * context,GLuint id)1622 bool ValidateIsQueryEXT(Context *context, GLuint id)
1623 {
1624 if (!context->getExtensions().occlusionQueryBoolean &&
1625 !context->getExtensions().disjointTimerQuery)
1626 {
1627 context->validationError(GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
1628 return false;
1629 }
1630
1631 return true;
1632 }
1633
ValidateBeginQueryBase(Context * context,QueryType target,GLuint id)1634 bool ValidateBeginQueryBase(Context *context, QueryType target, GLuint id)
1635 {
1636 if (!ValidQueryType(context, target))
1637 {
1638 context->validationError(GL_INVALID_ENUM, kInvalidQueryType);
1639 return false;
1640 }
1641
1642 if (id == 0)
1643 {
1644 context->validationError(GL_INVALID_OPERATION, kInvalidQueryId);
1645 return false;
1646 }
1647
1648 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1649 // of zero, if the active query object name for <target> is non-zero (for the
1650 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1651 // the active query for either target is non-zero), if <id> is the name of an
1652 // existing query object whose type does not match <target>, or if <id> is the
1653 // active query object name for any query type, the error INVALID_OPERATION is
1654 // generated.
1655
1656 // Ensure no other queries are active
1657 // NOTE: If other queries than occlusion are supported, we will need to check
1658 // separately that:
1659 // a) The query ID passed is not the current active query for any target/type
1660 // b) There are no active queries for the requested target (and in the case
1661 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1662 // no query may be active for either if glBeginQuery targets either.
1663
1664 if (context->getState().isQueryActive(target))
1665 {
1666 context->validationError(GL_INVALID_OPERATION, kOtherQueryActive);
1667 return false;
1668 }
1669
1670 Query *queryObject = context->getQuery(id, true, target);
1671
1672 // check that name was obtained with glGenQueries
1673 if (!queryObject)
1674 {
1675 context->validationError(GL_INVALID_OPERATION, kInvalidQueryId);
1676 return false;
1677 }
1678
1679 // check for type mismatch
1680 if (queryObject->getType() != target)
1681 {
1682 context->validationError(GL_INVALID_OPERATION, kQueryTargetMismatch);
1683 return false;
1684 }
1685
1686 return true;
1687 }
1688
ValidateBeginQueryEXT(Context * context,QueryType target,GLuint id)1689 bool ValidateBeginQueryEXT(Context *context, QueryType target, GLuint id)
1690 {
1691 if (!context->getExtensions().occlusionQueryBoolean &&
1692 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
1693 {
1694 context->validationError(GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
1695 return false;
1696 }
1697
1698 return ValidateBeginQueryBase(context, target, id);
1699 }
1700
ValidateEndQueryBase(Context * context,QueryType target)1701 bool ValidateEndQueryBase(Context *context, QueryType target)
1702 {
1703 if (!ValidQueryType(context, target))
1704 {
1705 context->validationError(GL_INVALID_ENUM, kInvalidQueryType);
1706 return false;
1707 }
1708
1709 const Query *queryObject = context->getState().getActiveQuery(target);
1710
1711 if (queryObject == nullptr)
1712 {
1713 context->validationError(GL_INVALID_OPERATION, kQueryInactive);
1714 return false;
1715 }
1716
1717 return true;
1718 }
1719
ValidateEndQueryEXT(Context * context,QueryType target)1720 bool ValidateEndQueryEXT(Context *context, QueryType target)
1721 {
1722 if (!context->getExtensions().occlusionQueryBoolean &&
1723 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
1724 {
1725 context->validationError(GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
1726 return false;
1727 }
1728
1729 return ValidateEndQueryBase(context, target);
1730 }
1731
ValidateQueryCounterEXT(Context * context,GLuint id,QueryType target)1732 bool ValidateQueryCounterEXT(Context *context, GLuint id, QueryType target)
1733 {
1734 if (!context->getExtensions().disjointTimerQuery)
1735 {
1736 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
1737 return false;
1738 }
1739
1740 if (target != QueryType::Timestamp)
1741 {
1742 context->validationError(GL_INVALID_ENUM, kInvalidQueryTarget);
1743 return false;
1744 }
1745
1746 Query *queryObject = context->getQuery(id, true, target);
1747 if (queryObject == nullptr)
1748 {
1749 context->validationError(GL_INVALID_OPERATION, kInvalidQueryId);
1750 return false;
1751 }
1752
1753 if (context->getState().isQueryActive(queryObject))
1754 {
1755 context->validationError(GL_INVALID_OPERATION, kQueryActive);
1756 return false;
1757 }
1758
1759 return true;
1760 }
1761
ValidateGetQueryivBase(Context * context,QueryType target,GLenum pname,GLsizei * numParams)1762 bool ValidateGetQueryivBase(Context *context, QueryType target, GLenum pname, GLsizei *numParams)
1763 {
1764 if (numParams)
1765 {
1766 *numParams = 0;
1767 }
1768
1769 if (!ValidQueryType(context, target) && target != QueryType::Timestamp)
1770 {
1771 context->validationError(GL_INVALID_ENUM, kInvalidQueryType);
1772 return false;
1773 }
1774
1775 switch (pname)
1776 {
1777 case GL_CURRENT_QUERY_EXT:
1778 if (target == QueryType::Timestamp)
1779 {
1780 context->validationError(GL_INVALID_ENUM, kInvalidQueryTarget);
1781 return false;
1782 }
1783 break;
1784 case GL_QUERY_COUNTER_BITS_EXT:
1785 if (!context->getExtensions().disjointTimerQuery ||
1786 (target != QueryType::Timestamp && target != QueryType::TimeElapsed))
1787 {
1788 context->validationError(GL_INVALID_ENUM, kInvalidPname);
1789 return false;
1790 }
1791 break;
1792 default:
1793 context->validationError(GL_INVALID_ENUM, kInvalidPname);
1794 return false;
1795 }
1796
1797 if (numParams)
1798 {
1799 // All queries return only one value
1800 *numParams = 1;
1801 }
1802
1803 return true;
1804 }
1805
ValidateGetQueryivEXT(Context * context,QueryType target,GLenum pname,GLint * params)1806 bool ValidateGetQueryivEXT(Context *context, QueryType target, GLenum pname, GLint *params)
1807 {
1808 if (!context->getExtensions().occlusionQueryBoolean &&
1809 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
1810 {
1811 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
1812 return false;
1813 }
1814
1815 return ValidateGetQueryivBase(context, target, pname, nullptr);
1816 }
1817
ValidateGetQueryivRobustANGLE(Context * context,QueryType target,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)1818 bool ValidateGetQueryivRobustANGLE(Context *context,
1819 QueryType target,
1820 GLenum pname,
1821 GLsizei bufSize,
1822 GLsizei *length,
1823 GLint *params)
1824 {
1825 if (!ValidateRobustEntryPoint(context, bufSize))
1826 {
1827 return false;
1828 }
1829
1830 GLsizei numParams = 0;
1831
1832 if (!ValidateGetQueryivBase(context, target, pname, &numParams))
1833 {
1834 return false;
1835 }
1836
1837 if (!ValidateRobustBufferSize(context, bufSize, numParams))
1838 {
1839 return false;
1840 }
1841
1842 SetRobustLengthParam(length, numParams);
1843
1844 return true;
1845 }
1846
ValidateGetQueryObjectValueBase(Context * context,GLuint id,GLenum pname,GLsizei * numParams)1847 bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams)
1848 {
1849 if (numParams)
1850 {
1851 *numParams = 1;
1852 }
1853
1854 if (context->isContextLost())
1855 {
1856 context->validationError(GL_CONTEXT_LOST, kContextLost);
1857
1858 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
1859 {
1860 // Generate an error but still return true, the context still needs to return a
1861 // value in this case.
1862 return true;
1863 }
1864 else
1865 {
1866 return false;
1867 }
1868 }
1869
1870 Query *queryObject = context->getQuery(id, false, QueryType::InvalidEnum);
1871
1872 if (!queryObject)
1873 {
1874 context->validationError(GL_INVALID_OPERATION, kInvalidQueryId);
1875 return false;
1876 }
1877
1878 if (context->getState().isQueryActive(queryObject))
1879 {
1880 context->validationError(GL_INVALID_OPERATION, kQueryActive);
1881 return false;
1882 }
1883
1884 switch (pname)
1885 {
1886 case GL_QUERY_RESULT_EXT:
1887 case GL_QUERY_RESULT_AVAILABLE_EXT:
1888 break;
1889
1890 default:
1891 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
1892 return false;
1893 }
1894
1895 return true;
1896 }
1897
ValidateGetQueryObjectivEXT(Context * context,GLuint id,GLenum pname,GLint * params)1898 bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1899 {
1900 if (!context->getExtensions().disjointTimerQuery)
1901 {
1902 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
1903 return false;
1904 }
1905 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
1906 }
1907
ValidateGetQueryObjectivRobustANGLE(Context * context,GLuint id,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)1908 bool ValidateGetQueryObjectivRobustANGLE(Context *context,
1909 GLuint id,
1910 GLenum pname,
1911 GLsizei bufSize,
1912 GLsizei *length,
1913 GLint *params)
1914 {
1915 if (!context->getExtensions().disjointTimerQuery)
1916 {
1917 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
1918 return false;
1919 }
1920
1921 if (!ValidateRobustEntryPoint(context, bufSize))
1922 {
1923 return false;
1924 }
1925
1926 GLsizei numParams = 0;
1927
1928 if (!ValidateGetQueryObjectValueBase(context, id, pname, &numParams))
1929 {
1930 return false;
1931 }
1932
1933 if (!ValidateRobustBufferSize(context, bufSize, numParams))
1934 {
1935 return false;
1936 }
1937
1938 SetRobustLengthParam(length, numParams);
1939
1940 return true;
1941 }
1942
ValidateGetQueryObjectuivEXT(Context * context,GLuint id,GLenum pname,GLuint * params)1943 bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1944 {
1945 if (!context->getExtensions().disjointTimerQuery &&
1946 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
1947 {
1948 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
1949 return false;
1950 }
1951 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
1952 }
1953
ValidateGetQueryObjectuivRobustANGLE(Context * context,GLuint id,GLenum pname,GLsizei bufSize,GLsizei * length,GLuint * params)1954 bool ValidateGetQueryObjectuivRobustANGLE(Context *context,
1955 GLuint id,
1956 GLenum pname,
1957 GLsizei bufSize,
1958 GLsizei *length,
1959 GLuint *params)
1960 {
1961 if (!context->getExtensions().disjointTimerQuery &&
1962 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
1963 {
1964 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
1965 return false;
1966 }
1967
1968 if (!ValidateRobustEntryPoint(context, bufSize))
1969 {
1970 return false;
1971 }
1972
1973 GLsizei numParams = 0;
1974
1975 if (!ValidateGetQueryObjectValueBase(context, id, pname, &numParams))
1976 {
1977 return false;
1978 }
1979
1980 if (!ValidateRobustBufferSize(context, bufSize, numParams))
1981 {
1982 return false;
1983 }
1984
1985 SetRobustLengthParam(length, numParams);
1986
1987 return true;
1988 }
1989
ValidateGetQueryObjecti64vEXT(Context * context,GLuint id,GLenum pname,GLint64 * params)1990 bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1991 {
1992 if (!context->getExtensions().disjointTimerQuery)
1993 {
1994 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
1995 return false;
1996 }
1997 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
1998 }
1999
ValidateGetQueryObjecti64vRobustANGLE(Context * context,GLuint id,GLenum pname,GLsizei bufSize,GLsizei * length,GLint64 * params)2000 bool ValidateGetQueryObjecti64vRobustANGLE(Context *context,
2001 GLuint id,
2002 GLenum pname,
2003 GLsizei bufSize,
2004 GLsizei *length,
2005 GLint64 *params)
2006 {
2007 if (!context->getExtensions().disjointTimerQuery)
2008 {
2009 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
2010 return false;
2011 }
2012
2013 if (!ValidateRobustEntryPoint(context, bufSize))
2014 {
2015 return false;
2016 }
2017
2018 GLsizei numParams = 0;
2019
2020 if (!ValidateGetQueryObjectValueBase(context, id, pname, &numParams))
2021 {
2022 return false;
2023 }
2024
2025 if (!ValidateRobustBufferSize(context, bufSize, numParams))
2026 {
2027 return false;
2028 }
2029
2030 SetRobustLengthParam(length, numParams);
2031
2032 return true;
2033 }
2034
ValidateGetQueryObjectui64vEXT(Context * context,GLuint id,GLenum pname,GLuint64 * params)2035 bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
2036 {
2037 if (!context->getExtensions().disjointTimerQuery)
2038 {
2039 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
2040 return false;
2041 }
2042 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2043 }
2044
ValidateGetQueryObjectui64vRobustANGLE(Context * context,GLuint id,GLenum pname,GLsizei bufSize,GLsizei * length,GLuint64 * params)2045 bool ValidateGetQueryObjectui64vRobustANGLE(Context *context,
2046 GLuint id,
2047 GLenum pname,
2048 GLsizei bufSize,
2049 GLsizei *length,
2050 GLuint64 *params)
2051 {
2052 if (!context->getExtensions().disjointTimerQuery)
2053 {
2054 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
2055 return false;
2056 }
2057
2058 if (!ValidateRobustEntryPoint(context, bufSize))
2059 {
2060 return false;
2061 }
2062
2063 GLsizei numParams = 0;
2064
2065 if (!ValidateGetQueryObjectValueBase(context, id, pname, &numParams))
2066 {
2067 return false;
2068 }
2069
2070 if (!ValidateRobustBufferSize(context, bufSize, numParams))
2071 {
2072 return false;
2073 }
2074
2075 SetRobustLengthParam(length, numParams);
2076
2077 return true;
2078 }
2079
ValidateUniformCommonBase(Context * context,Program * program,GLint location,GLsizei count,const LinkedUniform ** uniformOut)2080 bool ValidateUniformCommonBase(Context *context,
2081 Program *program,
2082 GLint location,
2083 GLsizei count,
2084 const LinkedUniform **uniformOut)
2085 {
2086 // TODO(Jiajia): Add image uniform check in future.
2087 if (count < 0)
2088 {
2089 context->validationError(GL_INVALID_VALUE, kNegativeCount);
2090 return false;
2091 }
2092
2093 if (!program)
2094 {
2095 context->validationError(GL_INVALID_OPERATION, kInvalidProgramName);
2096 return false;
2097 }
2098
2099 if (!program->isLinked())
2100 {
2101 context->validationError(GL_INVALID_OPERATION, kProgramNotLinked);
2102 return false;
2103 }
2104
2105 if (location == -1)
2106 {
2107 // Silently ignore the uniform command
2108 return false;
2109 }
2110
2111 const auto &uniformLocations = program->getUniformLocations();
2112 size_t castedLocation = static_cast<size_t>(location);
2113 if (castedLocation >= uniformLocations.size())
2114 {
2115 context->validationError(GL_INVALID_OPERATION, kInvalidUniformLocation);
2116 return false;
2117 }
2118
2119 const auto &uniformLocation = uniformLocations[castedLocation];
2120 if (uniformLocation.ignored)
2121 {
2122 // Silently ignore the uniform command
2123 return false;
2124 }
2125
2126 if (!uniformLocation.used())
2127 {
2128 context->validationError(GL_INVALID_OPERATION, kInvalidUniformLocation);
2129 return false;
2130 }
2131
2132 const auto &uniform = program->getUniformByIndex(uniformLocation.index);
2133
2134 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
2135 if (count > 1 && !uniform.isArray())
2136 {
2137 context->validationError(GL_INVALID_OPERATION, kInvalidUniformCount);
2138 return false;
2139 }
2140
2141 *uniformOut = &uniform;
2142 return true;
2143 }
2144
ValidateUniform1ivValue(Context * context,GLenum uniformType,GLsizei count,const GLint * value)2145 bool ValidateUniform1ivValue(Context *context,
2146 GLenum uniformType,
2147 GLsizei count,
2148 const GLint *value)
2149 {
2150 // Value type is GL_INT, because we only get here from glUniform1i{v}.
2151 // It is compatible with INT or BOOL.
2152 // Do these cheap tests first, for a little extra speed.
2153 if (GL_INT == uniformType || GL_BOOL == uniformType)
2154 {
2155 return true;
2156 }
2157
2158 if (IsSamplerType(uniformType))
2159 {
2160 // Check that the values are in range.
2161 const GLint max = context->getCaps().maxCombinedTextureImageUnits;
2162 for (GLsizei i = 0; i < count; ++i)
2163 {
2164 if (value[i] < 0 || value[i] >= max)
2165 {
2166 context->validationError(GL_INVALID_VALUE, kSamplerUniformValueOutOfRange);
2167 return false;
2168 }
2169 }
2170 return true;
2171 }
2172
2173 context->validationError(GL_INVALID_OPERATION, kUniformTypeMismatch);
2174 return false;
2175 }
2176
ValidateUniformMatrixValue(Context * context,GLenum valueType,GLenum uniformType)2177 bool ValidateUniformMatrixValue(Context *context, GLenum valueType, GLenum uniformType)
2178 {
2179 // Check that the value type is compatible with uniform type.
2180 if (valueType == uniformType)
2181 {
2182 return true;
2183 }
2184
2185 context->validationError(GL_INVALID_OPERATION, kUniformTypeMismatch);
2186 return false;
2187 }
2188
ValidateUniform(Context * context,GLenum valueType,GLint location,GLsizei count)2189 bool ValidateUniform(Context *context, GLenum valueType, GLint location, GLsizei count)
2190 {
2191 const LinkedUniform *uniform = nullptr;
2192 Program *programObject = context->getState().getLinkedProgram(context);
2193 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2194 ValidateUniformValue(context, valueType, uniform->type);
2195 }
2196
ValidateUniform1iv(Context * context,GLint location,GLsizei count,const GLint * value)2197 bool ValidateUniform1iv(Context *context, GLint location, GLsizei count, const GLint *value)
2198 {
2199 const LinkedUniform *uniform = nullptr;
2200 Program *programObject = context->getState().getLinkedProgram(context);
2201 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2202 ValidateUniform1ivValue(context, uniform->type, count, value);
2203 }
2204
ValidateUniformMatrix(Context * context,GLenum valueType,GLint location,GLsizei count,GLboolean transpose)2205 bool ValidateUniformMatrix(Context *context,
2206 GLenum valueType,
2207 GLint location,
2208 GLsizei count,
2209 GLboolean transpose)
2210 {
2211 if (ConvertToBool(transpose) && context->getClientMajorVersion() < 3)
2212 {
2213 context->validationError(GL_INVALID_VALUE, kES3Required);
2214 return false;
2215 }
2216
2217 const LinkedUniform *uniform = nullptr;
2218 Program *programObject = context->getState().getLinkedProgram(context);
2219 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2220 ValidateUniformMatrixValue(context, valueType, uniform->type);
2221 }
2222
ValidateStateQuery(Context * context,GLenum pname,GLenum * nativeType,unsigned int * numParams)2223 bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
2224 {
2225 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
2226 {
2227 context->validationError(GL_INVALID_ENUM, kInvalidPname);
2228 return false;
2229 }
2230
2231 const Caps &caps = context->getCaps();
2232
2233 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
2234 {
2235 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
2236
2237 if (colorAttachment >= caps.maxDrawBuffers)
2238 {
2239 context->validationError(GL_INVALID_OPERATION, kIndexExceedsMaxDrawBuffer);
2240 return false;
2241 }
2242 }
2243
2244 switch (pname)
2245 {
2246 case GL_TEXTURE_BINDING_2D:
2247 case GL_TEXTURE_BINDING_CUBE_MAP:
2248 case GL_TEXTURE_BINDING_3D:
2249 case GL_TEXTURE_BINDING_2D_ARRAY:
2250 case GL_TEXTURE_BINDING_2D_MULTISAMPLE:
2251 break;
2252 case GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY:
2253 if (!context->getExtensions().textureStorageMultisample2DArray)
2254 {
2255 context->validationError(GL_INVALID_ENUM, kMultisampleArrayExtensionRequired);
2256 return false;
2257 }
2258 break;
2259 case GL_TEXTURE_BINDING_RECTANGLE_ANGLE:
2260 if (!context->getExtensions().textureRectangle)
2261 {
2262 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
2263 return false;
2264 }
2265 break;
2266 case GL_TEXTURE_BINDING_EXTERNAL_OES:
2267 if (!context->getExtensions().eglStreamConsumerExternal &&
2268 !context->getExtensions().eglImageExternal)
2269 {
2270 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
2271 return false;
2272 }
2273 break;
2274
2275 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
2276 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
2277 {
2278 Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
2279 ASSERT(readFramebuffer);
2280
2281 if (!ValidateFramebufferComplete<GL_INVALID_OPERATION>(context, readFramebuffer))
2282 {
2283 return false;
2284 }
2285
2286 if (readFramebuffer->getReadBufferState() == GL_NONE)
2287 {
2288 context->validationError(GL_INVALID_OPERATION, kReadBufferNone);
2289 return false;
2290 }
2291
2292 const FramebufferAttachment *attachment = readFramebuffer->getReadColorAttachment();
2293 if (!attachment)
2294 {
2295 context->validationError(GL_INVALID_OPERATION, kReadBufferNotAttached);
2296 return false;
2297 }
2298 }
2299 break;
2300
2301 default:
2302 break;
2303 }
2304
2305 // pname is valid, but there are no parameters to return
2306 if (*numParams == 0)
2307 {
2308 return false;
2309 }
2310
2311 return true;
2312 }
2313
ValidateGetBooleanvRobustANGLE(Context * context,GLenum pname,GLsizei bufSize,GLsizei * length,GLboolean * params)2314 bool ValidateGetBooleanvRobustANGLE(Context *context,
2315 GLenum pname,
2316 GLsizei bufSize,
2317 GLsizei *length,
2318 GLboolean *params)
2319 {
2320 GLenum nativeType;
2321 unsigned int numParams = 0;
2322
2323 if (!ValidateRobustStateQuery(context, pname, bufSize, &nativeType, &numParams))
2324 {
2325 return false;
2326 }
2327
2328 SetRobustLengthParam(length, numParams);
2329
2330 return true;
2331 }
2332
ValidateGetFloatvRobustANGLE(Context * context,GLenum pname,GLsizei bufSize,GLsizei * length,GLfloat * params)2333 bool ValidateGetFloatvRobustANGLE(Context *context,
2334 GLenum pname,
2335 GLsizei bufSize,
2336 GLsizei *length,
2337 GLfloat *params)
2338 {
2339 GLenum nativeType;
2340 unsigned int numParams = 0;
2341
2342 if (!ValidateRobustStateQuery(context, pname, bufSize, &nativeType, &numParams))
2343 {
2344 return false;
2345 }
2346
2347 SetRobustLengthParam(length, numParams);
2348
2349 return true;
2350 }
2351
ValidateGetIntegervRobustANGLE(Context * context,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * data)2352 bool ValidateGetIntegervRobustANGLE(Context *context,
2353 GLenum pname,
2354 GLsizei bufSize,
2355 GLsizei *length,
2356 GLint *data)
2357 {
2358 GLenum nativeType;
2359 unsigned int numParams = 0;
2360
2361 if (!ValidateRobustStateQuery(context, pname, bufSize, &nativeType, &numParams))
2362 {
2363 return false;
2364 }
2365
2366 SetRobustLengthParam(length, numParams);
2367
2368 return true;
2369 }
2370
ValidateGetInteger64vRobustANGLE(Context * context,GLenum pname,GLsizei bufSize,GLsizei * length,GLint64 * data)2371 bool ValidateGetInteger64vRobustANGLE(Context *context,
2372 GLenum pname,
2373 GLsizei bufSize,
2374 GLsizei *length,
2375 GLint64 *data)
2376 {
2377 GLenum nativeType;
2378 unsigned int numParams = 0;
2379
2380 if (!ValidateRobustStateQuery(context, pname, bufSize, &nativeType, &numParams))
2381 {
2382 return false;
2383 }
2384
2385 if (nativeType == GL_INT_64_ANGLEX)
2386 {
2387 CastStateValues(context, nativeType, pname, numParams, data);
2388 return false;
2389 }
2390
2391 SetRobustLengthParam(length, numParams);
2392 return true;
2393 }
2394
ValidateRobustStateQuery(Context * context,GLenum pname,GLsizei bufSize,GLenum * nativeType,unsigned int * numParams)2395 bool ValidateRobustStateQuery(Context *context,
2396 GLenum pname,
2397 GLsizei bufSize,
2398 GLenum *nativeType,
2399 unsigned int *numParams)
2400 {
2401 if (!ValidateRobustEntryPoint(context, bufSize))
2402 {
2403 return false;
2404 }
2405
2406 if (!ValidateStateQuery(context, pname, nativeType, numParams))
2407 {
2408 return false;
2409 }
2410
2411 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
2412 {
2413 return false;
2414 }
2415
2416 return true;
2417 }
2418
ValidateCopyTexImageParametersBase(Context * context,TextureTarget target,GLint level,GLenum internalformat,bool isSubImage,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,GLint border,Format * textureFormatOut)2419 bool ValidateCopyTexImageParametersBase(Context *context,
2420 TextureTarget target,
2421 GLint level,
2422 GLenum internalformat,
2423 bool isSubImage,
2424 GLint xoffset,
2425 GLint yoffset,
2426 GLint zoffset,
2427 GLint x,
2428 GLint y,
2429 GLsizei width,
2430 GLsizei height,
2431 GLint border,
2432 Format *textureFormatOut)
2433 {
2434 TextureType texType = TextureTargetToType(target);
2435
2436 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
2437 {
2438 context->validationError(GL_INVALID_VALUE, kNegativeOffset);
2439 return false;
2440 }
2441
2442 if (width < 0 || height < 0)
2443 {
2444 context->validationError(GL_INVALID_VALUE, kNegativeSize);
2445 return false;
2446 }
2447
2448 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
2449 std::numeric_limits<GLsizei>::max() - yoffset < height)
2450 {
2451 context->validationError(GL_INVALID_VALUE, kOffsetOverflow);
2452 return false;
2453 }
2454
2455 if (border != 0)
2456 {
2457 context->validationError(GL_INVALID_VALUE, kInvalidBorder);
2458 return false;
2459 }
2460
2461 if (!ValidMipLevel(context, texType, level))
2462 {
2463 context->validationError(GL_INVALID_VALUE, kInvalidMipLevel);
2464 return false;
2465 }
2466
2467 const State &state = context->getState();
2468 Framebuffer *readFramebuffer = state.getReadFramebuffer();
2469 if (!ValidateFramebufferComplete(context, readFramebuffer))
2470 {
2471 return false;
2472 }
2473
2474 if (readFramebuffer->id() != 0 && !ValidateFramebufferNotMultisampled(context, readFramebuffer))
2475 {
2476 return false;
2477 }
2478
2479 if (readFramebuffer->getReadBufferState() == GL_NONE)
2480 {
2481 context->validationError(GL_INVALID_OPERATION, kReadBufferNone);
2482 return false;
2483 }
2484
2485 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
2486 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
2487 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
2488 // situation is an application error that would lead to a crash in ANGLE.
2489 const FramebufferAttachment *source = readFramebuffer->getReadColorAttachment();
2490 if (source == nullptr)
2491 {
2492 context->validationError(GL_INVALID_OPERATION, kMissingReadAttachment);
2493 return false;
2494 }
2495
2496 // ANGLE_multiview spec, Revision 1:
2497 // Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an
2498 // INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the current read framebuffer
2499 // is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views in the current read
2500 // framebuffer is more than one.
2501 if (readFramebuffer->readDisallowedByMultiview())
2502 {
2503 context->validationError(GL_INVALID_FRAMEBUFFER_OPERATION, kMultiviewReadFramebuffer);
2504 return false;
2505 }
2506
2507 const Caps &caps = context->getCaps();
2508
2509 GLuint maxDimension = 0;
2510 switch (texType)
2511 {
2512 case TextureType::_2D:
2513 maxDimension = caps.max2DTextureSize;
2514 break;
2515
2516 case TextureType::CubeMap:
2517 maxDimension = caps.maxCubeMapTextureSize;
2518 break;
2519
2520 case TextureType::Rectangle:
2521 maxDimension = caps.maxRectangleTextureSize;
2522 break;
2523
2524 case TextureType::_2DArray:
2525 maxDimension = caps.max2DTextureSize;
2526 break;
2527
2528 case TextureType::_3D:
2529 maxDimension = caps.max3DTextureSize;
2530 break;
2531
2532 default:
2533 context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
2534 return false;
2535 }
2536
2537 Texture *texture = state.getTargetTexture(texType);
2538 if (!texture)
2539 {
2540 context->validationError(GL_INVALID_OPERATION, kTextureNotBound);
2541 return false;
2542 }
2543
2544 if (texture->getImmutableFormat() && !isSubImage)
2545 {
2546 context->validationError(GL_INVALID_OPERATION, kTextureIsImmutable);
2547 return false;
2548 }
2549
2550 const InternalFormat &formatInfo =
2551 isSubImage ? *texture->getFormat(target, level).info
2552 : GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
2553
2554 if (formatInfo.depthBits > 0 || formatInfo.compressed)
2555 {
2556 context->validationError(GL_INVALID_OPERATION, kInvalidFormat);
2557 return false;
2558 }
2559
2560 if (isSubImage)
2561 {
2562 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
2563 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
2564 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
2565 {
2566 context->validationError(GL_INVALID_VALUE, kOffsetOverflow);
2567 return false;
2568 }
2569 }
2570 else
2571 {
2572 if (texType == TextureType::CubeMap && width != height)
2573 {
2574 context->validationError(GL_INVALID_VALUE, kCubemapIncomplete);
2575 return false;
2576 }
2577
2578 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
2579 {
2580 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
2581 return false;
2582 }
2583
2584 int maxLevelDimension = (maxDimension >> level);
2585 if (static_cast<int>(width) > maxLevelDimension ||
2586 static_cast<int>(height) > maxLevelDimension)
2587 {
2588 context->validationError(GL_INVALID_VALUE, kResourceMaxTextureSize);
2589 return false;
2590 }
2591 }
2592
2593 if (textureFormatOut)
2594 {
2595 *textureFormatOut = texture->getFormat(target, level);
2596 }
2597
2598 // Detect texture copying feedback loops for WebGL.
2599 if (context->getExtensions().webglCompatibility)
2600 {
2601 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
2602 {
2603 context->validationError(GL_INVALID_OPERATION, kFeedbackLoop);
2604 return false;
2605 }
2606 }
2607
2608 return true;
2609 }
2610
2611 // Note all errors returned from this function are INVALID_OPERATION except for the draw framebuffer
2612 // completeness check.
ValidateDrawStates(Context * context)2613 const char *ValidateDrawStates(Context *context)
2614 {
2615 const Extensions &extensions = context->getExtensions();
2616 const State &state = context->getState();
2617
2618 // WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange,
2619 // and UnmapBuffer entry points are removed from the WebGL 2.0 API.
2620 // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
2621 VertexArray *vertexArray = state.getVertexArray();
2622 ASSERT(vertexArray);
2623
2624 if (!extensions.webglCompatibility && vertexArray->hasMappedEnabledArrayBuffer())
2625 {
2626 return kBufferMapped;
2627 }
2628
2629 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
2630 // Section 6.10 of the WebGL 1.0 spec.
2631 Framebuffer *framebuffer = state.getDrawFramebuffer();
2632 ASSERT(framebuffer);
2633
2634 if (context->getLimitations().noSeparateStencilRefsAndMasks || extensions.webglCompatibility)
2635 {
2636 ASSERT(framebuffer);
2637 const FramebufferAttachment *dsAttachment =
2638 framebuffer->getStencilOrDepthStencilAttachment();
2639 const GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
2640 ASSERT(stencilBits <= 8);
2641
2642 const DepthStencilState &depthStencilState = state.getDepthStencilState();
2643 if (depthStencilState.stencilTest && stencilBits > 0)
2644 {
2645 GLuint maxStencilValue = (1 << stencilBits) - 1;
2646
2647 bool differentRefs =
2648 clamp(state.getStencilRef(), 0, static_cast<GLint>(maxStencilValue)) !=
2649 clamp(state.getStencilBackRef(), 0, static_cast<GLint>(maxStencilValue));
2650 bool differentWritemasks = (depthStencilState.stencilWritemask & maxStencilValue) !=
2651 (depthStencilState.stencilBackWritemask & maxStencilValue);
2652 bool differentMasks = (depthStencilState.stencilMask & maxStencilValue) !=
2653 (depthStencilState.stencilBackMask & maxStencilValue);
2654
2655 if (differentRefs || differentWritemasks || differentMasks)
2656 {
2657 if (!extensions.webglCompatibility)
2658 {
2659 WARN() << "This ANGLE implementation does not support separate front/back "
2660 "stencil writemasks, reference values, or stencil mask values.";
2661 }
2662 return kStencilReferenceMaskOrMismatch;
2663 }
2664 }
2665 }
2666
2667 if (!extensions.floatBlend && context->getState().isBlendEnabled() &&
2668 framebuffer->hasActiveFloat32ColorAttachment())
2669 {
2670 return kUnsupportedFloatBlending;
2671 }
2672
2673 if (!framebuffer->isComplete(context))
2674 {
2675 // Note: this error should be generated as INVALID_FRAMEBUFFER_OPERATION.
2676 return kDrawFramebufferIncomplete;
2677 }
2678
2679 if (context->getStateCache().hasAnyEnabledClientAttrib())
2680 {
2681 if (context->getExtensions().webglCompatibility || !state.areClientArraysEnabled())
2682 {
2683 // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking
2684 // If a vertex attribute is enabled as an array via enableVertexAttribArray but no
2685 // buffer is bound to that attribute via bindBuffer and vertexAttribPointer, then calls
2686 // to drawArrays or drawElements will generate an INVALID_OPERATION error.
2687 return kVertexArrayNoBuffer;
2688 }
2689
2690 if (state.getVertexArray()->hasEnabledNullPointerClientArray())
2691 {
2692 // This is an application error that would normally result in a crash, but we catch it
2693 // and return an error
2694 return kVertexArrayNoBufferPointer;
2695 }
2696 }
2697
2698 // If we are running GLES1, there is no current program.
2699 if (context->getClientVersion() >= Version(2, 0))
2700 {
2701 Program *program = state.getLinkedProgram(context);
2702 if (!program)
2703 {
2704 return kProgramNotBound;
2705 }
2706
2707 // In OpenGL ES spec for UseProgram at section 7.3, trying to render without
2708 // vertex shader stage or fragment shader stage is a undefined behaviour.
2709 // But ANGLE should clearly generate an INVALID_OPERATION error instead of
2710 // produce undefined result.
2711 if (!program->hasLinkedShaderStage(ShaderType::Vertex) ||
2712 !program->hasLinkedShaderStage(ShaderType::Fragment))
2713 {
2714 return kNoActiveGraphicsShaderStage;
2715 }
2716
2717 if (!program->validateSamplers(nullptr, context->getCaps()))
2718 {
2719 return kTextureTypeConflict;
2720 }
2721
2722 if (extensions.multiview || extensions.multiview2)
2723 {
2724 const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1;
2725 const int framebufferNumViews = framebuffer->getNumViews();
2726 if (framebufferNumViews != programNumViews)
2727 {
2728 return kMultiviewMismatch;
2729 }
2730
2731 if (state.isTransformFeedbackActiveUnpaused() && framebufferNumViews > 1)
2732 {
2733 return kMultiviewTransformFeedback;
2734 }
2735
2736 if (extensions.disjointTimerQuery && framebufferNumViews > 1 &&
2737 state.isQueryActive(QueryType::TimeElapsed))
2738 {
2739 return kMultiviewTimerQuery;
2740 }
2741 }
2742
2743 // Uniform buffer validation
2744 for (unsigned int uniformBlockIndex = 0;
2745 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
2746 {
2747 const InterfaceBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
2748 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
2749 const OffsetBindingPointer<Buffer> &uniformBuffer =
2750 state.getIndexedUniformBuffer(blockBinding);
2751
2752 if (uniformBuffer.get() == nullptr)
2753 {
2754 // undefined behaviour
2755 return kUniformBufferUnbound;
2756 }
2757
2758 size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
2759 if (uniformBufferSize < uniformBlock.dataSize)
2760 {
2761 // undefined behaviour
2762 return kUniformBufferTooSmall;
2763 }
2764
2765 if (extensions.webglCompatibility &&
2766 uniformBuffer->isBoundForTransformFeedbackAndOtherUse())
2767 {
2768 return kUniformBufferBoundForTransformFeedback;
2769 }
2770 }
2771
2772 // Do some additonal WebGL-specific validation
2773 if (extensions.webglCompatibility)
2774 {
2775 if (!state.validateSamplerFormats())
2776 {
2777 return kSamplerFormatMismatch;
2778 }
2779
2780 const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
2781 if (state.isTransformFeedbackActive() &&
2782 transformFeedbackObject->buffersBoundForOtherUse())
2783 {
2784 return kTransformFeedbackBufferDoubleBound;
2785 }
2786
2787 // Detect rendering feedback loops for WebGL.
2788 if (framebuffer->formsRenderingFeedbackLoopWith(context))
2789 {
2790 return kFeedbackLoop;
2791 }
2792
2793 // Detect that the vertex shader input types match the attribute types
2794 if (!ValidateVertexShaderAttributeTypeMatch(context))
2795 {
2796 return kVertexShaderTypeMismatch;
2797 }
2798
2799 if (!context->getState().getRasterizerState().rasterizerDiscard &&
2800 !context->getState().getBlendState().allChannelsMasked())
2801 {
2802 // Detect that if there's active color buffer without fragment shader output
2803 if (!ValidateFragmentShaderColorBufferMaskMatch(context))
2804 {
2805 return kDrawBufferMaskMismatch;
2806 }
2807
2808 // Detect that the color buffer types match the fragment shader output types
2809 if (!ValidateFragmentShaderColorBufferTypeMatch(context))
2810 {
2811 return kDrawBufferTypeMismatch;
2812 }
2813 }
2814
2815 const VertexArray *vao = context->getState().getVertexArray();
2816 if (vao->hasTransformFeedbackBindingConflict(context))
2817 {
2818 return kVertexBufferBoundForTransformFeedback;
2819 }
2820 }
2821 }
2822
2823 return nullptr;
2824 }
2825
RecordDrawModeError(Context * context,PrimitiveMode mode)2826 void RecordDrawModeError(Context *context, PrimitiveMode mode)
2827 {
2828 const State &state = context->getState();
2829 TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
2830 if (state.isTransformFeedbackActiveUnpaused())
2831 {
2832 if (!ValidateTransformFeedbackPrimitiveMode(context,
2833 curTransformFeedback->getPrimitiveMode(), mode))
2834 {
2835 context->validationError(GL_INVALID_OPERATION, kInvalidDrawModeTransformFeedback);
2836 return;
2837 }
2838 }
2839
2840 const Extensions &extensions = context->getExtensions();
2841
2842 switch (mode)
2843 {
2844 case PrimitiveMode::Points:
2845 case PrimitiveMode::Lines:
2846 case PrimitiveMode::LineLoop:
2847 case PrimitiveMode::LineStrip:
2848 case PrimitiveMode::Triangles:
2849 case PrimitiveMode::TriangleStrip:
2850 case PrimitiveMode::TriangleFan:
2851 break;
2852
2853 case PrimitiveMode::LinesAdjacency:
2854 case PrimitiveMode::LineStripAdjacency:
2855 case PrimitiveMode::TrianglesAdjacency:
2856 case PrimitiveMode::TriangleStripAdjacency:
2857 if (!extensions.geometryShader)
2858 {
2859 context->validationError(GL_INVALID_ENUM, kGeometryShaderExtensionNotEnabled);
2860 return;
2861 }
2862 break;
2863 default:
2864 context->validationError(GL_INVALID_ENUM, kInvalidDrawMode);
2865 return;
2866 }
2867
2868 // If we are running GLES1, there is no current program.
2869 if (context->getClientVersion() >= Version(2, 0))
2870 {
2871 Program *program = state.getLinkedProgram(context);
2872 ASSERT(program);
2873
2874 // Do geometry shader specific validations
2875 if (program->hasLinkedShaderStage(ShaderType::Geometry))
2876 {
2877 if (!IsCompatibleDrawModeWithGeometryShader(
2878 mode, program->getGeometryShaderInputPrimitiveType()))
2879 {
2880 context->validationError(GL_INVALID_OPERATION,
2881 kIncompatibleDrawModeAgainstGeometryShader);
2882 return;
2883 }
2884 }
2885 }
2886
2887 // An error should be recorded.
2888 UNREACHABLE();
2889 }
2890
ValidateDrawArraysInstancedANGLE(Context * context,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)2891 bool ValidateDrawArraysInstancedANGLE(Context *context,
2892 PrimitiveMode mode,
2893 GLint first,
2894 GLsizei count,
2895 GLsizei primcount)
2896 {
2897 if (!context->getExtensions().instancedArraysANGLE)
2898 {
2899 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
2900 return false;
2901 }
2902
2903 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
2904 {
2905 return false;
2906 }
2907
2908 return ValidateDrawInstancedANGLE(context);
2909 }
2910
ValidateDrawArraysInstancedEXT(Context * context,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)2911 bool ValidateDrawArraysInstancedEXT(Context *context,
2912 PrimitiveMode mode,
2913 GLint first,
2914 GLsizei count,
2915 GLsizei primcount)
2916 {
2917 if (!context->getExtensions().instancedArraysEXT)
2918 {
2919 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
2920 return false;
2921 }
2922
2923 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
2924 {
2925 return false;
2926 }
2927
2928 return true;
2929 }
2930
ValidateDrawElementsStates(Context * context)2931 const char *ValidateDrawElementsStates(Context *context)
2932 {
2933 const State &state = context->getState();
2934
2935 if (context->getStateCache().isTransformFeedbackActiveUnpaused())
2936 {
2937 // EXT_geometry_shader allows transform feedback to work with all draw commands.
2938 // [EXT_geometry_shader] Section 12.1, "Transform Feedback"
2939 if (!context->getExtensions().geometryShader)
2940 {
2941 // It is an invalid operation to call DrawElements, DrawRangeElements or
2942 // DrawElementsInstanced while transform feedback is active, (3.0.2, section 2.14, pg
2943 // 86)
2944 return kUnsupportedDrawModeForTransformFeedback;
2945 }
2946 }
2947
2948 const VertexArray *vao = state.getVertexArray();
2949 Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
2950
2951 if (elementArrayBuffer)
2952 {
2953 if (context->getExtensions().webglCompatibility)
2954 {
2955 if (elementArrayBuffer->isBoundForTransformFeedbackAndOtherUse())
2956 {
2957 return kElementArrayBufferBoundForTransformFeedback;
2958 }
2959 }
2960 else if (elementArrayBuffer->isMapped())
2961 {
2962 // WebGL buffers cannot be mapped/unmapped because the MapBufferRange,
2963 // FlushMappedBufferRange, and UnmapBuffer entry points are removed from the
2964 // WebGL 2.0 API. https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
2965 return kBufferMapped;
2966 }
2967 }
2968 else
2969 {
2970 // [WebGL 1.0] Section 6.2 No Client Side Arrays
2971 // If an indexed draw command (drawElements) is called and no WebGLBuffer is bound to
2972 // the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
2973 if (!context->getState().areClientArraysEnabled() ||
2974 context->getExtensions().webglCompatibility)
2975 {
2976 return kMustHaveElementArrayBinding;
2977 }
2978 }
2979
2980 return nullptr;
2981 }
2982
ValidateDrawElementsInstancedANGLE(Context * context,PrimitiveMode mode,GLsizei count,DrawElementsType type,const void * indices,GLsizei primcount)2983 bool ValidateDrawElementsInstancedANGLE(Context *context,
2984 PrimitiveMode mode,
2985 GLsizei count,
2986 DrawElementsType type,
2987 const void *indices,
2988 GLsizei primcount)
2989 {
2990 if (!context->getExtensions().instancedArraysANGLE)
2991 {
2992 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
2993 return false;
2994 }
2995
2996 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
2997 {
2998 return false;
2999 }
3000
3001 return ValidateDrawInstancedANGLE(context);
3002 }
3003
ValidateDrawElementsInstancedEXT(Context * context,PrimitiveMode mode,GLsizei count,DrawElementsType type,const void * indices,GLsizei primcount)3004 bool ValidateDrawElementsInstancedEXT(Context *context,
3005 PrimitiveMode mode,
3006 GLsizei count,
3007 DrawElementsType type,
3008 const void *indices,
3009 GLsizei primcount)
3010 {
3011 if (!context->getExtensions().instancedArraysEXT)
3012 {
3013 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
3014 return false;
3015 }
3016
3017 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
3018 {
3019 return false;
3020 }
3021
3022 return true;
3023 }
3024
ValidateFramebufferTextureBase(Context * context,GLenum target,GLenum attachment,TextureID texture,GLint level)3025 bool ValidateFramebufferTextureBase(Context *context,
3026 GLenum target,
3027 GLenum attachment,
3028 TextureID texture,
3029 GLint level)
3030 {
3031 if (!ValidFramebufferTarget(context, target))
3032 {
3033 context->validationError(GL_INVALID_ENUM, kInvalidFramebufferTarget);
3034 return false;
3035 }
3036
3037 if (!ValidateAttachmentTarget(context, attachment))
3038 {
3039 return false;
3040 }
3041
3042 if (texture.value != 0)
3043 {
3044 Texture *tex = context->getTexture(texture);
3045
3046 if (tex == nullptr)
3047 {
3048 context->validationError(GL_INVALID_OPERATION, kMissingTexture);
3049 return false;
3050 }
3051
3052 if (level < 0)
3053 {
3054 context->validationError(GL_INVALID_VALUE, kInvalidMipLevel);
3055 return false;
3056 }
3057 }
3058
3059 const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
3060 ASSERT(framebuffer);
3061
3062 if (framebuffer->id() == 0)
3063 {
3064 context->validationError(GL_INVALID_OPERATION, kDefaultFramebufferTarget);
3065 return false;
3066 }
3067
3068 return true;
3069 }
3070
ValidateGetUniformBase(Context * context,GLuint program,GLint location)3071 bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
3072 {
3073 if (program == 0)
3074 {
3075 context->validationError(GL_INVALID_VALUE, kProgramDoesNotExist);
3076 return false;
3077 }
3078
3079 Program *programObject = GetValidProgram(context, program);
3080 if (!programObject)
3081 {
3082 return false;
3083 }
3084
3085 if (!programObject || !programObject->isLinked())
3086 {
3087 context->validationError(GL_INVALID_OPERATION, kProgramNotLinked);
3088 return false;
3089 }
3090
3091 if (!programObject->isValidUniformLocation(location))
3092 {
3093 context->validationError(GL_INVALID_OPERATION, kInvalidUniformLocation);
3094 return false;
3095 }
3096
3097 return true;
3098 }
3099
ValidateSizedGetUniform(Context * context,GLuint program,GLint location,GLsizei bufSize,GLsizei * length)3100 static bool ValidateSizedGetUniform(Context *context,
3101 GLuint program,
3102 GLint location,
3103 GLsizei bufSize,
3104 GLsizei *length)
3105 {
3106 if (length)
3107 {
3108 *length = 0;
3109 }
3110
3111 if (!ValidateGetUniformBase(context, program, location))
3112 {
3113 return false;
3114 }
3115
3116 if (bufSize < 0)
3117 {
3118 context->validationError(GL_INVALID_VALUE, kNegativeBufferSize);
3119 return false;
3120 }
3121
3122 Program *programObject = context->getProgramResolveLink(program);
3123 ASSERT(programObject);
3124
3125 // sized queries -- ensure the provided buffer is large enough
3126 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
3127 size_t requiredBytes = VariableExternalSize(uniform.type);
3128 if (static_cast<size_t>(bufSize) < requiredBytes)
3129 {
3130 context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
3131 return false;
3132 }
3133
3134 if (length)
3135 {
3136 *length = VariableComponentCount(uniform.type);
3137 }
3138
3139 return true;
3140 }
3141
ValidateGetnUniformfvEXT(Context * context,GLuint program,GLint location,GLsizei bufSize,GLfloat * params)3142 bool ValidateGetnUniformfvEXT(Context *context,
3143 GLuint program,
3144 GLint location,
3145 GLsizei bufSize,
3146 GLfloat *params)
3147 {
3148 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
3149 }
3150
ValidateGetnUniformfvRobustANGLE(Context * context,GLuint program,GLint location,GLsizei bufSize,GLsizei * length,GLfloat * params)3151 bool ValidateGetnUniformfvRobustANGLE(Context *context,
3152 GLuint program,
3153 GLint location,
3154 GLsizei bufSize,
3155 GLsizei *length,
3156 GLfloat *params)
3157 {
3158 UNIMPLEMENTED();
3159 return false;
3160 }
3161
ValidateGetnUniformivEXT(Context * context,GLuint program,GLint location,GLsizei bufSize,GLint * params)3162 bool ValidateGetnUniformivEXT(Context *context,
3163 GLuint program,
3164 GLint location,
3165 GLsizei bufSize,
3166 GLint *params)
3167 {
3168 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
3169 }
3170
ValidateGetnUniformivRobustANGLE(Context * context,GLuint program,GLint location,GLsizei bufSize,GLsizei * length,GLint * params)3171 bool ValidateGetnUniformivRobustANGLE(Context *context,
3172 GLuint program,
3173 GLint location,
3174 GLsizei bufSize,
3175 GLsizei *length,
3176 GLint *params)
3177 {
3178 UNIMPLEMENTED();
3179 return false;
3180 }
3181
ValidateGetnUniformuivRobustANGLE(Context * context,GLuint program,GLint location,GLsizei bufSize,GLsizei * length,GLuint * params)3182 bool ValidateGetnUniformuivRobustANGLE(Context *context,
3183 GLuint program,
3184 GLint location,
3185 GLsizei bufSize,
3186 GLsizei *length,
3187 GLuint *params)
3188 {
3189 UNIMPLEMENTED();
3190 return false;
3191 }
3192
ValidateGetUniformfvRobustANGLE(Context * context,GLuint program,GLint location,GLsizei bufSize,GLsizei * length,GLfloat * params)3193 bool ValidateGetUniformfvRobustANGLE(Context *context,
3194 GLuint program,
3195 GLint location,
3196 GLsizei bufSize,
3197 GLsizei *length,
3198 GLfloat *params)
3199 {
3200 if (!ValidateRobustEntryPoint(context, bufSize))
3201 {
3202 return false;
3203 }
3204
3205 GLsizei writeLength = 0;
3206
3207 // bufSize is validated in ValidateSizedGetUniform
3208 if (!ValidateSizedGetUniform(context, program, location, bufSize, &writeLength))
3209 {
3210 return false;
3211 }
3212
3213 SetRobustLengthParam(length, writeLength);
3214
3215 return true;
3216 }
3217
ValidateGetUniformivRobustANGLE(Context * context,GLuint program,GLint location,GLsizei bufSize,GLsizei * length,GLint * params)3218 bool ValidateGetUniformivRobustANGLE(Context *context,
3219 GLuint program,
3220 GLint location,
3221 GLsizei bufSize,
3222 GLsizei *length,
3223 GLint *params)
3224 {
3225 if (!ValidateRobustEntryPoint(context, bufSize))
3226 {
3227 return false;
3228 }
3229
3230 GLsizei writeLength = 0;
3231
3232 // bufSize is validated in ValidateSizedGetUniform
3233 if (!ValidateSizedGetUniform(context, program, location, bufSize, &writeLength))
3234 {
3235 return false;
3236 }
3237
3238 SetRobustLengthParam(length, writeLength);
3239
3240 return true;
3241 }
3242
ValidateGetUniformuivRobustANGLE(Context * context,GLuint program,GLint location,GLsizei bufSize,GLsizei * length,GLuint * params)3243 bool ValidateGetUniformuivRobustANGLE(Context *context,
3244 GLuint program,
3245 GLint location,
3246 GLsizei bufSize,
3247 GLsizei *length,
3248 GLuint *params)
3249 {
3250 if (!ValidateRobustEntryPoint(context, bufSize))
3251 {
3252 return false;
3253 }
3254
3255 if (context->getClientMajorVersion() < 3)
3256 {
3257 context->validationError(GL_INVALID_OPERATION, kES3Required);
3258 return false;
3259 }
3260
3261 GLsizei writeLength = 0;
3262
3263 // bufSize is validated in ValidateSizedGetUniform
3264 if (!ValidateSizedGetUniform(context, program, location, bufSize, &writeLength))
3265 {
3266 return false;
3267 }
3268
3269 SetRobustLengthParam(length, writeLength);
3270
3271 return true;
3272 }
3273
ValidateDiscardFramebufferBase(Context * context,GLenum target,GLsizei numAttachments,const GLenum * attachments,bool defaultFramebuffer)3274 bool ValidateDiscardFramebufferBase(Context *context,
3275 GLenum target,
3276 GLsizei numAttachments,
3277 const GLenum *attachments,
3278 bool defaultFramebuffer)
3279 {
3280 if (numAttachments < 0)
3281 {
3282 context->validationError(GL_INVALID_VALUE, kNegativeAttachments);
3283 return false;
3284 }
3285
3286 for (GLsizei i = 0; i < numAttachments; ++i)
3287 {
3288 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
3289 {
3290 if (defaultFramebuffer)
3291 {
3292 context->validationError(GL_INVALID_ENUM, kDefaultFramebufferInvalidAttachment);
3293 return false;
3294 }
3295
3296 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
3297 {
3298 context->validationError(GL_INVALID_OPERATION, kExceedsMaxColorAttachments);
3299 return false;
3300 }
3301 }
3302 else
3303 {
3304 switch (attachments[i])
3305 {
3306 case GL_DEPTH_ATTACHMENT:
3307 case GL_STENCIL_ATTACHMENT:
3308 case GL_DEPTH_STENCIL_ATTACHMENT:
3309 if (defaultFramebuffer)
3310 {
3311 context->validationError(GL_INVALID_ENUM,
3312 kDefaultFramebufferInvalidAttachment);
3313 return false;
3314 }
3315 break;
3316 case GL_COLOR:
3317 case GL_DEPTH:
3318 case GL_STENCIL:
3319 if (!defaultFramebuffer)
3320 {
3321 context->validationError(GL_INVALID_ENUM,
3322 kDefaultFramebufferInvalidAttachment);
3323 return false;
3324 }
3325 break;
3326 default:
3327 context->validationError(GL_INVALID_ENUM, kInvalidAttachment);
3328 return false;
3329 }
3330 }
3331 }
3332
3333 return true;
3334 }
3335
ValidateInsertEventMarkerEXT(Context * context,GLsizei length,const char * marker)3336 bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
3337 {
3338 if (!context->getExtensions().debugMarker)
3339 {
3340 // The debug marker calls should not set error state
3341 // However, it seems reasonable to set an error state if the extension is not enabled
3342 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
3343 return false;
3344 }
3345
3346 // Note that debug marker calls must not set error state
3347 if (length < 0)
3348 {
3349 return false;
3350 }
3351
3352 if (marker == nullptr)
3353 {
3354 return false;
3355 }
3356
3357 return true;
3358 }
3359
ValidatePushGroupMarkerEXT(Context * context,GLsizei length,const char * marker)3360 bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
3361 {
3362 if (!context->getExtensions().debugMarker)
3363 {
3364 // The debug marker calls should not set error state
3365 // However, it seems reasonable to set an error state if the extension is not enabled
3366 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
3367 return false;
3368 }
3369
3370 // Note that debug marker calls must not set error state
3371 if (length < 0)
3372 {
3373 return false;
3374 }
3375
3376 if (length > 0 && marker == nullptr)
3377 {
3378 return false;
3379 }
3380
3381 return true;
3382 }
3383
ValidateEGLImageTargetTexture2DOES(Context * context,TextureType type,GLeglImageOES image)3384 bool ValidateEGLImageTargetTexture2DOES(Context *context, TextureType type, GLeglImageOES image)
3385 {
3386 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
3387 {
3388 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
3389 return false;
3390 }
3391
3392 switch (type)
3393 {
3394 case TextureType::_2D:
3395 if (!context->getExtensions().eglImage)
3396 {
3397 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
3398 }
3399 break;
3400
3401 case TextureType::External:
3402 if (!context->getExtensions().eglImageExternal)
3403 {
3404 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
3405 }
3406 break;
3407
3408 default:
3409 context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
3410 return false;
3411 }
3412
3413 egl::Image *imageObject = static_cast<egl::Image *>(image);
3414
3415 ASSERT(context->getDisplay());
3416 if (!context->getDisplay()->isValidImage(imageObject))
3417 {
3418 context->validationError(GL_INVALID_VALUE, kInvalidEGLImage);
3419 return false;
3420 }
3421
3422 if (imageObject->getSamples() > 0)
3423 {
3424 context->validationError(GL_INVALID_OPERATION, kEGLImageCannotCreate2DMultisampled);
3425 return false;
3426 }
3427
3428 if (!imageObject->isTexturable(context))
3429 {
3430 context->validationError(GL_INVALID_OPERATION, kEGLImageTextureFormatNotSupported);
3431 return false;
3432 }
3433
3434 return true;
3435 }
3436
ValidateEGLImageTargetRenderbufferStorageOES(Context * context,GLenum target,GLeglImageOES image)3437 bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
3438 GLenum target,
3439 GLeglImageOES image)
3440 {
3441 if (!context->getExtensions().eglImage)
3442 {
3443 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
3444 return false;
3445 }
3446
3447 switch (target)
3448 {
3449 case GL_RENDERBUFFER:
3450 break;
3451
3452 default:
3453 context->validationError(GL_INVALID_ENUM, kInvalidRenderbufferTarget);
3454 return false;
3455 }
3456
3457 egl::Image *imageObject = static_cast<egl::Image *>(image);
3458
3459 ASSERT(context->getDisplay());
3460 if (!context->getDisplay()->isValidImage(imageObject))
3461 {
3462 context->validationError(GL_INVALID_VALUE, kInvalidEGLImage);
3463 return false;
3464 }
3465
3466 if (!imageObject->isRenderable(context))
3467 {
3468 context->validationError(GL_INVALID_OPERATION, kEGLImageRenderbufferFormatNotSupported);
3469 return false;
3470 }
3471
3472 return true;
3473 }
3474
ValidateBindVertexArrayBase(Context * context,GLuint array)3475 bool ValidateBindVertexArrayBase(Context *context, GLuint array)
3476 {
3477 if (!context->isVertexArrayGenerated(array))
3478 {
3479 // The default VAO should always exist
3480 ASSERT(array != 0);
3481 context->validationError(GL_INVALID_OPERATION, kInvalidVertexArray);
3482 return false;
3483 }
3484
3485 return true;
3486 }
3487
ValidateProgramBinaryBase(Context * context,GLuint program,GLenum binaryFormat,const void * binary,GLint length)3488 bool ValidateProgramBinaryBase(Context *context,
3489 GLuint program,
3490 GLenum binaryFormat,
3491 const void *binary,
3492 GLint length)
3493 {
3494 Program *programObject = GetValidProgram(context, program);
3495 if (programObject == nullptr)
3496 {
3497 return false;
3498 }
3499
3500 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
3501 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
3502 programBinaryFormats.end())
3503 {
3504 context->validationError(GL_INVALID_ENUM, kInvalidProgramBinaryFormat);
3505 return false;
3506 }
3507
3508 if (context->hasActiveTransformFeedback(program))
3509 {
3510 // ES 3.0.4 section 2.15 page 91
3511 context->validationError(GL_INVALID_OPERATION, kTransformFeedbackProgramBinary);
3512 return false;
3513 }
3514
3515 return true;
3516 }
3517
ValidateGetProgramBinaryBase(Context * context,GLuint program,GLsizei bufSize,GLsizei * length,GLenum * binaryFormat,void * binary)3518 bool ValidateGetProgramBinaryBase(Context *context,
3519 GLuint program,
3520 GLsizei bufSize,
3521 GLsizei *length,
3522 GLenum *binaryFormat,
3523 void *binary)
3524 {
3525 Program *programObject = GetValidProgram(context, program);
3526 if (programObject == nullptr)
3527 {
3528 return false;
3529 }
3530
3531 if (!programObject->isLinked())
3532 {
3533 context->validationError(GL_INVALID_OPERATION, kProgramNotLinked);
3534 return false;
3535 }
3536
3537 if (context->getCaps().programBinaryFormats.empty())
3538 {
3539 context->validationError(GL_INVALID_OPERATION, kNoProgramBinaryFormats);
3540 return false;
3541 }
3542
3543 return true;
3544 }
3545
ValidateDrawBuffersBase(Context * context,GLsizei n,const GLenum * bufs)3546 bool ValidateDrawBuffersBase(Context *context, GLsizei n, const GLenum *bufs)
3547 {
3548 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
3549 if (n < 0)
3550 {
3551 context->validationError(GL_INVALID_VALUE, kNegativeCount);
3552 return false;
3553 }
3554 if (static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
3555 {
3556 context->validationError(GL_INVALID_VALUE, kIndexExceedsMaxDrawBuffer);
3557 return false;
3558 }
3559
3560 ASSERT(context->getState().getDrawFramebuffer());
3561 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
3562 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
3563
3564 // This should come first before the check for the default frame buffer
3565 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
3566 // rather than INVALID_OPERATION
3567 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
3568 {
3569 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
3570
3571 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
3572 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
3573 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
3574 {
3575 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
3576 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
3577 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
3578 // 3.1 is still a bit ambiguous about the error, but future specs are
3579 // expected to clarify that GL_INVALID_ENUM is the correct error.
3580 context->validationError(GL_INVALID_ENUM, kInvalidDrawBuffer);
3581 return false;
3582 }
3583 else if (bufs[colorAttachment] >= maxColorAttachment)
3584 {
3585 context->validationError(GL_INVALID_OPERATION, kExceedsMaxColorAttachments);
3586 return false;
3587 }
3588 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
3589 frameBufferId != 0)
3590 {
3591 // INVALID_OPERATION-GL is bound to buffer and ith argument
3592 // is not COLOR_ATTACHMENTi or NONE
3593 context->validationError(GL_INVALID_OPERATION, kInvalidDrawBufferValue);
3594 return false;
3595 }
3596 }
3597
3598 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
3599 // and n is not 1 or bufs is bound to value other than BACK and NONE
3600 if (frameBufferId == 0)
3601 {
3602 if (n != 1)
3603 {
3604 context->validationError(GL_INVALID_OPERATION, kInvalidDrawBufferCountForDefault);
3605 return false;
3606 }
3607
3608 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
3609 {
3610 context->validationError(GL_INVALID_OPERATION, kDefaultFramebufferInvalidDrawBuffer);
3611 return false;
3612 }
3613 }
3614
3615 return true;
3616 }
3617
ValidateGetBufferPointervBase(Context * context,BufferBinding target,GLenum pname,GLsizei * length,void ** params)3618 bool ValidateGetBufferPointervBase(Context *context,
3619 BufferBinding target,
3620 GLenum pname,
3621 GLsizei *length,
3622 void **params)
3623 {
3624 if (length)
3625 {
3626 *length = 0;
3627 }
3628
3629 if (!context->isValidBufferBinding(target))
3630 {
3631 context->validationError(GL_INVALID_ENUM, kInvalidBufferTypes);
3632 return false;
3633 }
3634
3635 switch (pname)
3636 {
3637 case GL_BUFFER_MAP_POINTER:
3638 break;
3639
3640 default:
3641 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
3642 return false;
3643 }
3644
3645 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
3646 // target bound to zero generate an INVALID_OPERATION error."
3647 // GLES 3.1 section 6.6 explicitly specifies this error.
3648 if (context->getState().getTargetBuffer(target) == nullptr)
3649 {
3650 context->validationError(GL_INVALID_OPERATION, kBufferPointerNotAvailable);
3651 return false;
3652 }
3653
3654 if (length)
3655 {
3656 *length = 1;
3657 }
3658
3659 return true;
3660 }
3661
ValidateUnmapBufferBase(Context * context,BufferBinding target)3662 bool ValidateUnmapBufferBase(Context *context, BufferBinding target)
3663 {
3664 if (!context->isValidBufferBinding(target))
3665 {
3666 context->validationError(GL_INVALID_ENUM, kInvalidBufferTypes);
3667 return false;
3668 }
3669
3670 Buffer *buffer = context->getState().getTargetBuffer(target);
3671
3672 if (buffer == nullptr || !buffer->isMapped())
3673 {
3674 context->validationError(GL_INVALID_OPERATION, kBufferNotMapped);
3675 return false;
3676 }
3677
3678 return true;
3679 }
3680
ValidateMapBufferRangeBase(Context * context,BufferBinding target,GLintptr offset,GLsizeiptr length,GLbitfield access)3681 bool ValidateMapBufferRangeBase(Context *context,
3682 BufferBinding target,
3683 GLintptr offset,
3684 GLsizeiptr length,
3685 GLbitfield access)
3686 {
3687 if (!context->isValidBufferBinding(target))
3688 {
3689 context->validationError(GL_INVALID_ENUM, kInvalidBufferTypes);
3690 return false;
3691 }
3692
3693 if (offset < 0)
3694 {
3695 context->validationError(GL_INVALID_VALUE, kNegativeOffset);
3696 return false;
3697 }
3698
3699 if (length < 0)
3700 {
3701 context->validationError(GL_INVALID_VALUE, kNegativeLength);
3702 return false;
3703 }
3704
3705 Buffer *buffer = context->getState().getTargetBuffer(target);
3706
3707 if (!buffer)
3708 {
3709 context->validationError(GL_INVALID_OPERATION, kBufferNotMappable);
3710 return false;
3711 }
3712
3713 // Check for buffer overflow
3714 CheckedNumeric<size_t> checkedOffset(offset);
3715 auto checkedSize = checkedOffset + length;
3716
3717 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
3718 {
3719 context->validationError(GL_INVALID_VALUE, kMapOutOfRange);
3720 return false;
3721 }
3722
3723 // Check for invalid bits in the mask
3724 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
3725 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
3726 GL_MAP_UNSYNCHRONIZED_BIT;
3727
3728 if (access & ~(allAccessBits))
3729 {
3730 context->validationError(GL_INVALID_VALUE, kInvalidAccessBits);
3731 return false;
3732 }
3733
3734 if (length == 0)
3735 {
3736 context->validationError(GL_INVALID_OPERATION, kLengthZero);
3737 return false;
3738 }
3739
3740 if (buffer->isMapped())
3741 {
3742 context->validationError(GL_INVALID_OPERATION, kBufferAlreadyMapped);
3743 return false;
3744 }
3745
3746 // Check for invalid bit combinations
3747 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
3748 {
3749 context->validationError(GL_INVALID_OPERATION, kInvalidAccessBitsReadWrite);
3750 return false;
3751 }
3752
3753 GLbitfield writeOnlyBits =
3754 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
3755
3756 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
3757 {
3758 context->validationError(GL_INVALID_OPERATION, kInvalidAccessBitsRead);
3759 return false;
3760 }
3761
3762 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
3763 {
3764 context->validationError(GL_INVALID_OPERATION, kInvalidAccessBitsFlush);
3765 return false;
3766 }
3767
3768 return ValidateMapBufferBase(context, target);
3769 }
3770
ValidateFlushMappedBufferRangeBase(Context * context,BufferBinding target,GLintptr offset,GLsizeiptr length)3771 bool ValidateFlushMappedBufferRangeBase(Context *context,
3772 BufferBinding target,
3773 GLintptr offset,
3774 GLsizeiptr length)
3775 {
3776 if (offset < 0)
3777 {
3778 context->validationError(GL_INVALID_VALUE, kNegativeOffset);
3779 return false;
3780 }
3781
3782 if (length < 0)
3783 {
3784 context->validationError(GL_INVALID_VALUE, kNegativeLength);
3785 return false;
3786 }
3787
3788 if (!context->isValidBufferBinding(target))
3789 {
3790 context->validationError(GL_INVALID_ENUM, kInvalidBufferTypes);
3791 return false;
3792 }
3793
3794 Buffer *buffer = context->getState().getTargetBuffer(target);
3795
3796 if (buffer == nullptr)
3797 {
3798 context->validationError(GL_INVALID_OPERATION, kInvalidFlushZero);
3799 return false;
3800 }
3801
3802 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
3803 {
3804 context->validationError(GL_INVALID_OPERATION, kInvalidFlushTarget);
3805 return false;
3806 }
3807
3808 // Check for buffer overflow
3809 CheckedNumeric<size_t> checkedOffset(offset);
3810 auto checkedSize = checkedOffset + length;
3811
3812 if (!checkedSize.IsValid() ||
3813 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
3814 {
3815 context->validationError(GL_INVALID_VALUE, kInvalidFlushOutOfRange);
3816 return false;
3817 }
3818
3819 return true;
3820 }
3821
ValidateGenOrDelete(Context * context,GLint n)3822 bool ValidateGenOrDelete(Context *context, GLint n)
3823 {
3824 if (n < 0)
3825 {
3826 context->validationError(GL_INVALID_VALUE, kNegativeCount);
3827 return false;
3828 }
3829 return true;
3830 }
3831
ValidateRobustEntryPoint(Context * context,GLsizei bufSize)3832 bool ValidateRobustEntryPoint(Context *context, GLsizei bufSize)
3833 {
3834 if (!context->getExtensions().robustClientMemory)
3835 {
3836 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
3837 return false;
3838 }
3839
3840 if (bufSize < 0)
3841 {
3842 context->validationError(GL_INVALID_VALUE, kNegativeBufferSize);
3843 return false;
3844 }
3845
3846 return true;
3847 }
3848
ValidateRobustBufferSize(Context * context,GLsizei bufSize,GLsizei numParams)3849 bool ValidateRobustBufferSize(Context *context, GLsizei bufSize, GLsizei numParams)
3850 {
3851 if (bufSize < numParams)
3852 {
3853 context->validationError(GL_INVALID_OPERATION, kInsufficientParams);
3854 return false;
3855 }
3856
3857 return true;
3858 }
3859
ValidateGetFramebufferAttachmentParameterivBase(Context * context,GLenum target,GLenum attachment,GLenum pname,GLsizei * numParams)3860 bool ValidateGetFramebufferAttachmentParameterivBase(Context *context,
3861 GLenum target,
3862 GLenum attachment,
3863 GLenum pname,
3864 GLsizei *numParams)
3865 {
3866 if (!ValidFramebufferTarget(context, target))
3867 {
3868 context->validationError(GL_INVALID_ENUM, kInvalidFramebufferTarget);
3869 return false;
3870 }
3871
3872 int clientVersion = context->getClientMajorVersion();
3873
3874 switch (pname)
3875 {
3876 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3877 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3878 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3879 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3880 break;
3881
3882 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR:
3883 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR:
3884 if (clientVersion < 3 ||
3885 !(context->getExtensions().multiview || context->getExtensions().multiview2))
3886 {
3887 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
3888 return false;
3889 }
3890 break;
3891
3892 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
3893 if (clientVersion < 3 && !context->getExtensions().sRGB)
3894 {
3895 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
3896 return false;
3897 }
3898 break;
3899
3900 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
3901 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
3902 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
3903 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
3904 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
3905 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
3906 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
3907 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
3908 if (clientVersion < 3)
3909 {
3910 context->validationError(GL_INVALID_ENUM, kES3Required);
3911 return false;
3912 }
3913 break;
3914
3915 case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT:
3916 if (!context->getExtensions().geometryShader)
3917 {
3918 context->validationError(GL_INVALID_ENUM, kGeometryShaderExtensionNotEnabled);
3919 return false;
3920 }
3921 break;
3922
3923 default:
3924 context->validationError(GL_INVALID_ENUM, kInvalidPname);
3925 return false;
3926 }
3927
3928 // Determine if the attachment is a valid enum
3929 switch (attachment)
3930 {
3931 case GL_BACK:
3932 case GL_DEPTH:
3933 case GL_STENCIL:
3934 if (clientVersion < 3)
3935 {
3936 context->validationError(GL_INVALID_ENUM, kInvalidAttachment);
3937 return false;
3938 }
3939 break;
3940
3941 case GL_DEPTH_STENCIL_ATTACHMENT:
3942 if (clientVersion < 3 && !context->isWebGL1())
3943 {
3944 context->validationError(GL_INVALID_ENUM, kInvalidAttachment);
3945 return false;
3946 }
3947 break;
3948
3949 case GL_COLOR_ATTACHMENT0:
3950 case GL_DEPTH_ATTACHMENT:
3951 case GL_STENCIL_ATTACHMENT:
3952 break;
3953
3954 default:
3955 if ((clientVersion < 3 && !context->getExtensions().drawBuffers) ||
3956 attachment < GL_COLOR_ATTACHMENT0_EXT ||
3957 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
3958 {
3959 context->validationError(GL_INVALID_ENUM, kInvalidAttachment);
3960 return false;
3961 }
3962 break;
3963 }
3964
3965 const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
3966 ASSERT(framebuffer);
3967
3968 if (framebuffer->id() == 0)
3969 {
3970 if (clientVersion < 3)
3971 {
3972 context->validationError(GL_INVALID_OPERATION, kDefaultFramebufferTarget);
3973 return false;
3974 }
3975
3976 switch (attachment)
3977 {
3978 case GL_BACK:
3979 case GL_DEPTH:
3980 case GL_STENCIL:
3981 break;
3982
3983 default:
3984 context->validationError(GL_INVALID_OPERATION, kInvalidAttachment);
3985 return false;
3986 }
3987 }
3988 else
3989 {
3990 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
3991 {
3992 // Valid attachment query
3993 }
3994 else
3995 {
3996 switch (attachment)
3997 {
3998 case GL_DEPTH_ATTACHMENT:
3999 case GL_STENCIL_ATTACHMENT:
4000 break;
4001
4002 case GL_DEPTH_STENCIL_ATTACHMENT:
4003 if (!framebuffer->hasValidDepthStencil() && !context->isWebGL1())
4004 {
4005 context->validationError(GL_INVALID_OPERATION, kInvalidAttachment);
4006 return false;
4007 }
4008 break;
4009
4010 default:
4011 context->validationError(GL_INVALID_OPERATION, kInvalidAttachment);
4012 return false;
4013 }
4014 }
4015 }
4016
4017 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(context, attachment);
4018 if (attachmentObject)
4019 {
4020 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
4021 attachmentObject->type() == GL_TEXTURE ||
4022 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
4023
4024 switch (pname)
4025 {
4026 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4027 if (attachmentObject->type() != GL_RENDERBUFFER &&
4028 attachmentObject->type() != GL_TEXTURE)
4029 {
4030 context->validationError(GL_INVALID_ENUM, kFramebufferIncompleteAttachment);
4031 return false;
4032 }
4033 break;
4034
4035 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
4036 if (attachmentObject->type() != GL_TEXTURE)
4037 {
4038 context->validationError(GL_INVALID_ENUM, kFramebufferIncompleteAttachment);
4039 return false;
4040 }
4041 break;
4042
4043 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
4044 if (attachmentObject->type() != GL_TEXTURE)
4045 {
4046 context->validationError(GL_INVALID_ENUM, kFramebufferIncompleteAttachment);
4047 return false;
4048 }
4049 break;
4050
4051 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
4052 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
4053 {
4054 context->validationError(GL_INVALID_OPERATION, kInvalidAttachment);
4055 return false;
4056 }
4057 break;
4058
4059 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
4060 if (attachmentObject->type() != GL_TEXTURE)
4061 {
4062 context->validationError(GL_INVALID_ENUM, kFramebufferIncompleteAttachment);
4063 return false;
4064 }
4065 break;
4066
4067 default:
4068 break;
4069 }
4070 }
4071 else
4072 {
4073 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
4074 // is NONE, then querying any other pname will generate INVALID_ENUM.
4075
4076 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
4077 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
4078 // INVALID_OPERATION for all other pnames
4079
4080 switch (pname)
4081 {
4082 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
4083 break;
4084
4085 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4086 if (clientVersion < 3)
4087 {
4088 context->validationError(GL_INVALID_ENUM,
4089 kInvalidFramebufferAttachmentParameter);
4090 return false;
4091 }
4092 break;
4093
4094 default:
4095 if (clientVersion < 3)
4096 {
4097 context->validationError(GL_INVALID_ENUM,
4098 kInvalidFramebufferAttachmentParameter);
4099 return false;
4100 }
4101 else
4102 {
4103 context->validationError(GL_INVALID_OPERATION,
4104 kInvalidFramebufferAttachmentParameter);
4105 return false;
4106 }
4107 }
4108 }
4109
4110 if (numParams)
4111 {
4112 *numParams = 1;
4113 }
4114
4115 return true;
4116 }
4117
ValidateGetFramebufferAttachmentParameterivRobustANGLE(Context * context,GLenum target,GLenum attachment,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4118 bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(Context *context,
4119 GLenum target,
4120 GLenum attachment,
4121 GLenum pname,
4122 GLsizei bufSize,
4123 GLsizei *length,
4124 GLint *params)
4125 {
4126 if (!ValidateRobustEntryPoint(context, bufSize))
4127 {
4128 return false;
4129 }
4130
4131 GLsizei numParams = 0;
4132 if (!ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname,
4133 &numParams))
4134 {
4135 return false;
4136 }
4137
4138 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4139 {
4140 return false;
4141 }
4142
4143 SetRobustLengthParam(length, numParams);
4144
4145 return true;
4146 }
4147
ValidateGetBufferParameterivRobustANGLE(Context * context,BufferBinding target,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4148 bool ValidateGetBufferParameterivRobustANGLE(Context *context,
4149 BufferBinding target,
4150 GLenum pname,
4151 GLsizei bufSize,
4152 GLsizei *length,
4153 GLint *params)
4154 {
4155 if (!ValidateRobustEntryPoint(context, bufSize))
4156 {
4157 return false;
4158 }
4159
4160 GLsizei numParams = 0;
4161
4162 if (!ValidateGetBufferParameterBase(context, target, pname, false, &numParams))
4163 {
4164 return false;
4165 }
4166
4167 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4168 {
4169 return false;
4170 }
4171
4172 SetRobustLengthParam(length, numParams);
4173 return true;
4174 }
4175
ValidateGetBufferParameteri64vRobustANGLE(Context * context,BufferBinding target,GLenum pname,GLsizei bufSize,GLsizei * length,GLint64 * params)4176 bool ValidateGetBufferParameteri64vRobustANGLE(Context *context,
4177 BufferBinding target,
4178 GLenum pname,
4179 GLsizei bufSize,
4180 GLsizei *length,
4181 GLint64 *params)
4182 {
4183 GLsizei numParams = 0;
4184
4185 if (!ValidateRobustEntryPoint(context, bufSize))
4186 {
4187 return false;
4188 }
4189
4190 if (!ValidateGetBufferParameterBase(context, target, pname, false, &numParams))
4191 {
4192 return false;
4193 }
4194
4195 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4196 {
4197 return false;
4198 }
4199
4200 SetRobustLengthParam(length, numParams);
4201
4202 return true;
4203 }
4204
ValidateGetProgramivBase(Context * context,GLuint program,GLenum pname,GLsizei * numParams)4205 bool ValidateGetProgramivBase(Context *context, GLuint program, GLenum pname, GLsizei *numParams)
4206 {
4207 // Currently, all GetProgramiv queries return 1 parameter
4208 if (numParams)
4209 {
4210 *numParams = 1;
4211 }
4212
4213 if (context->isContextLost())
4214 {
4215 context->validationError(GL_CONTEXT_LOST, kContextLost);
4216
4217 if (context->getExtensions().parallelShaderCompile && pname == GL_COMPLETION_STATUS_KHR)
4218 {
4219 // Generate an error but still return true, the context still needs to return a
4220 // value in this case.
4221 return true;
4222 }
4223 else
4224 {
4225 return false;
4226 }
4227 }
4228
4229 // Special case for GL_COMPLETION_STATUS_KHR: don't resolve the link. Otherwise resolve it now.
4230 Program *programObject = (pname == GL_COMPLETION_STATUS_KHR)
4231 ? GetValidProgramNoResolve(context, program)
4232 : GetValidProgram(context, program);
4233 if (!programObject)
4234 {
4235 return false;
4236 }
4237
4238 switch (pname)
4239 {
4240 case GL_DELETE_STATUS:
4241 case GL_LINK_STATUS:
4242 case GL_VALIDATE_STATUS:
4243 case GL_INFO_LOG_LENGTH:
4244 case GL_ATTACHED_SHADERS:
4245 case GL_ACTIVE_ATTRIBUTES:
4246 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
4247 case GL_ACTIVE_UNIFORMS:
4248 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
4249 break;
4250
4251 case GL_PROGRAM_BINARY_LENGTH:
4252 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
4253 {
4254 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
4255 return false;
4256 }
4257 break;
4258
4259 case GL_ACTIVE_UNIFORM_BLOCKS:
4260 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
4261 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
4262 case GL_TRANSFORM_FEEDBACK_VARYINGS:
4263 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
4264 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
4265 if (context->getClientMajorVersion() < 3)
4266 {
4267 context->validationError(GL_INVALID_ENUM, kEnumRequiresGLES30);
4268 return false;
4269 }
4270 break;
4271
4272 case GL_PROGRAM_SEPARABLE:
4273 case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS:
4274 if (context->getClientVersion() < Version(3, 1))
4275 {
4276 context->validationError(GL_INVALID_ENUM, kEnumRequiresGLES31);
4277 return false;
4278 }
4279 break;
4280
4281 case GL_COMPUTE_WORK_GROUP_SIZE:
4282 if (context->getClientVersion() < Version(3, 1))
4283 {
4284 context->validationError(GL_INVALID_ENUM, kEnumRequiresGLES31);
4285 return false;
4286 }
4287
4288 // [OpenGL ES 3.1] Chapter 7.12 Page 122
4289 // An INVALID_OPERATION error is generated if COMPUTE_WORK_GROUP_SIZE is queried for a
4290 // program which has not been linked successfully, or which does not contain objects to
4291 // form a compute shader.
4292 if (!programObject->isLinked())
4293 {
4294 context->validationError(GL_INVALID_OPERATION, kProgramNotLinked);
4295 return false;
4296 }
4297 if (!programObject->hasLinkedShaderStage(ShaderType::Compute))
4298 {
4299 context->validationError(GL_INVALID_OPERATION, kNoActiveComputeShaderStage);
4300 return false;
4301 }
4302 break;
4303
4304 case GL_GEOMETRY_LINKED_INPUT_TYPE_EXT:
4305 case GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT:
4306 case GL_GEOMETRY_LINKED_VERTICES_OUT_EXT:
4307 case GL_GEOMETRY_SHADER_INVOCATIONS_EXT:
4308 if (!context->getExtensions().geometryShader)
4309 {
4310 context->validationError(GL_INVALID_ENUM, kGeometryShaderExtensionNotEnabled);
4311 return false;
4312 }
4313
4314 // [EXT_geometry_shader] Chapter 7.12
4315 // An INVALID_OPERATION error is generated if GEOMETRY_LINKED_VERTICES_OUT_EXT,
4316 // GEOMETRY_LINKED_INPUT_TYPE_EXT, GEOMETRY_LINKED_OUTPUT_TYPE_EXT, or
4317 // GEOMETRY_SHADER_INVOCATIONS_EXT are queried for a program which has not been linked
4318 // successfully, or which does not contain objects to form a geometry shader.
4319 if (!programObject->isLinked())
4320 {
4321 context->validationError(GL_INVALID_OPERATION, kProgramNotLinked);
4322 return false;
4323 }
4324 if (!programObject->hasLinkedShaderStage(ShaderType::Geometry))
4325 {
4326 context->validationError(GL_INVALID_OPERATION, kNoActiveGeometryShaderStage);
4327 return false;
4328 }
4329 break;
4330
4331 case GL_COMPLETION_STATUS_KHR:
4332 if (!context->getExtensions().parallelShaderCompile)
4333 {
4334 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
4335 return false;
4336 }
4337 break;
4338
4339 default:
4340 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
4341 return false;
4342 }
4343
4344 return true;
4345 }
4346
ValidateGetProgramivRobustANGLE(Context * context,GLuint program,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4347 bool ValidateGetProgramivRobustANGLE(Context *context,
4348 GLuint program,
4349 GLenum pname,
4350 GLsizei bufSize,
4351 GLsizei *length,
4352 GLint *params)
4353 {
4354 if (!ValidateRobustEntryPoint(context, bufSize))
4355 {
4356 return false;
4357 }
4358
4359 GLsizei numParams = 0;
4360
4361 if (!ValidateGetProgramivBase(context, program, pname, &numParams))
4362 {
4363 return false;
4364 }
4365
4366 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4367 {
4368 return false;
4369 }
4370
4371 SetRobustLengthParam(length, numParams);
4372
4373 return true;
4374 }
4375
ValidateGetRenderbufferParameterivRobustANGLE(Context * context,GLenum target,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4376 bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
4377 GLenum target,
4378 GLenum pname,
4379 GLsizei bufSize,
4380 GLsizei *length,
4381 GLint *params)
4382 {
4383 if (!ValidateRobustEntryPoint(context, bufSize))
4384 {
4385 return false;
4386 }
4387
4388 GLsizei numParams = 0;
4389
4390 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, &numParams))
4391 {
4392 return false;
4393 }
4394
4395 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4396 {
4397 return false;
4398 }
4399
4400 SetRobustLengthParam(length, numParams);
4401
4402 return true;
4403 }
4404
ValidateGetShaderivRobustANGLE(Context * context,GLuint shader,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4405 bool ValidateGetShaderivRobustANGLE(Context *context,
4406 GLuint shader,
4407 GLenum pname,
4408 GLsizei bufSize,
4409 GLsizei *length,
4410 GLint *params)
4411 {
4412 if (!ValidateRobustEntryPoint(context, bufSize))
4413 {
4414 return false;
4415 }
4416
4417 GLsizei numParams = 0;
4418
4419 if (!ValidateGetShaderivBase(context, shader, pname, &numParams))
4420 {
4421 return false;
4422 }
4423
4424 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4425 {
4426 return false;
4427 }
4428
4429 SetRobustLengthParam(length, numParams);
4430
4431 return true;
4432 }
4433
ValidateGetTexParameterfvRobustANGLE(Context * context,TextureType target,GLenum pname,GLsizei bufSize,GLsizei * length,GLfloat * params)4434 bool ValidateGetTexParameterfvRobustANGLE(Context *context,
4435 TextureType target,
4436 GLenum pname,
4437 GLsizei bufSize,
4438 GLsizei *length,
4439 GLfloat *params)
4440 {
4441 if (!ValidateRobustEntryPoint(context, bufSize))
4442 {
4443 return false;
4444 }
4445
4446 GLsizei numParams = 0;
4447
4448 if (!ValidateGetTexParameterBase(context, target, pname, &numParams))
4449 {
4450 return false;
4451 }
4452
4453 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4454 {
4455 return false;
4456 }
4457
4458 SetRobustLengthParam(length, numParams);
4459
4460 return true;
4461 }
4462
ValidateGetTexParameterivRobustANGLE(Context * context,TextureType target,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4463 bool ValidateGetTexParameterivRobustANGLE(Context *context,
4464 TextureType target,
4465 GLenum pname,
4466 GLsizei bufSize,
4467 GLsizei *length,
4468 GLint *params)
4469 {
4470
4471 if (!ValidateRobustEntryPoint(context, bufSize))
4472 {
4473 return false;
4474 }
4475 GLsizei numParams = 0;
4476 if (!ValidateGetTexParameterBase(context, target, pname, &numParams))
4477 {
4478 return false;
4479 }
4480
4481 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4482 {
4483 return false;
4484 }
4485
4486 SetRobustLengthParam(length, numParams);
4487 return true;
4488 }
4489
ValidateGetTexParameterIivRobustANGLE(Context * context,TextureType target,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4490 bool ValidateGetTexParameterIivRobustANGLE(Context *context,
4491 TextureType target,
4492 GLenum pname,
4493 GLsizei bufSize,
4494 GLsizei *length,
4495 GLint *params)
4496 {
4497 UNIMPLEMENTED();
4498 return false;
4499 }
4500
ValidateGetTexParameterIuivRobustANGLE(Context * context,TextureType target,GLenum pname,GLsizei bufSize,GLsizei * length,GLuint * params)4501 bool ValidateGetTexParameterIuivRobustANGLE(Context *context,
4502 TextureType target,
4503 GLenum pname,
4504 GLsizei bufSize,
4505 GLsizei *length,
4506 GLuint *params)
4507 {
4508 UNIMPLEMENTED();
4509 return false;
4510 }
4511
ValidateTexParameterfvRobustANGLE(Context * context,TextureType target,GLenum pname,GLsizei bufSize,const GLfloat * params)4512 bool ValidateTexParameterfvRobustANGLE(Context *context,
4513 TextureType target,
4514 GLenum pname,
4515 GLsizei bufSize,
4516 const GLfloat *params)
4517 {
4518 if (!ValidateRobustEntryPoint(context, bufSize))
4519 {
4520 return false;
4521 }
4522
4523 return ValidateTexParameterBase(context, target, pname, bufSize, true, params);
4524 }
4525
ValidateTexParameterivRobustANGLE(Context * context,TextureType target,GLenum pname,GLsizei bufSize,const GLint * params)4526 bool ValidateTexParameterivRobustANGLE(Context *context,
4527 TextureType target,
4528 GLenum pname,
4529 GLsizei bufSize,
4530 const GLint *params)
4531 {
4532 if (!ValidateRobustEntryPoint(context, bufSize))
4533 {
4534 return false;
4535 }
4536
4537 return ValidateTexParameterBase(context, target, pname, bufSize, true, params);
4538 }
4539
ValidateTexParameterIivRobustANGLE(Context * context,TextureType target,GLenum pname,GLsizei bufSize,const GLint * params)4540 bool ValidateTexParameterIivRobustANGLE(Context *context,
4541 TextureType target,
4542 GLenum pname,
4543 GLsizei bufSize,
4544 const GLint *params)
4545 {
4546 UNIMPLEMENTED();
4547 return false;
4548 }
4549
ValidateTexParameterIuivRobustANGLE(Context * context,TextureType target,GLenum pname,GLsizei bufSize,const GLuint * params)4550 bool ValidateTexParameterIuivRobustANGLE(Context *context,
4551 TextureType target,
4552 GLenum pname,
4553 GLsizei bufSize,
4554 const GLuint *params)
4555 {
4556 UNIMPLEMENTED();
4557 return false;
4558 }
4559
ValidateGetSamplerParameterfvRobustANGLE(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,GLsizei * length,GLfloat * params)4560 bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
4561 GLuint sampler,
4562 GLenum pname,
4563 GLsizei bufSize,
4564 GLsizei *length,
4565 GLfloat *params)
4566 {
4567 if (!ValidateRobustEntryPoint(context, bufSize))
4568 {
4569 return false;
4570 }
4571
4572 GLsizei numParams = 0;
4573
4574 if (!ValidateGetSamplerParameterBase(context, sampler, pname, &numParams))
4575 {
4576 return false;
4577 }
4578
4579 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4580 {
4581 return false;
4582 }
4583
4584 SetRobustLengthParam(length, numParams);
4585 return true;
4586 }
4587
ValidateGetSamplerParameterivRobustANGLE(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4588 bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
4589 GLuint sampler,
4590 GLenum pname,
4591 GLsizei bufSize,
4592 GLsizei *length,
4593 GLint *params)
4594 {
4595 if (!ValidateRobustEntryPoint(context, bufSize))
4596 {
4597 return false;
4598 }
4599
4600 GLsizei numParams = 0;
4601
4602 if (!ValidateGetSamplerParameterBase(context, sampler, pname, &numParams))
4603 {
4604 return false;
4605 }
4606
4607 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4608 {
4609 return false;
4610 }
4611
4612 SetRobustLengthParam(length, numParams);
4613 return true;
4614 }
4615
ValidateGetSamplerParameterIivRobustANGLE(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4616 bool ValidateGetSamplerParameterIivRobustANGLE(Context *context,
4617 GLuint sampler,
4618 GLenum pname,
4619 GLsizei bufSize,
4620 GLsizei *length,
4621 GLint *params)
4622 {
4623 UNIMPLEMENTED();
4624 return false;
4625 }
4626
ValidateGetSamplerParameterIuivRobustANGLE(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,GLsizei * length,GLuint * params)4627 bool ValidateGetSamplerParameterIuivRobustANGLE(Context *context,
4628 GLuint sampler,
4629 GLenum pname,
4630 GLsizei bufSize,
4631 GLsizei *length,
4632 GLuint *params)
4633 {
4634 UNIMPLEMENTED();
4635 return false;
4636 }
4637
ValidateSamplerParameterfvRobustANGLE(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,const GLfloat * params)4638 bool ValidateSamplerParameterfvRobustANGLE(Context *context,
4639 GLuint sampler,
4640 GLenum pname,
4641 GLsizei bufSize,
4642 const GLfloat *params)
4643 {
4644 if (!ValidateRobustEntryPoint(context, bufSize))
4645 {
4646 return false;
4647 }
4648
4649 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, true, params);
4650 }
4651
ValidateSamplerParameterivRobustANGLE(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,const GLint * params)4652 bool ValidateSamplerParameterivRobustANGLE(Context *context,
4653 GLuint sampler,
4654 GLenum pname,
4655 GLsizei bufSize,
4656 const GLint *params)
4657 {
4658 if (!ValidateRobustEntryPoint(context, bufSize))
4659 {
4660 return false;
4661 }
4662
4663 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, true, params);
4664 }
4665
ValidateSamplerParameterIivRobustANGLE(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,const GLint * param)4666 bool ValidateSamplerParameterIivRobustANGLE(Context *context,
4667 GLuint sampler,
4668 GLenum pname,
4669 GLsizei bufSize,
4670 const GLint *param)
4671 {
4672 UNIMPLEMENTED();
4673 return false;
4674 }
4675
ValidateSamplerParameterIuivRobustANGLE(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,const GLuint * param)4676 bool ValidateSamplerParameterIuivRobustANGLE(Context *context,
4677 GLuint sampler,
4678 GLenum pname,
4679 GLsizei bufSize,
4680 const GLuint *param)
4681 {
4682 UNIMPLEMENTED();
4683 return false;
4684 }
4685
ValidateGetVertexAttribfvRobustANGLE(Context * context,GLuint index,GLenum pname,GLsizei bufSize,GLsizei * length,GLfloat * params)4686 bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
4687 GLuint index,
4688 GLenum pname,
4689 GLsizei bufSize,
4690 GLsizei *length,
4691 GLfloat *params)
4692 {
4693 if (!ValidateRobustEntryPoint(context, bufSize))
4694 {
4695 return false;
4696 }
4697
4698 GLsizei writeLength = 0;
4699
4700 if (!ValidateGetVertexAttribBase(context, index, pname, &writeLength, false, false))
4701 {
4702 return false;
4703 }
4704
4705 if (!ValidateRobustBufferSize(context, bufSize, writeLength))
4706 {
4707 return false;
4708 }
4709
4710 SetRobustLengthParam(length, writeLength);
4711 return true;
4712 }
4713
ValidateGetVertexAttribivRobustANGLE(Context * context,GLuint index,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4714 bool ValidateGetVertexAttribivRobustANGLE(Context *context,
4715 GLuint index,
4716 GLenum pname,
4717 GLsizei bufSize,
4718 GLsizei *length,
4719 GLint *params)
4720 {
4721 if (!ValidateRobustEntryPoint(context, bufSize))
4722 {
4723 return false;
4724 }
4725
4726 GLsizei writeLength = 0;
4727
4728 if (!ValidateGetVertexAttribBase(context, index, pname, &writeLength, false, false))
4729 {
4730 return false;
4731 }
4732
4733 if (!ValidateRobustBufferSize(context, bufSize, writeLength))
4734 {
4735 return false;
4736 }
4737
4738 SetRobustLengthParam(length, writeLength);
4739
4740 return true;
4741 }
4742
ValidateGetVertexAttribPointervRobustANGLE(Context * context,GLuint index,GLenum pname,GLsizei bufSize,GLsizei * length,void ** pointer)4743 bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
4744 GLuint index,
4745 GLenum pname,
4746 GLsizei bufSize,
4747 GLsizei *length,
4748 void **pointer)
4749 {
4750 if (!ValidateRobustEntryPoint(context, bufSize))
4751 {
4752 return false;
4753 }
4754
4755 GLsizei writeLength = 0;
4756
4757 if (!ValidateGetVertexAttribBase(context, index, pname, &writeLength, true, false))
4758 {
4759 return false;
4760 }
4761
4762 if (!ValidateRobustBufferSize(context, bufSize, writeLength))
4763 {
4764 return false;
4765 }
4766
4767 SetRobustLengthParam(length, writeLength);
4768
4769 return true;
4770 }
4771
ValidateGetVertexAttribIivRobustANGLE(Context * context,GLuint index,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4772 bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
4773 GLuint index,
4774 GLenum pname,
4775 GLsizei bufSize,
4776 GLsizei *length,
4777 GLint *params)
4778 {
4779 if (!ValidateRobustEntryPoint(context, bufSize))
4780 {
4781 return false;
4782 }
4783
4784 GLsizei writeLength = 0;
4785
4786 if (!ValidateGetVertexAttribBase(context, index, pname, &writeLength, false, true))
4787 {
4788 return false;
4789 }
4790
4791 if (!ValidateRobustBufferSize(context, bufSize, writeLength))
4792 {
4793 return false;
4794 }
4795
4796 SetRobustLengthParam(length, writeLength);
4797
4798 return true;
4799 }
4800
ValidateGetVertexAttribIuivRobustANGLE(Context * context,GLuint index,GLenum pname,GLsizei bufSize,GLsizei * length,GLuint * params)4801 bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
4802 GLuint index,
4803 GLenum pname,
4804 GLsizei bufSize,
4805 GLsizei *length,
4806 GLuint *params)
4807 {
4808 if (!ValidateRobustEntryPoint(context, bufSize))
4809 {
4810 return false;
4811 }
4812
4813 GLsizei writeLength = 0;
4814
4815 if (!ValidateGetVertexAttribBase(context, index, pname, &writeLength, false, true))
4816 {
4817 return false;
4818 }
4819
4820 if (!ValidateRobustBufferSize(context, bufSize, writeLength))
4821 {
4822 return false;
4823 }
4824
4825 SetRobustLengthParam(length, writeLength);
4826
4827 return true;
4828 }
4829
ValidateGetActiveUniformBlockivRobustANGLE(Context * context,GLuint program,GLuint uniformBlockIndex,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4830 bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
4831 GLuint program,
4832 GLuint uniformBlockIndex,
4833 GLenum pname,
4834 GLsizei bufSize,
4835 GLsizei *length,
4836 GLint *params)
4837 {
4838 if (!ValidateRobustEntryPoint(context, bufSize))
4839 {
4840 return false;
4841 }
4842
4843 GLsizei writeLength = 0;
4844
4845 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname,
4846 &writeLength))
4847 {
4848 return false;
4849 }
4850
4851 if (!ValidateRobustBufferSize(context, bufSize, writeLength))
4852 {
4853 return false;
4854 }
4855
4856 SetRobustLengthParam(length, writeLength);
4857
4858 return true;
4859 }
4860
ValidateGetInternalformativRobustANGLE(Context * context,GLenum target,GLenum internalformat,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * params)4861 bool ValidateGetInternalformativRobustANGLE(Context *context,
4862 GLenum target,
4863 GLenum internalformat,
4864 GLenum pname,
4865 GLsizei bufSize,
4866 GLsizei *length,
4867 GLint *params)
4868 {
4869 if (!ValidateRobustEntryPoint(context, bufSize))
4870 {
4871 return false;
4872 }
4873
4874 GLsizei numParams = 0;
4875
4876 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
4877 &numParams))
4878 {
4879 return false;
4880 }
4881
4882 if (!ValidateRobustBufferSize(context, bufSize, numParams))
4883 {
4884 return false;
4885 }
4886
4887 SetRobustLengthParam(length, numParams);
4888
4889 return true;
4890 }
4891
4892 // Perform validation from WebGL 2 section 5.10 "Invalid Clears":
4893 // In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
4894 // specified clear value and the type of a buffer that is being cleared generates an
4895 // INVALID_OPERATION error instead of producing undefined results
ValidateWebGLFramebufferAttachmentClearType(Context * context,GLint drawbuffer,const GLenum * validComponentTypes,size_t validComponentTypeCount)4896 bool ValidateWebGLFramebufferAttachmentClearType(Context *context,
4897 GLint drawbuffer,
4898 const GLenum *validComponentTypes,
4899 size_t validComponentTypeCount)
4900 {
4901 const FramebufferAttachment *attachment =
4902 context->getState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
4903 if (attachment)
4904 {
4905 GLenum componentType = attachment->getFormat().info->componentType;
4906 const GLenum *end = validComponentTypes + validComponentTypeCount;
4907 if (std::find(validComponentTypes, end, componentType) == end)
4908 {
4909 context->validationError(GL_INVALID_OPERATION, kNoDefinedClearConversion);
4910 return false;
4911 }
4912 }
4913
4914 return true;
4915 }
4916
ValidateRobustCompressedTexImageBase(Context * context,GLsizei imageSize,GLsizei dataSize)4917 bool ValidateRobustCompressedTexImageBase(Context *context, GLsizei imageSize, GLsizei dataSize)
4918 {
4919 if (!ValidateRobustEntryPoint(context, dataSize))
4920 {
4921 return false;
4922 }
4923
4924 Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
4925 if (pixelUnpackBuffer == nullptr)
4926 {
4927 if (dataSize < imageSize)
4928 {
4929 context->validationError(GL_INVALID_OPERATION, kCompressedDataSizeTooSmall);
4930 }
4931 }
4932 return true;
4933 }
4934
ValidateGetBufferParameterBase(Context * context,BufferBinding target,GLenum pname,bool pointerVersion,GLsizei * numParams)4935 bool ValidateGetBufferParameterBase(Context *context,
4936 BufferBinding target,
4937 GLenum pname,
4938 bool pointerVersion,
4939 GLsizei *numParams)
4940 {
4941 if (numParams)
4942 {
4943 *numParams = 0;
4944 }
4945
4946 if (!context->isValidBufferBinding(target))
4947 {
4948 context->validationError(GL_INVALID_ENUM, kInvalidBufferTypes);
4949 return false;
4950 }
4951
4952 const Buffer *buffer = context->getState().getTargetBuffer(target);
4953 if (!buffer)
4954 {
4955 // A null buffer means that "0" is bound to the requested buffer target
4956 context->validationError(GL_INVALID_OPERATION, kBufferNotBound);
4957 return false;
4958 }
4959
4960 const Extensions &extensions = context->getExtensions();
4961
4962 switch (pname)
4963 {
4964 case GL_BUFFER_USAGE:
4965 case GL_BUFFER_SIZE:
4966 break;
4967
4968 case GL_BUFFER_ACCESS_OES:
4969 if (!extensions.mapBuffer)
4970 {
4971 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
4972 return false;
4973 }
4974 break;
4975
4976 case GL_BUFFER_MAPPED:
4977 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
4978 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
4979 !extensions.mapBufferRange)
4980 {
4981 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
4982 return false;
4983 }
4984 break;
4985
4986 case GL_BUFFER_MAP_POINTER:
4987 if (!pointerVersion)
4988 {
4989 context->validationError(GL_INVALID_ENUM, kInvalidMapPointerQuery);
4990 return false;
4991 }
4992 break;
4993
4994 case GL_BUFFER_ACCESS_FLAGS:
4995 case GL_BUFFER_MAP_OFFSET:
4996 case GL_BUFFER_MAP_LENGTH:
4997 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
4998 {
4999 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5000 return false;
5001 }
5002 break;
5003
5004 case GL_MEMORY_SIZE_ANGLE:
5005 if (!context->getExtensions().memorySize)
5006 {
5007 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
5008 return false;
5009 }
5010 break;
5011
5012 default:
5013 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5014 return false;
5015 }
5016
5017 // All buffer parameter queries return one value.
5018 if (numParams)
5019 {
5020 *numParams = 1;
5021 }
5022
5023 return true;
5024 }
5025
ValidateGetRenderbufferParameterivBase(Context * context,GLenum target,GLenum pname,GLsizei * length)5026 bool ValidateGetRenderbufferParameterivBase(Context *context,
5027 GLenum target,
5028 GLenum pname,
5029 GLsizei *length)
5030 {
5031 if (length)
5032 {
5033 *length = 0;
5034 }
5035
5036 if (target != GL_RENDERBUFFER)
5037 {
5038 context->validationError(GL_INVALID_ENUM, kInvalidRenderbufferTarget);
5039 return false;
5040 }
5041
5042 Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer();
5043 if (renderbuffer == nullptr)
5044 {
5045 context->validationError(GL_INVALID_OPERATION, kRenderbufferNotBound);
5046 return false;
5047 }
5048
5049 switch (pname)
5050 {
5051 case GL_RENDERBUFFER_WIDTH:
5052 case GL_RENDERBUFFER_HEIGHT:
5053 case GL_RENDERBUFFER_INTERNAL_FORMAT:
5054 case GL_RENDERBUFFER_RED_SIZE:
5055 case GL_RENDERBUFFER_GREEN_SIZE:
5056 case GL_RENDERBUFFER_BLUE_SIZE:
5057 case GL_RENDERBUFFER_ALPHA_SIZE:
5058 case GL_RENDERBUFFER_DEPTH_SIZE:
5059 case GL_RENDERBUFFER_STENCIL_SIZE:
5060 break;
5061
5062 case GL_RENDERBUFFER_SAMPLES_ANGLE:
5063 if (!context->getExtensions().framebufferMultisample)
5064 {
5065 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
5066 return false;
5067 }
5068 break;
5069
5070 case GL_MEMORY_SIZE_ANGLE:
5071 if (!context->getExtensions().memorySize)
5072 {
5073 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
5074 return false;
5075 }
5076 break;
5077
5078 default:
5079 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5080 return false;
5081 }
5082
5083 if (length)
5084 {
5085 *length = 1;
5086 }
5087 return true;
5088 }
5089
ValidateGetShaderivBase(Context * context,GLuint shader,GLenum pname,GLsizei * length)5090 bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
5091 {
5092 if (length)
5093 {
5094 *length = 0;
5095 }
5096
5097 if (context->isContextLost())
5098 {
5099 context->validationError(GL_CONTEXT_LOST, kContextLost);
5100
5101 if (context->getExtensions().parallelShaderCompile && pname == GL_COMPLETION_STATUS_KHR)
5102 {
5103 // Generate an error but still return true, the context still needs to return a
5104 // value in this case.
5105 return true;
5106 }
5107 else
5108 {
5109 return false;
5110 }
5111 }
5112
5113 if (GetValidShader(context, shader) == nullptr)
5114 {
5115 return false;
5116 }
5117
5118 switch (pname)
5119 {
5120 case GL_SHADER_TYPE:
5121 case GL_DELETE_STATUS:
5122 case GL_COMPILE_STATUS:
5123 case GL_INFO_LOG_LENGTH:
5124 case GL_SHADER_SOURCE_LENGTH:
5125 break;
5126
5127 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
5128 if (!context->getExtensions().translatedShaderSource)
5129 {
5130 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
5131 return false;
5132 }
5133 break;
5134
5135 case GL_COMPLETION_STATUS_KHR:
5136 if (!context->getExtensions().parallelShaderCompile)
5137 {
5138 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
5139 return false;
5140 }
5141 break;
5142
5143 default:
5144 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5145 return false;
5146 }
5147
5148 if (length)
5149 {
5150 *length = 1;
5151 }
5152 return true;
5153 }
5154
ValidateGetTexParameterBase(Context * context,TextureType target,GLenum pname,GLsizei * length)5155 bool ValidateGetTexParameterBase(Context *context,
5156 TextureType target,
5157 GLenum pname,
5158 GLsizei *length)
5159 {
5160 if (length)
5161 {
5162 *length = 0;
5163 }
5164
5165 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5166 {
5167 context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
5168 return false;
5169 }
5170
5171 if (context->getTextureByType(target) == nullptr)
5172 {
5173 // Should only be possible for external textures
5174 context->validationError(GL_INVALID_ENUM, kTextureNotBound);
5175 return false;
5176 }
5177
5178 if (context->getClientMajorVersion() == 1 && !IsValidGLES1TextureParameter(pname))
5179 {
5180 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5181 return false;
5182 }
5183
5184 switch (pname)
5185 {
5186 case GL_TEXTURE_MAG_FILTER:
5187 case GL_TEXTURE_MIN_FILTER:
5188 case GL_TEXTURE_WRAP_S:
5189 case GL_TEXTURE_WRAP_T:
5190 break;
5191
5192 case GL_TEXTURE_USAGE_ANGLE:
5193 if (!context->getExtensions().textureUsage)
5194 {
5195 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5196 return false;
5197 }
5198 break;
5199
5200 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5201 if (!ValidateTextureMaxAnisotropyExtensionEnabled(context))
5202 {
5203 return false;
5204 }
5205 break;
5206
5207 case GL_TEXTURE_IMMUTABLE_FORMAT:
5208 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
5209 {
5210 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5211 return false;
5212 }
5213 break;
5214
5215 case GL_TEXTURE_WRAP_R:
5216 case GL_TEXTURE_IMMUTABLE_LEVELS:
5217 case GL_TEXTURE_SWIZZLE_R:
5218 case GL_TEXTURE_SWIZZLE_G:
5219 case GL_TEXTURE_SWIZZLE_B:
5220 case GL_TEXTURE_SWIZZLE_A:
5221 case GL_TEXTURE_BASE_LEVEL:
5222 case GL_TEXTURE_MAX_LEVEL:
5223 case GL_TEXTURE_MIN_LOD:
5224 case GL_TEXTURE_MAX_LOD:
5225 case GL_TEXTURE_COMPARE_MODE:
5226 case GL_TEXTURE_COMPARE_FUNC:
5227 if (context->getClientMajorVersion() < 3)
5228 {
5229 context->validationError(GL_INVALID_ENUM, kEnumRequiresGLES30);
5230 return false;
5231 }
5232 break;
5233
5234 case GL_TEXTURE_SRGB_DECODE_EXT:
5235 if (!context->getExtensions().textureSRGBDecode)
5236 {
5237 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5238 return false;
5239 }
5240 break;
5241
5242 case GL_DEPTH_STENCIL_TEXTURE_MODE:
5243 if (context->getClientVersion() < Version(3, 1))
5244 {
5245 context->validationError(GL_INVALID_ENUM, kEnumRequiresGLES31);
5246 return false;
5247 }
5248 break;
5249
5250 case GL_GENERATE_MIPMAP:
5251 case GL_TEXTURE_CROP_RECT_OES:
5252 // TODO(lfy@google.com): Restrict to GL_OES_draw_texture
5253 // after GL_OES_draw_texture functionality implemented
5254 if (context->getClientMajorVersion() > 1)
5255 {
5256 context->validationError(GL_INVALID_ENUM, kGLES1Only);
5257 return false;
5258 }
5259 break;
5260
5261 case GL_MEMORY_SIZE_ANGLE:
5262 if (!context->getExtensions().memorySize)
5263 {
5264 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5265 return false;
5266 }
5267 break;
5268
5269 case GL_TEXTURE_BORDER_COLOR:
5270 if (!context->getExtensions().textureBorderClamp)
5271 {
5272 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
5273 return false;
5274 }
5275 break;
5276
5277 case GL_TEXTURE_NATIVE_ID_ANGLE:
5278 if (!context->getExtensions().textureExternalUpdateANGLE)
5279 {
5280 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
5281 return false;
5282 }
5283 break;
5284
5285 default:
5286 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5287 return false;
5288 }
5289
5290 if (length)
5291 {
5292 *length = GetTexParameterCount(pname);
5293 }
5294 return true;
5295 }
5296
ValidateGetVertexAttribBase(Context * context,GLuint index,GLenum pname,GLsizei * length,bool pointer,bool pureIntegerEntryPoint)5297 bool ValidateGetVertexAttribBase(Context *context,
5298 GLuint index,
5299 GLenum pname,
5300 GLsizei *length,
5301 bool pointer,
5302 bool pureIntegerEntryPoint)
5303 {
5304 if (length)
5305 {
5306 *length = 0;
5307 }
5308
5309 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
5310 {
5311 context->validationError(GL_INVALID_OPERATION, kES3Required);
5312 return false;
5313 }
5314
5315 if (index >= context->getCaps().maxVertexAttributes)
5316 {
5317 context->validationError(GL_INVALID_VALUE, kIndexExceedsMaxVertexAttribute);
5318 return false;
5319 }
5320
5321 if (pointer)
5322 {
5323 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
5324 {
5325 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5326 return false;
5327 }
5328 }
5329 else
5330 {
5331 switch (pname)
5332 {
5333 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
5334 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
5335 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
5336 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
5337 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
5338 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
5339 case GL_CURRENT_VERTEX_ATTRIB:
5340 break;
5341
5342 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
5343 static_assert(
5344 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
5345 "ANGLE extension enums not equal to GL enums.");
5346 if (context->getClientMajorVersion() < 3 &&
5347 !context->getExtensions().instancedArraysAny())
5348 {
5349 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5350 return false;
5351 }
5352 break;
5353
5354 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
5355 if (context->getClientMajorVersion() < 3)
5356 {
5357 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5358 return false;
5359 }
5360 break;
5361
5362 case GL_VERTEX_ATTRIB_BINDING:
5363 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
5364 if (context->getClientVersion() < ES_3_1)
5365 {
5366 context->validationError(GL_INVALID_ENUM, kEnumRequiresGLES31);
5367 return false;
5368 }
5369 break;
5370
5371 default:
5372 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5373 return false;
5374 }
5375 }
5376
5377 if (length)
5378 {
5379 if (pname == GL_CURRENT_VERTEX_ATTRIB)
5380 {
5381 *length = 4;
5382 }
5383 else
5384 {
5385 *length = 1;
5386 }
5387 }
5388
5389 return true;
5390 }
5391
ValidateReadPixelsBase(Context * context,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,GLsizei * length,GLsizei * columns,GLsizei * rows,void * pixels)5392 bool ValidateReadPixelsBase(Context *context,
5393 GLint x,
5394 GLint y,
5395 GLsizei width,
5396 GLsizei height,
5397 GLenum format,
5398 GLenum type,
5399 GLsizei bufSize,
5400 GLsizei *length,
5401 GLsizei *columns,
5402 GLsizei *rows,
5403 void *pixels)
5404 {
5405 if (length != nullptr)
5406 {
5407 *length = 0;
5408 }
5409 if (rows != nullptr)
5410 {
5411 *rows = 0;
5412 }
5413 if (columns != nullptr)
5414 {
5415 *columns = 0;
5416 }
5417
5418 if (width < 0 || height < 0)
5419 {
5420 context->validationError(GL_INVALID_VALUE, kNegativeSize);
5421 return false;
5422 }
5423
5424 Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
5425
5426 if (!ValidateFramebufferComplete(context, readFramebuffer))
5427 {
5428 return false;
5429 }
5430
5431 if (readFramebuffer->id() != 0 && !ValidateFramebufferNotMultisampled(context, readFramebuffer))
5432 {
5433 return false;
5434 }
5435
5436 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
5437 ASSERT(framebuffer);
5438
5439 if (framebuffer->getReadBufferState() == GL_NONE)
5440 {
5441 context->validationError(GL_INVALID_OPERATION, kReadBufferNone);
5442 return false;
5443 }
5444
5445 const FramebufferAttachment *readBuffer = framebuffer->getReadColorAttachment();
5446 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
5447 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
5448 // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the
5449 // situation is an application error that would lead to a crash in ANGLE.
5450 if (readBuffer == nullptr)
5451 {
5452 context->validationError(GL_INVALID_OPERATION, kMissingReadAttachment);
5453 return false;
5454 }
5455
5456 // OVR_multiview2, Revision 1:
5457 // ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if
5458 // the number of views in the current read framebuffer is more than one.
5459 if (framebuffer->readDisallowedByMultiview())
5460 {
5461 context->validationError(GL_INVALID_FRAMEBUFFER_OPERATION, kMultiviewReadFramebuffer);
5462 return false;
5463 }
5464
5465 if (context->getExtensions().webglCompatibility)
5466 {
5467 // The ES 2.0 spec states that the format must be "among those defined in table 3.4,
5468 // excluding formats LUMINANCE and LUMINANCE_ALPHA.". This requires validating the format
5469 // and type before validating the combination of format and type. However, the
5470 // dEQP-GLES3.functional.negative_api.buffer.read_pixels passes GL_LUMINANCE as a format and
5471 // verifies that GL_INVALID_OPERATION is generated.
5472 // TODO(geofflang): Update this check to be done in all/no cases once this is resolved in
5473 // dEQP/WebGL.
5474 if (!ValidReadPixelsFormatEnum(context, format))
5475 {
5476 context->validationError(GL_INVALID_ENUM, kInvalidFormat);
5477 return false;
5478 }
5479
5480 if (!ValidReadPixelsTypeEnum(context, type))
5481 {
5482 context->validationError(GL_INVALID_ENUM, kInvalidType);
5483 return false;
5484 }
5485 }
5486
5487 GLenum currentFormat = GL_NONE;
5488 ANGLE_VALIDATION_TRY(framebuffer->getImplementationColorReadFormat(context, ¤tFormat));
5489
5490 GLenum currentType = GL_NONE;
5491 ANGLE_VALIDATION_TRY(framebuffer->getImplementationColorReadType(context, ¤tType));
5492
5493 GLenum currentComponentType = readBuffer->getFormat().info->componentType;
5494
5495 bool validFormatTypeCombination =
5496 ValidReadPixelsFormatType(context, currentComponentType, format, type);
5497
5498 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
5499 {
5500 context->validationError(GL_INVALID_OPERATION, kMismatchedTypeAndFormat);
5501 return false;
5502 }
5503
5504 // Check for pixel pack buffer related API errors
5505 Buffer *pixelPackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelPack);
5506 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
5507 {
5508 // ...the buffer object's data store is currently mapped.
5509 context->validationError(GL_INVALID_OPERATION, kBufferMapped);
5510 return false;
5511 }
5512 if (context->getExtensions().webglCompatibility && pixelPackBuffer != nullptr &&
5513 pixelPackBuffer->isBoundForTransformFeedbackAndOtherUse())
5514 {
5515 context->validationError(GL_INVALID_OPERATION, kPixelPackBufferBoundForTransformFeedback);
5516 return false;
5517 }
5518
5519 // .. the data would be packed to the buffer object such that the memory writes required
5520 // would exceed the data store size.
5521 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
5522 const Extents size(width, height, 1);
5523 const auto &pack = context->getState().getPackState();
5524
5525 GLuint endByte = 0;
5526 if (!formatInfo.computePackUnpackEndByte(type, size, pack, false, &endByte))
5527 {
5528 context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
5529 return false;
5530 }
5531
5532 if (bufSize >= 0)
5533 {
5534 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
5535 {
5536 context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
5537 return false;
5538 }
5539 }
5540
5541 if (pixelPackBuffer != nullptr)
5542 {
5543 CheckedNumeric<size_t> checkedEndByte(endByte);
5544 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
5545 checkedEndByte += checkedOffset;
5546
5547 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
5548 {
5549 // Overflow past the end of the buffer
5550 context->validationError(GL_INVALID_OPERATION, kParamOverflow);
5551 return false;
5552 }
5553 }
5554
5555 if (pixelPackBuffer == nullptr && length != nullptr)
5556 {
5557 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
5558 {
5559 context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
5560 return false;
5561 }
5562
5563 *length = static_cast<GLsizei>(endByte);
5564 }
5565
5566 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize, GLsizei *outExtent) {
5567 angle::CheckedNumeric<int> clippedExtent(length);
5568 if (start < 0)
5569 {
5570 // "subtract" the area that is less than 0
5571 clippedExtent += start;
5572 }
5573
5574 angle::CheckedNumeric<int> readExtent = start;
5575 readExtent += length;
5576 if (!readExtent.IsValid())
5577 {
5578 return false;
5579 }
5580
5581 if (readExtent.ValueOrDie() > bufferSize)
5582 {
5583 // Subtract the region to the right of the read buffer
5584 clippedExtent -= (readExtent - bufferSize);
5585 }
5586
5587 if (!clippedExtent.IsValid())
5588 {
5589 return false;
5590 }
5591
5592 *outExtent = std::max(clippedExtent.ValueOrDie(), 0);
5593 return true;
5594 };
5595
5596 GLsizei writtenColumns = 0;
5597 if (!getClippedExtent(x, width, readBuffer->getSize().width, &writtenColumns))
5598 {
5599 context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
5600 return false;
5601 }
5602
5603 GLsizei writtenRows = 0;
5604 if (!getClippedExtent(y, height, readBuffer->getSize().height, &writtenRows))
5605 {
5606 context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
5607 return false;
5608 }
5609
5610 if (columns != nullptr)
5611 {
5612 *columns = writtenColumns;
5613 }
5614
5615 if (rows != nullptr)
5616 {
5617 *rows = writtenRows;
5618 }
5619
5620 return true;
5621 }
5622
5623 template <typename ParamType>
ValidateTexParameterBase(Context * context,TextureType target,GLenum pname,GLsizei bufSize,bool vectorParams,const ParamType * params)5624 bool ValidateTexParameterBase(Context *context,
5625 TextureType target,
5626 GLenum pname,
5627 GLsizei bufSize,
5628 bool vectorParams,
5629 const ParamType *params)
5630 {
5631 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5632 {
5633 context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
5634 return false;
5635 }
5636
5637 if (context->getTextureByType(target) == nullptr)
5638 {
5639 // Should only be possible for external textures
5640 context->validationError(GL_INVALID_ENUM, kTextureNotBound);
5641 return false;
5642 }
5643
5644 const GLsizei minBufSize = GetTexParameterCount(pname);
5645 if (bufSize >= 0 && bufSize < minBufSize)
5646 {
5647 context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
5648 return false;
5649 }
5650
5651 if (context->getClientMajorVersion() == 1 && !IsValidGLES1TextureParameter(pname))
5652 {
5653 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5654 return false;
5655 }
5656
5657 switch (pname)
5658 {
5659 case GL_TEXTURE_WRAP_R:
5660 case GL_TEXTURE_SWIZZLE_R:
5661 case GL_TEXTURE_SWIZZLE_G:
5662 case GL_TEXTURE_SWIZZLE_B:
5663 case GL_TEXTURE_SWIZZLE_A:
5664 case GL_TEXTURE_BASE_LEVEL:
5665 case GL_TEXTURE_MAX_LEVEL:
5666 case GL_TEXTURE_COMPARE_MODE:
5667 case GL_TEXTURE_COMPARE_FUNC:
5668 case GL_TEXTURE_MIN_LOD:
5669 case GL_TEXTURE_MAX_LOD:
5670 if (context->getClientMajorVersion() < 3 &&
5671 !(pname == GL_TEXTURE_WRAP_R && context->getExtensions().texture3DOES))
5672 {
5673 context->validationError(GL_INVALID_ENUM, kES3Required);
5674 return false;
5675 }
5676 if (target == TextureType::External && !context->getExtensions().eglImageExternalEssl3)
5677 {
5678 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5679 return false;
5680 }
5681 break;
5682
5683 case GL_GENERATE_MIPMAP:
5684 case GL_TEXTURE_CROP_RECT_OES:
5685 if (context->getClientMajorVersion() > 1)
5686 {
5687 context->validationError(GL_INVALID_ENUM, kGLES1Only);
5688 return false;
5689 }
5690 break;
5691 default:
5692 break;
5693 }
5694
5695 if (target == TextureType::_2DMultisample || target == TextureType::_2DMultisampleArray)
5696 {
5697 switch (pname)
5698 {
5699 case GL_TEXTURE_MIN_FILTER:
5700 case GL_TEXTURE_MAG_FILTER:
5701 case GL_TEXTURE_WRAP_S:
5702 case GL_TEXTURE_WRAP_T:
5703 case GL_TEXTURE_WRAP_R:
5704 case GL_TEXTURE_MIN_LOD:
5705 case GL_TEXTURE_MAX_LOD:
5706 case GL_TEXTURE_COMPARE_MODE:
5707 case GL_TEXTURE_COMPARE_FUNC:
5708 case GL_TEXTURE_BORDER_COLOR:
5709 context->validationError(GL_INVALID_ENUM, kInvalidPname);
5710 return false;
5711 }
5712 }
5713
5714 switch (pname)
5715 {
5716 case GL_TEXTURE_WRAP_S:
5717 case GL_TEXTURE_WRAP_T:
5718 case GL_TEXTURE_WRAP_R:
5719 {
5720 bool restrictedWrapModes =
5721 target == TextureType::External || target == TextureType::Rectangle;
5722 if (!ValidateTextureWrapModeValue(context, params, restrictedWrapModes))
5723 {
5724 return false;
5725 }
5726 }
5727 break;
5728
5729 case GL_TEXTURE_MIN_FILTER:
5730 {
5731 bool restrictedMinFilter =
5732 target == TextureType::External || target == TextureType::Rectangle;
5733 if (!ValidateTextureMinFilterValue(context, params, restrictedMinFilter))
5734 {
5735 return false;
5736 }
5737 }
5738 break;
5739
5740 case GL_TEXTURE_MAG_FILTER:
5741 if (!ValidateTextureMagFilterValue(context, params))
5742 {
5743 return false;
5744 }
5745 break;
5746
5747 case GL_TEXTURE_USAGE_ANGLE:
5748 if (!context->getExtensions().textureUsage)
5749 {
5750 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5751 return false;
5752 }
5753
5754 switch (ConvertToGLenum(params[0]))
5755 {
5756 case GL_NONE:
5757 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
5758 break;
5759
5760 default:
5761 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5762 return false;
5763 }
5764 break;
5765
5766 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5767 {
5768 GLfloat paramValue = static_cast<GLfloat>(params[0]);
5769 if (!ValidateTextureMaxAnisotropyValue(context, paramValue))
5770 {
5771 return false;
5772 }
5773 ASSERT(static_cast<ParamType>(paramValue) == params[0]);
5774 }
5775 break;
5776
5777 case GL_TEXTURE_MIN_LOD:
5778 case GL_TEXTURE_MAX_LOD:
5779 // any value is permissible
5780 break;
5781
5782 case GL_TEXTURE_COMPARE_MODE:
5783 if (!ValidateTextureCompareModeValue(context, params))
5784 {
5785 return false;
5786 }
5787 break;
5788
5789 case GL_TEXTURE_COMPARE_FUNC:
5790 if (!ValidateTextureCompareFuncValue(context, params))
5791 {
5792 return false;
5793 }
5794 break;
5795
5796 case GL_TEXTURE_SWIZZLE_R:
5797 case GL_TEXTURE_SWIZZLE_G:
5798 case GL_TEXTURE_SWIZZLE_B:
5799 case GL_TEXTURE_SWIZZLE_A:
5800 switch (ConvertToGLenum(params[0]))
5801 {
5802 case GL_RED:
5803 case GL_GREEN:
5804 case GL_BLUE:
5805 case GL_ALPHA:
5806 case GL_ZERO:
5807 case GL_ONE:
5808 break;
5809
5810 default:
5811 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5812 return false;
5813 }
5814 break;
5815
5816 case GL_TEXTURE_BASE_LEVEL:
5817 if (ConvertToGLint(params[0]) < 0)
5818 {
5819 context->validationError(GL_INVALID_VALUE, kBaseLevelNegative);
5820 return false;
5821 }
5822 if (target == TextureType::External && static_cast<GLuint>(params[0]) != 0)
5823 {
5824 context->validationError(GL_INVALID_OPERATION, kBaseLevelNonZero);
5825 return false;
5826 }
5827 if ((target == TextureType::_2DMultisample ||
5828 target == TextureType::_2DMultisampleArray) &&
5829 static_cast<GLuint>(params[0]) != 0)
5830 {
5831 context->validationError(GL_INVALID_OPERATION, kBaseLevelNonZero);
5832 return false;
5833 }
5834 if (target == TextureType::Rectangle && static_cast<GLuint>(params[0]) != 0)
5835 {
5836 context->validationError(GL_INVALID_OPERATION, kBaseLevelNonZero);
5837 return false;
5838 }
5839 break;
5840
5841 case GL_TEXTURE_MAX_LEVEL:
5842 if (ConvertToGLint(params[0]) < 0)
5843 {
5844 context->validationError(GL_INVALID_VALUE, kInvalidMipLevel);
5845 return false;
5846 }
5847 break;
5848
5849 case GL_DEPTH_STENCIL_TEXTURE_MODE:
5850 if (context->getClientVersion() < Version(3, 1))
5851 {
5852 context->validationError(GL_INVALID_ENUM, kEnumRequiresGLES31);
5853 return false;
5854 }
5855 switch (ConvertToGLenum(params[0]))
5856 {
5857 case GL_DEPTH_COMPONENT:
5858 case GL_STENCIL_INDEX:
5859 break;
5860
5861 default:
5862 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5863 return false;
5864 }
5865 break;
5866
5867 case GL_TEXTURE_SRGB_DECODE_EXT:
5868 if (!ValidateTextureSRGBDecodeValue(context, params))
5869 {
5870 return false;
5871 }
5872 break;
5873
5874 case GL_GENERATE_MIPMAP:
5875 if (context->getClientMajorVersion() > 1)
5876 {
5877 context->validationError(GL_INVALID_ENUM, kGLES1Only);
5878 return false;
5879 }
5880 break;
5881
5882 case GL_TEXTURE_CROP_RECT_OES:
5883 if (context->getClientMajorVersion() > 1)
5884 {
5885 context->validationError(GL_INVALID_ENUM, kGLES1Only);
5886 return false;
5887 }
5888 if (!vectorParams)
5889 {
5890 context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
5891 return false;
5892 }
5893 break;
5894
5895 case GL_TEXTURE_BORDER_COLOR:
5896 if (!context->getExtensions().textureBorderClamp)
5897 {
5898 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
5899 return false;
5900 }
5901 if (!vectorParams)
5902 {
5903 context->validationError(GL_INVALID_ENUM, kInsufficientBufferSize);
5904 return false;
5905 }
5906 break;
5907
5908 default:
5909 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5910 return false;
5911 }
5912
5913 return true;
5914 }
5915
5916 template bool ValidateTexParameterBase(Context *,
5917 TextureType,
5918 GLenum,
5919 GLsizei,
5920 bool,
5921 const GLfloat *);
5922 template bool ValidateTexParameterBase(Context *,
5923 TextureType,
5924 GLenum,
5925 GLsizei,
5926 bool,
5927 const GLint *);
5928 template bool ValidateTexParameterBase(Context *,
5929 TextureType,
5930 GLenum,
5931 GLsizei,
5932 bool,
5933 const GLuint *);
5934
ValidateVertexAttribIndex(Context * context,GLuint index)5935 bool ValidateVertexAttribIndex(Context *context, GLuint index)
5936 {
5937 if (index >= MAX_VERTEX_ATTRIBS)
5938 {
5939 context->validationError(GL_INVALID_VALUE, kIndexExceedsMaxVertexAttribute);
5940 return false;
5941 }
5942
5943 return true;
5944 }
5945
ValidateGetActiveUniformBlockivBase(Context * context,GLuint program,GLuint uniformBlockIndex,GLenum pname,GLsizei * length)5946 bool ValidateGetActiveUniformBlockivBase(Context *context,
5947 GLuint program,
5948 GLuint uniformBlockIndex,
5949 GLenum pname,
5950 GLsizei *length)
5951 {
5952 if (length)
5953 {
5954 *length = 0;
5955 }
5956
5957 if (context->getClientMajorVersion() < 3)
5958 {
5959 context->validationError(GL_INVALID_OPERATION, kES3Required);
5960 return false;
5961 }
5962
5963 Program *programObject = GetValidProgram(context, program);
5964 if (!programObject)
5965 {
5966 return false;
5967 }
5968
5969 if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
5970 {
5971 context->validationError(GL_INVALID_VALUE, kIndexExceedsActiveUniformBlockCount);
5972 return false;
5973 }
5974
5975 switch (pname)
5976 {
5977 case GL_UNIFORM_BLOCK_BINDING:
5978 case GL_UNIFORM_BLOCK_DATA_SIZE:
5979 case GL_UNIFORM_BLOCK_NAME_LENGTH:
5980 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
5981 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
5982 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
5983 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
5984 break;
5985
5986 default:
5987 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
5988 return false;
5989 }
5990
5991 if (length)
5992 {
5993 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
5994 {
5995 const InterfaceBlock &uniformBlock =
5996 programObject->getUniformBlockByIndex(uniformBlockIndex);
5997 *length = static_cast<GLsizei>(uniformBlock.memberIndexes.size());
5998 }
5999 else
6000 {
6001 *length = 1;
6002 }
6003 }
6004
6005 return true;
6006 }
6007
6008 template <typename ParamType>
ValidateSamplerParameterBase(Context * context,GLuint sampler,GLenum pname,GLsizei bufSize,bool vectorParams,const ParamType * params)6009 bool ValidateSamplerParameterBase(Context *context,
6010 GLuint sampler,
6011 GLenum pname,
6012 GLsizei bufSize,
6013 bool vectorParams,
6014 const ParamType *params)
6015 {
6016 if (context->getClientMajorVersion() < 3)
6017 {
6018 context->validationError(GL_INVALID_OPERATION, kES3Required);
6019 return false;
6020 }
6021
6022 if (!context->isSampler(sampler))
6023 {
6024 context->validationError(GL_INVALID_OPERATION, kInvalidSampler);
6025 return false;
6026 }
6027
6028 const GLsizei minBufSize = GetSamplerParameterCount(pname);
6029 if (bufSize >= 0 && bufSize < minBufSize)
6030 {
6031 context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize);
6032 return false;
6033 }
6034
6035 switch (pname)
6036 {
6037 case GL_TEXTURE_WRAP_S:
6038 case GL_TEXTURE_WRAP_T:
6039 case GL_TEXTURE_WRAP_R:
6040 if (!ValidateTextureWrapModeValue(context, params, false))
6041 {
6042 return false;
6043 }
6044 break;
6045
6046 case GL_TEXTURE_MIN_FILTER:
6047 if (!ValidateTextureMinFilterValue(context, params, false))
6048 {
6049 return false;
6050 }
6051 break;
6052
6053 case GL_TEXTURE_MAG_FILTER:
6054 if (!ValidateTextureMagFilterValue(context, params))
6055 {
6056 return false;
6057 }
6058 break;
6059
6060 case GL_TEXTURE_MIN_LOD:
6061 case GL_TEXTURE_MAX_LOD:
6062 // any value is permissible
6063 break;
6064
6065 case GL_TEXTURE_COMPARE_MODE:
6066 if (!ValidateTextureCompareModeValue(context, params))
6067 {
6068 return false;
6069 }
6070 break;
6071
6072 case GL_TEXTURE_COMPARE_FUNC:
6073 if (!ValidateTextureCompareFuncValue(context, params))
6074 {
6075 return false;
6076 }
6077 break;
6078
6079 case GL_TEXTURE_SRGB_DECODE_EXT:
6080 if (!ValidateTextureSRGBDecodeValue(context, params))
6081 {
6082 return false;
6083 }
6084 break;
6085
6086 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
6087 {
6088 GLfloat paramValue = static_cast<GLfloat>(params[0]);
6089 if (!ValidateTextureMaxAnisotropyValue(context, paramValue))
6090 {
6091 return false;
6092 }
6093 }
6094 break;
6095
6096 case GL_TEXTURE_BORDER_COLOR:
6097 if (!context->getExtensions().textureBorderClamp)
6098 {
6099 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
6100 return false;
6101 }
6102 if (!vectorParams)
6103 {
6104 context->validationError(GL_INVALID_ENUM, kInsufficientBufferSize);
6105 return false;
6106 }
6107 break;
6108
6109 default:
6110 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
6111 return false;
6112 }
6113
6114 return true;
6115 }
6116
6117 template bool ValidateSamplerParameterBase(Context *,
6118 GLuint,
6119 GLenum,
6120 GLsizei,
6121 bool,
6122 const GLfloat *);
6123 template bool ValidateSamplerParameterBase(Context *, GLuint, GLenum, GLsizei, bool, const GLint *);
6124 template bool ValidateSamplerParameterBase(Context *,
6125 GLuint,
6126 GLenum,
6127 GLsizei,
6128 bool,
6129 const GLuint *);
6130
ValidateGetSamplerParameterBase(Context * context,GLuint sampler,GLenum pname,GLsizei * length)6131 bool ValidateGetSamplerParameterBase(Context *context,
6132 GLuint sampler,
6133 GLenum pname,
6134 GLsizei *length)
6135 {
6136 if (length)
6137 {
6138 *length = 0;
6139 }
6140
6141 if (context->getClientMajorVersion() < 3)
6142 {
6143 context->validationError(GL_INVALID_OPERATION, kES3Required);
6144 return false;
6145 }
6146
6147 if (!context->isSampler(sampler))
6148 {
6149 context->validationError(GL_INVALID_OPERATION, kInvalidSampler);
6150 return false;
6151 }
6152
6153 switch (pname)
6154 {
6155 case GL_TEXTURE_WRAP_S:
6156 case GL_TEXTURE_WRAP_T:
6157 case GL_TEXTURE_WRAP_R:
6158 case GL_TEXTURE_MIN_FILTER:
6159 case GL_TEXTURE_MAG_FILTER:
6160 case GL_TEXTURE_MIN_LOD:
6161 case GL_TEXTURE_MAX_LOD:
6162 case GL_TEXTURE_COMPARE_MODE:
6163 case GL_TEXTURE_COMPARE_FUNC:
6164 break;
6165
6166 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
6167 if (!ValidateTextureMaxAnisotropyExtensionEnabled(context))
6168 {
6169 return false;
6170 }
6171 break;
6172
6173 case GL_TEXTURE_SRGB_DECODE_EXT:
6174 if (!context->getExtensions().textureSRGBDecode)
6175 {
6176 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
6177 return false;
6178 }
6179 break;
6180
6181 case GL_TEXTURE_BORDER_COLOR:
6182 if (!context->getExtensions().textureBorderClamp)
6183 {
6184 context->validationError(GL_INVALID_ENUM, kExtensionNotEnabled);
6185 return false;
6186 }
6187 break;
6188
6189 default:
6190 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
6191 return false;
6192 }
6193
6194 if (length)
6195 {
6196 *length = GetSamplerParameterCount(pname);
6197 }
6198 return true;
6199 }
6200
ValidateGetInternalFormativBase(Context * context,GLenum target,GLenum internalformat,GLenum pname,GLsizei bufSize,GLsizei * numParams)6201 bool ValidateGetInternalFormativBase(Context *context,
6202 GLenum target,
6203 GLenum internalformat,
6204 GLenum pname,
6205 GLsizei bufSize,
6206 GLsizei *numParams)
6207 {
6208 if (numParams)
6209 {
6210 *numParams = 0;
6211 }
6212
6213 if (context->getClientMajorVersion() < 3)
6214 {
6215 context->validationError(GL_INVALID_OPERATION, kES3Required);
6216 return false;
6217 }
6218
6219 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
6220 if (!formatCaps.renderbuffer)
6221 {
6222 context->validationError(GL_INVALID_ENUM, kFormatNotRenderable);
6223 return false;
6224 }
6225
6226 switch (target)
6227 {
6228 case GL_RENDERBUFFER:
6229 break;
6230
6231 case GL_TEXTURE_2D_MULTISAMPLE:
6232 if (context->getClientVersion() < ES_3_1 &&
6233 !context->getExtensions().textureMultisample)
6234 {
6235 context->validationError(GL_INVALID_ENUM,
6236 kMultisampleTextureExtensionOrES31Required);
6237 return false;
6238 }
6239 break;
6240 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES:
6241 if (!context->getExtensions().textureStorageMultisample2DArray)
6242 {
6243 context->validationError(GL_INVALID_ENUM, kMultisampleArrayExtensionRequired);
6244 return false;
6245 }
6246 break;
6247 default:
6248 context->validationError(GL_INVALID_ENUM, kInvalidTarget);
6249 return false;
6250 }
6251
6252 if (bufSize < 0)
6253 {
6254 context->validationError(GL_INVALID_VALUE, kInsufficientBufferSize);
6255 return false;
6256 }
6257
6258 GLsizei maxWriteParams = 0;
6259 switch (pname)
6260 {
6261 case GL_NUM_SAMPLE_COUNTS:
6262 maxWriteParams = 1;
6263 break;
6264
6265 case GL_SAMPLES:
6266 maxWriteParams = static_cast<GLsizei>(formatCaps.sampleCounts.size());
6267 break;
6268
6269 default:
6270 context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
6271 return false;
6272 }
6273
6274 if (numParams)
6275 {
6276 // glGetInternalFormativ will not overflow bufSize
6277 *numParams = std::min(bufSize, maxWriteParams);
6278 }
6279
6280 return true;
6281 }
6282
ValidateFramebufferNotMultisampled(Context * context,Framebuffer * framebuffer)6283 bool ValidateFramebufferNotMultisampled(Context *context, Framebuffer *framebuffer)
6284 {
6285 if (framebuffer->getSamples(context) != 0)
6286 {
6287 context->validationError(GL_INVALID_OPERATION, kInvalidMultisampledFramebufferOperation);
6288 return false;
6289 }
6290 return true;
6291 }
6292
ValidateMultitextureUnit(Context * context,GLenum texture)6293 bool ValidateMultitextureUnit(Context *context, GLenum texture)
6294 {
6295 if (texture < GL_TEXTURE0 || texture >= GL_TEXTURE0 + context->getCaps().maxMultitextureUnits)
6296 {
6297 context->validationError(GL_INVALID_ENUM, kInvalidMultitextureUnit);
6298 return false;
6299 }
6300 return true;
6301 }
6302
ValidateTexStorageMultisample(Context * context,TextureType target,GLsizei samples,GLint internalFormat,GLsizei width,GLsizei height)6303 bool ValidateTexStorageMultisample(Context *context,
6304 TextureType target,
6305 GLsizei samples,
6306 GLint internalFormat,
6307 GLsizei width,
6308 GLsizei height)
6309 {
6310 const Caps &caps = context->getCaps();
6311 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
6312 static_cast<GLuint>(height) > caps.max2DTextureSize)
6313 {
6314 context->validationError(GL_INVALID_VALUE, kTextureWidthOrHeightOutOfRange);
6315 return false;
6316 }
6317
6318 if (samples == 0)
6319 {
6320 context->validationError(GL_INVALID_VALUE, kSamplesZero);
6321 return false;
6322 }
6323
6324 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
6325 if (!formatCaps.textureAttachment)
6326 {
6327 context->validationError(GL_INVALID_ENUM, kRenderableInternalFormat);
6328 return false;
6329 }
6330
6331 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
6332 // is one of the unsized base internalformats listed in table 8.11.
6333 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
6334 if (formatInfo.internalFormat == GL_NONE)
6335 {
6336 context->validationError(GL_INVALID_ENUM, kUnsizedInternalFormatUnsupported);
6337 return false;
6338 }
6339
6340 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
6341 {
6342 context->validationError(GL_INVALID_OPERATION, kSamplesOutOfRange);
6343 return false;
6344 }
6345
6346 Texture *texture = context->getTextureByType(target);
6347 if (!texture || texture->id() == 0)
6348 {
6349 context->validationError(GL_INVALID_OPERATION, kZeroBoundToTarget);
6350 return false;
6351 }
6352
6353 if (texture->getImmutableFormat())
6354 {
6355 context->validationError(GL_INVALID_OPERATION, kImmutableTextureBound);
6356 return false;
6357 }
6358 return true;
6359 }
6360
ValidateTexStorage2DMultisampleBase(Context * context,TextureType target,GLsizei samples,GLint internalFormat,GLsizei width,GLsizei height)6361 bool ValidateTexStorage2DMultisampleBase(Context *context,
6362 TextureType target,
6363 GLsizei samples,
6364 GLint internalFormat,
6365 GLsizei width,
6366 GLsizei height)
6367 {
6368 if (target != TextureType::_2DMultisample)
6369 {
6370 context->validationError(GL_INVALID_ENUM, kInvalidTarget);
6371 return false;
6372 }
6373
6374 if (width < 1 || height < 1)
6375 {
6376 context->validationError(GL_INVALID_VALUE, kTextureSizeTooSmall);
6377 return false;
6378 }
6379
6380 return ValidateTexStorageMultisample(context, target, samples, internalFormat, width, height);
6381 }
6382
ValidateGetTexLevelParameterBase(Context * context,TextureTarget target,GLint level,GLenum pname,GLsizei * length)6383 bool ValidateGetTexLevelParameterBase(Context *context,
6384 TextureTarget target,
6385 GLint level,
6386 GLenum pname,
6387 GLsizei *length)
6388 {
6389
6390 if (length)
6391 {
6392 *length = 0;
6393 }
6394
6395 TextureType type = TextureTargetToType(target);
6396
6397 if (!ValidTexLevelDestinationTarget(context, type))
6398 {
6399 context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
6400 return false;
6401 }
6402
6403 if (context->getTextureByType(type) == nullptr)
6404 {
6405 context->validationError(GL_INVALID_ENUM, kTextureNotBound);
6406 return false;
6407 }
6408
6409 if (!ValidMipLevel(context, type, level))
6410 {
6411 context->validationError(GL_INVALID_VALUE, kInvalidMipLevel);
6412 return false;
6413 }
6414
6415 switch (pname)
6416 {
6417 case GL_TEXTURE_RED_TYPE:
6418 case GL_TEXTURE_GREEN_TYPE:
6419 case GL_TEXTURE_BLUE_TYPE:
6420 case GL_TEXTURE_ALPHA_TYPE:
6421 case GL_TEXTURE_DEPTH_TYPE:
6422 break;
6423 case GL_TEXTURE_RED_SIZE:
6424 case GL_TEXTURE_GREEN_SIZE:
6425 case GL_TEXTURE_BLUE_SIZE:
6426 case GL_TEXTURE_ALPHA_SIZE:
6427 case GL_TEXTURE_DEPTH_SIZE:
6428 case GL_TEXTURE_STENCIL_SIZE:
6429 case GL_TEXTURE_SHARED_SIZE:
6430 break;
6431 case GL_TEXTURE_INTERNAL_FORMAT:
6432 case GL_TEXTURE_WIDTH:
6433 case GL_TEXTURE_HEIGHT:
6434 case GL_TEXTURE_DEPTH:
6435 break;
6436 case GL_TEXTURE_SAMPLES:
6437 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
6438 break;
6439 case GL_TEXTURE_COMPRESSED:
6440 break;
6441 default:
6442 context->validationError(GL_INVALID_ENUM, kInvalidPname);
6443 return false;
6444 }
6445
6446 if (length)
6447 {
6448 *length = 1;
6449 }
6450 return true;
6451 }
6452
ValidateGetMultisamplefvBase(Context * context,GLenum pname,GLuint index,GLfloat * val)6453 bool ValidateGetMultisamplefvBase(Context *context, GLenum pname, GLuint index, GLfloat *val)
6454 {
6455 if (pname != GL_SAMPLE_POSITION)
6456 {
6457 context->validationError(GL_INVALID_ENUM, kInvalidPname);
6458 return false;
6459 }
6460
6461 Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
6462 GLint samples = framebuffer->getSamples(context);
6463
6464 if (index >= static_cast<GLuint>(samples))
6465 {
6466 context->validationError(GL_INVALID_VALUE, kIndexExceedsSamples);
6467 return false;
6468 }
6469
6470 return true;
6471 }
6472
ValidateSampleMaskiBase(Context * context,GLuint maskNumber,GLbitfield mask)6473 bool ValidateSampleMaskiBase(Context *context, GLuint maskNumber, GLbitfield mask)
6474 {
6475 if (maskNumber >= context->getCaps().maxSampleMaskWords)
6476 {
6477 context->validationError(GL_INVALID_VALUE, kInvalidSampleMaskNumber);
6478 return false;
6479 }
6480
6481 return true;
6482 }
6483
RecordDrawAttribsError(Context * context)6484 void RecordDrawAttribsError(Context *context)
6485 {
6486 // An overflow can happen when adding the offset. Check against a special constant.
6487 if (context->getStateCache().getNonInstancedVertexElementLimit() ==
6488 VertexAttribute::kIntegerOverflow ||
6489 context->getStateCache().getInstancedVertexElementLimit() ==
6490 VertexAttribute::kIntegerOverflow)
6491 {
6492 context->validationError(GL_INVALID_OPERATION, kIntegerOverflow);
6493 }
6494 else
6495 {
6496 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
6497 // We can return INVALID_OPERATION if our buffer does not have enough backing data.
6498 context->validationError(GL_INVALID_OPERATION, kInsufficientVertexBufferSize);
6499 }
6500 }
6501
ValidateLoseContextCHROMIUM(Context * context,GraphicsResetStatus current,GraphicsResetStatus other)6502 bool ValidateLoseContextCHROMIUM(Context *context,
6503 GraphicsResetStatus current,
6504 GraphicsResetStatus other)
6505 {
6506 if (!context->getExtensions().loseContextCHROMIUM)
6507 {
6508 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
6509 return false;
6510 }
6511
6512 switch (current)
6513 {
6514 case GraphicsResetStatus::GuiltyContextReset:
6515 case GraphicsResetStatus::InnocentContextReset:
6516 case GraphicsResetStatus::UnknownContextReset:
6517 break;
6518
6519 default:
6520 context->validationError(GL_INVALID_ENUM, kInvalidResetStatus);
6521 }
6522
6523 switch (other)
6524 {
6525 case GraphicsResetStatus::GuiltyContextReset:
6526 case GraphicsResetStatus::InnocentContextReset:
6527 case GraphicsResetStatus::UnknownContextReset:
6528 break;
6529
6530 default:
6531 context->validationError(GL_INVALID_ENUM, kInvalidResetStatus);
6532 }
6533
6534 return true;
6535 }
6536
6537 // GL_ANGLE_texture_storage_external
ValidateTexImage2DExternalANGLE(Context * context,TextureTarget target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type)6538 bool ValidateTexImage2DExternalANGLE(Context *context,
6539 TextureTarget target,
6540 GLint level,
6541 GLint internalformat,
6542 GLsizei width,
6543 GLsizei height,
6544 GLint border,
6545 GLenum format,
6546 GLenum type)
6547 {
6548 if (!context->getExtensions().textureExternalUpdateANGLE)
6549 {
6550 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
6551 return false;
6552 }
6553
6554 if (!ValidTexture2DDestinationTarget(context, target) &&
6555 !ValidTextureExternalTarget(context, target))
6556 {
6557 context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
6558 return false;
6559 }
6560
6561 if (context->getClientMajorVersion() <= 2)
6562 {
6563 if (!ValidateES2TexImageParametersBase(context, target, level, internalformat, false, false,
6564 0, 0, width, height, border, format, type, -1,
6565 nullptr))
6566 {
6567 return false;
6568 }
6569 }
6570 else
6571 {
6572 if (!ValidateES3TexImageParametersBase(context, target, level, internalformat, false, false,
6573 0, 0, 0, width, height, 1, border, format, type, -1,
6574 nullptr))
6575 {
6576 return false;
6577 }
6578 }
6579
6580 return true;
6581 }
6582
ValidateInvalidateTextureANGLE(Context * context,TextureType target)6583 bool ValidateInvalidateTextureANGLE(Context *context, TextureType target)
6584 {
6585 if (!context->getExtensions().textureExternalUpdateANGLE)
6586 {
6587 context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled);
6588 return false;
6589 }
6590
6591 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
6592 {
6593 context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget);
6594 return false;
6595 }
6596
6597 return true;
6598 }
6599
6600 } // namespace gl
6601