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
4091 if (programIsYUVOutput != framebufferIsYUV)
4092 {
4093 // Both the program and framebuffer must match in YUV output state.
4094 return kYUVOutputMissmatch;
4095 }
4096
4097 if (!state.validateSamplerFormats())
4098 {
4099 return kSamplerFormatMismatch;
4100 }
4101
4102 // Do some additional WebGL-specific validation
4103 if (extensions.webglCompatibilityANGLE)
4104 {
4105 const TransformFeedback *transformFeedbackObject = state.getCurrentTransformFeedback();
4106 if (state.isTransformFeedbackActive() &&
4107 transformFeedbackObject->buffersBoundForOtherUseInWebGL())
4108 {
4109 return kTransformFeedbackBufferDoubleBound;
4110 }
4111
4112 // Detect rendering feedback loops for WebGL.
4113 if (framebuffer->formsRenderingFeedbackLoopWith(context))
4114 {
4115 return kFeedbackLoop;
4116 }
4117
4118 // Detect that the vertex shader input types match the attribute types
4119 if (!ValidateVertexShaderAttributeTypeMatch(context))
4120 {
4121 return kVertexShaderTypeMismatch;
4122 }
4123
4124 if (!context->getState().getRasterizerState().rasterizerDiscard &&
4125 !context->getState().allActiveDrawBufferChannelsMasked())
4126 {
4127 // Detect that if there's active color buffer without fragment shader output
4128 if (!ValidateFragmentShaderColorBufferMaskMatch(context))
4129 {
4130 return kDrawBufferMaskMismatch;
4131 }
4132
4133 // Detect that the color buffer types match the fragment shader output types
4134 if (!ValidateFragmentShaderColorBufferTypeMatch(context))
4135 {
4136 return kDrawBufferTypeMismatch;
4137 }
4138 }
4139
4140 const VertexArray *vao = context->getState().getVertexArray();
4141 if (vao->hasTransformFeedbackBindingConflict(context))
4142 {
4143 return kVertexBufferBoundForTransformFeedback;
4144 }
4145
4146 // Validate that we are rendering with a linked program.
4147 if (!program->isLinked())
4148 {
4149 return kProgramNotLinked;
4150 }
4151 }
4152 }
4153
4154 return nullptr;
4155 }
4156
RecordDrawModeError(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode)4157 void RecordDrawModeError(const Context *context, angle::EntryPoint entryPoint, PrimitiveMode mode)
4158 {
4159 const State &state = context->getState();
4160 TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
4161 if (state.isTransformFeedbackActiveUnpaused())
4162 {
4163 if (!ValidateTransformFeedbackPrimitiveMode(context, entryPoint,
4164 curTransformFeedback->getPrimitiveMode(), mode))
4165 {
4166 context->validationError(entryPoint, GL_INVALID_OPERATION,
4167 kInvalidDrawModeTransformFeedback);
4168 return;
4169 }
4170 }
4171
4172 const Extensions &extensions = context->getExtensions();
4173
4174 switch (mode)
4175 {
4176 case PrimitiveMode::Points:
4177 case PrimitiveMode::Lines:
4178 case PrimitiveMode::LineLoop:
4179 case PrimitiveMode::LineStrip:
4180 case PrimitiveMode::Triangles:
4181 case PrimitiveMode::TriangleStrip:
4182 case PrimitiveMode::TriangleFan:
4183 break;
4184
4185 case PrimitiveMode::LinesAdjacency:
4186 case PrimitiveMode::LineStripAdjacency:
4187 case PrimitiveMode::TrianglesAdjacency:
4188 case PrimitiveMode::TriangleStripAdjacency:
4189 if (!extensions.geometryShaderAny() && context->getClientVersion() < ES_3_2)
4190 {
4191 context->validationError(entryPoint, GL_INVALID_ENUM,
4192 kGeometryShaderExtensionNotEnabled);
4193 return;
4194 }
4195 break;
4196
4197 case PrimitiveMode::Patches:
4198 if (!extensions.tessellationShaderEXT && context->getClientVersion() < ES_3_2)
4199 {
4200 context->validationError(entryPoint, GL_INVALID_ENUM,
4201 kTessellationShaderExtensionNotEnabled);
4202 return;
4203 }
4204 break;
4205
4206 default:
4207 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidDrawMode);
4208 return;
4209 }
4210
4211 // If we are running GLES1, there is no current program.
4212 if (context->getClientVersion() >= Version(2, 0))
4213 {
4214 const ProgramExecutable *executable = state.getProgramExecutable();
4215 ASSERT(executable);
4216
4217 // Do geometry shader specific validations
4218 if (executable->hasLinkedShaderStage(ShaderType::Geometry))
4219 {
4220 if (!IsCompatibleDrawModeWithGeometryShader(
4221 mode, executable->getGeometryShaderInputPrimitiveType()))
4222 {
4223 context->validationError(entryPoint, GL_INVALID_OPERATION,
4224 kIncompatibleDrawModeAgainstGeometryShader);
4225 return;
4226 }
4227 }
4228
4229 if (executable->hasLinkedTessellationShader() && mode != PrimitiveMode::Patches)
4230 {
4231 context->validationError(entryPoint, GL_INVALID_OPERATION,
4232 kIncompatibleDrawModeWithTessellationShader);
4233 return;
4234 }
4235
4236 if (!executable->hasLinkedTessellationShader() && mode == PrimitiveMode::Patches)
4237 {
4238 context->validationError(entryPoint, GL_INVALID_OPERATION,
4239 kIncompatibleDrawModeWithoutTessellationShader);
4240 return;
4241 }
4242 }
4243
4244 // An error should be recorded.
4245 UNREACHABLE();
4246 }
4247
ValidateDrawArraysInstancedANGLE(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)4248 bool ValidateDrawArraysInstancedANGLE(const Context *context,
4249 angle::EntryPoint entryPoint,
4250 PrimitiveMode mode,
4251 GLint first,
4252 GLsizei count,
4253 GLsizei primcount)
4254 {
4255 if (!context->getExtensions().instancedArraysANGLE)
4256 {
4257 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4258 return false;
4259 }
4260
4261 if (!ValidateDrawArraysInstancedBase(context, entryPoint, mode, first, count, primcount))
4262 {
4263 return false;
4264 }
4265
4266 return ValidateDrawInstancedANGLE(context, entryPoint);
4267 }
4268
ValidateDrawArraysInstancedEXT(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)4269 bool ValidateDrawArraysInstancedEXT(const Context *context,
4270 angle::EntryPoint entryPoint,
4271 PrimitiveMode mode,
4272 GLint first,
4273 GLsizei count,
4274 GLsizei primcount)
4275 {
4276 if (!context->getExtensions().instancedArraysEXT)
4277 {
4278 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4279 return false;
4280 }
4281
4282 if (!ValidateDrawArraysInstancedBase(context, entryPoint, mode, first, count, primcount))
4283 {
4284 return false;
4285 }
4286
4287 return true;
4288 }
4289
ValidateDrawElementsStates(const Context * context)4290 const char *ValidateDrawElementsStates(const Context *context)
4291 {
4292 const State &state = context->getState();
4293
4294 if (context->getStateCache().isTransformFeedbackActiveUnpaused())
4295 {
4296 // EXT_geometry_shader allows transform feedback to work with all draw commands.
4297 // [EXT_geometry_shader] Section 12.1, "Transform Feedback"
4298 if (!context->getExtensions().geometryShaderAny() && context->getClientVersion() < ES_3_2)
4299 {
4300 // It is an invalid operation to call DrawElements, DrawRangeElements or
4301 // DrawElementsInstanced while transform feedback is active, (3.0.2, section 2.14, pg
4302 // 86)
4303 return kUnsupportedDrawModeForTransformFeedback;
4304 }
4305 }
4306
4307 const VertexArray *vao = state.getVertexArray();
4308 Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
4309
4310 if (elementArrayBuffer)
4311 {
4312 if (elementArrayBuffer->hasWebGLXFBBindingConflict(context->isWebGL()))
4313 {
4314 return kElementArrayBufferBoundForTransformFeedback;
4315 }
4316 if (elementArrayBuffer->isMapped() &&
4317 (!elementArrayBuffer->isImmutable() ||
4318 (elementArrayBuffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) == 0))
4319 {
4320 return kBufferMapped;
4321 }
4322 }
4323 else
4324 {
4325 // [WebGL 1.0] Section 6.2 No Client Side Arrays
4326 // If an indexed draw command (drawElements) is called and no WebGLBuffer is bound to
4327 // the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
4328 if (!context->getState().areClientArraysEnabled() || context->isWebGL())
4329 {
4330 return kMustHaveElementArrayBinding;
4331 }
4332 }
4333
4334 return nullptr;
4335 }
4336
ValidateDrawElementsInstancedANGLE(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLsizei count,DrawElementsType type,const void * indices,GLsizei primcount)4337 bool ValidateDrawElementsInstancedANGLE(const Context *context,
4338 angle::EntryPoint entryPoint,
4339 PrimitiveMode mode,
4340 GLsizei count,
4341 DrawElementsType type,
4342 const void *indices,
4343 GLsizei primcount)
4344 {
4345 if (!context->getExtensions().instancedArraysANGLE)
4346 {
4347 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4348 return false;
4349 }
4350
4351 if (!ValidateDrawElementsInstancedBase(context, entryPoint, mode, count, type, indices,
4352 primcount))
4353 {
4354 return false;
4355 }
4356
4357 return ValidateDrawInstancedANGLE(context, entryPoint);
4358 }
4359
ValidateDrawElementsInstancedEXT(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLsizei count,DrawElementsType type,const void * indices,GLsizei primcount)4360 bool ValidateDrawElementsInstancedEXT(const Context *context,
4361 angle::EntryPoint entryPoint,
4362 PrimitiveMode mode,
4363 GLsizei count,
4364 DrawElementsType type,
4365 const void *indices,
4366 GLsizei primcount)
4367 {
4368 if (!context->getExtensions().instancedArraysEXT)
4369 {
4370 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4371 return false;
4372 }
4373
4374 if (!ValidateDrawElementsInstancedBase(context, entryPoint, mode, count, type, indices,
4375 primcount))
4376 {
4377 return false;
4378 }
4379
4380 return true;
4381 }
4382
ValidateGetUniformBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location)4383 bool ValidateGetUniformBase(const Context *context,
4384 angle::EntryPoint entryPoint,
4385 ShaderProgramID program,
4386 UniformLocation location)
4387 {
4388 if (program.value == 0)
4389 {
4390 context->validationError(entryPoint, GL_INVALID_VALUE, kProgramDoesNotExist);
4391 return false;
4392 }
4393
4394 Program *programObject = GetValidProgram(context, entryPoint, program);
4395 if (!programObject)
4396 {
4397 return false;
4398 }
4399
4400 if (!programObject || !programObject->isLinked())
4401 {
4402 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
4403 return false;
4404 }
4405
4406 if (!programObject->isValidUniformLocation(location))
4407 {
4408 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidUniformLocation);
4409 return false;
4410 }
4411
4412 return true;
4413 }
4414
ValidateSizedGetUniform(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,GLsizei * length)4415 static bool ValidateSizedGetUniform(const Context *context,
4416 angle::EntryPoint entryPoint,
4417 ShaderProgramID program,
4418 UniformLocation location,
4419 GLsizei bufSize,
4420 GLsizei *length)
4421 {
4422 if (length)
4423 {
4424 *length = 0;
4425 }
4426
4427 if (!ValidateGetUniformBase(context, entryPoint, program, location))
4428 {
4429 return false;
4430 }
4431
4432 if (bufSize < 0)
4433 {
4434 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeBufferSize);
4435 return false;
4436 }
4437
4438 Program *programObject = context->getProgramResolveLink(program);
4439 ASSERT(programObject);
4440
4441 // sized queries -- ensure the provided buffer is large enough
4442 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
4443 size_t requiredBytes = VariableExternalSize(uniform.type);
4444 if (static_cast<size_t>(bufSize) < requiredBytes)
4445 {
4446 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
4447 return false;
4448 }
4449
4450 if (length)
4451 {
4452 *length = VariableComponentCount(uniform.type);
4453 }
4454 return true;
4455 }
4456
ValidateGetnUniformfvEXT(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLfloat * params)4457 bool ValidateGetnUniformfvEXT(const Context *context,
4458 angle::EntryPoint entryPoint,
4459 ShaderProgramID program,
4460 UniformLocation location,
4461 GLsizei bufSize,
4462 const GLfloat *params)
4463 {
4464 return ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, nullptr);
4465 }
4466
ValidateGetnUniformfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLfloat * params)4467 bool ValidateGetnUniformfvRobustANGLE(const Context *context,
4468 angle::EntryPoint entryPoint,
4469 ShaderProgramID program,
4470 UniformLocation location,
4471 GLsizei bufSize,
4472 const GLsizei *length,
4473 const GLfloat *params)
4474 {
4475 UNIMPLEMENTED();
4476 return false;
4477 }
4478
ValidateGetnUniformivEXT(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLint * params)4479 bool ValidateGetnUniformivEXT(const Context *context,
4480 angle::EntryPoint entryPoint,
4481 ShaderProgramID program,
4482 UniformLocation location,
4483 GLsizei bufSize,
4484 const GLint *params)
4485 {
4486 return ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, nullptr);
4487 }
4488
ValidateGetnUniformivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLint * params)4489 bool ValidateGetnUniformivRobustANGLE(const Context *context,
4490 angle::EntryPoint entryPoint,
4491 ShaderProgramID program,
4492 UniformLocation location,
4493 GLsizei bufSize,
4494 const GLsizei *length,
4495 const GLint *params)
4496 {
4497 UNIMPLEMENTED();
4498 return false;
4499 }
4500
ValidateGetnUniformuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLuint * params)4501 bool ValidateGetnUniformuivRobustANGLE(const Context *context,
4502 angle::EntryPoint entryPoint,
4503 ShaderProgramID program,
4504 UniformLocation location,
4505 GLsizei bufSize,
4506 const GLsizei *length,
4507 const GLuint *params)
4508 {
4509 UNIMPLEMENTED();
4510 return false;
4511 }
4512
ValidateGetUniformfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLfloat * params)4513 bool ValidateGetUniformfvRobustANGLE(const Context *context,
4514 angle::EntryPoint entryPoint,
4515 ShaderProgramID program,
4516 UniformLocation location,
4517 GLsizei bufSize,
4518 const GLsizei *length,
4519 const GLfloat *params)
4520 {
4521 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
4522 {
4523 return false;
4524 }
4525
4526 GLsizei writeLength = 0;
4527
4528 // bufSize is validated in ValidateSizedGetUniform
4529 if (!ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, &writeLength))
4530 {
4531 return false;
4532 }
4533
4534 SetRobustLengthParam(length, writeLength);
4535
4536 return true;
4537 }
4538
ValidateGetUniformivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLint * params)4539 bool ValidateGetUniformivRobustANGLE(const Context *context,
4540 angle::EntryPoint entryPoint,
4541 ShaderProgramID program,
4542 UniformLocation location,
4543 GLsizei bufSize,
4544 const GLsizei *length,
4545 const GLint *params)
4546 {
4547 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
4548 {
4549 return false;
4550 }
4551
4552 GLsizei writeLength = 0;
4553
4554 // bufSize is validated in ValidateSizedGetUniform
4555 if (!ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, &writeLength))
4556 {
4557 return false;
4558 }
4559
4560 SetRobustLengthParam(length, writeLength);
4561
4562 return true;
4563 }
4564
ValidateGetUniformuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformLocation location,GLsizei bufSize,const GLsizei * length,const GLuint * params)4565 bool ValidateGetUniformuivRobustANGLE(const Context *context,
4566 angle::EntryPoint entryPoint,
4567 ShaderProgramID program,
4568 UniformLocation location,
4569 GLsizei bufSize,
4570 const GLsizei *length,
4571 const GLuint *params)
4572 {
4573 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
4574 {
4575 return false;
4576 }
4577
4578 if (context->getClientMajorVersion() < 3)
4579 {
4580 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
4581 return false;
4582 }
4583
4584 GLsizei writeLength = 0;
4585
4586 // bufSize is validated in ValidateSizedGetUniform
4587 if (!ValidateSizedGetUniform(context, entryPoint, program, location, bufSize, &writeLength))
4588 {
4589 return false;
4590 }
4591
4592 SetRobustLengthParam(length, writeLength);
4593
4594 return true;
4595 }
4596
ValidateDiscardFramebufferBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLsizei numAttachments,const GLenum * attachments,bool defaultFramebuffer)4597 bool ValidateDiscardFramebufferBase(const Context *context,
4598 angle::EntryPoint entryPoint,
4599 GLenum target,
4600 GLsizei numAttachments,
4601 const GLenum *attachments,
4602 bool defaultFramebuffer)
4603 {
4604 if (numAttachments < 0)
4605 {
4606 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeAttachments);
4607 return false;
4608 }
4609
4610 for (GLsizei i = 0; i < numAttachments; ++i)
4611 {
4612 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
4613 {
4614 if (defaultFramebuffer)
4615 {
4616 context->validationError(entryPoint, GL_INVALID_ENUM,
4617 kDefaultFramebufferInvalidAttachment);
4618 return false;
4619 }
4620
4621 if (attachments[i] >=
4622 GL_COLOR_ATTACHMENT0 + static_cast<GLuint>(context->getCaps().maxColorAttachments))
4623 {
4624 context->validationError(entryPoint, GL_INVALID_OPERATION,
4625 kExceedsMaxColorAttachments);
4626 return false;
4627 }
4628 }
4629 else
4630 {
4631 switch (attachments[i])
4632 {
4633 case GL_DEPTH_ATTACHMENT:
4634 case GL_STENCIL_ATTACHMENT:
4635 case GL_DEPTH_STENCIL_ATTACHMENT:
4636 if (defaultFramebuffer)
4637 {
4638 context->validationError(entryPoint, GL_INVALID_ENUM,
4639 kDefaultFramebufferInvalidAttachment);
4640 return false;
4641 }
4642 break;
4643 case GL_COLOR:
4644 case GL_DEPTH:
4645 case GL_STENCIL:
4646 if (!defaultFramebuffer)
4647 {
4648 context->validationError(entryPoint, GL_INVALID_ENUM,
4649 kDefaultFramebufferAttachmentOnUserFBO);
4650 return false;
4651 }
4652 break;
4653 default:
4654 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
4655 return false;
4656 }
4657 }
4658 }
4659
4660 return true;
4661 }
4662
ValidateInsertEventMarkerEXT(const Context * context,angle::EntryPoint entryPoint,GLsizei length,const char * marker)4663 bool ValidateInsertEventMarkerEXT(const Context *context,
4664 angle::EntryPoint entryPoint,
4665 GLsizei length,
4666 const char *marker)
4667 {
4668 if (!context->getExtensions().debugMarkerEXT)
4669 {
4670 // The debug marker calls should not set error state
4671 // However, it seems reasonable to set an error state if the extension is not enabled
4672 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4673 return false;
4674 }
4675
4676 // Note that debug marker calls must not set error state
4677 if (length < 0)
4678 {
4679 return false;
4680 }
4681
4682 if (marker == nullptr)
4683 {
4684 return false;
4685 }
4686
4687 return true;
4688 }
4689
ValidatePushGroupMarkerEXT(const Context * context,angle::EntryPoint entryPoint,GLsizei length,const char * marker)4690 bool ValidatePushGroupMarkerEXT(const Context *context,
4691 angle::EntryPoint entryPoint,
4692 GLsizei length,
4693 const char *marker)
4694 {
4695 if (!context->getExtensions().debugMarkerEXT)
4696 {
4697 // The debug marker calls should not set error state
4698 // However, it seems reasonable to set an error state if the extension is not enabled
4699 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4700 return false;
4701 }
4702
4703 // Note that debug marker calls must not set error state
4704 if (length < 0)
4705 {
4706 return false;
4707 }
4708
4709 if (length > 0 && marker == nullptr)
4710 {
4711 return false;
4712 }
4713
4714 return true;
4715 }
4716
ValidateEGLImageTargetTexture2DOES(const Context * context,angle::EntryPoint entryPoint,TextureType type,GLeglImageOES image)4717 bool ValidateEGLImageTargetTexture2DOES(const Context *context,
4718 angle::EntryPoint entryPoint,
4719 TextureType type,
4720 GLeglImageOES image)
4721 {
4722 if (!context->getExtensions().EGLImageOES && !context->getExtensions().EGLImageExternalOES)
4723 {
4724 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4725 return false;
4726 }
4727
4728 switch (type)
4729 {
4730 case TextureType::_2D:
4731 if (!context->getExtensions().EGLImageOES)
4732 {
4733 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
4734 }
4735 break;
4736
4737 case TextureType::_2DArray:
4738 if (!context->getExtensions().EGLImageArrayEXT)
4739 {
4740 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
4741 }
4742 break;
4743
4744 case TextureType::External:
4745 if (!context->getExtensions().EGLImageExternalOES)
4746 {
4747 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
4748 }
4749 break;
4750
4751 default:
4752 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
4753 return false;
4754 }
4755
4756 egl::Image *imageObject = static_cast<egl::Image *>(image);
4757
4758 ASSERT(context->getDisplay());
4759 if (!context->getDisplay()->isValidImage(imageObject))
4760 {
4761 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidEGLImage);
4762 return false;
4763 }
4764
4765 if (imageObject->getSamples() > 0)
4766 {
4767 context->validationError(entryPoint, GL_INVALID_OPERATION,
4768 kEGLImageCannotCreate2DMultisampled);
4769 return false;
4770 }
4771
4772 if (!imageObject->isTexturable(context))
4773 {
4774 context->validationError(entryPoint, GL_INVALID_OPERATION,
4775 kEGLImageTextureFormatNotSupported);
4776 return false;
4777 }
4778
4779 if (imageObject->isLayered() && type != TextureType::_2DArray)
4780 {
4781 context->validationError(entryPoint, GL_INVALID_OPERATION,
4782 "Image has more than 1 layer, target must be TEXTURE_2D_ARRAY");
4783 return false;
4784 }
4785
4786 if (imageObject->isYUV() && type != TextureType::External)
4787 {
4788 context->validationError(entryPoint, GL_INVALID_OPERATION,
4789 "Image is YUV, target must be TEXTURE_EXTERNAL_OES");
4790 return false;
4791 }
4792
4793 if (imageObject->hasProtectedContent() != context->getState().hasProtectedContent())
4794 {
4795 context->validationError(entryPoint, GL_INVALID_OPERATION,
4796 "Mismatch between Image and Context Protected Content state");
4797 return false;
4798 }
4799
4800 return true;
4801 }
4802
ValidateEGLImageTargetRenderbufferStorageOES(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLeglImageOES image)4803 bool ValidateEGLImageTargetRenderbufferStorageOES(const Context *context,
4804 angle::EntryPoint entryPoint,
4805 GLenum target,
4806 GLeglImageOES image)
4807 {
4808 if (!context->getExtensions().EGLImageOES)
4809 {
4810 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
4811 return false;
4812 }
4813
4814 switch (target)
4815 {
4816 case GL_RENDERBUFFER:
4817 break;
4818
4819 default:
4820 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferTarget);
4821 return false;
4822 }
4823
4824 egl::Image *imageObject = static_cast<egl::Image *>(image);
4825
4826 ASSERT(context->getDisplay());
4827 if (!context->getDisplay()->isValidImage(imageObject))
4828 {
4829 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidEGLImage);
4830 return false;
4831 }
4832
4833 if (!imageObject->isRenderable(context))
4834 {
4835 context->validationError(entryPoint, GL_INVALID_OPERATION,
4836 kEGLImageRenderbufferFormatNotSupported);
4837 return false;
4838 }
4839
4840 if (imageObject->hasProtectedContent() != context->getState().hasProtectedContent())
4841 {
4842 context->validationError(entryPoint, GL_INVALID_OPERATION,
4843 "Mismatch between Image and Context Protected Content state");
4844 return false;
4845 }
4846
4847 return true;
4848 }
4849
ValidateProgramBinaryBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,GLenum binaryFormat,const void * binary,GLint length)4850 bool ValidateProgramBinaryBase(const Context *context,
4851 angle::EntryPoint entryPoint,
4852 ShaderProgramID program,
4853 GLenum binaryFormat,
4854 const void *binary,
4855 GLint length)
4856 {
4857 Program *programObject = GetValidProgram(context, entryPoint, program);
4858 if (programObject == nullptr)
4859 {
4860 return false;
4861 }
4862
4863 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
4864 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
4865 programBinaryFormats.end())
4866 {
4867 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidProgramBinaryFormat);
4868 return false;
4869 }
4870
4871 if (context->hasActiveTransformFeedback(program))
4872 {
4873 // ES 3.0.4 section 2.15 page 91
4874 context->validationError(entryPoint, GL_INVALID_OPERATION, kTransformFeedbackProgramBinary);
4875 return false;
4876 }
4877
4878 return true;
4879 }
4880
ValidateGetProgramBinaryBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,GLsizei bufSize,const GLsizei * length,const GLenum * binaryFormat,const void * binary)4881 bool ValidateGetProgramBinaryBase(const Context *context,
4882 angle::EntryPoint entryPoint,
4883 ShaderProgramID program,
4884 GLsizei bufSize,
4885 const GLsizei *length,
4886 const GLenum *binaryFormat,
4887 const void *binary)
4888 {
4889 Program *programObject = GetValidProgram(context, entryPoint, program);
4890 if (programObject == nullptr)
4891 {
4892 return false;
4893 }
4894
4895 if (!programObject->isLinked())
4896 {
4897 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
4898 return false;
4899 }
4900
4901 if (context->getCaps().programBinaryFormats.empty())
4902 {
4903 context->validationError(entryPoint, GL_INVALID_OPERATION, kNoProgramBinaryFormats);
4904 return false;
4905 }
4906
4907 return true;
4908 }
4909
ValidateDrawBuffersBase(const Context * context,angle::EntryPoint entryPoint,GLsizei n,const GLenum * bufs)4910 bool ValidateDrawBuffersBase(const Context *context,
4911 angle::EntryPoint entryPoint,
4912 GLsizei n,
4913 const GLenum *bufs)
4914 {
4915 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
4916 if (n < 0)
4917 {
4918 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeCount);
4919 return false;
4920 }
4921 if (n > context->getCaps().maxDrawBuffers)
4922 {
4923 context->validationError(entryPoint, GL_INVALID_VALUE, kIndexExceedsMaxDrawBuffer);
4924 return false;
4925 }
4926
4927 ASSERT(context->getState().getDrawFramebuffer());
4928 FramebufferID frameBufferId = context->getState().getDrawFramebuffer()->id();
4929 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
4930
4931 // This should come first before the check for the default frame buffer
4932 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
4933 // rather than INVALID_OPERATION
4934 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
4935 {
4936 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
4937
4938 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
4939 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
4940 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
4941 {
4942 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
4943 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
4944 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
4945 // 3.1 is still a bit ambiguous about the error, but future specs are
4946 // expected to clarify that GL_INVALID_ENUM is the correct error.
4947 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidDrawBuffer);
4948 return false;
4949 }
4950 else if (bufs[colorAttachment] >= maxColorAttachment)
4951 {
4952 context->validationError(entryPoint, GL_INVALID_OPERATION, kExceedsMaxColorAttachments);
4953 return false;
4954 }
4955 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
4956 frameBufferId.value != 0)
4957 {
4958 // INVALID_OPERATION-GL is bound to buffer and ith argument
4959 // is not COLOR_ATTACHMENTi or NONE
4960 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidDrawBufferValue);
4961 return false;
4962 }
4963 }
4964
4965 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
4966 // and n is not 1 or bufs is bound to value other than BACK and NONE
4967 if (frameBufferId.value == 0)
4968 {
4969 if (n != 1)
4970 {
4971 context->validationError(entryPoint, GL_INVALID_OPERATION,
4972 kInvalidDrawBufferCountForDefault);
4973 return false;
4974 }
4975
4976 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
4977 {
4978 context->validationError(entryPoint, GL_INVALID_OPERATION,
4979 kDefaultFramebufferInvalidDrawBuffer);
4980 return false;
4981 }
4982 }
4983
4984 return true;
4985 }
4986
ValidateGetBufferPointervBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLenum pname,GLsizei * length,void * const * params)4987 bool ValidateGetBufferPointervBase(const Context *context,
4988 angle::EntryPoint entryPoint,
4989 BufferBinding target,
4990 GLenum pname,
4991 GLsizei *length,
4992 void *const *params)
4993 {
4994 if (length)
4995 {
4996 *length = 0;
4997 }
4998
4999 if (!context->isValidBufferBinding(target))
5000 {
5001 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
5002 return false;
5003 }
5004
5005 switch (pname)
5006 {
5007 case GL_BUFFER_MAP_POINTER:
5008 break;
5009
5010 default:
5011 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5012 return false;
5013 }
5014
5015 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
5016 // target bound to zero generate an INVALID_OPERATION error."
5017 // GLES 3.1 section 6.6 explicitly specifies this error.
5018 if (context->getState().getTargetBuffer(target) == nullptr)
5019 {
5020 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferPointerNotAvailable);
5021 return false;
5022 }
5023
5024 if (length)
5025 {
5026 *length = 1;
5027 }
5028
5029 return true;
5030 }
5031
ValidateUnmapBufferBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target)5032 bool ValidateUnmapBufferBase(const Context *context,
5033 angle::EntryPoint entryPoint,
5034 BufferBinding target)
5035 {
5036 if (!context->isValidBufferBinding(target))
5037 {
5038 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
5039 return false;
5040 }
5041
5042 Buffer *buffer = context->getState().getTargetBuffer(target);
5043
5044 if (buffer == nullptr || !buffer->isMapped())
5045 {
5046 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferNotMapped);
5047 return false;
5048 }
5049
5050 return true;
5051 }
5052
ValidateMapBufferRangeBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLintptr offset,GLsizeiptr length,GLbitfield access)5053 bool ValidateMapBufferRangeBase(const Context *context,
5054 angle::EntryPoint entryPoint,
5055 BufferBinding target,
5056 GLintptr offset,
5057 GLsizeiptr length,
5058 GLbitfield access)
5059 {
5060 if (!context->isValidBufferBinding(target))
5061 {
5062 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
5063 return false;
5064 }
5065
5066 if (offset < 0)
5067 {
5068 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeOffset);
5069 return false;
5070 }
5071
5072 if (length < 0)
5073 {
5074 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeLength);
5075 return false;
5076 }
5077
5078 Buffer *buffer = context->getState().getTargetBuffer(target);
5079
5080 if (!buffer)
5081 {
5082 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferNotMappable);
5083 return false;
5084 }
5085
5086 // Check for buffer overflow
5087 CheckedNumeric<size_t> checkedOffset(offset);
5088 auto checkedSize = checkedOffset + length;
5089
5090 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
5091 {
5092 context->validationError(entryPoint, GL_INVALID_VALUE, kMapOutOfRange);
5093 return false;
5094 }
5095
5096 // Check for invalid bits in the mask
5097 constexpr GLbitfield kAllAccessBits =
5098 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
5099 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
5100
5101 if (buffer->isImmutable())
5102 {
5103 // GL_EXT_buffer_storage's additions to glMapBufferRange
5104 constexpr GLbitfield kBufferStorageAccessBits =
5105 kAllAccessBits | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT;
5106
5107 if ((access & ~kBufferStorageAccessBits) != 0)
5108 {
5109 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidAccessBits);
5110 return false;
5111 }
5112
5113 // It is invalid if any of bufferStorageMatchedAccessBits bits are included in access,
5114 // but the same bits are not included in the buffer's storage flags
5115 constexpr GLbitfield kBufferStorageMatchedAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT |
5116 GL_MAP_PERSISTENT_BIT_EXT |
5117 GL_MAP_COHERENT_BIT_EXT;
5118 GLbitfield accessFlags = access & kBufferStorageMatchedAccessBits;
5119 if ((accessFlags & buffer->getStorageExtUsageFlags()) != accessFlags)
5120 {
5121 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAccessBits);
5122 return false;
5123 }
5124 }
5125 else if ((access & ~kAllAccessBits) != 0)
5126 {
5127 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidAccessBits);
5128 return false;
5129 }
5130
5131 if (length == 0)
5132 {
5133 context->validationError(entryPoint, GL_INVALID_OPERATION, kLengthZero);
5134 return false;
5135 }
5136
5137 if (buffer->isMapped())
5138 {
5139 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferAlreadyMapped);
5140 return false;
5141 }
5142
5143 // Check for invalid bit combinations
5144 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
5145 {
5146 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAccessBitsReadWrite);
5147 return false;
5148 }
5149
5150 GLbitfield writeOnlyBits =
5151 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
5152
5153 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
5154 {
5155 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAccessBitsRead);
5156 return false;
5157 }
5158
5159 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
5160 {
5161 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAccessBitsFlush);
5162 return false;
5163 }
5164
5165 return ValidateMapBufferBase(context, entryPoint, target);
5166 }
5167
ValidateFlushMappedBufferRangeBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLintptr offset,GLsizeiptr length)5168 bool ValidateFlushMappedBufferRangeBase(const Context *context,
5169 angle::EntryPoint entryPoint,
5170 BufferBinding target,
5171 GLintptr offset,
5172 GLsizeiptr length)
5173 {
5174 if (offset < 0)
5175 {
5176 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeOffset);
5177 return false;
5178 }
5179
5180 if (length < 0)
5181 {
5182 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeLength);
5183 return false;
5184 }
5185
5186 if (!context->isValidBufferBinding(target))
5187 {
5188 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
5189 return false;
5190 }
5191
5192 Buffer *buffer = context->getState().getTargetBuffer(target);
5193
5194 if (buffer == nullptr)
5195 {
5196 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFlushZero);
5197 return false;
5198 }
5199
5200 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
5201 {
5202 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFlushTarget);
5203 return false;
5204 }
5205
5206 // Check for buffer overflow
5207 CheckedNumeric<size_t> checkedOffset(offset);
5208 auto checkedSize = checkedOffset + length;
5209
5210 if (!checkedSize.IsValid() ||
5211 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
5212 {
5213 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidFlushOutOfRange);
5214 return false;
5215 }
5216
5217 return true;
5218 }
5219
ValidateGenOrDelete(const Context * context,angle::EntryPoint entryPoint,GLint n)5220 bool ValidateGenOrDelete(const Context *context, angle::EntryPoint entryPoint, GLint n)
5221 {
5222 if (n < 0)
5223 {
5224 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeCount);
5225 return false;
5226 }
5227 return true;
5228 }
5229
ValidateRobustEntryPoint(const Context * context,angle::EntryPoint entryPoint,GLsizei bufSize)5230 bool ValidateRobustEntryPoint(const Context *context, angle::EntryPoint entryPoint, GLsizei bufSize)
5231 {
5232 if (!context->getExtensions().robustClientMemoryANGLE)
5233 {
5234 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
5235 return false;
5236 }
5237
5238 if (bufSize < 0)
5239 {
5240 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeBufferSize);
5241 return false;
5242 }
5243
5244 return true;
5245 }
5246
ValidateRobustBufferSize(const Context * context,angle::EntryPoint entryPoint,GLsizei bufSize,GLsizei numParams)5247 bool ValidateRobustBufferSize(const Context *context,
5248 angle::EntryPoint entryPoint,
5249 GLsizei bufSize,
5250 GLsizei numParams)
5251 {
5252 if (bufSize < numParams)
5253 {
5254 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientParams);
5255 return false;
5256 }
5257
5258 return true;
5259 }
5260
ValidateGetFramebufferAttachmentParameterivBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum attachment,GLenum pname,GLsizei * numParams)5261 bool ValidateGetFramebufferAttachmentParameterivBase(const Context *context,
5262 angle::EntryPoint entryPoint,
5263 GLenum target,
5264 GLenum attachment,
5265 GLenum pname,
5266 GLsizei *numParams)
5267 {
5268 if (!ValidFramebufferTarget(context, target))
5269 {
5270 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFramebufferTarget);
5271 return false;
5272 }
5273
5274 int clientVersion = context->getClientMajorVersion();
5275
5276 switch (pname)
5277 {
5278 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5279 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5280 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5281 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5282 break;
5283
5284 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR:
5285 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR:
5286 if (clientVersion < 3 ||
5287 !(context->getExtensions().multiviewOVR || context->getExtensions().multiview2OVR))
5288 {
5289 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5290 return false;
5291 }
5292 break;
5293
5294 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT:
5295 if (!context->getExtensions().multisampledRenderToTextureEXT)
5296 {
5297 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5298 return false;
5299 }
5300 break;
5301
5302 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
5303 if (clientVersion < 3 && !context->getExtensions().sRGBEXT)
5304 {
5305 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5306 return false;
5307 }
5308 break;
5309
5310 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
5311 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
5312 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
5313 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
5314 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
5315 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
5316 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5317 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5318 if (clientVersion < 3)
5319 {
5320 context->validationError(entryPoint, GL_INVALID_ENUM, kES3Required);
5321 return false;
5322 }
5323 break;
5324
5325 case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT:
5326 if (!context->getExtensions().geometryShaderAny() &&
5327 context->getClientVersion() < ES_3_2)
5328 {
5329 context->validationError(entryPoint, GL_INVALID_ENUM,
5330 kGeometryShaderExtensionNotEnabled);
5331 return false;
5332 }
5333 break;
5334
5335 default:
5336 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
5337 return false;
5338 }
5339
5340 // Determine if the attachment is a valid enum
5341 switch (attachment)
5342 {
5343 case GL_BACK:
5344 case GL_DEPTH:
5345 case GL_STENCIL:
5346 if (clientVersion < 3)
5347 {
5348 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
5349 return false;
5350 }
5351 break;
5352
5353 case GL_DEPTH_STENCIL_ATTACHMENT:
5354 if (clientVersion < 3 && !context->isWebGL1())
5355 {
5356 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
5357 return false;
5358 }
5359 break;
5360
5361 case GL_COLOR_ATTACHMENT0:
5362 case GL_DEPTH_ATTACHMENT:
5363 case GL_STENCIL_ATTACHMENT:
5364 break;
5365
5366 default:
5367 if ((clientVersion < 3 && !context->getExtensions().drawBuffersEXT) ||
5368 attachment < GL_COLOR_ATTACHMENT0_EXT ||
5369 (attachment - GL_COLOR_ATTACHMENT0_EXT) >=
5370 static_cast<GLuint>(context->getCaps().maxColorAttachments))
5371 {
5372 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidAttachment);
5373 return false;
5374 }
5375 break;
5376 }
5377
5378 const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
5379 ASSERT(framebuffer);
5380
5381 if (framebuffer->isDefault())
5382 {
5383 if (clientVersion < 3)
5384 {
5385 context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultFramebufferTarget);
5386 return false;
5387 }
5388
5389 switch (attachment)
5390 {
5391 case GL_BACK:
5392 case GL_DEPTH:
5393 case GL_STENCIL:
5394 break;
5395
5396 default:
5397 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAttachment);
5398 return false;
5399 }
5400 }
5401 else
5402 {
5403 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
5404 {
5405 // Valid attachment query
5406 }
5407 else
5408 {
5409 switch (attachment)
5410 {
5411 case GL_DEPTH_ATTACHMENT:
5412 case GL_STENCIL_ATTACHMENT:
5413 break;
5414
5415 case GL_DEPTH_STENCIL_ATTACHMENT:
5416 if (!framebuffer->hasValidDepthStencil() && !context->isWebGL1())
5417 {
5418 context->validationError(entryPoint, GL_INVALID_OPERATION,
5419 kInvalidAttachment);
5420 return false;
5421 }
5422 break;
5423
5424 default:
5425 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAttachment);
5426 return false;
5427 }
5428 }
5429 }
5430
5431 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(context, attachment);
5432 if (attachmentObject)
5433 {
5434 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
5435 attachmentObject->type() == GL_TEXTURE ||
5436 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
5437
5438 switch (pname)
5439 {
5440 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5441 if (attachmentObject->type() != GL_RENDERBUFFER &&
5442 attachmentObject->type() != GL_TEXTURE)
5443 {
5444 context->validationError(entryPoint, GL_INVALID_ENUM,
5445 kFramebufferIncompleteAttachment);
5446 return false;
5447 }
5448 break;
5449
5450 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5451 if (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_CUBE_MAP_FACE:
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_COMPONENT_TYPE:
5469 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
5470 {
5471 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidAttachment);
5472 return false;
5473 }
5474 break;
5475
5476 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5477 if (attachmentObject->type() != GL_TEXTURE)
5478 {
5479 context->validationError(entryPoint, GL_INVALID_ENUM,
5480 kFramebufferIncompleteAttachment);
5481 return false;
5482 }
5483 break;
5484
5485 default:
5486 break;
5487 }
5488 }
5489 else
5490 {
5491 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
5492 // is NONE, then querying any other pname will generate INVALID_ENUM.
5493
5494 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
5495 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
5496 // INVALID_OPERATION for all other pnames
5497
5498 switch (pname)
5499 {
5500 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5501 break;
5502
5503 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5504 if (clientVersion < 3)
5505 {
5506 context->validationError(entryPoint, GL_INVALID_ENUM,
5507 kInvalidFramebufferAttachmentParameter);
5508 return false;
5509 }
5510 break;
5511
5512 default:
5513 if (clientVersion < 3)
5514 {
5515 context->validationError(entryPoint, GL_INVALID_ENUM,
5516 kInvalidFramebufferAttachmentParameter);
5517 return false;
5518 }
5519 else
5520 {
5521 context->validationError(entryPoint, GL_INVALID_OPERATION,
5522 kInvalidFramebufferAttachmentParameter);
5523 return false;
5524 }
5525 }
5526 }
5527
5528 if (numParams)
5529 {
5530 *numParams = 1;
5531 }
5532
5533 return true;
5534 }
5535
ValidateGetFramebufferAttachmentParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum attachment,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5536 bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(const Context *context,
5537 angle::EntryPoint entryPoint,
5538 GLenum target,
5539 GLenum attachment,
5540 GLenum pname,
5541 GLsizei bufSize,
5542 const GLsizei *length,
5543 const GLint *params)
5544 {
5545 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5546 {
5547 return false;
5548 }
5549
5550 GLsizei numParams = 0;
5551 if (!ValidateGetFramebufferAttachmentParameterivBase(context, entryPoint, target, attachment,
5552 pname, &numParams))
5553 {
5554 return false;
5555 }
5556
5557 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5558 {
5559 return false;
5560 }
5561
5562 SetRobustLengthParam(length, numParams);
5563
5564 return true;
5565 }
5566
ValidateGetBufferParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5567 bool ValidateGetBufferParameterivRobustANGLE(const Context *context,
5568 angle::EntryPoint entryPoint,
5569 BufferBinding target,
5570 GLenum pname,
5571 GLsizei bufSize,
5572 const GLsizei *length,
5573 const GLint *params)
5574 {
5575 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5576 {
5577 return false;
5578 }
5579
5580 GLsizei numParams = 0;
5581
5582 if (!ValidateGetBufferParameterBase(context, entryPoint, target, pname, false, &numParams))
5583 {
5584 return false;
5585 }
5586
5587 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5588 {
5589 return false;
5590 }
5591
5592 SetRobustLengthParam(length, numParams);
5593 return true;
5594 }
5595
ValidateGetBufferParameteri64vRobustANGLE(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint64 * params)5596 bool ValidateGetBufferParameteri64vRobustANGLE(const Context *context,
5597 angle::EntryPoint entryPoint,
5598 BufferBinding target,
5599 GLenum pname,
5600 GLsizei bufSize,
5601 const GLsizei *length,
5602 const GLint64 *params)
5603 {
5604 GLsizei numParams = 0;
5605
5606 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5607 {
5608 return false;
5609 }
5610
5611 if (!ValidateGetBufferParameterBase(context, entryPoint, target, pname, false, &numParams))
5612 {
5613 return false;
5614 }
5615
5616 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5617 {
5618 return false;
5619 }
5620
5621 SetRobustLengthParam(length, numParams);
5622
5623 return true;
5624 }
5625
ValidateGetProgramivBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,GLenum pname,GLsizei * numParams)5626 bool ValidateGetProgramivBase(const Context *context,
5627 angle::EntryPoint entryPoint,
5628 ShaderProgramID program,
5629 GLenum pname,
5630 GLsizei *numParams)
5631 {
5632 // Currently, all GetProgramiv queries return 1 parameter
5633 if (numParams)
5634 {
5635 *numParams = 1;
5636 }
5637
5638 if (context->isContextLost())
5639 {
5640 context->validationError(entryPoint, GL_CONTEXT_LOST, kContextLost);
5641
5642 if (context->getExtensions().parallelShaderCompileKHR && pname == GL_COMPLETION_STATUS_KHR)
5643 {
5644 // Generate an error but still return true, the context still needs to return a
5645 // value in this case.
5646 return true;
5647 }
5648 else
5649 {
5650 return false;
5651 }
5652 }
5653
5654 // Special case for GL_COMPLETION_STATUS_KHR: don't resolve the link. Otherwise resolve it now.
5655 Program *programObject = (pname == GL_COMPLETION_STATUS_KHR)
5656 ? GetValidProgramNoResolve(context, entryPoint, program)
5657 : GetValidProgram(context, entryPoint, program);
5658 if (!programObject)
5659 {
5660 return false;
5661 }
5662
5663 switch (pname)
5664 {
5665 case GL_DELETE_STATUS:
5666 case GL_LINK_STATUS:
5667 case GL_VALIDATE_STATUS:
5668 case GL_INFO_LOG_LENGTH:
5669 case GL_ATTACHED_SHADERS:
5670 case GL_ACTIVE_ATTRIBUTES:
5671 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
5672 case GL_ACTIVE_UNIFORMS:
5673 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
5674 break;
5675
5676 case GL_PROGRAM_BINARY_LENGTH:
5677 if (context->getClientMajorVersion() < 3 &&
5678 !context->getExtensions().getProgramBinaryOES)
5679 {
5680 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5681 return false;
5682 }
5683 break;
5684
5685 case GL_ACTIVE_UNIFORM_BLOCKS:
5686 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
5687 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
5688 case GL_TRANSFORM_FEEDBACK_VARYINGS:
5689 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
5690 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
5691 if (context->getClientMajorVersion() < 3)
5692 {
5693 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES30);
5694 return false;
5695 }
5696 break;
5697
5698 case GL_PROGRAM_SEPARABLE:
5699 case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS:
5700 if (context->getClientVersion() < Version(3, 1))
5701 {
5702 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
5703 return false;
5704 }
5705 break;
5706
5707 case GL_COMPUTE_WORK_GROUP_SIZE:
5708 if (context->getClientVersion() < Version(3, 1))
5709 {
5710 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
5711 return false;
5712 }
5713
5714 // [OpenGL ES 3.1] Chapter 7.12 Page 122
5715 // An INVALID_OPERATION error is generated if COMPUTE_WORK_GROUP_SIZE is queried for a
5716 // program which has not been linked successfully, or which does not contain objects to
5717 // form a compute shader.
5718 if (!programObject->isLinked())
5719 {
5720 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
5721 return false;
5722 }
5723 if (!programObject->getExecutable().hasLinkedShaderStage(ShaderType::Compute))
5724 {
5725 context->validationError(entryPoint, GL_INVALID_OPERATION,
5726 kNoActiveComputeShaderStage);
5727 return false;
5728 }
5729 break;
5730
5731 case GL_GEOMETRY_LINKED_INPUT_TYPE_EXT:
5732 case GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT:
5733 case GL_GEOMETRY_LINKED_VERTICES_OUT_EXT:
5734 case GL_GEOMETRY_SHADER_INVOCATIONS_EXT:
5735 if (!context->getExtensions().geometryShaderAny() &&
5736 context->getClientVersion() < ES_3_2)
5737 {
5738 context->validationError(entryPoint, GL_INVALID_ENUM,
5739 kGeometryShaderExtensionNotEnabled);
5740 return false;
5741 }
5742
5743 // [EXT_geometry_shader] Chapter 7.12
5744 // An INVALID_OPERATION error is generated if GEOMETRY_LINKED_VERTICES_OUT_EXT,
5745 // GEOMETRY_LINKED_INPUT_TYPE_EXT, GEOMETRY_LINKED_OUTPUT_TYPE_EXT, or
5746 // GEOMETRY_SHADER_INVOCATIONS_EXT are queried for a program which has not been linked
5747 // successfully, or which does not contain objects to form a geometry shader.
5748 if (!programObject->isLinked())
5749 {
5750 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
5751 return false;
5752 }
5753 if (!programObject->getExecutable().hasLinkedShaderStage(ShaderType::Geometry))
5754 {
5755 context->validationError(entryPoint, GL_INVALID_OPERATION,
5756 kNoActiveGeometryShaderStage);
5757 return false;
5758 }
5759 break;
5760
5761 case GL_COMPLETION_STATUS_KHR:
5762 if (!context->getExtensions().parallelShaderCompileKHR)
5763 {
5764 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
5765 return false;
5766 }
5767 break;
5768 case GL_TESS_CONTROL_OUTPUT_VERTICES_EXT:
5769 case GL_TESS_GEN_MODE_EXT:
5770 case GL_TESS_GEN_SPACING_EXT:
5771 case GL_TESS_GEN_VERTEX_ORDER_EXT:
5772 case GL_TESS_GEN_POINT_MODE_EXT:
5773 if (!context->getExtensions().tessellationShaderEXT &&
5774 context->getClientVersion() < ES_3_2)
5775 {
5776 context->validationError(entryPoint, GL_INVALID_ENUM,
5777 kTessellationShaderExtensionNotEnabled);
5778 return false;
5779 }
5780 if (!programObject->isLinked())
5781 {
5782 context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
5783 return false;
5784 }
5785 break;
5786 default:
5787 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
5788 return false;
5789 }
5790
5791 return true;
5792 }
5793
ValidateGetProgramivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5794 bool ValidateGetProgramivRobustANGLE(const Context *context,
5795 angle::EntryPoint entryPoint,
5796 ShaderProgramID program,
5797 GLenum pname,
5798 GLsizei bufSize,
5799 const GLsizei *length,
5800 const GLint *params)
5801 {
5802 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5803 {
5804 return false;
5805 }
5806
5807 GLsizei numParams = 0;
5808
5809 if (!ValidateGetProgramivBase(context, entryPoint, program, pname, &numParams))
5810 {
5811 return false;
5812 }
5813
5814 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5815 {
5816 return false;
5817 }
5818
5819 SetRobustLengthParam(length, numParams);
5820
5821 return true;
5822 }
5823
ValidateGetRenderbufferParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5824 bool ValidateGetRenderbufferParameterivRobustANGLE(const Context *context,
5825 angle::EntryPoint entryPoint,
5826 GLenum target,
5827 GLenum pname,
5828 GLsizei bufSize,
5829 const GLsizei *length,
5830 const GLint *params)
5831 {
5832 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5833 {
5834 return false;
5835 }
5836
5837 GLsizei numParams = 0;
5838
5839 if (!ValidateGetRenderbufferParameterivBase(context, entryPoint, target, pname, &numParams))
5840 {
5841 return false;
5842 }
5843
5844 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5845 {
5846 return false;
5847 }
5848
5849 SetRobustLengthParam(length, numParams);
5850
5851 return true;
5852 }
5853
ValidateGetShaderivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID shader,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5854 bool ValidateGetShaderivRobustANGLE(const Context *context,
5855 angle::EntryPoint entryPoint,
5856 ShaderProgramID shader,
5857 GLenum pname,
5858 GLsizei bufSize,
5859 const GLsizei *length,
5860 const GLint *params)
5861 {
5862 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5863 {
5864 return false;
5865 }
5866
5867 GLsizei numParams = 0;
5868
5869 if (!ValidateGetShaderivBase(context, entryPoint, shader, pname, &numParams))
5870 {
5871 return false;
5872 }
5873
5874 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5875 {
5876 return false;
5877 }
5878
5879 SetRobustLengthParam(length, numParams);
5880
5881 return true;
5882 }
5883
ValidateGetTexParameterfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLfloat * params)5884 bool ValidateGetTexParameterfvRobustANGLE(const Context *context,
5885 angle::EntryPoint entryPoint,
5886 TextureType target,
5887 GLenum pname,
5888 GLsizei bufSize,
5889 const GLsizei *length,
5890 const GLfloat *params)
5891 {
5892 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5893 {
5894 return false;
5895 }
5896
5897 GLsizei numParams = 0;
5898
5899 if (!ValidateGetTexParameterBase(context, entryPoint, target, pname, &numParams))
5900 {
5901 return false;
5902 }
5903
5904 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5905 {
5906 return false;
5907 }
5908
5909 SetRobustLengthParam(length, numParams);
5910
5911 return true;
5912 }
5913
ValidateGetTexParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5914 bool ValidateGetTexParameterivRobustANGLE(const Context *context,
5915 angle::EntryPoint entryPoint,
5916 TextureType target,
5917 GLenum pname,
5918 GLsizei bufSize,
5919 const GLsizei *length,
5920 const GLint *params)
5921 {
5922
5923 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5924 {
5925 return false;
5926 }
5927 GLsizei numParams = 0;
5928 if (!ValidateGetTexParameterBase(context, entryPoint, target, pname, &numParams))
5929 {
5930 return false;
5931 }
5932
5933 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
5934 {
5935 return false;
5936 }
5937
5938 SetRobustLengthParam(length, numParams);
5939 return true;
5940 }
5941
ValidateGetTexParameterIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)5942 bool ValidateGetTexParameterIivRobustANGLE(const Context *context,
5943 angle::EntryPoint entryPoint,
5944 TextureType target,
5945 GLenum pname,
5946 GLsizei bufSize,
5947 const GLsizei *length,
5948 const GLint *params)
5949 {
5950 UNIMPLEMENTED();
5951 return false;
5952 }
5953
ValidateGetTexParameterIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLuint * params)5954 bool ValidateGetTexParameterIuivRobustANGLE(const Context *context,
5955 angle::EntryPoint entryPoint,
5956 TextureType target,
5957 GLenum pname,
5958 GLsizei bufSize,
5959 const GLsizei *length,
5960 const GLuint *params)
5961 {
5962 UNIMPLEMENTED();
5963 return false;
5964 }
5965
ValidateTexParameterfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLfloat * params)5966 bool ValidateTexParameterfvRobustANGLE(const Context *context,
5967 angle::EntryPoint entryPoint,
5968 TextureType target,
5969 GLenum pname,
5970 GLsizei bufSize,
5971 const GLfloat *params)
5972 {
5973 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5974 {
5975 return false;
5976 }
5977
5978 return ValidateTexParameterBase(context, entryPoint, target, pname, bufSize, true, params);
5979 }
5980
ValidateTexParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLint * params)5981 bool ValidateTexParameterivRobustANGLE(const Context *context,
5982 angle::EntryPoint entryPoint,
5983 TextureType target,
5984 GLenum pname,
5985 GLsizei bufSize,
5986 const GLint *params)
5987 {
5988 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
5989 {
5990 return false;
5991 }
5992
5993 return ValidateTexParameterBase(context, entryPoint, target, pname, bufSize, true, params);
5994 }
5995
ValidateTexParameterIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLint * params)5996 bool ValidateTexParameterIivRobustANGLE(const Context *context,
5997 angle::EntryPoint entryPoint,
5998 TextureType target,
5999 GLenum pname,
6000 GLsizei bufSize,
6001 const GLint *params)
6002 {
6003 UNIMPLEMENTED();
6004 return false;
6005 }
6006
ValidateTexParameterIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,const GLuint * params)6007 bool ValidateTexParameterIuivRobustANGLE(const Context *context,
6008 angle::EntryPoint entryPoint,
6009 TextureType target,
6010 GLenum pname,
6011 GLsizei bufSize,
6012 const GLuint *params)
6013 {
6014 UNIMPLEMENTED();
6015 return false;
6016 }
6017
ValidateGetSamplerParameterfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLfloat * params)6018 bool ValidateGetSamplerParameterfvRobustANGLE(const Context *context,
6019 angle::EntryPoint entryPoint,
6020 SamplerID sampler,
6021 GLenum pname,
6022 GLsizei bufSize,
6023 const GLsizei *length,
6024 const GLfloat *params)
6025 {
6026 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6027 {
6028 return false;
6029 }
6030
6031 GLsizei numParams = 0;
6032
6033 if (!ValidateGetSamplerParameterBase(context, entryPoint, sampler, pname, &numParams))
6034 {
6035 return false;
6036 }
6037
6038 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
6039 {
6040 return false;
6041 }
6042
6043 SetRobustLengthParam(length, numParams);
6044 return true;
6045 }
6046
ValidateGetSamplerParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6047 bool ValidateGetSamplerParameterivRobustANGLE(const Context *context,
6048 angle::EntryPoint entryPoint,
6049 SamplerID sampler,
6050 GLenum pname,
6051 GLsizei bufSize,
6052 const GLsizei *length,
6053 const GLint *params)
6054 {
6055 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6056 {
6057 return false;
6058 }
6059
6060 GLsizei numParams = 0;
6061
6062 if (!ValidateGetSamplerParameterBase(context, entryPoint, sampler, pname, &numParams))
6063 {
6064 return false;
6065 }
6066
6067 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
6068 {
6069 return false;
6070 }
6071
6072 SetRobustLengthParam(length, numParams);
6073 return true;
6074 }
6075
ValidateGetSamplerParameterIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6076 bool ValidateGetSamplerParameterIivRobustANGLE(const Context *context,
6077 angle::EntryPoint entryPoint,
6078 SamplerID sampler,
6079 GLenum pname,
6080 GLsizei bufSize,
6081 const GLsizei *length,
6082 const GLint *params)
6083 {
6084 UNIMPLEMENTED();
6085 return false;
6086 }
6087
ValidateGetSamplerParameterIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLuint * params)6088 bool ValidateGetSamplerParameterIuivRobustANGLE(const Context *context,
6089 angle::EntryPoint entryPoint,
6090 SamplerID sampler,
6091 GLenum pname,
6092 GLsizei bufSize,
6093 const GLsizei *length,
6094 const GLuint *params)
6095 {
6096 UNIMPLEMENTED();
6097 return false;
6098 }
6099
ValidateSamplerParameterfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLfloat * params)6100 bool ValidateSamplerParameterfvRobustANGLE(const Context *context,
6101 angle::EntryPoint entryPoint,
6102 SamplerID sampler,
6103 GLenum pname,
6104 GLsizei bufSize,
6105 const GLfloat *params)
6106 {
6107 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6108 {
6109 return false;
6110 }
6111
6112 return ValidateSamplerParameterBase(context, entryPoint, sampler, pname, bufSize, true, params);
6113 }
6114
ValidateSamplerParameterivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLint * params)6115 bool ValidateSamplerParameterivRobustANGLE(const Context *context,
6116 angle::EntryPoint entryPoint,
6117 SamplerID sampler,
6118 GLenum pname,
6119 GLsizei bufSize,
6120 const GLint *params)
6121 {
6122 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6123 {
6124 return false;
6125 }
6126
6127 return ValidateSamplerParameterBase(context, entryPoint, sampler, pname, bufSize, true, params);
6128 }
6129
ValidateSamplerParameterIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLint * param)6130 bool ValidateSamplerParameterIivRobustANGLE(const Context *context,
6131 angle::EntryPoint entryPoint,
6132 SamplerID sampler,
6133 GLenum pname,
6134 GLsizei bufSize,
6135 const GLint *param)
6136 {
6137 UNIMPLEMENTED();
6138 return false;
6139 }
6140
ValidateSamplerParameterIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,const GLuint * param)6141 bool ValidateSamplerParameterIuivRobustANGLE(const Context *context,
6142 angle::EntryPoint entryPoint,
6143 SamplerID sampler,
6144 GLenum pname,
6145 GLsizei bufSize,
6146 const GLuint *param)
6147 {
6148 UNIMPLEMENTED();
6149 return false;
6150 }
6151
ValidateGetVertexAttribfvRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLfloat * params)6152 bool ValidateGetVertexAttribfvRobustANGLE(const Context *context,
6153 angle::EntryPoint entryPoint,
6154 GLuint index,
6155 GLenum pname,
6156 GLsizei bufSize,
6157 const GLsizei *length,
6158 const GLfloat *params)
6159 {
6160 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6161 {
6162 return false;
6163 }
6164
6165 GLsizei writeLength = 0;
6166
6167 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, false, false))
6168 {
6169 return false;
6170 }
6171
6172 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6173 {
6174 return false;
6175 }
6176
6177 SetRobustLengthParam(length, writeLength);
6178 return true;
6179 }
6180
ValidateGetVertexAttribivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6181 bool ValidateGetVertexAttribivRobustANGLE(const Context *context,
6182 angle::EntryPoint entryPoint,
6183 GLuint index,
6184 GLenum pname,
6185 GLsizei bufSize,
6186 const GLsizei *length,
6187 const GLint *params)
6188 {
6189 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6190 {
6191 return false;
6192 }
6193
6194 GLsizei writeLength = 0;
6195
6196 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, false, false))
6197 {
6198 return false;
6199 }
6200
6201 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6202 {
6203 return false;
6204 }
6205
6206 SetRobustLengthParam(length, writeLength);
6207
6208 return true;
6209 }
6210
ValidateGetVertexAttribPointervRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,void * const * pointer)6211 bool ValidateGetVertexAttribPointervRobustANGLE(const Context *context,
6212 angle::EntryPoint entryPoint,
6213 GLuint index,
6214 GLenum pname,
6215 GLsizei bufSize,
6216 const GLsizei *length,
6217 void *const *pointer)
6218 {
6219 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6220 {
6221 return false;
6222 }
6223
6224 GLsizei writeLength = 0;
6225
6226 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, true, false))
6227 {
6228 return false;
6229 }
6230
6231 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6232 {
6233 return false;
6234 }
6235
6236 SetRobustLengthParam(length, writeLength);
6237
6238 return true;
6239 }
6240
ValidateGetVertexAttribIivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6241 bool ValidateGetVertexAttribIivRobustANGLE(const Context *context,
6242 angle::EntryPoint entryPoint,
6243 GLuint index,
6244 GLenum pname,
6245 GLsizei bufSize,
6246 const GLsizei *length,
6247 const GLint *params)
6248 {
6249 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6250 {
6251 return false;
6252 }
6253
6254 GLsizei writeLength = 0;
6255
6256 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, false, true))
6257 {
6258 return false;
6259 }
6260
6261 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6262 {
6263 return false;
6264 }
6265
6266 SetRobustLengthParam(length, writeLength);
6267
6268 return true;
6269 }
6270
ValidateGetVertexAttribIuivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLuint * params)6271 bool ValidateGetVertexAttribIuivRobustANGLE(const Context *context,
6272 angle::EntryPoint entryPoint,
6273 GLuint index,
6274 GLenum pname,
6275 GLsizei bufSize,
6276 const GLsizei *length,
6277 const GLuint *params)
6278 {
6279 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6280 {
6281 return false;
6282 }
6283
6284 GLsizei writeLength = 0;
6285
6286 if (!ValidateGetVertexAttribBase(context, entryPoint, index, pname, &writeLength, false, true))
6287 {
6288 return false;
6289 }
6290
6291 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6292 {
6293 return false;
6294 }
6295
6296 SetRobustLengthParam(length, writeLength);
6297
6298 return true;
6299 }
6300
ValidateGetActiveUniformBlockivRobustANGLE(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformBlockIndex uniformBlockIndex,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6301 bool ValidateGetActiveUniformBlockivRobustANGLE(const Context *context,
6302 angle::EntryPoint entryPoint,
6303 ShaderProgramID program,
6304 UniformBlockIndex uniformBlockIndex,
6305 GLenum pname,
6306 GLsizei bufSize,
6307 const GLsizei *length,
6308 const GLint *params)
6309 {
6310 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6311 {
6312 return false;
6313 }
6314
6315 GLsizei writeLength = 0;
6316
6317 if (!ValidateGetActiveUniformBlockivBase(context, entryPoint, program, uniformBlockIndex, pname,
6318 &writeLength))
6319 {
6320 return false;
6321 }
6322
6323 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, writeLength))
6324 {
6325 return false;
6326 }
6327
6328 SetRobustLengthParam(length, writeLength);
6329
6330 return true;
6331 }
6332
ValidateGetInternalformativRobustANGLE(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum internalformat,GLenum pname,GLsizei bufSize,const GLsizei * length,const GLint * params)6333 bool ValidateGetInternalformativRobustANGLE(const Context *context,
6334 angle::EntryPoint entryPoint,
6335 GLenum target,
6336 GLenum internalformat,
6337 GLenum pname,
6338 GLsizei bufSize,
6339 const GLsizei *length,
6340 const GLint *params)
6341 {
6342 if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
6343 {
6344 return false;
6345 }
6346
6347 GLsizei numParams = 0;
6348
6349 if (!ValidateGetInternalFormativBase(context, entryPoint, target, internalformat, pname,
6350 bufSize, &numParams))
6351 {
6352 return false;
6353 }
6354
6355 if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
6356 {
6357 return false;
6358 }
6359
6360 SetRobustLengthParam(length, numParams);
6361
6362 return true;
6363 }
6364
6365 // Perform validation from WebGL 2 section 5.10 "Invalid Clears":
6366 // In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
6367 // specified clear value and the type of a buffer that is being cleared generates an
6368 // INVALID_OPERATION error instead of producing undefined results
ValidateWebGLFramebufferAttachmentClearType(const Context * context,angle::EntryPoint entryPoint,GLint drawbuffer,const GLenum * validComponentTypes,size_t validComponentTypeCount)6369 bool ValidateWebGLFramebufferAttachmentClearType(const Context *context,
6370 angle::EntryPoint entryPoint,
6371 GLint drawbuffer,
6372 const GLenum *validComponentTypes,
6373 size_t validComponentTypeCount)
6374 {
6375 const FramebufferAttachment *attachment =
6376 context->getState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
6377 if (attachment)
6378 {
6379 GLenum componentType = attachment->getFormat().info->componentType;
6380 const GLenum *end = validComponentTypes + validComponentTypeCount;
6381 if (std::find(validComponentTypes, end, componentType) == end)
6382 {
6383 context->validationError(entryPoint, GL_INVALID_OPERATION, kNoDefinedClearConversion);
6384 return false;
6385 }
6386 }
6387
6388 return true;
6389 }
6390
ValidateRobustCompressedTexImageBase(const Context * context,angle::EntryPoint entryPoint,GLsizei imageSize,GLsizei dataSize)6391 bool ValidateRobustCompressedTexImageBase(const Context *context,
6392 angle::EntryPoint entryPoint,
6393 GLsizei imageSize,
6394 GLsizei dataSize)
6395 {
6396 if (!ValidateRobustEntryPoint(context, entryPoint, dataSize))
6397 {
6398 return false;
6399 }
6400
6401 Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
6402 if (pixelUnpackBuffer == nullptr)
6403 {
6404 if (dataSize < imageSize)
6405 {
6406 context->validationError(entryPoint, GL_INVALID_OPERATION, kCompressedDataSizeTooSmall);
6407 }
6408 }
6409 return true;
6410 }
6411
ValidateGetBufferParameterBase(const Context * context,angle::EntryPoint entryPoint,BufferBinding target,GLenum pname,bool pointerVersion,GLsizei * numParams)6412 bool ValidateGetBufferParameterBase(const Context *context,
6413 angle::EntryPoint entryPoint,
6414 BufferBinding target,
6415 GLenum pname,
6416 bool pointerVersion,
6417 GLsizei *numParams)
6418 {
6419 if (numParams)
6420 {
6421 *numParams = 0;
6422 }
6423
6424 if (!context->isValidBufferBinding(target))
6425 {
6426 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidBufferTypes);
6427 return false;
6428 }
6429
6430 const Buffer *buffer = context->getState().getTargetBuffer(target);
6431 if (!buffer)
6432 {
6433 // A null buffer means that "0" is bound to the requested buffer target
6434 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferNotBound);
6435 return false;
6436 }
6437
6438 const Extensions &extensions = context->getExtensions();
6439
6440 switch (pname)
6441 {
6442 case GL_BUFFER_USAGE:
6443 case GL_BUFFER_SIZE:
6444 break;
6445
6446 case GL_BUFFER_ACCESS_OES:
6447 if (!extensions.mapbufferOES)
6448 {
6449 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6450 return false;
6451 }
6452 break;
6453
6454 case GL_BUFFER_MAPPED:
6455 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
6456 if (context->getClientMajorVersion() < 3 && !extensions.mapbufferOES &&
6457 !extensions.mapBufferRangeEXT)
6458 {
6459 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6460 return false;
6461 }
6462 break;
6463
6464 case GL_BUFFER_MAP_POINTER:
6465 if (!pointerVersion)
6466 {
6467 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidMapPointerQuery);
6468 return false;
6469 }
6470 break;
6471
6472 case GL_BUFFER_ACCESS_FLAGS:
6473 case GL_BUFFER_MAP_OFFSET:
6474 case GL_BUFFER_MAP_LENGTH:
6475 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRangeEXT)
6476 {
6477 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6478 return false;
6479 }
6480 break;
6481
6482 case GL_MEMORY_SIZE_ANGLE:
6483 if (!context->getExtensions().memorySizeANGLE)
6484 {
6485 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6486 return false;
6487 }
6488 break;
6489
6490 case GL_RESOURCE_INITIALIZED_ANGLE:
6491 if (!context->getExtensions().robustResourceInitializationANGLE)
6492 {
6493 context->validationError(entryPoint, GL_INVALID_ENUM,
6494 kRobustResourceInitializationExtensionRequired);
6495 return false;
6496 }
6497 break;
6498
6499 default:
6500 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6501 return false;
6502 }
6503
6504 // All buffer parameter queries return one value.
6505 if (numParams)
6506 {
6507 *numParams = 1;
6508 }
6509
6510 return true;
6511 }
6512
ValidateGetRenderbufferParameterivBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum pname,GLsizei * length)6513 bool ValidateGetRenderbufferParameterivBase(const Context *context,
6514 angle::EntryPoint entryPoint,
6515 GLenum target,
6516 GLenum pname,
6517 GLsizei *length)
6518 {
6519 if (length)
6520 {
6521 *length = 0;
6522 }
6523
6524 if (target != GL_RENDERBUFFER)
6525 {
6526 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidRenderbufferTarget);
6527 return false;
6528 }
6529
6530 Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer();
6531 if (renderbuffer == nullptr)
6532 {
6533 context->validationError(entryPoint, GL_INVALID_OPERATION, kRenderbufferNotBound);
6534 return false;
6535 }
6536
6537 switch (pname)
6538 {
6539 case GL_RENDERBUFFER_WIDTH:
6540 case GL_RENDERBUFFER_HEIGHT:
6541 case GL_RENDERBUFFER_INTERNAL_FORMAT:
6542 case GL_RENDERBUFFER_RED_SIZE:
6543 case GL_RENDERBUFFER_GREEN_SIZE:
6544 case GL_RENDERBUFFER_BLUE_SIZE:
6545 case GL_RENDERBUFFER_ALPHA_SIZE:
6546 case GL_RENDERBUFFER_DEPTH_SIZE:
6547 case GL_RENDERBUFFER_STENCIL_SIZE:
6548 break;
6549
6550 case GL_RENDERBUFFER_SAMPLES_ANGLE:
6551 if (!context->getExtensions().framebufferMultisampleANGLE)
6552 {
6553 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6554 return false;
6555 }
6556 break;
6557
6558 case GL_MEMORY_SIZE_ANGLE:
6559 if (!context->getExtensions().memorySizeANGLE)
6560 {
6561 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6562 return false;
6563 }
6564 break;
6565
6566 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
6567 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
6568 if (!context->getExtensions().getImageANGLE)
6569 {
6570 context->validationError(entryPoint, GL_INVALID_ENUM, kGetImageExtensionNotEnabled);
6571 return false;
6572 }
6573 break;
6574
6575 case GL_RESOURCE_INITIALIZED_ANGLE:
6576 if (!context->getExtensions().robustResourceInitializationANGLE)
6577 {
6578 context->validationError(entryPoint, GL_INVALID_ENUM,
6579 kRobustResourceInitializationExtensionRequired);
6580 return false;
6581 }
6582 break;
6583
6584 default:
6585 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6586 return false;
6587 }
6588
6589 if (length)
6590 {
6591 *length = 1;
6592 }
6593 return true;
6594 }
6595
ValidateGetShaderivBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID shader,GLenum pname,GLsizei * length)6596 bool ValidateGetShaderivBase(const Context *context,
6597 angle::EntryPoint entryPoint,
6598 ShaderProgramID shader,
6599 GLenum pname,
6600 GLsizei *length)
6601 {
6602 if (length)
6603 {
6604 *length = 0;
6605 }
6606
6607 if (context->isContextLost())
6608 {
6609 context->validationError(entryPoint, GL_CONTEXT_LOST, kContextLost);
6610
6611 if (context->getExtensions().parallelShaderCompileKHR && pname == GL_COMPLETION_STATUS_KHR)
6612 {
6613 // Generate an error but still return true, the context still needs to return a
6614 // value in this case.
6615 return true;
6616 }
6617 else
6618 {
6619 return false;
6620 }
6621 }
6622
6623 if (GetValidShader(context, entryPoint, shader) == nullptr)
6624 {
6625 return false;
6626 }
6627
6628 switch (pname)
6629 {
6630 case GL_SHADER_TYPE:
6631 case GL_DELETE_STATUS:
6632 case GL_COMPILE_STATUS:
6633 case GL_INFO_LOG_LENGTH:
6634 case GL_SHADER_SOURCE_LENGTH:
6635 break;
6636
6637 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
6638 if (!context->getExtensions().translatedShaderSourceANGLE)
6639 {
6640 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6641 return false;
6642 }
6643 break;
6644
6645 case GL_COMPLETION_STATUS_KHR:
6646 if (!context->getExtensions().parallelShaderCompileKHR)
6647 {
6648 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
6649 return false;
6650 }
6651 break;
6652
6653 default:
6654 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6655 return false;
6656 }
6657
6658 if (length)
6659 {
6660 *length = 1;
6661 }
6662 return true;
6663 }
6664
ValidateGetTexParameterBase(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei * length)6665 bool ValidateGetTexParameterBase(const Context *context,
6666 angle::EntryPoint entryPoint,
6667 TextureType target,
6668 GLenum pname,
6669 GLsizei *length)
6670 {
6671 if (length)
6672 {
6673 *length = 0;
6674 }
6675
6676 if ((!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) ||
6677 target == TextureType::Buffer)
6678 {
6679 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
6680 return false;
6681 }
6682
6683 if (context->getTextureByType(target) == nullptr)
6684 {
6685 // Should only be possible for external textures
6686 context->validationError(entryPoint, GL_INVALID_ENUM, kTextureNotBound);
6687 return false;
6688 }
6689
6690 if (context->getClientMajorVersion() == 1 && !IsValidGLES1TextureParameter(pname))
6691 {
6692 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6693 return false;
6694 }
6695
6696 switch (pname)
6697 {
6698 case GL_TEXTURE_MAG_FILTER:
6699 case GL_TEXTURE_MIN_FILTER:
6700 case GL_TEXTURE_WRAP_S:
6701 case GL_TEXTURE_WRAP_T:
6702 break;
6703
6704 case GL_TEXTURE_USAGE_ANGLE:
6705 if (!context->getExtensions().textureUsageANGLE)
6706 {
6707 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6708 return false;
6709 }
6710 break;
6711
6712 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
6713 if (!ValidateTextureMaxAnisotropyExtensionEnabled(context, entryPoint))
6714 {
6715 return false;
6716 }
6717 break;
6718
6719 case GL_TEXTURE_IMMUTABLE_FORMAT:
6720 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorageEXT)
6721 {
6722 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6723 return false;
6724 }
6725 break;
6726
6727 case GL_TEXTURE_WRAP_R:
6728 case GL_TEXTURE_IMMUTABLE_LEVELS:
6729 case GL_TEXTURE_SWIZZLE_R:
6730 case GL_TEXTURE_SWIZZLE_G:
6731 case GL_TEXTURE_SWIZZLE_B:
6732 case GL_TEXTURE_SWIZZLE_A:
6733 case GL_TEXTURE_BASE_LEVEL:
6734 case GL_TEXTURE_MAX_LEVEL:
6735 case GL_TEXTURE_MIN_LOD:
6736 case GL_TEXTURE_MAX_LOD:
6737 if (context->getClientMajorVersion() < 3)
6738 {
6739 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES30);
6740 return false;
6741 }
6742 break;
6743
6744 case GL_TEXTURE_COMPARE_MODE:
6745 case GL_TEXTURE_COMPARE_FUNC:
6746 if (context->getClientMajorVersion() < 3 && !context->getExtensions().shadowSamplersEXT)
6747 {
6748 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6749 return false;
6750 }
6751 break;
6752
6753 case GL_TEXTURE_SRGB_DECODE_EXT:
6754 if (!context->getExtensions().textureSRGBDecodeEXT)
6755 {
6756 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6757 return false;
6758 }
6759 break;
6760
6761 case GL_DEPTH_STENCIL_TEXTURE_MODE:
6762 case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE:
6763 if (context->getClientVersion() < ES_3_1)
6764 {
6765 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
6766 return false;
6767 }
6768 break;
6769
6770 case GL_GENERATE_MIPMAP:
6771 case GL_TEXTURE_CROP_RECT_OES:
6772 // TODO(lfy@google.com): Restrict to GL_OES_draw_texture
6773 // after GL_OES_draw_texture functionality implemented
6774 if (context->getClientMajorVersion() > 1)
6775 {
6776 context->validationError(entryPoint, GL_INVALID_ENUM, kGLES1Only);
6777 return false;
6778 }
6779 break;
6780
6781 case GL_MEMORY_SIZE_ANGLE:
6782 if (!context->getExtensions().memorySizeANGLE)
6783 {
6784 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6785 return false;
6786 }
6787 break;
6788
6789 case GL_TEXTURE_BORDER_COLOR:
6790 if (!context->getExtensions().textureBorderClampOES &&
6791 context->getClientVersion() < ES_3_2)
6792 {
6793 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6794 return false;
6795 }
6796 break;
6797
6798 case GL_TEXTURE_NATIVE_ID_ANGLE:
6799 if (!context->getExtensions().textureExternalUpdateANGLE)
6800 {
6801 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
6802 return false;
6803 }
6804 break;
6805
6806 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
6807 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
6808 if (!context->getExtensions().getImageANGLE)
6809 {
6810 context->validationError(entryPoint, GL_INVALID_ENUM, kGetImageExtensionNotEnabled);
6811 return false;
6812 }
6813 break;
6814
6815 case GL_RESOURCE_INITIALIZED_ANGLE:
6816 if (!context->getExtensions().robustResourceInitializationANGLE)
6817 {
6818 context->validationError(entryPoint, GL_INVALID_ENUM,
6819 kRobustResourceInitializationExtensionRequired);
6820 return false;
6821 }
6822 break;
6823
6824 case GL_TEXTURE_PROTECTED_EXT:
6825 if (!context->getExtensions().protectedTexturesEXT)
6826 {
6827 context->validationError(entryPoint, GL_INVALID_ENUM,
6828 kProtectedTexturesExtensionRequired);
6829 return false;
6830 }
6831 break;
6832
6833 default:
6834 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6835 return false;
6836 }
6837
6838 if (length)
6839 {
6840 *length = GetTexParameterCount(pname);
6841 }
6842 return true;
6843 }
6844
ValidateGetVertexAttribBase(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLenum pname,GLsizei * length,bool pointer,bool pureIntegerEntryPoint)6845 bool ValidateGetVertexAttribBase(const Context *context,
6846 angle::EntryPoint entryPoint,
6847 GLuint index,
6848 GLenum pname,
6849 GLsizei *length,
6850 bool pointer,
6851 bool pureIntegerEntryPoint)
6852 {
6853 if (length)
6854 {
6855 *length = 0;
6856 }
6857
6858 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
6859 {
6860 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
6861 return false;
6862 }
6863
6864 if (index >= static_cast<GLuint>(context->getCaps().maxVertexAttributes))
6865 {
6866 context->validationError(entryPoint, GL_INVALID_VALUE, kIndexExceedsMaxVertexAttribute);
6867 return false;
6868 }
6869
6870 if (pointer)
6871 {
6872 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
6873 {
6874 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6875 return false;
6876 }
6877 }
6878 else
6879 {
6880 switch (pname)
6881 {
6882 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
6883 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
6884 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
6885 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
6886 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
6887 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
6888 case GL_CURRENT_VERTEX_ATTRIB:
6889 break;
6890
6891 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
6892 static_assert(
6893 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
6894 "ANGLE extension enums not equal to GL enums.");
6895 if (context->getClientMajorVersion() < 3 &&
6896 !context->getExtensions().instancedArraysAny())
6897 {
6898 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6899 return false;
6900 }
6901 break;
6902
6903 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
6904 if (context->getClientMajorVersion() < 3)
6905 {
6906 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6907 return false;
6908 }
6909 break;
6910
6911 case GL_VERTEX_ATTRIB_BINDING:
6912 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
6913 if (context->getClientVersion() < ES_3_1)
6914 {
6915 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
6916 return false;
6917 }
6918 break;
6919
6920 default:
6921 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
6922 return false;
6923 }
6924 }
6925
6926 if (length)
6927 {
6928 if (pname == GL_CURRENT_VERTEX_ATTRIB)
6929 {
6930 *length = 4;
6931 }
6932 else
6933 {
6934 *length = 1;
6935 }
6936 }
6937
6938 return true;
6939 }
6940
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)6941 bool ValidatePixelPack(const Context *context,
6942 angle::EntryPoint entryPoint,
6943 GLenum format,
6944 GLenum type,
6945 GLint x,
6946 GLint y,
6947 GLsizei width,
6948 GLsizei height,
6949 GLsizei bufSize,
6950 GLsizei *length,
6951 const void *pixels)
6952 {
6953 // Check for pixel pack buffer related API errors
6954 Buffer *pixelPackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelPack);
6955 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
6956 {
6957 // ...the buffer object's data store is currently mapped.
6958 context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferMapped);
6959 return false;
6960 }
6961 if (pixelPackBuffer != nullptr &&
6962 pixelPackBuffer->hasWebGLXFBBindingConflict(context->isWebGL()))
6963 {
6964 context->validationError(entryPoint, GL_INVALID_OPERATION,
6965 kPixelPackBufferBoundForTransformFeedback);
6966 return false;
6967 }
6968
6969 // .. the data would be packed to the buffer object such that the memory writes required
6970 // would exceed the data store size.
6971 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
6972 const Extents size(width, height, 1);
6973 const auto &pack = context->getState().getPackState();
6974
6975 GLuint endByte = 0;
6976 if (!formatInfo.computePackUnpackEndByte(type, size, pack, false, &endByte))
6977 {
6978 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
6979 return false;
6980 }
6981
6982 if (bufSize >= 0)
6983 {
6984 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
6985 {
6986 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
6987 return false;
6988 }
6989 }
6990
6991 if (pixelPackBuffer != nullptr)
6992 {
6993 CheckedNumeric<size_t> checkedEndByte(endByte);
6994 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
6995 checkedEndByte += checkedOffset;
6996
6997 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
6998 {
6999 // Overflow past the end of the buffer
7000 context->validationError(entryPoint, GL_INVALID_OPERATION, kParamOverflow);
7001 return false;
7002 }
7003 }
7004
7005 if (pixelPackBuffer == nullptr && length != nullptr)
7006 {
7007 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
7008 {
7009 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
7010 return false;
7011 }
7012
7013 *length = static_cast<GLsizei>(endByte);
7014 }
7015
7016 if (context->isWebGL())
7017 {
7018 // WebGL 2.0 disallows the scenario:
7019 // GL_PACK_SKIP_PIXELS + width > DataStoreWidth
7020 // where:
7021 // DataStoreWidth = (GL_PACK_ROW_LENGTH ? GL_PACK_ROW_LENGTH : width)
7022 // Since these two pack parameters can only be set to non-zero values
7023 // on WebGL 2.0 contexts, verify them for all WebGL contexts.
7024 GLint dataStoreWidth = pack.rowLength ? pack.rowLength : width;
7025 if (pack.skipPixels + width > dataStoreWidth)
7026 {
7027 context->validationError(entryPoint, GL_INVALID_OPERATION,
7028 kInvalidPackParametersForWebGL);
7029 return false;
7030 }
7031 }
7032
7033 return true;
7034 }
7035
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)7036 bool ValidateReadPixelsBase(const Context *context,
7037 angle::EntryPoint entryPoint,
7038 GLint x,
7039 GLint y,
7040 GLsizei width,
7041 GLsizei height,
7042 GLenum format,
7043 GLenum type,
7044 GLsizei bufSize,
7045 GLsizei *length,
7046 GLsizei *columns,
7047 GLsizei *rows,
7048 const void *pixels)
7049 {
7050 if (length != nullptr)
7051 {
7052 *length = 0;
7053 }
7054 if (rows != nullptr)
7055 {
7056 *rows = 0;
7057 }
7058 if (columns != nullptr)
7059 {
7060 *columns = 0;
7061 }
7062
7063 if (width < 0 || height < 0)
7064 {
7065 context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeSize);
7066 return false;
7067 }
7068
7069 Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
7070 ASSERT(readFramebuffer);
7071
7072 if (!ValidateFramebufferComplete(context, entryPoint, readFramebuffer))
7073 {
7074 return false;
7075 }
7076
7077 // needIntrinsic = true. Treat renderToTexture textures as single sample since they will be
7078 // resolved before reading.
7079 if (!readFramebuffer->isDefault() &&
7080 !ValidateFramebufferNotMultisampled(context, entryPoint, readFramebuffer, true))
7081 {
7082 return false;
7083 }
7084
7085 if (readFramebuffer->getReadBufferState() == GL_NONE)
7086 {
7087 context->validationError(entryPoint, GL_INVALID_OPERATION, kReadBufferNone);
7088 return false;
7089 }
7090
7091 const FramebufferAttachment *readBuffer = nullptr;
7092 switch (format)
7093 {
7094 case GL_DEPTH_COMPONENT:
7095 readBuffer = readFramebuffer->getDepthAttachment();
7096 break;
7097 case GL_STENCIL_INDEX_OES:
7098 readBuffer = readFramebuffer->getStencilOrDepthStencilAttachment();
7099 break;
7100 default:
7101 readBuffer = readFramebuffer->getReadColorAttachment();
7102 break;
7103 }
7104
7105 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
7106 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
7107 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
7108 // situation is an application error that would lead to a crash in ANGLE.
7109 if (readBuffer == nullptr)
7110 {
7111 context->validationError(entryPoint, GL_INVALID_OPERATION, kMissingReadAttachment);
7112 return false;
7113 }
7114
7115 // OVR_multiview2, Revision 1:
7116 // ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if
7117 // the number of views in the current read framebuffer is more than one.
7118 if (readFramebuffer->readDisallowedByMultiview())
7119 {
7120 context->validationError(entryPoint, GL_INVALID_FRAMEBUFFER_OPERATION,
7121 kMultiviewReadFramebuffer);
7122 return false;
7123 }
7124
7125 if (context->isWebGL())
7126 {
7127 // The ES 2.0 spec states that the format must be "among those defined in table 3.4,
7128 // excluding formats LUMINANCE and LUMINANCE_ALPHA.". This requires validating the format
7129 // and type before validating the combination of format and type. However, the
7130 // dEQP-GLES3.functional.negative_api.buffer.read_pixels passes GL_LUMINANCE as a format and
7131 // verifies that GL_INVALID_OPERATION is generated.
7132 // TODO(geofflang): Update this check to be done in all/no cases once this is resolved in
7133 // dEQP/WebGL.
7134 if (!ValidReadPixelsFormatEnum(context, format))
7135 {
7136 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
7137 return false;
7138 }
7139
7140 if (!ValidReadPixelsTypeEnum(context, type))
7141 {
7142 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidType);
7143 return false;
7144 }
7145 }
7146
7147 GLenum currentFormat = GL_NONE;
7148 GLenum currentType = GL_NONE;
7149
7150 switch (format)
7151 {
7152 case GL_DEPTH_COMPONENT:
7153 case GL_STENCIL_INDEX_OES:
7154 // Only rely on ValidReadPixelsFormatType for depth/stencil formats
7155 break;
7156 default:
7157 currentFormat = readFramebuffer->getImplementationColorReadFormat(context);
7158 currentType = readFramebuffer->getImplementationColorReadType(context);
7159 break;
7160 }
7161
7162 bool validFormatTypeCombination =
7163 ValidReadPixelsFormatType(context, readBuffer->getFormat().info, format, type);
7164
7165 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
7166 {
7167 context->validationError(entryPoint, GL_INVALID_OPERATION, kMismatchedTypeAndFormat);
7168 return false;
7169 }
7170
7171 if (!ValidatePixelPack(context, entryPoint, format, type, x, y, width, height, bufSize, length,
7172 pixels))
7173 {
7174 return false;
7175 }
7176
7177 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize, GLsizei *outExtent) {
7178 angle::CheckedNumeric<int> clippedExtent(length);
7179 if (start < 0)
7180 {
7181 // "subtract" the area that is less than 0
7182 clippedExtent += start;
7183 }
7184
7185 angle::CheckedNumeric<int> readExtent = start;
7186 readExtent += length;
7187 if (!readExtent.IsValid())
7188 {
7189 return false;
7190 }
7191
7192 if (readExtent.ValueOrDie() > bufferSize)
7193 {
7194 // Subtract the region to the right of the read buffer
7195 clippedExtent -= (readExtent - bufferSize);
7196 }
7197
7198 if (!clippedExtent.IsValid())
7199 {
7200 return false;
7201 }
7202
7203 *outExtent = std::max<int>(clippedExtent.ValueOrDie(), 0);
7204 return true;
7205 };
7206
7207 GLsizei writtenColumns = 0;
7208 if (!getClippedExtent(x, width, readBuffer->getSize().width, &writtenColumns))
7209 {
7210 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
7211 return false;
7212 }
7213
7214 GLsizei writtenRows = 0;
7215 if (!getClippedExtent(y, height, readBuffer->getSize().height, &writtenRows))
7216 {
7217 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
7218 return false;
7219 }
7220
7221 if (columns != nullptr)
7222 {
7223 *columns = writtenColumns;
7224 }
7225
7226 if (rows != nullptr)
7227 {
7228 *rows = writtenRows;
7229 }
7230
7231 return true;
7232 }
7233
7234 template <typename ParamType>
ValidateTexParameterBase(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLenum pname,GLsizei bufSize,bool vectorParams,const ParamType * params)7235 bool ValidateTexParameterBase(const Context *context,
7236 angle::EntryPoint entryPoint,
7237 TextureType target,
7238 GLenum pname,
7239 GLsizei bufSize,
7240 bool vectorParams,
7241 const ParamType *params)
7242 {
7243 if ((!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) ||
7244 target == TextureType::Buffer)
7245 {
7246 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
7247 return false;
7248 }
7249
7250 if (context->getTextureByType(target) == nullptr)
7251 {
7252 // Should only be possible for external textures
7253 context->validationError(entryPoint, GL_INVALID_ENUM, kTextureNotBound);
7254 return false;
7255 }
7256
7257 const GLsizei minBufSize = GetTexParameterCount(pname);
7258 if (bufSize >= 0 && bufSize < minBufSize)
7259 {
7260 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
7261 return false;
7262 }
7263
7264 if (context->getClientMajorVersion() == 1 && !IsValidGLES1TextureParameter(pname))
7265 {
7266 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7267 return false;
7268 }
7269
7270 switch (pname)
7271 {
7272 case GL_TEXTURE_WRAP_R:
7273 case GL_TEXTURE_SWIZZLE_R:
7274 case GL_TEXTURE_SWIZZLE_G:
7275 case GL_TEXTURE_SWIZZLE_B:
7276 case GL_TEXTURE_SWIZZLE_A:
7277 case GL_TEXTURE_BASE_LEVEL:
7278 case GL_TEXTURE_MAX_LEVEL:
7279 case GL_TEXTURE_COMPARE_MODE:
7280 case GL_TEXTURE_COMPARE_FUNC:
7281 case GL_TEXTURE_MIN_LOD:
7282 case GL_TEXTURE_MAX_LOD:
7283 if (context->getClientMajorVersion() < 3 &&
7284 !(pname == GL_TEXTURE_WRAP_R && context->getExtensions().texture3DOES))
7285 {
7286 context->validationError(entryPoint, GL_INVALID_ENUM, kES3Required);
7287 return false;
7288 }
7289 if (target == TextureType::External &&
7290 !context->getExtensions().EGLImageExternalEssl3OES)
7291 {
7292 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7293 return false;
7294 }
7295 if (target == TextureType::VideoImage && !context->getExtensions().videoTextureWEBGL)
7296 {
7297 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7298 }
7299 break;
7300
7301 case GL_GENERATE_MIPMAP:
7302 case GL_TEXTURE_CROP_RECT_OES:
7303 if (context->getClientMajorVersion() > 1)
7304 {
7305 context->validationError(entryPoint, GL_INVALID_ENUM, kGLES1Only);
7306 return false;
7307 }
7308 break;
7309
7310 default:
7311 break;
7312 }
7313
7314 if (target == TextureType::_2DMultisample || target == TextureType::_2DMultisampleArray)
7315 {
7316 switch (pname)
7317 {
7318 case GL_TEXTURE_MIN_FILTER:
7319 case GL_TEXTURE_MAG_FILTER:
7320 case GL_TEXTURE_WRAP_S:
7321 case GL_TEXTURE_WRAP_T:
7322 case GL_TEXTURE_WRAP_R:
7323 case GL_TEXTURE_MIN_LOD:
7324 case GL_TEXTURE_MAX_LOD:
7325 case GL_TEXTURE_COMPARE_MODE:
7326 case GL_TEXTURE_COMPARE_FUNC:
7327 case GL_TEXTURE_BORDER_COLOR:
7328 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
7329 return false;
7330 }
7331 }
7332
7333 switch (pname)
7334 {
7335 case GL_TEXTURE_WRAP_S:
7336 case GL_TEXTURE_WRAP_T:
7337 case GL_TEXTURE_WRAP_R:
7338 {
7339 bool restrictedWrapModes = ((target == TextureType::External &&
7340 !context->getExtensions().EGLImageExternalWrapModesEXT) ||
7341 target == TextureType::Rectangle);
7342 if (!ValidateTextureWrapModeValue(context, entryPoint, params, restrictedWrapModes))
7343 {
7344 return false;
7345 }
7346 }
7347 break;
7348
7349 case GL_TEXTURE_MIN_FILTER:
7350 {
7351 bool restrictedMinFilter =
7352 target == TextureType::External || target == TextureType::Rectangle;
7353 if (!ValidateTextureMinFilterValue(context, entryPoint, params, restrictedMinFilter))
7354 {
7355 return false;
7356 }
7357 }
7358 break;
7359
7360 case GL_TEXTURE_MAG_FILTER:
7361 if (!ValidateTextureMagFilterValue(context, entryPoint, params))
7362 {
7363 return false;
7364 }
7365 break;
7366
7367 case GL_TEXTURE_USAGE_ANGLE:
7368 if (!context->getExtensions().textureUsageANGLE)
7369 {
7370 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7371 return false;
7372 }
7373
7374 switch (ConvertToGLenum(params[0]))
7375 {
7376 case GL_NONE:
7377 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
7378 break;
7379
7380 default:
7381 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7382 return false;
7383 }
7384 break;
7385
7386 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
7387 {
7388 GLfloat paramValue = static_cast<GLfloat>(params[0]);
7389 if (!ValidateTextureMaxAnisotropyValue(context, entryPoint, paramValue))
7390 {
7391 return false;
7392 }
7393 ASSERT(static_cast<ParamType>(paramValue) == params[0]);
7394 }
7395 break;
7396
7397 case GL_TEXTURE_MIN_LOD:
7398 case GL_TEXTURE_MAX_LOD:
7399 // any value is permissible
7400 break;
7401
7402 case GL_TEXTURE_COMPARE_MODE:
7403 if (!ValidateTextureCompareModeValue(context, entryPoint, params))
7404 {
7405 return false;
7406 }
7407 break;
7408
7409 case GL_TEXTURE_COMPARE_FUNC:
7410 if (!ValidateTextureCompareFuncValue(context, entryPoint, params))
7411 {
7412 return false;
7413 }
7414 break;
7415
7416 case GL_TEXTURE_SWIZZLE_R:
7417 case GL_TEXTURE_SWIZZLE_G:
7418 case GL_TEXTURE_SWIZZLE_B:
7419 case GL_TEXTURE_SWIZZLE_A:
7420 switch (ConvertToGLenum(params[0]))
7421 {
7422 case GL_RED:
7423 case GL_GREEN:
7424 case GL_BLUE:
7425 case GL_ALPHA:
7426 case GL_ZERO:
7427 case GL_ONE:
7428 break;
7429
7430 default:
7431 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7432 return false;
7433 }
7434 break;
7435
7436 case GL_TEXTURE_BASE_LEVEL:
7437 if (ConvertToGLint(params[0]) < 0)
7438 {
7439 context->validationError(entryPoint, GL_INVALID_VALUE, kBaseLevelNegative);
7440 return false;
7441 }
7442 if (target == TextureType::External && static_cast<GLuint>(params[0]) != 0)
7443 {
7444 context->validationError(entryPoint, GL_INVALID_OPERATION, kBaseLevelNonZero);
7445 return false;
7446 }
7447 if ((target == TextureType::_2DMultisample ||
7448 target == TextureType::_2DMultisampleArray) &&
7449 static_cast<GLuint>(params[0]) != 0)
7450 {
7451 context->validationError(entryPoint, GL_INVALID_OPERATION, kBaseLevelNonZero);
7452 return false;
7453 }
7454 if (target == TextureType::Rectangle && static_cast<GLuint>(params[0]) != 0)
7455 {
7456 context->validationError(entryPoint, GL_INVALID_OPERATION, kBaseLevelNonZero);
7457 return false;
7458 }
7459 break;
7460
7461 case GL_TEXTURE_MAX_LEVEL:
7462 if (ConvertToGLint(params[0]) < 0)
7463 {
7464 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
7465 return false;
7466 }
7467 break;
7468
7469 case GL_DEPTH_STENCIL_TEXTURE_MODE:
7470 if (context->getClientVersion() < Version(3, 1))
7471 {
7472 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumRequiresGLES31);
7473 return false;
7474 }
7475 switch (ConvertToGLenum(params[0]))
7476 {
7477 case GL_DEPTH_COMPONENT:
7478 case GL_STENCIL_INDEX:
7479 break;
7480
7481 default:
7482 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7483 return false;
7484 }
7485 break;
7486
7487 case GL_TEXTURE_SRGB_DECODE_EXT:
7488 if (!ValidateTextureSRGBDecodeValue(context, entryPoint, params))
7489 {
7490 return false;
7491 }
7492 break;
7493
7494 case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT:
7495 if (!ValidateTextureSRGBOverrideValue(context, entryPoint, params))
7496 {
7497 return false;
7498 }
7499 break;
7500
7501 case GL_GENERATE_MIPMAP:
7502 if (context->getClientMajorVersion() > 1)
7503 {
7504 context->validationError(entryPoint, GL_INVALID_ENUM, kGLES1Only);
7505 return false;
7506 }
7507 break;
7508
7509 case GL_TEXTURE_CROP_RECT_OES:
7510 if (context->getClientMajorVersion() > 1)
7511 {
7512 context->validationError(entryPoint, GL_INVALID_ENUM, kGLES1Only);
7513 return false;
7514 }
7515 if (!vectorParams)
7516 {
7517 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
7518 return false;
7519 }
7520 break;
7521
7522 case GL_TEXTURE_BORDER_COLOR:
7523 if (!context->getExtensions().textureBorderClampOES &&
7524 context->getClientVersion() < ES_3_2)
7525 {
7526 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
7527 return false;
7528 }
7529 if (!vectorParams)
7530 {
7531 context->validationError(entryPoint, GL_INVALID_ENUM, kInsufficientBufferSize);
7532 return false;
7533 }
7534 break;
7535
7536 case GL_RESOURCE_INITIALIZED_ANGLE:
7537 if (!context->getExtensions().robustResourceInitializationANGLE)
7538 {
7539 context->validationError(entryPoint, GL_INVALID_ENUM,
7540 kRobustResourceInitializationExtensionRequired);
7541 return false;
7542 }
7543 break;
7544
7545 case GL_TEXTURE_PROTECTED_EXT:
7546 if (!context->getExtensions().protectedTexturesEXT)
7547 {
7548 context->validationError(entryPoint, GL_INVALID_ENUM,
7549 kProtectedTexturesExtensionRequired);
7550 return false;
7551 }
7552 if (ConvertToBool(params[0]) != context->getState().hasProtectedContent())
7553 {
7554 context->validationError(entryPoint, GL_INVALID_OPERATION,
7555 "Protected Texture must match Protected Context");
7556 return false;
7557 }
7558 break;
7559
7560 default:
7561 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7562 return false;
7563 }
7564
7565 return true;
7566 }
7567
7568 template bool ValidateTexParameterBase(const Context *,
7569 angle::EntryPoint,
7570 TextureType,
7571 GLenum,
7572 GLsizei,
7573 bool,
7574 const GLfloat *);
7575 template bool ValidateTexParameterBase(const Context *,
7576 angle::EntryPoint,
7577 TextureType,
7578 GLenum,
7579 GLsizei,
7580 bool,
7581 const GLint *);
7582 template bool ValidateTexParameterBase(const Context *,
7583 angle::EntryPoint,
7584 TextureType,
7585 GLenum,
7586 GLsizei,
7587 bool,
7588 const GLuint *);
7589
ValidateGetActiveUniformBlockivBase(const Context * context,angle::EntryPoint entryPoint,ShaderProgramID program,UniformBlockIndex uniformBlockIndex,GLenum pname,GLsizei * length)7590 bool ValidateGetActiveUniformBlockivBase(const Context *context,
7591 angle::EntryPoint entryPoint,
7592 ShaderProgramID program,
7593 UniformBlockIndex uniformBlockIndex,
7594 GLenum pname,
7595 GLsizei *length)
7596 {
7597 if (length)
7598 {
7599 *length = 0;
7600 }
7601
7602 if (context->getClientMajorVersion() < 3)
7603 {
7604 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
7605 return false;
7606 }
7607
7608 Program *programObject = GetValidProgram(context, entryPoint, program);
7609 if (!programObject)
7610 {
7611 return false;
7612 }
7613
7614 if (uniformBlockIndex.value >= programObject->getActiveUniformBlockCount())
7615 {
7616 context->validationError(entryPoint, GL_INVALID_VALUE,
7617 kIndexExceedsActiveUniformBlockCount);
7618 return false;
7619 }
7620
7621 switch (pname)
7622 {
7623 case GL_UNIFORM_BLOCK_BINDING:
7624 case GL_UNIFORM_BLOCK_DATA_SIZE:
7625 case GL_UNIFORM_BLOCK_NAME_LENGTH:
7626 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
7627 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
7628 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
7629 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
7630 break;
7631
7632 default:
7633 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7634 return false;
7635 }
7636
7637 if (length)
7638 {
7639 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
7640 {
7641 const InterfaceBlock &uniformBlock =
7642 programObject->getUniformBlockByIndex(uniformBlockIndex.value);
7643 *length = static_cast<GLsizei>(uniformBlock.memberIndexes.size());
7644 }
7645 else
7646 {
7647 *length = 1;
7648 }
7649 }
7650
7651 return true;
7652 }
7653
7654 template <typename ParamType>
ValidateSamplerParameterBase(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei bufSize,bool vectorParams,const ParamType * params)7655 bool ValidateSamplerParameterBase(const Context *context,
7656 angle::EntryPoint entryPoint,
7657 SamplerID sampler,
7658 GLenum pname,
7659 GLsizei bufSize,
7660 bool vectorParams,
7661 const ParamType *params)
7662 {
7663 if (context->getClientMajorVersion() < 3)
7664 {
7665 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
7666 return false;
7667 }
7668
7669 if (!context->isSampler(sampler))
7670 {
7671 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidSampler);
7672 return false;
7673 }
7674
7675 const GLsizei minBufSize = GetSamplerParameterCount(pname);
7676 if (bufSize >= 0 && bufSize < minBufSize)
7677 {
7678 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
7679 return false;
7680 }
7681
7682 switch (pname)
7683 {
7684 case GL_TEXTURE_WRAP_S:
7685 case GL_TEXTURE_WRAP_T:
7686 case GL_TEXTURE_WRAP_R:
7687 if (!ValidateTextureWrapModeValue(context, entryPoint, params, false))
7688 {
7689 return false;
7690 }
7691 break;
7692
7693 case GL_TEXTURE_MIN_FILTER:
7694 if (!ValidateTextureMinFilterValue(context, entryPoint, params, false))
7695 {
7696 return false;
7697 }
7698 break;
7699
7700 case GL_TEXTURE_MAG_FILTER:
7701 if (!ValidateTextureMagFilterValue(context, entryPoint, params))
7702 {
7703 return false;
7704 }
7705 break;
7706
7707 case GL_TEXTURE_MIN_LOD:
7708 case GL_TEXTURE_MAX_LOD:
7709 // any value is permissible
7710 break;
7711
7712 case GL_TEXTURE_COMPARE_MODE:
7713 if (!ValidateTextureCompareModeValue(context, entryPoint, params))
7714 {
7715 return false;
7716 }
7717 break;
7718
7719 case GL_TEXTURE_COMPARE_FUNC:
7720 if (!ValidateTextureCompareFuncValue(context, entryPoint, params))
7721 {
7722 return false;
7723 }
7724 break;
7725
7726 case GL_TEXTURE_SRGB_DECODE_EXT:
7727 if (!ValidateTextureSRGBDecodeValue(context, entryPoint, params))
7728 {
7729 return false;
7730 }
7731 break;
7732
7733 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
7734 {
7735 GLfloat paramValue = static_cast<GLfloat>(params[0]);
7736 if (!ValidateTextureMaxAnisotropyValue(context, entryPoint, paramValue))
7737 {
7738 return false;
7739 }
7740 }
7741 break;
7742
7743 case GL_TEXTURE_BORDER_COLOR:
7744 if (!context->getExtensions().textureBorderClampOES &&
7745 context->getClientVersion() < ES_3_2)
7746 {
7747 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
7748 return false;
7749 }
7750 if (!vectorParams)
7751 {
7752 context->validationError(entryPoint, GL_INVALID_ENUM, kInsufficientBufferSize);
7753 return false;
7754 }
7755 break;
7756
7757 default:
7758 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7759 return false;
7760 }
7761
7762 return true;
7763 }
7764
7765 template bool ValidateSamplerParameterBase(const Context *,
7766 angle::EntryPoint,
7767 SamplerID,
7768 GLenum,
7769 GLsizei,
7770 bool,
7771 const GLfloat *);
7772 template bool ValidateSamplerParameterBase(const Context *,
7773 angle::EntryPoint,
7774 SamplerID,
7775 GLenum,
7776 GLsizei,
7777 bool,
7778 const GLint *);
7779 template bool ValidateSamplerParameterBase(const Context *,
7780 angle::EntryPoint,
7781 SamplerID,
7782 GLenum,
7783 GLsizei,
7784 bool,
7785 const GLuint *);
7786
ValidateGetSamplerParameterBase(const Context * context,angle::EntryPoint entryPoint,SamplerID sampler,GLenum pname,GLsizei * length)7787 bool ValidateGetSamplerParameterBase(const Context *context,
7788 angle::EntryPoint entryPoint,
7789 SamplerID sampler,
7790 GLenum pname,
7791 GLsizei *length)
7792 {
7793 if (length)
7794 {
7795 *length = 0;
7796 }
7797
7798 if (context->getClientMajorVersion() < 3)
7799 {
7800 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
7801 return false;
7802 }
7803
7804 if (!context->isSampler(sampler))
7805 {
7806 context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidSampler);
7807 return false;
7808 }
7809
7810 switch (pname)
7811 {
7812 case GL_TEXTURE_WRAP_S:
7813 case GL_TEXTURE_WRAP_T:
7814 case GL_TEXTURE_WRAP_R:
7815 case GL_TEXTURE_MIN_FILTER:
7816 case GL_TEXTURE_MAG_FILTER:
7817 case GL_TEXTURE_MIN_LOD:
7818 case GL_TEXTURE_MAX_LOD:
7819 case GL_TEXTURE_COMPARE_MODE:
7820 case GL_TEXTURE_COMPARE_FUNC:
7821 break;
7822
7823 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
7824 if (!ValidateTextureMaxAnisotropyExtensionEnabled(context, entryPoint))
7825 {
7826 return false;
7827 }
7828 break;
7829
7830 case GL_TEXTURE_SRGB_DECODE_EXT:
7831 if (!context->getExtensions().textureSRGBDecodeEXT)
7832 {
7833 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7834 return false;
7835 }
7836 break;
7837
7838 case GL_TEXTURE_BORDER_COLOR:
7839 if (!context->getExtensions().textureBorderClampOES &&
7840 context->getClientVersion() < ES_3_2)
7841 {
7842 context->validationError(entryPoint, GL_INVALID_ENUM, kExtensionNotEnabled);
7843 return false;
7844 }
7845 break;
7846
7847 default:
7848 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7849 return false;
7850 }
7851
7852 if (length)
7853 {
7854 *length = GetSamplerParameterCount(pname);
7855 }
7856 return true;
7857 }
7858
ValidateGetInternalFormativBase(const Context * context,angle::EntryPoint entryPoint,GLenum target,GLenum internalformat,GLenum pname,GLsizei bufSize,GLsizei * numParams)7859 bool ValidateGetInternalFormativBase(const Context *context,
7860 angle::EntryPoint entryPoint,
7861 GLenum target,
7862 GLenum internalformat,
7863 GLenum pname,
7864 GLsizei bufSize,
7865 GLsizei *numParams)
7866 {
7867 if (numParams)
7868 {
7869 *numParams = 0;
7870 }
7871
7872 if (context->getClientMajorVersion() < 3)
7873 {
7874 context->validationError(entryPoint, GL_INVALID_OPERATION, kES3Required);
7875 return false;
7876 }
7877
7878 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
7879 if (!formatCaps.renderbuffer)
7880 {
7881 context->validationError(entryPoint, GL_INVALID_ENUM, kFormatNotRenderable);
7882 return false;
7883 }
7884
7885 switch (target)
7886 {
7887 case GL_RENDERBUFFER:
7888 break;
7889
7890 case GL_TEXTURE_2D_MULTISAMPLE:
7891 if (context->getClientVersion() < ES_3_1 &&
7892 !context->getExtensions().textureMultisampleANGLE)
7893 {
7894 context->validationError(entryPoint, GL_INVALID_ENUM,
7895 kMultisampleTextureExtensionOrES31Required);
7896 return false;
7897 }
7898 break;
7899 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES:
7900 if (!context->getExtensions().textureStorageMultisample2dArrayOES)
7901 {
7902 context->validationError(entryPoint, GL_INVALID_ENUM,
7903 kMultisampleArrayExtensionRequired);
7904 return false;
7905 }
7906 break;
7907 default:
7908 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTarget);
7909 return false;
7910 }
7911
7912 if (bufSize < 0)
7913 {
7914 context->validationError(entryPoint, GL_INVALID_VALUE, kInsufficientBufferSize);
7915 return false;
7916 }
7917
7918 GLsizei maxWriteParams = 0;
7919 switch (pname)
7920 {
7921 case GL_NUM_SAMPLE_COUNTS:
7922 maxWriteParams = 1;
7923 break;
7924
7925 case GL_SAMPLES:
7926 maxWriteParams = static_cast<GLsizei>(formatCaps.sampleCounts.size());
7927 break;
7928
7929 default:
7930 context->validationError(entryPoint, GL_INVALID_ENUM, kEnumNotSupported);
7931 return false;
7932 }
7933
7934 if (numParams)
7935 {
7936 // glGetInternalFormativ will not overflow bufSize
7937 *numParams = std::min(bufSize, maxWriteParams);
7938 }
7939
7940 return true;
7941 }
7942
ValidateFramebufferNotMultisampled(const Context * context,angle::EntryPoint entryPoint,const Framebuffer * framebuffer,bool checkReadBufferResourceSamples)7943 bool ValidateFramebufferNotMultisampled(const Context *context,
7944 angle::EntryPoint entryPoint,
7945 const Framebuffer *framebuffer,
7946 bool checkReadBufferResourceSamples)
7947 {
7948 int samples = checkReadBufferResourceSamples
7949 ? framebuffer->getReadBufferResourceSamples(context)
7950 : framebuffer->getSamples(context);
7951 if (samples != 0)
7952 {
7953 context->validationError(entryPoint, GL_INVALID_OPERATION,
7954 kInvalidMultisampledFramebufferOperation);
7955 return false;
7956 }
7957 return true;
7958 }
7959
ValidateMultitextureUnit(const Context * context,angle::EntryPoint entryPoint,GLenum texture)7960 bool ValidateMultitextureUnit(const Context *context, angle::EntryPoint entryPoint, GLenum texture)
7961 {
7962 if (texture < GL_TEXTURE0 || texture >= GL_TEXTURE0 + context->getCaps().maxMultitextureUnits)
7963 {
7964 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidMultitextureUnit);
7965 return false;
7966 }
7967 return true;
7968 }
7969
ValidateTexStorageMultisample(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLsizei samples,GLint internalFormat,GLsizei width,GLsizei height)7970 bool ValidateTexStorageMultisample(const Context *context,
7971 angle::EntryPoint entryPoint,
7972 TextureType target,
7973 GLsizei samples,
7974 GLint internalFormat,
7975 GLsizei width,
7976 GLsizei height)
7977 {
7978 const Caps &caps = context->getCaps();
7979 if (width > caps.max2DTextureSize || height > caps.max2DTextureSize)
7980 {
7981 context->validationError(entryPoint, GL_INVALID_VALUE, kTextureWidthOrHeightOutOfRange);
7982 return false;
7983 }
7984
7985 if (samples == 0)
7986 {
7987 context->validationError(entryPoint, GL_INVALID_VALUE, kSamplesZero);
7988 return false;
7989 }
7990
7991 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
7992 if (!formatCaps.textureAttachment)
7993 {
7994 context->validationError(entryPoint, GL_INVALID_ENUM, kRenderableInternalFormat);
7995 return false;
7996 }
7997
7998 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
7999 // is one of the unsized base internalformats listed in table 8.11.
8000 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
8001 if (formatInfo.internalFormat == GL_NONE)
8002 {
8003 context->validationError(entryPoint, GL_INVALID_ENUM, kUnsizedInternalFormatUnsupported);
8004 return false;
8005 }
8006
8007 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
8008 {
8009 context->validationError(entryPoint, GL_INVALID_OPERATION, kSamplesOutOfRange);
8010 return false;
8011 }
8012
8013 Texture *texture = context->getTextureByType(target);
8014 if (!texture || texture->id().value == 0)
8015 {
8016 context->validationError(entryPoint, GL_INVALID_OPERATION, kZeroBoundToTarget);
8017 return false;
8018 }
8019
8020 if (texture->getImmutableFormat())
8021 {
8022 context->validationError(entryPoint, GL_INVALID_OPERATION, kImmutableTextureBound);
8023 return false;
8024 }
8025 return true;
8026 }
8027
ValidateTexStorage2DMultisampleBase(const Context * context,angle::EntryPoint entryPoint,TextureType target,GLsizei samples,GLint internalFormat,GLsizei width,GLsizei height)8028 bool ValidateTexStorage2DMultisampleBase(const Context *context,
8029 angle::EntryPoint entryPoint,
8030 TextureType target,
8031 GLsizei samples,
8032 GLint internalFormat,
8033 GLsizei width,
8034 GLsizei height)
8035 {
8036 if (target != TextureType::_2DMultisample)
8037 {
8038 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTarget);
8039 return false;
8040 }
8041
8042 if (width < 1 || height < 1)
8043 {
8044 context->validationError(entryPoint, GL_INVALID_VALUE, kTextureSizeTooSmall);
8045 return false;
8046 }
8047
8048 return ValidateTexStorageMultisample(context, entryPoint, target, samples, internalFormat,
8049 width, height);
8050 }
8051
ValidateGetTexLevelParameterBase(const Context * context,angle::EntryPoint entryPoint,TextureTarget target,GLint level,GLenum pname,GLsizei * length)8052 bool ValidateGetTexLevelParameterBase(const Context *context,
8053 angle::EntryPoint entryPoint,
8054 TextureTarget target,
8055 GLint level,
8056 GLenum pname,
8057 GLsizei *length)
8058 {
8059
8060 if (length)
8061 {
8062 *length = 0;
8063 }
8064
8065 TextureType type = TextureTargetToType(target);
8066
8067 if (!ValidTexLevelDestinationTarget(context, type))
8068 {
8069 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
8070 return false;
8071 }
8072
8073 if (context->getTextureByType(type) == nullptr)
8074 {
8075 context->validationError(entryPoint, GL_INVALID_ENUM, kTextureNotBound);
8076 return false;
8077 }
8078
8079 if (!ValidMipLevel(context, type, level))
8080 {
8081 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
8082 return false;
8083 }
8084
8085 switch (pname)
8086 {
8087 case GL_TEXTURE_RED_TYPE:
8088 case GL_TEXTURE_GREEN_TYPE:
8089 case GL_TEXTURE_BLUE_TYPE:
8090 case GL_TEXTURE_ALPHA_TYPE:
8091 case GL_TEXTURE_DEPTH_TYPE:
8092 case GL_TEXTURE_RED_SIZE:
8093 case GL_TEXTURE_GREEN_SIZE:
8094 case GL_TEXTURE_BLUE_SIZE:
8095 case GL_TEXTURE_ALPHA_SIZE:
8096 case GL_TEXTURE_DEPTH_SIZE:
8097 case GL_TEXTURE_STENCIL_SIZE:
8098 case GL_TEXTURE_SHARED_SIZE:
8099 case GL_TEXTURE_INTERNAL_FORMAT:
8100 case GL_TEXTURE_WIDTH:
8101 case GL_TEXTURE_HEIGHT:
8102 case GL_TEXTURE_DEPTH:
8103 case GL_TEXTURE_SAMPLES:
8104 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
8105 case GL_TEXTURE_COMPRESSED:
8106 break;
8107
8108 case GL_RESOURCE_INITIALIZED_ANGLE:
8109 if (!context->getExtensions().robustResourceInitializationANGLE)
8110 {
8111 context->validationError(entryPoint, GL_INVALID_ENUM,
8112 kRobustResourceInitializationExtensionRequired);
8113 return false;
8114 }
8115 break;
8116
8117 case GL_TEXTURE_BUFFER_DATA_STORE_BINDING:
8118 case GL_TEXTURE_BUFFER_OFFSET:
8119 case GL_TEXTURE_BUFFER_SIZE:
8120 if (context->getClientVersion() < Version(3, 2) &&
8121 !context->getExtensions().textureBufferAny())
8122 {
8123 context->validationError(entryPoint, GL_INVALID_ENUM,
8124 kTextureBufferExtensionNotAvailable);
8125 return false;
8126 }
8127 break;
8128
8129 default:
8130 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
8131 return false;
8132 }
8133
8134 if (length)
8135 {
8136 *length = 1;
8137 }
8138 return true;
8139 }
8140
ValidateGetMultisamplefvBase(const Context * context,angle::EntryPoint entryPoint,GLenum pname,GLuint index,const GLfloat * val)8141 bool ValidateGetMultisamplefvBase(const Context *context,
8142 angle::EntryPoint entryPoint,
8143 GLenum pname,
8144 GLuint index,
8145 const GLfloat *val)
8146 {
8147 if (pname != GL_SAMPLE_POSITION)
8148 {
8149 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
8150 return false;
8151 }
8152
8153 Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
8154 GLint samples = framebuffer->getSamples(context);
8155
8156 if (index >= static_cast<GLuint>(samples))
8157 {
8158 context->validationError(entryPoint, GL_INVALID_VALUE, kIndexExceedsSamples);
8159 return false;
8160 }
8161
8162 return true;
8163 }
8164
ValidateSampleMaskiBase(const Context * context,angle::EntryPoint entryPoint,GLuint maskNumber,GLbitfield mask)8165 bool ValidateSampleMaskiBase(const Context *context,
8166 angle::EntryPoint entryPoint,
8167 GLuint maskNumber,
8168 GLbitfield mask)
8169 {
8170 if (maskNumber >= static_cast<GLuint>(context->getCaps().maxSampleMaskWords))
8171 {
8172 context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidSampleMaskNumber);
8173 return false;
8174 }
8175
8176 return true;
8177 }
8178
RecordDrawAttribsError(const Context * context,angle::EntryPoint entryPoint)8179 void RecordDrawAttribsError(const Context *context, angle::EntryPoint entryPoint)
8180 {
8181 // An overflow can happen when adding the offset. Check against a special constant.
8182 if (context->getStateCache().getNonInstancedVertexElementLimit() ==
8183 VertexAttribute::kIntegerOverflow ||
8184 context->getStateCache().getInstancedVertexElementLimit() ==
8185 VertexAttribute::kIntegerOverflow)
8186 {
8187 context->validationError(entryPoint, GL_INVALID_OPERATION, kIntegerOverflow);
8188 }
8189 else
8190 {
8191 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
8192 // We can return INVALID_OPERATION if our buffer does not have enough backing data.
8193 context->validationError(entryPoint, GL_INVALID_OPERATION, kInsufficientVertexBufferSize);
8194 }
8195 }
8196
ValidateLoseContextCHROMIUM(const Context * context,angle::EntryPoint entryPoint,GraphicsResetStatus current,GraphicsResetStatus other)8197 bool ValidateLoseContextCHROMIUM(const Context *context,
8198 angle::EntryPoint entryPoint,
8199 GraphicsResetStatus current,
8200 GraphicsResetStatus other)
8201 {
8202 if (!context->getExtensions().loseContextCHROMIUM)
8203 {
8204 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
8205 return false;
8206 }
8207
8208 switch (current)
8209 {
8210 case GraphicsResetStatus::GuiltyContextReset:
8211 case GraphicsResetStatus::InnocentContextReset:
8212 case GraphicsResetStatus::UnknownContextReset:
8213 break;
8214
8215 default:
8216 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidResetStatus);
8217 }
8218
8219 switch (other)
8220 {
8221 case GraphicsResetStatus::GuiltyContextReset:
8222 case GraphicsResetStatus::InnocentContextReset:
8223 case GraphicsResetStatus::UnknownContextReset:
8224 break;
8225
8226 default:
8227 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidResetStatus);
8228 }
8229
8230 return true;
8231 }
8232
8233 // 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)8234 bool ValidateTexImage2DExternalANGLE(const Context *context,
8235 angle::EntryPoint entryPoint,
8236 TextureTarget target,
8237 GLint level,
8238 GLint internalformat,
8239 GLsizei width,
8240 GLsizei height,
8241 GLint border,
8242 GLenum format,
8243 GLenum type)
8244 {
8245 if (!context->getExtensions().textureExternalUpdateANGLE)
8246 {
8247 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
8248 return false;
8249 }
8250
8251 if (!ValidTexture2DDestinationTarget(context, target) &&
8252 !ValidTextureExternalTarget(context, target))
8253 {
8254 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
8255 return false;
8256 }
8257
8258 if (context->getClientMajorVersion() <= 2)
8259 {
8260 if (!ValidateES2TexImageParametersBase(context, entryPoint, target, level, internalformat,
8261 false, false, 0, 0, width, height, border, format,
8262 type, -1, nullptr))
8263 {
8264 return false;
8265 }
8266 }
8267 else
8268 {
8269 if (!ValidateES3TexImageParametersBase(context, entryPoint, target, level, internalformat,
8270 false, false, 0, 0, 0, width, height, 1, border,
8271 format, type, -1, nullptr))
8272 {
8273 return false;
8274 }
8275 }
8276
8277 return true;
8278 }
8279
ValidateInvalidateTextureANGLE(const Context * context,angle::EntryPoint entryPoint,TextureType target)8280 bool ValidateInvalidateTextureANGLE(const Context *context,
8281 angle::EntryPoint entryPoint,
8282 TextureType target)
8283 {
8284 if (!context->getExtensions().textureExternalUpdateANGLE)
8285 {
8286 context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
8287 return false;
8288 }
8289
8290 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
8291 {
8292 context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
8293 return false;
8294 }
8295
8296 return true;
8297 }
8298
8299 } // namespace gl
8300