blob: f59b2f593acff8b759b4d4334366edd3eca470af [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001#include "precompiled.h"
2//
3// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// validationES.h: Validation functions for generic OpenGL ES entry point parameters
9
10#include "libGLESv2/validationES.h"
Jamie Madill26e91952014-03-05 15:01:27 -050011#include "libGLESv2/validationES2.h"
12#include "libGLESv2/validationES3.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040013#include "libGLESv2/Context.h"
14#include "libGLESv2/Texture.h"
15#include "libGLESv2/Framebuffer.h"
16#include "libGLESv2/Renderbuffer.h"
17#include "libGLESv2/formatutils.h"
18#include "libGLESv2/main.h"
Jamie Madilldb2f14c2014-05-13 13:56:30 -040019#include "libGLESv2/Query.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040020
21#include "common/mathutil.h"
22#include "common/utilities.h"
23
24namespace gl
25{
26
Geoff Lang0550d032014-01-30 11:29:07 -050027bool ValidCap(const Context *context, GLenum cap)
28{
29 switch (cap)
30 {
31 case GL_CULL_FACE:
32 case GL_POLYGON_OFFSET_FILL:
33 case GL_SAMPLE_ALPHA_TO_COVERAGE:
34 case GL_SAMPLE_COVERAGE:
35 case GL_SCISSOR_TEST:
36 case GL_STENCIL_TEST:
37 case GL_DEPTH_TEST:
38 case GL_BLEND:
39 case GL_DITHER:
40 return true;
41 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
42 case GL_RASTERIZER_DISCARD:
43 return (context->getClientVersion() >= 3);
44 default:
45 return false;
46 }
47}
48
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050049bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040050{
Jamie Madilld7460c72014-01-21 16:38:14 -050051 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040052 {
Jamie Madilld7460c72014-01-21 16:38:14 -050053 case GL_TEXTURE_2D:
54 case GL_TEXTURE_CUBE_MAP:
55 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040056
Jamie Madilld7460c72014-01-21 16:38:14 -050057 case GL_TEXTURE_3D:
58 case GL_TEXTURE_2D_ARRAY:
59 return (context->getClientVersion() >= 3);
60
61 default:
62 return false;
63 }
Jamie Madill35d15012013-10-07 10:46:37 -040064}
65
Shannon Woods4dfed832014-03-17 20:03:39 -040066// This function differs from ValidTextureTarget in that the target must be
67// usable as the destination of a 2D operation-- so a cube face is valid, but
68// GL_TEXTURE_CUBE_MAP is not.
69bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
70{
71 switch (target)
72 {
73 case GL_TEXTURE_2D:
74 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
75 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
76 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
77 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
78 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
79 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
80 return true;
81 case GL_TEXTURE_2D_ARRAY:
82 case GL_TEXTURE_3D:
83 return (context->getClientVersion() >= 3);
84 default:
85 return false;
86 }
87}
88
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050089bool ValidFramebufferTarget(GLenum target)
90{
91 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
92
93 switch (target)
94 {
95 case GL_FRAMEBUFFER: return true;
96 case GL_READ_FRAMEBUFFER: return true;
97 case GL_DRAW_FRAMEBUFFER: return true;
98 default: return false;
99 }
100}
101
Jamie Madill8c96d582014-03-05 15:01:23 -0500102bool ValidBufferTarget(const Context *context, GLenum target)
103{
104 switch (target)
105 {
106 case GL_ARRAY_BUFFER:
107 case GL_ELEMENT_ARRAY_BUFFER:
108 return true;
109
Jamie Madill8c96d582014-03-05 15:01:23 -0500110 case GL_PIXEL_PACK_BUFFER:
111 case GL_PIXEL_UNPACK_BUFFER:
Shannon Woods158c4382014-05-06 13:00:07 -0400112 return context->supportsPBOs();
113
Shannon Woodsb3801742014-03-27 14:59:19 -0400114 case GL_COPY_READ_BUFFER:
115 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500116 case GL_TRANSFORM_FEEDBACK_BUFFER:
117 case GL_UNIFORM_BUFFER:
118 return (context->getClientVersion() >= 3);
119
120 default:
121 return false;
122 }
123}
124
Jamie Madill70656a62014-03-05 15:01:26 -0500125bool ValidBufferParameter(const Context *context, GLenum pname)
126{
127 switch (pname)
128 {
129 case GL_BUFFER_USAGE:
130 case GL_BUFFER_SIZE:
131 return true;
132
133 // GL_BUFFER_MAP_POINTER is a special case, and may only be
134 // queried with GetBufferPointerv
135 case GL_BUFFER_ACCESS_FLAGS:
136 case GL_BUFFER_MAPPED:
137 case GL_BUFFER_MAP_OFFSET:
138 case GL_BUFFER_MAP_LENGTH:
139 return (context->getClientVersion() >= 3);
140
141 default:
142 return false;
143 }
144}
145
Jamie Madill8c96d582014-03-05 15:01:23 -0500146bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400147{
148 int maxLevel = 0;
149 switch (target)
150 {
151 case GL_TEXTURE_2D: maxLevel = context->getMaximum2DTextureLevel(); break;
152 case GL_TEXTURE_CUBE_MAP:
153 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
154 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
155 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
156 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
157 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
158 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxLevel = context->getMaximumCubeTextureLevel(); break;
159 case GL_TEXTURE_3D: maxLevel = context->getMaximum3DTextureLevel(); break;
160 case GL_TEXTURE_2D_ARRAY: maxLevel = context->getMaximum2DArrayTextureLevel(); break;
161 default: UNREACHABLE();
162 }
163
164 return level < maxLevel;
165}
166
167bool ValidImageSize(const gl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth)
168{
169 if (level < 0 || width < 0 || height < 0 || depth < 0)
170 {
171 return false;
172 }
173
174 if (!context->supportsNonPower2Texture() && (level != 0 || !gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))
175 {
176 return false;
177 }
178
179 if (!ValidMipLevel(context, target, level))
180 {
181 return false;
182 }
183
184 return true;
185}
186
Geoff Lang005df412013-10-16 14:12:50 -0400187bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400188{
189 GLuint clientVersion = context->getClientVersion();
190 if (!IsFormatCompressed(internalFormat, clientVersion))
191 {
192 return false;
193 }
194
195 GLint blockWidth = GetCompressedBlockWidth(internalFormat, clientVersion);
196 GLint blockHeight = GetCompressedBlockHeight(internalFormat, clientVersion);
197 if (width < 0 || (width > blockWidth && width % blockWidth != 0) ||
198 height < 0 || (height > blockHeight && height % blockHeight != 0))
199 {
200 return false;
201 }
202
203 return true;
204}
205
Geoff Lang37dde692014-01-31 16:34:54 -0500206bool ValidQueryType(const Context *context, GLenum queryType)
207{
208 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
209 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
210
211 switch (queryType)
212 {
213 case GL_ANY_SAMPLES_PASSED:
214 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
215 return true;
216 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
217 return (context->getClientVersion() >= 3);
218 default:
219 return false;
220 }
221}
222
Geoff Lang48dcae72014-02-05 16:28:24 -0500223bool ValidProgram(const Context *context, GLuint id)
224{
225 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
226 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
227 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
228
229 if (context->getProgram(id) != NULL)
230 {
231 return true;
232 }
233 else if (context->getShader(id) != NULL)
234 {
235 // ID is the wrong type
236 return gl::error(GL_INVALID_OPERATION, false);
237 }
238 else
239 {
240 // No shader/program object has this ID
241 return gl::error(GL_INVALID_VALUE, false);
242 }
243}
244
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400245bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400246 GLenum internalformat, GLsizei width, GLsizei height,
247 bool angleExtension)
248{
249 switch (target)
250 {
251 case GL_RENDERBUFFER:
252 break;
253 default:
254 return gl::error(GL_INVALID_ENUM, false);
255 }
256
257 if (width < 0 || height < 0 || samples < 0)
258 {
259 return gl::error(GL_INVALID_VALUE, false);
260 }
261
262 if (!gl::IsValidInternalFormat(internalformat, context))
263 {
264 return gl::error(GL_INVALID_ENUM, false);
265 }
266
267 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
268 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
269 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
270 // internal format must be sized and not an integer format if samples is greater than zero.
271 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
272 {
273 return gl::error(GL_INVALID_ENUM, false);
274 }
275
Geoff Langb2f3d052013-08-13 12:49:27 -0400276 GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion());
277 if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400278 {
279 return gl::error(GL_INVALID_OPERATION, false);
280 }
281
282 if (!gl::IsColorRenderingSupported(internalformat, context) &&
283 !gl::IsDepthRenderingSupported(internalformat, context) &&
284 !gl::IsStencilRenderingSupported(internalformat, context))
285 {
286 return gl::error(GL_INVALID_ENUM, false);
287 }
288
289 if (std::max(width, height) > context->getMaximumRenderbufferDimension())
290 {
291 return gl::error(GL_INVALID_VALUE, false);
292 }
293
294 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
295 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
296 // states that samples must be less than or equal to the maximum samples for the specified
297 // internal format.
298 if (angleExtension)
299 {
300 if (samples > context->getMaxSupportedSamples())
301 {
302 return gl::error(GL_INVALID_VALUE, false);
303 }
304 }
305 else
306 {
307 if (samples > context->getMaxSupportedFormatSamples(internalformat))
308 {
309 return gl::error(GL_INVALID_VALUE, false);
310 }
311 }
312
313 GLuint handle = context->getRenderbufferHandle();
314 if (handle == 0)
315 {
316 return gl::error(GL_INVALID_OPERATION, false);
317 }
318
319 return true;
320}
321
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500322bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
323 GLenum renderbuffertarget, GLuint renderbuffer)
324{
325 gl::Framebuffer *framebuffer = context->getTargetFramebuffer(target);
326 GLuint framebufferHandle = context->getTargetFramebufferHandle(target);
327
328 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
329 {
330 return gl::error(GL_INVALID_OPERATION, false);
331 }
332
333 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
334 {
335 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
336
337 if (colorAttachment >= context->getMaximumRenderTargets())
338 {
339 return gl::error(GL_INVALID_VALUE, false);
340 }
341 }
342 else
343 {
344 switch (attachment)
345 {
346 case GL_DEPTH_ATTACHMENT:
347 break;
348 case GL_STENCIL_ATTACHMENT:
349 break;
350 case GL_DEPTH_STENCIL_ATTACHMENT:
351 if (context->getClientVersion() < 3)
352 {
353 return gl::error(GL_INVALID_ENUM, false);
354 }
355 break;
356 default:
357 return gl::error(GL_INVALID_ENUM, false);
358 }
359 }
360
Jamie Madillab9d82c2014-01-21 16:38:14 -0500361 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
362 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
363 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
364 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
365 if (renderbuffer != 0)
366 {
367 if (!context->getRenderbuffer(renderbuffer))
368 {
369 return gl::error(GL_INVALID_OPERATION, false);
370 }
371 }
372
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500373 return true;
374}
375
Geoff Lang125deab2013-08-09 13:34:16 -0400376static bool IsPartialBlit(gl::Context *context, gl::Renderbuffer *readBuffer, gl::Renderbuffer *writeBuffer,
377 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
378 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
379{
380 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
381 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
382 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
383 {
384 return true;
385 }
386 else if (context->isScissorTestEnabled())
387 {
388 int scissorX, scissorY, scissorWidth, scissorHeight;
389 context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight);
390
391 return scissorX > 0 || scissorY > 0 ||
392 scissorWidth < writeBuffer->getWidth() ||
393 scissorHeight < writeBuffer->getHeight();
394 }
395 else
396 {
397 return false;
398 }
399}
400
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400401bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400402 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
403 GLenum filter, bool fromAngleExtension)
404{
405 switch (filter)
406 {
407 case GL_NEAREST:
408 break;
409 case GL_LINEAR:
410 if (fromAngleExtension)
411 {
412 return gl::error(GL_INVALID_ENUM, false);
413 }
414 break;
415 default:
416 return gl::error(GL_INVALID_ENUM, false);
417 }
418
419 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
420 {
421 return gl::error(GL_INVALID_VALUE, false);
422 }
423
424 if (mask == 0)
425 {
426 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
427 // buffers are copied.
428 return false;
429 }
430
431 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
432 {
433 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
434 return gl::error(GL_INVALID_OPERATION, false);
435 }
436
437 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
438 // color buffer, leaving only nearest being unfiltered from above
439 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
440 {
441 return gl::error(GL_INVALID_OPERATION, false);
442 }
443
444 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
445 {
446 if (fromAngleExtension)
447 {
448 ERR("Blits with the same source and destination framebuffer are not supported by this "
449 "implementation.");
450 }
451 return gl::error(GL_INVALID_OPERATION, false);
452 }
453
454 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
455 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
456 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
457 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
458 {
459 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
460 }
461
462 if (drawFramebuffer->getSamples() != 0)
463 {
464 return gl::error(GL_INVALID_OPERATION, false);
465 }
466
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400467 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
468
469 GLuint clientVersion = context->getClientVersion();
470
471 if (mask & GL_COLOR_BUFFER_BIT)
472 {
473 gl::Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer();
474 gl::Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
475
476 if (readColorBuffer && drawColorBuffer)
477 {
Geoff Lang005df412013-10-16 14:12:50 -0400478 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400479 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400480
481 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
482 {
483 if (drawFramebuffer->isEnabledColorAttachment(i))
484 {
Geoff Lang005df412013-10-16 14:12:50 -0400485 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400486 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400487
Geoff Langb2f3d052013-08-13 12:49:27 -0400488 // The GL ES 3.0.2 spec (pg 193) states that:
489 // 1) If the read buffer is fixed point format, the draw buffer must be as well
490 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
491 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
492 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
493 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400494 {
495 return gl::error(GL_INVALID_OPERATION, false);
496 }
497
Geoff Langb2f3d052013-08-13 12:49:27 -0400498 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400499 {
500 return gl::error(GL_INVALID_OPERATION, false);
501 }
502
Geoff Langb2f3d052013-08-13 12:49:27 -0400503 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400504 {
505 return gl::error(GL_INVALID_OPERATION, false);
506 }
507
Geoff Langb2f3d052013-08-13 12:49:27 -0400508 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400509 {
510 return gl::error(GL_INVALID_OPERATION, false);
511 }
512 }
513 }
514
Geoff Langb2f3d052013-08-13 12:49:27 -0400515 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 {
517 return gl::error(GL_INVALID_OPERATION, false);
518 }
519
520 if (fromAngleExtension)
521 {
522 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
523 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
524 {
525 return gl::error(GL_INVALID_OPERATION, false);
526 }
527
528 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
529 {
530 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
531 {
532 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
533 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
534 {
535 return gl::error(GL_INVALID_OPERATION, false);
536 }
537
538 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
539 {
540 return gl::error(GL_INVALID_OPERATION, false);
541 }
542 }
543 }
Geoff Lang125deab2013-08-09 13:34:16 -0400544 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
545 srcX0, srcY0, srcX1, srcY1,
546 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400547 {
548 return gl::error(GL_INVALID_OPERATION, false);
549 }
550 }
551 }
552 }
553
554 if (mask & GL_DEPTH_BUFFER_BIT)
555 {
556 gl::Renderbuffer *readDepthBuffer = readFramebuffer->getDepthbuffer();
557 gl::Renderbuffer *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
558
559 if (readDepthBuffer && drawDepthBuffer)
560 {
561 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
562 {
563 return gl::error(GL_INVALID_OPERATION, false);
564 }
565
566 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
567 {
568 return gl::error(GL_INVALID_OPERATION, false);
569 }
570
571 if (fromAngleExtension)
572 {
Geoff Lang125deab2013-08-09 13:34:16 -0400573 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
574 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400575 {
576 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
577 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
578 }
579
580 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
581 {
582 return gl::error(GL_INVALID_OPERATION, false);
583 }
584 }
585 }
586 }
587
588 if (mask & GL_STENCIL_BUFFER_BIT)
589 {
590 gl::Renderbuffer *readStencilBuffer = readFramebuffer->getStencilbuffer();
591 gl::Renderbuffer *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
592
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400593 if (readStencilBuffer && drawStencilBuffer)
594 {
595 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
596 {
597 return gl::error(GL_INVALID_OPERATION, false);
598 }
599
600 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
601 {
602 return gl::error(GL_INVALID_OPERATION, false);
603 }
604
605 if (fromAngleExtension)
606 {
Geoff Lang125deab2013-08-09 13:34:16 -0400607 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
608 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400609 {
610 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
611 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
612 }
613
614 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
615 {
616 return gl::error(GL_INVALID_OPERATION, false);
617 }
618 }
619 }
620 }
621
622 return true;
623}
624
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400625bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400626{
627 switch (pname)
628 {
629 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
630 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
631 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
632 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
633 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
634 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
635 case GL_CURRENT_VERTEX_ATTRIB:
636 return true;
637
638 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
639 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
640 // the same constant.
641 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
642 return true;
643
644 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
645 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
646
647 default:
648 return gl::error(GL_INVALID_ENUM, false);
649 }
650}
651
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400652bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400653{
654 switch (pname)
655 {
656 case GL_TEXTURE_WRAP_R:
657 case GL_TEXTURE_SWIZZLE_R:
658 case GL_TEXTURE_SWIZZLE_G:
659 case GL_TEXTURE_SWIZZLE_B:
660 case GL_TEXTURE_SWIZZLE_A:
661 case GL_TEXTURE_BASE_LEVEL:
662 case GL_TEXTURE_MAX_LEVEL:
663 case GL_TEXTURE_COMPARE_MODE:
664 case GL_TEXTURE_COMPARE_FUNC:
665 case GL_TEXTURE_MIN_LOD:
666 case GL_TEXTURE_MAX_LOD:
667 if (context->getClientVersion() < 3)
668 {
669 return gl::error(GL_INVALID_ENUM, false);
670 }
671 break;
672
673 default: break;
674 }
675
676 switch (pname)
677 {
678 case GL_TEXTURE_WRAP_S:
679 case GL_TEXTURE_WRAP_T:
680 case GL_TEXTURE_WRAP_R:
681 switch (param)
682 {
683 case GL_REPEAT:
684 case GL_CLAMP_TO_EDGE:
685 case GL_MIRRORED_REPEAT:
686 return true;
687 default:
688 return gl::error(GL_INVALID_ENUM, false);
689 }
690
691 case GL_TEXTURE_MIN_FILTER:
692 switch (param)
693 {
694 case GL_NEAREST:
695 case GL_LINEAR:
696 case GL_NEAREST_MIPMAP_NEAREST:
697 case GL_LINEAR_MIPMAP_NEAREST:
698 case GL_NEAREST_MIPMAP_LINEAR:
699 case GL_LINEAR_MIPMAP_LINEAR:
700 return true;
701 default:
702 return gl::error(GL_INVALID_ENUM, false);
703 }
704 break;
705
706 case GL_TEXTURE_MAG_FILTER:
707 switch (param)
708 {
709 case GL_NEAREST:
710 case GL_LINEAR:
711 return true;
712 default:
713 return gl::error(GL_INVALID_ENUM, false);
714 }
715 break;
716
717 case GL_TEXTURE_USAGE_ANGLE:
718 switch (param)
719 {
720 case GL_NONE:
721 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
722 return true;
723 default:
724 return gl::error(GL_INVALID_ENUM, false);
725 }
726 break;
727
728 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
729 if (!context->supportsTextureFilterAnisotropy())
730 {
731 return gl::error(GL_INVALID_ENUM, false);
732 }
733
734 // we assume the parameter passed to this validation method is truncated, not rounded
735 if (param < 1)
736 {
737 return gl::error(GL_INVALID_VALUE, false);
738 }
739 return true;
740
741 case GL_TEXTURE_MIN_LOD:
742 case GL_TEXTURE_MAX_LOD:
743 // any value is permissible
744 return true;
745
746 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400747 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748 switch (param)
749 {
750 case GL_NONE:
751 case GL_COMPARE_REF_TO_TEXTURE:
752 return true;
753 default:
754 return gl::error(GL_INVALID_ENUM, false);
755 }
756 break;
757
758 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400759 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400760 switch (param)
761 {
762 case GL_LEQUAL:
763 case GL_GEQUAL:
764 case GL_LESS:
765 case GL_GREATER:
766 case GL_EQUAL:
767 case GL_NOTEQUAL:
768 case GL_ALWAYS:
769 case GL_NEVER:
770 return true;
771 default:
772 return gl::error(GL_INVALID_ENUM, false);
773 }
774 break;
775
776 case GL_TEXTURE_SWIZZLE_R:
777 case GL_TEXTURE_SWIZZLE_G:
778 case GL_TEXTURE_SWIZZLE_B:
779 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400780 switch (param)
781 {
782 case GL_RED:
783 case GL_GREEN:
784 case GL_BLUE:
785 case GL_ALPHA:
786 case GL_ZERO:
787 case GL_ONE:
788 return true;
789 default:
790 return gl::error(GL_INVALID_ENUM, false);
791 }
792 break;
793
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400794 case GL_TEXTURE_BASE_LEVEL:
795 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400796 if (param < 0)
797 {
798 return gl::error(GL_INVALID_VALUE, false);
799 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 return true;
801
802 default:
803 return gl::error(GL_INVALID_ENUM, false);
804 }
805}
806
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400807bool ValidateSamplerObjectParameter(GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400808{
809 switch (pname)
810 {
811 case GL_TEXTURE_MIN_FILTER:
812 case GL_TEXTURE_MAG_FILTER:
813 case GL_TEXTURE_WRAP_S:
814 case GL_TEXTURE_WRAP_T:
815 case GL_TEXTURE_WRAP_R:
816 case GL_TEXTURE_MIN_LOD:
817 case GL_TEXTURE_MAX_LOD:
818 case GL_TEXTURE_COMPARE_MODE:
819 case GL_TEXTURE_COMPARE_FUNC:
820 return true;
821
822 default:
823 return gl::error(GL_INVALID_ENUM, false);
824 }
825}
826
Jamie Madill26e91952014-03-05 15:01:27 -0500827bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
828 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
829{
830 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
831
832 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
833 {
834 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
835 }
836
837 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
838 {
839 return gl::error(GL_INVALID_OPERATION, false);
840 }
841
842 GLenum currentInternalFormat, currentFormat, currentType;
843 int clientVersion = context->getClientVersion();
844
845 // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
846 // and attempting to read back if that's the case is an error. The error will be registered
847 // by getCurrentReadFormat.
848 // Note: we need to explicitly check for framebuffer completeness here, before we call
849 // getCurrentReadFormatType, because it generates a different (wrong) error for incomplete FBOs
850 if (!context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType))
851 return false;
852
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400853 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
854 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500855
856 if (!(currentFormat == format && currentType == type) && !validReadFormat)
857 {
858 return gl::error(GL_INVALID_OPERATION, false);
859 }
860
861 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format :
862 GetSizedInternalFormat(format, type, clientVersion);
863
864 GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, clientVersion, width, context->getPackAlignment());
865 // sized query sanity check
866 if (bufSize)
867 {
868 int requiredSize = outputPitch * height;
869 if (requiredSize > *bufSize)
870 {
871 return gl::error(GL_INVALID_OPERATION, false);
872 }
873 }
874
875 return true;
876}
877
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400878bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
879{
880 if (!ValidQueryType(context, target))
881 {
882 return gl::error(GL_INVALID_ENUM, false);
883 }
884
885 if (id == 0)
886 {
887 return gl::error(GL_INVALID_OPERATION, false);
888 }
889
890 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
891 // of zero, if the active query object name for <target> is non-zero (for the
892 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
893 // the active query for either target is non-zero), if <id> is the name of an
894 // existing query object whose type does not match <target>, or if <id> is the
895 // active query object name for any query type, the error INVALID_OPERATION is
896 // generated.
897
898 // Ensure no other queries are active
899 // NOTE: If other queries than occlusion are supported, we will need to check
900 // separately that:
901 // a) The query ID passed is not the current active query for any target/type
902 // b) There are no active queries for the requested target (and in the case
903 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
904 // no query may be active for either if glBeginQuery targets either.
905 if (context->isQueryActive())
906 {
907 return gl::error(GL_INVALID_OPERATION, false);
908 }
909
910 Query *queryObject = context->getQuery(id, true, target);
911
912 // check that name was obtained with glGenQueries
913 if (!queryObject)
914 {
915 return gl::error(GL_INVALID_OPERATION, false);
916 }
917
918 // check for type mismatch
919 if (queryObject->getType() != target)
920 {
921 return gl::error(GL_INVALID_OPERATION, false);
922 }
923
924 return true;
925}
926
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400927}