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_RED_RGTC1_EXT:
61 case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
62 case GL_COMPRESSED_RED_GREEN_RGTC2_EXT:
63 case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
64 case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT:
65 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:
66 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT:
67 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT:
68 return true;
69
70 default:
71 return false;
72 }
73 }
CompressedSubTextureFormatRequiresExactSize(GLenum internalFormat)74 bool CompressedSubTextureFormatRequiresExactSize(GLenum internalFormat)
75 {
76 // Compressed sub textures have additional formats that requires exact size.
77 // ES 3.1, Section 8.7, Page 171
78 return CompressedTextureFormatRequiresExactSize(internalFormat) ||
79 IsETC2EACFormat(internalFormat);
80 }
81
DifferenceCanOverflow(GLint a,GLint b)82 bool DifferenceCanOverflow(GLint a, GLint b)
83 {
84 CheckedNumeric<GLint> checkedA(a);
85 checkedA -= b;
86 // Use negation to make sure that the difference can't overflow regardless of the order.
87 checkedA = -checkedA;
88 return !checkedA.IsValid();
89 }
90
ValidReadPixelsTypeEnum(const Context * context,GLenum type)91 bool ValidReadPixelsTypeEnum(const Context *context, GLenum type)
92 {
93 switch (type)
94 {
95 // Types referenced in Table 3.4 of the ES 2.0.25 spec
96 case GL_UNSIGNED_BYTE:
97 case GL_UNSIGNED_SHORT_4_4_4_4:
98 case GL_UNSIGNED_SHORT_5_5_5_1:
99 case GL_UNSIGNED_SHORT_5_6_5:
100 return context->getClientVersion() >= ES_2_0;
101
102 // Types referenced in Table 3.2 of the ES 3.0.5 spec (Except depth stencil)
103 case GL_BYTE:
104 case GL_INT:
105 case GL_SHORT:
106 case GL_UNSIGNED_INT:
107 case GL_UNSIGNED_INT_10F_11F_11F_REV:
108 case GL_UNSIGNED_INT_24_8:
109 case GL_UNSIGNED_INT_2_10_10_10_REV:
110 case GL_UNSIGNED_INT_5_9_9_9_REV:
111 case GL_UNSIGNED_SHORT:
112 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
113 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
114 return context->getClientVersion() >= ES_3_0;
115
116 case GL_FLOAT:
117 return context->getClientVersion() >= ES_3_0 ||
118 context->getExtensions().textureFloatOES ||
119 context->getExtensions().colorBufferHalfFloatEXT;
120
121 case GL_HALF_FLOAT:
122 return context->getClientVersion() >= ES_3_0 ||
123 context->getExtensions().textureHalfFloatOES;
124
125 case GL_HALF_FLOAT_OES:
126 return context->getExtensions().colorBufferHalfFloatEXT;
127
128 default:
129 return false;
130 }
131 }
132
ValidReadPixelsFormatEnum(const Context * context,GLenum format)133 bool ValidReadPixelsFormatEnum(const Context *context, GLenum format)
134 {
135 switch (format)
136 {
137 // Formats referenced in Table 3.4 of the ES 2.0.25 spec (Except luminance)
138 case GL_RGBA:
139 case GL_RGB:
140 case GL_ALPHA:
141 return context->getClientVersion() >= ES_2_0;
142
143 // Formats referenced in Table 3.2 of the ES 3.0.5 spec
144 case GL_RG:
145 case GL_RED:
146 case GL_RGBA_INTEGER:
147 case GL_RGB_INTEGER:
148 case GL_RG_INTEGER:
149 case GL_RED_INTEGER:
150 return context->getClientVersion() >= ES_3_0;
151
152 case GL_SRGB_ALPHA_EXT:
153 case GL_SRGB_EXT:
154 return context->getExtensions().sRGBEXT;
155
156 case GL_BGRA_EXT:
157 return context->getExtensions().readFormatBgraEXT;
158
159 case GL_RGBX8_ANGLE:
160 return context->getExtensions().rgbxInternalFormatANGLE;
161
162 default:
163 return false;
164 }
165 }
166
ValidReadPixelsUnsignedNormalizedDepthType(const Context * context,const gl::InternalFormat * info,GLenum type)167 bool ValidReadPixelsUnsignedNormalizedDepthType(const Context *context,
168 const gl::InternalFormat *info,
169 GLenum type)
170 {
171 bool supportsReadDepthNV = (context->getExtensions().readDepthNV && (info->depthBits > 0) &&
172 (info->componentCount == 1));
173 switch (type)
174 {
175 case GL_UNSIGNED_SHORT:
176 case GL_UNSIGNED_INT:
177 case GL_UNSIGNED_INT_24_8:
178 return supportsReadDepthNV;
179 default:
180 return false;
181 }
182 }
183
ValidReadPixelsFloatDepthType(const Context * context,const gl::InternalFormat * info,GLenum type)184 bool ValidReadPixelsFloatDepthType(const Context *context,
185 const gl::InternalFormat *info,
186 GLenum type)
187 {
188 return context->getExtensions().readDepthNV && (type == GL_FLOAT) &&
189 context->getExtensions().depthBufferFloat2NV && (info->componentCount == 1);
190 }
191
ValidReadPixelsFormatType(const Context * context,const gl::InternalFormat * info,GLenum format,GLenum type)192 bool ValidReadPixelsFormatType(const Context *context,
193 const gl::InternalFormat *info,
194 GLenum format,
195 GLenum type)
196 {
197 switch (info->componentType)
198 {
199 case GL_UNSIGNED_NORMALIZED:
200 // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
201 // ReadPixels with BGRA even if the extension is not present
202 switch (format)
203 {
204 case GL_RGBA:
205 return ((type == GL_UNSIGNED_BYTE) && info->pixelBytes >= 1) ||
206 (context->getExtensions().textureNorm16EXT &&
207 (type == GL_UNSIGNED_SHORT) && info->pixelBytes >= 2);
208 case GL_BGRA_EXT:
209 return context->getExtensions().readFormatBgraEXT && (type == GL_UNSIGNED_BYTE);
210 case GL_STENCIL_INDEX_OES:
211 return context->getExtensions().readStencilNV && (type == GL_UNSIGNED_BYTE);
212 case GL_DEPTH_COMPONENT:
213 return ValidReadPixelsUnsignedNormalizedDepthType(context, info, type);
214 case GL_RGBX8_ANGLE:
215 return context->getExtensions().rgbxInternalFormatANGLE &&
216 (type == GL_UNSIGNED_BYTE);
217 default:
218 return false;
219 }
220 case GL_SIGNED_NORMALIZED:
221 return (format == GL_RGBA && type == GL_BYTE && info->pixelBytes >= 1) ||
222 (context->getExtensions().textureNorm16EXT && format == GL_RGBA &&
223 type == GL_UNSIGNED_SHORT && info->pixelBytes >= 2);
224
225 case GL_INT:
226 return (format == GL_RGBA_INTEGER && type == GL_INT);
227
228 case GL_UNSIGNED_INT:
229 return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
230
231 case GL_FLOAT:
232 switch (format)
233 {
234 case GL_RGBA:
235 return (type == GL_FLOAT);
236 case GL_DEPTH_COMPONENT:
237 return ValidReadPixelsFloatDepthType(context, info, type);
238 default:
239 return false;
240 }
241 default:
242 UNREACHABLE();
243 return false;
244 }
245 }
246
247 template <typename ParamType>
ValidateTextureWrapModeValue(const Context * context,angle::EntryPoint entryPoint,const ParamType * params,bool restrictedWrapModes)248 bool ValidateTextureWrapModeValue(const Context *context,
249 angle::EntryPoint entryPoint,
250 const ParamType *params,
251 bool restrictedWrapModes)
252 {
253 switch (ConvertToGLenum(params[0]))
254 {
255 case GL_CLAMP_TO_EDGE:
256 break;
257
258 case GL_CLAMP_TO_BORDER:
259 if (!context->getExtensions().textureBorderClampAny() &&
260 context->getClientVersion() < ES_3_2)
261 {
262 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
263 return false;
264 }
265 break;
266
267 case GL_REPEAT:
268 case GL_MIRRORED_REPEAT:
269 if (restrictedWrapModes)
270 {
271 // OES_EGL_image_external and ANGLE_texture_rectangle specifies this error.
272 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidWrapModeTexture);
273 return false;
274 }
275 break;
276
277 default:
278 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureWrap);
279 return false;
280 }
281
282 return true;
283 }
284
285 template <typename ParamType>
ValidateTextureMinFilterValue(const Context * context,angle::EntryPoint entryPoint,const ParamType * params,bool restrictedMinFilter)286 bool ValidateTextureMinFilterValue(const Context *context,
287 angle::EntryPoint entryPoint,
288 const ParamType *params,
289 bool restrictedMinFilter)
290 {
291 switch (ConvertToGLenum(params[0]))
292 {
293 case GL_NEAREST:
294 case GL_LINEAR:
295 break;
296
297 case GL_NEAREST_MIPMAP_NEAREST:
298 case GL_LINEAR_MIPMAP_NEAREST:
299 case GL_NEAREST_MIPMAP_LINEAR:
300 case GL_LINEAR_MIPMAP_LINEAR:
301 if (restrictedMinFilter)
302 {
303 // OES_EGL_image_external specifies this error.
304 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFilterTexture);
305 return false;
306 }
307 break;
308
309 default:
310 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureFilterParam);
311 return false;
312 }
313
314 return true;
315 }
316
317 template <typename ParamType>
ValidateTextureMagFilterValue(const Context * context,angle::EntryPoint entryPoint,const ParamType * params)318 bool ValidateTextureMagFilterValue(const Context *context,
319 angle::EntryPoint entryPoint,
320 const ParamType *params)
321 {
322 switch (ConvertToGLenum(params[0]))
323 {
324 case GL_NEAREST:
325 case GL_LINEAR:
326 break;
327
328 default:
329 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureFilterParam);
330 return false;
331 }
332
333 return true;
334 }
335
336 template <typename ParamType>
ValidateTextureCompareModeValue(const Context * context,angle::EntryPoint entryPoint,const ParamType * params)337 bool ValidateTextureCompareModeValue(const Context *context,
338 angle::EntryPoint entryPoint,
339 const ParamType *params)
340 {
341 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
342 switch (ConvertToGLenum(params[0]))
343 {
344 case GL_NONE:
345 case GL_COMPARE_REF_TO_TEXTURE:
346 break;
347
348 default:
349 context->validationError(entryPoint, GL_INVALID_ENUM, kUnknownParameter);
350 return false;
351 }
352
353 return true;
354 }
355
356 template <typename ParamType>
ValidateTextureCompareFuncValue(const Context * context,angle::EntryPoint entryPoint,const ParamType * params)357 bool ValidateTextureCompareFuncValue(const Context *context,
358 angle::EntryPoint entryPoint,
359 const ParamType *params)
360 {
361 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
362 switch (ConvertToGLenum(params[0]))
363 {
364 case GL_LEQUAL:
365 case GL_GEQUAL:
366 case GL_LESS:
367 case GL_GREATER:
368 case GL_EQUAL:
369 case GL_NOTEQUAL:
370 case GL_ALWAYS:
371 case GL_NEVER:
372 break;
373
374 default:
375 context->validationError(entryPoint, GL_INVALID_ENUM, kUnknownParameter);
376 return false;
377 }
378
379 return true;
380 }
381
382 template <typename ParamType>
ValidateTextureSRGBDecodeValue(const Context * context,angle::EntryPoint entryPoint,const ParamType * params)383 bool ValidateTextureSRGBDecodeValue(const Context *context,
384 angle::EntryPoint entryPoint,
385 const ParamType *params)
386 {
387 if (!context->getExtensions().textureSRGBDecodeEXT)
388 {
389 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
390 return false;
391 }
392
393 switch (ConvertToGLenum(params[0]))
394 {
395 case GL_DECODE_EXT:
396 case GL_SKIP_DECODE_EXT:
397 break;
398
399 default:
400 context->validationError(entryPoint, GL_INVALID_ENUM, kUnknownParameter);
401 return false;
402 }
403
404 return true;
405 }
406
407 template <typename ParamType>
ValidateTextureSRGBOverrideValue(const Context * context,angle::EntryPoint entryPoint,const ParamType * params)408 bool ValidateTextureSRGBOverrideValue(const Context *context,
409 angle::EntryPoint entryPoint,
410 const ParamType *params)
411 {
412 if (!context->getExtensions().textureFormatSRGBOverrideEXT)
413 {
414 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
415 return false;
416 }
417
418 switch (ConvertToGLenum(params[0]))
419 {
420 case GL_SRGB:
421 case GL_NONE:
422 break;
423
424 default:
425 context->validationError(entryPoint, GL_INVALID_ENUM, kUnknownParameter);
426 return false;
427 }
428
429 return true;
430 }
431
ValidateTextureMaxAnisotropyExtensionEnabled(const Context * context,angle::EntryPoint entryPoint)432 bool ValidateTextureMaxAnisotropyExtensionEnabled(const Context *context,
433 angle::EntryPoint entryPoint)
434 {
435 if (!context->getExtensions().textureFilterAnisotropicEXT)
436 {
437 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
438 return false;
439 }
440
441 return true;
442 }
443
ValidateTextureMaxAnisotropyValue(const Context * context,angle::EntryPoint entryPoint,GLfloat paramValue)444 bool ValidateTextureMaxAnisotropyValue(const Context *context,
445 angle::EntryPoint entryPoint,
446 GLfloat paramValue)
447 {
448 if (!ValidateTextureMaxAnisotropyExtensionEnabled(context, entryPoint))
449 {
450 return false;
451 }
452
453 GLfloat largest = context->getCaps().maxTextureAnisotropy;
454
455 if (paramValue < 1 || paramValue > largest)
456 {
457 context->validationError(entryPoint, GL_INVALID_VALUE, kOutsideOfBounds);
458 return false;
459 }
460
461 return true;
462 }
463
ValidateFragmentShaderColorBufferMaskMatch(const Context * context)464 bool ValidateFragmentShaderColorBufferMaskMatch(const Context *context)
465 {
466 const Program *program = context->getActiveLinkedProgram();
467 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
468
469 auto drawBufferMask = framebuffer->getDrawBufferMask().to_ulong();
470 auto fragmentOutputMask = program->getExecutable().getActiveOutputVariablesMask().to_ulong();
471
472 return drawBufferMask == (drawBufferMask & fragmentOutputMask);
473 }
474
ValidateFragmentShaderColorBufferTypeMatch(const Context * context)475 bool ValidateFragmentShaderColorBufferTypeMatch(const Context *context)
476 {
477 const ProgramExecutable *executable = context->getState().getProgramExecutable();
478 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
479
480 return ValidateComponentTypeMasks(executable->getFragmentOutputsTypeMask().to_ulong(),
481 framebuffer->getDrawBufferTypeMask().to_ulong(),
482 executable->getActiveOutputVariablesMask().to_ulong(),
483 framebuffer->getDrawBufferMask().to_ulong());
484 }
485
ValidateVertexShaderAttributeTypeMatch(const Context * context)486 bool ValidateVertexShaderAttributeTypeMatch(const Context *context)
487 {
488 const auto &glState = context->getState();
489 const Program *program = context->getActiveLinkedProgram();
490 const VertexArray *vao = context->getState().getVertexArray();
491
492 if (!program)
493 {
494 return false;
495 }
496
497 unsigned long stateCurrentValuesTypeBits = glState.getCurrentValuesTypeMask().to_ulong();
498 unsigned long vaoAttribTypeBits = vao->getAttributesTypeMask().to_ulong();
499 unsigned long vaoAttribEnabledMask = vao->getAttributesMask().to_ulong();
500
501 vaoAttribEnabledMask |= vaoAttribEnabledMask << kMaxComponentTypeMaskIndex;
502 vaoAttribTypeBits = (vaoAttribEnabledMask & vaoAttribTypeBits);
503 vaoAttribTypeBits |= (~vaoAttribEnabledMask & stateCurrentValuesTypeBits);
504
505 const ProgramExecutable &executable = program->getExecutable();
506 return ValidateComponentTypeMasks(executable.getAttributesTypeMask().to_ulong(),
507 vaoAttribTypeBits, executable.getAttributesMask().to_ulong(),
508 0xFFFF);
509 }
510
IsCompatibleDrawModeWithGeometryShader(PrimitiveMode drawMode,PrimitiveMode geometryShaderInputPrimitiveType)511 bool IsCompatibleDrawModeWithGeometryShader(PrimitiveMode drawMode,
512 PrimitiveMode geometryShaderInputPrimitiveType)
513 {
514 // [EXT_geometry_shader] Section 11.1gs.1, Geometry Shader Input Primitives
515 switch (drawMode)
516 {
517 case PrimitiveMode::Points:
518 return geometryShaderInputPrimitiveType == PrimitiveMode::Points;
519 case PrimitiveMode::Lines:
520 case PrimitiveMode::LineStrip:
521 case PrimitiveMode::LineLoop:
522 return geometryShaderInputPrimitiveType == PrimitiveMode::Lines;
523 case PrimitiveMode::LinesAdjacency:
524 case PrimitiveMode::LineStripAdjacency:
525 return geometryShaderInputPrimitiveType == PrimitiveMode::LinesAdjacency;
526 case PrimitiveMode::Triangles:
527 case PrimitiveMode::TriangleFan:
528 case PrimitiveMode::TriangleStrip:
529 return geometryShaderInputPrimitiveType == PrimitiveMode::Triangles;
530 case PrimitiveMode::TrianglesAdjacency:
531 case PrimitiveMode::TriangleStripAdjacency:
532 return geometryShaderInputPrimitiveType == PrimitiveMode::TrianglesAdjacency;
533 default:
534 UNREACHABLE();
535 return false;
536 }
537 }
538
539 // GLES1 texture parameters are a small subset of the others
IsValidGLES1TextureParameter(GLenum pname)540 bool IsValidGLES1TextureParameter(GLenum pname)
541 {
542 switch (pname)
543 {
544 case GL_TEXTURE_MAG_FILTER:
545 case GL_TEXTURE_MIN_FILTER:
546 case GL_TEXTURE_WRAP_S:
547 case GL_TEXTURE_WRAP_T:
548 case GL_TEXTURE_WRAP_R:
549 case GL_GENERATE_MIPMAP:
550 case GL_TEXTURE_CROP_RECT_OES:
551 return true;
552 default:
553 return false;
554 }
555 }
556
GetSamplerParameterCount(GLenum pname)557 unsigned int GetSamplerParameterCount(GLenum pname)
558 {
559 return pname == GL_TEXTURE_BORDER_COLOR ? 4 : 1;
560 }
561
ValidateProgramDrawStates(const Context * context,const Extensions & extensions,Program * program)562 ANGLE_INLINE const char *ValidateProgramDrawStates(const Context *context,
563 const Extensions &extensions,
564 Program *program)
565 {
566 const State &state = context->getState();
567 if (extensions.multiviewOVR || extensions.multiview2OVR)
568 {
569 const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1;
570 Framebuffer *framebuffer = state.getDrawFramebuffer();
571 const int framebufferNumViews = framebuffer->getNumViews();
572
573 if (framebufferNumViews != programNumViews)
574 {
575 return gl::err::kMultiviewMismatch;
576 }
577
578 if (state.isTransformFeedbackActiveUnpaused() && framebufferNumViews > 1)
579 {
580 return gl::err::kMultiviewTransformFeedback;
581 }
582
583 if (extensions.disjointTimerQueryEXT && framebufferNumViews > 1 &&
584 state.isQueryActive(QueryType::TimeElapsed))
585 {
586 return gl::err::kMultiviewTimerQuery;
587 }
588 }
589
590 // Uniform buffer validation
591 for (unsigned int uniformBlockIndex = 0;
592 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
593 {
594 const InterfaceBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
595 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
596 const OffsetBindingPointer<Buffer> &uniformBuffer =
597 state.getIndexedUniformBuffer(blockBinding);
598
599 if (uniformBuffer.get() == nullptr && context->isWebGL())
600 {
601 // undefined behaviour
602 return gl::err::kUniformBufferUnbound;
603 }
604
605 size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
606 if (uniformBufferSize < uniformBlock.dataSize &&
607 (context->isWebGL() || context->isBufferAccessValidationEnabled()))
608 {
609 // undefined behaviour
610 return gl::err::kUniformBufferTooSmall;
611 }
612
613 if (uniformBuffer->hasWebGLXFBBindingConflict(context->isWebGL()))
614 {
615 return gl::err::kUniformBufferBoundForTransformFeedback;
616 }
617 }
618
619 return nullptr;
620 }
621 } // anonymous namespace
622
SetRobustLengthParam(const GLsizei * length,GLsizei value)623 void SetRobustLengthParam(const GLsizei *length, GLsizei value)
624 {
625 if (length)
626 {
627 // Currently we modify robust length parameters in the validation layer. We should be only
628 // doing this in the Context instead.
629 // TODO(http://anglebug.com/4406): Remove when possible.
630 *const_cast<GLsizei *>(length) = value;
631 }
632 }
633
ValidTextureTarget(const Context * context,TextureType type)634 bool ValidTextureTarget(const Context *context, TextureType type)
635 {
636 switch (type)
637 {
638 case TextureType::_2D:
639 case TextureType::CubeMap:
640 return true;
641
642 case TextureType::Rectangle:
643 return context->getExtensions().textureRectangleANGLE;
644
645 case TextureType::_3D:
646 return ((context->getClientMajorVersion() >= 3) ||
647 context->getExtensions().texture3DOES);
648
649 case TextureType::_2DArray:
650 return (context->getClientMajorVersion() >= 3);
651
652 case TextureType::_2DMultisample:
653 return (context->getClientVersion() >= Version(3, 1) ||
654 context->getExtensions().textureMultisampleANGLE);
655 case TextureType::_2DMultisampleArray:
656 return context->getExtensions().textureStorageMultisample2dArrayOES;
657
658 case TextureType::CubeMapArray:
659 return (context->getClientVersion() >= Version(3, 2) ||
660 context->getExtensions().textureCubeMapArrayAny());
661
662 case TextureType::VideoImage:
663 return context->getExtensions().videoTextureWEBGL;
664
665 case TextureType::Buffer:
666 return (context->getClientVersion() >= Version(3, 2) ||
667 context->getExtensions().textureBufferAny());
668
669 default:
670 return false;
671 }
672 }
673
ValidTexture2DTarget(const Context * context,TextureType type)674 bool ValidTexture2DTarget(const Context *context, TextureType type)
675 {
676 switch (type)
677 {
678 case TextureType::_2D:
679 case TextureType::CubeMap:
680 return true;
681
682 case TextureType::Rectangle:
683 return context->getExtensions().textureRectangleANGLE;
684
685 default:
686 return false;
687 }
688 }
689
ValidTexture3DTarget(const Context * context,TextureType target)690 bool ValidTexture3DTarget(const Context *context, TextureType target)
691 {
692 switch (target)
693 {
694 case TextureType::_3D:
695 case TextureType::_2DArray:
696 return (context->getClientMajorVersion() >= 3);
697
698 case TextureType::CubeMapArray:
699 return (context->getClientVersion() >= Version(3, 2) ||
700 context->getExtensions().textureCubeMapArrayAny());
701
702 default:
703 return false;
704 }
705 }
706
707 // Most texture GL calls are not compatible with external textures, so we have a separate validation
708 // function for use in the GL calls that do
ValidTextureExternalTarget(const Context * context,TextureType target)709 bool ValidTextureExternalTarget(const Context *context, TextureType target)
710 {
711 return (target == TextureType::External) &&
712 (context->getExtensions().EGLImageExternalOES ||
713 context->getExtensions().EGLStreamConsumerExternalNV);
714 }
715
ValidTextureExternalTarget(const Context * context,TextureTarget target)716 bool ValidTextureExternalTarget(const Context *context, TextureTarget target)
717 {
718 return (target == TextureTarget::External) &&
719 ValidTextureExternalTarget(context, TextureType::External);
720 }
721
722 // This function differs from ValidTextureTarget in that the target must be
723 // usable as the destination of a 2D operation-- so a cube face is valid, but
724 // GL_TEXTURE_CUBE_MAP is not.
725 // Note: duplicate of IsInternalTextureTarget
ValidTexture2DDestinationTarget(const Context * context,TextureTarget target)726 bool ValidTexture2DDestinationTarget(const Context *context, TextureTarget target)
727 {
728 switch (target)
729 {
730 case TextureTarget::_2D:
731 case TextureTarget::CubeMapNegativeX:
732 case TextureTarget::CubeMapNegativeY:
733 case TextureTarget::CubeMapNegativeZ:
734 case TextureTarget::CubeMapPositiveX:
735 case TextureTarget::CubeMapPositiveY:
736 case TextureTarget::CubeMapPositiveZ:
737 return true;
738 case TextureTarget::Rectangle:
739 return context->getExtensions().textureRectangleANGLE;
740 case TextureTarget::VideoImage:
741 return context->getExtensions().videoTextureWEBGL;
742 default:
743 return false;
744 }
745 }
746
ValidateTransformFeedbackPrimitiveMode(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode transformFeedbackPrimitiveMode,PrimitiveMode renderPrimitiveMode)747 bool ValidateTransformFeedbackPrimitiveMode(const Context *context,
748 angle::EntryPoint entryPoint,
749 PrimitiveMode transformFeedbackPrimitiveMode,
750 PrimitiveMode renderPrimitiveMode)
751 {
752 ASSERT(context);
753
754 if ((!context->getExtensions().geometryShaderAny() ||
755 !context->getExtensions().tessellationShaderEXT) &&
756 context->getClientVersion() < ES_3_2)
757 {
758 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
759 // that does not match the current transform feedback object's draw mode (if transform
760 // feedback is active), (3.0.2, section 2.14, pg 86)
761 return transformFeedbackPrimitiveMode == renderPrimitiveMode;
762 }
763
764 const ProgramExecutable *executable = context->getState().getProgramExecutable();
765 ASSERT(executable);
766 if (executable->hasLinkedShaderStage(ShaderType::Geometry))
767 {
768 // If geometry shader is active, transform feedback mode must match what is output from this
769 // stage.
770 renderPrimitiveMode = executable->getGeometryShaderOutputPrimitiveType();
771 }
772 else if (executable->hasLinkedShaderStage(ShaderType::TessEvaluation))
773 {
774 // Similarly with tessellation shaders, but only if no geometry shader is present. With
775 // tessellation shaders, only triangles are possibly output.
776 return transformFeedbackPrimitiveMode == PrimitiveMode::Triangles &&
777 executable->getTessGenMode() == GL_TRIANGLES;
778 }
779
780 // [GL_EXT_geometry_shader] Table 12.1gs
781 switch (renderPrimitiveMode)
782 {
783 case PrimitiveMode::Points:
784 return transformFeedbackPrimitiveMode == PrimitiveMode::Points;
785 case PrimitiveMode::Lines:
786 case PrimitiveMode::LineStrip:
787 case PrimitiveMode::LineLoop:
788 return transformFeedbackPrimitiveMode == PrimitiveMode::Lines;
789 case PrimitiveMode::Triangles:
790 case PrimitiveMode::TriangleFan:
791 case PrimitiveMode::TriangleStrip:
792 return transformFeedbackPrimitiveMode == PrimitiveMode::Triangles;
793 case PrimitiveMode::Patches:
794 return transformFeedbackPrimitiveMode == PrimitiveMode::Patches;
795 default:
796 UNREACHABLE();
797 return false;
798 }
799 }
800
ValidateDrawElementsInstancedBase(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLsizei count,DrawElementsType type,const void * indices,GLsizei primcount)801 bool ValidateDrawElementsInstancedBase(const Context *context,
802 angle::EntryPoint entryPoint,
803 PrimitiveMode mode,
804 GLsizei count,
805 DrawElementsType type,
806 const void *indices,
807 GLsizei primcount)
808 {
809 if (primcount <= 0)
810 {
811 if (primcount < 0)
812 {
813 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativePrimcount);
814 return false;
815 }
816
817 // Early exit.
818 return ValidateDrawElementsCommon(context, entryPoint, mode, count, type, indices,
819 primcount);
820 }
821
822 if (!ValidateDrawElementsCommon(context, entryPoint, mode, count, type, indices, primcount))
823 {
824 return false;
825 }
826
827 if (count == 0)
828 {
829 // Early exit.
830 return true;
831 }
832
833 return ValidateDrawInstancedAttribs(context, entryPoint, primcount);
834 }
835
ValidateDrawArraysInstancedBase(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)836 bool ValidateDrawArraysInstancedBase(const Context *context,
837 angle::EntryPoint entryPoint,
838 PrimitiveMode mode,
839 GLint first,
840 GLsizei count,
841 GLsizei primcount)
842 {
843 if (primcount <= 0)
844 {
845 if (primcount < 0)
846 {
847 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativePrimcount);
848 return false;
849 }
850
851 // Early exit.
852 return ValidateDrawArraysCommon(context, entryPoint, mode, first, count, primcount);
853 }
854
855 if (!ValidateDrawArraysCommon(context, entryPoint, mode, first, count, primcount))
856 {
857 return false;
858 }
859
860 if (count == 0)
861 {
862 // Early exit.
863 return true;
864 }
865
866 return ValidateDrawInstancedAttribs(context, entryPoint, primcount);
867 }
868
ValidateDrawInstancedANGLE(const Context * context,angle::EntryPoint entryPoint)869 bool ValidateDrawInstancedANGLE(const Context *context, angle::EntryPoint entryPoint)
870 {
871 // Verify there is at least one active attribute with a divisor of zero
872 const State &state = context->getState();
873 const ProgramExecutable *executable = state.getProgramExecutable();
874
875 if (!executable)
876 {
877 // No executable means there is no Program/PPO bound, which is undefined behavior, but isn't
878 // an error.
879 context->getState().getDebug().insertMessage(
880 GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, 0, GL_DEBUG_SEVERITY_HIGH,
881 std::string("Attempting to draw without a program"), gl::LOG_WARN, entryPoint);
882 return true;
883 }
884
885 const auto &attribs = state.getVertexArray()->getVertexAttributes();
886 const auto &bindings = state.getVertexArray()->getVertexBindings();
887 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
888 {
889 const VertexAttribute &attrib = attribs[attributeIndex];
890 const VertexBinding &binding = bindings[attrib.bindingIndex];
891 if (executable->isAttribLocationActive(attributeIndex) && binding.getDivisor() == 0)
892 {
893 return true;
894 }
895 }
896
897 context->validationError(entryPoint, GL_INVALID_OPERATION, kNoZeroDivisor);
898 return false;
899 }
900
ValidTexture3DDestinationTarget(const Context * context,TextureTarget target)901 bool ValidTexture3DDestinationTarget(const Context *context, TextureTarget target)
902 {
903 switch (target)
904 {
905 case TextureTarget::_3D:
906 case TextureTarget::_2DArray:
907 return true;
908 case TextureTarget::CubeMapArray:
909 return (context->getClientVersion() >= Version(3, 2) ||
910 context->getExtensions().textureCubeMapArrayAny());
911 default:
912 return false;
913 }
914 }
915
ValidTexLevelDestinationTarget(const Context * context,TextureType type)916 bool ValidTexLevelDestinationTarget(const Context *context, TextureType type)
917 {
918 switch (type)
919 {
920 case TextureType::_2D:
921 case TextureType::_2DArray:
922 case TextureType::_2DMultisample:
923 case TextureType::CubeMap:
924 case TextureType::_3D:
925 return true;
926 case TextureType::CubeMapArray:
927 return (context->getClientVersion() >= Version(3, 2) ||
928 context->getExtensions().textureCubeMapArrayAny());
929 case TextureType::Rectangle:
930 return context->getExtensions().textureRectangleANGLE;
931 case TextureType::_2DMultisampleArray:
932 return context->getExtensions().textureStorageMultisample2dArrayOES;
933 case TextureType::Buffer:
934 return (context->getClientVersion() >= Version(3, 2) ||
935 context->getExtensions().textureBufferAny());
936 default:
937 return false;
938 }
939 }
940
ValidFramebufferTarget(const Context * context,GLenum target)941 bool ValidFramebufferTarget(const Context *context, GLenum target)
942 {
943 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER &&
944 GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
945 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
946
947 switch (target)
948 {
949 case GL_FRAMEBUFFER:
950 return true;
951
952 case GL_READ_FRAMEBUFFER:
953 case GL_DRAW_FRAMEBUFFER:
954 return (context->getExtensions().framebufferBlitAny() ||
955 context->getClientMajorVersion() >= 3);
956
957 default:
958 return false;
959 }
960 }
961
ValidMipLevel(const Context * context,TextureType type,GLint level)962 bool ValidMipLevel(const Context *context, TextureType type, GLint level)
963 {
964 const auto &caps = context->getCaps();
965 int maxDimension = 0;
966 switch (type)
967 {
968 case TextureType::_2D:
969 case TextureType::_2DArray:
970 case TextureType::_2DMultisample:
971 case TextureType::_2DMultisampleArray:
972 // TODO(http://anglebug.com/2775): It's a bit unclear what the "maximum allowable
973 // level-of-detail" for multisample textures should be. Could maybe make it zero.
974 maxDimension = caps.max2DTextureSize;
975 break;
976
977 case TextureType::CubeMap:
978 case TextureType::CubeMapArray:
979 maxDimension = caps.maxCubeMapTextureSize;
980 break;
981
982 case TextureType::External:
983 case TextureType::Rectangle:
984 case TextureType::VideoImage:
985 case TextureType::Buffer:
986 return level == 0;
987
988 case TextureType::_3D:
989 maxDimension = caps.max3DTextureSize;
990 break;
991
992 default:
993 UNREACHABLE();
994 }
995
996 return level <= log2(maxDimension) && level >= 0;
997 }
998
ValidImageSizeParameters(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLint level,GLsizei width,GLsizei height,GLsizei depth,bool isSubImage)999 bool ValidImageSizeParameters(const Context *context,
1000 angle::EntryPoint entryPoint,
1001 TextureType target,
1002 GLint level,
1003 GLsizei width,
1004 GLsizei height,
1005 GLsizei depth,
1006 bool isSubImage)
1007 {
1008 if (width < 0 || height < 0 || depth < 0)
1009 {
1010 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeSize);
1011 return false;
1012 }
1013 // TexSubImage parameters can be NPOT without textureNPOT extension,
1014 // as long as the destination texture is POT.
1015 bool hasNPOTSupport =
1016 context->getExtensions().textureNpotOES || context->getClientVersion() >= Version(3, 0);
1017 if (!isSubImage && !hasNPOTSupport &&
1018 (level != 0 && (!isPow2(width) || !isPow2(height) || !isPow2(depth))))
1019 {
1020 context->validationError(entryPoint, GL_INVALID_VALUE, kTextureNotPow2);
1021 return false;
1022 }
1023
1024 if (!ValidMipLevel(context, target, level))
1025 {
1026 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
1027 return false;
1028 }
1029
1030 return true;
1031 }
1032
ValidCompressedDimension(GLsizei size,GLuint blockSize,GLint level)1033 bool ValidCompressedDimension(GLsizei size, GLuint blockSize, GLint level)
1034 {
1035 return (level > 0) || (size % blockSize == 0);
1036 }
1037
ValidCompressedBaseLevelForWebGL(GLsizei size,GLuint blockSize,GLint level)1038 bool ValidCompressedBaseLevelForWebGL(GLsizei size, GLuint blockSize, GLint level)
1039 {
1040 // Avoid C++ undefined behavior.
1041 constexpr int maxValidShifts = 31;
1042 if (level > maxValidShifts)
1043 return false;
1044 return ((size << level) % blockSize) == 0;
1045 }
1046
ValidCompressedImageSize(const Context * context,GLenum internalFormat,GLint level,GLsizei width,GLsizei height,GLsizei depth)1047 bool ValidCompressedImageSize(const Context *context,
1048 GLenum internalFormat,
1049 GLint level,
1050 GLsizei width,
1051 GLsizei height,
1052 GLsizei depth)
1053 {
1054 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
1055 if (!formatInfo.compressed)
1056 {
1057 return false;
1058 }
1059
1060 if (width < 0 || height < 0)
1061 {
1062 return false;
1063 }
1064
1065 // Only PVRTC1 requires dimensions to be powers of two
1066 if (IsPVRTC1Format(internalFormat))
1067 {
1068 if (!isPow2(width) || !isPow2(height))
1069 {
1070 return false;
1071 }
1072
1073 if (context->getLimitations().squarePvrtc1)
1074 {
1075 if (width != height)
1076 {
1077 return false;
1078 }
1079 }
1080 }
1081
1082 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1083 {
1084 // In WebGL compatibility mode, enforce that the base level implied
1085 // by the compressed texture's mip level would conform to the block
1086 // size. This is more strict than the non-WebGL check.
1087 if (context->isWebGL())
1088 {
1089 if (!ValidCompressedBaseLevelForWebGL(width, formatInfo.compressedBlockWidth, level) ||
1090 !ValidCompressedBaseLevelForWebGL(height, formatInfo.compressedBlockHeight,
1091 level) ||
1092 !ValidCompressedBaseLevelForWebGL(depth, formatInfo.compressedBlockDepth, level))
1093 {
1094 return false;
1095 }
1096 }
1097 else
1098 {
1099 if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth, level) ||
1100 !ValidCompressedDimension(height, formatInfo.compressedBlockHeight, level) ||
1101 !ValidCompressedDimension(depth, formatInfo.compressedBlockDepth, level))
1102 {
1103 return false;
1104 }
1105 }
1106 }
1107
1108 return true;
1109 }
1110
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)1111 bool ValidCompressedSubImageSize(const Context *context,
1112 GLenum internalFormat,
1113 GLint xoffset,
1114 GLint yoffset,
1115 GLint zoffset,
1116 GLsizei width,
1117 GLsizei height,
1118 GLsizei depth,
1119 size_t textureWidth,
1120 size_t textureHeight,
1121 size_t textureDepth)
1122 {
1123 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
1124 if (!formatInfo.compressed)
1125 {
1126 return false;
1127 }
1128
1129 if (xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0 || depth < 0)
1130 {
1131 return false;
1132 }
1133
1134 bool fillsEntireMip =
1135 xoffset == 0 && yoffset == 0 && static_cast<size_t>(width) == textureWidth &&
1136 static_cast<size_t>(height) == textureHeight && static_cast<size_t>(depth) == textureDepth;
1137
1138 if (CompressedFormatRequiresWholeImage(internalFormat))
1139 {
1140 return fillsEntireMip;
1141 }
1142
1143 if (CompressedSubTextureFormatRequiresExactSize(internalFormat))
1144 {
1145 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
1146 yoffset % formatInfo.compressedBlockHeight != 0 ||
1147 zoffset % formatInfo.compressedBlockDepth != 0)
1148 {
1149 return false;
1150 }
1151
1152 // Allowed to either have data that is a multiple of block size or is smaller than the block
1153 // size but fills the entire mip
1154 bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 &&
1155 (height % formatInfo.compressedBlockHeight) == 0 &&
1156 (depth % formatInfo.compressedBlockDepth) == 0;
1157 if (!sizeMultipleOfBlockSize && !fillsEntireMip)
1158 {
1159 return false;
1160 }
1161 }
1162
1163 return true;
1164 }
1165
ValidImageDataSize(const Context * context,angle::EntryPoint entryPoint,TextureType texType,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const void * pixels,GLsizei imageSize)1166 bool ValidImageDataSize(const Context *context,
1167 angle::EntryPoint entryPoint,
1168 TextureType texType,
1169 GLsizei width,
1170 GLsizei height,
1171 GLsizei depth,
1172 GLenum format,
1173 GLenum type,
1174 const void *pixels,
1175 GLsizei imageSize)
1176 {
1177 Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1178 if (pixelUnpackBuffer == nullptr && imageSize < 0)
1179 {
1180 // Checks are not required
1181 return true;
1182 }
1183
1184 // ...the data would be unpacked from the buffer object such that the memory reads required
1185 // would exceed the data store size.
1186 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
1187 ASSERT(formatInfo.internalFormat != GL_NONE);
1188 const Extents size(width, height, depth);
1189 const auto &unpack = context->getState().getUnpackState();
1190
1191 bool targetIs3D = texType == TextureType::_3D || texType == TextureType::_2DArray;
1192 GLuint endByte = 0;
1193 if (!formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D, &endByte))
1194 {
1195 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
1196 return false;
1197 }
1198
1199 if (pixelUnpackBuffer)
1200 {
1201 CheckedNumeric<size_t> checkedEndByte(endByte);
1202 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
1203 checkedEndByte += checkedOffset;
1204
1205 if (!checkedEndByte.IsValid() ||
1206 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
1207 {
1208 // Overflow past the end of the buffer
1209 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
1210 return false;
1211 }
1212 if (pixelUnpackBuffer->hasWebGLXFBBindingConflict(context->isWebGL()))
1213 {
1214 context->validationError(entryPoint, GL_INVALID_OPERATION,
1215 kPixelUnpackBufferBoundForTransformFeedback);
1216 return false;
1217 }
1218 }
1219 else
1220 {
1221 ASSERT(imageSize >= 0);
1222 if (pixels == nullptr && imageSize != 0)
1223 {
1224 context->validationError(entryPoint, GL_INVALID_OPERATION, kImageSizeMustBeZero);
1225 return false;
1226 }
1227
1228 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
1229 {
1230 context->validationError(entryPoint, GL_INVALID_OPERATION, kImageSizeTooSmall);
1231 return false;
1232 }
1233 }
1234
1235 return true;
1236 }
1237
ValidQueryType(const Context * context,QueryType queryType)1238 bool ValidQueryType(const Context *context, QueryType queryType)
1239 {
1240 switch (queryType)
1241 {
1242 case QueryType::AnySamples:
1243 case QueryType::AnySamplesConservative:
1244 return context->getClientMajorVersion() >= 3 ||
1245 context->getExtensions().occlusionQueryBooleanEXT;
1246 case QueryType::TransformFeedbackPrimitivesWritten:
1247 return (context->getClientMajorVersion() >= 3);
1248 case QueryType::TimeElapsed:
1249 return context->getExtensions().disjointTimerQueryEXT;
1250 case QueryType::CommandsCompleted:
1251 return context->getExtensions().syncQueryCHROMIUM;
1252 case QueryType::PrimitivesGenerated:
1253 return context->getClientVersion() >= ES_3_2 ||
1254 context->getExtensions().geometryShaderAny();
1255 default:
1256 return false;
1257 }
1258 }
1259
ValidateWebGLVertexAttribPointer(const Context * context,angle::EntryPoint entryPoint,VertexAttribType type,GLboolean normalized,GLsizei stride,const void * ptr,bool pureInteger)1260 bool ValidateWebGLVertexAttribPointer(const Context *context,
1261 angle::EntryPoint entryPoint,
1262 VertexAttribType type,
1263 GLboolean normalized,
1264 GLsizei stride,
1265 const void *ptr,
1266 bool pureInteger)
1267 {
1268 ASSERT(context->isWebGL());
1269 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
1270 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
1271 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
1272 // parameter exceeds 255.
1273 constexpr GLsizei kMaxWebGLStride = 255;
1274 if (stride > kMaxWebGLStride)
1275 {
1276 context->validationError(entryPoint, GL_INVALID_VALUE, kStrideExceedsWebGLLimit);
1277 return false;
1278 }
1279
1280 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
1281 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
1282 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
1283 // or an INVALID_OPERATION error is generated.
1284 angle::FormatID internalType = GetVertexFormatID(type, normalized, 1, pureInteger);
1285 size_t typeSize = GetVertexFormatSize(internalType);
1286
1287 ASSERT(isPow2(typeSize) && typeSize > 0);
1288 size_t sizeMask = (typeSize - 1);
1289 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
1290 {
1291 context->validationError(entryPoint, GL_INVALID_OPERATION, kOffsetMustBeMultipleOfType);
1292 return false;
1293 }
1294
1295 if ((stride & sizeMask) != 0)
1296 {
1297 context->validationError(entryPoint, GL_INVALID_OPERATION, kStrideMustBeMultipleOfType);
1298 return false;
1299 }
1300
1301 return true;
1302 }
1303
GetValidProgramNoResolve(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID id)1304 Program *GetValidProgramNoResolve(const Context *context,
1305 angle::EntryPoint entryPoint,
1306 ShaderProgramID id)
1307 {
1308 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
1309 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
1310 // or program object and INVALID_OPERATION if the provided name identifies an object
1311 // that is not the expected type."
1312
1313 Program *validProgram = context->getProgramNoResolveLink(id);
1314
1315 if (!validProgram)
1316 {
1317 if (context->getShader(id))
1318 {
1319 context->validationError(entryPoint, GL_INVALID_OPERATION, kExpectedProgramName);
1320 }
1321 else
1322 {
1323 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidProgramName);
1324 }
1325 }
1326
1327 return validProgram;
1328 }
1329
GetValidProgram(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID id)1330 Program *GetValidProgram(const Context *context, angle::EntryPoint entryPoint, ShaderProgramID id)
1331 {
1332 Program *program = GetValidProgramNoResolve(context, entryPoint, id);
1333 if (program)
1334 {
1335 program->resolveLink(context);
1336 }
1337 return program;
1338 }
1339
GetValidShader(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID id)1340 Shader *GetValidShader(const Context *context, angle::EntryPoint entryPoint, ShaderProgramID id)
1341 {
1342 // See ValidProgram for spec details.
1343
1344 Shader *validShader = context->getShader(id);
1345
1346 if (!validShader)
1347 {
1348 if (context->getProgramNoResolveLink(id))
1349 {
1350 context->validationError(entryPoint, GL_INVALID_OPERATION, kExpectedShaderName);
1351 }
1352 else
1353 {
1354 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidShaderName);
1355 }
1356 }
1357
1358 return validShader;
1359 }
1360
ValidateAttachmentTarget(const Context * context,angle::EntryPoint entryPoint,GLenum attachment)1361 bool ValidateAttachmentTarget(const Context *context,
1362 angle::EntryPoint entryPoint,
1363 GLenum attachment)
1364 {
1365 if (attachment >= GL_COLOR_ATTACHMENT1_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
1366 {
1367 if (context->getClientMajorVersion() < 3 && !context->getExtensions().drawBuffersEXT)
1368 {
1369 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
1370 return false;
1371 }
1372
1373 // Color attachment 0 is validated below because it is always valid
1374 const int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
1375 if (colorAttachment >= context->getCaps().maxColorAttachments)
1376 {
1377 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAttachment);
1378 return false;
1379 }
1380 }
1381 else
1382 {
1383 switch (attachment)
1384 {
1385 case GL_COLOR_ATTACHMENT0:
1386 case GL_DEPTH_ATTACHMENT:
1387 case GL_STENCIL_ATTACHMENT:
1388 break;
1389
1390 case GL_DEPTH_STENCIL_ATTACHMENT:
1391 if (!context->isWebGL() && context->getClientMajorVersion() < 3)
1392 {
1393 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
1394 return false;
1395 }
1396 break;
1397
1398 default:
1399 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
1400 return false;
1401 }
1402 }
1403
1404 return true;
1405 }
1406
ValidateRenderbufferStorageParametersBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height)1407 bool ValidateRenderbufferStorageParametersBase(const Context *context,
1408 angle::EntryPoint entryPoint,
1409 GLenum target,
1410 GLsizei samples,
1411 GLenum internalformat,
1412 GLsizei width,
1413 GLsizei height)
1414 {
1415 switch (target)
1416 {
1417 case GL_RENDERBUFFER:
1418 break;
1419 default:
1420 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferTarget);
1421 return false;
1422 }
1423
1424 if (width < 0 || height < 0 || samples < 0)
1425 {
1426 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidRenderbufferWidthHeight);
1427 return false;
1428 }
1429
1430 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
1431 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
1432
1433 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
1434 if (!formatCaps.renderbuffer)
1435 {
1436 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferInternalFormat);
1437 return false;
1438 }
1439
1440 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
1441 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
1442 // only sized internal formats.
1443 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(convertedInternalFormat);
1444 if (formatInfo.internalFormat == GL_NONE)
1445 {
1446 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferInternalFormat);
1447 return false;
1448 }
1449
1450 if (std::max(width, height) > context->getCaps().maxRenderbufferSize)
1451 {
1452 context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxRenderbufferSize);
1453 return false;
1454 }
1455
1456 RenderbufferID id = context->getState().getRenderbufferId();
1457 if (id.value == 0)
1458 {
1459 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidRenderbufferTarget);
1460 return false;
1461 }
1462
1463 return true;
1464 }
1465
ValidateBlitFramebufferParameters(const Context * context,angle::EntryPoint entryPoint,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)1466 bool ValidateBlitFramebufferParameters(const Context *context,
1467 angle::EntryPoint entryPoint,
1468 GLint srcX0,
1469 GLint srcY0,
1470 GLint srcX1,
1471 GLint srcY1,
1472 GLint dstX0,
1473 GLint dstY0,
1474 GLint dstX1,
1475 GLint dstY1,
1476 GLbitfield mask,
1477 GLenum filter)
1478 {
1479 switch (filter)
1480 {
1481 case GL_NEAREST:
1482 break;
1483 case GL_LINEAR:
1484 break;
1485 default:
1486 context->validationError(entryPoint, GL_INVALID_ENUM, kBlitInvalidFilter);
1487 return false;
1488 }
1489
1490 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
1491 {
1492 context->validationError(entryPoint, GL_INVALID_VALUE, kBlitInvalidMask);
1493 return false;
1494 }
1495
1496 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
1497 // color buffer, leaving only nearest being unfiltered from above
1498 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
1499 {
1500 context->validationError(entryPoint, GL_INVALID_OPERATION, kBlitOnlyNearestForNonColor);
1501 return false;
1502 }
1503
1504 const auto &glState = context->getState();
1505 Framebuffer *readFramebuffer = glState.getReadFramebuffer();
1506 Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
1507
1508 if (!readFramebuffer || !drawFramebuffer)
1509 {
1510 context->validationError(entryPoint, GL_INVALID_FRAMEBUFFER_OPERATION,
1511 kBlitFramebufferMissing);
1512 return false;
1513 }
1514
1515 if (!ValidateFramebufferComplete(context, entryPoint, readFramebuffer))
1516 {
1517 return false;
1518 }
1519
1520 if (!ValidateFramebufferComplete(context, entryPoint, drawFramebuffer))
1521 {
1522 return false;
1523 }
1524
1525 // EXT_YUV_target disallows blitting to or from a YUV framebuffer
1526 if ((mask & GL_COLOR_BUFFER_BIT) != 0 &&
1527 (readFramebuffer->hasYUVAttachment() || drawFramebuffer->hasYUVAttachment()))
1528 {
1529 context->validationError(entryPoint, GL_INVALID_OPERATION, kBlitYUVFramebuffer);
1530 return false;
1531 }
1532
1533 // The draw and read framebuffers can only match if:
1534 // - They are the default framebuffer AND
1535 // - The read/draw surfaces are different
1536 if ((readFramebuffer->id() == drawFramebuffer->id()) &&
1537 ((drawFramebuffer->id() != Framebuffer::kDefaultDrawFramebufferHandle) ||
1538 (context->getCurrentDrawSurface() == context->getCurrentReadSurface())))
1539 {
1540 context->validationError(entryPoint, GL_INVALID_OPERATION, kBlitFeedbackLoop);
1541 return false;
1542 }
1543
1544 // Not allow blitting to MS buffers, therefore if renderToTextureSamples exist,
1545 // consider it MS. checkReadBufferResourceSamples = false
1546 if (!ValidateFramebufferNotMultisampled(context, entryPoint, drawFramebuffer, false))
1547 {
1548 return false;
1549 }
1550
1551 // This validation is specified in the WebGL 2.0 spec and not in the GLES 3.0.5 spec, but we
1552 // always run it in order to avoid triggering driver bugs.
1553 if (DifferenceCanOverflow(srcX0, srcX1) || DifferenceCanOverflow(srcY0, srcY1) ||
1554 DifferenceCanOverflow(dstX0, dstX1) || DifferenceCanOverflow(dstY0, dstY1))
1555 {
1556 context->validationError(entryPoint, GL_INVALID_VALUE, kBlitDimensionsOutOfRange);
1557 return false;
1558 }
1559
1560 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
1561
1562 if (mask & GL_COLOR_BUFFER_BIT)
1563 {
1564 const FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorAttachment();
1565 const Extensions &extensions = context->getExtensions();
1566
1567 if (readColorBuffer)
1568 {
1569 const Format &readFormat = readColorBuffer->getFormat();
1570
1571 for (size_t drawbufferIdx = 0;
1572 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
1573 {
1574 const FramebufferAttachment *attachment =
1575 drawFramebuffer->getDrawBuffer(drawbufferIdx);
1576 if (attachment)
1577 {
1578 const Format &drawFormat = attachment->getFormat();
1579
1580 // The GL ES 3.0.2 spec (pg 193) states that:
1581 // 1) If the read buffer is fixed point format, the draw buffer must be as well
1582 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
1583 // as well
1584 // 3) If the read buffer is a signed integer format, the draw buffer must be as
1585 // well
1586 // Changes with EXT_color_buffer_float:
1587 // Case 1) is changed to fixed point OR floating point
1588 GLenum readComponentType = readFormat.info->componentType;
1589 GLenum drawComponentType = drawFormat.info->componentType;
1590 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
1591 readComponentType == GL_SIGNED_NORMALIZED);
1592 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
1593 drawComponentType == GL_SIGNED_NORMALIZED);
1594
1595 if (extensions.colorBufferFloatEXT)
1596 {
1597 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
1598 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
1599
1600 if (readFixedOrFloat != drawFixedOrFloat)
1601 {
1602 context->validationError(entryPoint, GL_INVALID_OPERATION,
1603 kBlitTypeMismatchFixedOrFloat);
1604 return false;
1605 }
1606 }
1607 else if (readFixedPoint != drawFixedPoint)
1608 {
1609 context->validationError(entryPoint, GL_INVALID_OPERATION,
1610 kBlitTypeMismatchFixedPoint);
1611 return false;
1612 }
1613
1614 if (readComponentType == GL_UNSIGNED_INT &&
1615 drawComponentType != GL_UNSIGNED_INT)
1616 {
1617 context->validationError(entryPoint, GL_INVALID_OPERATION,
1618 kBlitTypeMismatchUnsignedInteger);
1619 return false;
1620 }
1621
1622 if (readComponentType == GL_INT && drawComponentType != GL_INT)
1623 {
1624 context->validationError(entryPoint, GL_INVALID_OPERATION,
1625 kBlitTypeMismatchSignedInteger);
1626 return false;
1627 }
1628
1629 if (readColorBuffer->getResourceSamples() > 0 &&
1630 (!Format::EquivalentForBlit(readFormat, drawFormat) || !sameBounds))
1631 {
1632 context->validationError(entryPoint, GL_INVALID_OPERATION,
1633 kBlitMultisampledFormatOrBoundsMismatch);
1634 return false;
1635 }
1636
1637 if (context->isWebGL() && *readColorBuffer == *attachment)
1638 {
1639 context->validationError(entryPoint, GL_INVALID_OPERATION,
1640 kBlitSameImageColor);
1641 return false;
1642 }
1643 }
1644 }
1645
1646 if (readFormat.info->isInt() && filter == GL_LINEAR)
1647 {
1648 context->validationError(entryPoint, GL_INVALID_OPERATION,
1649 kBlitIntegerWithLinearFilter);
1650 return false;
1651 }
1652 }
1653 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1654 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
1655 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
1656 // situation is an application error that would lead to a crash in ANGLE.
1657 else if (drawFramebuffer->hasEnabledDrawBuffer())
1658 {
1659 context->validationError(entryPoint, GL_INVALID_OPERATION, kBlitMissingColor);
1660 return false;
1661 }
1662 }
1663
1664 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
1665 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
1666 for (size_t i = 0; i < 2; i++)
1667 {
1668 if (mask & masks[i])
1669 {
1670 const FramebufferAttachment *readBuffer =
1671 readFramebuffer->getAttachment(context, attachments[i]);
1672 const FramebufferAttachment *drawBuffer =
1673 drawFramebuffer->getAttachment(context, attachments[i]);
1674
1675 if (readBuffer && drawBuffer)
1676 {
1677 if (!Format::EquivalentForBlit(readBuffer->getFormat(), drawBuffer->getFormat()))
1678 {
1679 context->validationError(entryPoint, GL_INVALID_OPERATION,
1680 kBlitDepthOrStencilFormatMismatch);
1681 return false;
1682 }
1683
1684 if (readBuffer->getResourceSamples() > 0 && !sameBounds)
1685 {
1686 context->validationError(entryPoint, GL_INVALID_OPERATION,
1687 kBlitMultisampledBoundsMismatch);
1688 return false;
1689 }
1690
1691 if (context->isWebGL() && *readBuffer == *drawBuffer)
1692 {
1693 context->validationError(entryPoint, GL_INVALID_OPERATION,
1694 kBlitSameImageDepthOrStencil);
1695 return false;
1696 }
1697 }
1698 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1699 else if (drawBuffer)
1700 {
1701 context->validationError(entryPoint, GL_INVALID_OPERATION,
1702 kBlitMissingDepthOrStencil);
1703 return false;
1704 }
1705 }
1706 }
1707
1708 // OVR_multiview2:
1709 // Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the
1710 // current draw framebuffer isMultiview() or the number of
1711 // views in the current read framebuffer is more than one.
1712 if (readFramebuffer->readDisallowedByMultiview())
1713 {
1714 context->validationError(entryPoint, GL_INVALID_FRAMEBUFFER_OPERATION, kBlitFromMultiview);
1715 return false;
1716 }
1717 if (drawFramebuffer->isMultiview())
1718 {
1719 context->validationError(entryPoint, GL_INVALID_FRAMEBUFFER_OPERATION, kBlitToMultiview);
1720 return false;
1721 }
1722
1723 return true;
1724 }
1725
ValidateBindFramebufferBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,FramebufferID framebuffer)1726 bool ValidateBindFramebufferBase(const Context *context,
1727 angle::EntryPoint entryPoint,
1728 GLenum target,
1729 FramebufferID framebuffer)
1730 {
1731 if (!ValidFramebufferTarget(context, target))
1732 {
1733 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFramebufferTarget);
1734 return false;
1735 }
1736
1737 if (!context->getState().isBindGeneratesResourceEnabled() &&
1738 !context->isFramebufferGenerated(framebuffer))
1739 {
1740 context->validationError(entryPoint, GL_INVALID_OPERATION, kObjectNotGenerated);
1741 return false;
1742 }
1743
1744 return true;
1745 }
1746
ValidateBindRenderbufferBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,RenderbufferID renderbuffer)1747 bool ValidateBindRenderbufferBase(const Context *context,
1748 angle::EntryPoint entryPoint,
1749 GLenum target,
1750 RenderbufferID renderbuffer)
1751 {
1752 if (target != GL_RENDERBUFFER)
1753 {
1754 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferTarget);
1755 return false;
1756 }
1757
1758 if (!context->getState().isBindGeneratesResourceEnabled() &&
1759 !context->isRenderbufferGenerated(renderbuffer))
1760 {
1761 context->validationError(entryPoint, GL_INVALID_OPERATION, kObjectNotGenerated);
1762 return false;
1763 }
1764
1765 return true;
1766 }
1767
ValidateFramebufferRenderbufferBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum attachment,GLenum renderbuffertarget,RenderbufferID renderbuffer)1768 bool ValidateFramebufferRenderbufferBase(const Context *context,
1769 angle::EntryPoint entryPoint,
1770 GLenum target,
1771 GLenum attachment,
1772 GLenum renderbuffertarget,
1773 RenderbufferID renderbuffer)
1774 {
1775 if (!ValidFramebufferTarget(context, target))
1776 {
1777 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFramebufferTarget);
1778 return false;
1779 }
1780
1781 if (renderbuffertarget != GL_RENDERBUFFER)
1782 {
1783 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferTarget);
1784 return false;
1785 }
1786
1787 Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1788
1789 ASSERT(framebuffer);
1790 if (framebuffer->isDefault())
1791 {
1792 context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultFramebufferTarget);
1793 return false;
1794 }
1795
1796 if (!ValidateAttachmentTarget(context, entryPoint, attachment))
1797 {
1798 return false;
1799 }
1800
1801 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
1802 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
1803 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
1804 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
1805 if (renderbuffer.value != 0)
1806 {
1807 if (!context->getRenderbuffer(renderbuffer))
1808 {
1809 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidRenderbufferTarget);
1810 return false;
1811 }
1812 }
1813
1814 return true;
1815 }
1816
ValidateFramebufferTextureBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum attachment,TextureID texture,GLint level)1817 bool ValidateFramebufferTextureBase(const Context *context,
1818 angle::EntryPoint entryPoint,
1819 GLenum target,
1820 GLenum attachment,
1821 TextureID texture,
1822 GLint level)
1823 {
1824 if (!ValidFramebufferTarget(context, target))
1825 {
1826 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFramebufferTarget);
1827 return false;
1828 }
1829
1830 if (!ValidateAttachmentTarget(context, entryPoint, attachment))
1831 {
1832 return false;
1833 }
1834
1835 if (texture.value != 0)
1836 {
1837 Texture *tex = context->getTexture(texture);
1838
1839 if (tex == nullptr)
1840 {
1841 context->validationError(entryPoint, GL_INVALID_OPERATION, kMissingTexture);
1842 return false;
1843 }
1844
1845 if (level < 0)
1846 {
1847 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
1848 return false;
1849 }
1850
1851 // GLES spec 3.1, Section 9.2.8 "Attaching Texture Images to a Framebuffer"
1852 // An INVALID_VALUE error is generated if texture is not zero and level is
1853 // not a supported texture level for textarget
1854
1855 // Common criteria for not supported texture levels(other criteria are handled case by case
1856 // in non base functions): If texture refers to an immutable-format texture, level must be
1857 // greater than or equal to zero and smaller than the value of TEXTURE_IMMUTABLE_LEVELS for
1858 // texture.
1859 if (tex->getImmutableFormat() && context->getClientVersion() >= ES_3_1)
1860 {
1861 if (level >= static_cast<GLint>(tex->getImmutableLevels()))
1862 {
1863 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
1864 return false;
1865 }
1866 }
1867
1868 // GLES spec 3.2, Section 9.2.8 "Attaching Texture Images to a Framebuffer"
1869 // An INVALID_OPERATION error is generated if <texture> is the name of a buffer texture.
1870 if ((context->getClientVersion() >= ES_3_2 ||
1871 context->getExtensions().textureBufferAny()) &&
1872 tex->getType() == TextureType::Buffer)
1873 {
1874 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidTextureTarget);
1875 return false;
1876 }
1877 }
1878
1879 const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1880 ASSERT(framebuffer);
1881
1882 if (framebuffer->isDefault())
1883 {
1884 context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultFramebufferTarget);
1885 return false;
1886 }
1887
1888 return true;
1889 }
1890
ValidateGenerateMipmapBase(const Context * context,angle::EntryPoint entryPoint,TextureType target)1891 bool ValidateGenerateMipmapBase(const Context *context,
1892 angle::EntryPoint entryPoint,
1893 TextureType target)
1894 {
1895 if (!ValidTextureTarget(context, target))
1896 {
1897 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
1898 return false;
1899 }
1900
1901 Texture *texture = context->getTextureByType(target);
1902
1903 if (texture == nullptr)
1904 {
1905 context->validationError(entryPoint, GL_INVALID_OPERATION, kTextureNotBound);
1906 return false;
1907 }
1908
1909 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
1910
1911 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
1912 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
1913 if (effectiveBaseLevel >= IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1914 {
1915 context->validationError(entryPoint, GL_INVALID_OPERATION, kBaseLevelOutOfRange);
1916 return false;
1917 }
1918
1919 TextureTarget baseTarget = (target == TextureType::CubeMap)
1920 ? TextureTarget::CubeMapPositiveX
1921 : NonCubeTextureTypeToTarget(target);
1922 const auto &format = *(texture->getFormat(baseTarget, effectiveBaseLevel).info);
1923 if (format.sizedInternalFormat == GL_NONE || format.compressed || format.depthBits > 0 ||
1924 format.stencilBits > 0)
1925 {
1926 context->validationError(entryPoint, GL_INVALID_OPERATION, kGenerateMipmapNotAllowed);
1927 return false;
1928 }
1929
1930 // GenerateMipmap accepts formats that are unsized or both color renderable and filterable.
1931 bool formatUnsized = !format.sized;
1932 bool formatColorRenderableAndFilterable =
1933 format.filterSupport(context->getClientVersion(), context->getExtensions()) &&
1934 format.textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1935 if (!formatUnsized && !formatColorRenderableAndFilterable)
1936 {
1937 context->validationError(entryPoint, GL_INVALID_OPERATION, kGenerateMipmapNotAllowed);
1938 return false;
1939 }
1940
1941 // GL_EXT_sRGB adds an unsized SRGB (no alpha) format which has explicitly disabled mipmap
1942 // generation
1943 if (format.colorEncoding == GL_SRGB && format.format == GL_RGB)
1944 {
1945 context->validationError(entryPoint, GL_INVALID_OPERATION, kGenerateMipmapNotAllowed);
1946 return false;
1947 }
1948
1949 // According to the OpenGL extension spec EXT_sRGB.txt, EXT_SRGB is based on ES 2.0 and
1950 // generateMipmap is not allowed if texture format is SRGB_EXT or SRGB_ALPHA_EXT.
1951 if (context->getClientVersion() < Version(3, 0) && format.colorEncoding == GL_SRGB)
1952 {
1953 context->validationError(entryPoint, GL_INVALID_OPERATION, kGenerateMipmapNotAllowed);
1954 return false;
1955 }
1956
1957 // Non-power of 2 ES2 check
1958 if (context->getClientVersion() < Version(3, 0) && !context->getExtensions().textureNpotOES &&
1959 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
1960 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
1961 {
1962 ASSERT(target == TextureType::_2D || target == TextureType::Rectangle ||
1963 target == TextureType::CubeMap);
1964 context->validationError(entryPoint, GL_INVALID_OPERATION, kTextureNotPow2);
1965 return false;
1966 }
1967
1968 // Cube completeness check
1969 if (target == TextureType::CubeMap && !texture->getTextureState().isCubeComplete())
1970 {
1971 context->validationError(entryPoint, GL_INVALID_OPERATION, kCubemapIncomplete);
1972 return false;
1973 }
1974
1975 if (context->isWebGL() && (texture->getWidth(baseTarget, effectiveBaseLevel) == 0 ||
1976 texture->getHeight(baseTarget, effectiveBaseLevel) == 0))
1977 {
1978 context->validationError(entryPoint, GL_INVALID_OPERATION, kGenerateMipmapZeroSize);
1979 return false;
1980 }
1981
1982 return true;
1983 }
1984
ValidateReadPixelsRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,const GLsizei * length,const GLsizei * columns,const GLsizei * rows,const void * pixels)1985 bool ValidateReadPixelsRobustANGLE(const Context *context,
1986 angle::EntryPoint entryPoint,
1987 GLint x,
1988 GLint y,
1989 GLsizei width,
1990 GLsizei height,
1991 GLenum format,
1992 GLenum type,
1993 GLsizei bufSize,
1994 const GLsizei *length,
1995 const GLsizei *columns,
1996 const GLsizei *rows,
1997 const void *pixels)
1998 {
1999 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
2000 {
2001 return false;
2002 }
2003
2004 GLsizei writeLength = 0;
2005 GLsizei writeColumns = 0;
2006 GLsizei writeRows = 0;
2007
2008 if (!ValidateReadPixelsBase(context, entryPoint, x, y, width, height, format, type, bufSize,
2009 &writeLength, &writeColumns, &writeRows, pixels))
2010 {
2011 return false;
2012 }
2013
2014 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
2015 {
2016 return false;
2017 }
2018
2019 SetRobustLengthParam(length, writeLength);
2020 SetRobustLengthParam(columns, writeColumns);
2021 SetRobustLengthParam(rows, writeRows);
2022
2023 return true;
2024 }
2025
ValidateReadnPixelsEXT(const Context * context,angle::EntryPoint entryPoint,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,const void * pixels)2026 bool ValidateReadnPixelsEXT(const Context *context,
2027 angle::EntryPoint entryPoint,
2028 GLint x,
2029 GLint y,
2030 GLsizei width,
2031 GLsizei height,
2032 GLenum format,
2033 GLenum type,
2034 GLsizei bufSize,
2035 const void *pixels)
2036 {
2037 if (bufSize < 0)
2038 {
2039 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeBufferSize);
2040 return false;
2041 }
2042
2043 return ValidateReadPixelsBase(context, entryPoint, x, y, width, height, format, type, bufSize,
2044 nullptr, nullptr, nullptr, pixels);
2045 }
2046
ValidateReadnPixelsRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,const GLsizei * length,const GLsizei * columns,const GLsizei * rows,const void * data)2047 bool ValidateReadnPixelsRobustANGLE(const Context *context,
2048 angle::EntryPoint entryPoint,
2049 GLint x,
2050 GLint y,
2051 GLsizei width,
2052 GLsizei height,
2053 GLenum format,
2054 GLenum type,
2055 GLsizei bufSize,
2056 const GLsizei *length,
2057 const GLsizei *columns,
2058 const GLsizei *rows,
2059 const void *data)
2060 {
2061 GLsizei writeLength = 0;
2062 GLsizei writeColumns = 0;
2063 GLsizei writeRows = 0;
2064
2065 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
2066 {
2067 return false;
2068 }
2069
2070 if (!ValidateReadPixelsBase(context, entryPoint, x, y, width, height, format, type, bufSize,
2071 &writeLength, &writeColumns, &writeRows, data))
2072 {
2073 return false;
2074 }
2075
2076 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
2077 {
2078 return false;
2079 }
2080
2081 SetRobustLengthParam(length, writeLength);
2082 SetRobustLengthParam(columns, writeColumns);
2083 SetRobustLengthParam(rows, writeRows);
2084
2085 return true;
2086 }
2087
ValidateGenQueriesEXT(const Context * context,angle::EntryPoint entryPoint,GLsizei n,const QueryID * ids)2088 bool ValidateGenQueriesEXT(const Context *context,
2089 angle::EntryPoint entryPoint,
2090 GLsizei n,
2091 const QueryID *ids)
2092 {
2093 if (!context->getExtensions().occlusionQueryBooleanEXT &&
2094 !context->getExtensions().disjointTimerQueryEXT)
2095 {
2096 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
2097 return false;
2098 }
2099
2100 return ValidateGenOrDelete(context, entryPoint, n);
2101 }
2102
ValidateDeleteQueriesEXT(const Context * context,angle::EntryPoint entryPoint,GLsizei n,const QueryID * ids)2103 bool ValidateDeleteQueriesEXT(const Context *context,
2104 angle::EntryPoint entryPoint,
2105 GLsizei n,
2106 const QueryID *ids)
2107 {
2108 if (!context->getExtensions().occlusionQueryBooleanEXT &&
2109 !context->getExtensions().disjointTimerQueryEXT)
2110 {
2111 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
2112 return false;
2113 }
2114
2115 return ValidateGenOrDelete(context, entryPoint, n);
2116 }
2117
ValidateIsQueryEXT(const Context * context,angle::EntryPoint entryPoint,QueryID id)2118 bool ValidateIsQueryEXT(const Context *context, angle::EntryPoint entryPoint, QueryID id)
2119 {
2120 if (!context->getExtensions().occlusionQueryBooleanEXT &&
2121 !context->getExtensions().disjointTimerQueryEXT)
2122 {
2123 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
2124 return false;
2125 }
2126
2127 return true;
2128 }
2129
ValidateBeginQueryBase(const Context * context,angle::EntryPoint entryPoint,QueryType target,QueryID id)2130 bool ValidateBeginQueryBase(const Context *context,
2131 angle::EntryPoint entryPoint,
2132 QueryType target,
2133 QueryID id)
2134 {
2135 if (!ValidQueryType(context, target))
2136 {
2137 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidQueryType);
2138 return false;
2139 }
2140
2141 if (id.value == 0)
2142 {
2143 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidQueryId);
2144 return false;
2145 }
2146
2147 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
2148 // of zero, if the active query object name for <target> is non-zero (for the
2149 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
2150 // the active query for either target is non-zero), if <id> is the name of an
2151 // existing query object whose type does not match <target>, or if <id> is the
2152 // active query object name for any query type, the error INVALID_OPERATION is
2153 // generated.
2154
2155 // Ensure no other queries are active
2156 // NOTE: If other queries than occlusion are supported, we will need to check
2157 // separately that:
2158 // a) The query ID passed is not the current active query for any target/type
2159 // b) There are no active queries for the requested target (and in the case
2160 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
2161 // no query may be active for either if glBeginQuery targets either.
2162
2163 if (context->getState().isQueryActive(target))
2164 {
2165 context->validationError(entryPoint, GL_INVALID_OPERATION, kOtherQueryActive);
2166 return false;
2167 }
2168
2169 // check that name was obtained with glGenQueries
2170 if (!context->isQueryGenerated(id))
2171 {
2172 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidQueryId);
2173 return false;
2174 }
2175
2176 // Check for type mismatch. If query is not yet started we're good to go.
2177 Query *queryObject = context->getQuery(id);
2178 if (queryObject && queryObject->getType() != target)
2179 {
2180 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryTargetMismatch);
2181 return false;
2182 }
2183
2184 return true;
2185 }
2186
ValidateBeginQueryEXT(const Context * context,angle::EntryPoint entryPoint,QueryType target,QueryID id)2187 bool ValidateBeginQueryEXT(const Context *context,
2188 angle::EntryPoint entryPoint,
2189 QueryType target,
2190 QueryID id)
2191 {
2192 if (!context->getExtensions().occlusionQueryBooleanEXT &&
2193 !context->getExtensions().disjointTimerQueryEXT &&
2194 !context->getExtensions().syncQueryCHROMIUM)
2195 {
2196 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
2197 return false;
2198 }
2199
2200 return ValidateBeginQueryBase(context, entryPoint, target, id);
2201 }
2202
ValidateEndQueryBase(const Context * context,angle::EntryPoint entryPoint,QueryType target)2203 bool ValidateEndQueryBase(const Context *context, angle::EntryPoint entryPoint, QueryType target)
2204 {
2205 if (!ValidQueryType(context, target))
2206 {
2207 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidQueryType);
2208 return false;
2209 }
2210
2211 const Query *queryObject = context->getState().getActiveQuery(target);
2212
2213 if (queryObject == nullptr)
2214 {
2215 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryInactive);
2216 return false;
2217 }
2218
2219 return true;
2220 }
2221
ValidateEndQueryEXT(const Context * context,angle::EntryPoint entryPoint,QueryType target)2222 bool ValidateEndQueryEXT(const Context *context, angle::EntryPoint entryPoint, QueryType target)
2223 {
2224 if (!context->getExtensions().occlusionQueryBooleanEXT &&
2225 !context->getExtensions().disjointTimerQueryEXT &&
2226 !context->getExtensions().syncQueryCHROMIUM)
2227 {
2228 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryExtensionNotEnabled);
2229 return false;
2230 }
2231
2232 return ValidateEndQueryBase(context, entryPoint, target);
2233 }
2234
ValidateQueryCounterEXT(const Context * context,angle::EntryPoint entryPoint,QueryID id,QueryType target)2235 bool ValidateQueryCounterEXT(const Context *context,
2236 angle::EntryPoint entryPoint,
2237 QueryID id,
2238 QueryType target)
2239 {
2240 if (!context->getExtensions().disjointTimerQueryEXT)
2241 {
2242 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2243 return false;
2244 }
2245
2246 if (target != QueryType::Timestamp)
2247 {
2248 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidQueryTarget);
2249 return false;
2250 }
2251
2252 if (!context->isQueryGenerated(id))
2253 {
2254 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidQueryId);
2255 return false;
2256 }
2257
2258 // If query object is not started, that's fine.
2259 Query *queryObject = context->getQuery(id);
2260 if (queryObject && context->getState().isQueryActive(queryObject))
2261 {
2262 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryActive);
2263 return false;
2264 }
2265
2266 return true;
2267 }
2268
ValidateGetQueryivBase(const Context * context,angle::EntryPoint entryPoint,QueryType target,GLenum pname,GLsizei * numParams)2269 bool ValidateGetQueryivBase(const Context *context,
2270 angle::EntryPoint entryPoint,
2271 QueryType target,
2272 GLenum pname,
2273 GLsizei *numParams)
2274 {
2275 if (numParams)
2276 {
2277 *numParams = 0;
2278 }
2279
2280 if (!ValidQueryType(context, target) && target != QueryType::Timestamp)
2281 {
2282 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidQueryType);
2283 return false;
2284 }
2285
2286 switch (pname)
2287 {
2288 case GL_CURRENT_QUERY_EXT:
2289 if (target == QueryType::Timestamp)
2290 {
2291 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidQueryTarget);
2292 return false;
2293 }
2294 break;
2295 case GL_QUERY_COUNTER_BITS_EXT:
2296 if (!context->getExtensions().disjointTimerQueryEXT ||
2297 (target != QueryType::Timestamp && target != QueryType::TimeElapsed))
2298 {
2299 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
2300 return false;
2301 }
2302 break;
2303 default:
2304 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
2305 return false;
2306 }
2307
2308 if (numParams)
2309 {
2310 // All queries return only one value
2311 *numParams = 1;
2312 }
2313
2314 return true;
2315 }
2316
ValidateGetQueryivEXT(const Context * context,angle::EntryPoint entryPoint,QueryType target,GLenum pname,const GLint * params)2317 bool ValidateGetQueryivEXT(const Context *context,
2318 angle::EntryPoint entryPoint,
2319 QueryType target,
2320 GLenum pname,
2321 const GLint *params)
2322 {
2323 if (!context->getExtensions().occlusionQueryBooleanEXT &&
2324 !context->getExtensions().disjointTimerQueryEXT &&
2325 !context->getExtensions().syncQueryCHROMIUM)
2326 {
2327 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2328 return false;
2329 }
2330
2331 return ValidateGetQueryivBase(context, entryPoint, target, pname, nullptr);
2332 }
2333
ValidateGetQueryivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,QueryType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)2334 bool ValidateGetQueryivRobustANGLE(const Context *context,
2335 angle::EntryPoint entryPoint,
2336 QueryType target,
2337 GLenum pname,
2338 GLsizei bufSize,
2339 const GLsizei *length,
2340 const GLint *params)
2341 {
2342 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
2343 {
2344 return false;
2345 }
2346
2347 GLsizei numParams = 0;
2348
2349 if (!ValidateGetQueryivBase(context, entryPoint, target, pname, &numParams))
2350 {
2351 return false;
2352 }
2353
2354 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
2355 {
2356 return false;
2357 }
2358
2359 SetRobustLengthParam(length, numParams);
2360
2361 return true;
2362 }
2363
ValidateGetQueryObjectValueBase(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,GLsizei * numParams)2364 bool ValidateGetQueryObjectValueBase(const Context *context,
2365 angle::EntryPoint entryPoint,
2366 QueryID id,
2367 GLenum pname,
2368 GLsizei *numParams)
2369 {
2370 if (numParams)
2371 {
2372 *numParams = 1;
2373 }
2374
2375 if (context->isContextLost())
2376 {
2377 context->validationError(entryPoint, GL_CONTEXT_LOST, kContextLost);
2378
2379 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
2380 {
2381 // Generate an error but still return true, the context still needs to return a
2382 // value in this case.
2383 return true;
2384 }
2385 else
2386 {
2387 return false;
2388 }
2389 }
2390
2391 Query *queryObject = context->getQuery(id);
2392
2393 if (!queryObject)
2394 {
2395 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidQueryId);
2396 return false;
2397 }
2398
2399 if (context->getState().isQueryActive(queryObject))
2400 {
2401 context->validationError(entryPoint, GL_INVALID_OPERATION, kQueryActive);
2402 return false;
2403 }
2404
2405 switch (pname)
2406 {
2407 case GL_QUERY_RESULT_EXT:
2408 case GL_QUERY_RESULT_AVAILABLE_EXT:
2409 break;
2410
2411 default:
2412 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
2413 return false;
2414 }
2415
2416 return true;
2417 }
2418
ValidateGetQueryObjectivEXT(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,const GLint * params)2419 bool ValidateGetQueryObjectivEXT(const Context *context,
2420 angle::EntryPoint entryPoint,
2421 QueryID id,
2422 GLenum pname,
2423 const GLint *params)
2424 {
2425 if (!context->getExtensions().disjointTimerQueryEXT)
2426 {
2427 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2428 return false;
2429 }
2430 return ValidateGetQueryObjectValueBase(context, entryPoint, id, pname, nullptr);
2431 }
2432
ValidateGetQueryObjectivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)2433 bool ValidateGetQueryObjectivRobustANGLE(const Context *context,
2434 angle::EntryPoint entryPoint,
2435 QueryID id,
2436 GLenum pname,
2437 GLsizei bufSize,
2438 const GLsizei *length,
2439 const GLint *params)
2440 {
2441 if (!context->getExtensions().disjointTimerQueryEXT)
2442 {
2443 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2444 return false;
2445 }
2446
2447 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
2448 {
2449 return false;
2450 }
2451
2452 GLsizei numParams = 0;
2453
2454 if (!ValidateGetQueryObjectValueBase(context, entryPoint, id, pname, &numParams))
2455 {
2456 return false;
2457 }
2458
2459 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
2460 {
2461 return false;
2462 }
2463
2464 SetRobustLengthParam(length, numParams);
2465
2466 return true;
2467 }
2468
ValidateGetQueryObjectuivEXT(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,const GLuint * params)2469 bool ValidateGetQueryObjectuivEXT(const Context *context,
2470 angle::EntryPoint entryPoint,
2471 QueryID id,
2472 GLenum pname,
2473 const GLuint *params)
2474 {
2475 if (!context->getExtensions().disjointTimerQueryEXT &&
2476 !context->getExtensions().occlusionQueryBooleanEXT &&
2477 !context->getExtensions().syncQueryCHROMIUM)
2478 {
2479 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2480 return false;
2481 }
2482 return ValidateGetQueryObjectValueBase(context, entryPoint, id, pname, nullptr);
2483 }
2484
ValidateGetQueryObjectuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLuint * params)2485 bool ValidateGetQueryObjectuivRobustANGLE(const Context *context,
2486 angle::EntryPoint entryPoint,
2487 QueryID id,
2488 GLenum pname,
2489 GLsizei bufSize,
2490 const GLsizei *length,
2491 const GLuint *params)
2492 {
2493 if (!context->getExtensions().disjointTimerQueryEXT &&
2494 !context->getExtensions().occlusionQueryBooleanEXT &&
2495 !context->getExtensions().syncQueryCHROMIUM)
2496 {
2497 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2498 return false;
2499 }
2500
2501 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
2502 {
2503 return false;
2504 }
2505
2506 GLsizei numParams = 0;
2507
2508 if (!ValidateGetQueryObjectValueBase(context, entryPoint, id, pname, &numParams))
2509 {
2510 return false;
2511 }
2512
2513 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
2514 {
2515 return false;
2516 }
2517
2518 SetRobustLengthParam(length, numParams);
2519
2520 return true;
2521 }
2522
ValidateGetQueryObjecti64vEXT(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,GLint64 * params)2523 bool ValidateGetQueryObjecti64vEXT(const Context *context,
2524 angle::EntryPoint entryPoint,
2525 QueryID id,
2526 GLenum pname,
2527 GLint64 *params)
2528 {
2529 if (!context->getExtensions().disjointTimerQueryEXT)
2530 {
2531 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2532 return false;
2533 }
2534 return ValidateGetQueryObjectValueBase(context, entryPoint, id, pname, nullptr);
2535 }
2536
ValidateGetQueryObjecti64vRobustANGLE(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,GLsizei bufSize,const GLsizei * length,GLint64 * params)2537 bool ValidateGetQueryObjecti64vRobustANGLE(const Context *context,
2538 angle::EntryPoint entryPoint,
2539 QueryID id,
2540 GLenum pname,
2541 GLsizei bufSize,
2542 const GLsizei *length,
2543 GLint64 *params)
2544 {
2545 if (!context->getExtensions().disjointTimerQueryEXT)
2546 {
2547 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2548 return false;
2549 }
2550
2551 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
2552 {
2553 return false;
2554 }
2555
2556 GLsizei numParams = 0;
2557
2558 if (!ValidateGetQueryObjectValueBase(context, entryPoint, id, pname, &numParams))
2559 {
2560 return false;
2561 }
2562
2563 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
2564 {
2565 return false;
2566 }
2567
2568 SetRobustLengthParam(length, numParams);
2569
2570 return true;
2571 }
2572
ValidateGetQueryObjectui64vEXT(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,GLuint64 * params)2573 bool ValidateGetQueryObjectui64vEXT(const Context *context,
2574 angle::EntryPoint entryPoint,
2575 QueryID id,
2576 GLenum pname,
2577 GLuint64 *params)
2578 {
2579 if (!context->getExtensions().disjointTimerQueryEXT)
2580 {
2581 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2582 return false;
2583 }
2584 return ValidateGetQueryObjectValueBase(context, entryPoint, id, pname, nullptr);
2585 }
2586
ValidateGetQueryObjectui64vRobustANGLE(const Context * context,angle::EntryPoint entryPoint,QueryID id,GLenum pname,GLsizei bufSize,const GLsizei * length,GLuint64 * params)2587 bool ValidateGetQueryObjectui64vRobustANGLE(const Context *context,
2588 angle::EntryPoint entryPoint,
2589 QueryID id,
2590 GLenum pname,
2591 GLsizei bufSize,
2592 const GLsizei *length,
2593 GLuint64 *params)
2594 {
2595 if (!context->getExtensions().disjointTimerQueryEXT)
2596 {
2597 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
2598 return false;
2599 }
2600
2601 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
2602 {
2603 return false;
2604 }
2605
2606 GLsizei numParams = 0;
2607
2608 if (!ValidateGetQueryObjectValueBase(context, entryPoint, id, pname, &numParams))
2609 {
2610 return false;
2611 }
2612
2613 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
2614 {
2615 return false;
2616 }
2617
2618 SetRobustLengthParam(length, numParams);
2619
2620 return true;
2621 }
2622
ValidateUniformCommonBase(const Context * context,angle::EntryPoint entryPoint,const Program * program,UniformLocation location,GLsizei count,const LinkedUniform ** uniformOut)2623 bool ValidateUniformCommonBase(const Context *context,
2624 angle::EntryPoint entryPoint,
2625 const Program *program,
2626 UniformLocation location,
2627 GLsizei count,
2628 const LinkedUniform **uniformOut)
2629 {
2630 // TODO(Jiajia): Add image uniform check in future.
2631 if (count < 0)
2632 {
2633 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeCount);
2634 return false;
2635 }
2636
2637 if (!program)
2638 {
2639 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidProgramName);
2640 return false;
2641 }
2642
2643 if (!program->isLinked())
2644 {
2645 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
2646 return false;
2647 }
2648
2649 if (location.value == -1)
2650 {
2651 // Silently ignore the uniform command
2652 return false;
2653 }
2654
2655 const auto &uniformLocations = program->getUniformLocations();
2656 size_t castedLocation = static_cast<size_t>(location.value);
2657 if (castedLocation >= uniformLocations.size())
2658 {
2659 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidUniformLocation);
2660 return false;
2661 }
2662
2663 const auto &uniformLocation = uniformLocations[castedLocation];
2664 if (uniformLocation.ignored)
2665 {
2666 // Silently ignore the uniform command
2667 return false;
2668 }
2669
2670 if (!uniformLocation.used())
2671 {
2672 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidUniformLocation);
2673 return false;
2674 }
2675
2676 const auto &uniform = program->getUniformByIndex(uniformLocation.index);
2677
2678 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
2679 if (count > 1 && !uniform.isArray())
2680 {
2681 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidUniformCount);
2682 return false;
2683 }
2684
2685 *uniformOut = &uniform;
2686 return true;
2687 }
2688
ValidateUniform1ivValue(const Context * context,angle::EntryPoint entryPoint,GLenum uniformType,GLsizei count,const GLint * value)2689 bool ValidateUniform1ivValue(const Context *context,
2690 angle::EntryPoint entryPoint,
2691 GLenum uniformType,
2692 GLsizei count,
2693 const GLint *value)
2694 {
2695 // Value type is GL_INT, because we only get here from glUniform1i{v}.
2696 // It is compatible with INT or BOOL.
2697 // Do these cheap tests first, for a little extra speed.
2698 if (GL_INT == uniformType || GL_BOOL == uniformType)
2699 {
2700 return true;
2701 }
2702
2703 if (IsSamplerType(uniformType))
2704 {
2705 // Check that the values are in range.
2706 const GLint max = context->getCaps().maxCombinedTextureImageUnits;
2707 for (GLsizei i = 0; i < count; ++i)
2708 {
2709 if (value[i] < 0 || value[i] >= max)
2710 {
2711 context->validationError(entryPoint, GL_INVALID_VALUE,
2712 kSamplerUniformValueOutOfRange);
2713 return false;
2714 }
2715 }
2716 return true;
2717 }
2718
2719 context->validationError(entryPoint, GL_INVALID_OPERATION, kUniformTypeMismatch);
2720 return false;
2721 }
2722
ValidateUniformMatrixValue(const Context * context,angle::EntryPoint entryPoint,GLenum valueType,GLenum uniformType)2723 bool ValidateUniformMatrixValue(const Context *context,
2724 angle::EntryPoint entryPoint,
2725 GLenum valueType,
2726 GLenum uniformType)
2727 {
2728 // Check that the value type is compatible with uniform type.
2729 if (valueType == uniformType)
2730 {
2731 return true;
2732 }
2733
2734 context->validationError(entryPoint, GL_INVALID_OPERATION, kUniformTypeMismatch);
2735 return false;
2736 }
2737
ValidateUniform(const Context * context,angle::EntryPoint entryPoint,GLenum valueType,UniformLocation location,GLsizei count)2738 bool ValidateUniform(const Context *context,
2739 angle::EntryPoint entryPoint,
2740 GLenum valueType,
2741 UniformLocation location,
2742 GLsizei count)
2743 {
2744 const LinkedUniform *uniform = nullptr;
2745 Program *programObject = context->getActiveLinkedProgram();
2746 return ValidateUniformCommonBase(context, entryPoint, programObject, location, count,
2747 &uniform) &&
2748 ValidateUniformValue(context, entryPoint, valueType, uniform->type);
2749 }
2750
ValidateUniform1iv(const Context * context,angle::EntryPoint entryPoint,UniformLocation location,GLsizei count,const GLint * value)2751 bool ValidateUniform1iv(const Context *context,
2752 angle::EntryPoint entryPoint,
2753 UniformLocation location,
2754 GLsizei count,
2755 const GLint *value)
2756 {
2757 const LinkedUniform *uniform = nullptr;
2758 Program *programObject = context->getActiveLinkedProgram();
2759 return ValidateUniformCommonBase(context, entryPoint, programObject, location, count,
2760 &uniform) &&
2761 ValidateUniform1ivValue(context, entryPoint, uniform->type, count, value);
2762 }
2763
ValidateUniformMatrix(const Context * context,angle::EntryPoint entryPoint,GLenum valueType,UniformLocation location,GLsizei count,GLboolean transpose)2764 bool ValidateUniformMatrix(const Context *context,
2765 angle::EntryPoint entryPoint,
2766 GLenum valueType,
2767 UniformLocation location,
2768 GLsizei count,
2769 GLboolean transpose)
2770 {
2771 if (ConvertToBool(transpose) && context->getClientMajorVersion() < 3)
2772 {
2773 context->validationError(entryPoint, GL_INVALID_VALUE, kES3Required);
2774 return false;
2775 }
2776
2777 const LinkedUniform *uniform = nullptr;
2778 Program *programObject = context->getActiveLinkedProgram();
2779 return ValidateUniformCommonBase(context, entryPoint, programObject, location, count,
2780 &uniform) &&
2781 ValidateUniformMatrixValue(context, entryPoint, valueType, uniform->type);
2782 }
2783
ValidateStateQuery(const Context * context,angle::EntryPoint entryPoint,GLenum pname,GLenum * nativeType,unsigned int * numParams)2784 bool ValidateStateQuery(const Context *context,
2785 angle::EntryPoint entryPoint,
2786 GLenum pname,
2787 GLenum *nativeType,
2788 unsigned int *numParams)
2789 {
2790 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
2791 {
2792 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
2793 return false;
2794 }
2795
2796 const Caps &caps = context->getCaps();
2797
2798 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
2799 {
2800 int colorAttachment = (pname - GL_DRAW_BUFFER0);
2801
2802 if (colorAttachment >= caps.maxDrawBuffers)
2803 {
2804 context->validationError(entryPoint, GL_INVALID_OPERATION, kIndexExceedsMaxDrawBuffer);
2805 return false;
2806 }
2807 }
2808
2809 switch (pname)
2810 {
2811 case GL_TEXTURE_BINDING_2D:
2812 case GL_TEXTURE_BINDING_CUBE_MAP:
2813 case GL_TEXTURE_BINDING_3D:
2814 case GL_TEXTURE_BINDING_2D_ARRAY:
2815 case GL_TEXTURE_BINDING_2D_MULTISAMPLE:
2816 break;
2817 case GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY:
2818 if (!context->getExtensions().textureStorageMultisample2dArrayOES)
2819 {
2820 context->validationError(entryPoint, GL_INVALID_ENUM,
2821 kMultisampleArrayExtensionRequired);
2822 return false;
2823 }
2824 break;
2825 case GL_TEXTURE_BINDING_RECTANGLE_ANGLE:
2826 if (!context->getExtensions().textureRectangleANGLE)
2827 {
2828 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
2829 return false;
2830 }
2831 break;
2832 case GL_TEXTURE_BINDING_EXTERNAL_OES:
2833 if (!context->getExtensions().EGLStreamConsumerExternalNV &&
2834 !context->getExtensions().EGLImageExternalOES)
2835 {
2836 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
2837 return false;
2838 }
2839 break;
2840 case GL_TEXTURE_BUFFER_BINDING:
2841 case GL_TEXTURE_BINDING_BUFFER:
2842 case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
2843 case GL_MAX_TEXTURE_BUFFER_SIZE:
2844 if (context->getClientVersion() < Version(3, 2) &&
2845 !context->getExtensions().textureBufferAny())
2846 {
2847 context->validationError(entryPoint, GL_INVALID_ENUM,
2848 kTextureBufferExtensionNotAvailable);
2849 return false;
2850 }
2851 break;
2852
2853 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
2854 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
2855 {
2856 Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
2857 ASSERT(readFramebuffer);
2858
2859 if (!ValidateFramebufferComplete<GL_INVALID_OPERATION>(context, entryPoint,
2860 readFramebuffer))
2861 {
2862 return false;
2863 }
2864
2865 if (readFramebuffer->getReadBufferState() == GL_NONE)
2866 {
2867 context->validationError(entryPoint, GL_INVALID_OPERATION, kReadBufferNone);
2868 return false;
2869 }
2870
2871 const FramebufferAttachment *attachment = readFramebuffer->getReadColorAttachment();
2872 if (!attachment)
2873 {
2874 context->validationError(entryPoint, GL_INVALID_OPERATION, kReadBufferNotAttached);
2875 return false;
2876 }
2877 }
2878 break;
2879
2880 case GL_PRIMITIVE_BOUNDING_BOX:
2881 if (!context->getExtensions().primitiveBoundingBoxEXT)
2882 {
2883 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
2884 return false;
2885 }
2886 break;
2887
2888 default:
2889 break;
2890 }
2891
2892 // pname is valid, but there are no parameters to return
2893 if (*numParams == 0)
2894 {
2895 return false;
2896 }
2897
2898 return true;
2899 }
2900
ValidateGetBooleanvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLboolean * params)2901 bool ValidateGetBooleanvRobustANGLE(const Context *context,
2902 angle::EntryPoint entryPoint,
2903 GLenum pname,
2904 GLsizei bufSize,
2905 const GLsizei *length,
2906 const GLboolean *params)
2907 {
2908 GLenum nativeType;
2909 unsigned int numParams = 0;
2910
2911 if (!ValidateRobustStateQuery(context, entryPoint, pname, bufSize, &nativeType, &numParams))
2912 {
2913 return false;
2914 }
2915
2916 SetRobustLengthParam(length, numParams);
2917
2918 return true;
2919 }
2920
ValidateGetFloatvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLfloat * params)2921 bool ValidateGetFloatvRobustANGLE(const Context *context,
2922 angle::EntryPoint entryPoint,
2923 GLenum pname,
2924 GLsizei bufSize,
2925 const GLsizei *length,
2926 const GLfloat *params)
2927 {
2928 GLenum nativeType;
2929 unsigned int numParams = 0;
2930
2931 if (!ValidateRobustStateQuery(context, entryPoint, pname, bufSize, &nativeType, &numParams))
2932 {
2933 return false;
2934 }
2935
2936 SetRobustLengthParam(length, numParams);
2937
2938 return true;
2939 }
2940
ValidateGetIntegervRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * data)2941 bool ValidateGetIntegervRobustANGLE(const Context *context,
2942 angle::EntryPoint entryPoint,
2943 GLenum pname,
2944 GLsizei bufSize,
2945 const GLsizei *length,
2946 const GLint *data)
2947 {
2948 GLenum nativeType;
2949 unsigned int numParams = 0;
2950
2951 if (!ValidateRobustStateQuery(context, entryPoint, pname, bufSize, &nativeType, &numParams))
2952 {
2953 return false;
2954 }
2955
2956 SetRobustLengthParam(length, numParams);
2957
2958 return true;
2959 }
2960
ValidateGetInteger64vRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum pname,GLsizei bufSize,const GLsizei * length,GLint64 * data)2961 bool ValidateGetInteger64vRobustANGLE(const Context *context,
2962 angle::EntryPoint entryPoint,
2963 GLenum pname,
2964 GLsizei bufSize,
2965 const GLsizei *length,
2966 GLint64 *data)
2967 {
2968 GLenum nativeType;
2969 unsigned int numParams = 0;
2970
2971 if (!ValidateRobustStateQuery(context, entryPoint, pname, bufSize, &nativeType, &numParams))
2972 {
2973 return false;
2974 }
2975
2976 if (nativeType == GL_INT_64_ANGLEX)
2977 {
2978 CastStateValues(context, nativeType, pname, numParams, data);
2979 return false;
2980 }
2981
2982 SetRobustLengthParam(length, numParams);
2983 return true;
2984 }
2985
ValidateRobustStateQuery(const Context * context,angle::EntryPoint entryPoint,GLenum pname,GLsizei bufSize,GLenum * nativeType,unsigned int * numParams)2986 bool ValidateRobustStateQuery(const Context *context,
2987 angle::EntryPoint entryPoint,
2988 GLenum pname,
2989 GLsizei bufSize,
2990 GLenum *nativeType,
2991 unsigned int *numParams)
2992 {
2993 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
2994 {
2995 return false;
2996 }
2997
2998 if (!ValidateStateQuery(context, entryPoint, pname, nativeType, numParams))
2999 {
3000 return false;
3001 }
3002
3003 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, *numParams))
3004 {
3005 return false;
3006 }
3007
3008 return true;
3009 }
3010
ValidateCopyImageSubDataTarget(const Context * context,angle::EntryPoint entryPoint,GLuint name,GLenum target)3011 bool ValidateCopyImageSubDataTarget(const Context *context,
3012 angle::EntryPoint entryPoint,
3013 GLuint name,
3014 GLenum target)
3015 {
3016 // From EXT_copy_image: INVALID_ENUM is generated if either <srcTarget> or <dstTarget> is not
3017 // RENDERBUFFER or a valid non - proxy texture target, is TEXTURE_BUFFER, or is one of the
3018 // cubemap face selectors described in table 3.17, or if the target does not match the type of
3019 // the object. INVALID_VALUE is generated if either <srcName> or <dstName> does not correspond
3020 // to a valid renderbuffer or texture object according to the corresponding target parameter.
3021 switch (target)
3022 {
3023 case GL_RENDERBUFFER:
3024 {
3025 RenderbufferID renderbuffer = PackParam<RenderbufferID>(name);
3026 if (!context->isRenderbuffer(renderbuffer))
3027 {
3028 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidRenderbufferName);
3029 return false;
3030 }
3031 break;
3032 }
3033 case GL_TEXTURE_2D:
3034 case GL_TEXTURE_3D:
3035 case GL_TEXTURE_2D_ARRAY:
3036 case GL_TEXTURE_CUBE_MAP:
3037 case GL_TEXTURE_CUBE_MAP_ARRAY_EXT:
3038 {
3039 TextureID texture = PackParam<TextureID>(name);
3040 if (!context->isTexture(texture))
3041 {
3042 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidTextureName);
3043 return false;
3044 }
3045
3046 Texture *textureObject = context->getTexture(texture);
3047 if (textureObject && textureObject->getType() != PackParam<TextureType>(target))
3048 {
3049 context->validationError(entryPoint, GL_INVALID_ENUM, err::kTextureTypeMismatch);
3050 return false;
3051 }
3052 break;
3053 }
3054 default:
3055 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTarget);
3056 return false;
3057 }
3058
3059 return true;
3060 }
3061
ValidateCopyImageSubDataLevel(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLint level)3062 bool ValidateCopyImageSubDataLevel(const Context *context,
3063 angle::EntryPoint entryPoint,
3064 GLenum target,
3065 GLint level)
3066 {
3067 switch (target)
3068 {
3069 case GL_RENDERBUFFER:
3070 {
3071 if (level != 0)
3072 {
3073 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
3074 return false;
3075 }
3076 break;
3077 }
3078 case GL_TEXTURE_2D:
3079 case GL_TEXTURE_3D:
3080 case GL_TEXTURE_2D_ARRAY:
3081 case GL_TEXTURE_CUBE_MAP:
3082 case GL_TEXTURE_CUBE_MAP_ARRAY_EXT:
3083 {
3084 if (!ValidMipLevel(context, PackParam<TextureType>(target), level))
3085 {
3086 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
3087 return false;
3088 }
3089 break;
3090 }
3091 default:
3092 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTarget);
3093 return false;
3094 }
3095
3096 return true;
3097 }
3098
ValidateCopyImageSubDataTargetRegion(const Context * context,angle::EntryPoint entryPoint,GLuint name,GLenum target,GLint level,GLint offsetX,GLint offsetY,GLint offsetZ,GLsizei width,GLsizei height,GLsizei * samples)3099 bool ValidateCopyImageSubDataTargetRegion(const Context *context,
3100 angle::EntryPoint entryPoint,
3101 GLuint name,
3102 GLenum target,
3103 GLint level,
3104 GLint offsetX,
3105 GLint offsetY,
3106 GLint offsetZ,
3107 GLsizei width,
3108 GLsizei height,
3109 GLsizei *samples)
3110 {
3111 // INVALID_VALUE is generated if the dimensions of the either subregion exceeds the boundaries
3112 // of the corresponding image object.
3113 if (offsetX < 0 || offsetY < 0 || offsetZ < 0)
3114 {
3115 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeOffset);
3116 return false;
3117 }
3118
3119 if (target == GL_RENDERBUFFER)
3120 {
3121 // INVALID_VALUE is generated if the dimensions of the either subregion exceeds the
3122 // boundaries of the corresponding image object
3123 Renderbuffer *buffer = context->getRenderbuffer(PackParam<RenderbufferID>(name));
3124 if ((buffer->getWidth() - offsetX < width) || (buffer->getHeight() - offsetY < height))
3125 {
3126 context->validationError(entryPoint, GL_INVALID_VALUE, kSourceTextureTooSmall);
3127 return false;
3128 }
3129 }
3130 else
3131 {
3132 Texture *texture = context->getTexture(PackParam<TextureID>(name));
3133
3134 // INVALID_OPERATION is generated if either object is a texture and the texture is not
3135 // complete
3136 // This will handle the texture completeness check. Note that this is missing
3137 // completeness validation that ignores format-based compleness rules.
3138 if (!texture->isSamplerComplete(context, nullptr))
3139 {
3140 context->validationError(entryPoint, GL_INVALID_OPERATION, kNotTextureComplete);
3141 return false;
3142 }
3143
3144 GLenum textureTargetToUse = target;
3145 if (target == GL_TEXTURE_CUBE_MAP)
3146 {
3147 // Use GL_TEXTURE_CUBE_MAP_POSITIVE_X to properly gather the textureWidth/textureHeight
3148 textureTargetToUse = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
3149 }
3150
3151 const GLsizei textureWidth = static_cast<GLsizei>(
3152 texture->getWidth(PackParam<TextureTarget>(textureTargetToUse), level));
3153 const GLsizei textureHeight = static_cast<GLsizei>(
3154 texture->getHeight(PackParam<TextureTarget>(textureTargetToUse), level));
3155
3156 // INVALID_VALUE is generated if the dimensions of the either subregion exceeds the
3157 // boundaries of the corresponding image object
3158 if ((textureWidth - offsetX < width) || (textureHeight - offsetY < height))
3159 {
3160 context->validationError(entryPoint, GL_INVALID_VALUE, kSourceTextureTooSmall);
3161 return false;
3162 }
3163
3164 *samples = texture->getSamples(PackParam<TextureTarget>(textureTargetToUse), level);
3165 *samples = (*samples == 0) ? 1 : *samples;
3166 }
3167
3168 return true;
3169 }
3170
ValidateCompressedRegion(const Context * context,angle::EntryPoint entryPoint,const InternalFormat & formatInfo,GLsizei width,GLsizei height)3171 bool ValidateCompressedRegion(const Context *context,
3172 angle::EntryPoint entryPoint,
3173 const InternalFormat &formatInfo,
3174 GLsizei width,
3175 GLsizei height)
3176 {
3177 ASSERT(formatInfo.compressed);
3178
3179 // INVALID_VALUE is generated if the image format is compressed and the dimensions of the
3180 // subregion fail to meet the alignment constraints of the format.
3181 if ((width % formatInfo.compressedBlockWidth != 0) ||
3182 (height % formatInfo.compressedBlockHeight != 0))
3183 {
3184 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidCompressedRegionSize);
3185 return false;
3186 }
3187
3188 return true;
3189 }
3190
GetTargetFormatInfo(const Context * context,angle::EntryPoint entryPoint,GLuint name,GLenum target,GLint level)3191 const InternalFormat &GetTargetFormatInfo(const Context *context,
3192 angle::EntryPoint entryPoint,
3193 GLuint name,
3194 GLenum target,
3195 GLint level)
3196 {
3197 static const InternalFormat defaultInternalFormat;
3198
3199 switch (target)
3200 {
3201 case GL_RENDERBUFFER:
3202 {
3203 Renderbuffer *buffer = context->getRenderbuffer(PackParam<RenderbufferID>(name));
3204 return *buffer->getFormat().info;
3205 }
3206 case GL_TEXTURE_2D:
3207 case GL_TEXTURE_3D:
3208 case GL_TEXTURE_2D_ARRAY:
3209 case GL_TEXTURE_CUBE_MAP:
3210 case GL_TEXTURE_CUBE_MAP_ARRAY_EXT:
3211 {
3212 Texture *texture = context->getTexture(PackParam<TextureID>(name));
3213 GLenum textureTargetToUse = target;
3214
3215 if (target == GL_TEXTURE_CUBE_MAP)
3216 {
3217 // Use GL_TEXTURE_CUBE_MAP_POSITIVE_X to properly gather the
3218 // textureWidth/textureHeight
3219 textureTargetToUse = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
3220 }
3221 return *texture->getFormat(PackParam<TextureTarget>(textureTargetToUse), level).info;
3222 }
3223 default:
3224 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTarget);
3225 return defaultInternalFormat;
3226 }
3227 }
3228
ValidateCopyMixedFormatCompatible(GLenum uncompressedFormat,GLenum compressedFormat)3229 bool ValidateCopyMixedFormatCompatible(GLenum uncompressedFormat, GLenum compressedFormat)
3230 {
3231 // Validates mixed format compatibility (uncompressed and compressed) from Table 4.X.1 of the
3232 // EXT_copy_image spec.
3233 switch (compressedFormat)
3234 {
3235 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
3236 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
3237 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
3238 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
3239 case GL_COMPRESSED_RED_GREEN_RGTC2_EXT:
3240 case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
3241 case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT:
3242 case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:
3243 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT:
3244 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT:
3245 case GL_COMPRESSED_RGBA8_ETC2_EAC:
3246 case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
3247 case GL_COMPRESSED_RG11_EAC:
3248 case GL_COMPRESSED_SIGNED_RG11_EAC:
3249 case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
3250 case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
3251 case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
3252 case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
3253 case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
3254 case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
3255 case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
3256 case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
3257 case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
3258 case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
3259 case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
3260 case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
3261 case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
3262 case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
3263 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
3264 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
3265 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
3266 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
3267 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
3268 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
3269 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
3270 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
3271 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
3272 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
3273 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
3274 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
3275 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
3276 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
3277 case GL_COMPRESSED_RGBA_ASTC_3x3x3_OES:
3278 case GL_COMPRESSED_RGBA_ASTC_4x3x3_OES:
3279 case GL_COMPRESSED_RGBA_ASTC_4x4x3_OES:
3280 case GL_COMPRESSED_RGBA_ASTC_4x4x4_OES:
3281 case GL_COMPRESSED_RGBA_ASTC_5x4x4_OES:
3282 case GL_COMPRESSED_RGBA_ASTC_5x5x4_OES:
3283 case GL_COMPRESSED_RGBA_ASTC_5x5x5_OES:
3284 case GL_COMPRESSED_RGBA_ASTC_6x5x5_OES:
3285 case GL_COMPRESSED_RGBA_ASTC_6x6x5_OES:
3286 case GL_COMPRESSED_RGBA_ASTC_6x6x6_OES:
3287 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES:
3288 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES:
3289 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES:
3290 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES:
3291 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES:
3292 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES:
3293 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES:
3294 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES:
3295 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES:
3296 case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES:
3297 {
3298 switch (uncompressedFormat)
3299 {
3300 case GL_RGBA32UI:
3301 case GL_RGBA32I:
3302 case GL_RGBA32F:
3303 return true;
3304 default:
3305 return false;
3306 }
3307 }
3308 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
3309 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
3310 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
3311 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
3312 case GL_COMPRESSED_RED_RGTC1_EXT:
3313 case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
3314 case GL_COMPRESSED_RGB8_ETC2:
3315 case GL_COMPRESSED_SRGB8_ETC2:
3316 case GL_COMPRESSED_R11_EAC:
3317 case GL_COMPRESSED_SIGNED_R11_EAC:
3318 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
3319 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
3320 {
3321 switch (uncompressedFormat)
3322 {
3323 case GL_RGBA16UI:
3324 case GL_RGBA16I:
3325 case GL_RGBA16F:
3326 case GL_RG32UI:
3327 case GL_RG32I:
3328 case GL_RG32F:
3329 return true;
3330 default:
3331 return false;
3332 }
3333 }
3334 default:
3335 break;
3336 }
3337
3338 return false;
3339 }
3340
ValidateCopyCompressedFormatCompatible(const InternalFormat & srcFormatInfo,const InternalFormat & dstFormatInfo)3341 bool ValidateCopyCompressedFormatCompatible(const InternalFormat &srcFormatInfo,
3342 const InternalFormat &dstFormatInfo)
3343 {
3344 // Validates compressed format compatibility from Table 4.X.2 of the EXT_copy_image spec.
3345
3346 ASSERT(srcFormatInfo.internalFormat != dstFormatInfo.internalFormat);
3347
3348 const GLenum srcFormat = srcFormatInfo.internalFormat;
3349 const GLenum dstFormat = dstFormatInfo.internalFormat;
3350
3351 switch (srcFormat)
3352 {
3353 case GL_COMPRESSED_RED_RGTC1_EXT:
3354 return (dstFormat == GL_COMPRESSED_SIGNED_RED_RGTC1_EXT);
3355 case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT:
3356 return (dstFormat == GL_COMPRESSED_RED_RGTC1_EXT);
3357 case GL_COMPRESSED_RED_GREEN_RGTC2_EXT:
3358 return (dstFormat == GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT);
3359 case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
3360 return (dstFormat == GL_COMPRESSED_RED_GREEN_RGTC2_EXT);
3361 case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT:
3362 return (dstFormat == GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT);
3363 case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT:
3364 return (dstFormat == GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT);
3365 case GL_COMPRESSED_R11_EAC:
3366 return (dstFormat == GL_COMPRESSED_SIGNED_R11_EAC);
3367 case GL_COMPRESSED_SIGNED_R11_EAC:
3368 return (dstFormat == GL_COMPRESSED_R11_EAC);
3369 case GL_COMPRESSED_RG11_EAC:
3370 return (dstFormat == GL_COMPRESSED_SIGNED_RG11_EAC);
3371 case GL_COMPRESSED_SIGNED_RG11_EAC:
3372 return (dstFormat == GL_COMPRESSED_RG11_EAC);
3373 default:
3374 break;
3375 }
3376
3377 // Since they can't be the same format and are both compressed formats, one must be linear and
3378 // the other nonlinear.
3379 if (srcFormatInfo.colorEncoding == dstFormatInfo.colorEncoding)
3380 {
3381 return false;
3382 }
3383
3384 const GLenum linearFormat = (srcFormatInfo.colorEncoding == GL_LINEAR) ? srcFormat : dstFormat;
3385 const GLenum nonLinearFormat =
3386 (srcFormatInfo.colorEncoding != GL_LINEAR) ? srcFormat : dstFormat;
3387
3388 switch (linearFormat)
3389 {
3390 case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT:
3391 return (nonLinearFormat == GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT);
3392 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
3393 return (nonLinearFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT);
3394 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
3395 return (nonLinearFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT);
3396 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
3397 return (nonLinearFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT);
3398 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
3399 return (nonLinearFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT);
3400 case GL_COMPRESSED_RGB8_ETC2:
3401 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ETC2);
3402 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
3403 return (nonLinearFormat == GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2);
3404 case GL_COMPRESSED_RGBA8_ETC2_EAC:
3405 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC);
3406 case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
3407 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR);
3408 case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
3409 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR);
3410 case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
3411 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR);
3412 case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
3413 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR);
3414 case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
3415 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR);
3416 case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
3417 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR);
3418 case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
3419 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR);
3420 case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
3421 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR);
3422 case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
3423 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR);
3424 case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
3425 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR);
3426 case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
3427 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR);
3428 case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
3429 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR);
3430 case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
3431 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR);
3432 case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
3433 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR);
3434 case GL_COMPRESSED_RGBA_ASTC_3x3x3_OES:
3435 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES);
3436 case GL_COMPRESSED_RGBA_ASTC_4x3x3_OES:
3437 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES);
3438 case GL_COMPRESSED_RGBA_ASTC_4x4x3_OES:
3439 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES);
3440 case GL_COMPRESSED_RGBA_ASTC_4x4x4_OES:
3441 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES);
3442 case GL_COMPRESSED_RGBA_ASTC_5x4x4_OES:
3443 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES);
3444 case GL_COMPRESSED_RGBA_ASTC_5x5x4_OES:
3445 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES);
3446 case GL_COMPRESSED_RGBA_ASTC_5x5x5_OES:
3447 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES);
3448 case GL_COMPRESSED_RGBA_ASTC_6x5x5_OES:
3449 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES);
3450 case GL_COMPRESSED_RGBA_ASTC_6x6x5_OES:
3451 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES);
3452 case GL_COMPRESSED_RGBA_ASTC_6x6x6_OES:
3453 return (nonLinearFormat == GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES);
3454 default:
3455 break;
3456 }
3457
3458 return false;
3459 }
3460
ValidateCopyFormatCompatible(const InternalFormat & srcFormatInfo,const InternalFormat & dstFormatInfo)3461 bool ValidateCopyFormatCompatible(const InternalFormat &srcFormatInfo,
3462 const InternalFormat &dstFormatInfo)
3463 {
3464 // Matching source and destination formats are compatible.
3465 if (srcFormatInfo.internalFormat == dstFormatInfo.internalFormat)
3466 {
3467 return true;
3468 }
3469
3470 if (srcFormatInfo.compressed != dstFormatInfo.compressed)
3471 {
3472 GLenum uncompressedFormat = (!srcFormatInfo.compressed) ? srcFormatInfo.internalFormat
3473 : dstFormatInfo.internalFormat;
3474 GLenum compressedFormat = (srcFormatInfo.compressed) ? srcFormatInfo.internalFormat
3475 : dstFormatInfo.internalFormat;
3476
3477 return ValidateCopyMixedFormatCompatible(uncompressedFormat, compressedFormat);
3478 }
3479
3480 if (!srcFormatInfo.compressed)
3481 {
3482 // Source and destination are uncompressed formats.
3483 return (srcFormatInfo.pixelBytes == dstFormatInfo.pixelBytes);
3484 }
3485
3486 return ValidateCopyCompressedFormatCompatible(srcFormatInfo, dstFormatInfo);
3487 }
3488
ValidateCopyImageSubDataBase(const Context * context,angle::EntryPoint entryPoint,GLuint srcName,GLenum srcTarget,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLuint dstName,GLenum dstTarget,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)3489 bool ValidateCopyImageSubDataBase(const Context *context,
3490 angle::EntryPoint entryPoint,
3491 GLuint srcName,
3492 GLenum srcTarget,
3493 GLint srcLevel,
3494 GLint srcX,
3495 GLint srcY,
3496 GLint srcZ,
3497 GLuint dstName,
3498 GLenum dstTarget,
3499 GLint dstLevel,
3500 GLint dstX,
3501 GLint dstY,
3502 GLint dstZ,
3503 GLsizei srcWidth,
3504 GLsizei srcHeight,
3505 GLsizei srcDepth)
3506 {
3507 // INVALID_VALUE is generated if the dimensions of the either subregion exceeds the boundaries
3508 // of the corresponding image object
3509 if ((srcWidth < 0) || (srcHeight < 0) || (srcDepth < 0))
3510 {
3511 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeSize);
3512 return false;
3513 }
3514
3515 if (!ValidateCopyImageSubDataTarget(context, entryPoint, srcName, srcTarget))
3516 {
3517 return false;
3518 }
3519 if (!ValidateCopyImageSubDataTarget(context, entryPoint, dstName, dstTarget))
3520 {
3521 return false;
3522 }
3523
3524 if (!ValidateCopyImageSubDataLevel(context, entryPoint, srcTarget, srcLevel))
3525 {
3526 return false;
3527 }
3528 if (!ValidateCopyImageSubDataLevel(context, entryPoint, dstTarget, dstLevel))
3529 {
3530 return false;
3531 }
3532
3533 const InternalFormat &srcFormatInfo =
3534 GetTargetFormatInfo(context, entryPoint, srcName, srcTarget, srcLevel);
3535 const InternalFormat &dstFormatInfo =
3536 GetTargetFormatInfo(context, entryPoint, dstName, dstTarget, dstLevel);
3537 GLsizei dstWidth = srcWidth;
3538 GLsizei dstHeight = srcHeight;
3539 GLsizei srcSamples = 1;
3540 GLsizei dstSamples = 1;
3541
3542 if (srcFormatInfo.internalFormat == GL_NONE || dstFormatInfo.internalFormat == GL_NONE)
3543 {
3544 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidTextureLevel);
3545 return false;
3546 }
3547
3548 if (!ValidateCopyImageSubDataTargetRegion(context, entryPoint, srcName, srcTarget, srcLevel,
3549 srcX, srcY, srcZ, srcWidth, srcHeight, &srcSamples))
3550 {
3551 return false;
3552 }
3553
3554 // When copying from a compressed image to an uncompressed image the image texel dimensions
3555 // written to the uncompressed image will be source extent divided by the compressed texel block
3556 // dimensions.
3557 if ((srcFormatInfo.compressed) && (!dstFormatInfo.compressed))
3558 {
3559 ASSERT(srcFormatInfo.compressedBlockWidth != 0);
3560 ASSERT(srcFormatInfo.compressedBlockHeight != 0);
3561
3562 dstWidth /= srcFormatInfo.compressedBlockWidth;
3563 dstHeight /= srcFormatInfo.compressedBlockHeight;
3564 }
3565 // When copying from an uncompressed image to a compressed image the image texel dimensions
3566 // written to the compressed image will be the source extent multiplied by the compressed texel
3567 // block dimensions.
3568 else if ((!srcFormatInfo.compressed) && (dstFormatInfo.compressed))
3569 {
3570 dstWidth *= dstFormatInfo.compressedBlockWidth;
3571 dstHeight *= dstFormatInfo.compressedBlockHeight;
3572 }
3573
3574 if (!ValidateCopyImageSubDataTargetRegion(context, entryPoint, dstName, dstTarget, dstLevel,
3575 dstX, dstY, dstZ, dstWidth, dstHeight, &dstSamples))
3576 {
3577 return false;
3578 }
3579
3580 bool fillsEntireMip = false;
3581 gl::Texture *dstTexture = context->getTexture({dstName});
3582 gl::TextureTarget dstTargetPacked = gl::PackParam<gl::TextureTarget>(dstTarget);
3583 // TODO(http://anglebug.com/5643): Some targets (e.g., GL_TEXTURE_CUBE_MAP, GL_RENDERBUFFER) are
3584 // unsupported when used with compressed formats due to gl::PackParam() returning
3585 // TextureTarget::InvalidEnum.
3586 if (dstTargetPacked != gl::TextureTarget::InvalidEnum)
3587 {
3588 const gl::Extents &dstExtents = dstTexture->getExtents(dstTargetPacked, dstLevel);
3589 fillsEntireMip = dstX == 0 && dstY == 0 && dstZ == 0 && srcWidth == dstExtents.width &&
3590 srcHeight == dstExtents.height && srcDepth == dstExtents.depth;
3591 }
3592
3593 if (srcFormatInfo.compressed && !fillsEntireMip &&
3594 !ValidateCompressedRegion(context, entryPoint, srcFormatInfo, srcWidth, srcHeight))
3595 {
3596 return false;
3597 }
3598
3599 if (dstFormatInfo.compressed && !fillsEntireMip &&
3600 !ValidateCompressedRegion(context, entryPoint, dstFormatInfo, dstWidth, dstHeight))
3601 {
3602 return false;
3603 }
3604
3605 // From EXT_copy_image: INVALID_OPERATION is generated if the source and destination formats
3606 // are not compatible, if one image is compressed and the other is uncompressed and the block
3607 // size of compressed image is not equal to the texel size of the compressed image.
3608 if (!ValidateCopyFormatCompatible(srcFormatInfo, dstFormatInfo))
3609 {
3610 context->validationError(entryPoint, GL_INVALID_OPERATION, kIncompatibleTextures);
3611 return false;
3612 }
3613
3614 // INVALID_OPERATION is generated if the source and destination number of samples do not match
3615 if (srcSamples != dstSamples)
3616 {
3617 context->validationError(entryPoint, GL_INVALID_OPERATION, kSamplesOutOfRange);
3618 return false;
3619 }
3620
3621 return true;
3622 }
3623
ValidateCopyTexImageParametersBase(const Context * context,angle::EntryPoint entryPoint,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)3624 bool ValidateCopyTexImageParametersBase(const Context *context,
3625 angle::EntryPoint entryPoint,
3626 TextureTarget target,
3627 GLint level,
3628 GLenum internalformat,
3629 bool isSubImage,
3630 GLint xoffset,
3631 GLint yoffset,
3632 GLint zoffset,
3633 GLint x,
3634 GLint y,
3635 GLsizei width,
3636 GLsizei height,
3637 GLint border,
3638 Format *textureFormatOut)
3639 {
3640 TextureType texType = TextureTargetToType(target);
3641
3642 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
3643 {
3644 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeOffset);
3645 return false;
3646 }
3647
3648 if (width < 0 || height < 0)
3649 {
3650 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeSize);
3651 return false;
3652 }
3653
3654 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
3655 std::numeric_limits<GLsizei>::max() - yoffset < height)
3656 {
3657 context->validationError(entryPoint, GL_INVALID_VALUE, kOffsetOverflow);
3658 return false;
3659 }
3660
3661 if (border != 0)
3662 {
3663 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidBorder);
3664 return false;
3665 }
3666
3667 if (!ValidMipLevel(context, texType, level))
3668 {
3669 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
3670 return false;
3671 }
3672
3673 const State &state = context->getState();
3674 Framebuffer *readFramebuffer = state.getReadFramebuffer();
3675 if (!ValidateFramebufferComplete(context, entryPoint, readFramebuffer))
3676 {
3677 return false;
3678 }
3679
3680 // checkReadBufferResourceSamples = true. Treat renderToTexture textures as single sample since
3681 // they will be resolved before copying.
3682 if (!readFramebuffer->isDefault() &&
3683 !ValidateFramebufferNotMultisampled(context, entryPoint, readFramebuffer, true))
3684 {
3685 return false;
3686 }
3687
3688 if (readFramebuffer->getReadBufferState() == GL_NONE)
3689 {
3690 context->validationError(entryPoint, GL_INVALID_OPERATION, kReadBufferNone);
3691 return false;
3692 }
3693
3694 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
3695 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
3696 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
3697 // situation is an application error that would lead to a crash in ANGLE.
3698 const FramebufferAttachment *source = readFramebuffer->getReadColorAttachment();
3699 if (source == nullptr)
3700 {
3701 context->validationError(entryPoint, GL_INVALID_OPERATION, kMissingReadAttachment);
3702 return false;
3703 }
3704
3705 if (source->isYUV())
3706 {
3707 context->validationError(entryPoint, GL_INVALID_OPERATION, kCopyFromYUVFramebuffer);
3708 return false;
3709 }
3710
3711 // ANGLE_multiview spec, Revision 1:
3712 // Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an
3713 // INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the current read framebuffer
3714 // is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views in the current read
3715 // framebuffer is more than one.
3716 if (readFramebuffer->readDisallowedByMultiview())
3717 {
3718 context->validationError(entryPoint, GL_INVALID_FRAMEBUFFER_OPERATION,
3719 kMultiviewReadFramebuffer);
3720 return false;
3721 }
3722
3723 const Caps &caps = context->getCaps();
3724
3725 GLint maxDimension = 0;
3726 switch (texType)
3727 {
3728 case TextureType::_2D:
3729 maxDimension = caps.max2DTextureSize;
3730 break;
3731
3732 case TextureType::CubeMap:
3733 case TextureType::CubeMapArray:
3734 maxDimension = caps.maxCubeMapTextureSize;
3735 break;
3736
3737 case TextureType::Rectangle:
3738 maxDimension = caps.maxRectangleTextureSize;
3739 break;
3740
3741 case TextureType::_2DArray:
3742 maxDimension = caps.max2DTextureSize;
3743 break;
3744
3745 case TextureType::_3D:
3746 maxDimension = caps.max3DTextureSize;
3747 break;
3748
3749 default:
3750 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
3751 return false;
3752 }
3753
3754 Texture *texture = state.getTargetTexture(texType);
3755 if (!texture)
3756 {
3757 context->validationError(entryPoint, GL_INVALID_OPERATION, kTextureNotBound);
3758 return false;
3759 }
3760
3761 if (texture->getImmutableFormat() && !isSubImage)
3762 {
3763 context->validationError(entryPoint, GL_INVALID_OPERATION, kTextureIsImmutable);
3764 return false;
3765 }
3766
3767 const InternalFormat &formatInfo =
3768 isSubImage ? *texture->getFormat(target, level).info
3769 : GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
3770
3771 if (formatInfo.depthBits > 0 || formatInfo.compressed)
3772 {
3773 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
3774 return false;
3775 }
3776
3777 if (isSubImage)
3778 {
3779 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
3780 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
3781 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
3782 {
3783 context->validationError(entryPoint, GL_INVALID_VALUE, kOffsetOverflow);
3784 return false;
3785 }
3786 }
3787 else
3788 {
3789 if ((texType == TextureType::CubeMap || texType == TextureType::CubeMapArray) &&
3790 width != height)
3791 {
3792 context->validationError(entryPoint, GL_INVALID_VALUE, kCubemapIncomplete);
3793 return false;
3794 }
3795
3796 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
3797 {
3798 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
3799 return false;
3800 }
3801
3802 int maxLevelDimension = (maxDimension >> level);
3803 if (static_cast<int>(width) > maxLevelDimension ||
3804 static_cast<int>(height) > maxLevelDimension)
3805 {
3806 context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxTextureSize);
3807 return false;
3808 }
3809 }
3810
3811 // Do not leak the previous texture format for non-subImage case.
3812 if (textureFormatOut && isSubImage)
3813 {
3814 *textureFormatOut = texture->getFormat(target, level);
3815 }
3816
3817 // Detect texture copying feedback loops for WebGL.
3818 if (context->isWebGL())
3819 {
3820 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
3821 {
3822 context->validationError(entryPoint, GL_INVALID_OPERATION, kFeedbackLoop);
3823 return false;
3824 }
3825 }
3826
3827 return true;
3828 }
3829
ValidateProgramPipelineDrawStates(const Context * context,const Extensions & extensions,ProgramPipeline * programPipeline)3830 const char *ValidateProgramPipelineDrawStates(const Context *context,
3831 const Extensions &extensions,
3832 ProgramPipeline *programPipeline)
3833 {
3834 for (const ShaderType shaderType : gl::AllShaderTypes())
3835 {
3836 Program *program = programPipeline->getShaderProgram(shaderType);
3837 if (program)
3838 {
3839 const char *errorMsg = ValidateProgramDrawStates(context, extensions, program);
3840 if (errorMsg)
3841 {
3842 return errorMsg;
3843 }
3844 }
3845 }
3846
3847 return nullptr;
3848 }
3849
ValidateProgramPipelineAttachedPrograms(ProgramPipeline * programPipeline)3850 const char *ValidateProgramPipelineAttachedPrograms(ProgramPipeline *programPipeline)
3851 {
3852 // An INVALID_OPERATION error is generated by any command that transfers vertices to the
3853 // GL or launches compute work if the current set of active
3854 // program objects cannot be executed, for reasons including:
3855 // - There is no current program object specified by UseProgram, there is a current program
3856 // pipeline object, and that object is empty (no executable code is installed for any stage).
3857 // - A program object is active for at least one, but not all of the shader
3858 // stages that were present when the program was linked.
3859 if (!programPipeline->getExecutable().getLinkedShaderStages().any())
3860 {
3861 return gl::err::kNoExecutableCodeInstalled;
3862 }
3863 for (const ShaderType shaderType : gl::AllShaderTypes())
3864 {
3865 Program *shaderProgram = programPipeline->getShaderProgram(shaderType);
3866 if (shaderProgram)
3867 {
3868 ProgramExecutable &executable = shaderProgram->getExecutable();
3869 for (const ShaderType programShaderType : executable.getLinkedShaderStages())
3870 {
3871 if (shaderProgram != programPipeline->getShaderProgram(programShaderType))
3872 {
3873 return gl::err::kNotAllStagesOfSeparableProgramUsed;
3874 }
3875 }
3876 }
3877 }
3878
3879 // [EXT_geometry_shader] Section 11.1.gs Geometry Shaders
3880 // A non-separable program object or program pipeline object that includes
3881 // a geometry shader must also include a vertex shader.
3882 // An INVALID_OPERATION error is generated by any command that transfers
3883 // vertices to the GL if the current program state has a geometry shader
3884 // but no vertex shader.
3885 if (!programPipeline->getShaderProgram(ShaderType::Vertex) &&
3886 programPipeline->getShaderProgram(ShaderType::Geometry))
3887 {
3888 return gl::err::kNoActiveGraphicsShaderStage;
3889 }
3890
3891 return nullptr;
3892 }
3893
3894 // Note all errors returned from this function are INVALID_OPERATION except for the draw framebuffer
3895 // completeness check.
ValidateDrawStates(const Context * context)3896 const char *ValidateDrawStates(const Context *context)
3897 {
3898 const Extensions &extensions = context->getExtensions();
3899 const State &state = context->getState();
3900
3901 // WebGL buffers cannot be mapped/unmapped because the MapBufferRange, FlushMappedBufferRange,
3902 // and UnmapBuffer entry points are removed from the WebGL 2.0 API.
3903 // https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.14
3904 VertexArray *vertexArray = state.getVertexArray();
3905 ASSERT(vertexArray);
3906
3907 if (!extensions.webglCompatibilityANGLE && vertexArray->hasInvalidMappedArrayBuffer())
3908 {
3909 return kBufferMapped;
3910 }
3911
3912 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
3913 // Section 6.10 of the WebGL 1.0 spec.
3914 Framebuffer *framebuffer = state.getDrawFramebuffer();
3915 ASSERT(framebuffer);
3916
3917 if (context->getLimitations().noSeparateStencilRefsAndMasks ||
3918 extensions.webglCompatibilityANGLE)
3919 {
3920 ASSERT(framebuffer);
3921 const FramebufferAttachment *dsAttachment =
3922 framebuffer->getStencilOrDepthStencilAttachment();
3923 const GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
3924 ASSERT(stencilBits <= 8);
3925
3926 const DepthStencilState &depthStencilState = state.getDepthStencilState();
3927 if (depthStencilState.stencilTest && stencilBits > 0)
3928 {
3929 GLuint maxStencilValue = (1 << stencilBits) - 1;
3930
3931 bool differentRefs =
3932 clamp(state.getStencilRef(), 0, static_cast<GLint>(maxStencilValue)) !=
3933 clamp(state.getStencilBackRef(), 0, static_cast<GLint>(maxStencilValue));
3934 bool differentWritemasks = (depthStencilState.stencilWritemask & maxStencilValue) !=
3935 (depthStencilState.stencilBackWritemask & maxStencilValue);
3936 bool differentMasks = (depthStencilState.stencilMask & maxStencilValue) !=
3937 (depthStencilState.stencilBackMask & maxStencilValue);
3938
3939 if (differentRefs || differentWritemasks || differentMasks)
3940 {
3941 if (!extensions.webglCompatibilityANGLE)
3942 {
3943 WARN() << "This ANGLE implementation does not support separate front/back "
3944 "stencil writemasks, reference values, or stencil mask values.";
3945 }
3946 return kStencilReferenceMaskOrMismatch;
3947 }
3948 }
3949 }
3950
3951 if (!extensions.floatBlendEXT)
3952 {
3953 const DrawBufferMask blendEnabledActiveFloat32ColorAttachmentDrawBufferMask =
3954 state.getBlendEnabledDrawBufferMask() &
3955 framebuffer->getActiveFloat32ColorAttachmentDrawBufferMask();
3956 if (blendEnabledActiveFloat32ColorAttachmentDrawBufferMask.any())
3957 {
3958 return kUnsupportedFloatBlending;
3959 }
3960 }
3961
3962 if (context->getLimitations().noSimultaneousConstantColorAndAlphaBlendFunc ||
3963 extensions.webglCompatibilityANGLE)
3964 {
3965 if (state.hasSimultaneousConstantColorAndAlphaBlendFunc())
3966 {
3967 if (extensions.webglCompatibilityANGLE)
3968 {
3969 return kInvalidConstantColor;
3970 }
3971
3972 WARN() << kConstantColorAlphaLimitation;
3973 return kConstantColorAlphaLimitation;
3974 }
3975 }
3976
3977 if (!framebuffer->isComplete(context))
3978 {
3979 // Note: this error should be generated as INVALID_FRAMEBUFFER_OPERATION.
3980 return kDrawFramebufferIncomplete;
3981 }
3982
3983 bool framebufferIsYUV = framebuffer->hasYUVAttachment();
3984 if (framebufferIsYUV)
3985 {
3986 const BlendState &blendState = state.getBlendState();
3987 if (!blendState.colorMaskRed || !blendState.colorMaskGreen || !blendState.colorMaskBlue)
3988 {
3989 // When rendering into a YUV framebuffer, the color mask must have r g and b set to
3990 // true.
3991 return kInvalidColorMaskForYUV;
3992 }
3993
3994 if (blendState.blend)
3995 {
3996 // When rendering into a YUV framebuffer, blending must be disabled.
3997 return kInvalidBlendStateForYUV;
3998 }
3999 }
4000 else
4001 {
4002 if (framebuffer->hasExternalTextureAttachment())
4003 {
4004 // It is an error to render into an external texture that is not YUV.
4005 return kExternalTextureAttachmentNotYUV;
4006 }
4007 }
4008
4009 if (context->getStateCache().hasAnyEnabledClientAttrib())
4010 {
4011 if (extensions.webglCompatibilityANGLE || !state.areClientArraysEnabled())
4012 {
4013 // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking
4014 // If a vertex attribute is enabled as an array via enableVertexAttribArray but no
4015 // buffer is bound to that attribute via bindBuffer and vertexAttribPointer, then calls
4016 // to drawArrays or drawElements will generate an INVALID_OPERATION error.
4017 return kVertexArrayNoBuffer;
4018 }
4019
4020 if (state.getVertexArray()->hasEnabledNullPointerClientArray())
4021 {
4022 // This is an application error that would normally result in a crash, but we catch it
4023 // and return an error
4024 return kVertexArrayNoBufferPointer;
4025 }
4026 }
4027
4028 // If we are running GLES1, there is no current program.
4029 if (context->getClientVersion() >= Version(2, 0))
4030 {
4031 Program *program = state.getLinkedProgram(context);
4032 ProgramPipeline *programPipeline = state.getProgramPipeline();
4033 const ProgramExecutable *executable = state.getProgramExecutable();
4034
4035 bool programIsYUVOutput = false;
4036
4037 if (program)
4038 {
4039 const char *errorMsg = ValidateProgramDrawStates(context, extensions, program);
4040 if (errorMsg)
4041 {
4042 return errorMsg;
4043 }
4044
4045 programIsYUVOutput = executable->isYUVOutput();
4046 }
4047 else if (programPipeline)
4048 {
4049 const char *errorMsg = ValidateProgramPipelineAttachedPrograms(programPipeline);
4050 if (errorMsg)
4051 {
4052 return errorMsg;
4053 }
4054
4055 errorMsg = ValidateProgramPipelineDrawStates(context, extensions, programPipeline);
4056 if (errorMsg)
4057 {
4058 return errorMsg;
4059 }
4060
4061 if (!programPipeline->isLinked())
4062 {
4063 return kProgramPipelineLinkFailed;
4064 }
4065
4066 programIsYUVOutput = executable->isYUVOutput();
4067 }
4068
4069 if (executable)
4070 {
4071 if (!executable->validateSamplers(nullptr, context->getCaps()))
4072 {
4073 return kTextureTypeConflict;
4074 }
4075
4076 if (executable->hasLinkedTessellationShader())
4077 {
4078 if (!executable->hasLinkedShaderStage(ShaderType::Vertex))
4079 {
4080 return kTessellationShaderRequiresVertexShader;
4081 }
4082
4083 if (!executable->hasLinkedShaderStage(ShaderType::TessControl) ||
4084 !executable->hasLinkedShaderStage(ShaderType::TessEvaluation))
4085 {
4086 return kTessellationShaderRequiresBothControlAndEvaluation;
4087 }
4088 }
4089
4090 //angle CVE-2022-0975
4091 if (state.isTransformFeedbackActive())
4092 {
4093 if (!ValidateProgramExecutableXFBBuffersPresent(context, executable))
4094 {
4095 return kTransformFeedbackBufferMissing;
4096 }
4097 }
4098 }
4099
4100 if (programIsYUVOutput != framebufferIsYUV)
4101 {
4102 // Both the program and framebuffer must match in YUV output state.
4103 return kYUVOutputMissmatch;
4104 }
4105
4106 if (!state.validateSamplerFormats())
4107 {
4108 return kSamplerFormatMismatch;
4109 }
4110
4111 // Do some additional WebGL-specific validation
4112 if (extensions.webglCompatibilityANGLE)
4113 {
4114 const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
4115 if (state.isTransformFeedbackActive() &&
4116 transformFeedbackObject->buffersBoundForOtherUseInWebGL())
4117 {
4118 return kTransformFeedbackBufferDoubleBound;
4119 }
4120
4121 // Detect rendering feedback loops for WebGL.
4122 if (framebuffer->formsRenderingFeedbackLoopWith(context))
4123 {
4124 return kFeedbackLoop;
4125 }
4126
4127 // Detect that the vertex shader input types match the attribute types
4128 if (!ValidateVertexShaderAttributeTypeMatch(context))
4129 {
4130 return kVertexShaderTypeMismatch;
4131 }
4132
4133 if (!context->getState().getRasterizerState().rasterizerDiscard &&
4134 !context->getState().allActiveDrawBufferChannelsMasked())
4135 {
4136 // Detect that if there's active color buffer without fragment shader output
4137 if (!ValidateFragmentShaderColorBufferMaskMatch(context))
4138 {
4139 return kDrawBufferMaskMismatch;
4140 }
4141
4142 // Detect that the color buffer types match the fragment shader output types
4143 if (!ValidateFragmentShaderColorBufferTypeMatch(context))
4144 {
4145 return kDrawBufferTypeMismatch;
4146 }
4147 }
4148
4149 const VertexArray *vao = context->getState().getVertexArray();
4150 if (vao->hasTransformFeedbackBindingConflict(context))
4151 {
4152 return kVertexBufferBoundForTransformFeedback;
4153 }
4154
4155 // Validate that we are rendering with a linked program.
4156 if (!program->isLinked())
4157 {
4158 return kProgramNotLinked;
4159 }
4160 }
4161 }
4162
4163 return nullptr;
4164 }
4165
RecordDrawModeError(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode)4166 void RecordDrawModeError(const Context *context, angle::EntryPoint entryPoint, PrimitiveMode mode)
4167 {
4168 const State &state = context->getState();
4169 TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
4170 if (state.isTransformFeedbackActiveUnpaused())
4171 {
4172 if (!ValidateTransformFeedbackPrimitiveMode(context, entryPoint,
4173 curTransformFeedback->getPrimitiveMode(), mode))
4174 {
4175 context->validationError(entryPoint, GL_INVALID_OPERATION,
4176 kInvalidDrawModeTransformFeedback);
4177 return;
4178 }
4179 }
4180
4181 const Extensions &extensions = context->getExtensions();
4182
4183 switch (mode)
4184 {
4185 case PrimitiveMode::Points:
4186 case PrimitiveMode::Lines:
4187 case PrimitiveMode::LineLoop:
4188 case PrimitiveMode::LineStrip:
4189 case PrimitiveMode::Triangles:
4190 case PrimitiveMode::TriangleStrip:
4191 case PrimitiveMode::TriangleFan:
4192 break;
4193
4194 case PrimitiveMode::LinesAdjacency:
4195 case PrimitiveMode::LineStripAdjacency:
4196 case PrimitiveMode::TrianglesAdjacency:
4197 case PrimitiveMode::TriangleStripAdjacency:
4198 if (!extensions.geometryShaderAny() && context->getClientVersion() < ES_3_2)
4199 {
4200 context->validationError(entryPoint, GL_INVALID_ENUM,
4201 kGeometryShaderExtensionNotEnabled);
4202 return;
4203 }
4204 break;
4205
4206 case PrimitiveMode::Patches:
4207 if (!extensions.tessellationShaderEXT && context->getClientVersion() < ES_3_2)
4208 {
4209 context->validationError(entryPoint, GL_INVALID_ENUM,
4210 kTessellationShaderExtensionNotEnabled);
4211 return;
4212 }
4213 break;
4214
4215 default:
4216 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidDrawMode);
4217 return;
4218 }
4219
4220 // If we are running GLES1, there is no current program.
4221 if (context->getClientVersion() >= Version(2, 0))
4222 {
4223 const ProgramExecutable *executable = state.getProgramExecutable();
4224 ASSERT(executable);
4225
4226 // Do geometry shader specific validations
4227 if (executable->hasLinkedShaderStage(ShaderType::Geometry))
4228 {
4229 if (!IsCompatibleDrawModeWithGeometryShader(
4230 mode, executable->getGeometryShaderInputPrimitiveType()))
4231 {
4232 context->validationError(entryPoint, GL_INVALID_OPERATION,
4233 kIncompatibleDrawModeAgainstGeometryShader);
4234 return;
4235 }
4236 }
4237
4238 if (executable->hasLinkedTessellationShader() && mode != PrimitiveMode::Patches)
4239 {
4240 context->validationError(entryPoint, GL_INVALID_OPERATION,
4241 kIncompatibleDrawModeWithTessellationShader);
4242 return;
4243 }
4244
4245 if (!executable->hasLinkedTessellationShader() && mode == PrimitiveMode::Patches)
4246 {
4247 context->validationError(entryPoint, GL_INVALID_OPERATION,
4248 kIncompatibleDrawModeWithoutTessellationShader);
4249 return;
4250 }
4251 }
4252
4253 // An error should be recorded.
4254 UNREACHABLE();
4255 }
4256
ValidateDrawArraysInstancedANGLE(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)4257 bool ValidateDrawArraysInstancedANGLE(const Context *context,
4258 angle::EntryPoint entryPoint,
4259 PrimitiveMode mode,
4260 GLint first,
4261 GLsizei count,
4262 GLsizei primcount)
4263 {
4264 if (!context->getExtensions().instancedArraysANGLE)
4265 {
4266 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4267 return false;
4268 }
4269
4270 if (!ValidateDrawArraysInstancedBase(context, entryPoint, mode, first, count, primcount))
4271 {
4272 return false;
4273 }
4274
4275 return ValidateDrawInstancedANGLE(context, entryPoint);
4276 }
4277
ValidateDrawArraysInstancedEXT(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)4278 bool ValidateDrawArraysInstancedEXT(const Context *context,
4279 angle::EntryPoint entryPoint,
4280 PrimitiveMode mode,
4281 GLint first,
4282 GLsizei count,
4283 GLsizei primcount)
4284 {
4285 if (!context->getExtensions().instancedArraysEXT)
4286 {
4287 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4288 return false;
4289 }
4290
4291 if (!ValidateDrawArraysInstancedBase(context, entryPoint, mode, first, count, primcount))
4292 {
4293 return false;
4294 }
4295
4296 return true;
4297 }
4298
ValidateDrawElementsStates(const Context * context)4299 const char *ValidateDrawElementsStates(const Context *context)
4300 {
4301 const State &state = context->getState();
4302
4303 if (context->getStateCache().isTransformFeedbackActiveUnpaused())
4304 {
4305 // EXT_geometry_shader allows transform feedback to work with all draw commands.
4306 // [EXT_geometry_shader] Section 12.1, "Transform Feedback"
4307 if (!context->getExtensions().geometryShaderAny() && context->getClientVersion() < ES_3_2)
4308 {
4309 // It is an invalid operation to call DrawElements, DrawRangeElements or
4310 // DrawElementsInstanced while transform feedback is active, (3.0.2, section 2.14, pg
4311 // 86)
4312 return kUnsupportedDrawModeForTransformFeedback;
4313 }
4314 }
4315
4316 const VertexArray *vao = state.getVertexArray();
4317 Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
4318
4319 if (elementArrayBuffer)
4320 {
4321 if (elementArrayBuffer->hasWebGLXFBBindingConflict(context->isWebGL()))
4322 {
4323 return kElementArrayBufferBoundForTransformFeedback;
4324 }
4325 if (elementArrayBuffer->isMapped() &&
4326 (!elementArrayBuffer->isImmutable() ||
4327 (elementArrayBuffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) == 0))
4328 {
4329 return kBufferMapped;
4330 }
4331 }
4332 else
4333 {
4334 // [WebGL 1.0] Section 6.2 No Client Side Arrays
4335 // If an indexed draw command (drawElements) is called and no WebGLBuffer is bound to
4336 // the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
4337 if (!context->getState().areClientArraysEnabled() || context->isWebGL())
4338 {
4339 return kMustHaveElementArrayBinding;
4340 }
4341 }
4342
4343 return nullptr;
4344 }
4345
ValidateDrawElementsInstancedANGLE(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLsizei count,DrawElementsType type,const void * indices,GLsizei primcount)4346 bool ValidateDrawElementsInstancedANGLE(const Context *context,
4347 angle::EntryPoint entryPoint,
4348 PrimitiveMode mode,
4349 GLsizei count,
4350 DrawElementsType type,
4351 const void *indices,
4352 GLsizei primcount)
4353 {
4354 if (!context->getExtensions().instancedArraysANGLE)
4355 {
4356 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4357 return false;
4358 }
4359
4360 if (!ValidateDrawElementsInstancedBase(context, entryPoint, mode, count, type, indices,
4361 primcount))
4362 {
4363 return false;
4364 }
4365
4366 return ValidateDrawInstancedANGLE(context, entryPoint);
4367 }
4368
ValidateDrawElementsInstancedEXT(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLsizei count,DrawElementsType type,const void * indices,GLsizei primcount)4369 bool ValidateDrawElementsInstancedEXT(const Context *context,
4370 angle::EntryPoint entryPoint,
4371 PrimitiveMode mode,
4372 GLsizei count,
4373 DrawElementsType type,
4374 const void *indices,
4375 GLsizei primcount)
4376 {
4377 if (!context->getExtensions().instancedArraysEXT)
4378 {
4379 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4380 return false;
4381 }
4382
4383 if (!ValidateDrawElementsInstancedBase(context, entryPoint, mode, count, type, indices,
4384 primcount))
4385 {
4386 return false;
4387 }
4388
4389 return true;
4390 }
4391
ValidateGetUniformBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location)4392 bool ValidateGetUniformBase(const Context *context,
4393 angle::EntryPoint entryPoint,
4394 ShaderProgramID program,
4395 UniformLocation location)
4396 {
4397 if (program.value == 0)
4398 {
4399 context->validationError(entryPoint, GL_INVALID_VALUE, kProgramDoesNotExist);
4400 return false;
4401 }
4402
4403 Program *programObject = GetValidProgram(context, entryPoint, program);
4404 if (!programObject)
4405 {
4406 return false;
4407 }
4408
4409 if (!programObject || !programObject->isLinked())
4410 {
4411 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
4412 return false;
4413 }
4414
4415 if (!programObject->isValidUniformLocation(location))
4416 {
4417 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidUniformLocation);
4418 return false;
4419 }
4420
4421 return true;
4422 }
4423
ValidateSizedGetUniform(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,GLsizei * length)4424 static bool ValidateSizedGetUniform(const Context *context,
4425 angle::EntryPoint entryPoint,
4426 ShaderProgramID program,
4427 UniformLocation location,
4428 GLsizei bufSize,
4429 GLsizei *length)
4430 {
4431 if (length)
4432 {
4433 *length = 0;
4434 }
4435
4436 if (!ValidateGetUniformBase(context, entryPoint, program, location))
4437 {
4438 return false;
4439 }
4440
4441 if (bufSize < 0)
4442 {
4443 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeBufferSize);
4444 return false;
4445 }
4446
4447 Program *programObject = context->getProgramResolveLink(program);
4448 ASSERT(programObject);
4449
4450 // sized queries -- ensure the provided buffer is large enough
4451 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
4452 size_t requiredBytes = VariableExternalSize(uniform.type);
4453 if (static_cast<size_t>(bufSize) < requiredBytes)
4454 {
4455 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
4456 return false;
4457 }
4458
4459 if (length)
4460 {
4461 *length = VariableComponentCount(uniform.type);
4462 }
4463 return true;
4464 }
4465
ValidateGetnUniformfvEXT(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLfloat * params)4466 bool ValidateGetnUniformfvEXT(const Context *context,
4467 angle::EntryPoint entryPoint,
4468 ShaderProgramID program,
4469 UniformLocation location,
4470 GLsizei bufSize,
4471 const GLfloat *params)
4472 {
4473 return ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, nullptr);
4474 }
4475
ValidateGetnUniformfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLfloat * params)4476 bool ValidateGetnUniformfvRobustANGLE(const Context *context,
4477 angle::EntryPoint entryPoint,
4478 ShaderProgramID program,
4479 UniformLocation location,
4480 GLsizei bufSize,
4481 const GLsizei *length,
4482 const GLfloat *params)
4483 {
4484 UNIMPLEMENTED();
4485 return false;
4486 }
4487
ValidateGetnUniformivEXT(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLint * params)4488 bool ValidateGetnUniformivEXT(const Context *context,
4489 angle::EntryPoint entryPoint,
4490 ShaderProgramID program,
4491 UniformLocation location,
4492 GLsizei bufSize,
4493 const GLint *params)
4494 {
4495 return ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, nullptr);
4496 }
4497
ValidateGetnUniformivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLint * params)4498 bool ValidateGetnUniformivRobustANGLE(const Context *context,
4499 angle::EntryPoint entryPoint,
4500 ShaderProgramID program,
4501 UniformLocation location,
4502 GLsizei bufSize,
4503 const GLsizei *length,
4504 const GLint *params)
4505 {
4506 UNIMPLEMENTED();
4507 return false;
4508 }
4509
ValidateGetnUniformuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLuint * params)4510 bool ValidateGetnUniformuivRobustANGLE(const Context *context,
4511 angle::EntryPoint entryPoint,
4512 ShaderProgramID program,
4513 UniformLocation location,
4514 GLsizei bufSize,
4515 const GLsizei *length,
4516 const GLuint *params)
4517 {
4518 UNIMPLEMENTED();
4519 return false;
4520 }
4521
ValidateGetUniformfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLfloat * params)4522 bool ValidateGetUniformfvRobustANGLE(const Context *context,
4523 angle::EntryPoint entryPoint,
4524 ShaderProgramID program,
4525 UniformLocation location,
4526 GLsizei bufSize,
4527 const GLsizei *length,
4528 const GLfloat *params)
4529 {
4530 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
4531 {
4532 return false;
4533 }
4534
4535 GLsizei writeLength = 0;
4536
4537 // bufSize is validated in ValidateSizedGetUniform
4538 if (!ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, &writeLength))
4539 {
4540 return false;
4541 }
4542
4543 SetRobustLengthParam(length, writeLength);
4544
4545 return true;
4546 }
4547
ValidateGetUniformivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLint * params)4548 bool ValidateGetUniformivRobustANGLE(const Context *context,
4549 angle::EntryPoint entryPoint,
4550 ShaderProgramID program,
4551 UniformLocation location,
4552 GLsizei bufSize,
4553 const GLsizei *length,
4554 const GLint *params)
4555 {
4556 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
4557 {
4558 return false;
4559 }
4560
4561 GLsizei writeLength = 0;
4562
4563 // bufSize is validated in ValidateSizedGetUniform
4564 if (!ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, &writeLength))
4565 {
4566 return false;
4567 }
4568
4569 SetRobustLengthParam(length, writeLength);
4570
4571 return true;
4572 }
4573
ValidateGetUniformuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLuint * params)4574 bool ValidateGetUniformuivRobustANGLE(const Context *context,
4575 angle::EntryPoint entryPoint,
4576 ShaderProgramID program,
4577 UniformLocation location,
4578 GLsizei bufSize,
4579 const GLsizei *length,
4580 const GLuint *params)
4581 {
4582 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
4583 {
4584 return false;
4585 }
4586
4587 if (context->getClientMajorVersion() < 3)
4588 {
4589 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
4590 return false;
4591 }
4592
4593 GLsizei writeLength = 0;
4594
4595 // bufSize is validated in ValidateSizedGetUniform
4596 if (!ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, &writeLength))
4597 {
4598 return false;
4599 }
4600
4601 SetRobustLengthParam(length, writeLength);
4602
4603 return true;
4604 }
4605
ValidateDiscardFramebufferBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLsizei numAttachments,const GLenum * attachments,bool defaultFramebuffer)4606 bool ValidateDiscardFramebufferBase(const Context *context,
4607 angle::EntryPoint entryPoint,
4608 GLenum target,
4609 GLsizei numAttachments,
4610 const GLenum *attachments,
4611 bool defaultFramebuffer)
4612 {
4613 if (numAttachments < 0)
4614 {
4615 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeAttachments);
4616 return false;
4617 }
4618
4619 for (GLsizei i = 0; i < numAttachments; ++i)
4620 {
4621 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
4622 {
4623 if (defaultFramebuffer)
4624 {
4625 context->validationError(entryPoint, GL_INVALID_ENUM,
4626 kDefaultFramebufferInvalidAttachment);
4627 return false;
4628 }
4629
4630 if (attachments[i] >=
4631 GL_COLOR_ATTACHMENT0 + static_cast<GLuint>(context->getCaps().maxColorAttachments))
4632 {
4633 context->validationError(entryPoint, GL_INVALID_OPERATION,
4634 kExceedsMaxColorAttachments);
4635 return false;
4636 }
4637 }
4638 else
4639 {
4640 switch (attachments[i])
4641 {
4642 case GL_DEPTH_ATTACHMENT:
4643 case GL_STENCIL_ATTACHMENT:
4644 case GL_DEPTH_STENCIL_ATTACHMENT:
4645 if (defaultFramebuffer)
4646 {
4647 context->validationError(entryPoint, GL_INVALID_ENUM,
4648 kDefaultFramebufferInvalidAttachment);
4649 return false;
4650 }
4651 break;
4652 case GL_COLOR:
4653 case GL_DEPTH:
4654 case GL_STENCIL:
4655 if (!defaultFramebuffer)
4656 {
4657 context->validationError(entryPoint, GL_INVALID_ENUM,
4658 kDefaultFramebufferAttachmentOnUserFBO);
4659 return false;
4660 }
4661 break;
4662 default:
4663 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
4664 return false;
4665 }
4666 }
4667 }
4668
4669 return true;
4670 }
4671
ValidateInsertEventMarkerEXT(const Context * context,angle::EntryPoint entryPoint,GLsizei length,const char * marker)4672 bool ValidateInsertEventMarkerEXT(const Context *context,
4673 angle::EntryPoint entryPoint,
4674 GLsizei length,
4675 const char *marker)
4676 {
4677 if (!context->getExtensions().debugMarkerEXT)
4678 {
4679 // The debug marker calls should not set error state
4680 // However, it seems reasonable to set an error state if the extension is not enabled
4681 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4682 return false;
4683 }
4684
4685 // Note that debug marker calls must not set error state
4686 if (length < 0)
4687 {
4688 return false;
4689 }
4690
4691 if (marker == nullptr)
4692 {
4693 return false;
4694 }
4695
4696 return true;
4697 }
4698
ValidatePushGroupMarkerEXT(const Context * context,angle::EntryPoint entryPoint,GLsizei length,const char * marker)4699 bool ValidatePushGroupMarkerEXT(const Context *context,
4700 angle::EntryPoint entryPoint,
4701 GLsizei length,
4702 const char *marker)
4703 {
4704 if (!context->getExtensions().debugMarkerEXT)
4705 {
4706 // The debug marker calls should not set error state
4707 // However, it seems reasonable to set an error state if the extension is not enabled
4708 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4709 return false;
4710 }
4711
4712 // Note that debug marker calls must not set error state
4713 if (length < 0)
4714 {
4715 return false;
4716 }
4717
4718 if (length > 0 && marker == nullptr)
4719 {
4720 return false;
4721 }
4722
4723 return true;
4724 }
4725
ValidateEGLImageTargetTexture2DOES(const Context * context,angle::EntryPoint entryPoint,TextureType type,GLeglImageOES image)4726 bool ValidateEGLImageTargetTexture2DOES(const Context *context,
4727 angle::EntryPoint entryPoint,
4728 TextureType type,
4729 GLeglImageOES image)
4730 {
4731 if (!context->getExtensions().EGLImageOES && !context->getExtensions().EGLImageExternalOES)
4732 {
4733 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4734 return false;
4735 }
4736
4737 switch (type)
4738 {
4739 case TextureType::_2D:
4740 if (!context->getExtensions().EGLImageOES)
4741 {
4742 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
4743 }
4744 break;
4745
4746 case TextureType::_2DArray:
4747 if (!context->getExtensions().EGLImageArrayEXT)
4748 {
4749 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
4750 }
4751 break;
4752
4753 case TextureType::External:
4754 if (!context->getExtensions().EGLImageExternalOES)
4755 {
4756 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
4757 }
4758 break;
4759
4760 default:
4761 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
4762 return false;
4763 }
4764
4765 egl::Image *imageObject = static_cast<egl::Image *>(image);
4766
4767 ASSERT(context->getDisplay());
4768 if (!context->getDisplay()->isValidImage(imageObject))
4769 {
4770 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidEGLImage);
4771 return false;
4772 }
4773
4774 if (imageObject->getSamples() > 0)
4775 {
4776 context->validationError(entryPoint, GL_INVALID_OPERATION,
4777 kEGLImageCannotCreate2DMultisampled);
4778 return false;
4779 }
4780
4781 if (!imageObject->isTexturable(context))
4782 {
4783 context->validationError(entryPoint, GL_INVALID_OPERATION,
4784 kEGLImageTextureFormatNotSupported);
4785 return false;
4786 }
4787
4788 if (imageObject->isLayered() && type != TextureType::_2DArray)
4789 {
4790 context->validationError(entryPoint, GL_INVALID_OPERATION,
4791 "Image has more than 1 layer, target must be TEXTURE_2D_ARRAY");
4792 return false;
4793 }
4794
4795 if (imageObject->isYUV() && type != TextureType::External)
4796 {
4797 context->validationError(entryPoint, GL_INVALID_OPERATION,
4798 "Image is YUV, target must be TEXTURE_EXTERNAL_OES");
4799 return false;
4800 }
4801
4802 if (imageObject->hasProtectedContent() != context->getState().hasProtectedContent())
4803 {
4804 context->validationError(entryPoint, GL_INVALID_OPERATION,
4805 "Mismatch between Image and Context Protected Content state");
4806 return false;
4807 }
4808
4809 return true;
4810 }
4811
ValidateEGLImageTargetRenderbufferStorageOES(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLeglImageOES image)4812 bool ValidateEGLImageTargetRenderbufferStorageOES(const Context *context,
4813 angle::EntryPoint entryPoint,
4814 GLenum target,
4815 GLeglImageOES image)
4816 {
4817 if (!context->getExtensions().EGLImageOES)
4818 {
4819 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4820 return false;
4821 }
4822
4823 switch (target)
4824 {
4825 case GL_RENDERBUFFER:
4826 break;
4827
4828 default:
4829 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferTarget);
4830 return false;
4831 }
4832
4833 egl::Image *imageObject = static_cast<egl::Image *>(image);
4834
4835 ASSERT(context->getDisplay());
4836 if (!context->getDisplay()->isValidImage(imageObject))
4837 {
4838 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidEGLImage);
4839 return false;
4840 }
4841
4842 if (!imageObject->isRenderable(context))
4843 {
4844 context->validationError(entryPoint, GL_INVALID_OPERATION,
4845 kEGLImageRenderbufferFormatNotSupported);
4846 return false;
4847 }
4848
4849 if (imageObject->hasProtectedContent() != context->getState().hasProtectedContent())
4850 {
4851 context->validationError(entryPoint, GL_INVALID_OPERATION,
4852 "Mismatch between Image and Context Protected Content state");
4853 return false;
4854 }
4855
4856 return true;
4857 }
4858
ValidateProgramBinaryBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,GLenum binaryFormat,const void * binary,GLint length)4859 bool ValidateProgramBinaryBase(const Context *context,
4860 angle::EntryPoint entryPoint,
4861 ShaderProgramID program,
4862 GLenum binaryFormat,
4863 const void *binary,
4864 GLint length)
4865 {
4866 Program *programObject = GetValidProgram(context, entryPoint, program);
4867 if (programObject == nullptr)
4868 {
4869 return false;
4870 }
4871
4872 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
4873 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
4874 programBinaryFormats.end())
4875 {
4876 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidProgramBinaryFormat);
4877 return false;
4878 }
4879
4880 if (context->hasActiveTransformFeedback(program))
4881 {
4882 // ES 3.0.4 section 2.15 page 91
4883 context->validationError(entryPoint, GL_INVALID_OPERATION, kTransformFeedbackProgramBinary);
4884 return false;
4885 }
4886
4887 return true;
4888 }
4889
ValidateGetProgramBinaryBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,GLsizei bufSize,const GLsizei * length,const GLenum * binaryFormat,const void * binary)4890 bool ValidateGetProgramBinaryBase(const Context *context,
4891 angle::EntryPoint entryPoint,
4892 ShaderProgramID program,
4893 GLsizei bufSize,
4894 const GLsizei *length,
4895 const GLenum *binaryFormat,
4896 const void *binary)
4897 {
4898 Program *programObject = GetValidProgram(context, entryPoint, program);
4899 if (programObject == nullptr)
4900 {
4901 return false;
4902 }
4903
4904 if (!programObject->isLinked())
4905 {
4906 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
4907 return false;
4908 }
4909
4910 if (context->getCaps().programBinaryFormats.empty())
4911 {
4912 context->validationError(entryPoint, GL_INVALID_OPERATION, kNoProgramBinaryFormats);
4913 return false;
4914 }
4915
4916 return true;
4917 }
4918
ValidateDrawBuffersBase(const Context * context,angle::EntryPoint entryPoint,GLsizei n,const GLenum * bufs)4919 bool ValidateDrawBuffersBase(const Context *context,
4920 angle::EntryPoint entryPoint,
4921 GLsizei n,
4922 const GLenum *bufs)
4923 {
4924 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
4925 if (n < 0)
4926 {
4927 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeCount);
4928 return false;
4929 }
4930 if (n > context->getCaps().maxDrawBuffers)
4931 {
4932 context->validationError(entryPoint, GL_INVALID_VALUE, kIndexExceedsMaxDrawBuffer);
4933 return false;
4934 }
4935
4936 ASSERT(context->getState().getDrawFramebuffer());
4937 FramebufferID frameBufferId = context->getState().getDrawFramebuffer()->id();
4938 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
4939
4940 // This should come first before the check for the default frame buffer
4941 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
4942 // rather than INVALID_OPERATION
4943 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
4944 {
4945 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
4946
4947 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
4948 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
4949 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
4950 {
4951 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
4952 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
4953 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
4954 // 3.1 is still a bit ambiguous about the error, but future specs are
4955 // expected to clarify that GL_INVALID_ENUM is the correct error.
4956 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidDrawBuffer);
4957 return false;
4958 }
4959 else if (bufs[colorAttachment] >= maxColorAttachment)
4960 {
4961 context->validationError(entryPoint, GL_INVALID_OPERATION, kExceedsMaxColorAttachments);
4962 return false;
4963 }
4964 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
4965 frameBufferId.value != 0)
4966 {
4967 // INVALID_OPERATION-GL is bound to buffer and ith argument
4968 // is not COLOR_ATTACHMENTi or NONE
4969 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidDrawBufferValue);
4970 return false;
4971 }
4972 }
4973
4974 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
4975 // and n is not 1 or bufs is bound to value other than BACK and NONE
4976 if (frameBufferId.value == 0)
4977 {
4978 if (n != 1)
4979 {
4980 context->validationError(entryPoint, GL_INVALID_OPERATION,
4981 kInvalidDrawBufferCountForDefault);
4982 return false;
4983 }
4984
4985 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
4986 {
4987 context->validationError(entryPoint, GL_INVALID_OPERATION,
4988 kDefaultFramebufferInvalidDrawBuffer);
4989 return false;
4990 }
4991 }
4992
4993 return true;
4994 }
4995
ValidateGetBufferPointervBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLenum pname,GLsizei * length,void * const * params)4996 bool ValidateGetBufferPointervBase(const Context *context,
4997 angle::EntryPoint entryPoint,
4998 BufferBinding target,
4999 GLenum pname,
5000 GLsizei *length,
5001 void *const *params)
5002 {
5003 if (length)
5004 {
5005 *length = 0;
5006 }
5007
5008 if (!context->isValidBufferBinding(target))
5009 {
5010 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
5011 return false;
5012 }
5013
5014 switch (pname)
5015 {
5016 case GL_BUFFER_MAP_POINTER:
5017 break;
5018
5019 default:
5020 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5021 return false;
5022 }
5023
5024 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
5025 // target bound to zero generate an INVALID_OPERATION error."
5026 // GLES 3.1 section 6.6 explicitly specifies this error.
5027 if (context->getState().getTargetBuffer(target) == nullptr)
5028 {
5029 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferPointerNotAvailable);
5030 return false;
5031 }
5032
5033 if (length)
5034 {
5035 *length = 1;
5036 }
5037
5038 return true;
5039 }
5040
ValidateUnmapBufferBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target)5041 bool ValidateUnmapBufferBase(const Context *context,
5042 angle::EntryPoint entryPoint,
5043 BufferBinding target)
5044 {
5045 if (!context->isValidBufferBinding(target))
5046 {
5047 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
5048 return false;
5049 }
5050
5051 Buffer *buffer = context->getState().getTargetBuffer(target);
5052
5053 if (buffer == nullptr || !buffer->isMapped())
5054 {
5055 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferNotMapped);
5056 return false;
5057 }
5058
5059 return true;
5060 }
5061
ValidateMapBufferRangeBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLintptr offset,GLsizeiptr length,GLbitfield access)5062 bool ValidateMapBufferRangeBase(const Context *context,
5063 angle::EntryPoint entryPoint,
5064 BufferBinding target,
5065 GLintptr offset,
5066 GLsizeiptr length,
5067 GLbitfield access)
5068 {
5069 if (!context->isValidBufferBinding(target))
5070 {
5071 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
5072 return false;
5073 }
5074
5075 if (offset < 0)
5076 {
5077 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeOffset);
5078 return false;
5079 }
5080
5081 if (length < 0)
5082 {
5083 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeLength);
5084 return false;
5085 }
5086
5087 Buffer *buffer = context->getState().getTargetBuffer(target);
5088
5089 if (!buffer)
5090 {
5091 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferNotMappable);
5092 return false;
5093 }
5094
5095 // Check for buffer overflow
5096 CheckedNumeric<size_t> checkedOffset(offset);
5097 auto checkedSize = checkedOffset + length;
5098
5099 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
5100 {
5101 context->validationError(entryPoint, GL_INVALID_VALUE, kMapOutOfRange);
5102 return false;
5103 }
5104
5105 // Check for invalid bits in the mask
5106 constexpr GLbitfield kAllAccessBits =
5107 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
5108 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
5109
5110 if (buffer->isImmutable())
5111 {
5112 // GL_EXT_buffer_storage's additions to glMapBufferRange
5113 constexpr GLbitfield kBufferStorageAccessBits =
5114 kAllAccessBits | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT;
5115
5116 if ((access & ~kBufferStorageAccessBits) != 0)
5117 {
5118 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidAccessBits);
5119 return false;
5120 }
5121
5122 // It is invalid if any of bufferStorageMatchedAccessBits bits are included in access,
5123 // but the same bits are not included in the buffer's storage flags
5124 constexpr GLbitfield kBufferStorageMatchedAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT |
5125 GL_MAP_PERSISTENT_BIT_EXT |
5126 GL_MAP_COHERENT_BIT_EXT;
5127 GLbitfield accessFlags = access & kBufferStorageMatchedAccessBits;
5128 if ((accessFlags & buffer->getStorageExtUsageFlags()) != accessFlags)
5129 {
5130 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAccessBits);
5131 return false;
5132 }
5133 }
5134 else if ((access & ~kAllAccessBits) != 0)
5135 {
5136 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidAccessBits);
5137 return false;
5138 }
5139
5140 if (length == 0)
5141 {
5142 context->validationError(entryPoint, GL_INVALID_OPERATION, kLengthZero);
5143 return false;
5144 }
5145
5146 if (buffer->isMapped())
5147 {
5148 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferAlreadyMapped);
5149 return false;
5150 }
5151
5152 // Check for invalid bit combinations
5153 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
5154 {
5155 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAccessBitsReadWrite);
5156 return false;
5157 }
5158
5159 GLbitfield writeOnlyBits =
5160 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
5161
5162 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
5163 {
5164 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAccessBitsRead);
5165 return false;
5166 }
5167
5168 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
5169 {
5170 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAccessBitsFlush);
5171 return false;
5172 }
5173
5174 return ValidateMapBufferBase(context, entryPoint, target);
5175 }
5176
ValidateFlushMappedBufferRangeBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLintptr offset,GLsizeiptr length)5177 bool ValidateFlushMappedBufferRangeBase(const Context *context,
5178 angle::EntryPoint entryPoint,
5179 BufferBinding target,
5180 GLintptr offset,
5181 GLsizeiptr length)
5182 {
5183 if (offset < 0)
5184 {
5185 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeOffset);
5186 return false;
5187 }
5188
5189 if (length < 0)
5190 {
5191 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeLength);
5192 return false;
5193 }
5194
5195 if (!context->isValidBufferBinding(target))
5196 {
5197 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
5198 return false;
5199 }
5200
5201 Buffer *buffer = context->getState().getTargetBuffer(target);
5202
5203 if (buffer == nullptr)
5204 {
5205 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFlushZero);
5206 return false;
5207 }
5208
5209 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
5210 {
5211 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFlushTarget);
5212 return false;
5213 }
5214
5215 // Check for buffer overflow
5216 CheckedNumeric<size_t> checkedOffset(offset);
5217 auto checkedSize = checkedOffset + length;
5218
5219 if (!checkedSize.IsValid() ||
5220 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
5221 {
5222 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidFlushOutOfRange);
5223 return false;
5224 }
5225
5226 return true;
5227 }
5228
ValidateGenOrDelete(const Context * context,angle::EntryPoint entryPoint,GLint n)5229 bool ValidateGenOrDelete(const Context *context, angle::EntryPoint entryPoint, GLint n)
5230 {
5231 if (n < 0)
5232 {
5233 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeCount);
5234 return false;
5235 }
5236 return true;
5237 }
5238
ValidateRobustEntryPoint(const Context * context,angle::EntryPoint entryPoint,GLsizei bufSize)5239 bool ValidateRobustEntryPoint(const Context *context, angle::EntryPoint entryPoint, GLsizei bufSize)
5240 {
5241 if (!context->getExtensions().robustClientMemoryANGLE)
5242 {
5243 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
5244 return false;
5245 }
5246
5247 if (bufSize < 0)
5248 {
5249 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeBufferSize);
5250 return false;
5251 }
5252
5253 return true;
5254 }
5255
ValidateRobustBufferSize(const Context * context,angle::EntryPoint entryPoint,GLsizei bufSize,GLsizei numParams)5256 bool ValidateRobustBufferSize(const Context *context,
5257 angle::EntryPoint entryPoint,
5258 GLsizei bufSize,
5259 GLsizei numParams)
5260 {
5261 if (bufSize < numParams)
5262 {
5263 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientParams);
5264 return false;
5265 }
5266
5267 return true;
5268 }
5269
ValidateGetFramebufferAttachmentParameterivBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum attachment,GLenum pname,GLsizei * numParams)5270 bool ValidateGetFramebufferAttachmentParameterivBase(const Context *context,
5271 angle::EntryPoint entryPoint,
5272 GLenum target,
5273 GLenum attachment,
5274 GLenum pname,
5275 GLsizei *numParams)
5276 {
5277 if (!ValidFramebufferTarget(context, target))
5278 {
5279 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFramebufferTarget);
5280 return false;
5281 }
5282
5283 int clientVersion = context->getClientMajorVersion();
5284
5285 switch (pname)
5286 {
5287 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5288 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5289 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5290 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5291 break;
5292
5293 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR:
5294 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR:
5295 if (clientVersion < 3 ||
5296 !(context->getExtensions().multiviewOVR || context->getExtensions().multiview2OVR))
5297 {
5298 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5299 return false;
5300 }
5301 break;
5302
5303 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT:
5304 if (!context->getExtensions().multisampledRenderToTextureEXT)
5305 {
5306 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5307 return false;
5308 }
5309 break;
5310
5311 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
5312 if (clientVersion < 3 && !context->getExtensions().sRGBEXT)
5313 {
5314 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5315 return false;
5316 }
5317 break;
5318
5319 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
5320 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
5321 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
5322 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
5323 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
5324 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
5325 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5326 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5327 if (clientVersion < 3)
5328 {
5329 context->validationError(entryPoint, GL_INVALID_ENUM, kES3Required);
5330 return false;
5331 }
5332 break;
5333
5334 case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT:
5335 if (!context->getExtensions().geometryShaderAny() &&
5336 context->getClientVersion() < ES_3_2)
5337 {
5338 context->validationError(entryPoint, GL_INVALID_ENUM,
5339 kGeometryShaderExtensionNotEnabled);
5340 return false;
5341 }
5342 break;
5343
5344 default:
5345 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
5346 return false;
5347 }
5348
5349 // Determine if the attachment is a valid enum
5350 switch (attachment)
5351 {
5352 case GL_BACK:
5353 case GL_DEPTH:
5354 case GL_STENCIL:
5355 if (clientVersion < 3)
5356 {
5357 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
5358 return false;
5359 }
5360 break;
5361
5362 case GL_DEPTH_STENCIL_ATTACHMENT:
5363 if (clientVersion < 3 && !context->isWebGL1())
5364 {
5365 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
5366 return false;
5367 }
5368 break;
5369
5370 case GL_COLOR_ATTACHMENT0:
5371 case GL_DEPTH_ATTACHMENT:
5372 case GL_STENCIL_ATTACHMENT:
5373 break;
5374
5375 default:
5376 if ((clientVersion < 3 && !context->getExtensions().drawBuffersEXT) ||
5377 attachment < GL_COLOR_ATTACHMENT0_EXT ||
5378 (attachment - GL_COLOR_ATTACHMENT0_EXT) >=
5379 static_cast<GLuint>(context->getCaps().maxColorAttachments))
5380 {
5381 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
5382 return false;
5383 }
5384 break;
5385 }
5386
5387 const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
5388 ASSERT(framebuffer);
5389
5390 if (framebuffer->isDefault())
5391 {
5392 if (clientVersion < 3)
5393 {
5394 context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultFramebufferTarget);
5395 return false;
5396 }
5397
5398 switch (attachment)
5399 {
5400 case GL_BACK:
5401 case GL_DEPTH:
5402 case GL_STENCIL:
5403 break;
5404
5405 default:
5406 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAttachment);
5407 return false;
5408 }
5409 }
5410 else
5411 {
5412 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
5413 {
5414 // Valid attachment query
5415 }
5416 else
5417 {
5418 switch (attachment)
5419 {
5420 case GL_DEPTH_ATTACHMENT:
5421 case GL_STENCIL_ATTACHMENT:
5422 break;
5423
5424 case GL_DEPTH_STENCIL_ATTACHMENT:
5425 if (!framebuffer->hasValidDepthStencil() && !context->isWebGL1())
5426 {
5427 context->validationError(entryPoint, GL_INVALID_OPERATION,
5428 kInvalidAttachment);
5429 return false;
5430 }
5431 break;
5432
5433 default:
5434 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAttachment);
5435 return false;
5436 }
5437 }
5438 }
5439
5440 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(context, attachment);
5441 if (attachmentObject)
5442 {
5443 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
5444 attachmentObject->type() == GL_TEXTURE ||
5445 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
5446
5447 switch (pname)
5448 {
5449 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5450 if (attachmentObject->type() != GL_RENDERBUFFER &&
5451 attachmentObject->type() != GL_TEXTURE)
5452 {
5453 context->validationError(entryPoint, GL_INVALID_ENUM,
5454 kFramebufferIncompleteAttachment);
5455 return false;
5456 }
5457 break;
5458
5459 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5460 if (attachmentObject->type() != GL_TEXTURE)
5461 {
5462 context->validationError(entryPoint, GL_INVALID_ENUM,
5463 kFramebufferIncompleteAttachment);
5464 return false;
5465 }
5466 break;
5467
5468 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5469 if (attachmentObject->type() != GL_TEXTURE)
5470 {
5471 context->validationError(entryPoint, GL_INVALID_ENUM,
5472 kFramebufferIncompleteAttachment);
5473 return false;
5474 }
5475 break;
5476
5477 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5478 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
5479 {
5480 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAttachment);
5481 return false;
5482 }
5483 break;
5484
5485 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5486 if (attachmentObject->type() != GL_TEXTURE)
5487 {
5488 context->validationError(entryPoint, GL_INVALID_ENUM,
5489 kFramebufferIncompleteAttachment);
5490 return false;
5491 }
5492 break;
5493
5494 default:
5495 break;
5496 }
5497 }
5498 else
5499 {
5500 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
5501 // is NONE, then querying any other pname will generate INVALID_ENUM.
5502
5503 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
5504 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
5505 // INVALID_OPERATION for all other pnames
5506
5507 switch (pname)
5508 {
5509 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5510 break;
5511
5512 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5513 if (clientVersion < 3)
5514 {
5515 context->validationError(entryPoint, GL_INVALID_ENUM,
5516 kInvalidFramebufferAttachmentParameter);
5517 return false;
5518 }
5519 break;
5520
5521 default:
5522 if (clientVersion < 3)
5523 {
5524 context->validationError(entryPoint, GL_INVALID_ENUM,
5525 kInvalidFramebufferAttachmentParameter);
5526 return false;
5527 }
5528 else
5529 {
5530 context->validationError(entryPoint, GL_INVALID_OPERATION,
5531 kInvalidFramebufferAttachmentParameter);
5532 return false;
5533 }
5534 }
5535 }
5536
5537 if (numParams)
5538 {
5539 *numParams = 1;
5540 }
5541
5542 return true;
5543 }
5544
ValidateGetFramebufferAttachmentParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum attachment,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5545 bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(const Context *context,
5546 angle::EntryPoint entryPoint,
5547 GLenum target,
5548 GLenum attachment,
5549 GLenum pname,
5550 GLsizei bufSize,
5551 const GLsizei *length,
5552 const GLint *params)
5553 {
5554 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5555 {
5556 return false;
5557 }
5558
5559 GLsizei numParams = 0;
5560 if (!ValidateGetFramebufferAttachmentParameterivBase(context, entryPoint, target, attachment,
5561 pname, &numParams))
5562 {
5563 return false;
5564 }
5565
5566 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5567 {
5568 return false;
5569 }
5570
5571 SetRobustLengthParam(length, numParams);
5572
5573 return true;
5574 }
5575
ValidateGetBufferParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5576 bool ValidateGetBufferParameterivRobustANGLE(const Context *context,
5577 angle::EntryPoint entryPoint,
5578 BufferBinding target,
5579 GLenum pname,
5580 GLsizei bufSize,
5581 const GLsizei *length,
5582 const GLint *params)
5583 {
5584 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5585 {
5586 return false;
5587 }
5588
5589 GLsizei numParams = 0;
5590
5591 if (!ValidateGetBufferParameterBase(context, entryPoint, target, pname, false, &numParams))
5592 {
5593 return false;
5594 }
5595
5596 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5597 {
5598 return false;
5599 }
5600
5601 SetRobustLengthParam(length, numParams);
5602 return true;
5603 }
5604
ValidateGetBufferParameteri64vRobustANGLE(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint64 * params)5605 bool ValidateGetBufferParameteri64vRobustANGLE(const Context *context,
5606 angle::EntryPoint entryPoint,
5607 BufferBinding target,
5608 GLenum pname,
5609 GLsizei bufSize,
5610 const GLsizei *length,
5611 const GLint64 *params)
5612 {
5613 GLsizei numParams = 0;
5614
5615 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5616 {
5617 return false;
5618 }
5619
5620 if (!ValidateGetBufferParameterBase(context, entryPoint, target, pname, false, &numParams))
5621 {
5622 return false;
5623 }
5624
5625 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5626 {
5627 return false;
5628 }
5629
5630 SetRobustLengthParam(length, numParams);
5631
5632 return true;
5633 }
5634
ValidateGetProgramivBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,GLenum pname,GLsizei * numParams)5635 bool ValidateGetProgramivBase(const Context *context,
5636 angle::EntryPoint entryPoint,
5637 ShaderProgramID program,
5638 GLenum pname,
5639 GLsizei *numParams)
5640 {
5641 // Currently, all GetProgramiv queries return 1 parameter
5642 if (numParams)
5643 {
5644 *numParams = 1;
5645 }
5646
5647 if (context->isContextLost())
5648 {
5649 context->validationError(entryPoint, GL_CONTEXT_LOST, kContextLost);
5650
5651 if (context->getExtensions().parallelShaderCompileKHR && pname == GL_COMPLETION_STATUS_KHR)
5652 {
5653 // Generate an error but still return true, the context still needs to return a
5654 // value in this case.
5655 return true;
5656 }
5657 else
5658 {
5659 return false;
5660 }
5661 }
5662
5663 // Special case for GL_COMPLETION_STATUS_KHR: don't resolve the link. Otherwise resolve it now.
5664 Program *programObject = (pname == GL_COMPLETION_STATUS_KHR)
5665 ? GetValidProgramNoResolve(context, entryPoint, program)
5666 : GetValidProgram(context, entryPoint, program);
5667 if (!programObject)
5668 {
5669 return false;
5670 }
5671
5672 switch (pname)
5673 {
5674 case GL_DELETE_STATUS:
5675 case GL_LINK_STATUS:
5676 case GL_VALIDATE_STATUS:
5677 case GL_INFO_LOG_LENGTH:
5678 case GL_ATTACHED_SHADERS:
5679 case GL_ACTIVE_ATTRIBUTES:
5680 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
5681 case GL_ACTIVE_UNIFORMS:
5682 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
5683 break;
5684
5685 case GL_PROGRAM_BINARY_LENGTH:
5686 if (context->getClientMajorVersion() < 3 &&
5687 !context->getExtensions().getProgramBinaryOES)
5688 {
5689 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5690 return false;
5691 }
5692 break;
5693
5694 case GL_ACTIVE_UNIFORM_BLOCKS:
5695 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
5696 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
5697 case GL_TRANSFORM_FEEDBACK_VARYINGS:
5698 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
5699 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
5700 if (context->getClientMajorVersion() < 3)
5701 {
5702 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES30);
5703 return false;
5704 }
5705 break;
5706
5707 case GL_PROGRAM_SEPARABLE:
5708 case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS:
5709 if (context->getClientVersion() < Version(3, 1))
5710 {
5711 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
5712 return false;
5713 }
5714 break;
5715
5716 case GL_COMPUTE_WORK_GROUP_SIZE:
5717 if (context->getClientVersion() < Version(3, 1))
5718 {
5719 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
5720 return false;
5721 }
5722
5723 // [OpenGL ES 3.1] Chapter 7.12 Page 122
5724 // An INVALID_OPERATION error is generated if COMPUTE_WORK_GROUP_SIZE is queried for a
5725 // program which has not been linked successfully, or which does not contain objects to
5726 // form a compute shader.
5727 if (!programObject->isLinked())
5728 {
5729 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
5730 return false;
5731 }
5732 if (!programObject->getExecutable().hasLinkedShaderStage(ShaderType::Compute))
5733 {
5734 context->validationError(entryPoint, GL_INVALID_OPERATION,
5735 kNoActiveComputeShaderStage);
5736 return false;
5737 }
5738 break;
5739
5740 case GL_GEOMETRY_LINKED_INPUT_TYPE_EXT:
5741 case GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT:
5742 case GL_GEOMETRY_LINKED_VERTICES_OUT_EXT:
5743 case GL_GEOMETRY_SHADER_INVOCATIONS_EXT:
5744 if (!context->getExtensions().geometryShaderAny() &&
5745 context->getClientVersion() < ES_3_2)
5746 {
5747 context->validationError(entryPoint, GL_INVALID_ENUM,
5748 kGeometryShaderExtensionNotEnabled);
5749 return false;
5750 }
5751
5752 // [EXT_geometry_shader] Chapter 7.12
5753 // An INVALID_OPERATION error is generated if GEOMETRY_LINKED_VERTICES_OUT_EXT,
5754 // GEOMETRY_LINKED_INPUT_TYPE_EXT, GEOMETRY_LINKED_OUTPUT_TYPE_EXT, or
5755 // GEOMETRY_SHADER_INVOCATIONS_EXT are queried for a program which has not been linked
5756 // successfully, or which does not contain objects to form a geometry shader.
5757 if (!programObject->isLinked())
5758 {
5759 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
5760 return false;
5761 }
5762 if (!programObject->getExecutable().hasLinkedShaderStage(ShaderType::Geometry))
5763 {
5764 context->validationError(entryPoint, GL_INVALID_OPERATION,
5765 kNoActiveGeometryShaderStage);
5766 return false;
5767 }
5768 break;
5769
5770 case GL_COMPLETION_STATUS_KHR:
5771 if (!context->getExtensions().parallelShaderCompileKHR)
5772 {
5773 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
5774 return false;
5775 }
5776 break;
5777 case GL_TESS_CONTROL_OUTPUT_VERTICES_EXT:
5778 case GL_TESS_GEN_MODE_EXT:
5779 case GL_TESS_GEN_SPACING_EXT:
5780 case GL_TESS_GEN_VERTEX_ORDER_EXT:
5781 case GL_TESS_GEN_POINT_MODE_EXT:
5782 if (!context->getExtensions().tessellationShaderEXT &&
5783 context->getClientVersion() < ES_3_2)
5784 {
5785 context->validationError(entryPoint, GL_INVALID_ENUM,
5786 kTessellationShaderExtensionNotEnabled);
5787 return false;
5788 }
5789 if (!programObject->isLinked())
5790 {
5791 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
5792 return false;
5793 }
5794 break;
5795 default:
5796 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5797 return false;
5798 }
5799
5800 return true;
5801 }
5802
ValidateGetProgramivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5803 bool ValidateGetProgramivRobustANGLE(const Context *context,
5804 angle::EntryPoint entryPoint,
5805 ShaderProgramID program,
5806 GLenum pname,
5807 GLsizei bufSize,
5808 const GLsizei *length,
5809 const GLint *params)
5810 {
5811 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5812 {
5813 return false;
5814 }
5815
5816 GLsizei numParams = 0;
5817
5818 if (!ValidateGetProgramivBase(context, entryPoint, program, pname, &numParams))
5819 {
5820 return false;
5821 }
5822
5823 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5824 {
5825 return false;
5826 }
5827
5828 SetRobustLengthParam(length, numParams);
5829
5830 return true;
5831 }
5832
ValidateGetRenderbufferParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5833 bool ValidateGetRenderbufferParameterivRobustANGLE(const Context *context,
5834 angle::EntryPoint entryPoint,
5835 GLenum target,
5836 GLenum pname,
5837 GLsizei bufSize,
5838 const GLsizei *length,
5839 const GLint *params)
5840 {
5841 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5842 {
5843 return false;
5844 }
5845
5846 GLsizei numParams = 0;
5847
5848 if (!ValidateGetRenderbufferParameterivBase(context, entryPoint, target, pname, &numParams))
5849 {
5850 return false;
5851 }
5852
5853 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5854 {
5855 return false;
5856 }
5857
5858 SetRobustLengthParam(length, numParams);
5859
5860 return true;
5861 }
5862
ValidateGetShaderivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID shader,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5863 bool ValidateGetShaderivRobustANGLE(const Context *context,
5864 angle::EntryPoint entryPoint,
5865 ShaderProgramID shader,
5866 GLenum pname,
5867 GLsizei bufSize,
5868 const GLsizei *length,
5869 const GLint *params)
5870 {
5871 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5872 {
5873 return false;
5874 }
5875
5876 GLsizei numParams = 0;
5877
5878 if (!ValidateGetShaderivBase(context, entryPoint, shader, pname, &numParams))
5879 {
5880 return false;
5881 }
5882
5883 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5884 {
5885 return false;
5886 }
5887
5888 SetRobustLengthParam(length, numParams);
5889
5890 return true;
5891 }
5892
ValidateGetTexParameterfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLfloat * params)5893 bool ValidateGetTexParameterfvRobustANGLE(const Context *context,
5894 angle::EntryPoint entryPoint,
5895 TextureType target,
5896 GLenum pname,
5897 GLsizei bufSize,
5898 const GLsizei *length,
5899 const GLfloat *params)
5900 {
5901 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5902 {
5903 return false;
5904 }
5905
5906 GLsizei numParams = 0;
5907
5908 if (!ValidateGetTexParameterBase(context, entryPoint, target, pname, &numParams))
5909 {
5910 return false;
5911 }
5912
5913 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5914 {
5915 return false;
5916 }
5917
5918 SetRobustLengthParam(length, numParams);
5919
5920 return true;
5921 }
5922
ValidateGetTexParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5923 bool ValidateGetTexParameterivRobustANGLE(const Context *context,
5924 angle::EntryPoint entryPoint,
5925 TextureType target,
5926 GLenum pname,
5927 GLsizei bufSize,
5928 const GLsizei *length,
5929 const GLint *params)
5930 {
5931
5932 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5933 {
5934 return false;
5935 }
5936 GLsizei numParams = 0;
5937 if (!ValidateGetTexParameterBase(context, entryPoint, target, pname, &numParams))
5938 {
5939 return false;
5940 }
5941
5942 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5943 {
5944 return false;
5945 }
5946
5947 SetRobustLengthParam(length, numParams);
5948 return true;
5949 }
5950
ValidateGetTexParameterIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5951 bool ValidateGetTexParameterIivRobustANGLE(const Context *context,
5952 angle::EntryPoint entryPoint,
5953 TextureType target,
5954 GLenum pname,
5955 GLsizei bufSize,
5956 const GLsizei *length,
5957 const GLint *params)
5958 {
5959 UNIMPLEMENTED();
5960 return false;
5961 }
5962
ValidateGetTexParameterIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLuint * params)5963 bool ValidateGetTexParameterIuivRobustANGLE(const Context *context,
5964 angle::EntryPoint entryPoint,
5965 TextureType target,
5966 GLenum pname,
5967 GLsizei bufSize,
5968 const GLsizei *length,
5969 const GLuint *params)
5970 {
5971 UNIMPLEMENTED();
5972 return false;
5973 }
5974
ValidateTexParameterfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLfloat * params)5975 bool ValidateTexParameterfvRobustANGLE(const Context *context,
5976 angle::EntryPoint entryPoint,
5977 TextureType target,
5978 GLenum pname,
5979 GLsizei bufSize,
5980 const GLfloat *params)
5981 {
5982 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5983 {
5984 return false;
5985 }
5986
5987 return ValidateTexParameterBase(context, entryPoint, target, pname, bufSize, true, params);
5988 }
5989
ValidateTexParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLint * params)5990 bool ValidateTexParameterivRobustANGLE(const Context *context,
5991 angle::EntryPoint entryPoint,
5992 TextureType target,
5993 GLenum pname,
5994 GLsizei bufSize,
5995 const GLint *params)
5996 {
5997 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5998 {
5999 return false;
6000 }
6001
6002 return ValidateTexParameterBase(context, entryPoint, target, pname, bufSize, true, params);
6003 }
6004
ValidateTexParameterIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLint * params)6005 bool ValidateTexParameterIivRobustANGLE(const Context *context,
6006 angle::EntryPoint entryPoint,
6007 TextureType target,
6008 GLenum pname,
6009 GLsizei bufSize,
6010 const GLint *params)
6011 {
6012 UNIMPLEMENTED();
6013 return false;
6014 }
6015
ValidateTexParameterIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLuint * params)6016 bool ValidateTexParameterIuivRobustANGLE(const Context *context,
6017 angle::EntryPoint entryPoint,
6018 TextureType target,
6019 GLenum pname,
6020 GLsizei bufSize,
6021 const GLuint *params)
6022 {
6023 UNIMPLEMENTED();
6024 return false;
6025 }
6026
ValidateGetSamplerParameterfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLfloat * params)6027 bool ValidateGetSamplerParameterfvRobustANGLE(const Context *context,
6028 angle::EntryPoint entryPoint,
6029 SamplerID sampler,
6030 GLenum pname,
6031 GLsizei bufSize,
6032 const GLsizei *length,
6033 const GLfloat *params)
6034 {
6035 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6036 {
6037 return false;
6038 }
6039
6040 GLsizei numParams = 0;
6041
6042 if (!ValidateGetSamplerParameterBase(context, entryPoint, sampler, pname, &numParams))
6043 {
6044 return false;
6045 }
6046
6047 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
6048 {
6049 return false;
6050 }
6051
6052 SetRobustLengthParam(length, numParams);
6053 return true;
6054 }
6055
ValidateGetSamplerParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6056 bool ValidateGetSamplerParameterivRobustANGLE(const Context *context,
6057 angle::EntryPoint entryPoint,
6058 SamplerID sampler,
6059 GLenum pname,
6060 GLsizei bufSize,
6061 const GLsizei *length,
6062 const GLint *params)
6063 {
6064 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6065 {
6066 return false;
6067 }
6068
6069 GLsizei numParams = 0;
6070
6071 if (!ValidateGetSamplerParameterBase(context, entryPoint, sampler, pname, &numParams))
6072 {
6073 return false;
6074 }
6075
6076 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
6077 {
6078 return false;
6079 }
6080
6081 SetRobustLengthParam(length, numParams);
6082 return true;
6083 }
6084
ValidateGetSamplerParameterIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6085 bool ValidateGetSamplerParameterIivRobustANGLE(const Context *context,
6086 angle::EntryPoint entryPoint,
6087 SamplerID sampler,
6088 GLenum pname,
6089 GLsizei bufSize,
6090 const GLsizei *length,
6091 const GLint *params)
6092 {
6093 UNIMPLEMENTED();
6094 return false;
6095 }
6096
ValidateGetSamplerParameterIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLuint * params)6097 bool ValidateGetSamplerParameterIuivRobustANGLE(const Context *context,
6098 angle::EntryPoint entryPoint,
6099 SamplerID sampler,
6100 GLenum pname,
6101 GLsizei bufSize,
6102 const GLsizei *length,
6103 const GLuint *params)
6104 {
6105 UNIMPLEMENTED();
6106 return false;
6107 }
6108
ValidateSamplerParameterfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLfloat * params)6109 bool ValidateSamplerParameterfvRobustANGLE(const Context *context,
6110 angle::EntryPoint entryPoint,
6111 SamplerID sampler,
6112 GLenum pname,
6113 GLsizei bufSize,
6114 const GLfloat *params)
6115 {
6116 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6117 {
6118 return false;
6119 }
6120
6121 return ValidateSamplerParameterBase(context, entryPoint, sampler, pname, bufSize, true, params);
6122 }
6123
ValidateSamplerParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLint * params)6124 bool ValidateSamplerParameterivRobustANGLE(const Context *context,
6125 angle::EntryPoint entryPoint,
6126 SamplerID sampler,
6127 GLenum pname,
6128 GLsizei bufSize,
6129 const GLint *params)
6130 {
6131 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6132 {
6133 return false;
6134 }
6135
6136 return ValidateSamplerParameterBase(context, entryPoint, sampler, pname, bufSize, true, params);
6137 }
6138
ValidateSamplerParameterIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLint * param)6139 bool ValidateSamplerParameterIivRobustANGLE(const Context *context,
6140 angle::EntryPoint entryPoint,
6141 SamplerID sampler,
6142 GLenum pname,
6143 GLsizei bufSize,
6144 const GLint *param)
6145 {
6146 UNIMPLEMENTED();
6147 return false;
6148 }
6149
ValidateSamplerParameterIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLuint * param)6150 bool ValidateSamplerParameterIuivRobustANGLE(const Context *context,
6151 angle::EntryPoint entryPoint,
6152 SamplerID sampler,
6153 GLenum pname,
6154 GLsizei bufSize,
6155 const GLuint *param)
6156 {
6157 UNIMPLEMENTED();
6158 return false;
6159 }
6160
ValidateGetVertexAttribfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLfloat * params)6161 bool ValidateGetVertexAttribfvRobustANGLE(const Context *context,
6162 angle::EntryPoint entryPoint,
6163 GLuint index,
6164 GLenum pname,
6165 GLsizei bufSize,
6166 const GLsizei *length,
6167 const GLfloat *params)
6168 {
6169 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6170 {
6171 return false;
6172 }
6173
6174 GLsizei writeLength = 0;
6175
6176 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, false, false))
6177 {
6178 return false;
6179 }
6180
6181 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6182 {
6183 return false;
6184 }
6185
6186 SetRobustLengthParam(length, writeLength);
6187 return true;
6188 }
6189
ValidateGetVertexAttribivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6190 bool ValidateGetVertexAttribivRobustANGLE(const Context *context,
6191 angle::EntryPoint entryPoint,
6192 GLuint index,
6193 GLenum pname,
6194 GLsizei bufSize,
6195 const GLsizei *length,
6196 const GLint *params)
6197 {
6198 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6199 {
6200 return false;
6201 }
6202
6203 GLsizei writeLength = 0;
6204
6205 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, false, false))
6206 {
6207 return false;
6208 }
6209
6210 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6211 {
6212 return false;
6213 }
6214
6215 SetRobustLengthParam(length, writeLength);
6216
6217 return true;
6218 }
6219
ValidateGetVertexAttribPointervRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,void * const * pointer)6220 bool ValidateGetVertexAttribPointervRobustANGLE(const Context *context,
6221 angle::EntryPoint entryPoint,
6222 GLuint index,
6223 GLenum pname,
6224 GLsizei bufSize,
6225 const GLsizei *length,
6226 void *const *pointer)
6227 {
6228 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6229 {
6230 return false;
6231 }
6232
6233 GLsizei writeLength = 0;
6234
6235 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, true, false))
6236 {
6237 return false;
6238 }
6239
6240 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6241 {
6242 return false;
6243 }
6244
6245 SetRobustLengthParam(length, writeLength);
6246
6247 return true;
6248 }
6249
ValidateGetVertexAttribIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6250 bool ValidateGetVertexAttribIivRobustANGLE(const Context *context,
6251 angle::EntryPoint entryPoint,
6252 GLuint index,
6253 GLenum pname,
6254 GLsizei bufSize,
6255 const GLsizei *length,
6256 const GLint *params)
6257 {
6258 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6259 {
6260 return false;
6261 }
6262
6263 GLsizei writeLength = 0;
6264
6265 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, false, true))
6266 {
6267 return false;
6268 }
6269
6270 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6271 {
6272 return false;
6273 }
6274
6275 SetRobustLengthParam(length, writeLength);
6276
6277 return true;
6278 }
6279
ValidateGetVertexAttribIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLuint * params)6280 bool ValidateGetVertexAttribIuivRobustANGLE(const Context *context,
6281 angle::EntryPoint entryPoint,
6282 GLuint index,
6283 GLenum pname,
6284 GLsizei bufSize,
6285 const GLsizei *length,
6286 const GLuint *params)
6287 {
6288 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6289 {
6290 return false;
6291 }
6292
6293 GLsizei writeLength = 0;
6294
6295 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, false, true))
6296 {
6297 return false;
6298 }
6299
6300 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6301 {
6302 return false;
6303 }
6304
6305 SetRobustLengthParam(length, writeLength);
6306
6307 return true;
6308 }
6309
ValidateGetActiveUniformBlockivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformBlockIndex uniformBlockIndex,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6310 bool ValidateGetActiveUniformBlockivRobustANGLE(const Context *context,
6311 angle::EntryPoint entryPoint,
6312 ShaderProgramID program,
6313 UniformBlockIndex uniformBlockIndex,
6314 GLenum pname,
6315 GLsizei bufSize,
6316 const GLsizei *length,
6317 const GLint *params)
6318 {
6319 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6320 {
6321 return false;
6322 }
6323
6324 GLsizei writeLength = 0;
6325
6326 if (!ValidateGetActiveUniformBlockivBase(context, entryPoint, program, uniformBlockIndex, pname,
6327 &writeLength))
6328 {
6329 return false;
6330 }
6331
6332 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6333 {
6334 return false;
6335 }
6336
6337 SetRobustLengthParam(length, writeLength);
6338
6339 return true;
6340 }
6341
ValidateGetInternalformativRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum internalformat,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6342 bool ValidateGetInternalformativRobustANGLE(const Context *context,
6343 angle::EntryPoint entryPoint,
6344 GLenum target,
6345 GLenum internalformat,
6346 GLenum pname,
6347 GLsizei bufSize,
6348 const GLsizei *length,
6349 const GLint *params)
6350 {
6351 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6352 {
6353 return false;
6354 }
6355
6356 GLsizei numParams = 0;
6357
6358 if (!ValidateGetInternalFormativBase(context, entryPoint, target, internalformat, pname,
6359 bufSize, &numParams))
6360 {
6361 return false;
6362 }
6363
6364 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
6365 {
6366 return false;
6367 }
6368
6369 SetRobustLengthParam(length, numParams);
6370
6371 return true;
6372 }
6373
6374 // Perform validation from WebGL 2 section 5.10 "Invalid Clears":
6375 // In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
6376 // specified clear value and the type of a buffer that is being cleared generates an
6377 // INVALID_OPERATION error instead of producing undefined results
ValidateWebGLFramebufferAttachmentClearType(const Context * context,angle::EntryPoint entryPoint,GLint drawbuffer,const GLenum * validComponentTypes,size_t validComponentTypeCount)6378 bool ValidateWebGLFramebufferAttachmentClearType(const Context *context,
6379 angle::EntryPoint entryPoint,
6380 GLint drawbuffer,
6381 const GLenum *validComponentTypes,
6382 size_t validComponentTypeCount)
6383 {
6384 const FramebufferAttachment *attachment =
6385 context->getState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
6386 if (attachment)
6387 {
6388 GLenum componentType = attachment->getFormat().info->componentType;
6389 const GLenum *end = validComponentTypes + validComponentTypeCount;
6390 if (std::find(validComponentTypes, end, componentType) == end)
6391 {
6392 context->validationError(entryPoint, GL_INVALID_OPERATION, kNoDefinedClearConversion);
6393 return false;
6394 }
6395 }
6396
6397 return true;
6398 }
6399
ValidateRobustCompressedTexImageBase(const Context * context,angle::EntryPoint entryPoint,GLsizei imageSize,GLsizei dataSize)6400 bool ValidateRobustCompressedTexImageBase(const Context *context,
6401 angle::EntryPoint entryPoint,
6402 GLsizei imageSize,
6403 GLsizei dataSize)
6404 {
6405 if (!ValidateRobustEntryPoint(context, entryPoint, dataSize))
6406 {
6407 return false;
6408 }
6409
6410 Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
6411 if (pixelUnpackBuffer == nullptr)
6412 {
6413 if (dataSize < imageSize)
6414 {
6415 context->validationError(entryPoint, GL_INVALID_OPERATION, kCompressedDataSizeTooSmall);
6416 }
6417 }
6418 return true;
6419 }
6420
ValidateGetBufferParameterBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLenum pname,bool pointerVersion,GLsizei * numParams)6421 bool ValidateGetBufferParameterBase(const Context *context,
6422 angle::EntryPoint entryPoint,
6423 BufferBinding target,
6424 GLenum pname,
6425 bool pointerVersion,
6426 GLsizei *numParams)
6427 {
6428 if (numParams)
6429 {
6430 *numParams = 0;
6431 }
6432
6433 if (!context->isValidBufferBinding(target))
6434 {
6435 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
6436 return false;
6437 }
6438
6439 const Buffer *buffer = context->getState().getTargetBuffer(target);
6440 if (!buffer)
6441 {
6442 // A null buffer means that "0" is bound to the requested buffer target
6443 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferNotBound);
6444 return false;
6445 }
6446
6447 const Extensions &extensions = context->getExtensions();
6448
6449 switch (pname)
6450 {
6451 case GL_BUFFER_USAGE:
6452 case GL_BUFFER_SIZE:
6453 break;
6454
6455 case GL_BUFFER_ACCESS_OES:
6456 if (!extensions.mapbufferOES)
6457 {
6458 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6459 return false;
6460 }
6461 break;
6462
6463 case GL_BUFFER_MAPPED:
6464 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
6465 if (context->getClientMajorVersion() < 3 && !extensions.mapbufferOES &&
6466 !extensions.mapBufferRangeEXT)
6467 {
6468 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6469 return false;
6470 }
6471 break;
6472
6473 case GL_BUFFER_MAP_POINTER:
6474 if (!pointerVersion)
6475 {
6476 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidMapPointerQuery);
6477 return false;
6478 }
6479 break;
6480
6481 case GL_BUFFER_ACCESS_FLAGS:
6482 case GL_BUFFER_MAP_OFFSET:
6483 case GL_BUFFER_MAP_LENGTH:
6484 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRangeEXT)
6485 {
6486 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6487 return false;
6488 }
6489 break;
6490
6491 case GL_MEMORY_SIZE_ANGLE:
6492 if (!context->getExtensions().memorySizeANGLE)
6493 {
6494 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6495 return false;
6496 }
6497 break;
6498
6499 case GL_RESOURCE_INITIALIZED_ANGLE:
6500 if (!context->getExtensions().robustResourceInitializationANGLE)
6501 {
6502 context->validationError(entryPoint, GL_INVALID_ENUM,
6503 kRobustResourceInitializationExtensionRequired);
6504 return false;
6505 }
6506 break;
6507
6508 default:
6509 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6510 return false;
6511 }
6512
6513 // All buffer parameter queries return one value.
6514 if (numParams)
6515 {
6516 *numParams = 1;
6517 }
6518
6519 return true;
6520 }
6521
ValidateGetRenderbufferParameterivBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum pname,GLsizei * length)6522 bool ValidateGetRenderbufferParameterivBase(const Context *context,
6523 angle::EntryPoint entryPoint,
6524 GLenum target,
6525 GLenum pname,
6526 GLsizei *length)
6527 {
6528 if (length)
6529 {
6530 *length = 0;
6531 }
6532
6533 if (target != GL_RENDERBUFFER)
6534 {
6535 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferTarget);
6536 return false;
6537 }
6538
6539 Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer();
6540 if (renderbuffer == nullptr)
6541 {
6542 context->validationError(entryPoint, GL_INVALID_OPERATION, kRenderbufferNotBound);
6543 return false;
6544 }
6545
6546 switch (pname)
6547 {
6548 case GL_RENDERBUFFER_WIDTH:
6549 case GL_RENDERBUFFER_HEIGHT:
6550 case GL_RENDERBUFFER_INTERNAL_FORMAT:
6551 case GL_RENDERBUFFER_RED_SIZE:
6552 case GL_RENDERBUFFER_GREEN_SIZE:
6553 case GL_RENDERBUFFER_BLUE_SIZE:
6554 case GL_RENDERBUFFER_ALPHA_SIZE:
6555 case GL_RENDERBUFFER_DEPTH_SIZE:
6556 case GL_RENDERBUFFER_STENCIL_SIZE:
6557 break;
6558
6559 case GL_RENDERBUFFER_SAMPLES_ANGLE:
6560 if (!context->getExtensions().framebufferMultisampleANGLE)
6561 {
6562 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6563 return false;
6564 }
6565 break;
6566
6567 case GL_MEMORY_SIZE_ANGLE:
6568 if (!context->getExtensions().memorySizeANGLE)
6569 {
6570 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6571 return false;
6572 }
6573 break;
6574
6575 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
6576 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
6577 if (!context->getExtensions().getImageANGLE)
6578 {
6579 context->validationError(entryPoint, GL_INVALID_ENUM, kGetImageExtensionNotEnabled);
6580 return false;
6581 }
6582 break;
6583
6584 case GL_RESOURCE_INITIALIZED_ANGLE:
6585 if (!context->getExtensions().robustResourceInitializationANGLE)
6586 {
6587 context->validationError(entryPoint, GL_INVALID_ENUM,
6588 kRobustResourceInitializationExtensionRequired);
6589 return false;
6590 }
6591 break;
6592
6593 default:
6594 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6595 return false;
6596 }
6597
6598 if (length)
6599 {
6600 *length = 1;
6601 }
6602 return true;
6603 }
6604
ValidateGetShaderivBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID shader,GLenum pname,GLsizei * length)6605 bool ValidateGetShaderivBase(const Context *context,
6606 angle::EntryPoint entryPoint,
6607 ShaderProgramID shader,
6608 GLenum pname,
6609 GLsizei *length)
6610 {
6611 if (length)
6612 {
6613 *length = 0;
6614 }
6615
6616 if (context->isContextLost())
6617 {
6618 context->validationError(entryPoint, GL_CONTEXT_LOST, kContextLost);
6619
6620 if (context->getExtensions().parallelShaderCompileKHR && pname == GL_COMPLETION_STATUS_KHR)
6621 {
6622 // Generate an error but still return true, the context still needs to return a
6623 // value in this case.
6624 return true;
6625 }
6626 else
6627 {
6628 return false;
6629 }
6630 }
6631
6632 if (GetValidShader(context, entryPoint, shader) == nullptr)
6633 {
6634 return false;
6635 }
6636
6637 switch (pname)
6638 {
6639 case GL_SHADER_TYPE:
6640 case GL_DELETE_STATUS:
6641 case GL_COMPILE_STATUS:
6642 case GL_INFO_LOG_LENGTH:
6643 case GL_SHADER_SOURCE_LENGTH:
6644 break;
6645
6646 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
6647 if (!context->getExtensions().translatedShaderSourceANGLE)
6648 {
6649 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6650 return false;
6651 }
6652 break;
6653
6654 case GL_COMPLETION_STATUS_KHR:
6655 if (!context->getExtensions().parallelShaderCompileKHR)
6656 {
6657 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
6658 return false;
6659 }
6660 break;
6661
6662 default:
6663 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6664 return false;
6665 }
6666
6667 if (length)
6668 {
6669 *length = 1;
6670 }
6671 return true;
6672 }
6673
ValidateGetTexParameterBase(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei * length)6674 bool ValidateGetTexParameterBase(const Context *context,
6675 angle::EntryPoint entryPoint,
6676 TextureType target,
6677 GLenum pname,
6678 GLsizei *length)
6679 {
6680 if (length)
6681 {
6682 *length = 0;
6683 }
6684
6685 if ((!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) ||
6686 target == TextureType::Buffer)
6687 {
6688 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
6689 return false;
6690 }
6691
6692 if (context->getTextureByType(target) == nullptr)
6693 {
6694 // Should only be possible for external textures
6695 context->validationError(entryPoint, GL_INVALID_ENUM, kTextureNotBound);
6696 return false;
6697 }
6698
6699 if (context->getClientMajorVersion() == 1 && !IsValidGLES1TextureParameter(pname))
6700 {
6701 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6702 return false;
6703 }
6704
6705 switch (pname)
6706 {
6707 case GL_TEXTURE_MAG_FILTER:
6708 case GL_TEXTURE_MIN_FILTER:
6709 case GL_TEXTURE_WRAP_S:
6710 case GL_TEXTURE_WRAP_T:
6711 break;
6712
6713 case GL_TEXTURE_USAGE_ANGLE:
6714 if (!context->getExtensions().textureUsageANGLE)
6715 {
6716 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6717 return false;
6718 }
6719 break;
6720
6721 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
6722 if (!ValidateTextureMaxAnisotropyExtensionEnabled(context, entryPoint))
6723 {
6724 return false;
6725 }
6726 break;
6727
6728 case GL_TEXTURE_IMMUTABLE_FORMAT:
6729 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorageEXT)
6730 {
6731 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6732 return false;
6733 }
6734 break;
6735
6736 case GL_TEXTURE_WRAP_R:
6737 case GL_TEXTURE_IMMUTABLE_LEVELS:
6738 case GL_TEXTURE_SWIZZLE_R:
6739 case GL_TEXTURE_SWIZZLE_G:
6740 case GL_TEXTURE_SWIZZLE_B:
6741 case GL_TEXTURE_SWIZZLE_A:
6742 case GL_TEXTURE_BASE_LEVEL:
6743 case GL_TEXTURE_MAX_LEVEL:
6744 case GL_TEXTURE_MIN_LOD:
6745 case GL_TEXTURE_MAX_LOD:
6746 if (context->getClientMajorVersion() < 3)
6747 {
6748 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES30);
6749 return false;
6750 }
6751 break;
6752
6753 case GL_TEXTURE_COMPARE_MODE:
6754 case GL_TEXTURE_COMPARE_FUNC:
6755 if (context->getClientMajorVersion() < 3 && !context->getExtensions().shadowSamplersEXT)
6756 {
6757 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6758 return false;
6759 }
6760 break;
6761
6762 case GL_TEXTURE_SRGB_DECODE_EXT:
6763 if (!context->getExtensions().textureSRGBDecodeEXT)
6764 {
6765 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6766 return false;
6767 }
6768 break;
6769
6770 case GL_DEPTH_STENCIL_TEXTURE_MODE:
6771 case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE:
6772 if (context->getClientVersion() < ES_3_1)
6773 {
6774 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
6775 return false;
6776 }
6777 break;
6778
6779 case GL_GENERATE_MIPMAP:
6780 case GL_TEXTURE_CROP_RECT_OES:
6781 // TODO(lfy@google.com): Restrict to GL_OES_draw_texture
6782 // after GL_OES_draw_texture functionality implemented
6783 if (context->getClientMajorVersion() > 1)
6784 {
6785 context->validationError(entryPoint, GL_INVALID_ENUM, kGLES1Only);
6786 return false;
6787 }
6788 break;
6789
6790 case GL_MEMORY_SIZE_ANGLE:
6791 if (!context->getExtensions().memorySizeANGLE)
6792 {
6793 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6794 return false;
6795 }
6796 break;
6797
6798 case GL_TEXTURE_BORDER_COLOR:
6799 if (!context->getExtensions().textureBorderClampOES &&
6800 context->getClientVersion() < ES_3_2)
6801 {
6802 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6803 return false;
6804 }
6805 break;
6806
6807 case GL_TEXTURE_NATIVE_ID_ANGLE:
6808 if (!context->getExtensions().textureExternalUpdateANGLE)
6809 {
6810 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6811 return false;
6812 }
6813 break;
6814
6815 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
6816 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
6817 if (!context->getExtensions().getImageANGLE)
6818 {
6819 context->validationError(entryPoint, GL_INVALID_ENUM, kGetImageExtensionNotEnabled);
6820 return false;
6821 }
6822 break;
6823
6824 case GL_RESOURCE_INITIALIZED_ANGLE:
6825 if (!context->getExtensions().robustResourceInitializationANGLE)
6826 {
6827 context->validationError(entryPoint, GL_INVALID_ENUM,
6828 kRobustResourceInitializationExtensionRequired);
6829 return false;
6830 }
6831 break;
6832
6833 case GL_TEXTURE_PROTECTED_EXT:
6834 if (!context->getExtensions().protectedTexturesEXT)
6835 {
6836 context->validationError(entryPoint, GL_INVALID_ENUM,
6837 kProtectedTexturesExtensionRequired);
6838 return false;
6839 }
6840 break;
6841
6842 default:
6843 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6844 return false;
6845 }
6846
6847 if (length)
6848 {
6849 *length = GetTexParameterCount(pname);
6850 }
6851 return true;
6852 }
6853
ValidateGetVertexAttribBase(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei * length,bool pointer,bool pureIntegerEntryPoint)6854 bool ValidateGetVertexAttribBase(const Context *context,
6855 angle::EntryPoint entryPoint,
6856 GLuint index,
6857 GLenum pname,
6858 GLsizei *length,
6859 bool pointer,
6860 bool pureIntegerEntryPoint)
6861 {
6862 if (length)
6863 {
6864 *length = 0;
6865 }
6866
6867 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
6868 {
6869 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
6870 return false;
6871 }
6872
6873 if (index >= static_cast<GLuint>(context->getCaps().maxVertexAttributes))
6874 {
6875 context->validationError(entryPoint, GL_INVALID_VALUE, kIndexExceedsMaxVertexAttribute);
6876 return false;
6877 }
6878
6879 if (pointer)
6880 {
6881 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
6882 {
6883 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6884 return false;
6885 }
6886 }
6887 else
6888 {
6889 switch (pname)
6890 {
6891 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
6892 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
6893 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
6894 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
6895 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
6896 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
6897 case GL_CURRENT_VERTEX_ATTRIB:
6898 break;
6899
6900 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
6901 static_assert(
6902 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
6903 "ANGLE extension enums not equal to GL enums.");
6904 if (context->getClientMajorVersion() < 3 &&
6905 !context->getExtensions().instancedArraysAny())
6906 {
6907 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6908 return false;
6909 }
6910 break;
6911
6912 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
6913 if (context->getClientMajorVersion() < 3)
6914 {
6915 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6916 return false;
6917 }
6918 break;
6919
6920 case GL_VERTEX_ATTRIB_BINDING:
6921 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
6922 if (context->getClientVersion() < ES_3_1)
6923 {
6924 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
6925 return false;
6926 }
6927 break;
6928
6929 default:
6930 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6931 return false;
6932 }
6933 }
6934
6935 if (length)
6936 {
6937 if (pname == GL_CURRENT_VERTEX_ATTRIB)
6938 {
6939 *length = 4;
6940 }
6941 else
6942 {
6943 *length = 1;
6944 }
6945 }
6946
6947 return true;
6948 }
6949
ValidatePixelPack(const Context * context,angle::EntryPoint entryPoint,GLenum format,GLenum type,GLint x,GLint y,GLsizei width,GLsizei height,GLsizei bufSize,GLsizei * length,const void * pixels)6950 bool ValidatePixelPack(const Context *context,
6951 angle::EntryPoint entryPoint,
6952 GLenum format,
6953 GLenum type,
6954 GLint x,
6955 GLint y,
6956 GLsizei width,
6957 GLsizei height,
6958 GLsizei bufSize,
6959 GLsizei *length,
6960 const void *pixels)
6961 {
6962 // Check for pixel pack buffer related API errors
6963 Buffer *pixelPackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelPack);
6964 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
6965 {
6966 // ...the buffer object's data store is currently mapped.
6967 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferMapped);
6968 return false;
6969 }
6970 if (pixelPackBuffer != nullptr &&
6971 pixelPackBuffer->hasWebGLXFBBindingConflict(context->isWebGL()))
6972 {
6973 context->validationError(entryPoint, GL_INVALID_OPERATION,
6974 kPixelPackBufferBoundForTransformFeedback);
6975 return false;
6976 }
6977
6978 // .. the data would be packed to the buffer object such that the memory writes required
6979 // would exceed the data store size.
6980 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
6981 const Extents size(width, height, 1);
6982 const auto &pack = context->getState().getPackState();
6983
6984 GLuint endByte = 0;
6985 if (!formatInfo.computePackUnpackEndByte(type, size, pack, false, &endByte))
6986 {
6987 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
6988 return false;
6989 }
6990
6991 if (bufSize >= 0)
6992 {
6993 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
6994 {
6995 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
6996 return false;
6997 }
6998 }
6999
7000 if (pixelPackBuffer != nullptr)
7001 {
7002 CheckedNumeric<size_t> checkedEndByte(endByte);
7003 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
7004 checkedEndByte += checkedOffset;
7005
7006 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
7007 {
7008 // Overflow past the end of the buffer
7009 context->validationError(entryPoint, GL_INVALID_OPERATION, kParamOverflow);
7010 return false;
7011 }
7012 }
7013
7014 if (pixelPackBuffer == nullptr && length != nullptr)
7015 {
7016 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
7017 {
7018 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
7019 return false;
7020 }
7021
7022 *length = static_cast<GLsizei>(endByte);
7023 }
7024
7025 if (context->isWebGL())
7026 {
7027 // WebGL 2.0 disallows the scenario:
7028 // GL_PACK_SKIP_PIXELS + width > DataStoreWidth
7029 // where:
7030 // DataStoreWidth = (GL_PACK_ROW_LENGTH ? GL_PACK_ROW_LENGTH : width)
7031 // Since these two pack parameters can only be set to non-zero values
7032 // on WebGL 2.0 contexts, verify them for all WebGL contexts.
7033 GLint dataStoreWidth = pack.rowLength ? pack.rowLength : width;
7034 if (pack.skipPixels + width > dataStoreWidth)
7035 {
7036 context->validationError(entryPoint, GL_INVALID_OPERATION,
7037 kInvalidPackParametersForWebGL);
7038 return false;
7039 }
7040 }
7041
7042 return true;
7043 }
7044
ValidateReadPixelsBase(const Context * context,angle::EntryPoint entryPoint,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,GLsizei * length,GLsizei * columns,GLsizei * rows,const void * pixels)7045 bool ValidateReadPixelsBase(const Context *context,
7046 angle::EntryPoint entryPoint,
7047 GLint x,
7048 GLint y,
7049 GLsizei width,
7050 GLsizei height,
7051 GLenum format,
7052 GLenum type,
7053 GLsizei bufSize,
7054 GLsizei *length,
7055 GLsizei *columns,
7056 GLsizei *rows,
7057 const void *pixels)
7058 {
7059 if (length != nullptr)
7060 {
7061 *length = 0;
7062 }
7063 if (rows != nullptr)
7064 {
7065 *rows = 0;
7066 }
7067 if (columns != nullptr)
7068 {
7069 *columns = 0;
7070 }
7071
7072 if (width < 0 || height < 0)
7073 {
7074 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeSize);
7075 return false;
7076 }
7077
7078 Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
7079 ASSERT(readFramebuffer);
7080
7081 if (!ValidateFramebufferComplete(context, entryPoint, readFramebuffer))
7082 {
7083 return false;
7084 }
7085
7086 // needIntrinsic = true. Treat renderToTexture textures as single sample since they will be
7087 // resolved before reading.
7088 if (!readFramebuffer->isDefault() &&
7089 !ValidateFramebufferNotMultisampled(context, entryPoint, readFramebuffer, true))
7090 {
7091 return false;
7092 }
7093
7094 if (readFramebuffer->getReadBufferState() == GL_NONE)
7095 {
7096 context->validationError(entryPoint, GL_INVALID_OPERATION, kReadBufferNone);
7097 return false;
7098 }
7099
7100 const FramebufferAttachment *readBuffer = nullptr;
7101 switch (format)
7102 {
7103 case GL_DEPTH_COMPONENT:
7104 readBuffer = readFramebuffer->getDepthAttachment();
7105 break;
7106 case GL_STENCIL_INDEX_OES:
7107 readBuffer = readFramebuffer->getStencilOrDepthStencilAttachment();
7108 break;
7109 default:
7110 readBuffer = readFramebuffer->getReadColorAttachment();
7111 break;
7112 }
7113
7114 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
7115 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
7116 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
7117 // situation is an application error that would lead to a crash in ANGLE.
7118 if (readBuffer == nullptr)
7119 {
7120 context->validationError(entryPoint, GL_INVALID_OPERATION, kMissingReadAttachment);
7121 return false;
7122 }
7123
7124 // OVR_multiview2, Revision 1:
7125 // ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if
7126 // the number of views in the current read framebuffer is more than one.
7127 if (readFramebuffer->readDisallowedByMultiview())
7128 {
7129 context->validationError(entryPoint, GL_INVALID_FRAMEBUFFER_OPERATION,
7130 kMultiviewReadFramebuffer);
7131 return false;
7132 }
7133
7134 if (context->isWebGL())
7135 {
7136 // The ES 2.0 spec states that the format must be "among those defined in table 3.4,
7137 // excluding formats LUMINANCE and LUMINANCE_ALPHA.". This requires validating the format
7138 // and type before validating the combination of format and type. However, the
7139 // dEQP-GLES3.functional.negative_api.buffer.read_pixels passes GL_LUMINANCE as a format and
7140 // verifies that GL_INVALID_OPERATION is generated.
7141 // TODO(geofflang): Update this check to be done in all/no cases once this is resolved in
7142 // dEQP/WebGL.
7143 if (!ValidReadPixelsFormatEnum(context, format))
7144 {
7145 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
7146 return false;
7147 }
7148
7149 if (!ValidReadPixelsTypeEnum(context, type))
7150 {
7151 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidType);
7152 return false;
7153 }
7154 }
7155
7156 GLenum currentFormat = GL_NONE;
7157 GLenum currentType = GL_NONE;
7158
7159 switch (format)
7160 {
7161 case GL_DEPTH_COMPONENT:
7162 case GL_STENCIL_INDEX_OES:
7163 // Only rely on ValidReadPixelsFormatType for depth/stencil formats
7164 break;
7165 default:
7166 currentFormat = readFramebuffer->getImplementationColorReadFormat(context);
7167 currentType = readFramebuffer->getImplementationColorReadType(context);
7168 break;
7169 }
7170
7171 bool validFormatTypeCombination =
7172 ValidReadPixelsFormatType(context, readBuffer->getFormat().info, format, type);
7173
7174 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
7175 {
7176 context->validationError(entryPoint, GL_INVALID_OPERATION, kMismatchedTypeAndFormat);
7177 return false;
7178 }
7179
7180 if (!ValidatePixelPack(context, entryPoint, format, type, x, y, width, height, bufSize, length,
7181 pixels))
7182 {
7183 return false;
7184 }
7185
7186 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize, GLsizei *outExtent) {
7187 angle::CheckedNumeric<int> clippedExtent(length);
7188 if (start < 0)
7189 {
7190 // "subtract" the area that is less than 0
7191 clippedExtent += start;
7192 }
7193
7194 angle::CheckedNumeric<int> readExtent = start;
7195 readExtent += length;
7196 if (!readExtent.IsValid())
7197 {
7198 return false;
7199 }
7200
7201 if (readExtent.ValueOrDie() > bufferSize)
7202 {
7203 // Subtract the region to the right of the read buffer
7204 clippedExtent -= (readExtent - bufferSize);
7205 }
7206
7207 if (!clippedExtent.IsValid())
7208 {
7209 return false;
7210 }
7211
7212 *outExtent = std::max<int>(clippedExtent.ValueOrDie(), 0);
7213 return true;
7214 };
7215
7216 GLsizei writtenColumns = 0;
7217 if (!getClippedExtent(x, width, readBuffer->getSize().width, &writtenColumns))
7218 {
7219 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
7220 return false;
7221 }
7222
7223 GLsizei writtenRows = 0;
7224 if (!getClippedExtent(y, height, readBuffer->getSize().height, &writtenRows))
7225 {
7226 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
7227 return false;
7228 }
7229
7230 if (columns != nullptr)
7231 {
7232 *columns = writtenColumns;
7233 }
7234
7235 if (rows != nullptr)
7236 {
7237 *rows = writtenRows;
7238 }
7239
7240 return true;
7241 }
7242
7243 template <typename ParamType>
ValidateTexParameterBase(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,bool vectorParams,const ParamType * params)7244 bool ValidateTexParameterBase(const Context *context,
7245 angle::EntryPoint entryPoint,
7246 TextureType target,
7247 GLenum pname,
7248 GLsizei bufSize,
7249 bool vectorParams,
7250 const ParamType *params)
7251 {
7252 if ((!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) ||
7253 target == TextureType::Buffer)
7254 {
7255 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
7256 return false;
7257 }
7258
7259 if (context->getTextureByType(target) == nullptr)
7260 {
7261 // Should only be possible for external textures
7262 context->validationError(entryPoint, GL_INVALID_ENUM, kTextureNotBound);
7263 return false;
7264 }
7265
7266 const GLsizei minBufSize = GetTexParameterCount(pname);
7267 if (bufSize >= 0 && bufSize < minBufSize)
7268 {
7269 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
7270 return false;
7271 }
7272
7273 if (context->getClientMajorVersion() == 1 && !IsValidGLES1TextureParameter(pname))
7274 {
7275 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7276 return false;
7277 }
7278
7279 switch (pname)
7280 {
7281 case GL_TEXTURE_WRAP_R:
7282 case GL_TEXTURE_SWIZZLE_R:
7283 case GL_TEXTURE_SWIZZLE_G:
7284 case GL_TEXTURE_SWIZZLE_B:
7285 case GL_TEXTURE_SWIZZLE_A:
7286 case GL_TEXTURE_BASE_LEVEL:
7287 case GL_TEXTURE_MAX_LEVEL:
7288 case GL_TEXTURE_COMPARE_MODE:
7289 case GL_TEXTURE_COMPARE_FUNC:
7290 case GL_TEXTURE_MIN_LOD:
7291 case GL_TEXTURE_MAX_LOD:
7292 if (context->getClientMajorVersion() < 3 &&
7293 !(pname == GL_TEXTURE_WRAP_R && context->getExtensions().texture3DOES))
7294 {
7295 context->validationError(entryPoint, GL_INVALID_ENUM, kES3Required);
7296 return false;
7297 }
7298 if (target == TextureType::External &&
7299 !context->getExtensions().EGLImageExternalEssl3OES)
7300 {
7301 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7302 return false;
7303 }
7304 if (target == TextureType::VideoImage && !context->getExtensions().videoTextureWEBGL)
7305 {
7306 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7307 }
7308 break;
7309
7310 case GL_GENERATE_MIPMAP:
7311 case GL_TEXTURE_CROP_RECT_OES:
7312 if (context->getClientMajorVersion() > 1)
7313 {
7314 context->validationError(entryPoint, GL_INVALID_ENUM, kGLES1Only);
7315 return false;
7316 }
7317 break;
7318
7319 default:
7320 break;
7321 }
7322
7323 if (target == TextureType::_2DMultisample || target == TextureType::_2DMultisampleArray)
7324 {
7325 switch (pname)
7326 {
7327 case GL_TEXTURE_MIN_FILTER:
7328 case GL_TEXTURE_MAG_FILTER:
7329 case GL_TEXTURE_WRAP_S:
7330 case GL_TEXTURE_WRAP_T:
7331 case GL_TEXTURE_WRAP_R:
7332 case GL_TEXTURE_MIN_LOD:
7333 case GL_TEXTURE_MAX_LOD:
7334 case GL_TEXTURE_COMPARE_MODE:
7335 case GL_TEXTURE_COMPARE_FUNC:
7336 case GL_TEXTURE_BORDER_COLOR:
7337 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
7338 return false;
7339 }
7340 }
7341
7342 switch (pname)
7343 {
7344 case GL_TEXTURE_WRAP_S:
7345 case GL_TEXTURE_WRAP_T:
7346 case GL_TEXTURE_WRAP_R:
7347 {
7348 bool restrictedWrapModes = ((target == TextureType::External &&
7349 !context->getExtensions().EGLImageExternalWrapModesEXT) ||
7350 target == TextureType::Rectangle);
7351 if (!ValidateTextureWrapModeValue(context, entryPoint, params, restrictedWrapModes))
7352 {
7353 return false;
7354 }
7355 }
7356 break;
7357
7358 case GL_TEXTURE_MIN_FILTER:
7359 {
7360 bool restrictedMinFilter =
7361 target == TextureType::External || target == TextureType::Rectangle;
7362 if (!ValidateTextureMinFilterValue(context, entryPoint, params, restrictedMinFilter))
7363 {
7364 return false;
7365 }
7366 }
7367 break;
7368
7369 case GL_TEXTURE_MAG_FILTER:
7370 if (!ValidateTextureMagFilterValue(context, entryPoint, params))
7371 {
7372 return false;
7373 }
7374 break;
7375
7376 case GL_TEXTURE_USAGE_ANGLE:
7377 if (!context->getExtensions().textureUsageANGLE)
7378 {
7379 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7380 return false;
7381 }
7382
7383 switch (ConvertToGLenum(params[0]))
7384 {
7385 case GL_NONE:
7386 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
7387 break;
7388
7389 default:
7390 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7391 return false;
7392 }
7393 break;
7394
7395 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
7396 {
7397 GLfloat paramValue = static_cast<GLfloat>(params[0]);
7398 if (!ValidateTextureMaxAnisotropyValue(context, entryPoint, paramValue))
7399 {
7400 return false;
7401 }
7402 ASSERT(static_cast<ParamType>(paramValue) == params[0]);
7403 }
7404 break;
7405
7406 case GL_TEXTURE_MIN_LOD:
7407 case GL_TEXTURE_MAX_LOD:
7408 // any value is permissible
7409 break;
7410
7411 case GL_TEXTURE_COMPARE_MODE:
7412 if (!ValidateTextureCompareModeValue(context, entryPoint, params))
7413 {
7414 return false;
7415 }
7416 break;
7417
7418 case GL_TEXTURE_COMPARE_FUNC:
7419 if (!ValidateTextureCompareFuncValue(context, entryPoint, params))
7420 {
7421 return false;
7422 }
7423 break;
7424
7425 case GL_TEXTURE_SWIZZLE_R:
7426 case GL_TEXTURE_SWIZZLE_G:
7427 case GL_TEXTURE_SWIZZLE_B:
7428 case GL_TEXTURE_SWIZZLE_A:
7429 switch (ConvertToGLenum(params[0]))
7430 {
7431 case GL_RED:
7432 case GL_GREEN:
7433 case GL_BLUE:
7434 case GL_ALPHA:
7435 case GL_ZERO:
7436 case GL_ONE:
7437 break;
7438
7439 default:
7440 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7441 return false;
7442 }
7443 break;
7444
7445 case GL_TEXTURE_BASE_LEVEL:
7446 if (ConvertToGLint(params[0]) < 0)
7447 {
7448 context->validationError(entryPoint, GL_INVALID_VALUE, kBaseLevelNegative);
7449 return false;
7450 }
7451 if (target == TextureType::External && static_cast<GLuint>(params[0]) != 0)
7452 {
7453 context->validationError(entryPoint, GL_INVALID_OPERATION, kBaseLevelNonZero);
7454 return false;
7455 }
7456 if ((target == TextureType::_2DMultisample ||
7457 target == TextureType::_2DMultisampleArray) &&
7458 static_cast<GLuint>(params[0]) != 0)
7459 {
7460 context->validationError(entryPoint, GL_INVALID_OPERATION, kBaseLevelNonZero);
7461 return false;
7462 }
7463 if (target == TextureType::Rectangle && static_cast<GLuint>(params[0]) != 0)
7464 {
7465 context->validationError(entryPoint, GL_INVALID_OPERATION, kBaseLevelNonZero);
7466 return false;
7467 }
7468 break;
7469
7470 case GL_TEXTURE_MAX_LEVEL:
7471 if (ConvertToGLint(params[0]) < 0)
7472 {
7473 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
7474 return false;
7475 }
7476 break;
7477
7478 case GL_DEPTH_STENCIL_TEXTURE_MODE:
7479 if (context->getClientVersion() < Version(3, 1))
7480 {
7481 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
7482 return false;
7483 }
7484 switch (ConvertToGLenum(params[0]))
7485 {
7486 case GL_DEPTH_COMPONENT:
7487 case GL_STENCIL_INDEX:
7488 break;
7489
7490 default:
7491 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7492 return false;
7493 }
7494 break;
7495
7496 case GL_TEXTURE_SRGB_DECODE_EXT:
7497 if (!ValidateTextureSRGBDecodeValue(context, entryPoint, params))
7498 {
7499 return false;
7500 }
7501 break;
7502
7503 case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT:
7504 if (!ValidateTextureSRGBOverrideValue(context, entryPoint, params))
7505 {
7506 return false;
7507 }
7508 break;
7509
7510 case GL_GENERATE_MIPMAP:
7511 if (context->getClientMajorVersion() > 1)
7512 {
7513 context->validationError(entryPoint, GL_INVALID_ENUM, kGLES1Only);
7514 return false;
7515 }
7516 break;
7517
7518 case GL_TEXTURE_CROP_RECT_OES:
7519 if (context->getClientMajorVersion() > 1)
7520 {
7521 context->validationError(entryPoint, GL_INVALID_ENUM, kGLES1Only);
7522 return false;
7523 }
7524 if (!vectorParams)
7525 {
7526 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
7527 return false;
7528 }
7529 break;
7530
7531 case GL_TEXTURE_BORDER_COLOR:
7532 if (!context->getExtensions().textureBorderClampOES &&
7533 context->getClientVersion() < ES_3_2)
7534 {
7535 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
7536 return false;
7537 }
7538 if (!vectorParams)
7539 {
7540 context->validationError(entryPoint, GL_INVALID_ENUM, kInsufficientBufferSize);
7541 return false;
7542 }
7543 break;
7544
7545 case GL_RESOURCE_INITIALIZED_ANGLE:
7546 if (!context->getExtensions().robustResourceInitializationANGLE)
7547 {
7548 context->validationError(entryPoint, GL_INVALID_ENUM,
7549 kRobustResourceInitializationExtensionRequired);
7550 return false;
7551 }
7552 break;
7553
7554 case GL_TEXTURE_PROTECTED_EXT:
7555 if (!context->getExtensions().protectedTexturesEXT)
7556 {
7557 context->validationError(entryPoint, GL_INVALID_ENUM,
7558 kProtectedTexturesExtensionRequired);
7559 return false;
7560 }
7561 if (ConvertToBool(params[0]) != context->getState().hasProtectedContent())
7562 {
7563 context->validationError(entryPoint, GL_INVALID_OPERATION,
7564 "Protected Texture must match Protected Context");
7565 return false;
7566 }
7567 break;
7568
7569 default:
7570 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7571 return false;
7572 }
7573
7574 return true;
7575 }
7576
7577 template bool ValidateTexParameterBase(const Context *,
7578 angle::EntryPoint,
7579 TextureType,
7580 GLenum,
7581 GLsizei,
7582 bool,
7583 const GLfloat *);
7584 template bool ValidateTexParameterBase(const Context *,
7585 angle::EntryPoint,
7586 TextureType,
7587 GLenum,
7588 GLsizei,
7589 bool,
7590 const GLint *);
7591 template bool ValidateTexParameterBase(const Context *,
7592 angle::EntryPoint,
7593 TextureType,
7594 GLenum,
7595 GLsizei,
7596 bool,
7597 const GLuint *);
7598
ValidateGetActiveUniformBlockivBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformBlockIndex uniformBlockIndex,GLenum pname,GLsizei * length)7599 bool ValidateGetActiveUniformBlockivBase(const Context *context,
7600 angle::EntryPoint entryPoint,
7601 ShaderProgramID program,
7602 UniformBlockIndex uniformBlockIndex,
7603 GLenum pname,
7604 GLsizei *length)
7605 {
7606 if (length)
7607 {
7608 *length = 0;
7609 }
7610
7611 if (context->getClientMajorVersion() < 3)
7612 {
7613 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
7614 return false;
7615 }
7616
7617 Program *programObject = GetValidProgram(context, entryPoint, program);
7618 if (!programObject)
7619 {
7620 return false;
7621 }
7622
7623 if (uniformBlockIndex.value >= programObject->getActiveUniformBlockCount())
7624 {
7625 context->validationError(entryPoint, GL_INVALID_VALUE,
7626 kIndexExceedsActiveUniformBlockCount);
7627 return false;
7628 }
7629
7630 switch (pname)
7631 {
7632 case GL_UNIFORM_BLOCK_BINDING:
7633 case GL_UNIFORM_BLOCK_DATA_SIZE:
7634 case GL_UNIFORM_BLOCK_NAME_LENGTH:
7635 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
7636 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
7637 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
7638 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
7639 break;
7640
7641 default:
7642 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7643 return false;
7644 }
7645
7646 if (length)
7647 {
7648 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
7649 {
7650 const InterfaceBlock &uniformBlock =
7651 programObject->getUniformBlockByIndex(uniformBlockIndex.value);
7652 *length = static_cast<GLsizei>(uniformBlock.memberIndexes.size());
7653 }
7654 else
7655 {
7656 *length = 1;
7657 }
7658 }
7659
7660 return true;
7661 }
7662
7663 template <typename ParamType>
ValidateSamplerParameterBase(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,bool vectorParams,const ParamType * params)7664 bool ValidateSamplerParameterBase(const Context *context,
7665 angle::EntryPoint entryPoint,
7666 SamplerID sampler,
7667 GLenum pname,
7668 GLsizei bufSize,
7669 bool vectorParams,
7670 const ParamType *params)
7671 {
7672 if (context->getClientMajorVersion() < 3)
7673 {
7674 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
7675 return false;
7676 }
7677
7678 if (!context->isSampler(sampler))
7679 {
7680 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidSampler);
7681 return false;
7682 }
7683
7684 const GLsizei minBufSize = GetSamplerParameterCount(pname);
7685 if (bufSize >= 0 && bufSize < minBufSize)
7686 {
7687 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
7688 return false;
7689 }
7690
7691 switch (pname)
7692 {
7693 case GL_TEXTURE_WRAP_S:
7694 case GL_TEXTURE_WRAP_T:
7695 case GL_TEXTURE_WRAP_R:
7696 if (!ValidateTextureWrapModeValue(context, entryPoint, params, false))
7697 {
7698 return false;
7699 }
7700 break;
7701
7702 case GL_TEXTURE_MIN_FILTER:
7703 if (!ValidateTextureMinFilterValue(context, entryPoint, params, false))
7704 {
7705 return false;
7706 }
7707 break;
7708
7709 case GL_TEXTURE_MAG_FILTER:
7710 if (!ValidateTextureMagFilterValue(context, entryPoint, params))
7711 {
7712 return false;
7713 }
7714 break;
7715
7716 case GL_TEXTURE_MIN_LOD:
7717 case GL_TEXTURE_MAX_LOD:
7718 // any value is permissible
7719 break;
7720
7721 case GL_TEXTURE_COMPARE_MODE:
7722 if (!ValidateTextureCompareModeValue(context, entryPoint, params))
7723 {
7724 return false;
7725 }
7726 break;
7727
7728 case GL_TEXTURE_COMPARE_FUNC:
7729 if (!ValidateTextureCompareFuncValue(context, entryPoint, params))
7730 {
7731 return false;
7732 }
7733 break;
7734
7735 case GL_TEXTURE_SRGB_DECODE_EXT:
7736 if (!ValidateTextureSRGBDecodeValue(context, entryPoint, params))
7737 {
7738 return false;
7739 }
7740 break;
7741
7742 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
7743 {
7744 GLfloat paramValue = static_cast<GLfloat>(params[0]);
7745 if (!ValidateTextureMaxAnisotropyValue(context, entryPoint, paramValue))
7746 {
7747 return false;
7748 }
7749 }
7750 break;
7751
7752 case GL_TEXTURE_BORDER_COLOR:
7753 if (!context->getExtensions().textureBorderClampOES &&
7754 context->getClientVersion() < ES_3_2)
7755 {
7756 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
7757 return false;
7758 }
7759 if (!vectorParams)
7760 {
7761 context->validationError(entryPoint, GL_INVALID_ENUM, kInsufficientBufferSize);
7762 return false;
7763 }
7764 break;
7765
7766 default:
7767 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7768 return false;
7769 }
7770
7771 return true;
7772 }
7773
7774 template bool ValidateSamplerParameterBase(const Context *,
7775 angle::EntryPoint,
7776 SamplerID,
7777 GLenum,
7778 GLsizei,
7779 bool,
7780 const GLfloat *);
7781 template bool ValidateSamplerParameterBase(const Context *,
7782 angle::EntryPoint,
7783 SamplerID,
7784 GLenum,
7785 GLsizei,
7786 bool,
7787 const GLint *);
7788 template bool ValidateSamplerParameterBase(const Context *,
7789 angle::EntryPoint,
7790 SamplerID,
7791 GLenum,
7792 GLsizei,
7793 bool,
7794 const GLuint *);
7795
ValidateGetSamplerParameterBase(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei * length)7796 bool ValidateGetSamplerParameterBase(const Context *context,
7797 angle::EntryPoint entryPoint,
7798 SamplerID sampler,
7799 GLenum pname,
7800 GLsizei *length)
7801 {
7802 if (length)
7803 {
7804 *length = 0;
7805 }
7806
7807 if (context->getClientMajorVersion() < 3)
7808 {
7809 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
7810 return false;
7811 }
7812
7813 if (!context->isSampler(sampler))
7814 {
7815 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidSampler);
7816 return false;
7817 }
7818
7819 switch (pname)
7820 {
7821 case GL_TEXTURE_WRAP_S:
7822 case GL_TEXTURE_WRAP_T:
7823 case GL_TEXTURE_WRAP_R:
7824 case GL_TEXTURE_MIN_FILTER:
7825 case GL_TEXTURE_MAG_FILTER:
7826 case GL_TEXTURE_MIN_LOD:
7827 case GL_TEXTURE_MAX_LOD:
7828 case GL_TEXTURE_COMPARE_MODE:
7829 case GL_TEXTURE_COMPARE_FUNC:
7830 break;
7831
7832 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
7833 if (!ValidateTextureMaxAnisotropyExtensionEnabled(context, entryPoint))
7834 {
7835 return false;
7836 }
7837 break;
7838
7839 case GL_TEXTURE_SRGB_DECODE_EXT:
7840 if (!context->getExtensions().textureSRGBDecodeEXT)
7841 {
7842 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7843 return false;
7844 }
7845 break;
7846
7847 case GL_TEXTURE_BORDER_COLOR:
7848 if (!context->getExtensions().textureBorderClampOES &&
7849 context->getClientVersion() < ES_3_2)
7850 {
7851 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
7852 return false;
7853 }
7854 break;
7855
7856 default:
7857 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7858 return false;
7859 }
7860
7861 if (length)
7862 {
7863 *length = GetSamplerParameterCount(pname);
7864 }
7865 return true;
7866 }
7867
ValidateGetInternalFormativBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum internalformat,GLenum pname,GLsizei bufSize,GLsizei * numParams)7868 bool ValidateGetInternalFormativBase(const Context *context,
7869 angle::EntryPoint entryPoint,
7870 GLenum target,
7871 GLenum internalformat,
7872 GLenum pname,
7873 GLsizei bufSize,
7874 GLsizei *numParams)
7875 {
7876 if (numParams)
7877 {
7878 *numParams = 0;
7879 }
7880
7881 if (context->getClientMajorVersion() < 3)
7882 {
7883 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
7884 return false;
7885 }
7886
7887 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
7888 if (!formatCaps.renderbuffer)
7889 {
7890 context->validationError(entryPoint, GL_INVALID_ENUM, kFormatNotRenderable);
7891 return false;
7892 }
7893
7894 switch (target)
7895 {
7896 case GL_RENDERBUFFER:
7897 break;
7898
7899 case GL_TEXTURE_2D_MULTISAMPLE:
7900 if (context->getClientVersion() < ES_3_1 &&
7901 !context->getExtensions().textureMultisampleANGLE)
7902 {
7903 context->validationError(entryPoint, GL_INVALID_ENUM,
7904 kMultisampleTextureExtensionOrES31Required);
7905 return false;
7906 }
7907 break;
7908 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES:
7909 if (!context->getExtensions().textureStorageMultisample2dArrayOES)
7910 {
7911 context->validationError(entryPoint, GL_INVALID_ENUM,
7912 kMultisampleArrayExtensionRequired);
7913 return false;
7914 }
7915 break;
7916 default:
7917 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTarget);
7918 return false;
7919 }
7920
7921 if (bufSize < 0)
7922 {
7923 context->validationError(entryPoint, GL_INVALID_VALUE, kInsufficientBufferSize);
7924 return false;
7925 }
7926
7927 GLsizei maxWriteParams = 0;
7928 switch (pname)
7929 {
7930 case GL_NUM_SAMPLE_COUNTS:
7931 maxWriteParams = 1;
7932 break;
7933
7934 case GL_SAMPLES:
7935 maxWriteParams = static_cast<GLsizei>(formatCaps.sampleCounts.size());
7936 break;
7937
7938 default:
7939 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7940 return false;
7941 }
7942
7943 if (numParams)
7944 {
7945 // glGetInternalFormativ will not overflow bufSize
7946 *numParams = std::min(bufSize, maxWriteParams);
7947 }
7948
7949 return true;
7950 }
7951
ValidateFramebufferNotMultisampled(const Context * context,angle::EntryPoint entryPoint,const Framebuffer * framebuffer,bool checkReadBufferResourceSamples)7952 bool ValidateFramebufferNotMultisampled(const Context *context,
7953 angle::EntryPoint entryPoint,
7954 const Framebuffer *framebuffer,
7955 bool checkReadBufferResourceSamples)
7956 {
7957 int samples = checkReadBufferResourceSamples
7958 ? framebuffer->getReadBufferResourceSamples(context)
7959 : framebuffer->getSamples(context);
7960 if (samples != 0)
7961 {
7962 context->validationError(entryPoint, GL_INVALID_OPERATION,
7963 kInvalidMultisampledFramebufferOperation);
7964 return false;
7965 }
7966 return true;
7967 }
7968
ValidateMultitextureUnit(const Context * context,angle::EntryPoint entryPoint,GLenum texture)7969 bool ValidateMultitextureUnit(const Context *context, angle::EntryPoint entryPoint, GLenum texture)
7970 {
7971 if (texture < GL_TEXTURE0 || texture >= GL_TEXTURE0 + context->getCaps().maxMultitextureUnits)
7972 {
7973 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidMultitextureUnit);
7974 return false;
7975 }
7976 return true;
7977 }
7978
ValidateTexStorageMultisample(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLsizei samples,GLint internalFormat,GLsizei width,GLsizei height)7979 bool ValidateTexStorageMultisample(const Context *context,
7980 angle::EntryPoint entryPoint,
7981 TextureType target,
7982 GLsizei samples,
7983 GLint internalFormat,
7984 GLsizei width,
7985 GLsizei height)
7986 {
7987 const Caps &caps = context->getCaps();
7988 if (width > caps.max2DTextureSize || height > caps.max2DTextureSize)
7989 {
7990 context->validationError(entryPoint, GL_INVALID_VALUE, kTextureWidthOrHeightOutOfRange);
7991 return false;
7992 }
7993
7994 if (samples == 0)
7995 {
7996 context->validationError(entryPoint, GL_INVALID_VALUE, kSamplesZero);
7997 return false;
7998 }
7999
8000 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
8001 if (!formatCaps.textureAttachment)
8002 {
8003 context->validationError(entryPoint, GL_INVALID_ENUM, kRenderableInternalFormat);
8004 return false;
8005 }
8006
8007 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
8008 // is one of the unsized base internalformats listed in table 8.11.
8009 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
8010 if (formatInfo.internalFormat == GL_NONE)
8011 {
8012 context->validationError(entryPoint, GL_INVALID_ENUM, kUnsizedInternalFormatUnsupported);
8013 return false;
8014 }
8015
8016 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
8017 {
8018 context->validationError(entryPoint, GL_INVALID_OPERATION, kSamplesOutOfRange);
8019 return false;
8020 }
8021
8022 Texture *texture = context->getTextureByType(target);
8023 if (!texture || texture->id().value == 0)
8024 {
8025 context->validationError(entryPoint, GL_INVALID_OPERATION, kZeroBoundToTarget);
8026 return false;
8027 }
8028
8029 if (texture->getImmutableFormat())
8030 {
8031 context->validationError(entryPoint, GL_INVALID_OPERATION, kImmutableTextureBound);
8032 return false;
8033 }
8034 return true;
8035 }
8036
ValidateTexStorage2DMultisampleBase(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLsizei samples,GLint internalFormat,GLsizei width,GLsizei height)8037 bool ValidateTexStorage2DMultisampleBase(const Context *context,
8038 angle::EntryPoint entryPoint,
8039 TextureType target,
8040 GLsizei samples,
8041 GLint internalFormat,
8042 GLsizei width,
8043 GLsizei height)
8044 {
8045 if (target != TextureType::_2DMultisample)
8046 {
8047 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTarget);
8048 return false;
8049 }
8050
8051 if (width < 1 || height < 1)
8052 {
8053 context->validationError(entryPoint, GL_INVALID_VALUE, kTextureSizeTooSmall);
8054 return false;
8055 }
8056
8057 return ValidateTexStorageMultisample(context, entryPoint, target, samples, internalFormat,
8058 width, height);
8059 }
8060
ValidateGetTexLevelParameterBase(const Context * context,angle::EntryPoint entryPoint,TextureTarget target,GLint level,GLenum pname,GLsizei * length)8061 bool ValidateGetTexLevelParameterBase(const Context *context,
8062 angle::EntryPoint entryPoint,
8063 TextureTarget target,
8064 GLint level,
8065 GLenum pname,
8066 GLsizei *length)
8067 {
8068
8069 if (length)
8070 {
8071 *length = 0;
8072 }
8073
8074 TextureType type = TextureTargetToType(target);
8075
8076 if (!ValidTexLevelDestinationTarget(context, type))
8077 {
8078 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
8079 return false;
8080 }
8081
8082 if (context->getTextureByType(type) == nullptr)
8083 {
8084 context->validationError(entryPoint, GL_INVALID_ENUM, kTextureNotBound);
8085 return false;
8086 }
8087
8088 if (!ValidMipLevel(context, type, level))
8089 {
8090 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
8091 return false;
8092 }
8093
8094 switch (pname)
8095 {
8096 case GL_TEXTURE_RED_TYPE:
8097 case GL_TEXTURE_GREEN_TYPE:
8098 case GL_TEXTURE_BLUE_TYPE:
8099 case GL_TEXTURE_ALPHA_TYPE:
8100 case GL_TEXTURE_DEPTH_TYPE:
8101 case GL_TEXTURE_RED_SIZE:
8102 case GL_TEXTURE_GREEN_SIZE:
8103 case GL_TEXTURE_BLUE_SIZE:
8104 case GL_TEXTURE_ALPHA_SIZE:
8105 case GL_TEXTURE_DEPTH_SIZE:
8106 case GL_TEXTURE_STENCIL_SIZE:
8107 case GL_TEXTURE_SHARED_SIZE:
8108 case GL_TEXTURE_INTERNAL_FORMAT:
8109 case GL_TEXTURE_WIDTH:
8110 case GL_TEXTURE_HEIGHT:
8111 case GL_TEXTURE_DEPTH:
8112 case GL_TEXTURE_SAMPLES:
8113 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
8114 case GL_TEXTURE_COMPRESSED:
8115 break;
8116
8117 case GL_RESOURCE_INITIALIZED_ANGLE:
8118 if (!context->getExtensions().robustResourceInitializationANGLE)
8119 {
8120 context->validationError(entryPoint, GL_INVALID_ENUM,
8121 kRobustResourceInitializationExtensionRequired);
8122 return false;
8123 }
8124 break;
8125
8126 case GL_TEXTURE_BUFFER_DATA_STORE_BINDING:
8127 case GL_TEXTURE_BUFFER_OFFSET:
8128 case GL_TEXTURE_BUFFER_SIZE:
8129 if (context->getClientVersion() < Version(3, 2) &&
8130 !context->getExtensions().textureBufferAny())
8131 {
8132 context->validationError(entryPoint, GL_INVALID_ENUM,
8133 kTextureBufferExtensionNotAvailable);
8134 return false;
8135 }
8136 break;
8137
8138 default:
8139 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
8140 return false;
8141 }
8142
8143 if (length)
8144 {
8145 *length = 1;
8146 }
8147 return true;
8148 }
8149
ValidateGetMultisamplefvBase(const Context * context,angle::EntryPoint entryPoint,GLenum pname,GLuint index,const GLfloat * val)8150 bool ValidateGetMultisamplefvBase(const Context *context,
8151 angle::EntryPoint entryPoint,
8152 GLenum pname,
8153 GLuint index,
8154 const GLfloat *val)
8155 {
8156 if (pname != GL_SAMPLE_POSITION)
8157 {
8158 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
8159 return false;
8160 }
8161
8162 Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
8163 GLint samples = framebuffer->getSamples(context);
8164
8165 if (index >= static_cast<GLuint>(samples))
8166 {
8167 context->validationError(entryPoint, GL_INVALID_VALUE, kIndexExceedsSamples);
8168 return false;
8169 }
8170
8171 return true;
8172 }
8173
ValidateSampleMaskiBase(const Context * context,angle::EntryPoint entryPoint,GLuint maskNumber,GLbitfield mask)8174 bool ValidateSampleMaskiBase(const Context *context,
8175 angle::EntryPoint entryPoint,
8176 GLuint maskNumber,
8177 GLbitfield mask)
8178 {
8179 if (maskNumber >= static_cast<GLuint>(context->getCaps().maxSampleMaskWords))
8180 {
8181 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidSampleMaskNumber);
8182 return false;
8183 }
8184
8185 return true;
8186 }
8187
RecordDrawAttribsError(const Context * context,angle::EntryPoint entryPoint)8188 void RecordDrawAttribsError(const Context *context, angle::EntryPoint entryPoint)
8189 {
8190 // An overflow can happen when adding the offset. Check against a special constant.
8191 if (context->getStateCache().getNonInstancedVertexElementLimit() ==
8192 VertexAttribute::kIntegerOverflow ||
8193 context->getStateCache().getInstancedVertexElementLimit() ==
8194 VertexAttribute::kIntegerOverflow)
8195 {
8196 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
8197 }
8198 else
8199 {
8200 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
8201 // We can return INVALID_OPERATION if our buffer does not have enough backing data.
8202 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientVertexBufferSize);
8203 }
8204 }
8205
ValidateLoseContextCHROMIUM(const Context * context,angle::EntryPoint entryPoint,GraphicsResetStatus current,GraphicsResetStatus other)8206 bool ValidateLoseContextCHROMIUM(const Context *context,
8207 angle::EntryPoint entryPoint,
8208 GraphicsResetStatus current,
8209 GraphicsResetStatus other)
8210 {
8211 if (!context->getExtensions().loseContextCHROMIUM)
8212 {
8213 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
8214 return false;
8215 }
8216
8217 switch (current)
8218 {
8219 case GraphicsResetStatus::GuiltyContextReset:
8220 case GraphicsResetStatus::InnocentContextReset:
8221 case GraphicsResetStatus::UnknownContextReset:
8222 break;
8223
8224 default:
8225 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidResetStatus);
8226 }
8227
8228 switch (other)
8229 {
8230 case GraphicsResetStatus::GuiltyContextReset:
8231 case GraphicsResetStatus::InnocentContextReset:
8232 case GraphicsResetStatus::UnknownContextReset:
8233 break;
8234
8235 default:
8236 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidResetStatus);
8237 }
8238
8239 return true;
8240 }
8241
8242 // GL_ANGLE_texture_storage_external
ValidateTexImage2DExternalANGLE(const Context * context,angle::EntryPoint entryPoint,TextureTarget target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type)8243 bool ValidateTexImage2DExternalANGLE(const Context *context,
8244 angle::EntryPoint entryPoint,
8245 TextureTarget target,
8246 GLint level,
8247 GLint internalformat,
8248 GLsizei width,
8249 GLsizei height,
8250 GLint border,
8251 GLenum format,
8252 GLenum type)
8253 {
8254 if (!context->getExtensions().textureExternalUpdateANGLE)
8255 {
8256 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
8257 return false;
8258 }
8259
8260 if (!ValidTexture2DDestinationTarget(context, target) &&
8261 !ValidTextureExternalTarget(context, target))
8262 {
8263 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
8264 return false;
8265 }
8266
8267 if (context->getClientMajorVersion() <= 2)
8268 {
8269 if (!ValidateES2TexImageParametersBase(context, entryPoint, target, level, internalformat,
8270 false, false, 0, 0, width, height, border, format,
8271 type, -1, nullptr))
8272 {
8273 return false;
8274 }
8275 }
8276 else
8277 {
8278 if (!ValidateES3TexImageParametersBase(context, entryPoint, target, level, internalformat,
8279 false, false, 0, 0, 0, width, height, 1, border,
8280 format, type, -1, nullptr))
8281 {
8282 return false;
8283 }
8284 }
8285
8286 return true;
8287 }
8288
ValidateInvalidateTextureANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target)8289 bool ValidateInvalidateTextureANGLE(const Context *context,
8290 angle::EntryPoint entryPoint,
8291 TextureType target)
8292 {
8293 if (!context->getExtensions().textureExternalUpdateANGLE)
8294 {
8295 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
8296 return false;
8297 }
8298
8299 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
8300 {
8301 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
8302 return false;
8303 }
8304
8305 return true;
8306 }
8307
8308 //angle CVE-2022-0975
ValidateProgramExecutableXFBBuffersPresent(const Context * context,const ProgramExecutable * programExecutable)8309 bool ValidateProgramExecutableXFBBuffersPresent(const Context *context,
8310 const ProgramExecutable *programExecutable)
8311 {
8312 size_t programXfbCount = programExecutable->getTransformFeedbackBufferCount();
8313 const TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
8314 for (size_t programXfbIndex = 0; programXfbIndex < programXfbCount; ++programXfbIndex)
8315 {
8316 const OffsetBindingPointer<Buffer> &buffer =
8317 transformFeedback->getIndexedBuffer(programXfbIndex);
8318 if (!buffer.get())
8319 {
8320 return false;
8321 }
8322 }
8323
8324 return true;
8325 }
8326 } // namespace gl
8327