1 //
2 // Copyright 2013 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
9 #ifndef LIBANGLE_VALIDATION_ES_H_
10 #define LIBANGLE_VALIDATION_ES_H_
11
12 #include "common/PackedEnums.h"
13 #include "common/mathutil.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/ErrorStrings.h"
17 #include "libANGLE/Framebuffer.h"
18 #include "libANGLE/VertexArray.h"
19
20 #include <GLES2/gl2.h>
21 #include <GLES3/gl3.h>
22 #include <GLES3/gl31.h>
23
24 namespace egl
25 {
26 class Display;
27 class Image;
28 } // namespace egl
29
30 namespace gl
31 {
32 class Context;
33 struct Format;
34 class Framebuffer;
35 struct LinkedUniform;
36 class Program;
37 class Shader;
38
39 void SetRobustLengthParam(const GLsizei *length, GLsizei value);
40 bool ValidTextureTarget(const Context *context, TextureType type);
41 bool ValidTexture2DTarget(const Context *context, TextureType type);
42 bool ValidTexture3DTarget(const Context *context, TextureType target);
43 bool ValidTextureExternalTarget(const Context *context, TextureType target);
44 bool ValidTextureExternalTarget(const Context *context, TextureTarget target);
45 bool ValidTexture2DDestinationTarget(const Context *context, TextureTarget target);
46 bool ValidTexture3DDestinationTarget(const Context *context, TextureTarget target);
47 bool ValidTexLevelDestinationTarget(const Context *context, TextureType type);
48 bool ValidFramebufferTarget(const Context *context, GLenum target);
49 bool ValidMipLevel(const Context *context, TextureType type, GLint level);
50 bool ValidImageSizeParameters(const Context *context,
51 angle::EntryPoint entryPoint,
52 TextureType target,
53 GLint level,
54 GLsizei width,
55 GLsizei height,
56 GLsizei depth,
57 bool isSubImage);
58 bool ValidCompressedImageSize(const Context *context,
59 GLenum internalFormat,
60 GLint level,
61 GLsizei width,
62 GLsizei height,
63 GLsizei depth);
64 bool ValidCompressedSubImageSize(const Context *context,
65 GLenum internalFormat,
66 GLint xoffset,
67 GLint yoffset,
68 GLint zoffset,
69 GLsizei width,
70 GLsizei height,
71 GLsizei depth,
72 size_t textureWidth,
73 size_t textureHeight,
74 size_t textureDepth);
75 bool ValidImageDataSize(const Context *context,
76 angle::EntryPoint entryPoint,
77 TextureType texType,
78 GLsizei width,
79 GLsizei height,
80 GLsizei depth,
81 GLenum format,
82 GLenum type,
83 const void *pixels,
84 GLsizei imageSize);
85
86 bool ValidQueryType(const Context *context, QueryType queryType);
87
88 bool ValidateWebGLVertexAttribPointer(const Context *context,
89 angle::EntryPoint entryPoint,
90 VertexAttribType type,
91 GLboolean normalized,
92 GLsizei stride,
93 const void *ptr,
94 bool pureInteger);
95
96 // Returns valid program if id is a valid program name
97 // Errors INVALID_OPERATION if valid shader is given and returns NULL
98 // Errors INVALID_VALUE otherwise and returns NULL
99 Program *GetValidProgram(const Context *context, angle::EntryPoint entryPoint, ShaderProgramID id);
100
101 // Returns valid shader if id is a valid shader name
102 // Errors INVALID_OPERATION if valid program is given and returns NULL
103 // Errors INVALID_VALUE otherwise and returns NULL
104 Shader *GetValidShader(const Context *context, angle::EntryPoint entryPoint, ShaderProgramID id);
105
106 bool ValidateAttachmentTarget(const Context *context,
107 angle::EntryPoint entryPoint,
108 GLenum attachment);
109
110 bool ValidateBlitFramebufferParameters(const Context *context,
111 angle::EntryPoint entryPoint,
112 GLint srcX0,
113 GLint srcY0,
114 GLint srcX1,
115 GLint srcY1,
116 GLint dstX0,
117 GLint dstY0,
118 GLint dstX1,
119 GLint dstY1,
120 GLbitfield mask,
121 GLenum filter);
122
123 bool ValidateBindFramebufferBase(const Context *context,
124 angle::EntryPoint entryPoint,
125 GLenum target,
126 FramebufferID framebuffer);
127 bool ValidateBindRenderbufferBase(const Context *context,
128 angle::EntryPoint entryPoint,
129 GLenum target,
130 RenderbufferID renderbuffer);
131 bool ValidateFramebufferRenderbufferBase(const Context *context,
132 angle::EntryPoint entryPoint,
133 GLenum target,
134 GLenum attachment,
135 GLenum renderbuffertarget,
136 RenderbufferID renderbuffer);
137 bool ValidateFramebufferTextureBase(const Context *context,
138 angle::EntryPoint entryPoint,
139 GLenum target,
140 GLenum attachment,
141 TextureID texture,
142 GLint level);
143 bool ValidateGenerateMipmapBase(const Context *context,
144 angle::EntryPoint entryPoint,
145 TextureType target);
146
147 bool ValidateRenderbufferStorageParametersBase(const Context *context,
148 angle::EntryPoint entryPoint,
149 GLenum target,
150 GLsizei samples,
151 GLenum internalformat,
152 GLsizei width,
153 GLsizei height);
154
155 bool ValidatePixelPack(const Context *context,
156 angle::EntryPoint entryPoint,
157 GLenum format,
158 GLenum type,
159 GLint x,
160 GLint y,
161 GLsizei width,
162 GLsizei height,
163 GLsizei bufSize,
164 GLsizei *length,
165 const void *pixels);
166
167 bool ValidateReadPixelsBase(const Context *context,
168 angle::EntryPoint entryPoint,
169 GLint x,
170 GLint y,
171 GLsizei width,
172 GLsizei height,
173 GLenum format,
174 GLenum type,
175 GLsizei bufSize,
176 GLsizei *length,
177 GLsizei *columns,
178 GLsizei *rows,
179 const void *pixels);
180 bool ValidateReadPixelsRobustANGLE(const Context *context,
181 angle::EntryPoint entryPoint,
182 GLint x,
183 GLint y,
184 GLsizei width,
185 GLsizei height,
186 GLenum format,
187 GLenum type,
188 GLsizei bufSize,
189 const GLsizei *length,
190 const GLsizei *columns,
191 const GLsizei *rows,
192 const void *pixels);
193 bool ValidateReadnPixelsEXT(const Context *context,
194 angle::EntryPoint entryPoint,
195 GLint x,
196 GLint y,
197 GLsizei width,
198 GLsizei height,
199 GLenum format,
200 GLenum type,
201 GLsizei bufSize,
202 const void *pixels);
203 bool ValidateReadnPixelsRobustANGLE(const Context *context,
204 angle::EntryPoint entryPoint,
205 GLint x,
206 GLint y,
207 GLsizei width,
208 GLsizei height,
209 GLenum format,
210 GLenum type,
211 GLsizei bufSize,
212 const GLsizei *length,
213 const GLsizei *columns,
214 const GLsizei *rows,
215 const void *data);
216
217 bool ValidateGenQueriesEXT(const Context *context,
218 angle::EntryPoint entryPoint,
219 GLsizei n,
220 const QueryID *ids);
221 bool ValidateDeleteQueriesEXT(const Context *context,
222 angle::EntryPoint entryPoint,
223 GLsizei n,
224 const QueryID *ids);
225 bool ValidateIsQueryEXT(const Context *context, angle::EntryPoint entryPoint, QueryID id);
226 bool ValidateBeginQueryBase(const Context *context,
227 angle::EntryPoint entryPoint,
228 QueryType target,
229 QueryID id);
230 bool ValidateBeginQueryEXT(const Context *context,
231 angle::EntryPoint entryPoint,
232 QueryType target,
233 QueryID id);
234 bool ValidateEndQueryBase(const Context *context, angle::EntryPoint entryPoint, QueryType target);
235 bool ValidateEndQueryEXT(const Context *context, angle::EntryPoint entryPoint, QueryType target);
236 bool ValidateQueryCounterEXT(const Context *context,
237 angle::EntryPoint entryPoint,
238 QueryID id,
239 QueryType target);
240 bool ValidateGetQueryivBase(const Context *context,
241 angle::EntryPoint entryPoint,
242 QueryType target,
243 GLenum pname,
244 GLsizei *numParams);
245 bool ValidateGetQueryivEXT(const Context *context,
246 angle::EntryPoint entryPoint,
247 QueryType target,
248 GLenum pname,
249 const GLint *params);
250 bool ValidateGetQueryivRobustANGLE(const Context *context,
251 angle::EntryPoint entryPoint,
252 QueryType target,
253 GLenum pname,
254 GLsizei bufSize,
255 const GLsizei *length,
256 const GLint *params);
257 bool ValidateGetQueryObjectValueBase(const Context *context,
258 angle::EntryPoint entryPoint,
259 QueryID id,
260 GLenum pname,
261 GLsizei *numParams);
262 bool ValidateGetQueryObjectivEXT(const Context *context,
263 angle::EntryPoint entryPoint,
264 QueryID id,
265 GLenum pname,
266 const GLint *params);
267 bool ValidateGetQueryObjectivRobustANGLE(const Context *context,
268 angle::EntryPoint entryPoint,
269 QueryID id,
270 GLenum pname,
271 GLsizei bufSize,
272 const GLsizei *length,
273 const GLint *params);
274 bool ValidateGetQueryObjectuivEXT(const Context *context,
275 angle::EntryPoint entryPoint,
276 QueryID id,
277 GLenum pname,
278 const GLuint *params);
279 bool ValidateGetQueryObjectuivRobustANGLE(const Context *context,
280 angle::EntryPoint entryPoint,
281 QueryID id,
282 GLenum pname,
283 GLsizei bufSize,
284 const GLsizei *length,
285 const GLuint *params);
286 bool ValidateGetQueryObjecti64vEXT(const Context *context,
287 angle::EntryPoint entryPoint,
288 QueryID id,
289 GLenum pname,
290 GLint64 *params);
291 bool ValidateGetQueryObjecti64vRobustANGLE(const Context *context,
292 angle::EntryPoint entryPoint,
293 QueryID id,
294 GLenum pname,
295 GLsizei bufSize,
296 const GLsizei *length,
297 GLint64 *params);
298 bool ValidateGetQueryObjectui64vEXT(const Context *context,
299 angle::EntryPoint entryPoint,
300 QueryID id,
301 GLenum pname,
302 GLuint64 *params);
303 bool ValidateGetQueryObjectui64vRobustANGLE(const Context *context,
304 angle::EntryPoint entryPoint,
305 QueryID id,
306 GLenum pname,
307 GLsizei bufSize,
308 const GLsizei *length,
309 GLuint64 *params);
310
311 bool ValidateUniformCommonBase(const Context *context,
312 angle::EntryPoint entryPoint,
313 const Program *program,
314 UniformLocation location,
315 GLsizei count,
316 const LinkedUniform **uniformOut);
317 bool ValidateUniform1ivValue(const Context *context,
318 angle::EntryPoint entryPoint,
319 GLenum uniformType,
320 GLsizei count,
321 const GLint *value);
322
ValidateUniformValue(const Context * context,angle::EntryPoint entryPoint,GLenum valueType,GLenum uniformType)323 ANGLE_INLINE bool ValidateUniformValue(const Context *context,
324 angle::EntryPoint entryPoint,
325 GLenum valueType,
326 GLenum uniformType)
327 {
328 // Check that the value type is compatible with uniform type.
329 // Do the cheaper test first, for a little extra speed.
330 if (valueType != uniformType && VariableBoolVectorType(valueType) != uniformType)
331 {
332 context->validationError(entryPoint, GL_INVALID_OPERATION, err::kUniformSizeMismatch);
333 return false;
334 }
335 return true;
336 }
337
338 bool ValidateUniformMatrixValue(const Context *context,
339 angle::EntryPoint entryPoint,
340 GLenum valueType,
341 GLenum uniformType);
342 bool ValidateUniform(const Context *context,
343 angle::EntryPoint entryPoint,
344 GLenum uniformType,
345 UniformLocation location,
346 GLsizei count);
347 bool ValidateUniformMatrix(const Context *context,
348 angle::EntryPoint entryPoint,
349 GLenum matrixType,
350 UniformLocation location,
351 GLsizei count,
352 GLboolean transpose);
353 bool ValidateGetBooleanvRobustANGLE(const Context *context,
354 angle::EntryPoint entryPoint,
355 GLenum pname,
356 GLsizei bufSize,
357 const GLsizei *length,
358 const GLboolean *params);
359 bool ValidateGetFloatvRobustANGLE(const Context *context,
360 angle::EntryPoint entryPoint,
361 GLenum pname,
362 GLsizei bufSize,
363 const GLsizei *length,
364 const GLfloat *params);
365 bool ValidateStateQuery(const Context *context,
366 angle::EntryPoint entryPoint,
367 GLenum pname,
368 GLenum *nativeType,
369 unsigned int *numParams);
370 bool ValidateGetIntegervRobustANGLE(const Context *context,
371 angle::EntryPoint entryPoint,
372 GLenum pname,
373 GLsizei bufSize,
374 const GLsizei *length,
375 const GLint *data);
376 bool ValidateGetInteger64vRobustANGLE(const Context *context,
377 angle::EntryPoint entryPoint,
378 GLenum pname,
379 GLsizei bufSize,
380 const GLsizei *length,
381 GLint64 *data);
382 bool ValidateRobustStateQuery(const Context *context,
383 angle::EntryPoint entryPoint,
384 GLenum pname,
385 GLsizei bufSize,
386 GLenum *nativeType,
387 unsigned int *numParams);
388
389 bool ValidateCopyImageSubDataBase(const Context *context,
390 angle::EntryPoint entryPoint,
391 GLuint srcName,
392 GLenum srcTarget,
393 GLint srcLevel,
394 GLint srcX,
395 GLint srcY,
396 GLint srcZ,
397 GLuint dstName,
398 GLenum dstTarget,
399 GLint dstLevel,
400 GLint dstX,
401 GLint dstY,
402 GLint dstZ,
403 GLsizei srcWidth,
404 GLsizei srcHeight,
405 GLsizei srcDepth);
406
407 bool ValidateCopyTexImageParametersBase(const Context *context,
408 angle::EntryPoint entryPoint,
409 TextureTarget target,
410 GLint level,
411 GLenum internalformat,
412 bool isSubImage,
413 GLint xoffset,
414 GLint yoffset,
415 GLint zoffset,
416 GLint x,
417 GLint y,
418 GLsizei width,
419 GLsizei height,
420 GLint border,
421 Format *textureFormatOut);
422
423 void RecordDrawModeError(const Context *context, angle::EntryPoint entryPoint, PrimitiveMode mode);
424 const char *ValidateDrawElementsStates(const Context *context);
425
ValidateDrawBase(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode)426 ANGLE_INLINE bool ValidateDrawBase(const Context *context,
427 angle::EntryPoint entryPoint,
428 PrimitiveMode mode)
429 {
430 intptr_t drawStatesError = context->getStateCache().getBasicDrawStatesError(context);
431 if (drawStatesError)
432 {
433 const char *errorMessage = reinterpret_cast<const char *>(drawStatesError);
434
435 // All errors from ValidateDrawStates should return INVALID_OPERATION except Framebuffer
436 // Incomplete.
437 bool isFramebufferIncomplete = strcmp(errorMessage, err::kDrawFramebufferIncomplete) == 0;
438 GLenum errorCode =
439 isFramebufferIncomplete ? GL_INVALID_FRAMEBUFFER_OPERATION : GL_INVALID_OPERATION;
440 context->validationError(entryPoint, errorCode, errorMessage);
441 return false;
442 }
443
444 if (!context->getStateCache().isValidDrawMode(mode))
445 {
446 RecordDrawModeError(context, entryPoint, mode);
447 return false;
448 }
449
450 return true;
451 }
452
453 bool ValidateDrawArraysInstancedBase(const Context *context,
454 angle::EntryPoint entryPoint,
455 PrimitiveMode mode,
456 GLint first,
457 GLsizei count,
458 GLsizei primcount);
459 bool ValidateDrawArraysInstancedANGLE(const Context *context,
460 angle::EntryPoint entryPoint,
461 PrimitiveMode mode,
462 GLint first,
463 GLsizei count,
464 GLsizei primcount);
465 bool ValidateDrawArraysInstancedEXT(const Context *context,
466 angle::EntryPoint entryPoint,
467 PrimitiveMode mode,
468 GLint first,
469 GLsizei count,
470 GLsizei primcount);
471
472 bool ValidateDrawElementsInstancedBase(const Context *context,
473 angle::EntryPoint entryPoint,
474 PrimitiveMode mode,
475 GLsizei count,
476 DrawElementsType type,
477 const void *indices,
478 GLsizei primcount);
479 bool ValidateDrawElementsInstancedANGLE(const Context *context,
480 angle::EntryPoint entryPoint,
481 PrimitiveMode mode,
482 GLsizei count,
483 DrawElementsType type,
484 const void *indices,
485 GLsizei primcount);
486 bool ValidateDrawElementsInstancedEXT(const Context *context,
487 angle::EntryPoint entryPoint,
488 PrimitiveMode mode,
489 GLsizei count,
490 DrawElementsType type,
491 const void *indices,
492 GLsizei primcount);
493
494 bool ValidateDrawInstancedANGLE(const Context *context, angle::EntryPoint entryPoint);
495
496 bool ValidateGetUniformBase(const Context *context,
497 angle::EntryPoint entryPoint,
498 ShaderProgramID program,
499 UniformLocation location);
500 bool ValidateGetnUniformfvEXT(const Context *context,
501 angle::EntryPoint entryPoint,
502 ShaderProgramID program,
503 UniformLocation location,
504 GLsizei bufSize,
505 const GLfloat *params);
506 bool ValidateGetnUniformfvRobustANGLE(const Context *context,
507 angle::EntryPoint entryPoint,
508 ShaderProgramID program,
509 UniformLocation location,
510 GLsizei bufSize,
511 const GLsizei *length,
512 const GLfloat *params);
513 bool ValidateGetnUniformivEXT(const Context *context,
514 angle::EntryPoint entryPoint,
515 ShaderProgramID program,
516 UniformLocation location,
517 GLsizei bufSize,
518 const GLint *params);
519 bool ValidateGetnUniformivRobustANGLE(const Context *context,
520 angle::EntryPoint entryPoint,
521 ShaderProgramID program,
522 UniformLocation location,
523 GLsizei bufSize,
524 const GLsizei *length,
525 const GLint *params);
526 bool ValidateGetnUniformuivRobustANGLE(const Context *context,
527 angle::EntryPoint entryPoint,
528 ShaderProgramID program,
529 UniformLocation location,
530 GLsizei bufSize,
531 const GLsizei *length,
532 const GLuint *params);
533 bool ValidateGetUniformfvRobustANGLE(const Context *context,
534 angle::EntryPoint entryPoint,
535 ShaderProgramID program,
536 UniformLocation location,
537 GLsizei bufSize,
538 const GLsizei *length,
539 const GLfloat *params);
540 bool ValidateGetUniformivRobustANGLE(const Context *context,
541 angle::EntryPoint entryPoint,
542 ShaderProgramID program,
543 UniformLocation location,
544 GLsizei bufSize,
545 const GLsizei *length,
546 const GLint *params);
547 bool ValidateGetUniformuivRobustANGLE(const Context *context,
548 angle::EntryPoint entryPoint,
549 ShaderProgramID program,
550 UniformLocation location,
551 GLsizei bufSize,
552 const GLsizei *length,
553 const GLuint *params);
554
555 bool ValidateDiscardFramebufferBase(const Context *context,
556 angle::EntryPoint entryPoint,
557 GLenum target,
558 GLsizei numAttachments,
559 const GLenum *attachments,
560 bool defaultFramebuffer);
561
562 bool ValidateInsertEventMarkerEXT(const Context *context,
563 angle::EntryPoint entryPoint,
564 GLsizei length,
565 const char *marker);
566 bool ValidatePushGroupMarkerEXT(const Context *context,
567 angle::EntryPoint entryPoint,
568 GLsizei length,
569 const char *marker);
570
571 bool ValidateEGLImageTargetTexture2DOES(const Context *context,
572 angle::EntryPoint entryPoint,
573 TextureType type,
574 GLeglImageOES image);
575 bool ValidateEGLImageTargetRenderbufferStorageOES(const Context *context,
576 angle::EntryPoint entryPoint,
577 GLenum target,
578 GLeglImageOES image);
579
580 bool ValidateProgramBinaryBase(const Context *context,
581 angle::EntryPoint entryPoint,
582 ShaderProgramID program,
583 GLenum binaryFormat,
584 const void *binary,
585 GLint length);
586 bool ValidateGetProgramBinaryBase(const Context *context,
587 angle::EntryPoint entryPoint,
588 ShaderProgramID program,
589 GLsizei bufSize,
590 const GLsizei *length,
591 const GLenum *binaryFormat,
592 const void *binary);
593
594 bool ValidateDrawBuffersBase(const Context *context,
595 angle::EntryPoint entryPoint,
596 GLsizei n,
597 const GLenum *bufs);
598
599 bool ValidateGetBufferPointervBase(const Context *context,
600 angle::EntryPoint entryPoint,
601 BufferBinding target,
602 GLenum pname,
603 GLsizei *length,
604 void *const *params);
605 bool ValidateUnmapBufferBase(const Context *context,
606 angle::EntryPoint entryPoint,
607 BufferBinding target);
608 bool ValidateMapBufferRangeBase(const Context *context,
609 angle::EntryPoint entryPoint,
610 BufferBinding target,
611 GLintptr offset,
612 GLsizeiptr length,
613 GLbitfield access);
614 bool ValidateFlushMappedBufferRangeBase(const Context *context,
615 angle::EntryPoint entryPoint,
616 BufferBinding target,
617 GLintptr offset,
618 GLsizeiptr length);
619
620 bool ValidateGenOrDelete(const Context *context, angle::EntryPoint entryPoint, GLint n);
621
622 bool ValidateRobustEntryPoint(const Context *context,
623 angle::EntryPoint entryPoint,
624 GLsizei bufSize);
625 bool ValidateRobustBufferSize(const Context *context,
626 angle::EntryPoint entryPoint,
627 GLsizei bufSize,
628 GLsizei numParams);
629
630 bool ValidateGetFramebufferAttachmentParameterivBase(const Context *context,
631 angle::EntryPoint entryPoint,
632 GLenum target,
633 GLenum attachment,
634 GLenum pname,
635 GLsizei *numParams);
636
637 bool ValidateGetBufferParameterBase(const Context *context,
638 angle::EntryPoint entryPoint,
639 BufferBinding target,
640 GLenum pname,
641 bool pointerVersion,
642 GLsizei *numParams);
643
644 bool ValidateGetProgramivBase(const Context *context,
645 angle::EntryPoint entryPoint,
646 ShaderProgramID program,
647 GLenum pname,
648 GLsizei *numParams);
649
650 bool ValidateGetRenderbufferParameterivBase(const Context *context,
651 angle::EntryPoint entryPoint,
652 GLenum target,
653 GLenum pname,
654 GLsizei *length);
655
656 bool ValidateGetShaderivBase(const Context *context,
657 angle::EntryPoint entryPoint,
658 ShaderProgramID shader,
659 GLenum pname,
660 GLsizei *length);
661
662 bool ValidateGetTexParameterBase(const Context *context,
663 angle::EntryPoint entryPoint,
664 TextureType target,
665 GLenum pname,
666 GLsizei *length);
667
668 template <typename ParamType>
669 bool ValidateTexParameterBase(const Context *context,
670 angle::EntryPoint entryPoint,
671 TextureType target,
672 GLenum pname,
673 GLsizei bufSize,
674 bool vectorParams,
675 const ParamType *params);
676
677 bool ValidateGetVertexAttribBase(const Context *context,
678 angle::EntryPoint entryPoint,
679 GLuint index,
680 GLenum pname,
681 GLsizei *length,
682 bool pointer,
683 bool pureIntegerEntryPoint);
684
ValidateVertexFormat(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLint size,VertexAttribTypeCase validation)685 ANGLE_INLINE bool ValidateVertexFormat(const Context *context,
686 angle::EntryPoint entryPoint,
687 GLuint index,
688 GLint size,
689 VertexAttribTypeCase validation)
690 {
691 const Caps &caps = context->getCaps();
692 if (index >= static_cast<GLuint>(caps.maxVertexAttributes))
693 {
694 context->validationError(entryPoint, GL_INVALID_VALUE,
695 err::kIndexExceedsMaxVertexAttribute);
696 return false;
697 }
698
699 switch (validation)
700 {
701 case VertexAttribTypeCase::Invalid:
702 context->validationError(entryPoint, GL_INVALID_ENUM, err::kInvalidType);
703 return false;
704 case VertexAttribTypeCase::Valid:
705 if (size < 1 || size > 4)
706 {
707 context->validationError(entryPoint, GL_INVALID_VALUE, err::kInvalidVertexAttrSize);
708 return false;
709 }
710 break;
711 case VertexAttribTypeCase::ValidSize4Only:
712 if (size != 4)
713 {
714 context->validationError(entryPoint, GL_INVALID_OPERATION,
715 err::kInvalidVertexAttribSize2101010);
716 return false;
717 }
718 break;
719 case VertexAttribTypeCase::ValidSize3or4:
720 if (size != 3 && size != 4)
721 {
722 context->validationError(entryPoint, GL_INVALID_OPERATION,
723 err::kInvalidVertexAttribSize1010102);
724 return false;
725 }
726 break;
727 }
728
729 return true;
730 }
731
732 // Note: These byte, short, and int types are all converted to float for the shader.
ValidateFloatVertexFormat(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLint size,VertexAttribType type)733 ANGLE_INLINE bool ValidateFloatVertexFormat(const Context *context,
734 angle::EntryPoint entryPoint,
735 GLuint index,
736 GLint size,
737 VertexAttribType type)
738 {
739 return ValidateVertexFormat(context, entryPoint, index, size,
740 context->getStateCache().getVertexAttribTypeValidation(type));
741 }
742
ValidateIntegerVertexFormat(const Context * context,angle::EntryPoint entryPoint,GLuint index,GLint size,VertexAttribType type)743 ANGLE_INLINE bool ValidateIntegerVertexFormat(const Context *context,
744 angle::EntryPoint entryPoint,
745 GLuint index,
746 GLint size,
747 VertexAttribType type)
748 {
749 return ValidateVertexFormat(
750 context, entryPoint, index, size,
751 context->getStateCache().getIntegerVertexAttribTypeValidation(type));
752 }
753
754 bool ValidateWebGLFramebufferAttachmentClearType(const Context *context,
755 angle::EntryPoint entryPoint,
756 GLint drawbuffer,
757 const GLenum *validComponentTypes,
758 size_t validComponentTypeCount);
759
760 bool ValidateRobustCompressedTexImageBase(const Context *context,
761 angle::EntryPoint entryPoint,
762 GLsizei imageSize,
763 GLsizei dataSize);
764
765 bool ValidateVertexAttribIndex(const Context *context, angle::EntryPoint entryPoint, GLuint index);
766
767 bool ValidateGetActiveUniformBlockivBase(const Context *context,
768 angle::EntryPoint entryPoint,
769 ShaderProgramID program,
770 UniformBlockIndex uniformBlockIndex,
771 GLenum pname,
772 GLsizei *length);
773
774 bool ValidateGetSamplerParameterBase(const Context *context,
775 angle::EntryPoint entryPoint,
776 SamplerID sampler,
777 GLenum pname,
778 GLsizei *length);
779
780 template <typename ParamType>
781 bool ValidateSamplerParameterBase(const Context *context,
782 angle::EntryPoint entryPoint,
783 SamplerID sampler,
784 GLenum pname,
785 GLsizei bufSize,
786 bool vectorParams,
787 const ParamType *params);
788
789 bool ValidateGetInternalFormativBase(const Context *context,
790 angle::EntryPoint entryPoint,
791 GLenum target,
792 GLenum internalformat,
793 GLenum pname,
794 GLsizei bufSize,
795 GLsizei *numParams);
796
797 bool ValidateFramebufferNotMultisampled(const Context *context,
798 angle::EntryPoint entryPoint,
799 const Framebuffer *framebuffer,
800 bool checkReadBufferResourceSamples);
801
802 bool ValidateMultitextureUnit(const Context *context, angle::EntryPoint entryPoint, GLenum texture);
803
804 bool ValidateTransformFeedbackPrimitiveMode(const Context *context,
805 angle::EntryPoint entryPoint,
806 PrimitiveMode transformFeedbackPrimitiveMode,
807 PrimitiveMode renderPrimitiveMode);
808
809 // Common validation for 2D and 3D variants of TexStorage*Multisample.
810 bool ValidateTexStorageMultisample(const Context *context,
811 angle::EntryPoint entryPoint,
812 TextureType target,
813 GLsizei samples,
814 GLint internalFormat,
815 GLsizei width,
816 GLsizei height);
817
818 bool ValidateTexStorage2DMultisampleBase(const Context *context,
819 angle::EntryPoint entryPoint,
820 TextureType target,
821 GLsizei samples,
822 GLint internalFormat,
823 GLsizei width,
824 GLsizei height);
825
826 bool ValidateGetTexLevelParameterBase(const Context *context,
827 angle::EntryPoint entryPoint,
828 TextureTarget target,
829 GLint level,
830 GLenum pname,
831 GLsizei *length);
832
833 bool ValidateMapBufferBase(const Context *context,
834 angle::EntryPoint entryPoint,
835 BufferBinding target);
836 bool ValidateIndexedStateQuery(const Context *context,
837 angle::EntryPoint entryPoint,
838 GLenum pname,
839 GLuint index,
840 GLsizei *length);
841 bool ValidateES3TexImage2DParameters(const Context *context,
842 angle::EntryPoint entryPoint,
843 TextureTarget target,
844 GLint level,
845 GLenum internalformat,
846 bool isCompressed,
847 bool isSubImage,
848 GLint xoffset,
849 GLint yoffset,
850 GLint zoffset,
851 GLsizei width,
852 GLsizei height,
853 GLsizei depth,
854 GLint border,
855 GLenum format,
856 GLenum type,
857 GLsizei imageSize,
858 const void *pixels);
859 bool ValidateES3CopyTexImage2DParameters(const Context *context,
860 angle::EntryPoint entryPoint,
861 TextureTarget target,
862 GLint level,
863 GLenum internalformat,
864 bool isSubImage,
865 GLint xoffset,
866 GLint yoffset,
867 GLint zoffset,
868 GLint x,
869 GLint y,
870 GLsizei width,
871 GLsizei height,
872 GLint border);
873 bool ValidateES3TexStorage2DParameters(const Context *context,
874 angle::EntryPoint entryPoint,
875 TextureType target,
876 GLsizei levels,
877 GLenum internalformat,
878 GLsizei width,
879 GLsizei height,
880 GLsizei depth);
881 bool ValidateES3TexStorage3DParameters(const Context *context,
882 angle::EntryPoint entryPoint,
883 TextureType target,
884 GLsizei levels,
885 GLenum internalformat,
886 GLsizei width,
887 GLsizei height,
888 GLsizei depth);
889
890 bool ValidateGetMultisamplefvBase(const Context *context,
891 angle::EntryPoint entryPoint,
892 GLenum pname,
893 GLuint index,
894 const GLfloat *val);
895 bool ValidateSampleMaskiBase(const Context *context,
896 angle::EntryPoint entryPoint,
897 GLuint maskNumber,
898 GLbitfield mask);
899
900 // We should check with Khronos if returning INVALID_FRAMEBUFFER_OPERATION is OK when querying
901 // implementation format info for incomplete framebuffers. It seems like these queries are
902 // incongruent with the other errors.
903 // Inlined for speed.
904 template <GLenum ErrorCode = GL_INVALID_FRAMEBUFFER_OPERATION>
ValidateFramebufferComplete(const Context * context,angle::EntryPoint entryPoint,const Framebuffer * framebuffer)905 ANGLE_INLINE bool ValidateFramebufferComplete(const Context *context,
906 angle::EntryPoint entryPoint,
907 const Framebuffer *framebuffer)
908 {
909 const FramebufferStatus &framebufferStatus = framebuffer->checkStatus(context);
910 if (!framebufferStatus.isComplete())
911 {
912 ASSERT(framebufferStatus.reason != nullptr);
913 context->validationError(entryPoint, ErrorCode, framebufferStatus.reason);
914 return false;
915 }
916
917 return true;
918 }
919
920 const char *ValidateProgramPipelineDrawStates(const State &state,
921 const Extensions &extensions,
922 ProgramPipeline *programPipeline);
923 const char *ValidateProgramPipelineAttachedPrograms(ProgramPipeline *programPipeline);
924 const char *ValidateDrawStates(const Context *context);
925
926 void RecordDrawAttribsError(const Context *context, angle::EntryPoint entryPoint);
927
ValidateDrawAttribs(const Context * context,angle::EntryPoint entryPoint,int64_t maxVertex)928 ANGLE_INLINE bool ValidateDrawAttribs(const Context *context,
929 angle::EntryPoint entryPoint,
930 int64_t maxVertex)
931 {
932 if (maxVertex > context->getStateCache().getNonInstancedVertexElementLimit())
933 {
934 RecordDrawAttribsError(context, entryPoint);
935 return false;
936 }
937
938 return true;
939 }
940
ValidateDrawArraysAttribs(const Context * context,angle::EntryPoint entryPoint,GLint first,GLsizei count)941 ANGLE_INLINE bool ValidateDrawArraysAttribs(const Context *context,
942 angle::EntryPoint entryPoint,
943 GLint first,
944 GLsizei count)
945 {
946 if (!context->isBufferAccessValidationEnabled())
947 {
948 return true;
949 }
950
951 // Check the computation of maxVertex doesn't overflow.
952 // - first < 0 has been checked as an error condition.
953 // - if count <= 0, skip validating no-op draw calls.
954 // From this we know maxVertex will be positive, and only need to check if it overflows GLint.
955 ASSERT(first >= 0);
956 ASSERT(count > 0);
957 int64_t maxVertex = static_cast<int64_t>(first) + static_cast<int64_t>(count) - 1;
958 if (maxVertex > static_cast<int64_t>(std::numeric_limits<GLint>::max()))
959 {
960 context->validationError(entryPoint, GL_INVALID_OPERATION, err::kIntegerOverflow);
961 return false;
962 }
963
964 return ValidateDrawAttribs(context, entryPoint, maxVertex);
965 }
966
ValidateDrawInstancedAttribs(const Context * context,angle::EntryPoint entryPoint,GLint primcount)967 ANGLE_INLINE bool ValidateDrawInstancedAttribs(const Context *context,
968 angle::EntryPoint entryPoint,
969 GLint primcount)
970 {
971 if (!context->isBufferAccessValidationEnabled())
972 {
973 return true;
974 }
975
976 if ((primcount - 1) > context->getStateCache().getInstancedVertexElementLimit())
977 {
978 RecordDrawAttribsError(context, entryPoint);
979 return false;
980 }
981
982 return true;
983 }
984
ValidateDrawArraysCommon(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLint first,GLsizei count,GLsizei primcount)985 ANGLE_INLINE bool ValidateDrawArraysCommon(const Context *context,
986 angle::EntryPoint entryPoint,
987 PrimitiveMode mode,
988 GLint first,
989 GLsizei count,
990 GLsizei primcount)
991 {
992 if (first < 0)
993 {
994 context->validationError(entryPoint, GL_INVALID_VALUE, err::kNegativeStart);
995 return false;
996 }
997
998 if (count <= 0)
999 {
1000 if (count < 0)
1001 {
1002 context->validationError(entryPoint, GL_INVALID_VALUE, err::kNegativeCount);
1003 return false;
1004 }
1005
1006 // Early exit.
1007 return ValidateDrawBase(context, entryPoint, mode);
1008 }
1009
1010 if (!ValidateDrawBase(context, entryPoint, mode))
1011 {
1012 return false;
1013 }
1014
1015 if (context->getStateCache().isTransformFeedbackActiveUnpaused() &&
1016 !context->supportsGeometryOrTesselation())
1017 {
1018 const State &state = context->getState();
1019 TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
1020 if (!curTransformFeedback->checkBufferSpaceForDraw(count, primcount))
1021 {
1022 context->validationError(entryPoint, GL_INVALID_OPERATION,
1023 err::kTransformFeedbackBufferTooSmall);
1024 return false;
1025 }
1026 }
1027
1028 return ValidateDrawArraysAttribs(context, entryPoint, first, count);
1029 }
1030
ValidateDrawElementsBase(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,DrawElementsType type)1031 ANGLE_INLINE bool ValidateDrawElementsBase(const Context *context,
1032 angle::EntryPoint entryPoint,
1033 PrimitiveMode mode,
1034 DrawElementsType type)
1035 {
1036 if (!context->getStateCache().isValidDrawElementsType(type))
1037 {
1038 if (type == DrawElementsType::UnsignedInt)
1039 {
1040 context->validationError(entryPoint, GL_INVALID_ENUM, err::kTypeNotUnsignedShortByte);
1041 return false;
1042 }
1043
1044 ASSERT(type == DrawElementsType::InvalidEnum);
1045 context->validationError(entryPoint, GL_INVALID_ENUM, err::kEnumNotSupported);
1046 return false;
1047 }
1048
1049 intptr_t drawElementsError = context->getStateCache().getBasicDrawElementsError(context);
1050 if (drawElementsError)
1051 {
1052 // All errors from ValidateDrawElementsStates return INVALID_OPERATION.
1053 const char *errorMessage = reinterpret_cast<const char *>(drawElementsError);
1054 context->validationError(entryPoint, GL_INVALID_OPERATION, errorMessage);
1055 return false;
1056 }
1057
1058 // Note that we are missing overflow checks for active transform feedback buffers.
1059 return true;
1060 }
1061
ValidateDrawElementsCommon(const Context * context,angle::EntryPoint entryPoint,PrimitiveMode mode,GLsizei count,DrawElementsType type,const void * indices,GLsizei primcount)1062 ANGLE_INLINE bool ValidateDrawElementsCommon(const Context *context,
1063 angle::EntryPoint entryPoint,
1064 PrimitiveMode mode,
1065 GLsizei count,
1066 DrawElementsType type,
1067 const void *indices,
1068 GLsizei primcount)
1069 {
1070 if (!ValidateDrawElementsBase(context, entryPoint, mode, type))
1071 {
1072 return false;
1073 }
1074
1075 ASSERT(isPow2(GetDrawElementsTypeSize(type)) && GetDrawElementsTypeSize(type) > 0);
1076
1077 if (context->isWebGL())
1078 {
1079 GLuint typeBytes = GetDrawElementsTypeSize(type);
1080
1081 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
1082 {
1083 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
1084 // The offset arguments to drawElements and [...], must be a multiple of the size of the
1085 // data type passed to the call, or an INVALID_OPERATION error is generated.
1086 context->validationError(entryPoint, GL_INVALID_OPERATION,
1087 err::kOffsetMustBeMultipleOfType);
1088 return false;
1089 }
1090
1091 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
1092 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
1093 // error is generated.
1094 if (reinterpret_cast<intptr_t>(indices) < 0)
1095 {
1096 context->validationError(entryPoint, GL_INVALID_VALUE, err::kNegativeOffset);
1097 return false;
1098 }
1099 }
1100
1101 if (count <= 0)
1102 {
1103 if (count < 0)
1104 {
1105 context->validationError(entryPoint, GL_INVALID_VALUE, err::kNegativeCount);
1106 return false;
1107 }
1108
1109 // Early exit.
1110 return ValidateDrawBase(context, entryPoint, mode);
1111 }
1112
1113 if (!ValidateDrawBase(context, entryPoint, mode))
1114 {
1115 return false;
1116 }
1117
1118 const State &state = context->getState();
1119 const VertexArray *vao = state.getVertexArray();
1120 Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1121
1122 if (!elementArrayBuffer)
1123 {
1124 if (!indices)
1125 {
1126 // This is an application error that would normally result in a crash, but we catch
1127 // it and return an error
1128 context->validationError(entryPoint, GL_INVALID_OPERATION,
1129 err::kElementArrayNoBufferOrPointer);
1130 return false;
1131 }
1132 }
1133 else
1134 {
1135 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
1136 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
1137 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
1138 constexpr uint64_t kMaxTypeSize = 8;
1139 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
1140 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
1141 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
1142
1143 uint64_t elementCount = static_cast<uint64_t>(count);
1144 ASSERT(elementCount > 0 && GetDrawElementsTypeSize(type) <= kMaxTypeSize);
1145
1146 // Doing the multiplication here is overflow-safe
1147 uint64_t elementDataSizeNoOffset = elementCount << GetDrawElementsTypeShift(type);
1148
1149 // The offset can be any value, check for overflows
1150 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
1151 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
1152 if (elementDataSizeWithOffset < elementDataSizeNoOffset)
1153 {
1154 context->validationError(entryPoint, GL_INVALID_OPERATION, err::kIntegerOverflow);
1155 return false;
1156 }
1157
1158 // Related to possible test bug: https://github.com/KhronosGroup/WebGL/issues/3064
1159 if ((elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize())) &&
1160 (primcount > 0))
1161 {
1162 context->validationError(entryPoint, GL_INVALID_OPERATION,
1163 err::kInsufficientBufferSize);
1164 return false;
1165 }
1166 }
1167
1168 if (context->isBufferAccessValidationEnabled() && primcount > 0)
1169 {
1170 // Use the parameter buffer to retrieve and cache the index range.
1171 IndexRange indexRange{IndexRange::Undefined()};
1172 ANGLE_VALIDATION_TRY(vao->getIndexRange(context, type, count, indices, &indexRange));
1173
1174 // If we use an index greater than our maximum supported index range, return an error.
1175 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should
1176 // always return an error if possible here.
1177 if (static_cast<GLint64>(indexRange.end) >= context->getCaps().maxElementIndex)
1178 {
1179 context->validationError(entryPoint, GL_INVALID_OPERATION, err::kExceedsMaxElement);
1180 return false;
1181 }
1182
1183 if (!ValidateDrawAttribs(context, entryPoint, static_cast<GLint>(indexRange.end)))
1184 {
1185 return false;
1186 }
1187
1188 // No op if there are no real indices in the index data (all are primitive restart).
1189 return (indexRange.vertexIndexCount > 0);
1190 }
1191
1192 return true;
1193 }
1194
ValidateBindVertexArrayBase(const Context * context,angle::EntryPoint entryPoint,VertexArrayID array)1195 ANGLE_INLINE bool ValidateBindVertexArrayBase(const Context *context,
1196 angle::EntryPoint entryPoint,
1197 VertexArrayID array)
1198 {
1199 if (!context->isVertexArrayGenerated(array))
1200 {
1201 // The default VAO should always exist
1202 ASSERT(array.value != 0);
1203 context->validationError(entryPoint, GL_INVALID_OPERATION, err::kInvalidVertexArray);
1204 return false;
1205 }
1206
1207 return true;
1208 }
1209
ValidateVertexAttribIndex(const Context * context,angle::EntryPoint entryPoint,GLuint index)1210 ANGLE_INLINE bool ValidateVertexAttribIndex(const Context *context,
1211 angle::EntryPoint entryPoint,
1212 GLuint index)
1213 {
1214 if (index >= MAX_VERTEX_ATTRIBS)
1215 {
1216 context->validationError(entryPoint, GL_INVALID_VALUE,
1217 err::kIndexExceedsMaxVertexAttribute);
1218 return false;
1219 }
1220
1221 return true;
1222 }
1223 } // namespace gl
1224
1225 #endif // LIBANGLE_VALIDATION_ES_H_
1226