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