blob: 4856d852da453a3006f801ff740af7deb1007fc0 [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
jchen10fd7c3b52017-03-21 15:36:03 +080057bool ValidateProgramResourceIndex(const Program *programObject,
58 GLenum programInterface,
59 GLuint index)
60{
61 switch (programInterface)
62 {
63 case GL_PROGRAM_INPUT:
64 return (index < static_cast<GLuint>(programObject->getActiveAttributeCount()));
65
66 case GL_PROGRAM_OUTPUT:
67 return (index < static_cast<GLuint>(programObject->getOutputResourceCount()));
68
69 // TODO(Jie): more interfaces.
70 case GL_UNIFORM:
71 case GL_UNIFORM_BLOCK:
72 case GL_TRANSFORM_FEEDBACK_VARYING:
73 case GL_BUFFER_VARIABLE:
74 case GL_SHADER_STORAGE_BLOCK:
75 UNIMPLEMENTED();
76 return false;
77
78 default:
79 UNREACHABLE();
80 return false;
81 }
82}
83
jchen1015015f72017-03-16 13:54:21 +080084} // anonymous namespace
85
Martin Radev66fb8202016-07-28 11:45:20 +030086bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data)
87{
Geoff Langeb66a6e2016-10-31 13:06:12 -040088 if (context->getClientVersion() < ES_3_1)
Martin Radev66fb8202016-07-28 11:45:20 +030089 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -050090 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Martin Radev66fb8202016-07-28 11:45:20 +030091 return false;
92 }
93
Geoff Lang2e43dbb2016-10-14 12:27:35 -040094 if (!ValidateIndexedStateQuery(context, target, index, nullptr))
95 {
96 return false;
97 }
98
99 return true;
100}
101
102bool ValidateGetBooleani_vRobustANGLE(Context *context,
103 GLenum target,
104 GLuint index,
105 GLsizei bufSize,
106 GLsizei *length,
107 GLboolean *data)
108{
Geoff Langeb66a6e2016-10-31 13:06:12 -0400109 if (context->getClientVersion() < ES_3_1)
Geoff Lang2e43dbb2016-10-14 12:27:35 -0400110 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500111 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Geoff Lang2e43dbb2016-10-14 12:27:35 -0400112 return false;
113 }
114
115 if (!ValidateRobustEntryPoint(context, bufSize))
116 {
117 return false;
118 }
119
120 if (!ValidateIndexedStateQuery(context, target, index, length))
121 {
122 return false;
123 }
124
125 if (!ValidateRobustBufferSize(context, bufSize, *length))
Martin Radev66fb8202016-07-28 11:45:20 +0300126 {
127 return false;
128 }
129
130 return true;
131}
132
Jamie Madill876429b2017-04-20 15:46:24 -0400133bool ValidateDrawIndirectBase(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800134{
135 if (context->getClientVersion() < ES_3_1)
136 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500137 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
Jiajia Qind9671222016-11-29 16:30:31 +0800138 return false;
139 }
140
141 // Here the third parameter 1 is only to pass the count validation.
142 if (!ValidateDrawBase(context, mode, 1))
143 {
144 return false;
145 }
146
147 const State &state = context->getGLState();
148
149 // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING,
150 // DRAW_INDIRECT_BUFFER or to any enabled vertex array.
151 if (!state.getVertexArrayId())
152 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500153 context->handleError(InvalidOperation() << "zero is bound to VERTEX_ARRAY_BINDING");
Jiajia Qind9671222016-11-29 16:30:31 +0800154 return false;
155 }
156
157 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
158 if (!drawIndirectBuffer)
159 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500160 context->handleError(InvalidOperation() << "zero is bound to DRAW_INDIRECT_BUFFER");
Jiajia Qind9671222016-11-29 16:30:31 +0800161 return false;
162 }
163
164 // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic
165 // machine units, of uint.
166 GLint64 offset = reinterpret_cast<GLint64>(indirect);
167 if ((static_cast<GLuint>(offset) % sizeof(GLuint)) != 0)
168 {
169 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500170 InvalidValue()
171 << "indirect is not a multiple of the size, in basic machine units, of uint");
Jiajia Qind9671222016-11-29 16:30:31 +0800172 return false;
173 }
174
175 return true;
176}
177
Jamie Madill876429b2017-04-20 15:46:24 -0400178bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800179{
180 const State &state = context->getGLState();
181 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
182 if (curTransformFeedback && curTransformFeedback->isActive() &&
183 !curTransformFeedback->isPaused())
184 {
185 // An INVALID_OPERATION error is generated if transform feedback is active and not paused.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500186 context->handleError(InvalidOperation() << "transform feedback is active and not paused.");
Jiajia Qind9671222016-11-29 16:30:31 +0800187 return false;
188 }
189
190 if (!ValidateDrawIndirectBase(context, mode, indirect))
191 return false;
192
193 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
194 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
195 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand
196 // which's size is 4 * sizeof(uint).
197 auto checkedSum = checkedOffset + 4 * sizeof(GLuint);
198 if (!checkedSum.IsValid() ||
199 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
200 {
201 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500202 InvalidOperation()
203 << "the command would source data beyond the end of the buffer object.");
Jiajia Qind9671222016-11-29 16:30:31 +0800204 return false;
205 }
206
207 return true;
208}
209
Jamie Madill876429b2017-04-20 15:46:24 -0400210bool ValidateDrawElementsIndirect(Context *context, GLenum mode, GLenum type, const void *indirect)
Jiajia Qind9671222016-11-29 16:30:31 +0800211{
212 if (!ValidateDrawElementsBase(context, type))
213 return false;
214
215 const State &state = context->getGLState();
216 const VertexArray *vao = state.getVertexArray();
217 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
218 if (!elementArrayBuffer)
219 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500220 context->handleError(InvalidOperation() << "zero is bound to ELEMENT_ARRAY_BUFFER");
Jiajia Qind9671222016-11-29 16:30:31 +0800221 return false;
222 }
223
224 if (!ValidateDrawIndirectBase(context, mode, indirect))
225 return false;
226
227 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
228 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
229 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand
230 // which's size is 5 * sizeof(uint).
231 auto checkedSum = checkedOffset + 5 * sizeof(GLuint);
232 if (!checkedSum.IsValid() ||
233 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
234 {
235 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500236 InvalidOperation()
237 << "the command would source data beyond the end of the buffer object.");
Jiajia Qind9671222016-11-29 16:30:31 +0800238 return false;
239 }
240
241 return true;
242}
243
He Yunchao11b038b2016-11-22 21:24:04 +0800244bool ValidateGetTexLevelParameterBase(Context *context,
245 GLenum target,
246 GLint level,
247 GLenum pname,
248 GLsizei *length)
249{
250 if (context->getClientVersion() < ES_3_1)
251 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500252 context->handleError(InvalidOperation() << "Context does not support GLES3.1");
He Yunchao11b038b2016-11-22 21:24:04 +0800253 return false;
254 }
255
256 if (length)
257 {
258 *length = 0;
259 }
260
261 if (!ValidTexLevelDestinationTarget(context, target))
262 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500263 context->handleError(InvalidEnum() << "Invalid texture target");
He Yunchao11b038b2016-11-22 21:24:04 +0800264 return false;
265 }
266
267 if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) ==
268 nullptr)
269 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500270 context->handleError(InvalidEnum() << "No texture bound.");
He Yunchao11b038b2016-11-22 21:24:04 +0800271 return false;
272 }
273
274 if (!ValidMipLevel(context, target, level))
275 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500276 context->handleError(InvalidValue());
He Yunchao11b038b2016-11-22 21:24:04 +0800277 return false;
278 }
279
280 switch (pname)
281 {
282 case GL_TEXTURE_RED_TYPE:
283 case GL_TEXTURE_GREEN_TYPE:
284 case GL_TEXTURE_BLUE_TYPE:
285 case GL_TEXTURE_ALPHA_TYPE:
286 case GL_TEXTURE_DEPTH_TYPE:
287 break;
288 case GL_TEXTURE_RED_SIZE:
289 case GL_TEXTURE_GREEN_SIZE:
290 case GL_TEXTURE_BLUE_SIZE:
291 case GL_TEXTURE_ALPHA_SIZE:
292 case GL_TEXTURE_DEPTH_SIZE:
293 case GL_TEXTURE_STENCIL_SIZE:
294 case GL_TEXTURE_SHARED_SIZE:
295 break;
296 case GL_TEXTURE_INTERNAL_FORMAT:
297 case GL_TEXTURE_WIDTH:
298 case GL_TEXTURE_HEIGHT:
299 case GL_TEXTURE_DEPTH:
300 break;
301 case GL_TEXTURE_SAMPLES:
302 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
303 break;
304 case GL_TEXTURE_COMPRESSED:
305 break;
306 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500307 context->handleError(InvalidEnum() << "Unknown pname.");
He Yunchao11b038b2016-11-22 21:24:04 +0800308 return false;
309 }
310
311 if (length)
312 {
313 *length = 1;
314 }
315 return true;
316}
317
318bool ValidateGetTexLevelParameterfv(Context *context,
319 GLenum target,
320 GLint level,
321 GLenum pname,
322 GLfloat *params)
323{
324 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
325}
326
327bool ValidateGetTexLevelParameteriv(Context *context,
328 GLenum target,
329 GLint level,
330 GLenum pname,
331 GLint *params)
332{
333 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
334}
335
JiangYizhoubddc46b2016-12-09 09:50:51 +0800336bool ValidateTexStorage2DMultiSample(Context *context,
337 GLenum target,
338 GLsizei samples,
339 GLint internalFormat,
340 GLsizei width,
341 GLsizei height,
342 GLboolean fixedSampleLocations)
343{
344 if (context->getClientVersion() < ES_3_1)
345 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500346 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800347 return false;
348 }
349
350 if (target != GL_TEXTURE_2D_MULTISAMPLE)
351 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500352 context->handleError(InvalidEnum() << "Target must be TEXTURE_2D_MULTISAMPLE.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800353 return false;
354 }
355
356 if (width < 1 || height < 1)
357 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500358 context->handleError(InvalidValue() << "Width and height must be positive.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800359 return false;
360 }
361
362 const Caps &caps = context->getCaps();
363 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
364 static_cast<GLuint>(height) > caps.max2DTextureSize)
365 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500366 context
367 ->handleError(InvalidValue()
368 << "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800369 return false;
370 }
371
372 if (samples == 0)
373 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500374 context->handleError(InvalidValue() << "Samples may not be zero.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800375 return false;
376 }
377
378 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
379 if (!formatCaps.renderable)
380 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500381 context->handleError(InvalidEnum() << "SizedInternalformat must be color-renderable, "
382 "depth-renderable, or stencil-renderable.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800383 return false;
384 }
385
386 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
387 // is one of the unsized base internalformats listed in table 8.11.
Geoff Langca271392017-04-05 12:30:00 -0400388 const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalFormat);
389 if (formatInfo.internalFormat == GL_NONE)
JiangYizhoubddc46b2016-12-09 09:50:51 +0800390 {
391 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500392 InvalidEnum()
393 << "Internalformat is one of the unsupported unsized base internalformats.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800394 return false;
395 }
396
397 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
398 {
399 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500400 InvalidOperation()
401 << "Samples must not be greater than maximum supported value for the format.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800402 return false;
403 }
404
405 Texture *texture = context->getTargetTexture(target);
406 if (!texture || texture->id() == 0)
407 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500408 context->handleError(InvalidOperation() << "Zero is bound to target.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800409 return false;
410 }
411
412 if (texture->getImmutableFormat())
413 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500414 context->handleError(InvalidOperation() << "The value of TEXTURE_IMMUTABLE_FORMAT for "
415 "the texture currently bound to target on "
416 "the active texture unit is true.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800417 return false;
418 }
419
420 return true;
421}
422
423bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val)
424{
425 if (context->getClientVersion() < ES_3_1)
426 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500427 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800428 return false;
429 }
430
431 if (pname != GL_SAMPLE_POSITION)
432 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500433 context->handleError(InvalidEnum() << "Pname must be SAMPLE_POSITION.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800434 return false;
435 }
436
437 GLint maxSamples = context->getCaps().maxSamples;
438 if (index >= static_cast<GLuint>(maxSamples))
439 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500440 context->handleError(InvalidValue() << "Index must be less than the value of SAMPLES.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800441 return false;
442 }
443
444 return true;
445}
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800446
447bool ValidationFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param)
448{
449 if (context->getClientVersion() < ES_3_1)
450 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500451 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800452 return false;
453 }
454
455 if (!ValidFramebufferTarget(target))
456 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500457 context->handleError(InvalidEnum() << "Invalid framebuffer target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800458 return false;
459 }
460
461 switch (pname)
462 {
463 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
464 {
465 GLint maxWidth = context->getCaps().maxFramebufferWidth;
466 if (param < 0 || param > maxWidth)
467 {
468 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500469 InvalidValue()
470 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800471 return false;
472 }
473 break;
474 }
475 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
476 {
477 GLint maxHeight = context->getCaps().maxFramebufferHeight;
478 if (param < 0 || param > maxHeight)
479 {
480 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500481 InvalidValue()
482 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800483 return false;
484 }
485 break;
486 }
487 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
488 {
489 GLint maxSamples = context->getCaps().maxFramebufferSamples;
490 if (param < 0 || param > maxSamples)
491 {
492 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500493 InvalidValue()
494 << "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800495 return false;
496 }
497 break;
498 }
499 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
500 {
501 break;
502 }
503 default:
504 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500505 context->handleError(InvalidEnum()
506 << "Invalid pname: 0x" << std::hex << std::uppercase << pname);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800507 return false;
508 }
509 }
510
511 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
512 ASSERT(framebuffer);
513 if (framebuffer->id() == 0)
514 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500515 context->handleError(InvalidOperation() << "Default framebuffer is bound to target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800516 return false;
517 }
518 return true;
519}
520
521bool ValidationGetFramebufferParameteri(Context *context,
522 GLenum target,
523 GLenum pname,
524 GLint *params)
525{
526 if (context->getClientVersion() < ES_3_1)
527 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500528 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800529 return false;
530 }
531
532 if (!ValidFramebufferTarget(target))
533 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500534 context->handleError(InvalidEnum() << "Invalid framebuffer target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800535 return false;
536 }
537
538 switch (pname)
539 {
540 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
541 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
542 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
543 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
544 break;
545 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500546 context->handleError(InvalidEnum()
547 << "Invalid pname: 0x" << std::hex << std::uppercase << pname);
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800548 return false;
549 }
550
551 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
552 ASSERT(framebuffer);
553
554 if (framebuffer->id() == 0)
555 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500556 context->handleError(InvalidOperation() << "Default framebuffer is bound to target.");
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800557 return false;
558 }
559 return true;
560}
561
jchen1015015f72017-03-16 13:54:21 +0800562bool ValidateGetProgramResourceIndex(Context *context,
563 GLuint program,
564 GLenum programInterface,
565 const GLchar *name)
566{
567 if (context->getClientVersion() < ES_3_1)
568 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500569 context->handleError(InvalidOperation() << "Context does not support GLES 3.1.");
jchen1015015f72017-03-16 13:54:21 +0800570 return false;
571 }
572
573 Program *programObject = GetValidProgram(context, program);
574 if (programObject == nullptr)
575 {
576 return false;
577 }
578
579 if (!ValidateNamedProgramInterface(programInterface))
580 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500581 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
582 << std::uppercase << programInterface);
jchen1015015f72017-03-16 13:54:21 +0800583 return false;
584 }
Shao80957d92017-02-20 21:25:59 +0800585
586 return true;
587}
588
589bool ValidateBindVertexBuffer(ValidationContext *context,
590 GLuint bindingIndex,
591 GLuint buffer,
592 GLintptr offset,
593 GLsizei stride)
594{
595 if (context->getClientVersion() < ES_3_1)
596 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500597 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Shao80957d92017-02-20 21:25:59 +0800598 return false;
599 }
600
601 if (!context->isBufferGenerated(buffer))
602 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500603 context->handleError(InvalidOperation() << "Buffer is not generated.");
Shao80957d92017-02-20 21:25:59 +0800604 return false;
605 }
606
607 const Caps &caps = context->getCaps();
608 if (bindingIndex >= caps.maxVertexAttribBindings)
609 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500610 context->handleError(InvalidValue()
611 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS.");
Shao80957d92017-02-20 21:25:59 +0800612 return false;
613 }
614
615 if (offset < 0)
616 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500617 context->handleError(InvalidValue() << "offset cannot be negative.");
Shao80957d92017-02-20 21:25:59 +0800618 return false;
619 }
620
621 if (stride < 0 || stride > caps.maxVertexAttribStride)
622 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500623 context->handleError(InvalidValue()
624 << "stride must be between 0 and MAX_VERTEX_ATTRIB_STRIDE.");
Shao80957d92017-02-20 21:25:59 +0800625 return false;
626 }
627
628 // [OpenGL ES 3.1] Section 10.3.1 page 244:
629 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
630 if (context->getGLState().getVertexArrayId() == 0)
631 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500632 context->handleError(InvalidOperation() << "Default vertex array buffer is bound.");
Shao80957d92017-02-20 21:25:59 +0800633 return false;
634 }
635
636 return true;
637}
638
639bool ValidateVertexBindingDivisor(ValidationContext *context, GLuint bindingIndex, GLuint divisor)
640{
641 if (context->getClientVersion() < ES_3_1)
642 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500643 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Shao80957d92017-02-20 21:25:59 +0800644 return false;
645 }
646
647 const Caps &caps = context->getCaps();
648 if (bindingIndex >= caps.maxVertexAttribBindings)
649 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500650 context->handleError(InvalidValue()
651 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS.");
Shao80957d92017-02-20 21:25:59 +0800652 return false;
653 }
654
655 // [OpenGL ES 3.1] Section 10.3.1 page 243:
656 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
657 if (context->getGLState().getVertexArrayId() == 0)
658 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500659 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800660 return false;
661 }
662
663 return true;
664}
665
666bool ValidateVertexAttribFormat(ValidationContext *context,
667 GLuint attribIndex,
668 GLint size,
669 GLenum type,
670 GLuint relativeOffset,
671 GLboolean pureInteger)
672{
673 if (context->getClientVersion() < ES_3_1)
674 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500675 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Shao80957d92017-02-20 21:25:59 +0800676 return false;
677 }
678
679 const Caps &caps = context->getCaps();
680 if (relativeOffset > static_cast<GLuint>(caps.maxVertexAttribRelativeOffset))
681 {
682 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500683 InvalidValue()
684 << "relativeOffset cannot be greater than MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.");
Shao80957d92017-02-20 21:25:59 +0800685 return false;
686 }
687
688 // [OpenGL ES 3.1] Section 10.3.1 page 243:
689 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
690 if (context->getGLState().getVertexArrayId() == 0)
691 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500692 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800693 return false;
694 }
695
696 return ValidateVertexFormatBase(context, attribIndex, size, type, pureInteger);
697}
698
699bool ValidateVertexAttribBinding(ValidationContext *context,
700 GLuint attribIndex,
701 GLuint bindingIndex)
702{
703 if (context->getClientVersion() < ES_3_1)
704 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500705 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Shao80957d92017-02-20 21:25:59 +0800706 return false;
707 }
708
709 // [OpenGL ES 3.1] Section 10.3.1 page 243:
710 // An INVALID_OPERATION error is generated if the default vertex array object is bound.
711 if (context->getGLState().getVertexArrayId() == 0)
712 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500713 context->handleError(InvalidOperation() << "Default vertex array object is bound.");
Shao80957d92017-02-20 21:25:59 +0800714 return false;
715 }
716
717 const Caps &caps = context->getCaps();
718 if (attribIndex >= caps.maxVertexAttributes)
719 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500720 context->handleError(InvalidValue()
721 << "attribindex must be smaller than MAX_VERTEX_ATTRIBS.");
Shao80957d92017-02-20 21:25:59 +0800722 return false;
723 }
724
725 if (bindingIndex >= caps.maxVertexAttribBindings)
726 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500727 context->handleError(InvalidValue()
728 << "bindingindex must be smaller than MAX_VERTEX_ATTRIB_BINDINGS");
Shao80957d92017-02-20 21:25:59 +0800729 return false;
730 }
731
jchen1015015f72017-03-16 13:54:21 +0800732 return true;
733}
734
jchen10fd7c3b52017-03-21 15:36:03 +0800735bool ValidateGetProgramResourceName(Context *context,
736 GLuint program,
737 GLenum programInterface,
738 GLuint index,
739 GLsizei bufSize,
740 GLsizei *length,
741 GLchar *name)
742{
743 if (context->getClientVersion() < ES_3_1)
744 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500745 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
jchen10fd7c3b52017-03-21 15:36:03 +0800746 return false;
747 }
748
749 Program *programObject = GetValidProgram(context, program);
750 if (programObject == nullptr)
751 {
752 return false;
753 }
754
755 if (!ValidateNamedProgramInterface(programInterface))
756 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500757 context->handleError(InvalidEnum() << "Invalid program interface: 0x" << std::hex
758 << std::uppercase << programInterface);
jchen10fd7c3b52017-03-21 15:36:03 +0800759 return false;
760 }
761
762 if (!ValidateProgramResourceIndex(programObject, programInterface, index))
763 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500764 context->handleError(InvalidValue() << "Invalid index: " << index);
jchen10fd7c3b52017-03-21 15:36:03 +0800765 return false;
766 }
767
768 if (bufSize < 0)
769 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500770 context->handleError(InvalidValue() << "Invalid bufSize: " << bufSize);
jchen10fd7c3b52017-03-21 15:36:03 +0800771 return false;
772 }
773
774 return true;
775}
776
Xinghua Cao2b396592017-03-29 15:36:04 +0800777bool ValidateDispatchCompute(Context *context,
778 GLuint numGroupsX,
779 GLuint numGroupsY,
780 GLuint numGroupsZ)
781{
782 if (context->getClientVersion() < ES_3_1)
783 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500784 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800785 return false;
786 }
787
788 const State &state = context->getGLState();
789 Program *program = state.getProgram();
790
791 if (program == nullptr)
792 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500793 context->handleError(InvalidOperation()
794 << "No active program object for the compute shader stage.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800795 return false;
796 }
797
798 if (program->isLinked() == false || program->getAttachedComputeShader() == nullptr)
799 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500800 context->handleError(
801 InvalidOperation()
802 << "Program has not been successfully linked, or program contains no compute shaders.");
Xinghua Cao2b396592017-03-29 15:36:04 +0800803 return false;
804 }
805
806 const Caps &caps = context->getCaps();
807 if (numGroupsX > caps.maxComputeWorkGroupCount[0])
808 {
809 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500810 InvalidValue() << "num_groups_x cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[0]="
811 << caps.maxComputeWorkGroupCount[0]);
Xinghua Cao2b396592017-03-29 15:36:04 +0800812 return false;
813 }
814 if (numGroupsY > caps.maxComputeWorkGroupCount[1])
815 {
816 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500817 InvalidValue() << "num_groups_y cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[1]="
818 << caps.maxComputeWorkGroupCount[1]);
Xinghua Cao2b396592017-03-29 15:36:04 +0800819 return false;
820 }
821 if (numGroupsZ > caps.maxComputeWorkGroupCount[2])
822 {
823 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500824 InvalidValue() << "num_groups_z cannot be greater than MAX_COMPUTE_WORK_GROUP_COUNT[2]="
825 << caps.maxComputeWorkGroupCount[2]);
Xinghua Cao2b396592017-03-29 15:36:04 +0800826 return false;
827 }
828
829 return true;
830}
831
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800832bool ValidateBindImageTexture(Context *context,
833 GLuint unit,
834 GLuint texture,
835 GLint level,
836 GLboolean layered,
837 GLint layer,
838 GLenum access,
839 GLenum format)
840{
841 GLuint maxImageUnits = context->getCaps().maxImageUnits;
842 if (unit >= maxImageUnits)
843 {
844 context->handleError(InvalidValue()
845 << "unit cannot be greater than or equal than MAX_IMAGE_UNITS = "
846 << maxImageUnits);
847 return false;
848 }
849
850 if (level < 0)
851 {
852 context->handleError(InvalidValue() << "level is negative.");
853 return false;
854 }
855
856 if (layer < 0)
857 {
858 context->handleError(InvalidValue() << "layer is negative.");
859 return false;
860 }
861
862 if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE)
863 {
864 context->handleError(InvalidEnum() << "access is not one of the supported tokens.");
865 return false;
866 }
867
868 switch (format)
869 {
870 case GL_RGBA32F:
871 case GL_RGBA16F:
872 case GL_R32F:
873 case GL_RGBA32UI:
874 case GL_RGBA16UI:
875 case GL_RGBA8UI:
876 case GL_R32UI:
877 case GL_RGBA32I:
878 case GL_RGBA16I:
879 case GL_RGBA8I:
880 case GL_R32I:
881 case GL_RGBA8:
882 case GL_RGBA8_SNORM:
883 break;
884 default:
885 context->handleError(InvalidValue()
886 << "format is not one of supported image unit formats.");
887 return false;
888 }
889
890 if (texture != 0)
891 {
892 Texture *tex = context->getTexture(texture);
893
894 if (tex == nullptr)
895 {
896 context->handleError(InvalidValue()
897 << "texture is not the name of an existing texture object.");
898 return false;
899 }
900
901 if (!tex->getImmutableFormat())
902 {
903 context->handleError(InvalidOperation()
904 << "texture is not the name of an immutable texture object.");
905 return false;
906 }
907 }
908
909 return true;
910}
jchen10191381f2017-04-11 13:59:04 +0800911
912bool ValidateGetProgramResourceLocation(Context *context,
913 GLuint program,
914 GLenum programInterface,
915 const GLchar *name)
916{
917 if (context->getClientVersion() < ES_3_1)
918 {
919 context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
920 return false;
921 }
922
923 Program *programObject = GetValidProgram(context, program);
924 if (programObject == nullptr)
925 {
926 return false;
927 }
928
929 if (!programObject->isLinked())
930 {
931 context->handleError(InvalidOperation() << "Program is not successfully linked.");
932 return false;
933 }
934
935 if (!ValidateLocationProgramInterface(programInterface))
936 {
937 context->handleError(InvalidEnum() << "Invalid program interface.");
938 return false;
939 }
940 return true;
941}
942
Martin Radev66fb8202016-07-28 11:45:20 +0300943} // namespace gl