blob: 54b7351a147bd83d19cc2850f027b92417b3963b [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"
Jamie Madill231c7f52017-04-26 13:45:37 -040013#include "libANGLE/VertexArray.h"
Geoff Lang2e43dbb2016-10-14 12:27:35 -040014#include "libANGLE/validationES.h"
15#include "libANGLE/validationES3.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
jchen10191381f2017-04-11 13:59:04 +080044bool ValidateLocationProgramInterface(GLenum programInterface)
45{
46 switch (programInterface)
47 {
48 case GL_UNIFORM:
49 case GL_PROGRAM_INPUT:
50 case GL_PROGRAM_OUTPUT:
51 return true;
52 default:
53 return false;
54 }
55}
56
jchen10880683b2017-04-12 16:21:55 +080057bool ValidateProgramInterface(GLenum programInterface)
58{
59 return (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
60 ValidateNamedProgramInterface(programInterface));
61}
62
63bool ValidateProgramResourceProperty(GLenum prop)
64{
65 switch (prop)
66 {
67 case GL_ACTIVE_VARIABLES:
68 case GL_BUFFER_BINDING:
69 case GL_NUM_ACTIVE_VARIABLES:
70
71 case GL_ARRAY_SIZE:
72
73 case GL_ARRAY_STRIDE:
74 case GL_BLOCK_INDEX:
75 case GL_IS_ROW_MAJOR:
76 case GL_MATRIX_STRIDE:
77
78 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
79
80 case GL_BUFFER_DATA_SIZE:
81
82 case GL_LOCATION:
83
84 case GL_NAME_LENGTH:
85
86 case GL_OFFSET:
87
88 case GL_REFERENCED_BY_VERTEX_SHADER:
89 case GL_REFERENCED_BY_FRAGMENT_SHADER:
90 case GL_REFERENCED_BY_COMPUTE_SHADER:
91
92 case GL_TOP_LEVEL_ARRAY_SIZE:
93 case GL_TOP_LEVEL_ARRAY_STRIDE:
94
95 case GL_TYPE:
96 return true;
97
98 default:
99 return false;
100 }
101}
102
103// GLES 3.10 spec: Page 82 -- Table 7.2
104bool ValidateProgramResourcePropertyByInterface(GLenum prop, GLenum programInterface)
105{
106 switch (prop)
107 {
108 case GL_ACTIVE_VARIABLES:
109 case GL_BUFFER_BINDING:
110 case GL_NUM_ACTIVE_VARIABLES:
111 {
112 switch (programInterface)
113 {
114 case GL_ATOMIC_COUNTER_BUFFER:
115 case GL_SHADER_STORAGE_BLOCK:
116 case GL_UNIFORM_BLOCK:
117 return true;
118 default:
119 return false;
120 }
121 }
122
123 case GL_ARRAY_SIZE:
124 {
125 switch (programInterface)
126 {
127 case GL_BUFFER_VARIABLE:
128 case GL_PROGRAM_INPUT:
129 case GL_PROGRAM_OUTPUT:
130 case GL_TRANSFORM_FEEDBACK_VARYING:
131 case GL_UNIFORM:
132 return true;
133 default:
134 return false;
135 }
136 }
137
138 case GL_ARRAY_STRIDE:
139 case GL_BLOCK_INDEX:
140 case GL_IS_ROW_MAJOR:
141 case GL_MATRIX_STRIDE:
142 {
143 switch (programInterface)
144 {
145 case GL_BUFFER_VARIABLE:
146 case GL_UNIFORM:
147 return true;
148 default:
149 return false;
150 }
151 }
152
153 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
154 {
155 if (programInterface == GL_UNIFORM)
156 {
157 return true;
158 }
159 return false;
160 }
161
162 case GL_BUFFER_DATA_SIZE:
163 {
164 switch (programInterface)
165 {
166 case GL_ATOMIC_COUNTER_BUFFER:
167 case GL_SHADER_STORAGE_BLOCK:
168 case GL_UNIFORM_BLOCK:
169 return true;
170 default:
171 return false;
172 }
173 }
174
175 case GL_LOCATION:
176 {
177 return ValidateLocationProgramInterface(programInterface);
178 }
179
180 case GL_NAME_LENGTH:
181 {
182 return ValidateNamedProgramInterface(programInterface);
183 }
184
185 case GL_OFFSET:
186 {
187 switch (programInterface)
188 {
189 case GL_BUFFER_VARIABLE:
190 case GL_UNIFORM:
191 return true;
192 default:
193 return false;
194 }
195 }
196
197 case GL_REFERENCED_BY_VERTEX_SHADER:
198 case GL_REFERENCED_BY_FRAGMENT_SHADER:
199 case GL_REFERENCED_BY_COMPUTE_SHADER:
200 {
201 switch (programInterface)
202 {
203 case GL_ATOMIC_COUNTER_BUFFER:
204 case GL_BUFFER_VARIABLE:
205 case GL_PROGRAM_INPUT:
206 case GL_PROGRAM_OUTPUT:
207 case GL_SHADER_STORAGE_BLOCK:
208 case GL_UNIFORM:
209 case GL_UNIFORM_BLOCK:
210 return true;
211 default:
212 return false;
213 }
214 }
215
216 case GL_TOP_LEVEL_ARRAY_SIZE:
217 case GL_TOP_LEVEL_ARRAY_STRIDE:
218 {
219 if (programInterface == GL_BUFFER_VARIABLE)
220 {
221 return true;
222 }
223 return false;
224 }
225
226 case GL_TYPE:
227 {
228 switch (programInterface)
229 {
230 case GL_BUFFER_VARIABLE:
231 case GL_PROGRAM_INPUT:
232 case GL_PROGRAM_OUTPUT:
233 case GL_TRANSFORM_FEEDBACK_VARYING:
234 case GL_UNIFORM:
235 return true;
236 default:
237 return false;
238 }
239 }
240
241 default:
242 return false;
243 }
244}
245
jchen10fd7c3b52017-03-21 15:36:03 +0800246bool ValidateProgramResourceIndex(const Program *programObject,
247 GLenum programInterface,
248 GLuint index)
249{
250 switch (programInterface)
251 {
252 case GL_PROGRAM_INPUT:
253 return (index < static_cast<GLuint>(programObject->getActiveAttributeCount()));
254
255 case GL_PROGRAM_OUTPUT:
256 return (index < static_cast<GLuint>(programObject->getOutputResourceCount()));
257
jchen10880683b2017-04-12 16:21:55 +0800258 // TODO(jie.a.chen@intel.com): more interfaces.
jchen10fd7c3b52017-03-21 15:36:03 +0800259 case GL_UNIFORM:
260 case GL_UNIFORM_BLOCK:
261 case GL_TRANSFORM_FEEDBACK_VARYING:
262 case GL_BUFFER_VARIABLE:
263 case GL_SHADER_STORAGE_BLOCK:
jchen10880683b2017-04-12 16:21:55 +0800264 case GL_ATOMIC_COUNTER_BUFFER:
jchen10fd7c3b52017-03-21 15:36:03 +0800265 UNIMPLEMENTED();
266 return false;
267
268 default:
269 UNREACHABLE();
270 return false;
271 }
272}
273
jchen1015015f72017-03-16 13:54:21 +0800274} // anonymous namespace
275
Martin Radev66fb8202016-07-28 11:45:20 +0300276bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data)
277{
Geoff Langeb66a6e2016-10-31 13:06:12 -0400278 if (context->getClientVersion() < ES_3_1)
Martin Radev66fb8202016-07-28 11:45:20 +0300279 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500280 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Martin Radev66fb8202016-07-28 11:45:20 +0300281 return false;
282 }
283
Geoff Lang2e43dbb2016-10-14 12:27:35 -0400284 if (!ValidateIndexedStateQuery(context, target, index, nullptr))
285 {
286 return false;
287 }
288
289 return true;
290}
291
292bool ValidateGetBooleani_vRobustANGLE(Context *context,
293 GLenum target,
294 GLuint index,
295 GLsizei bufSize,
296 GLsizei *length,
297 GLboolean *data)
298{
Geoff Langeb66a6e2016-10-31 13:06:12 -0400299 if (context->getClientVersion() < ES_3_1)
Geoff Lang2e43dbb2016-10-14 12:27:35 -0400300 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500301 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Geoff Lang2e43dbb2016-10-14 12:27:35 -0400302 return false;
303 }
304
305 if (!ValidateRobustEntryPoint(context, bufSize))
306 {
307 return false;
308 }
309
310 if (!ValidateIndexedStateQuery(context, target, index, length))
311 {
312 return false;
313 }
314
315 if (!ValidateRobustBufferSize(context, bufSize, *length))
Martin Radev66fb8202016-07-28 11:45:20 +0300316 {
317 return false;
318 }
319
320 return true;
321}
322
Jamie Madill876429b2017-04-20 15:46:24 -0400323bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800324{
325 if (context->getClientVersion() < ES_3_1)
326 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500327 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Jiajia Qind9671222016-11-29 16:30:31 +0800328 return false;
329 }
330
331 // Here the third parameter 1 is only to pass the count validation.
332 if (!ValidateDrawBase(context, mode, 1))
333 {
334 return false;
335 }
336
337 const State &state = context->getGLState();
338
339 // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING,
340 // DRAW_INDIRECT_BUFFER or to any enabled vertex array.
341 if (!state.getVertexArrayId())
342 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500343 context->handleError(InvalidOperation() << "zero is bound to VERTEX_ARRAY_BINDING");
Jiajia Qind9671222016-11-29 16:30:31 +0800344 return false;
345 }
346
347 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
348 if (!drawIndirectBuffer)
349 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500350 context->handleError(InvalidOperation() << "zero is bound to DRAW_INDIRECT_BUFFER");
Jiajia Qind9671222016-11-29 16:30:31 +0800351 return false;
352 }
353
354 // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic
355 // machine units, of uint.
356 GLint64 offset = reinterpret_cast<GLint64>(indirect);
357 if ((static_cast<GLuint>(offset) % sizeof(GLuint)) != 0)
358 {
359 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500360 InvalidValue()
361 << "indirect is not a multiple of the size, in basic machine units, of uint");
Jiajia Qind9671222016-11-29 16:30:31 +0800362 return false;
363 }
364
Martin Radev14a26ae2017-07-24 15:56:29 +0300365 // ANGLE_multiview spec, revision 1:
366 // An INVALID_OPERATION is generated by DrawArraysIndirect and DrawElementsIndirect if the
367 // number of views in the draw framebuffer is greater than 1.
368 const Framebuffer *drawFramebuffer = context->getGLState().getDrawFramebuffer();
369 ASSERT(drawFramebuffer != nullptr);
370 if (drawFramebuffer->getNumViews() > 1)
371 {
372 context->handleError(
373 InvalidOperation()
374 << "The number of views in the active draw framebuffer is greater than 1.");
375 return false;
376 }
377
Jiajia Qind9671222016-11-29 16:30:31 +0800378 return true;
379}
380
Jamie Madill876429b2017-04-20 15:46:24 -0400381bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800382{
383 const State &state = context->getGLState();
384 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
385 if (curTransformFeedback && curTransformFeedback->isActive() &&
386 !curTransformFeedback->isPaused())
387 {
388 // An INVALID_OPERATION error is generated if transform feedback is active and not paused.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500389 context->handleError(InvalidOperation() << "transform feedback is active and not paused.");
Jiajia Qind9671222016-11-29 16:30:31 +0800390 return false;
391 }
392
393 if (!ValidateDrawIndirectBase(context, mode, indirect))
394 return false;
395
396 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
397 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
398 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand
399 // which's size is 4 * sizeof(uint).
400 auto checkedSum = checkedOffset + 4 * sizeof(GLuint);
401 if (!checkedSum.IsValid() ||
402 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
403 {
404 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500405 InvalidOperation()
406 << "the command would source data beyond the end of the buffer object.");
Jiajia Qind9671222016-11-29 16:30:31 +0800407 return false;
408 }
409
410 return true;
411}
412
Jamie Madill876429b2017-04-20 15:46:24 -0400413bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800414{
415 if (!ValidateDrawElementsBase(context, type))
416 return false;
417
418 const State &state = context->getGLState();
419 const VertexArray *vao = state.getVertexArray();
420 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
421 if (!elementArrayBuffer)
422 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500423 context->handleError(InvalidOperation() << "zero is bound to ELEMENT_ARRAY_BUFFER");
Jiajia Qind9671222016-11-29 16:30:31 +0800424 return false;
425 }
426
427 if (!ValidateDrawIndirectBase(context, mode, indirect))
428 return false;
429
430 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
431 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
432 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand
433 // which's size is 5 * sizeof(uint).
434 auto checkedSum = checkedOffset + 5 * sizeof(GLuint);
435 if (!checkedSum.IsValid() ||
436 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
437 {
438 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500439 InvalidOperation()
440 << "the command would source data beyond the end of the buffer object.");
Jiajia Qind9671222016-11-29 16:30:31 +0800441 return false;
442 }
443
444 return true;
445}
446
He Yunchao11b038b2016-11-22 21:24:04 +0800447bool ValidateGetTexLevelParameterBase(Context *context,
448 GLenum target,
449 GLint level,
450 GLenum pname,
451 GLsizei *length)
452{
453 if (context->getClientVersion() < ES_3_1)
454 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500455 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
He Yunchao11b038b2016-11-22 21:24:04 +0800456 return false;
457 }
458
459 if (length)
460 {
461 *length = 0;
462 }
463
464 if (!ValidTexLevelDestinationTarget(context, target))
465 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500466 context->handleError(InvalidEnum() << "Invalid texture target");
He Yunchao11b038b2016-11-22 21:24:04 +0800467 return false;
468 }
469
470 if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) ==
471 nullptr)
472 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500473 context->handleError(InvalidEnum() << "No texture bound.");
He Yunchao11b038b2016-11-22 21:24:04 +0800474 return false;
475 }
476
477 if (!ValidMipLevel(context, target, level))
478 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500479 context->handleError(InvalidValue());
He Yunchao11b038b2016-11-22 21:24:04 +0800480 return false;
481 }
482
483 switch (pname)
484 {
485 case GL_TEXTURE_RED_TYPE:
486 case GL_TEXTURE_GREEN_TYPE:
487 case GL_TEXTURE_BLUE_TYPE:
488 case GL_TEXTURE_ALPHA_TYPE:
489 case GL_TEXTURE_DEPTH_TYPE:
490 break;
491 case GL_TEXTURE_RED_SIZE:
492 case GL_TEXTURE_GREEN_SIZE:
493 case GL_TEXTURE_BLUE_SIZE:
494 case GL_TEXTURE_ALPHA_SIZE:
495 case GL_TEXTURE_DEPTH_SIZE:
496 case GL_TEXTURE_STENCIL_SIZE:
497 case GL_TEXTURE_SHARED_SIZE:
498 break;
499 case GL_TEXTURE_INTERNAL_FORMAT:
500 case GL_TEXTURE_WIDTH:
501 case GL_TEXTURE_HEIGHT:
502 case GL_TEXTURE_DEPTH:
503 break;
504 case GL_TEXTURE_SAMPLES:
505 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
506 break;
507 case GL_TEXTURE_COMPRESSED:
508 break;
509 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500510 context->handleError(InvalidEnum() << "Unknown pname.");
He Yunchao11b038b2016-11-22 21:24:04 +0800511 return false;
512 }
513
514 if (length)
515 {
516 *length = 1;
517 }
518 return true;
519}
520
521bool ValidateGetTexLevelParameterfv(Context *context,
522 GLenum target,
523 GLint level,
524 GLenum pname,
525 GLfloat *params)
526{
527 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
528}
529
530bool ValidateGetTexLevelParameteriv(Context *context,
531 GLenum target,
532 GLint level,
533 GLenum pname,
534 GLint *params)
535{
536 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
537}
538
JiangYizhoubddc46b2016-12-09 09:50:51 +0800539bool ValidateTexStorage2DMultiSample(Context *context,
540 GLenum target,
541 GLsizei samples,
542 GLint internalFormat,
543 GLsizei width,
544 GLsizei height,
545 GLboolean fixedSampleLocations)
546{
547 if (context->getClientVersion() < ES_3_1)
548 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500549 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800550 return false;
551 }
552
553 if (target != GL_TEXTURE_2D_MULTISAMPLE)
554 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500555 context->handleError(InvalidEnum() << "Target must be TEXTURE_2D_MULTISAMPLE.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800556 return false;
557 }
558
559 if (width < 1 || height < 1)
560 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500561 context->handleError(InvalidValue() << "Width and height must be positive.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800562 return false;
563 }
564
565 const Caps &caps = context->getCaps();
566 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
567 static_cast<GLuint>(height) > caps.max2DTextureSize)
568 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500569 context
570 ->handleError(InvalidValue()
571 << "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800572 return false;
573 }
574
575 if (samples == 0)
576 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500577 context->handleError(InvalidValue() << "Samples may not be zero.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800578 return false;
579 }
580
581 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
582 if (!formatCaps.renderable)
583 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500584 context->handleError(InvalidEnum() << "SizedInternalformat must be color-renderable, "
585 "depth-renderable, or stencil-renderable.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800586 return false;
587 }
588
589 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
590 // is one of the unsized base internalformats listed in table 8.11.
Geoff Langca271392017-04-05 12:30:00 -0400591 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
592 if (formatInfo.internalFormat == GL_NONE)
JiangYizhoubddc46b2016-12-09 09:50:51 +0800593 {
594 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500595 InvalidEnum()
596 << "Internalformat is one of the unsupported unsized base internalformats.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800597 return false;
598 }
599
600 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
601 {
602 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500603 InvalidOperation()
604 << "Samples must not be greater than maximum supported value for the format.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800605 return false;
606 }
607
608 Texture *texture = context->getTargetTexture(target);
609 if (!texture || texture->id() == 0)
610 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500611 context->handleError(InvalidOperation() << "Zero is bound to target.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800612 return false;
613 }
614
615 if (texture->getImmutableFormat())
616 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500617 context->handleError(InvalidOperation() << "The value of TEXTURE_IMMUTABLE_FORMAT for "
618 "the texture currently bound to target on "
619 "the active texture unit is true.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800620 return false;
621 }
622
623 return true;
624}
625
626bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val)
627{
628 if (context->getClientVersion() < ES_3_1)
629 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500630 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800631 return false;
632 }
633
634 if (pname != GL_SAMPLE_POSITION)
635 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500636 context->handleError(InvalidEnum() << "Pname must be SAMPLE_POSITION.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800637 return false;
638 }
639
640 GLint maxSamples = context->getCaps().maxSamples;
641 if (index >= static_cast<GLuint>(maxSamples))
642 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500643 context->handleError(InvalidValue() << "Index must be less than the value of SAMPLES.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800644 return false;
645 }
646
647 return true;
648}
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800649
650bool ValidationFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param)
651{
652 if (context->getClientVersion() < ES_3_1)
653 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500654 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800655 return false;
656 }
657
658 if (!ValidFramebufferTarget(target))
659 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500660 context->handleError(InvalidEnum() << "Invalid framebuffer target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800661 return false;
662 }
663
664 switch (pname)
665 {
666 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
667 {
668 GLint maxWidth = context->getCaps().maxFramebufferWidth;
669 if (param < 0 || param > maxWidth)
670 {
671 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500672 InvalidValue()
673 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800674 return false;
675 }
676 break;
677 }
678 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
679 {
680 GLint maxHeight = context->getCaps().maxFramebufferHeight;
681 if (param < 0 || param > maxHeight)
682 {
683 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500684 InvalidValue()
685 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800686 return false;
687 }
688 break;
689 }
690 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
691 {
692 GLint maxSamples = context->getCaps().maxFramebufferSamples;
693 if (param < 0 || param > maxSamples)
694 {
695 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500696 InvalidValue()
697 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800698 return false;
699 }
700 break;
701 }
702 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
703 {
704 break;
705 }
706 default:
707 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500708 context->handleError(InvalidEnum()
709 << "Invalid pname: 0x" << std::hex << std::uppercase << pname);
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 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500731 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800732 return false;
733 }
734
735 if (!ValidFramebufferTarget(target))
736 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500737 context->handleError(InvalidEnum() << "Invalid framebuffer target.");
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:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500749 context->handleError(InvalidEnum()
750 << "Invalid pname: 0x" << std::hex << std::uppercase << pname);
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 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500772 context->handleError(InvalidOperation() << "Context does not support GLES 3.1.");
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 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500800 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
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 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500820 context->handleError(InvalidValue() << "offset cannot be negative.");
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 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500846 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
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 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500878 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
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 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500908 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
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 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500923 context->handleError(InvalidValue()
924 << "attribindex must be smaller than MAX_VERTEX_ATTRIBS.");
Shao80957d92017-02-20 21:25:59 +0800925 return false;
926 }
927
928 if (bindingIndex >= caps.maxVertexAttribBindings)
929 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500930 context->handleError(InvalidValue()
931 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS");
Shao80957d92017-02-20 21:25:59 +0800932 return false;
933 }
934
jchen1015015f72017-03-16 13:54:21 +0800935 return true;
936}
937
jchen10fd7c3b52017-03-21 15:36:03 +0800938bool ValidateGetProgramResourceName(Context *context,
939 GLuint program,
940 GLenum programInterface,
941 GLuint index,
942 GLsizei bufSize,
943 GLsizei *length,
944 GLchar *name)
945{
946 if (context->getClientVersion() < ES_3_1)
947 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500948 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
jchen10fd7c3b52017-03-21 15:36:03 +0800949 return false;
950 }
951
952 Program *programObject = GetValidProgram(context, program);
953 if (programObject == nullptr)
954 {
955 return false;
956 }
957
958 if (!ValidateNamedProgramInterface(programInterface))
959 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500960 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
961 << std::uppercase << programInterface);
jchen10fd7c3b52017-03-21 15:36:03 +0800962 return false;
963 }
964
965 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
966 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500967 context->handleError(InvalidValue() << "Invalid index: " << index);
jchen10fd7c3b52017-03-21 15:36:03 +0800968 return false;
969 }
970
971 if (bufSize < 0)
972 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500973 context->handleError(InvalidValue() << "Invalid bufSize: " << bufSize);
jchen10fd7c3b52017-03-21 15:36:03 +0800974 return false;
975 }
976
977 return true;
978}
979
Xinghua Cao2b396592017-03-29 15:36:04 +0800980bool ValidateDispatchCompute(Context *context,
981 GLuint numGroupsX,
982 GLuint numGroupsY,
983 GLuint numGroupsZ)
984{
985 if (context->getClientVersion() < ES_3_1)
986 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500987 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800988 return false;
989 }
990
991 const State &state = context->getGLState();
992 Program *program = state.getProgram();
993
994 if (program == nullptr)
995 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500996 context->handleError(InvalidOperation()
997 << "No active program object for the compute shader stage.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800998 return false;
999 }
1000
1001 if (program->isLinked() == false || program->getAttachedComputeShader() == nullptr)
1002 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001003 context->handleError(
1004 InvalidOperation()
1005 << "Program has not been successfully linked, or program contains no compute shaders.");
Xinghua Cao2b396592017-03-29 15:36:04 +08001006 return false;
1007 }
1008
1009 const Caps &caps = context->getCaps();
1010 if (numGroupsX > caps.maxComputeWorkGroupCount[0])
1011 {
1012 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001013 InvalidValue() << "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]="
1014 << caps.maxComputeWorkGroupCount[0]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001015 return false;
1016 }
1017 if (numGroupsY > caps.maxComputeWorkGroupCount[1])
1018 {
1019 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001020 InvalidValue() << "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]="
1021 << caps.maxComputeWorkGroupCount[1]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001022 return false;
1023 }
1024 if (numGroupsZ > caps.maxComputeWorkGroupCount[2])
1025 {
1026 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001027 InvalidValue() << "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2]="
1028 << caps.maxComputeWorkGroupCount[2]);
Xinghua Cao2b396592017-03-29 15:36:04 +08001029 return false;
1030 }
1031
1032 return true;
1033}
1034
Xinghua Cao65ec0b22017-03-28 16:10:52 +08001035bool ValidateBindImageTexture(Context *context,
1036 GLuint unit,
1037 GLuint texture,
1038 GLint level,
1039 GLboolean layered,
1040 GLint layer,
1041 GLenum access,
1042 GLenum format)
1043{
1044 GLuint maxImageUnits = context->getCaps().maxImageUnits;
1045 if (unit >= maxImageUnits)
1046 {
1047 context->handleError(InvalidValue()
1048 << "unit cannot be greater than or equal than MAX_IMAGE_UNITS = "
1049 << maxImageUnits);
1050 return false;
1051 }
1052
1053 if (level < 0)
1054 {
1055 context->handleError(InvalidValue() << "level is negative.");
1056 return false;
1057 }
1058
1059 if (layer < 0)
1060 {
1061 context->handleError(InvalidValue() << "layer is negative.");
1062 return false;
1063 }
1064
1065 if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE)
1066 {
1067 context->handleError(InvalidEnum() << "access is not one of the supported tokens.");
1068 return false;
1069 }
1070
1071 switch (format)
1072 {
1073 case GL_RGBA32F:
1074 case GL_RGBA16F:
1075 case GL_R32F:
1076 case GL_RGBA32UI:
1077 case GL_RGBA16UI:
1078 case GL_RGBA8UI:
1079 case GL_R32UI:
1080 case GL_RGBA32I:
1081 case GL_RGBA16I:
1082 case GL_RGBA8I:
1083 case GL_R32I:
1084 case GL_RGBA8:
1085 case GL_RGBA8_SNORM:
1086 break;
1087 default:
1088 context->handleError(InvalidValue()
1089 << "format is not one of supported image unit formats.");
1090 return false;
1091 }
1092
1093 if (texture != 0)
1094 {
1095 Texture *tex = context->getTexture(texture);
1096
1097 if (tex == nullptr)
1098 {
1099 context->handleError(InvalidValue()
1100 << "texture is not the name of an existing texture object.");
1101 return false;
1102 }
1103
1104 if (!tex->getImmutableFormat())
1105 {
1106 context->handleError(InvalidOperation()
1107 << "texture is not the name of an immutable texture object.");
1108 return false;
1109 }
1110 }
1111
1112 return true;
1113}
jchen10191381f2017-04-11 13:59:04 +08001114
1115bool ValidateGetProgramResourceLocation(Context *context,
1116 GLuint program,
1117 GLenum programInterface,
1118 const GLchar *name)
1119{
1120 if (context->getClientVersion() < ES_3_1)
1121 {
1122 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
1123 return false;
1124 }
1125
1126 Program *programObject = GetValidProgram(context, program);
1127 if (programObject == nullptr)
1128 {
1129 return false;
1130 }
1131
1132 if (!programObject->isLinked())
1133 {
1134 context->handleError(InvalidOperation() << "Program is not successfully linked.");
1135 return false;
1136 }
1137
1138 if (!ValidateLocationProgramInterface(programInterface))
1139 {
1140 context->handleError(InvalidEnum() << "Invalid program interface.");
1141 return false;
1142 }
1143 return true;
1144}
1145
jchen10880683b2017-04-12 16:21:55 +08001146bool ValidateGetProgramResourceiv(Context *context,
1147 GLuint program,
1148 GLenum programInterface,
1149 GLuint index,
1150 GLsizei propCount,
1151 const GLenum *props,
1152 GLsizei bufSize,
1153 GLsizei *length,
1154 GLint *params)
1155{
1156 if (context->getClientVersion() < ES_3_1)
1157 {
1158 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
1159 return false;
1160 }
1161
1162 Program *programObject = GetValidProgram(context, program);
1163 if (programObject == nullptr)
1164 {
1165 return false;
1166 }
1167 if (!ValidateProgramInterface(programInterface))
1168 {
1169 context->handleError(InvalidEnum() << "Invalid program interface.");
1170 return false;
1171 }
1172 if (propCount <= 0)
1173 {
1174 context->handleError(InvalidValue() << "Invalid propCount.");
1175 return false;
1176 }
1177 if (bufSize < 0)
1178 {
1179 context->handleError(InvalidValue() << "Invalid bufSize.");
1180 return false;
1181 }
1182 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
1183 {
1184 context->handleError(InvalidValue() << "Invalid index: " << index);
1185 return false;
1186 }
1187 for (GLsizei i = 0; i < propCount; i++)
1188 {
1189 if (!ValidateProgramResourceProperty(props[i]))
1190 {
1191 context->handleError(InvalidEnum() << "Invalid prop.");
1192 return false;
1193 }
1194 if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface))
1195 {
1196 context->handleError(InvalidOperation() << "Not an allowed prop for interface");
1197 return false;
1198 }
1199 }
1200 return true;
1201}
1202
Martin Radev66fb8202016-07-28 11:45:20 +03001203} // namespace gl