blob: cbf44e7b15665ce84e25df5c32837e0e07229e91 [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
641 GLint maxSamples = context->getCaps().maxSamples;
642 if (index >= static_cast<GLuint>(maxSamples))
643 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500644 context->handleError(InvalidValue() << "Index must be less than the value of SAMPLES.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800645 return false;
646 }
647
648 return true;
649}
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800650
651bool ValidationFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param)
652{
653 if (context->getClientVersion() < ES_3_1)
654 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700655 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800656 return false;
657 }
658
659 if (!ValidFramebufferTarget(target))
660 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500661 context->handleError(InvalidEnum() << "Invalid framebuffer target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800662 return false;
663 }
664
665 switch (pname)
666 {
667 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
668 {
669 GLint maxWidth = context->getCaps().maxFramebufferWidth;
670 if (param < 0 || param > maxWidth)
671 {
672 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500673 InvalidValue()
674 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800675 return false;
676 }
677 break;
678 }
679 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
680 {
681 GLint maxHeight = context->getCaps().maxFramebufferHeight;
682 if (param < 0 || param > maxHeight)
683 {
684 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500685 InvalidValue()
686 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800687 return false;
688 }
689 break;
690 }
691 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
692 {
693 GLint maxSamples = context->getCaps().maxFramebufferSamples;
694 if (param < 0 || param > maxSamples)
695 {
696 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500697 InvalidValue()
698 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800699 return false;
700 }
701 break;
702 }
703 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
704 {
705 break;
706 }
707 default:
708 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700709 ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800710 return false;
711 }
712 }
713
714 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
715 ASSERT(framebuffer);
716 if (framebuffer->id() == 0)
717 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500718 context->handleError(InvalidOperation() << "Default framebuffer is bound to target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800719 return false;
720 }
721 return true;
722}
723
724bool ValidationGetFramebufferParameteri(Context *context,
725 GLenum target,
726 GLenum pname,
727 GLint *params)
728{
729 if (context->getClientVersion() < ES_3_1)
730 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700731 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800732 return false;
733 }
734
735 if (!ValidFramebufferTarget(target))
736 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700737 ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidFramebufferTarget);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800738 return false;
739 }
740
741 switch (pname)
742 {
743 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
744 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
745 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
746 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
747 break;
748 default:
Brandon Jonesafa75152017-07-21 13:11:29 -0700749 ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidPname);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800750 return false;
751 }
752
753 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
754 ASSERT(framebuffer);
755
756 if (framebuffer->id() == 0)
757 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500758 context->handleError(InvalidOperation() << "Default framebuffer is bound to target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800759 return false;
760 }
761 return true;
762}
763
jchen1015015f72017-03-16 13:54:21 +0800764bool ValidateGetProgramResourceIndex(Context *context,
765 GLuint program,
766 GLenum programInterface,
767 const GLchar *name)
768{
769 if (context->getClientVersion() < ES_3_1)
770 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700771 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
jchen1015015f72017-03-16 13:54:21 +0800772 return false;
773 }
774
775 Program *programObject = GetValidProgram(context, program);
776 if (programObject == nullptr)
777 {
778 return false;
779 }
780
781 if (!ValidateNamedProgramInterface(programInterface))
782 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500783 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
784 << std::uppercase << programInterface);
jchen1015015f72017-03-16 13:54:21 +0800785 return false;
786 }
Shao80957d92017-02-20 21:25:59 +0800787
788 return true;
789}
790
791bool ValidateBindVertexBuffer(ValidationContext *context,
792 GLuint bindingIndex,
793 GLuint buffer,
794 GLintptr offset,
795 GLsizei stride)
796{
797 if (context->getClientVersion() < ES_3_1)
798 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700799 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Shao80957d92017-02-20 21:25:59 +0800800 return false;
801 }
802
803 if (!context->isBufferGenerated(buffer))
804 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500805 context->handleError(InvalidOperation() << "Buffer is not generated.");
Shao80957d92017-02-20 21:25:59 +0800806 return false;
807 }
808
809 const Caps &caps = context->getCaps();
810 if (bindingIndex >= caps.maxVertexAttribBindings)
811 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500812 context->handleError(InvalidValue()
813 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS.");
Shao80957d92017-02-20 21:25:59 +0800814 return false;
815 }
816
817 if (offset < 0)
818 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700819 ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeOffset);
Shao80957d92017-02-20 21:25:59 +0800820 return false;
821 }
822
823 if (stride < 0 || stride > caps.maxVertexAttribStride)
824 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500825 context->handleError(InvalidValue()
826 << "stride must be between 0 and MAX_VERTEX_ATTRIB_STRIDE.");
Shao80957d92017-02-20 21:25:59 +0800827 return false;
828 }
829
830 // [OpenGL ES 3.1] Section 10.3.1 page 244:
831 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
832 if (context->getGLState().getVertexArrayId() == 0)
833 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500834 context->handleError(InvalidOperation() << "Default vertex array buffer is bound.");
Shao80957d92017-02-20 21:25:59 +0800835 return false;
836 }
837
838 return true;
839}
840
841bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor)
842{
843 if (context->getClientVersion() < ES_3_1)
844 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700845 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Shao80957d92017-02-20 21:25:59 +0800846 return false;
847 }
848
849 const Caps &caps = context->getCaps();
850 if (bindingIndex >= caps.maxVertexAttribBindings)
851 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500852 context->handleError(InvalidValue()
853 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS.");
Shao80957d92017-02-20 21:25:59 +0800854 return false;
855 }
856
857 // [OpenGL ES 3.1] Section 10.3.1 page 243:
858 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
859 if (context->getGLState().getVertexArrayId() == 0)
860 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500861 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800862 return false;
863 }
864
865 return true;
866}
867
868bool ValidateVertexAttribFormat(ValidationContext *context,
869 GLuint attribIndex,
870 GLint size,
871 GLenum type,
872 GLuint relativeOffset,
873 GLboolean pureInteger)
874{
875 if (context->getClientVersion() < ES_3_1)
876 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700877 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Shao80957d92017-02-20 21:25:59 +0800878 return false;
879 }
880
881 const Caps &caps = context->getCaps();
882 if (relativeOffset > static_cast<GLuint>(caps.maxVertexAttribRelativeOffset))
883 {
884 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500885 InvalidValue()
886 << "relativeOffset cannot be greater than MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.");
Shao80957d92017-02-20 21:25:59 +0800887 return false;
888 }
889
890 // [OpenGL ES 3.1] Section 10.3.1 page 243:
891 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
892 if (context->getGLState().getVertexArrayId() == 0)
893 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500894 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800895 return false;
896 }
897
898 return ValidateVertexFormatBase(context, attribIndex, size, type, pureInteger);
899}
900
901bool ValidateVertexAttribBinding(ValidationContext *context,
902 GLuint attribIndex,
903 GLuint bindingIndex)
904{
905 if (context->getClientVersion() < ES_3_1)
906 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700907 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Shao80957d92017-02-20 21:25:59 +0800908 return false;
909 }
910
911 // [OpenGL ES 3.1] Section 10.3.1 page 243:
912 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
913 if (context->getGLState().getVertexArrayId() == 0)
914 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500915 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800916 return false;
917 }
918
919 const Caps &caps = context->getCaps();
920 if (attribIndex >= caps.maxVertexAttributes)
921 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700922 ANGLE_VALIDATION_ERR(context, InvalidValue(), IndexExceedsMaxVertexAttribute);
Shao80957d92017-02-20 21:25:59 +0800923 return false;
924 }
925
926 if (bindingIndex >= caps.maxVertexAttribBindings)
927 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500928 context->handleError(InvalidValue()
929 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS");
Shao80957d92017-02-20 21:25:59 +0800930 return false;
931 }
932
jchen1015015f72017-03-16 13:54:21 +0800933 return true;
934}
935
jchen10fd7c3b52017-03-21 15:36:03 +0800936bool ValidateGetProgramResourceName(Context *context,
937 GLuint program,
938 GLenum programInterface,
939 GLuint index,
940 GLsizei bufSize,
941 GLsizei *length,
942 GLchar *name)
943{
944 if (context->getClientVersion() < ES_3_1)
945 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700946 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
jchen10fd7c3b52017-03-21 15:36:03 +0800947 return false;
948 }
949
950 Program *programObject = GetValidProgram(context, program);
951 if (programObject == nullptr)
952 {
953 return false;
954 }
955
956 if (!ValidateNamedProgramInterface(programInterface))
957 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500958 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
959 << std::uppercase << programInterface);
jchen10fd7c3b52017-03-21 15:36:03 +0800960 return false;
961 }
962
963 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
964 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500965 context->handleError(InvalidValue() << "Invalid index: " << index);
jchen10fd7c3b52017-03-21 15:36:03 +0800966 return false;
967 }
968
969 if (bufSize < 0)
970 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700971 ANGLE_VALIDATION_ERR(context, InvalidValue(), NegativeBufferSize);
jchen10fd7c3b52017-03-21 15:36:03 +0800972 return false;
973 }
974
975 return true;
976}
977
Xinghua Cao2b396592017-03-29 15:36:04 +0800978bool ValidateDispatchCompute(Context *context,
979 GLuint numGroupsX,
980 GLuint numGroupsY,
981 GLuint numGroupsZ)
982{
983 if (context->getClientVersion() < ES_3_1)
984 {
Brandon Jonesafa75152017-07-21 13:11:29 -0700985 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
Xinghua Cao2b396592017-03-29 15:36:04 +0800986 return false;
987 }
988
989 const State &state = context->getGLState();
990 Program *program = state.getProgram();
991
992 if (program == nullptr)
993 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500994 context->handleError(InvalidOperation()
995 << "No active program object for the compute shader stage.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800996 return false;
997 }
998
999 if (program->isLinked() == false || program->getAttachedComputeShader() == nullptr)
1000 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001001 context->handleError(
1002 InvalidOperation()
1003 << "Program has not been successfully linked, or program contains no compute shaders.");
Xinghua Cao2b396592017-03-29 15:36:04 +08001004 return false;
1005 }
1006
1007 const Caps &caps = context->getCaps();
1008 if (numGroupsX > caps.maxComputeWorkGroupCount[0])
1009 {
1010 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001011 InvalidValue() << "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]="
1012 << caps.maxComputeWorkGroupCount[0]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001013 return false;
1014 }
1015 if (numGroupsY > caps.maxComputeWorkGroupCount[1])
1016 {
1017 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001018 InvalidValue() << "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]="
1019 << caps.maxComputeWorkGroupCount[1]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001020 return false;
1021 }
1022 if (numGroupsZ > caps.maxComputeWorkGroupCount[2])
1023 {
1024 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001025 InvalidValue() << "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2]="
1026 << caps.maxComputeWorkGroupCount[2]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001027 return false;
1028 }
1029
1030 return true;
1031}
1032
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001033bool ValidateBindImageTexture(Context *context,
1034 GLuint unit,
1035 GLuint texture,
1036 GLint level,
1037 GLboolean layered,
1038 GLint layer,
1039 GLenum access,
1040 GLenum format)
1041{
1042 GLuint maxImageUnits = context->getCaps().maxImageUnits;
1043 if (unit >= maxImageUnits)
1044 {
1045 context->handleError(InvalidValue()
1046 << "unit cannot be greater than or equal than MAX_IMAGE_UNITS = "
1047 << maxImageUnits);
1048 return false;
1049 }
1050
1051 if (level < 0)
1052 {
1053 context->handleError(InvalidValue() << "level is negative.");
1054 return false;
1055 }
1056
1057 if (layer < 0)
1058 {
1059 context->handleError(InvalidValue() << "layer is negative.");
1060 return false;
1061 }
1062
1063 if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE)
1064 {
1065 context->handleError(InvalidEnum() << "access is not one of the supported tokens.");
1066 return false;
1067 }
1068
1069 switch (format)
1070 {
1071 case GL_RGBA32F:
1072 case GL_RGBA16F:
1073 case GL_R32F:
1074 case GL_RGBA32UI:
1075 case GL_RGBA16UI:
1076 case GL_RGBA8UI:
1077 case GL_R32UI:
1078 case GL_RGBA32I:
1079 case GL_RGBA16I:
1080 case GL_RGBA8I:
1081 case GL_R32I:
1082 case GL_RGBA8:
1083 case GL_RGBA8_SNORM:
1084 break;
1085 default:
1086 context->handleError(InvalidValue()
1087 << "format is not one of supported image unit formats.");
1088 return false;
1089 }
1090
1091 if (texture != 0)
1092 {
1093 Texture *tex = context->getTexture(texture);
1094
1095 if (tex == nullptr)
1096 {
1097 context->handleError(InvalidValue()
1098 << "texture is not the name of an existing texture object.");
1099 return false;
1100 }
1101
1102 if (!tex->getImmutableFormat())
1103 {
1104 context->handleError(InvalidOperation()
1105 << "texture is not the name of an immutable texture object.");
1106 return false;
1107 }
1108 }
1109
1110 return true;
1111}
jchen10191381f2017-04-11 13:59:04 +08001112
1113bool ValidateGetProgramResourceLocation(Context *context,
1114 GLuint program,
1115 GLenum programInterface,
1116 const GLchar *name)
1117{
1118 if (context->getClientVersion() < ES_3_1)
1119 {
Brandon Jonesafa75152017-07-21 13:11:29 -07001120 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
jchen10191381f2017-04-11 13:59:04 +08001121 return false;
1122 }
1123
1124 Program *programObject = GetValidProgram(context, program);
1125 if (programObject == nullptr)
1126 {
1127 return false;
1128 }
1129
1130 if (!programObject->isLinked())
1131 {
1132 context->handleError(InvalidOperation() << "Program is not successfully linked.");
1133 return false;
1134 }
1135
1136 if (!ValidateLocationProgramInterface(programInterface))
1137 {
1138 context->handleError(InvalidEnum() << "Invalid program interface.");
1139 return false;
1140 }
1141 return true;
1142}
1143
jchen10880683b2017-04-12 16:21:55 +08001144bool ValidateGetProgramResourceiv(Context *context,
1145 GLuint program,
1146 GLenum programInterface,
1147 GLuint index,
1148 GLsizei propCount,
1149 const GLenum *props,
1150 GLsizei bufSize,
1151 GLsizei *length,
1152 GLint *params)
1153{
1154 if (context->getClientVersion() < ES_3_1)
1155 {
jchen10d9cd7b72017-08-30 15:04:25 +08001156 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
jchen10880683b2017-04-12 16:21:55 +08001157 return false;
1158 }
1159
1160 Program *programObject = GetValidProgram(context, program);
1161 if (programObject == nullptr)
1162 {
1163 return false;
1164 }
1165 if (!ValidateProgramInterface(programInterface))
1166 {
1167 context->handleError(InvalidEnum() << "Invalid program interface.");
1168 return false;
1169 }
1170 if (propCount <= 0)
1171 {
1172 context->handleError(InvalidValue() << "Invalid propCount.");
1173 return false;
1174 }
1175 if (bufSize < 0)
1176 {
1177 context->handleError(InvalidValue() << "Invalid bufSize.");
1178 return false;
1179 }
1180 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
1181 {
1182 context->handleError(InvalidValue() << "Invalid index: " << index);
1183 return false;
1184 }
1185 for (GLsizei i = 0; i < propCount; i++)
1186 {
1187 if (!ValidateProgramResourceProperty(props[i]))
1188 {
1189 context->handleError(InvalidEnum() << "Invalid prop.");
1190 return false;
1191 }
1192 if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface))
1193 {
1194 context->handleError(InvalidOperation() << "Not an allowed prop for interface");
1195 return false;
1196 }
1197 }
1198 return true;
1199}
1200
jchen10d9cd7b72017-08-30 15:04:25 +08001201bool ValidateGetProgramInterfaceiv(Context *context,
1202 GLuint program,
1203 GLenum programInterface,
1204 GLenum pname,
1205 GLint *params)
1206{
1207 if (context->getClientVersion() < ES_3_1)
1208 {
1209 ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
1210 return false;
1211 }
1212
1213 Program *programObject = GetValidProgram(context, program);
1214 if (programObject == nullptr)
1215 {
1216 return false;
1217 }
1218
1219 if (!ValidateProgramInterface(programInterface))
1220 {
1221 context->handleError(InvalidEnum() << "Invalid program interface.");
1222 return false;
1223 }
1224
1225 switch (pname)
1226 {
1227 case GL_ACTIVE_RESOURCES:
1228 case GL_MAX_NAME_LENGTH:
1229 case GL_MAX_NUM_ACTIVE_VARIABLES:
1230 break;
1231
1232 default:
1233 context->handleError(InvalidEnum() << "Unknown property of program interface.");
1234 return false;
1235 }
1236
1237 if (pname == GL_MAX_NAME_LENGTH && programInterface == GL_ATOMIC_COUNTER_BUFFER)
1238 {
1239 context->handleError(InvalidOperation()
1240 << "Active atomic counter resources are not assigned name strings.");
1241 return false;
1242 }
1243
1244 if (pname == GL_MAX_NUM_ACTIVE_VARIABLES)
1245 {
1246 switch (programInterface)
1247 {
1248 case GL_ATOMIC_COUNTER_BUFFER:
1249 case GL_SHADER_STORAGE_BLOCK:
1250 case GL_UNIFORM_BLOCK:
1251 break;
1252
1253 default:
1254 context->handleError(
1255 InvalidOperation()
1256 << "MAX_NUM_ACTIVE_VARIABLES requires a buffer or block interface.");
1257 return false;
1258 }
1259 }
1260
1261 return true;
1262}
1263
Martin Radev66fb8202016-07-28 11:45:20 +03001264} // namespace gl