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