blob: b8ad6ef9f6dcbf8242d4d3125cdb1cb0050262c5 [file] [log] [blame]
Martin Radev66fb8202016-07-28 11:45:20 +03001//
2// Copyright (c) 2016 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// validationES31.cpp: Validation functions for OpenGL ES 3.1 entry point parameters
8
Martin Radev66fb8202016-07-28 11:45:20 +03009#include "libANGLE/validationES31.h"
10
11#include "libANGLE/Context.h"
JiangYizhouf7bbc8a2016-11-16 09:57:22 +080012#include "libANGLE/Framebuffer.h"
Geoff Lang2e43dbb2016-10-14 12:27:35 -040013#include "libANGLE/validationES.h"
14#include "libANGLE/validationES3.h"
Jiajia Qind9671222016-11-29 16:30:31 +080015#include "libANGLE/VertexArray.h"
Martin Radev66fb8202016-07-28 11:45:20 +030016
He Yunchao11b038b2016-11-22 21:24:04 +080017#include "common/utilities.h"
18
Martin Radev66fb8202016-07-28 11:45:20 +030019using namespace angle;
20
21namespace gl
22{
23
jchen1015015f72017-03-16 13:54:21 +080024namespace
25{
26
27bool ValidateNamedProgramInterface(GLenum programInterface)
28{
29 switch (programInterface)
30 {
31 case GL_UNIFORM:
32 case GL_UNIFORM_BLOCK:
33 case GL_PROGRAM_INPUT:
34 case GL_PROGRAM_OUTPUT:
35 case GL_TRANSFORM_FEEDBACK_VARYING:
36 case GL_BUFFER_VARIABLE:
37 case GL_SHADER_STORAGE_BLOCK:
38 return true;
39 default:
40 return false;
41 }
42}
43
jchen10fd7c3b52017-03-21 15:36:03 +080044bool ValidateProgramResourceIndex(const Program *programObject,
45 GLenum programInterface,
46 GLuint index)
47{
48 switch (programInterface)
49 {
50 case GL_PROGRAM_INPUT:
51 return (index < static_cast<GLuint>(programObject->getActiveAttributeCount()));
52
53 case GL_PROGRAM_OUTPUT:
54 return (index < static_cast<GLuint>(programObject->getOutputResourceCount()));
55
56 // TODO(Jie): more interfaces.
57 case GL_UNIFORM:
58 case GL_UNIFORM_BLOCK:
59 case GL_TRANSFORM_FEEDBACK_VARYING:
60 case GL_BUFFER_VARIABLE:
61 case GL_SHADER_STORAGE_BLOCK:
62 UNIMPLEMENTED();
63 return false;
64
65 default:
66 UNREACHABLE();
67 return false;
68 }
69}
70
jchen1015015f72017-03-16 13:54:21 +080071} // anonymous namespace
72
Martin Radev66fb8202016-07-28 11:45:20 +030073bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data)
74{
Geoff Langeb66a6e2016-10-31 13:06:12 -040075 if (context->getClientVersion() < ES_3_1)
Martin Radev66fb8202016-07-28 11:45:20 +030076 {
77 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
78 return false;
79 }
80
Geoff Lang2e43dbb2016-10-14 12:27:35 -040081 if (!ValidateIndexedStateQuery(context, target, index, nullptr))
82 {
83 return false;
84 }
85
86 return true;
87}
88
89bool ValidateGetBooleani_vRobustANGLE(Context *context,
90 GLenum target,
91 GLuint index,
92 GLsizei bufSize,
93 GLsizei *length,
94 GLboolean *data)
95{
Geoff Langeb66a6e2016-10-31 13:06:12 -040096 if (context->getClientVersion() < ES_3_1)
Geoff Lang2e43dbb2016-10-14 12:27:35 -040097 {
98 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
99 return false;
100 }
101
102 if (!ValidateRobustEntryPoint(context, bufSize))
103 {
104 return false;
105 }
106
107 if (!ValidateIndexedStateQuery(context, target, index, length))
108 {
109 return false;
110 }
111
112 if (!ValidateRobustBufferSize(context, bufSize, *length))
Martin Radev66fb8202016-07-28 11:45:20 +0300113 {
114 return false;
115 }
116
117 return true;
118}
119
Jamie Madill876429b2017-04-20 15:46:24 -0400120bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800121{
122 if (context->getClientVersion() < ES_3_1)
123 {
124 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
125 return false;
126 }
127
128 // Here the third parameter 1 is only to pass the count validation.
129 if (!ValidateDrawBase(context, mode, 1))
130 {
131 return false;
132 }
133
134 const State &state = context->getGLState();
135
136 // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING,
137 // DRAW_INDIRECT_BUFFER or to any enabled vertex array.
138 if (!state.getVertexArrayId())
139 {
140 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to VERTEX_ARRAY_BINDING"));
141 return false;
142 }
143
144 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
145 if (!drawIndirectBuffer)
146 {
147 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to DRAW_INDIRECT_BUFFER"));
148 return false;
149 }
150
151 // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic
152 // machine units, of uint.
153 GLint64 offset = reinterpret_cast<GLint64>(indirect);
154 if ((static_cast<GLuint>(offset) % sizeof(GLuint)) != 0)
155 {
156 context->handleError(
157 Error(GL_INVALID_VALUE,
158 "indirect is not a multiple of the size, in basic machine units, of uint"));
159 return false;
160 }
161
162 return true;
163}
164
Jamie Madill876429b2017-04-20 15:46:24 -0400165bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800166{
167 const State &state = context->getGLState();
168 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
169 if (curTransformFeedback && curTransformFeedback->isActive() &&
170 !curTransformFeedback->isPaused())
171 {
172 // An INVALID_OPERATION error is generated if transform feedback is active and not paused.
173 context->handleError(
174 Error(GL_INVALID_OPERATION, "transform feedback is active and not paused."));
175 return false;
176 }
177
178 if (!ValidateDrawIndirectBase(context, mode, indirect))
179 return false;
180
181 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
182 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
183 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand
184 // which's size is 4 * sizeof(uint).
185 auto checkedSum = checkedOffset + 4 * sizeof(GLuint);
186 if (!checkedSum.IsValid() ||
187 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
188 {
189 context->handleError(
190 Error(GL_INVALID_OPERATION,
191 "the command would source data beyond the end of the buffer object."));
192 return false;
193 }
194
195 return true;
196}
197
Jamie Madill876429b2017-04-20 15:46:24 -0400198bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800199{
200 if (!ValidateDrawElementsBase(context, type))
201 return false;
202
203 const State &state = context->getGLState();
204 const VertexArray *vao = state.getVertexArray();
205 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
206 if (!elementArrayBuffer)
207 {
208 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to ELEMENT_ARRAY_BUFFER"));
209 return false;
210 }
211
212 if (!ValidateDrawIndirectBase(context, mode, indirect))
213 return false;
214
215 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
216 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
217 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand
218 // which's size is 5 * sizeof(uint).
219 auto checkedSum = checkedOffset + 5 * sizeof(GLuint);
220 if (!checkedSum.IsValid() ||
221 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
222 {
223 context->handleError(
224 Error(GL_INVALID_OPERATION,
225 "the command would source data beyond the end of the buffer object."));
226 return false;
227 }
228
229 return true;
230}
231
He Yunchao11b038b2016-11-22 21:24:04 +0800232bool ValidateGetTexLevelParameterBase(Context *context,
233 GLenum target,
234 GLint level,
235 GLenum pname,
236 GLsizei *length)
237{
238 if (context->getClientVersion() < ES_3_1)
239 {
240 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
241 return false;
242 }
243
244 if (length)
245 {
246 *length = 0;
247 }
248
249 if (!ValidTexLevelDestinationTarget(context, target))
250 {
251 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
252 return false;
253 }
254
255 if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) ==
256 nullptr)
257 {
258 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
259 return false;
260 }
261
262 if (!ValidMipLevel(context, target, level))
263 {
264 context->handleError(Error(GL_INVALID_VALUE));
265 return false;
266 }
267
268 switch (pname)
269 {
270 case GL_TEXTURE_RED_TYPE:
271 case GL_TEXTURE_GREEN_TYPE:
272 case GL_TEXTURE_BLUE_TYPE:
273 case GL_TEXTURE_ALPHA_TYPE:
274 case GL_TEXTURE_DEPTH_TYPE:
275 break;
276 case GL_TEXTURE_RED_SIZE:
277 case GL_TEXTURE_GREEN_SIZE:
278 case GL_TEXTURE_BLUE_SIZE:
279 case GL_TEXTURE_ALPHA_SIZE:
280 case GL_TEXTURE_DEPTH_SIZE:
281 case GL_TEXTURE_STENCIL_SIZE:
282 case GL_TEXTURE_SHARED_SIZE:
283 break;
284 case GL_TEXTURE_INTERNAL_FORMAT:
285 case GL_TEXTURE_WIDTH:
286 case GL_TEXTURE_HEIGHT:
287 case GL_TEXTURE_DEPTH:
288 break;
289 case GL_TEXTURE_SAMPLES:
290 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
291 break;
292 case GL_TEXTURE_COMPRESSED:
293 break;
294 default:
295 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
296 return false;
297 }
298
299 if (length)
300 {
301 *length = 1;
302 }
303 return true;
304}
305
306bool ValidateGetTexLevelParameterfv(Context *context,
307 GLenum target,
308 GLint level,
309 GLenum pname,
310 GLfloat *params)
311{
312 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
313}
314
315bool ValidateGetTexLevelParameteriv(Context *context,
316 GLenum target,
317 GLint level,
318 GLenum pname,
319 GLint *params)
320{
321 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
322}
323
JiangYizhoubddc46b2016-12-09 09:50:51 +0800324bool ValidateTexStorage2DMultiSample(Context *context,
325 GLenum target,
326 GLsizei samples,
327 GLint internalFormat,
328 GLsizei width,
329 GLsizei height,
330 GLboolean fixedSampleLocations)
331{
332 if (context->getClientVersion() < ES_3_1)
333 {
334 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
335 return false;
336 }
337
338 if (target != GL_TEXTURE_2D_MULTISAMPLE)
339 {
340 context->handleError(Error(GL_INVALID_ENUM, "Target must be TEXTURE_2D_MULTISAMPLE."));
341 return false;
342 }
343
344 if (width < 1 || height < 1)
345 {
346 context->handleError(Error(GL_INVALID_VALUE, "Width and height must be positive."));
347 return false;
348 }
349
350 const Caps &caps = context->getCaps();
351 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
352 static_cast<GLuint>(height) > caps.max2DTextureSize)
353 {
354 context->handleError(
355 Error(GL_INVALID_VALUE,
356 "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE."));
357 return false;
358 }
359
360 if (samples == 0)
361 {
362 context->handleError(Error(GL_INVALID_VALUE, "Samples may not be zero."));
363 return false;
364 }
365
366 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
367 if (!formatCaps.renderable)
368 {
369 context->handleError(
370 Error(GL_INVALID_ENUM,
371 "SizedInternalformat must be color-renderable, depth-renderable, "
372 "or stencil-renderable."));
373 return false;
374 }
375
376 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
377 // is one of the unsized base internalformats listed in table 8.11.
Geoff Langca271392017-04-05 12:30:00 -0400378 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
379 if (formatInfo.internalFormat == GL_NONE)
JiangYizhoubddc46b2016-12-09 09:50:51 +0800380 {
381 context->handleError(
382 Error(GL_INVALID_ENUM,
383 "Internalformat is one of the unsupported unsized base internalformats."));
384 return false;
385 }
386
387 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
388 {
389 context->handleError(
390 Error(GL_INVALID_OPERATION,
391 "Samples must not be greater than maximum supported value for the format."));
392 return false;
393 }
394
395 Texture *texture = context->getTargetTexture(target);
396 if (!texture || texture->id() == 0)
397 {
398 context->handleError(Error(GL_INVALID_OPERATION, "Zero is bound to target."));
399 return false;
400 }
401
402 if (texture->getImmutableFormat())
403 {
404 context->handleError(
405 Error(GL_INVALID_OPERATION,
406 "The value of TEXTURE_IMMUTABLE_FORMAT for the texture "
407 "currently bound to target on the active texture unit is true."));
408 return false;
409 }
410
411 return true;
412}
413
414bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val)
415{
416 if (context->getClientVersion() < ES_3_1)
417 {
418 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
419 return false;
420 }
421
422 if (pname != GL_SAMPLE_POSITION)
423 {
424 context->handleError(Error(GL_INVALID_ENUM, "Pname must be SAMPLE_POSITION."));
425 return false;
426 }
427
428 GLint maxSamples = context->getCaps().maxSamples;
429 if (index >= static_cast<GLuint>(maxSamples))
430 {
431 context->handleError(
432 Error(GL_INVALID_VALUE, "Index must be less than the value of SAMPLES."));
433 return false;
434 }
435
436 return true;
437}
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800438
439bool ValidationFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param)
440{
441 if (context->getClientVersion() < ES_3_1)
442 {
443 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
444 return false;
445 }
446
447 if (!ValidFramebufferTarget(target))
448 {
449 context->handleError(Error(GL_INVALID_ENUM, "Invalid framebuffer target."));
450 return false;
451 }
452
453 switch (pname)
454 {
455 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
456 {
457 GLint maxWidth = context->getCaps().maxFramebufferWidth;
458 if (param < 0 || param > maxWidth)
459 {
460 context->handleError(
461 Error(GL_INVALID_VALUE,
462 "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH."));
463 return false;
464 }
465 break;
466 }
467 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
468 {
469 GLint maxHeight = context->getCaps().maxFramebufferHeight;
470 if (param < 0 || param > maxHeight)
471 {
472 context->handleError(
473 Error(GL_INVALID_VALUE,
474 "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT."));
475 return false;
476 }
477 break;
478 }
479 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
480 {
481 GLint maxSamples = context->getCaps().maxFramebufferSamples;
482 if (param < 0 || param > maxSamples)
483 {
484 context->handleError(
485 Error(GL_INVALID_VALUE,
486 "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES."));
487 return false;
488 }
489 break;
490 }
491 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
492 {
493 break;
494 }
495 default:
496 {
497 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname));
498 return false;
499 }
500 }
501
502 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
503 ASSERT(framebuffer);
504 if (framebuffer->id() == 0)
505 {
506 context->handleError(
507 Error(GL_INVALID_OPERATION, "Default framebuffer is bound to target."));
508 return false;
509 }
510 return true;
511}
512
513bool ValidationGetFramebufferParameteri(Context *context,
514 GLenum target,
515 GLenum pname,
516 GLint *params)
517{
518 if (context->getClientVersion() < ES_3_1)
519 {
520 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
521 return false;
522 }
523
524 if (!ValidFramebufferTarget(target))
525 {
526 context->handleError(Error(GL_INVALID_ENUM, "Invalid framebuffer target."));
527 return false;
528 }
529
530 switch (pname)
531 {
532 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
533 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
534 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
535 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
536 break;
537 default:
538 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname));
539 return false;
540 }
541
542 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
543 ASSERT(framebuffer);
544
545 if (framebuffer->id() == 0)
546 {
547 context->handleError(
548 Error(GL_INVALID_OPERATION, "Default framebuffer is bound to target."));
549 return false;
550 }
551 return true;
552}
553
jchen1015015f72017-03-16 13:54:21 +0800554bool ValidateGetProgramResourceIndex(Context *context,
555 GLuint program,
556 GLenum programInterface,
557 const GLchar *name)
558{
559 if (context->getClientVersion() < ES_3_1)
560 {
561 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES 3.1."));
562 return false;
563 }
564
565 Program *programObject = GetValidProgram(context, program);
566 if (programObject == nullptr)
567 {
568 return false;
569 }
570
571 if (!ValidateNamedProgramInterface(programInterface))
572 {
573 context->handleError(
574 Error(GL_INVALID_ENUM, "Invalid program interface: 0x%X", programInterface));
575 return false;
576 }
Shao80957d92017-02-20 21:25:59 +0800577
578 return true;
579}
580
581bool ValidateBindVertexBuffer(ValidationContext *context,
582 GLuint bindingIndex,
583 GLuint buffer,
584 GLintptr offset,
585 GLsizei stride)
586{
587 if (context->getClientVersion() < ES_3_1)
588 {
589 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
590 return false;
591 }
592
593 if (!context->isBufferGenerated(buffer))
594 {
595 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is not generated."));
596 return false;
597 }
598
599 const Caps &caps = context->getCaps();
600 if (bindingIndex >= caps.maxVertexAttribBindings)
601 {
602 context->handleError(Error(
603 GL_INVALID_VALUE, "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."));
604 return false;
605 }
606
607 if (offset < 0)
608 {
609 context->handleError(Error(GL_INVALID_VALUE, "offset cannot be negative."));
610 return false;
611 }
612
613 if (stride < 0 || stride > caps.maxVertexAttribStride)
614 {
615 context->handleError(
616 Error(GL_INVALID_VALUE, "stride must be between 0 and MAX_VERTEX_ATTRIB_STRIDE."));
617 return false;
618 }
619
620 // [OpenGL ES 3.1] Section 10.3.1 page 244:
621 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
622 if (context->getGLState().getVertexArrayId() == 0)
623 {
624 context->handleError(Error(GL_INVALID_OPERATION, "Default vertex array buffer is bound."));
625 return false;
626 }
627
628 return true;
629}
630
631bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor)
632{
633 if (context->getClientVersion() < ES_3_1)
634 {
635 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
636 return false;
637 }
638
639 const Caps &caps = context->getCaps();
640 if (bindingIndex >= caps.maxVertexAttribBindings)
641 {
642 context->handleError(Error(
643 GL_INVALID_VALUE, "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS."));
644 return false;
645 }
646
647 // [OpenGL ES 3.1] Section 10.3.1 page 243:
648 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
649 if (context->getGLState().getVertexArrayId() == 0)
650 {
651 context->handleError(Error(GL_INVALID_OPERATION, "Default vertex array object is bound."));
652 return false;
653 }
654
655 return true;
656}
657
658bool ValidateVertexAttribFormat(ValidationContext *context,
659 GLuint attribIndex,
660 GLint size,
661 GLenum type,
662 GLuint relativeOffset,
663 GLboolean pureInteger)
664{
665 if (context->getClientVersion() < ES_3_1)
666 {
667 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
668 return false;
669 }
670
671 const Caps &caps = context->getCaps();
672 if (relativeOffset > static_cast<GLuint>(caps.maxVertexAttribRelativeOffset))
673 {
674 context->handleError(
675 Error(GL_INVALID_VALUE,
676 "relativeOffset cannot be greater than MAX_VERTEX_ATTRIB_RELATIVE_OFFSET."));
677 return false;
678 }
679
680 // [OpenGL ES 3.1] Section 10.3.1 page 243:
681 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
682 if (context->getGLState().getVertexArrayId() == 0)
683 {
684 context->handleError(Error(GL_INVALID_OPERATION, "Default vertex array object is bound."));
685 return false;
686 }
687
688 return ValidateVertexFormatBase(context, attribIndex, size, type, pureInteger);
689}
690
691bool ValidateVertexAttribBinding(ValidationContext *context,
692 GLuint attribIndex,
693 GLuint bindingIndex)
694{
695 if (context->getClientVersion() < ES_3_1)
696 {
697 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
698 return false;
699 }
700
701 // [OpenGL ES 3.1] Section 10.3.1 page 243:
702 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
703 if (context->getGLState().getVertexArrayId() == 0)
704 {
705 context->handleError(Error(GL_INVALID_OPERATION, "Default vertex array object is bound."));
706 return false;
707 }
708
709 const Caps &caps = context->getCaps();
710 if (attribIndex >= caps.maxVertexAttributes)
711 {
712 context->handleError(
713 Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
714 return false;
715 }
716
717 if (bindingIndex >= caps.maxVertexAttribBindings)
718 {
719 context->handleError(Error(GL_INVALID_VALUE,
720 "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS"));
721 return false;
722 }
723
jchen1015015f72017-03-16 13:54:21 +0800724 return true;
725}
726
jchen10fd7c3b52017-03-21 15:36:03 +0800727bool ValidateGetProgramResourceName(Context *context,
728 GLuint program,
729 GLenum programInterface,
730 GLuint index,
731 GLsizei bufSize,
732 GLsizei *length,
733 GLchar *name)
734{
735 if (context->getClientVersion() < ES_3_1)
736 {
737 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
738 return false;
739 }
740
741 Program *programObject = GetValidProgram(context, program);
742 if (programObject == nullptr)
743 {
744 return false;
745 }
746
747 if (!ValidateNamedProgramInterface(programInterface))
748 {
749 context->handleError(
750 Error(GL_INVALID_ENUM, "Invalid program interface: 0x%X", programInterface));
751 return false;
752 }
753
754 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
755 {
756 context->handleError(Error(GL_INVALID_VALUE, "Invalid index: %d", index));
757 return false;
758 }
759
760 if (bufSize < 0)
761 {
762 context->handleError(Error(GL_INVALID_VALUE, "Invalid bufSize: %d", bufSize));
763 return false;
764 }
765
766 return true;
767}
768
Xinghua Cao2b396592017-03-29 15:36:04 +0800769bool ValidateDispatchCompute(Context *context,
770 GLuint numGroupsX,
771 GLuint numGroupsY,
772 GLuint numGroupsZ)
773{
774 if (context->getClientVersion() < ES_3_1)
775 {
776 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
777 return false;
778 }
779
780 const State &state = context->getGLState();
781 Program *program = state.getProgram();
782
783 if (program == nullptr)
784 {
785 context->handleError(
786 Error(GL_INVALID_OPERATION, "No active program object for the compute shader stage."));
787 return false;
788 }
789
790 if (program->isLinked() == false || program->getAttachedComputeShader() == nullptr)
791 {
792 context->handleError(Error(
793 GL_INVALID_OPERATION,
794 "Program has not been successfully linked, or program contains no compute shaders."));
795 return false;
796 }
797
798 const Caps &caps = context->getCaps();
799 if (numGroupsX > caps.maxComputeWorkGroupCount[0])
800 {
801 context->handleError(
802 Error(GL_INVALID_VALUE,
803 "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0](%u).",
804 caps.maxComputeWorkGroupCount[0]));
805 return false;
806 }
807 if (numGroupsY > caps.maxComputeWorkGroupCount[1])
808 {
809 context->handleError(
810 Error(GL_INVALID_VALUE,
811 "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1](%u).",
812 caps.maxComputeWorkGroupCount[1]));
813 return false;
814 }
815 if (numGroupsZ > caps.maxComputeWorkGroupCount[2])
816 {
817 context->handleError(
818 Error(GL_INVALID_VALUE,
819 "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2](%u).",
820 caps.maxComputeWorkGroupCount[2]));
821 return false;
822 }
823
824 return true;
825}
826
Martin Radev66fb8202016-07-28 11:45:20 +0300827} // namespace gl