blob: 0711029df5220672be6558c9d0766daab28d3aad [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
jchen10fd7c3b52017-03-21 15:36:03 +080044bool ValidateProgramResourceIndex(const Program *programObject,
45 GLenum programInterface,
46 GLuint index)
47{
48 switch (programInterface)
49 {
50 case GL_PROGRAM_INPUT:
51 return (index < static_cast<GLuint>(programObject->getActiveAttributeCount()));
52
53 case GL_PROGRAM_OUTPUT:
54 return (index < static_cast<GLuint>(programObject->getOutputResourceCount()));
55
56 // TODO(Jie): more interfaces.
57 case GL_UNIFORM:
58 case GL_UNIFORM_BLOCK:
59 case GL_TRANSFORM_FEEDBACK_VARYING:
60 case GL_BUFFER_VARIABLE:
61 case GL_SHADER_STORAGE_BLOCK:
62 UNIMPLEMENTED();
63 return false;
64
65 default:
66 UNREACHABLE();
67 return false;
68 }
69}
70
jchen1015015f72017-03-16 13:54:21 +080071} // anonymous namespace
72
Martin Radev66fb8202016-07-28 11:45:20 +030073bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data)
74{
Geoff Langeb66a6e2016-10-31 13:06:12 -040075 if (context->getClientVersion() < ES_3_1)
Martin Radev66fb8202016-07-28 11:45:20 +030076 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -050077 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Martin Radev66fb8202016-07-28 11:45:20 +030078 return false;
79 }
80
Geoff Lang2e43dbb2016-10-14 12:27:35 -040081 if (!ValidateIndexedStateQuery(context, target, index, nullptr))
82 {
83 return false;
84 }
85
86 return true;
87}
88
89bool ValidateGetBooleani_vRobustANGLE(Context *context,
90 GLenum target,
91 GLuint index,
92 GLsizei bufSize,
93 GLsizei *length,
94 GLboolean *data)
95{
Geoff Langeb66a6e2016-10-31 13:06:12 -040096 if (context->getClientVersion() < ES_3_1)
Geoff Lang2e43dbb2016-10-14 12:27:35 -040097 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -050098 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Geoff Lang2e43dbb2016-10-14 12:27:35 -040099 return false;
100 }
101
102 if (!ValidateRobustEntryPoint(context, bufSize))
103 {
104 return false;
105 }
106
107 if (!ValidateIndexedStateQuery(context, target, index, length))
108 {
109 return false;
110 }
111
112 if (!ValidateRobustBufferSize(context, bufSize, *length))
Martin Radev66fb8202016-07-28 11:45:20 +0300113 {
114 return false;
115 }
116
117 return true;
118}
119
Jamie Madill876429b2017-04-20 15:46:24 -0400120bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800121{
122 if (context->getClientVersion() < ES_3_1)
123 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500124 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Jiajia Qind9671222016-11-29 16:30:31 +0800125 return false;
126 }
127
128 // Here the third parameter 1 is only to pass the count validation.
129 if (!ValidateDrawBase(context, mode, 1))
130 {
131 return false;
132 }
133
134 const State &state = context->getGLState();
135
136 // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING,
137 // DRAW_INDIRECT_BUFFER or to any enabled vertex array.
138 if (!state.getVertexArrayId())
139 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500140 context->handleError(InvalidOperation() << "zero is bound to VERTEX_ARRAY_BINDING");
Jiajia Qind9671222016-11-29 16:30:31 +0800141 return false;
142 }
143
144 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
145 if (!drawIndirectBuffer)
146 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500147 context->handleError(InvalidOperation() << "zero is bound to DRAW_INDIRECT_BUFFER");
Jiajia Qind9671222016-11-29 16:30:31 +0800148 return false;
149 }
150
151 // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic
152 // machine units, of uint.
153 GLint64 offset = reinterpret_cast<GLint64>(indirect);
154 if ((static_cast<GLuint>(offset) % sizeof(GLuint)) != 0)
155 {
156 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500157 InvalidValue()
158 << "indirect is not a multiple of the size, in basic machine units, of uint");
Jiajia Qind9671222016-11-29 16:30:31 +0800159 return false;
160 }
161
162 return true;
163}
164
Jamie Madill876429b2017-04-20 15:46:24 -0400165bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800166{
167 const State &state = context->getGLState();
168 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
169 if (curTransformFeedback && curTransformFeedback->isActive() &&
170 !curTransformFeedback->isPaused())
171 {
172 // An INVALID_OPERATION error is generated if transform feedback is active and not paused.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500173 context->handleError(InvalidOperation() << "transform feedback is active and not paused.");
Jiajia Qind9671222016-11-29 16:30:31 +0800174 return false;
175 }
176
177 if (!ValidateDrawIndirectBase(context, mode, indirect))
178 return false;
179
180 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
181 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
182 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand
183 // which's size is 4 * sizeof(uint).
184 auto checkedSum = checkedOffset + 4 * sizeof(GLuint);
185 if (!checkedSum.IsValid() ||
186 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
187 {
188 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500189 InvalidOperation()
190 << "the command would source data beyond the end of the buffer object.");
Jiajia Qind9671222016-11-29 16:30:31 +0800191 return false;
192 }
193
194 return true;
195}
196
Jamie Madill876429b2017-04-20 15:46:24 -0400197bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800198{
199 if (!ValidateDrawElementsBase(context, type))
200 return false;
201
202 const State &state = context->getGLState();
203 const VertexArray *vao = state.getVertexArray();
204 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
205 if (!elementArrayBuffer)
206 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500207 context->handleError(InvalidOperation() << "zero is bound to ELEMENT_ARRAY_BUFFER");
Jiajia Qind9671222016-11-29 16:30:31 +0800208 return false;
209 }
210
211 if (!ValidateDrawIndirectBase(context, mode, indirect))
212 return false;
213
214 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
215 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
216 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand
217 // which's size is 5 * sizeof(uint).
218 auto checkedSum = checkedOffset + 5 * sizeof(GLuint);
219 if (!checkedSum.IsValid() ||
220 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
221 {
222 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500223 InvalidOperation()
224 << "the command would source data beyond the end of the buffer object.");
Jiajia Qind9671222016-11-29 16:30:31 +0800225 return false;
226 }
227
228 return true;
229}
230
He Yunchao11b038b2016-11-22 21:24:04 +0800231bool ValidateGetTexLevelParameterBase(Context *context,
232 GLenum target,
233 GLint level,
234 GLenum pname,
235 GLsizei *length)
236{
237 if (context->getClientVersion() < ES_3_1)
238 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500239 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
He Yunchao11b038b2016-11-22 21:24:04 +0800240 return false;
241 }
242
243 if (length)
244 {
245 *length = 0;
246 }
247
248 if (!ValidTexLevelDestinationTarget(context, target))
249 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500250 context->handleError(InvalidEnum() << "Invalid texture target");
He Yunchao11b038b2016-11-22 21:24:04 +0800251 return false;
252 }
253
254 if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) ==
255 nullptr)
256 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500257 context->handleError(InvalidEnum() << "No texture bound.");
He Yunchao11b038b2016-11-22 21:24:04 +0800258 return false;
259 }
260
261 if (!ValidMipLevel(context, target, level))
262 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500263 context->handleError(InvalidValue());
He Yunchao11b038b2016-11-22 21:24:04 +0800264 return false;
265 }
266
267 switch (pname)
268 {
269 case GL_TEXTURE_RED_TYPE:
270 case GL_TEXTURE_GREEN_TYPE:
271 case GL_TEXTURE_BLUE_TYPE:
272 case GL_TEXTURE_ALPHA_TYPE:
273 case GL_TEXTURE_DEPTH_TYPE:
274 break;
275 case GL_TEXTURE_RED_SIZE:
276 case GL_TEXTURE_GREEN_SIZE:
277 case GL_TEXTURE_BLUE_SIZE:
278 case GL_TEXTURE_ALPHA_SIZE:
279 case GL_TEXTURE_DEPTH_SIZE:
280 case GL_TEXTURE_STENCIL_SIZE:
281 case GL_TEXTURE_SHARED_SIZE:
282 break;
283 case GL_TEXTURE_INTERNAL_FORMAT:
284 case GL_TEXTURE_WIDTH:
285 case GL_TEXTURE_HEIGHT:
286 case GL_TEXTURE_DEPTH:
287 break;
288 case GL_TEXTURE_SAMPLES:
289 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
290 break;
291 case GL_TEXTURE_COMPRESSED:
292 break;
293 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500294 context->handleError(InvalidEnum() << "Unknown pname.");
He Yunchao11b038b2016-11-22 21:24:04 +0800295 return false;
296 }
297
298 if (length)
299 {
300 *length = 1;
301 }
302 return true;
303}
304
305bool ValidateGetTexLevelParameterfv(Context *context,
306 GLenum target,
307 GLint level,
308 GLenum pname,
309 GLfloat *params)
310{
311 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
312}
313
314bool ValidateGetTexLevelParameteriv(Context *context,
315 GLenum target,
316 GLint level,
317 GLenum pname,
318 GLint *params)
319{
320 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
321}
322
JiangYizhoubddc46b2016-12-09 09:50:51 +0800323bool ValidateTexStorage2DMultiSample(Context *context,
324 GLenum target,
325 GLsizei samples,
326 GLint internalFormat,
327 GLsizei width,
328 GLsizei height,
329 GLboolean fixedSampleLocations)
330{
331 if (context->getClientVersion() < ES_3_1)
332 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500333 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800334 return false;
335 }
336
337 if (target != GL_TEXTURE_2D_MULTISAMPLE)
338 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500339 context->handleError(InvalidEnum() << "Target must be TEXTURE_2D_MULTISAMPLE.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800340 return false;
341 }
342
343 if (width < 1 || height < 1)
344 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500345 context->handleError(InvalidValue() << "Width and height must be positive.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800346 return false;
347 }
348
349 const Caps &caps = context->getCaps();
350 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
351 static_cast<GLuint>(height) > caps.max2DTextureSize)
352 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500353 context
354 ->handleError(InvalidValue()
355 << "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800356 return false;
357 }
358
359 if (samples == 0)
360 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500361 context->handleError(InvalidValue() << "Samples may not be zero.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800362 return false;
363 }
364
365 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
366 if (!formatCaps.renderable)
367 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500368 context->handleError(InvalidEnum() << "SizedInternalformat must be color-renderable, "
369 "depth-renderable, or stencil-renderable.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800370 return false;
371 }
372
373 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
374 // is one of the unsized base internalformats listed in table 8.11.
Geoff Langca271392017-04-05 12:30:00 -0400375 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
376 if (formatInfo.internalFormat == GL_NONE)
JiangYizhoubddc46b2016-12-09 09:50:51 +0800377 {
378 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500379 InvalidEnum()
380 << "Internalformat is one of the unsupported unsized base internalformats.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800381 return false;
382 }
383
384 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
385 {
386 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500387 InvalidOperation()
388 << "Samples must not be greater than maximum supported value for the format.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800389 return false;
390 }
391
392 Texture *texture = context->getTargetTexture(target);
393 if (!texture || texture->id() == 0)
394 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500395 context->handleError(InvalidOperation() << "Zero is bound to target.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800396 return false;
397 }
398
399 if (texture->getImmutableFormat())
400 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500401 context->handleError(InvalidOperation() << "The value of TEXTURE_IMMUTABLE_FORMAT for "
402 "the texture currently bound to target on "
403 "the active texture unit is true.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800404 return false;
405 }
406
407 return true;
408}
409
410bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val)
411{
412 if (context->getClientVersion() < ES_3_1)
413 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500414 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800415 return false;
416 }
417
418 if (pname != GL_SAMPLE_POSITION)
419 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500420 context->handleError(InvalidEnum() << "Pname must be SAMPLE_POSITION.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800421 return false;
422 }
423
424 GLint maxSamples = context->getCaps().maxSamples;
425 if (index >= static_cast<GLuint>(maxSamples))
426 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500427 context->handleError(InvalidValue() << "Index must be less than the value of SAMPLES.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800428 return false;
429 }
430
431 return true;
432}
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800433
434bool ValidationFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param)
435{
436 if (context->getClientVersion() < ES_3_1)
437 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500438 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800439 return false;
440 }
441
442 if (!ValidFramebufferTarget(target))
443 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500444 context->handleError(InvalidEnum() << "Invalid framebuffer target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800445 return false;
446 }
447
448 switch (pname)
449 {
450 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
451 {
452 GLint maxWidth = context->getCaps().maxFramebufferWidth;
453 if (param < 0 || param > maxWidth)
454 {
455 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500456 InvalidValue()
457 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800458 return false;
459 }
460 break;
461 }
462 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
463 {
464 GLint maxHeight = context->getCaps().maxFramebufferHeight;
465 if (param < 0 || param > maxHeight)
466 {
467 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500468 InvalidValue()
469 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800470 return false;
471 }
472 break;
473 }
474 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
475 {
476 GLint maxSamples = context->getCaps().maxFramebufferSamples;
477 if (param < 0 || param > maxSamples)
478 {
479 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500480 InvalidValue()
481 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800482 return false;
483 }
484 break;
485 }
486 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
487 {
488 break;
489 }
490 default:
491 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500492 context->handleError(InvalidEnum()
493 << "Invalid pname: 0x" << std::hex << std::uppercase << pname);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800494 return false;
495 }
496 }
497
498 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
499 ASSERT(framebuffer);
500 if (framebuffer->id() == 0)
501 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500502 context->handleError(InvalidOperation() << "Default framebuffer is bound to target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800503 return false;
504 }
505 return true;
506}
507
508bool ValidationGetFramebufferParameteri(Context *context,
509 GLenum target,
510 GLenum pname,
511 GLint *params)
512{
513 if (context->getClientVersion() < ES_3_1)
514 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500515 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800516 return false;
517 }
518
519 if (!ValidFramebufferTarget(target))
520 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500521 context->handleError(InvalidEnum() << "Invalid framebuffer target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800522 return false;
523 }
524
525 switch (pname)
526 {
527 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
528 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
529 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
530 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
531 break;
532 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500533 context->handleError(InvalidEnum()
534 << "Invalid pname: 0x" << std::hex << std::uppercase << pname);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800535 return false;
536 }
537
538 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
539 ASSERT(framebuffer);
540
541 if (framebuffer->id() == 0)
542 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500543 context->handleError(InvalidOperation() << "Default framebuffer is bound to target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800544 return false;
545 }
546 return true;
547}
548
jchen1015015f72017-03-16 13:54:21 +0800549bool ValidateGetProgramResourceIndex(Context *context,
550 GLuint program,
551 GLenum programInterface,
552 const GLchar *name)
553{
554 if (context->getClientVersion() < ES_3_1)
555 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500556 context->handleError(InvalidOperation() << "Context does not support GLES 3.1.");
jchen1015015f72017-03-16 13:54:21 +0800557 return false;
558 }
559
560 Program *programObject = GetValidProgram(context, program);
561 if (programObject == nullptr)
562 {
563 return false;
564 }
565
566 if (!ValidateNamedProgramInterface(programInterface))
567 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500568 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
569 << std::uppercase << programInterface);
jchen1015015f72017-03-16 13:54:21 +0800570 return false;
571 }
Shao80957d92017-02-20 21:25:59 +0800572
573 return true;
574}
575
576bool ValidateBindVertexBuffer(ValidationContext *context,
577 GLuint bindingIndex,
578 GLuint buffer,
579 GLintptr offset,
580 GLsizei stride)
581{
582 if (context->getClientVersion() < ES_3_1)
583 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500584 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Shao80957d92017-02-20 21:25:59 +0800585 return false;
586 }
587
588 if (!context->isBufferGenerated(buffer))
589 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500590 context->handleError(InvalidOperation() << "Buffer is not generated.");
Shao80957d92017-02-20 21:25:59 +0800591 return false;
592 }
593
594 const Caps &caps = context->getCaps();
595 if (bindingIndex >= caps.maxVertexAttribBindings)
596 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500597 context->handleError(InvalidValue()
598 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS.");
Shao80957d92017-02-20 21:25:59 +0800599 return false;
600 }
601
602 if (offset < 0)
603 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500604 context->handleError(InvalidValue() << "offset cannot be negative.");
Shao80957d92017-02-20 21:25:59 +0800605 return false;
606 }
607
608 if (stride < 0 || stride > caps.maxVertexAttribStride)
609 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500610 context->handleError(InvalidValue()
611 << "stride must be between 0 and MAX_VERTEX_ATTRIB_STRIDE.");
Shao80957d92017-02-20 21:25:59 +0800612 return false;
613 }
614
615 // [OpenGL ES 3.1] Section 10.3.1 page 244:
616 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
617 if (context->getGLState().getVertexArrayId() == 0)
618 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500619 context->handleError(InvalidOperation() << "Default vertex array buffer is bound.");
Shao80957d92017-02-20 21:25:59 +0800620 return false;
621 }
622
623 return true;
624}
625
626bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor)
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.");
Shao80957d92017-02-20 21:25:59 +0800631 return false;
632 }
633
634 const Caps &caps = context->getCaps();
635 if (bindingIndex >= caps.maxVertexAttribBindings)
636 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500637 context->handleError(InvalidValue()
638 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS.");
Shao80957d92017-02-20 21:25:59 +0800639 return false;
640 }
641
642 // [OpenGL ES 3.1] Section 10.3.1 page 243:
643 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
644 if (context->getGLState().getVertexArrayId() == 0)
645 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500646 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800647 return false;
648 }
649
650 return true;
651}
652
653bool ValidateVertexAttribFormat(ValidationContext *context,
654 GLuint attribIndex,
655 GLint size,
656 GLenum type,
657 GLuint relativeOffset,
658 GLboolean pureInteger)
659{
660 if (context->getClientVersion() < ES_3_1)
661 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500662 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Shao80957d92017-02-20 21:25:59 +0800663 return false;
664 }
665
666 const Caps &caps = context->getCaps();
667 if (relativeOffset > static_cast<GLuint>(caps.maxVertexAttribRelativeOffset))
668 {
669 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500670 InvalidValue()
671 << "relativeOffset cannot be greater than MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.");
Shao80957d92017-02-20 21:25:59 +0800672 return false;
673 }
674
675 // [OpenGL ES 3.1] Section 10.3.1 page 243:
676 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
677 if (context->getGLState().getVertexArrayId() == 0)
678 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500679 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800680 return false;
681 }
682
683 return ValidateVertexFormatBase(context, attribIndex, size, type, pureInteger);
684}
685
686bool ValidateVertexAttribBinding(ValidationContext *context,
687 GLuint attribIndex,
688 GLuint bindingIndex)
689{
690 if (context->getClientVersion() < ES_3_1)
691 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500692 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Shao80957d92017-02-20 21:25:59 +0800693 return false;
694 }
695
696 // [OpenGL ES 3.1] Section 10.3.1 page 243:
697 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
698 if (context->getGLState().getVertexArrayId() == 0)
699 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500700 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800701 return false;
702 }
703
704 const Caps &caps = context->getCaps();
705 if (attribIndex >= caps.maxVertexAttributes)
706 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500707 context->handleError(InvalidValue()
708 << "attribindex must be smaller than MAX_VERTEX_ATTRIBS.");
Shao80957d92017-02-20 21:25:59 +0800709 return false;
710 }
711
712 if (bindingIndex >= caps.maxVertexAttribBindings)
713 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500714 context->handleError(InvalidValue()
715 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS");
Shao80957d92017-02-20 21:25:59 +0800716 return false;
717 }
718
jchen1015015f72017-03-16 13:54:21 +0800719 return true;
720}
721
jchen10fd7c3b52017-03-21 15:36:03 +0800722bool ValidateGetProgramResourceName(Context *context,
723 GLuint program,
724 GLenum programInterface,
725 GLuint index,
726 GLsizei bufSize,
727 GLsizei *length,
728 GLchar *name)
729{
730 if (context->getClientVersion() < ES_3_1)
731 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500732 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
jchen10fd7c3b52017-03-21 15:36:03 +0800733 return false;
734 }
735
736 Program *programObject = GetValidProgram(context, program);
737 if (programObject == nullptr)
738 {
739 return false;
740 }
741
742 if (!ValidateNamedProgramInterface(programInterface))
743 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500744 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
745 << std::uppercase << programInterface);
jchen10fd7c3b52017-03-21 15:36:03 +0800746 return false;
747 }
748
749 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
750 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500751 context->handleError(InvalidValue() << "Invalid index: " << index);
jchen10fd7c3b52017-03-21 15:36:03 +0800752 return false;
753 }
754
755 if (bufSize < 0)
756 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500757 context->handleError(InvalidValue() << "Invalid bufSize: " << bufSize);
jchen10fd7c3b52017-03-21 15:36:03 +0800758 return false;
759 }
760
761 return true;
762}
763
Xinghua Cao2b396592017-03-29 15:36:04 +0800764bool ValidateDispatchCompute(Context *context,
765 GLuint numGroupsX,
766 GLuint numGroupsY,
767 GLuint numGroupsZ)
768{
769 if (context->getClientVersion() < ES_3_1)
770 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500771 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800772 return false;
773 }
774
775 const State &state = context->getGLState();
776 Program *program = state.getProgram();
777
778 if (program == nullptr)
779 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500780 context->handleError(InvalidOperation()
781 << "No active program object for the compute shader stage.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800782 return false;
783 }
784
785 if (program->isLinked() == false || program->getAttachedComputeShader() == nullptr)
786 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500787 context->handleError(
788 InvalidOperation()
789 << "Program has not been successfully linked, or program contains no compute shaders.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800790 return false;
791 }
792
793 const Caps &caps = context->getCaps();
794 if (numGroupsX > caps.maxComputeWorkGroupCount[0])
795 {
796 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500797 InvalidValue() << "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]="
798 << caps.maxComputeWorkGroupCount[0]);
Xinghua Cao2b396592017-03-29 15:36:04 +0800799 return false;
800 }
801 if (numGroupsY > caps.maxComputeWorkGroupCount[1])
802 {
803 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500804 InvalidValue() << "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]="
805 << caps.maxComputeWorkGroupCount[1]);
Xinghua Cao2b396592017-03-29 15:36:04 +0800806 return false;
807 }
808 if (numGroupsZ > caps.maxComputeWorkGroupCount[2])
809 {
810 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500811 InvalidValue() << "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2]="
812 << caps.maxComputeWorkGroupCount[2]);
Xinghua Cao2b396592017-03-29 15:36:04 +0800813 return false;
814 }
815
816 return true;
817}
818
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800819bool ValidateBindImageTexture(Context *context,
820 GLuint unit,
821 GLuint texture,
822 GLint level,
823 GLboolean layered,
824 GLint layer,
825 GLenum access,
826 GLenum format)
827{
828 GLuint maxImageUnits = context->getCaps().maxImageUnits;
829 if (unit >= maxImageUnits)
830 {
831 context->handleError(InvalidValue()
832 << "unit cannot be greater than or equal than MAX_IMAGE_UNITS = "
833 << maxImageUnits);
834 return false;
835 }
836
837 if (level < 0)
838 {
839 context->handleError(InvalidValue() << "level is negative.");
840 return false;
841 }
842
843 if (layer < 0)
844 {
845 context->handleError(InvalidValue() << "layer is negative.");
846 return false;
847 }
848
849 if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE)
850 {
851 context->handleError(InvalidEnum() << "access is not one of the supported tokens.");
852 return false;
853 }
854
855 switch (format)
856 {
857 case GL_RGBA32F:
858 case GL_RGBA16F:
859 case GL_R32F:
860 case GL_RGBA32UI:
861 case GL_RGBA16UI:
862 case GL_RGBA8UI:
863 case GL_R32UI:
864 case GL_RGBA32I:
865 case GL_RGBA16I:
866 case GL_RGBA8I:
867 case GL_R32I:
868 case GL_RGBA8:
869 case GL_RGBA8_SNORM:
870 break;
871 default:
872 context->handleError(InvalidValue()
873 << "format is not one of supported image unit formats.");
874 return false;
875 }
876
877 if (texture != 0)
878 {
879 Texture *tex = context->getTexture(texture);
880
881 if (tex == nullptr)
882 {
883 context->handleError(InvalidValue()
884 << "texture is not the name of an existing texture object.");
885 return false;
886 }
887
888 if (!tex->getImmutableFormat())
889 {
890 context->handleError(InvalidOperation()
891 << "texture is not the name of an immutable texture object.");
892 return false;
893 }
894 }
895
896 return true;
897}
Martin Radev66fb8202016-07-28 11:45:20 +0300898} // namespace gl