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