blob: aec2adef7b309d6e779698d911ea50baf33fd802 [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"
Geoff Lang2e43dbb2016-10-14 12:27:35 -040013#include "libANGLE/validationES.h"
14#include "libANGLE/validationES3.h"
Jiajia Qind9671222016-11-29 16:30:31 +080015#include "libANGLE/VertexArray.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
44} // anonymous namespace
45
Martin Radev66fb8202016-07-28 11:45:20 +030046bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data)
47{
Geoff Langeb66a6e2016-10-31 13:06:12 -040048 if (context->getClientVersion() < ES_3_1)
Martin Radev66fb8202016-07-28 11:45:20 +030049 {
50 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
51 return false;
52 }
53
Geoff Lang2e43dbb2016-10-14 12:27:35 -040054 if (!ValidateIndexedStateQuery(context, target, index, nullptr))
55 {
56 return false;
57 }
58
59 return true;
60}
61
62bool ValidateGetBooleani_vRobustANGLE(Context *context,
63 GLenum target,
64 GLuint index,
65 GLsizei bufSize,
66 GLsizei *length,
67 GLboolean *data)
68{
Geoff Langeb66a6e2016-10-31 13:06:12 -040069 if (context->getClientVersion() < ES_3_1)
Geoff Lang2e43dbb2016-10-14 12:27:35 -040070 {
71 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
72 return false;
73 }
74
75 if (!ValidateRobustEntryPoint(context, bufSize))
76 {
77 return false;
78 }
79
80 if (!ValidateIndexedStateQuery(context, target, index, length))
81 {
82 return false;
83 }
84
85 if (!ValidateRobustBufferSize(context, bufSize, *length))
Martin Radev66fb8202016-07-28 11:45:20 +030086 {
87 return false;
88 }
89
90 return true;
91}
92
Jiajia Qind9671222016-11-29 16:30:31 +080093bool ValidateDrawIndirectBase(Context *context, GLenum mode, const GLvoid *indirect)
94{
95 if (context->getClientVersion() < ES_3_1)
96 {
97 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
98 return false;
99 }
100
101 // Here the third parameter 1 is only to pass the count validation.
102 if (!ValidateDrawBase(context, mode, 1))
103 {
104 return false;
105 }
106
107 const State &state = context->getGLState();
108
109 // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING,
110 // DRAW_INDIRECT_BUFFER or to any enabled vertex array.
111 if (!state.getVertexArrayId())
112 {
113 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to VERTEX_ARRAY_BINDING"));
114 return false;
115 }
116
117 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
118 if (!drawIndirectBuffer)
119 {
120 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to DRAW_INDIRECT_BUFFER"));
121 return false;
122 }
123
124 // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic
125 // machine units, of uint.
126 GLint64 offset = reinterpret_cast<GLint64>(indirect);
127 if ((static_cast<GLuint>(offset) % sizeof(GLuint)) != 0)
128 {
129 context->handleError(
130 Error(GL_INVALID_VALUE,
131 "indirect is not a multiple of the size, in basic machine units, of uint"));
132 return false;
133 }
134
135 return true;
136}
137
138bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const GLvoid *indirect)
139{
140 const State &state = context->getGLState();
141 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
142 if (curTransformFeedback && curTransformFeedback->isActive() &&
143 !curTransformFeedback->isPaused())
144 {
145 // An INVALID_OPERATION error is generated if transform feedback is active and not paused.
146 context->handleError(
147 Error(GL_INVALID_OPERATION, "transform feedback is active and not paused."));
148 return false;
149 }
150
151 if (!ValidateDrawIndirectBase(context, mode, indirect))
152 return false;
153
154 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
155 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
156 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand
157 // which's size is 4 * sizeof(uint).
158 auto checkedSum = checkedOffset + 4 * sizeof(GLuint);
159 if (!checkedSum.IsValid() ||
160 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
161 {
162 context->handleError(
163 Error(GL_INVALID_OPERATION,
164 "the command would source data beyond the end of the buffer object."));
165 return false;
166 }
167
168 return true;
169}
170
171bool ValidateDrawElementsIndirect(Context *context,
172 GLenum mode,
173 GLenum type,
174 const GLvoid *indirect)
175{
176 if (!ValidateDrawElementsBase(context, type))
177 return false;
178
179 const State &state = context->getGLState();
180 const VertexArray *vao = state.getVertexArray();
181 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
182 if (!elementArrayBuffer)
183 {
184 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to ELEMENT_ARRAY_BUFFER"));
185 return false;
186 }
187
188 if (!ValidateDrawIndirectBase(context, mode, indirect))
189 return false;
190
191 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
192 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
193 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand
194 // which's size is 5 * sizeof(uint).
195 auto checkedSum = checkedOffset + 5 * sizeof(GLuint);
196 if (!checkedSum.IsValid() ||
197 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
198 {
199 context->handleError(
200 Error(GL_INVALID_OPERATION,
201 "the command would source data beyond the end of the buffer object."));
202 return false;
203 }
204
205 return true;
206}
207
He Yunchao11b038b2016-11-22 21:24:04 +0800208bool ValidateGetTexLevelParameterBase(Context *context,
209 GLenum target,
210 GLint level,
211 GLenum pname,
212 GLsizei *length)
213{
214 if (context->getClientVersion() < ES_3_1)
215 {
216 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
217 return false;
218 }
219
220 if (length)
221 {
222 *length = 0;
223 }
224
225 if (!ValidTexLevelDestinationTarget(context, target))
226 {
227 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
228 return false;
229 }
230
231 if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) ==
232 nullptr)
233 {
234 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
235 return false;
236 }
237
238 if (!ValidMipLevel(context, target, level))
239 {
240 context->handleError(Error(GL_INVALID_VALUE));
241 return false;
242 }
243
244 switch (pname)
245 {
246 case GL_TEXTURE_RED_TYPE:
247 case GL_TEXTURE_GREEN_TYPE:
248 case GL_TEXTURE_BLUE_TYPE:
249 case GL_TEXTURE_ALPHA_TYPE:
250 case GL_TEXTURE_DEPTH_TYPE:
251 break;
252 case GL_TEXTURE_RED_SIZE:
253 case GL_TEXTURE_GREEN_SIZE:
254 case GL_TEXTURE_BLUE_SIZE:
255 case GL_TEXTURE_ALPHA_SIZE:
256 case GL_TEXTURE_DEPTH_SIZE:
257 case GL_TEXTURE_STENCIL_SIZE:
258 case GL_TEXTURE_SHARED_SIZE:
259 break;
260 case GL_TEXTURE_INTERNAL_FORMAT:
261 case GL_TEXTURE_WIDTH:
262 case GL_TEXTURE_HEIGHT:
263 case GL_TEXTURE_DEPTH:
264 break;
265 case GL_TEXTURE_SAMPLES:
266 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
267 break;
268 case GL_TEXTURE_COMPRESSED:
269 break;
270 default:
271 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
272 return false;
273 }
274
275 if (length)
276 {
277 *length = 1;
278 }
279 return true;
280}
281
282bool ValidateGetTexLevelParameterfv(Context *context,
283 GLenum target,
284 GLint level,
285 GLenum pname,
286 GLfloat *params)
287{
288 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
289}
290
291bool ValidateGetTexLevelParameteriv(Context *context,
292 GLenum target,
293 GLint level,
294 GLenum pname,
295 GLint *params)
296{
297 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
298}
299
JiangYizhoubddc46b2016-12-09 09:50:51 +0800300bool ValidateTexStorage2DMultiSample(Context *context,
301 GLenum target,
302 GLsizei samples,
303 GLint internalFormat,
304 GLsizei width,
305 GLsizei height,
306 GLboolean fixedSampleLocations)
307{
308 if (context->getClientVersion() < ES_3_1)
309 {
310 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
311 return false;
312 }
313
314 if (target != GL_TEXTURE_2D_MULTISAMPLE)
315 {
316 context->handleError(Error(GL_INVALID_ENUM, "Target must be TEXTURE_2D_MULTISAMPLE."));
317 return false;
318 }
319
320 if (width < 1 || height < 1)
321 {
322 context->handleError(Error(GL_INVALID_VALUE, "Width and height must be positive."));
323 return false;
324 }
325
326 const Caps &caps = context->getCaps();
327 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
328 static_cast<GLuint>(height) > caps.max2DTextureSize)
329 {
330 context->handleError(
331 Error(GL_INVALID_VALUE,
332 "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE."));
333 return false;
334 }
335
336 if (samples == 0)
337 {
338 context->handleError(Error(GL_INVALID_VALUE, "Samples may not be zero."));
339 return false;
340 }
341
342 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
343 if (!formatCaps.renderable)
344 {
345 context->handleError(
346 Error(GL_INVALID_ENUM,
347 "SizedInternalformat must be color-renderable, depth-renderable, "
348 "or stencil-renderable."));
349 return false;
350 }
351
352 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
353 // is one of the unsized base internalformats listed in table 8.11.
354 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
355 if (formatInfo.pixelBytes == 0)
356 {
357 context->handleError(
358 Error(GL_INVALID_ENUM,
359 "Internalformat is one of the unsupported unsized base internalformats."));
360 return false;
361 }
362
363 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
364 {
365 context->handleError(
366 Error(GL_INVALID_OPERATION,
367 "Samples must not be greater than maximum supported value for the format."));
368 return false;
369 }
370
371 Texture *texture = context->getTargetTexture(target);
372 if (!texture || texture->id() == 0)
373 {
374 context->handleError(Error(GL_INVALID_OPERATION, "Zero is bound to target."));
375 return false;
376 }
377
378 if (texture->getImmutableFormat())
379 {
380 context->handleError(
381 Error(GL_INVALID_OPERATION,
382 "The value of TEXTURE_IMMUTABLE_FORMAT for the texture "
383 "currently bound to target on the active texture unit is true."));
384 return false;
385 }
386
387 return true;
388}
389
390bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val)
391{
392 if (context->getClientVersion() < ES_3_1)
393 {
394 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
395 return false;
396 }
397
398 if (pname != GL_SAMPLE_POSITION)
399 {
400 context->handleError(Error(GL_INVALID_ENUM, "Pname must be SAMPLE_POSITION."));
401 return false;
402 }
403
404 GLint maxSamples = context->getCaps().maxSamples;
405 if (index >= static_cast<GLuint>(maxSamples))
406 {
407 context->handleError(
408 Error(GL_INVALID_VALUE, "Index must be less than the value of SAMPLES."));
409 return false;
410 }
411
412 return true;
413}
JiangYizhouf7bbc8a2016-11-16 09:57:22 +0800414
415bool ValidationFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param)
416{
417 if (context->getClientVersion() < ES_3_1)
418 {
419 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
420 return false;
421 }
422
423 if (!ValidFramebufferTarget(target))
424 {
425 context->handleError(Error(GL_INVALID_ENUM, "Invalid framebuffer target."));
426 return false;
427 }
428
429 switch (pname)
430 {
431 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
432 {
433 GLint maxWidth = context->getCaps().maxFramebufferWidth;
434 if (param < 0 || param > maxWidth)
435 {
436 context->handleError(
437 Error(GL_INVALID_VALUE,
438 "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_WIDTH."));
439 return false;
440 }
441 break;
442 }
443 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
444 {
445 GLint maxHeight = context->getCaps().maxFramebufferHeight;
446 if (param < 0 || param > maxHeight)
447 {
448 context->handleError(
449 Error(GL_INVALID_VALUE,
450 "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_HEIGHT."));
451 return false;
452 }
453 break;
454 }
455 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
456 {
457 GLint maxSamples = context->getCaps().maxFramebufferSamples;
458 if (param < 0 || param > maxSamples)
459 {
460 context->handleError(
461 Error(GL_INVALID_VALUE,
462 "Params less than 0 or greater than GL_MAX_FRAMEBUFFER_SAMPLES."));
463 return false;
464 }
465 break;
466 }
467 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
468 {
469 break;
470 }
471 default:
472 {
473 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname));
474 return false;
475 }
476 }
477
478 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
479 ASSERT(framebuffer);
480 if (framebuffer->id() == 0)
481 {
482 context->handleError(
483 Error(GL_INVALID_OPERATION, "Default framebuffer is bound to target."));
484 return false;
485 }
486 return true;
487}
488
489bool ValidationGetFramebufferParameteri(Context *context,
490 GLenum target,
491 GLenum pname,
492 GLint *params)
493{
494 if (context->getClientVersion() < ES_3_1)
495 {
496 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
497 return false;
498 }
499
500 if (!ValidFramebufferTarget(target))
501 {
502 context->handleError(Error(GL_INVALID_ENUM, "Invalid framebuffer target."));
503 return false;
504 }
505
506 switch (pname)
507 {
508 case GL_FRAMEBUFFER_DEFAULT_WIDTH:
509 case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
510 case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
511 case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
512 break;
513 default:
514 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname));
515 return false;
516 }
517
518 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
519 ASSERT(framebuffer);
520
521 if (framebuffer->id() == 0)
522 {
523 context->handleError(
524 Error(GL_INVALID_OPERATION, "Default framebuffer is bound to target."));
525 return false;
526 }
527 return true;
528}
529
jchen1015015f72017-03-16 13:54:21 +0800530bool ValidateGetProgramResourceIndex(Context *context,
531 GLuint program,
532 GLenum programInterface,
533 const GLchar *name)
534{
535 if (context->getClientVersion() < ES_3_1)
536 {
537 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES 3.1."));
538 return false;
539 }
540
541 Program *programObject = GetValidProgram(context, program);
542 if (programObject == nullptr)
543 {
544 return false;
545 }
546
547 if (!ValidateNamedProgramInterface(programInterface))
548 {
549 context->handleError(
550 Error(GL_INVALID_ENUM, "Invalid program interface: 0x%X", programInterface));
551 return false;
552 }
553 return true;
554}
555
Martin Radev66fb8202016-07-28 11:45:20 +0300556} // namespace gl