blob: e4c118d0f3848a497bf0ea058f2422b05195e1ad [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"
Brandon Jonesafa75152017-07-21 13:11:29 -070012#include "libANGLE/ErrorStrings.h"
JiangYizhouf7bbc8a2016-11-16 09:57:22 +080013#include "libANGLE/Framebuffer.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040014#include "libANGLE/VertexArray.h"
Geoff Lang2e43dbb2016-10-14 12:27:35 -040015#include "libANGLE/validationES.h"
16#include "libANGLE/validationES3.h"
Martin Radev66fb8202016-07-28 11:45:20 +030017
He Yunchao11b038b2016-11-22 21:24:04 +080018#include "common/utilities.h"
19
Martin Radev66fb8202016-07-28 11:45:20 +030020using namespace angle;
21
22namespace gl
23{
24
jchen1015015f72017-03-16 13:54:21 +080025namespace
26{
27
28bool ValidateNamedProgramInterface(GLenum programInterface)
29{
30 switch (programInterface)
31 {
32 case GL_UNIFORM:
33 case GL_UNIFORM_BLOCK:
34 case GL_PROGRAM_INPUT:
35 case GL_PROGRAM_OUTPUT:
36 case GL_TRANSFORM_FEEDBACK_VARYING:
37 case GL_BUFFER_VARIABLE:
38 case GL_SHADER_STORAGE_BLOCK:
39 return true;
40 default:
41 return false;
42 }
43}
44
jchen10191381f2017-04-11 13:59:04 +080045bool ValidateLocationProgramInterface(GLenum programInterface)
46{
47 switch (programInterface)
48 {
49 case GL_UNIFORM:
50 case GL_PROGRAM_INPUT:
51 case GL_PROGRAM_OUTPUT:
52 return true;
53 default:
54 return false;
55 }
56}
57
jchen10880683b2017-04-12 16:21:55 +080058bool ValidateProgramInterface(GLenum programInterface)
59{
60 return (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
61 ValidateNamedProgramInterface(programInterface));
62}
63
64bool ValidateProgramResourceProperty(GLenum prop)
65{
66 switch (prop)
67 {
68 case GL_ACTIVE_VARIABLES:
69 case GL_BUFFER_BINDING:
70 case GL_NUM_ACTIVE_VARIABLES:
71
72 case GL_ARRAY_SIZE:
73
74 case GL_ARRAY_STRIDE:
75 case GL_BLOCK_INDEX:
76 case GL_IS_ROW_MAJOR:
77 case GL_MATRIX_STRIDE:
78
79 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
80
81 case GL_BUFFER_DATA_SIZE:
82
83 case GL_LOCATION:
84
85 case GL_NAME_LENGTH:
86
87 case GL_OFFSET:
88
89 case GL_REFERENCED_BY_VERTEX_SHADER:
90 case GL_REFERENCED_BY_FRAGMENT_SHADER:
91 case GL_REFERENCED_BY_COMPUTE_SHADER:
92
93 case GL_TOP_LEVEL_ARRAY_SIZE:
94 case GL_TOP_LEVEL_ARRAY_STRIDE:
95
96 case GL_TYPE:
97 return true;
98
99 default:
100 return false;
101 }
102}
103
104// GLES 3.10 spec: Page 82 -- Table 7.2
105bool ValidateProgramResourcePropertyByInterface(GLenum prop, GLenum programInterface)
106{
107 switch (prop)
108 {
109 case GL_ACTIVE_VARIABLES:
110 case GL_BUFFER_BINDING:
111 case GL_NUM_ACTIVE_VARIABLES:
112 {
113 switch (programInterface)
114 {
115 case GL_ATOMIC_COUNTER_BUFFER:
116 case GL_SHADER_STORAGE_BLOCK:
117 case GL_UNIFORM_BLOCK:
118 return true;
119 default:
120 return false;
121 }
122 }
123
124 case GL_ARRAY_SIZE:
125 {
126 switch (programInterface)
127 {
128 case GL_BUFFER_VARIABLE:
129 case GL_PROGRAM_INPUT:
130 case GL_PROGRAM_OUTPUT:
131 case GL_TRANSFORM_FEEDBACK_VARYING:
132 case GL_UNIFORM:
133 return true;
134 default:
135 return false;
136 }
137 }
138
139 case GL_ARRAY_STRIDE:
140 case GL_BLOCK_INDEX:
141 case GL_IS_ROW_MAJOR:
142 case GL_MATRIX_STRIDE:
143 {
144 switch (programInterface)
145 {
146 case GL_BUFFER_VARIABLE:
147 case GL_UNIFORM:
148 return true;
149 default:
150 return false;
151 }
152 }
153
154 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
155 {
156 if (programInterface == GL_UNIFORM)
157 {
158 return true;
159 }
160 return false;
161 }
162
163 case GL_BUFFER_DATA_SIZE:
164 {
165 switch (programInterface)
166 {
167 case GL_ATOMIC_COUNTER_BUFFER:
168 case GL_SHADER_STORAGE_BLOCK:
169 case GL_UNIFORM_BLOCK:
170 return true;
171 default:
172 return false;
173 }
174 }
175
176 case GL_LOCATION:
177 {
178 return ValidateLocationProgramInterface(programInterface);
179 }
180
181 case GL_NAME_LENGTH:
182 {
183 return ValidateNamedProgramInterface(programInterface);
184 }
185
186 case GL_OFFSET:
187 {
188 switch (programInterface)
189 {
190 case GL_BUFFER_VARIABLE:
191 case GL_UNIFORM:
192 return true;
193 default:
194 return false;
195 }
196 }
197
198 case GL_REFERENCED_BY_VERTEX_SHADER:
199 case GL_REFERENCED_BY_FRAGMENT_SHADER:
200 case GL_REFERENCED_BY_COMPUTE_SHADER:
201 {
202 switch (programInterface)
203 {
204 case GL_ATOMIC_COUNTER_BUFFER:
205 case GL_BUFFER_VARIABLE:
206 case GL_PROGRAM_INPUT:
207 case GL_PROGRAM_OUTPUT:
208 case GL_SHADER_STORAGE_BLOCK:
209 case GL_UNIFORM:
210 case GL_UNIFORM_BLOCK:
211 return true;
212 default:
213 return false;
214 }
215 }
216
217 case GL_TOP_LEVEL_ARRAY_SIZE:
218 case GL_TOP_LEVEL_ARRAY_STRIDE:
219 {
220 if (programInterface == GL_BUFFER_VARIABLE)
221 {
222 return true;
223 }
224 return false;
225 }
226
227 case GL_TYPE:
228 {
229 switch (programInterface)
230 {
231 case GL_BUFFER_VARIABLE:
232 case GL_PROGRAM_INPUT:
233 case GL_PROGRAM_OUTPUT:
234 case GL_TRANSFORM_FEEDBACK_VARYING:
235 case GL_UNIFORM:
236 return true;
237 default:
238 return false;
239 }
240 }
241
242 default:
243 return false;
244 }
245}
246
jchen10fd7c3b52017-03-21 15:36:03 +0800247bool ValidateProgramResourceIndex(const Program *programObject,
248 GLenum programInterface,
249 GLuint index)
250{
251 switch (programInterface)
252 {
253 case GL_PROGRAM_INPUT:
254 return (index < static_cast<GLuint>(programObject->getActiveAttributeCount()));
255
256 case GL_PROGRAM_OUTPUT:
257 return (index < static_cast<GLuint>(programObject->getOutputResourceCount()));
258
jchen10880683b2017-04-12 16:21:55 +0800259 // TODO(jie.a.chen@intel.com): more interfaces.
jchen10fd7c3b52017-03-21 15:36:03 +0800260 case GL_UNIFORM:
261 case GL_UNIFORM_BLOCK:
262 case GL_TRANSFORM_FEEDBACK_VARYING:
263 case GL_BUFFER_VARIABLE:
264 case GL_SHADER_STORAGE_BLOCK:
jchen10880683b2017-04-12 16:21:55 +0800265 case GL_ATOMIC_COUNTER_BUFFER:
jchen10fd7c3b52017-03-21 15:36:03 +0800266 UNIMPLEMENTED();
267 return false;
268
269 default:
270 UNREACHABLE();
271 return false;
272 }
273}
274
jchen1015015f72017-03-16 13:54:21 +0800275} // anonymous namespace
276
Martin Radev66fb8202016-07-28 11:45:20 +0300277bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data)
278{
Geoff Langeb66a6e2016-10-31 13:06:12 -0400279 if (context->getClientVersion() < ES_3_1)
Martin Radev66fb8202016-07-28 11:45:20 +0300280 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700281 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Martin Radev66fb8202016-07-28 11:45:20 +0300282 return false;
283 }
284
Geoff Lang2e43dbb2016-10-14 12:27:35 -0400285 if (!ValidateIndexedStateQuery(context, target, index, nullptr))
286 {
287 return false;
288 }
289
290 return true;
291}
292
293bool ValidateGetBooleani_vRobustANGLE(Context *context,
294 GLenum target,
295 GLuint index,
296 GLsizei bufSize,
297 GLsizei *length,
298 GLboolean *data)
299{
Geoff Langeb66a6e2016-10-31 13:06:12 -0400300 if (context->getClientVersion() < ES_3_1)
Geoff Lang2e43dbb2016-10-14 12:27:35 -0400301 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700302 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Geoff Lang2e43dbb2016-10-14 12:27:35 -0400303 return false;
304 }
305
306 if (!ValidateRobustEntryPoint(context, bufSize))
307 {
308 return false;
309 }
310
311 if (!ValidateIndexedStateQuery(context, target, index, length))
312 {
313 return false;
314 }
315
316 if (!ValidateRobustBufferSize(context, bufSize, *length))
Martin Radev66fb8202016-07-28 11:45:20 +0300317 {
318 return false;
319 }
320
321 return true;
322}
323
Jamie Madill876429b2017-04-20 15:46:24 -0400324bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800325{
326 if (context->getClientVersion() < ES_3_1)
327 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700328 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Jiajia Qind9671222016-11-29 16:30:31 +0800329 return false;
330 }
331
332 // Here the third parameter 1 is only to pass the count validation.
333 if (!ValidateDrawBase(context, mode, 1))
334 {
335 return false;
336 }
337
338 const State &state = context->getGLState();
339
340 // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING,
341 // DRAW_INDIRECT_BUFFER or to any enabled vertex array.
342 if (!state.getVertexArrayId())
343 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500344 context->handleError(InvalidOperation() << "zero is bound to VERTEX_ARRAY_BINDING");
Jiajia Qind9671222016-11-29 16:30:31 +0800345 return false;
346 }
347
348 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
349 if (!drawIndirectBuffer)
350 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500351 context->handleError(InvalidOperation() << "zero is bound to DRAW_INDIRECT_BUFFER");
Jiajia Qind9671222016-11-29 16:30:31 +0800352 return false;
353 }
354
355 // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic
356 // machine units, of uint.
357 GLint64 offset = reinterpret_cast<GLint64>(indirect);
358 if ((static_cast<GLuint>(offset) % sizeof(GLuint)) != 0)
359 {
360 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500361 InvalidValue()
362 << "indirect is not a multiple of the size, in basic machine units, of uint");
Jiajia Qind9671222016-11-29 16:30:31 +0800363 return false;
364 }
365
Martin Radev14a26ae2017-07-24 15:56:29 +0300366 // ANGLE_multiview spec, revision 1:
367 // An INVALID_OPERATION is generated by DrawArraysIndirect and DrawElementsIndirect if the
368 // number of views in the draw framebuffer is greater than 1.
369 const Framebuffer *drawFramebuffer = context->getGLState().getDrawFramebuffer();
370 ASSERT(drawFramebuffer != nullptr);
371 if (drawFramebuffer->getNumViews() > 1)
372 {
373 context->handleError(
374 InvalidOperation()
375 << "The number of views in the active draw framebuffer is greater than 1.");
376 return false;
377 }
378
Jiajia Qind9671222016-11-29 16:30:31 +0800379 return true;
380}
381
Jamie Madill876429b2017-04-20 15:46:24 -0400382bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800383{
384 const State &state = context->getGLState();
385 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
386 if (curTransformFeedback && curTransformFeedback->isActive() &&
387 !curTransformFeedback->isPaused())
388 {
389 // An INVALID_OPERATION error is generated if transform feedback is active and not paused.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500390 context->handleError(InvalidOperation() << "transform feedback is active and not paused.");
Jiajia Qind9671222016-11-29 16:30:31 +0800391 return false;
392 }
393
394 if (!ValidateDrawIndirectBase(context, mode, indirect))
395 return false;
396
397 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
398 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
399 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand
400 // which's size is 4 * sizeof(uint).
401 auto checkedSum = checkedOffset + 4 * sizeof(GLuint);
402 if (!checkedSum.IsValid() ||
403 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
404 {
405 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500406 InvalidOperation()
407 << "the command would source data beyond the end of the buffer object.");
Jiajia Qind9671222016-11-29 16:30:31 +0800408 return false;
409 }
410
411 return true;
412}
413
Jamie Madill876429b2017-04-20 15:46:24 -0400414bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800415{
416 if (!ValidateDrawElementsBase(context, type))
417 return false;
418
419 const State &state = context->getGLState();
420 const VertexArray *vao = state.getVertexArray();
421 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
422 if (!elementArrayBuffer)
423 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500424 context->handleError(InvalidOperation() << "zero is bound to ELEMENT_ARRAY_BUFFER");
Jiajia Qind9671222016-11-29 16:30:31 +0800425 return false;
426 }
427
428 if (!ValidateDrawIndirectBase(context, mode, indirect))
429 return false;
430
431 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
432 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
433 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand
434 // which's size is 5 * sizeof(uint).
435 auto checkedSum = checkedOffset + 5 * sizeof(GLuint);
436 if (!checkedSum.IsValid() ||
437 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
438 {
439 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500440 InvalidOperation()
441 << "the command would source data beyond the end of the buffer object.");
Jiajia Qind9671222016-11-29 16:30:31 +0800442 return false;
443 }
444
445 return true;
446}
447
He Yunchao11b038b2016-11-22 21:24:04 +0800448bool ValidateGetTexLevelParameterBase(Context *context,
449 GLenum target,
450 GLint level,
451 GLenum pname,
452 GLsizei *length)
453{
454 if (context->getClientVersion() < ES_3_1)
455 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700456 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
He Yunchao11b038b2016-11-22 21:24:04 +0800457 return false;
458 }
459
460 if (length)
461 {
462 *length = 0;
463 }
464
465 if (!ValidTexLevelDestinationTarget(context, target))
466 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700467 ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidTextureTarget);
He Yunchao11b038b2016-11-22 21:24:04 +0800468 return false;
469 }
470
471 if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) ==
472 nullptr)
473 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500474 context->handleError(InvalidEnum() << "No texture bound.");
He Yunchao11b038b2016-11-22 21:24:04 +0800475 return false;
476 }
477
478 if (!ValidMipLevel(context, target, level))
479 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500480 context->handleError(InvalidValue());
He Yunchao11b038b2016-11-22 21:24:04 +0800481 return false;
482 }
483
484 switch (pname)
485 {
486 case GL_TEXTURE_RED_TYPE:
487 case GL_TEXTURE_GREEN_TYPE:
488 case GL_TEXTURE_BLUE_TYPE:
489 case GL_TEXTURE_ALPHA_TYPE:
490 case GL_TEXTURE_DEPTH_TYPE:
491 break;
492 case GL_TEXTURE_RED_SIZE:
493 case GL_TEXTURE_GREEN_SIZE:
494 case GL_TEXTURE_BLUE_SIZE:
495 case GL_TEXTURE_ALPHA_SIZE:
496 case GL_TEXTURE_DEPTH_SIZE:
497 case GL_TEXTURE_STENCIL_SIZE:
498 case GL_TEXTURE_SHARED_SIZE:
499 break;
500 case GL_TEXTURE_INTERNAL_FORMAT:
501 case GL_TEXTURE_WIDTH:
502 case GL_TEXTURE_HEIGHT:
503 case GL_TEXTURE_DEPTH:
504 break;
505 case GL_TEXTURE_SAMPLES:
506 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
507 break;
508 case GL_TEXTURE_COMPRESSED:
509 break;
510 default:
Brandon Jonesafa75152017-07-21 13:11:29 -0700511 ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname);
He Yunchao11b038b2016-11-22 21:24:04 +0800512 return false;
513 }
514
515 if (length)
516 {
517 *length = 1;
518 }
519 return true;
520}
521
522bool ValidateGetTexLevelParameterfv(Context *context,
523 GLenum target,
524 GLint level,
525 GLenum pname,
526 GLfloat *params)
527{
528 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
529}
530
531bool ValidateGetTexLevelParameteriv(Context *context,
532 GLenum target,
533 GLint level,
534 GLenum pname,
535 GLint *params)
536{
537 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
538}
539
JiangYizhoubddc46b2016-12-09 09:50:51 +0800540bool ValidateTexStorage2DMultiSample(Context *context,
541 GLenum target,
542 GLsizei samples,
543 GLint internalFormat,
544 GLsizei width,
545 GLsizei height,
546 GLboolean fixedSampleLocations)
547{
548 if (context->getClientVersion() < ES_3_1)
549 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700550 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
JiangYizhoubddc46b2016-12-09 09:50:51 +0800551 return false;
552 }
553
554 if (target != GL_TEXTURE_2D_MULTISAMPLE)
555 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500556 context->handleError(InvalidEnum() << "Target must be TEXTURE_2D_MULTISAMPLE.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800557 return false;
558 }
559
560 if (width < 1 || height < 1)
561 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700562 ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeSize);
JiangYizhoubddc46b2016-12-09 09:50:51 +0800563 return false;
564 }
565
566 const Caps &caps = context->getCaps();
567 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
568 static_cast<GLuint>(height) > caps.max2DTextureSize)
569 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500570 context
571 ->handleError(InvalidValue()
572 << "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800573 return false;
574 }
575
576 if (samples == 0)
577 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500578 context->handleError(InvalidValue() << "Samples may not be zero.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800579 return false;
580 }
581
582 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
583 if (!formatCaps.renderable)
584 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500585 context->handleError(InvalidEnum() << "SizedInternalformat must be color-renderable, "
586 "depth-renderable, or stencil-renderable.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800587 return false;
588 }
589
590 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
591 // is one of the unsized base internalformats listed in table 8.11.
Geoff Langca271392017-04-05 12:30:00 -0400592 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
593 if (formatInfo.internalFormat == GL_NONE)
JiangYizhoubddc46b2016-12-09 09:50:51 +0800594 {
595 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500596 InvalidEnum()
597 << "Internalformat is one of the unsupported unsized base internalformats.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800598 return false;
599 }
600
601 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
602 {
603 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500604 InvalidOperation()
605 << "Samples must not be greater than maximum supported value for the format.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800606 return false;
607 }
608
609 Texture *texture = context->getTargetTexture(target);
610 if (!texture || texture->id() == 0)
611 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500612 context->handleError(InvalidOperation() << "Zero is bound to target.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800613 return false;
614 }
615
616 if (texture->getImmutableFormat())
617 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500618 context->handleError(InvalidOperation() << "The value of TEXTURE_IMMUTABLE_FORMAT for "
619 "the texture currently bound to target on "
620 "the active texture unit is true.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800621 return false;
622 }
623
624 return true;
625}
626
627bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val)
628{
629 if (context->getClientVersion() < ES_3_1)
630 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700631 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
JiangYizhoubddc46b2016-12-09 09:50:51 +0800632 return false;
633 }
634
635 if (pname != GL_SAMPLE_POSITION)
636 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500637 context->handleError(InvalidEnum() << "Pname must be SAMPLE_POSITION.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800638 return false;
639 }
640
JiangYizhou5b03f472017-01-09 10:22:53 +0800641 Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer();
642
643 if (index >= static_cast<GLuint>(framebuffer->getSamples(context)))
JiangYizhoubddc46b2016-12-09 09:50:51 +0800644 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500645 context->handleError(InvalidValue() << "Index must be less than the value of SAMPLES.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800646 return false;
647 }
648
649 return true;
650}
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800651
652bool ValidationFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param)
653{
654 if (context->getClientVersion() < ES_3_1)
655 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700656 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800657 return false;
658 }
659
660 if (!ValidFramebufferTarget(target))
661 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500662 context->handleError(InvalidEnum() << "Invalid framebuffer target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800663 return false;
664 }
665
666 switch (pname)
667 {
668 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
669 {
670 GLint maxWidth = context->getCaps().maxFramebufferWidth;
671 if (param < 0 || param > maxWidth)
672 {
673 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500674 InvalidValue()
675 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800676 return false;
677 }
678 break;
679 }
680 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
681 {
682 GLint maxHeight = context->getCaps().maxFramebufferHeight;
683 if (param < 0 || param > maxHeight)
684 {
685 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500686 InvalidValue()
687 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800688 return false;
689 }
690 break;
691 }
692 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
693 {
694 GLint maxSamples = context->getCaps().maxFramebufferSamples;
695 if (param < 0 || param > maxSamples)
696 {
697 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500698 InvalidValue()
699 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800700 return false;
701 }
702 break;
703 }
704 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
705 {
706 break;
707 }
708 default:
709 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700710 ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800711 return false;
712 }
713 }
714
715 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
716 ASSERT(framebuffer);
717 if (framebuffer->id() == 0)
718 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500719 context->handleError(InvalidOperation() << "Default framebuffer is bound to target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800720 return false;
721 }
722 return true;
723}
724
725bool ValidationGetFramebufferParameteri(Context *context,
726 GLenum target,
727 GLenum pname,
728 GLint *params)
729{
730 if (context->getClientVersion() < ES_3_1)
731 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700732 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800733 return false;
734 }
735
736 if (!ValidFramebufferTarget(target))
737 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700738 ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800739 return false;
740 }
741
742 switch (pname)
743 {
744 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
745 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
746 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
747 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
748 break;
749 default:
Brandon Jonesafa75152017-07-21 13:11:29 -0700750 ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800751 return false;
752 }
753
754 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
755 ASSERT(framebuffer);
756
757 if (framebuffer->id() == 0)
758 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500759 context->handleError(InvalidOperation() << "Default framebuffer is bound to target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800760 return false;
761 }
762 return true;
763}
764
jchen1015015f72017-03-16 13:54:21 +0800765bool ValidateGetProgramResourceIndex(Context *context,
766 GLuint program,
767 GLenum programInterface,
768 const GLchar *name)
769{
770 if (context->getClientVersion() < ES_3_1)
771 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700772 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
jchen1015015f72017-03-16 13:54:21 +0800773 return false;
774 }
775
776 Program *programObject = GetValidProgram(context, program);
777 if (programObject == nullptr)
778 {
779 return false;
780 }
781
782 if (!ValidateNamedProgramInterface(programInterface))
783 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500784 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
785 << std::uppercase << programInterface);
jchen1015015f72017-03-16 13:54:21 +0800786 return false;
787 }
Shao80957d92017-02-20 21:25:59 +0800788
789 return true;
790}
791
792bool ValidateBindVertexBuffer(ValidationContext *context,
793 GLuint bindingIndex,
794 GLuint buffer,
795 GLintptr offset,
796 GLsizei stride)
797{
798 if (context->getClientVersion() < ES_3_1)
799 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700800 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Shao80957d92017-02-20 21:25:59 +0800801 return false;
802 }
803
804 if (!context->isBufferGenerated(buffer))
805 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500806 context->handleError(InvalidOperation() << "Buffer is not generated.");
Shao80957d92017-02-20 21:25:59 +0800807 return false;
808 }
809
810 const Caps &caps = context->getCaps();
811 if (bindingIndex >= caps.maxVertexAttribBindings)
812 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500813 context->handleError(InvalidValue()
814 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS.");
Shao80957d92017-02-20 21:25:59 +0800815 return false;
816 }
817
818 if (offset < 0)
819 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700820 ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset);
Shao80957d92017-02-20 21:25:59 +0800821 return false;
822 }
823
824 if (stride < 0 || stride > caps.maxVertexAttribStride)
825 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500826 context->handleError(InvalidValue()
827 << "stride must be between 0 and MAX_VERTEX_ATTRIB_STRIDE.");
Shao80957d92017-02-20 21:25:59 +0800828 return false;
829 }
830
831 // [OpenGL ES 3.1] Section 10.3.1 page 244:
832 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
833 if (context->getGLState().getVertexArrayId() == 0)
834 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500835 context->handleError(InvalidOperation() << "Default vertex array buffer is bound.");
Shao80957d92017-02-20 21:25:59 +0800836 return false;
837 }
838
839 return true;
840}
841
842bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor)
843{
844 if (context->getClientVersion() < ES_3_1)
845 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700846 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Shao80957d92017-02-20 21:25:59 +0800847 return false;
848 }
849
850 const Caps &caps = context->getCaps();
851 if (bindingIndex >= caps.maxVertexAttribBindings)
852 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500853 context->handleError(InvalidValue()
854 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS.");
Shao80957d92017-02-20 21:25:59 +0800855 return false;
856 }
857
858 // [OpenGL ES 3.1] Section 10.3.1 page 243:
859 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
860 if (context->getGLState().getVertexArrayId() == 0)
861 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500862 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800863 return false;
864 }
865
866 return true;
867}
868
869bool ValidateVertexAttribFormat(ValidationContext *context,
870 GLuint attribIndex,
871 GLint size,
872 GLenum type,
873 GLuint relativeOffset,
874 GLboolean pureInteger)
875{
876 if (context->getClientVersion() < ES_3_1)
877 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700878 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Shao80957d92017-02-20 21:25:59 +0800879 return false;
880 }
881
882 const Caps &caps = context->getCaps();
883 if (relativeOffset > static_cast<GLuint>(caps.maxVertexAttribRelativeOffset))
884 {
885 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500886 InvalidValue()
887 << "relativeOffset cannot be greater than MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.");
Shao80957d92017-02-20 21:25:59 +0800888 return false;
889 }
890
891 // [OpenGL ES 3.1] Section 10.3.1 page 243:
892 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
893 if (context->getGLState().getVertexArrayId() == 0)
894 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500895 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800896 return false;
897 }
898
899 return ValidateVertexFormatBase(context, attribIndex, size, type, pureInteger);
900}
901
902bool ValidateVertexAttribBinding(ValidationContext *context,
903 GLuint attribIndex,
904 GLuint bindingIndex)
905{
906 if (context->getClientVersion() < ES_3_1)
907 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700908 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Shao80957d92017-02-20 21:25:59 +0800909 return false;
910 }
911
912 // [OpenGL ES 3.1] Section 10.3.1 page 243:
913 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
914 if (context->getGLState().getVertexArrayId() == 0)
915 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500916 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800917 return false;
918 }
919
920 const Caps &caps = context->getCaps();
921 if (attribIndex >= caps.maxVertexAttributes)
922 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700923 ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute);
Shao80957d92017-02-20 21:25:59 +0800924 return false;
925 }
926
927 if (bindingIndex >= caps.maxVertexAttribBindings)
928 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500929 context->handleError(InvalidValue()
930 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS");
Shao80957d92017-02-20 21:25:59 +0800931 return false;
932 }
933
jchen1015015f72017-03-16 13:54:21 +0800934 return true;
935}
936
jchen10fd7c3b52017-03-21 15:36:03 +0800937bool ValidateGetProgramResourceName(Context *context,
938 GLuint program,
939 GLenum programInterface,
940 GLuint index,
941 GLsizei bufSize,
942 GLsizei *length,
943 GLchar *name)
944{
945 if (context->getClientVersion() < ES_3_1)
946 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700947 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
jchen10fd7c3b52017-03-21 15:36:03 +0800948 return false;
949 }
950
951 Program *programObject = GetValidProgram(context, program);
952 if (programObject == nullptr)
953 {
954 return false;
955 }
956
957 if (!ValidateNamedProgramInterface(programInterface))
958 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500959 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
960 << std::uppercase << programInterface);
jchen10fd7c3b52017-03-21 15:36:03 +0800961 return false;
962 }
963
964 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
965 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500966 context->handleError(InvalidValue() << "Invalid index: " << index);
jchen10fd7c3b52017-03-21 15:36:03 +0800967 return false;
968 }
969
970 if (bufSize < 0)
971 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700972 ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize);
jchen10fd7c3b52017-03-21 15:36:03 +0800973 return false;
974 }
975
976 return true;
977}
978
Xinghua Cao2b396592017-03-29 15:36:04 +0800979bool ValidateDispatchCompute(Context *context,
980 GLuint numGroupsX,
981 GLuint numGroupsY,
982 GLuint numGroupsZ)
983{
984 if (context->getClientVersion() < ES_3_1)
985 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700986 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Xinghua Cao2b396592017-03-29 15:36:04 +0800987 return false;
988 }
989
990 const State &state = context->getGLState();
991 Program *program = state.getProgram();
992
993 if (program == nullptr)
994 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500995 context->handleError(InvalidOperation()
996 << "No active program object for the compute shader stage.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800997 return false;
998 }
999
1000 if (program->isLinked() == false || program->getAttachedComputeShader() == nullptr)
1001 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001002 context->handleError(
1003 InvalidOperation()
1004 << "Program has not been successfully linked, or program contains no compute shaders.");
Xinghua Cao2b396592017-03-29 15:36:04 +08001005 return false;
1006 }
1007
1008 const Caps &caps = context->getCaps();
1009 if (numGroupsX > caps.maxComputeWorkGroupCount[0])
1010 {
1011 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001012 InvalidValue() << "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]="
1013 << caps.maxComputeWorkGroupCount[0]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001014 return false;
1015 }
1016 if (numGroupsY > caps.maxComputeWorkGroupCount[1])
1017 {
1018 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001019 InvalidValue() << "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]="
1020 << caps.maxComputeWorkGroupCount[1]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001021 return false;
1022 }
1023 if (numGroupsZ > caps.maxComputeWorkGroupCount[2])
1024 {
1025 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001026 InvalidValue() << "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2]="
1027 << caps.maxComputeWorkGroupCount[2]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001028 return false;
1029 }
1030
1031 return true;
1032}
1033
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001034bool ValidateBindImageTexture(Context *context,
1035 GLuint unit,
1036 GLuint texture,
1037 GLint level,
1038 GLboolean layered,
1039 GLint layer,
1040 GLenum access,
1041 GLenum format)
1042{
1043 GLuint maxImageUnits = context->getCaps().maxImageUnits;
1044 if (unit >= maxImageUnits)
1045 {
1046 context->handleError(InvalidValue()
1047 << "unit cannot be greater than or equal than MAX_IMAGE_UNITS = "
1048 << maxImageUnits);
1049 return false;
1050 }
1051
1052 if (level < 0)
1053 {
1054 context->handleError(InvalidValue() << "level is negative.");
1055 return false;
1056 }
1057
1058 if (layer < 0)
1059 {
1060 context->handleError(InvalidValue() << "layer is negative.");
1061 return false;
1062 }
1063
1064 if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE)
1065 {
1066 context->handleError(InvalidEnum() << "access is not one of the supported tokens.");
1067 return false;
1068 }
1069
1070 switch (format)
1071 {
1072 case GL_RGBA32F:
1073 case GL_RGBA16F:
1074 case GL_R32F:
1075 case GL_RGBA32UI:
1076 case GL_RGBA16UI:
1077 case GL_RGBA8UI:
1078 case GL_R32UI:
1079 case GL_RGBA32I:
1080 case GL_RGBA16I:
1081 case GL_RGBA8I:
1082 case GL_R32I:
1083 case GL_RGBA8:
1084 case GL_RGBA8_SNORM:
1085 break;
1086 default:
1087 context->handleError(InvalidValue()
1088 << "format is not one of supported image unit formats.");
1089 return false;
1090 }
1091
1092 if (texture != 0)
1093 {
1094 Texture *tex = context->getTexture(texture);
1095
1096 if (tex == nullptr)
1097 {
1098 context->handleError(InvalidValue()
1099 << "texture is not the name of an existing texture object.");
1100 return false;
1101 }
1102
1103 if (!tex->getImmutableFormat())
1104 {
1105 context->handleError(InvalidOperation()
1106 << "texture is not the name of an immutable texture object.");
1107 return false;
1108 }
1109 }
1110
1111 return true;
1112}
jchen10191381f2017-04-11 13:59:04 +08001113
1114bool ValidateGetProgramResourceLocation(Context *context,
1115 GLuint program,
1116 GLenum programInterface,
1117 const GLchar *name)
1118{
1119 if (context->getClientVersion() < ES_3_1)
1120 {
Brandon Jonesafa75152017-07-21 13:11:29 -07001121 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
jchen10191381f2017-04-11 13:59:04 +08001122 return false;
1123 }
1124
1125 Program *programObject = GetValidProgram(context, program);
1126 if (programObject == nullptr)
1127 {
1128 return false;
1129 }
1130
1131 if (!programObject->isLinked())
1132 {
1133 context->handleError(InvalidOperation() << "Program is not successfully linked.");
1134 return false;
1135 }
1136
1137 if (!ValidateLocationProgramInterface(programInterface))
1138 {
1139 context->handleError(InvalidEnum() << "Invalid program interface.");
1140 return false;
1141 }
1142 return true;
1143}
1144
jchen10880683b2017-04-12 16:21:55 +08001145bool ValidateGetProgramResourceiv(Context *context,
1146 GLuint program,
1147 GLenum programInterface,
1148 GLuint index,
1149 GLsizei propCount,
1150 const GLenum *props,
1151 GLsizei bufSize,
1152 GLsizei *length,
1153 GLint *params)
1154{
1155 if (context->getClientVersion() < ES_3_1)
1156 {
jchen10d9cd7b72017-08-30 15:04:25 +08001157 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
jchen10880683b2017-04-12 16:21:55 +08001158 return false;
1159 }
1160
1161 Program *programObject = GetValidProgram(context, program);
1162 if (programObject == nullptr)
1163 {
1164 return false;
1165 }
1166 if (!ValidateProgramInterface(programInterface))
1167 {
1168 context->handleError(InvalidEnum() << "Invalid program interface.");
1169 return false;
1170 }
1171 if (propCount <= 0)
1172 {
1173 context->handleError(InvalidValue() << "Invalid propCount.");
1174 return false;
1175 }
1176 if (bufSize < 0)
1177 {
1178 context->handleError(InvalidValue() << "Invalid bufSize.");
1179 return false;
1180 }
1181 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
1182 {
1183 context->handleError(InvalidValue() << "Invalid index: " << index);
1184 return false;
1185 }
1186 for (GLsizei i = 0; i < propCount; i++)
1187 {
1188 if (!ValidateProgramResourceProperty(props[i]))
1189 {
1190 context->handleError(InvalidEnum() << "Invalid prop.");
1191 return false;
1192 }
1193 if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface))
1194 {
1195 context->handleError(InvalidOperation() << "Not an allowed prop for interface");
1196 return false;
1197 }
1198 }
1199 return true;
1200}
1201
jchen10d9cd7b72017-08-30 15:04:25 +08001202bool ValidateGetProgramInterfaceiv(Context *context,
1203 GLuint program,
1204 GLenum programInterface,
1205 GLenum pname,
1206 GLint *params)
1207{
1208 if (context->getClientVersion() < ES_3_1)
1209 {
1210 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
1211 return false;
1212 }
1213
1214 Program *programObject = GetValidProgram(context, program);
1215 if (programObject == nullptr)
1216 {
1217 return false;
1218 }
1219
1220 if (!ValidateProgramInterface(programInterface))
1221 {
1222 context->handleError(InvalidEnum() << "Invalid program interface.");
1223 return false;
1224 }
1225
1226 switch (pname)
1227 {
1228 case GL_ACTIVE_RESOURCES:
1229 case GL_MAX_NAME_LENGTH:
1230 case GL_MAX_NUM_ACTIVE_VARIABLES:
1231 break;
1232
1233 default:
1234 context->handleError(InvalidEnum() << "Unknown property of program interface.");
1235 return false;
1236 }
1237
1238 if (pname == GL_MAX_NAME_LENGTH && programInterface == GL_ATOMIC_COUNTER_BUFFER)
1239 {
1240 context->handleError(InvalidOperation()
1241 << "Active atomic counter resources are not assigned name strings.");
1242 return false;
1243 }
1244
1245 if (pname == GL_MAX_NUM_ACTIVE_VARIABLES)
1246 {
1247 switch (programInterface)
1248 {
1249 case GL_ATOMIC_COUNTER_BUFFER:
1250 case GL_SHADER_STORAGE_BLOCK:
1251 case GL_UNIFORM_BLOCK:
1252 break;
1253
1254 default:
1255 context->handleError(
1256 InvalidOperation()
1257 << "MAX_NUM_ACTIVE_VARIABLES requires a buffer or block interface.");
1258 return false;
1259 }
1260 }
1261
1262 return true;
1263}
1264
Martin Radev66fb8202016-07-28 11:45:20 +03001265} // namespace gl