blob: 0fe7d22031f7b7b6ed63eb7d7fb402d88af40629 [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"
Jamie Madill36398922014-05-20 14:51:53 -040020#include "libGLESv2/ProgramBinary.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040021
22#include "common/mathutil.h"
23#include "common/utilities.h"
24
25namespace gl
26{
27
Geoff Lang0550d032014-01-30 11:29:07 -050028bool ValidCap(const Context *context, GLenum cap)
29{
30 switch (cap)
31 {
32 case GL_CULL_FACE:
33 case GL_POLYGON_OFFSET_FILL:
34 case GL_SAMPLE_ALPHA_TO_COVERAGE:
35 case GL_SAMPLE_COVERAGE:
36 case GL_SCISSOR_TEST:
37 case GL_STENCIL_TEST:
38 case GL_DEPTH_TEST:
39 case GL_BLEND:
40 case GL_DITHER:
41 return true;
42 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
43 case GL_RASTERIZER_DISCARD:
44 return (context->getClientVersion() >= 3);
45 default:
46 return false;
47 }
48}
49
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050050bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040051{
Jamie Madilld7460c72014-01-21 16:38:14 -050052 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040053 {
Jamie Madilld7460c72014-01-21 16:38:14 -050054 case GL_TEXTURE_2D:
55 case GL_TEXTURE_CUBE_MAP:
56 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040057
Jamie Madilld7460c72014-01-21 16:38:14 -050058 case GL_TEXTURE_3D:
59 case GL_TEXTURE_2D_ARRAY:
60 return (context->getClientVersion() >= 3);
61
62 default:
63 return false;
64 }
Jamie Madill35d15012013-10-07 10:46:37 -040065}
66
Shannon Woods4dfed832014-03-17 20:03:39 -040067// This function differs from ValidTextureTarget in that the target must be
68// usable as the destination of a 2D operation-- so a cube face is valid, but
69// GL_TEXTURE_CUBE_MAP is not.
70bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
71{
72 switch (target)
73 {
74 case GL_TEXTURE_2D:
75 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
76 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
77 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
78 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
79 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
80 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
81 return true;
82 case GL_TEXTURE_2D_ARRAY:
83 case GL_TEXTURE_3D:
84 return (context->getClientVersion() >= 3);
85 default:
86 return false;
87 }
88}
89
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050090bool ValidFramebufferTarget(GLenum target)
91{
92 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
93
94 switch (target)
95 {
96 case GL_FRAMEBUFFER: return true;
97 case GL_READ_FRAMEBUFFER: return true;
98 case GL_DRAW_FRAMEBUFFER: return true;
99 default: return false;
100 }
101}
102
Jamie Madill8c96d582014-03-05 15:01:23 -0500103bool ValidBufferTarget(const Context *context, GLenum target)
104{
105 switch (target)
106 {
107 case GL_ARRAY_BUFFER:
108 case GL_ELEMENT_ARRAY_BUFFER:
109 return true;
110
Jamie Madill8c96d582014-03-05 15:01:23 -0500111 case GL_PIXEL_PACK_BUFFER:
112 case GL_PIXEL_UNPACK_BUFFER:
Shannon Woods158c4382014-05-06 13:00:07 -0400113 return context->supportsPBOs();
114
Shannon Woodsb3801742014-03-27 14:59:19 -0400115 case GL_COPY_READ_BUFFER:
116 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500117 case GL_TRANSFORM_FEEDBACK_BUFFER:
118 case GL_UNIFORM_BUFFER:
119 return (context->getClientVersion() >= 3);
120
121 default:
122 return false;
123 }
124}
125
Jamie Madill70656a62014-03-05 15:01:26 -0500126bool ValidBufferParameter(const Context *context, GLenum pname)
127{
128 switch (pname)
129 {
130 case GL_BUFFER_USAGE:
131 case GL_BUFFER_SIZE:
132 return true;
133
134 // GL_BUFFER_MAP_POINTER is a special case, and may only be
135 // queried with GetBufferPointerv
136 case GL_BUFFER_ACCESS_FLAGS:
137 case GL_BUFFER_MAPPED:
138 case GL_BUFFER_MAP_OFFSET:
139 case GL_BUFFER_MAP_LENGTH:
140 return (context->getClientVersion() >= 3);
141
142 default:
143 return false;
144 }
145}
146
Jamie Madill8c96d582014-03-05 15:01:23 -0500147bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400148{
149 int maxLevel = 0;
150 switch (target)
151 {
152 case GL_TEXTURE_2D: maxLevel = context->getMaximum2DTextureLevel(); break;
153 case GL_TEXTURE_CUBE_MAP:
154 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
155 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
156 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
157 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
158 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
159 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxLevel = context->getMaximumCubeTextureLevel(); break;
160 case GL_TEXTURE_3D: maxLevel = context->getMaximum3DTextureLevel(); break;
161 case GL_TEXTURE_2D_ARRAY: maxLevel = context->getMaximum2DArrayTextureLevel(); break;
162 default: UNREACHABLE();
163 }
164
165 return level < maxLevel;
166}
167
168bool ValidImageSize(const gl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth)
169{
170 if (level < 0 || width < 0 || height < 0 || depth < 0)
171 {
172 return false;
173 }
174
175 if (!context->supportsNonPower2Texture() && (level != 0 || !gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))
176 {
177 return false;
178 }
179
180 if (!ValidMipLevel(context, target, level))
181 {
182 return false;
183 }
184
185 return true;
186}
187
Geoff Lang005df412013-10-16 14:12:50 -0400188bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400189{
190 GLuint clientVersion = context->getClientVersion();
191 if (!IsFormatCompressed(internalFormat, clientVersion))
192 {
193 return false;
194 }
195
196 GLint blockWidth = GetCompressedBlockWidth(internalFormat, clientVersion);
197 GLint blockHeight = GetCompressedBlockHeight(internalFormat, clientVersion);
198 if (width < 0 || (width > blockWidth && width % blockWidth != 0) ||
199 height < 0 || (height > blockHeight && height % blockHeight != 0))
200 {
201 return false;
202 }
203
204 return true;
205}
206
Geoff Lang37dde692014-01-31 16:34:54 -0500207bool ValidQueryType(const Context *context, GLenum queryType)
208{
209 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
210 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
211
212 switch (queryType)
213 {
214 case GL_ANY_SAMPLES_PASSED:
215 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
216 return true;
217 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
218 return (context->getClientVersion() >= 3);
219 default:
220 return false;
221 }
222}
223
Geoff Lang48dcae72014-02-05 16:28:24 -0500224bool ValidProgram(const Context *context, GLuint id)
225{
226 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
227 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
228 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
229
230 if (context->getProgram(id) != NULL)
231 {
232 return true;
233 }
234 else if (context->getShader(id) != NULL)
235 {
236 // ID is the wrong type
237 return gl::error(GL_INVALID_OPERATION, false);
238 }
239 else
240 {
241 // No shader/program object has this ID
242 return gl::error(GL_INVALID_VALUE, false);
243 }
244}
245
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400246bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400247 GLenum internalformat, GLsizei width, GLsizei height,
248 bool angleExtension)
249{
250 switch (target)
251 {
252 case GL_RENDERBUFFER:
253 break;
254 default:
255 return gl::error(GL_INVALID_ENUM, false);
256 }
257
258 if (width < 0 || height < 0 || samples < 0)
259 {
260 return gl::error(GL_INVALID_VALUE, false);
261 }
262
263 if (!gl::IsValidInternalFormat(internalformat, context))
264 {
265 return gl::error(GL_INVALID_ENUM, false);
266 }
267
268 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
269 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
270 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
271 // internal format must be sized and not an integer format if samples is greater than zero.
272 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
273 {
274 return gl::error(GL_INVALID_ENUM, false);
275 }
276
Geoff Langb2f3d052013-08-13 12:49:27 -0400277 GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion());
278 if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400279 {
280 return gl::error(GL_INVALID_OPERATION, false);
281 }
282
283 if (!gl::IsColorRenderingSupported(internalformat, context) &&
284 !gl::IsDepthRenderingSupported(internalformat, context) &&
285 !gl::IsStencilRenderingSupported(internalformat, context))
286 {
287 return gl::error(GL_INVALID_ENUM, false);
288 }
289
290 if (std::max(width, height) > context->getMaximumRenderbufferDimension())
291 {
292 return gl::error(GL_INVALID_VALUE, false);
293 }
294
295 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
296 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
297 // states that samples must be less than or equal to the maximum samples for the specified
298 // internal format.
299 if (angleExtension)
300 {
301 if (samples > context->getMaxSupportedSamples())
302 {
303 return gl::error(GL_INVALID_VALUE, false);
304 }
305 }
306 else
307 {
308 if (samples > context->getMaxSupportedFormatSamples(internalformat))
309 {
310 return gl::error(GL_INVALID_VALUE, false);
311 }
312 }
313
314 GLuint handle = context->getRenderbufferHandle();
315 if (handle == 0)
316 {
317 return gl::error(GL_INVALID_OPERATION, false);
318 }
319
320 return true;
321}
322
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500323bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
324 GLenum renderbuffertarget, GLuint renderbuffer)
325{
326 gl::Framebuffer *framebuffer = context->getTargetFramebuffer(target);
327 GLuint framebufferHandle = context->getTargetFramebufferHandle(target);
328
329 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
330 {
331 return gl::error(GL_INVALID_OPERATION, false);
332 }
333
334 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
335 {
336 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
337
338 if (colorAttachment >= context->getMaximumRenderTargets())
339 {
340 return gl::error(GL_INVALID_VALUE, false);
341 }
342 }
343 else
344 {
345 switch (attachment)
346 {
347 case GL_DEPTH_ATTACHMENT:
348 break;
349 case GL_STENCIL_ATTACHMENT:
350 break;
351 case GL_DEPTH_STENCIL_ATTACHMENT:
352 if (context->getClientVersion() < 3)
353 {
354 return gl::error(GL_INVALID_ENUM, false);
355 }
356 break;
357 default:
358 return gl::error(GL_INVALID_ENUM, false);
359 }
360 }
361
Jamie Madillab9d82c2014-01-21 16:38:14 -0500362 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
363 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
364 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
365 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
366 if (renderbuffer != 0)
367 {
368 if (!context->getRenderbuffer(renderbuffer))
369 {
370 return gl::error(GL_INVALID_OPERATION, false);
371 }
372 }
373
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500374 return true;
375}
376
Geoff Lang125deab2013-08-09 13:34:16 -0400377static bool IsPartialBlit(gl::Context *context, gl::Renderbuffer *readBuffer, gl::Renderbuffer *writeBuffer,
378 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
379 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
380{
381 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
382 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
383 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
384 {
385 return true;
386 }
387 else if (context->isScissorTestEnabled())
388 {
389 int scissorX, scissorY, scissorWidth, scissorHeight;
390 context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight);
391
392 return scissorX > 0 || scissorY > 0 ||
393 scissorWidth < writeBuffer->getWidth() ||
394 scissorHeight < writeBuffer->getHeight();
395 }
396 else
397 {
398 return false;
399 }
400}
401
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400402bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400403 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
404 GLenum filter, bool fromAngleExtension)
405{
406 switch (filter)
407 {
408 case GL_NEAREST:
409 break;
410 case GL_LINEAR:
411 if (fromAngleExtension)
412 {
413 return gl::error(GL_INVALID_ENUM, false);
414 }
415 break;
416 default:
417 return gl::error(GL_INVALID_ENUM, false);
418 }
419
420 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
421 {
422 return gl::error(GL_INVALID_VALUE, false);
423 }
424
425 if (mask == 0)
426 {
427 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
428 // buffers are copied.
429 return false;
430 }
431
432 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
433 {
434 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
435 return gl::error(GL_INVALID_OPERATION, false);
436 }
437
438 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
439 // color buffer, leaving only nearest being unfiltered from above
440 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
441 {
442 return gl::error(GL_INVALID_OPERATION, false);
443 }
444
445 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
446 {
447 if (fromAngleExtension)
448 {
449 ERR("Blits with the same source and destination framebuffer are not supported by this "
450 "implementation.");
451 }
452 return gl::error(GL_INVALID_OPERATION, false);
453 }
454
455 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
456 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
457 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
458 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
459 {
460 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
461 }
462
463 if (drawFramebuffer->getSamples() != 0)
464 {
465 return gl::error(GL_INVALID_OPERATION, false);
466 }
467
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400468 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
469
470 GLuint clientVersion = context->getClientVersion();
471
472 if (mask & GL_COLOR_BUFFER_BIT)
473 {
474 gl::Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer();
475 gl::Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
476
477 if (readColorBuffer && drawColorBuffer)
478 {
Geoff Lang005df412013-10-16 14:12:50 -0400479 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400480 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400481
482 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
483 {
484 if (drawFramebuffer->isEnabledColorAttachment(i))
485 {
Geoff Lang005df412013-10-16 14:12:50 -0400486 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400487 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400488
Geoff Langb2f3d052013-08-13 12:49:27 -0400489 // The GL ES 3.0.2 spec (pg 193) states that:
490 // 1) If the read buffer is fixed point format, the draw buffer must be as well
491 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
492 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
493 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
494 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400495 {
496 return gl::error(GL_INVALID_OPERATION, false);
497 }
498
Geoff Langb2f3d052013-08-13 12:49:27 -0400499 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500 {
501 return gl::error(GL_INVALID_OPERATION, false);
502 }
503
Geoff Langb2f3d052013-08-13 12:49:27 -0400504 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400505 {
506 return gl::error(GL_INVALID_OPERATION, false);
507 }
508
Geoff Langb2f3d052013-08-13 12:49:27 -0400509 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400510 {
511 return gl::error(GL_INVALID_OPERATION, false);
512 }
513 }
514 }
515
Geoff Langb2f3d052013-08-13 12:49:27 -0400516 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400517 {
518 return gl::error(GL_INVALID_OPERATION, false);
519 }
520
521 if (fromAngleExtension)
522 {
523 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
524 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
525 {
526 return gl::error(GL_INVALID_OPERATION, false);
527 }
528
529 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
530 {
531 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
532 {
533 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
534 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
535 {
536 return gl::error(GL_INVALID_OPERATION, false);
537 }
538
539 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
540 {
541 return gl::error(GL_INVALID_OPERATION, false);
542 }
543 }
544 }
Geoff Lang125deab2013-08-09 13:34:16 -0400545 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
546 srcX0, srcY0, srcX1, srcY1,
547 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400548 {
549 return gl::error(GL_INVALID_OPERATION, false);
550 }
551 }
552 }
553 }
554
555 if (mask & GL_DEPTH_BUFFER_BIT)
556 {
557 gl::Renderbuffer *readDepthBuffer = readFramebuffer->getDepthbuffer();
558 gl::Renderbuffer *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
559
560 if (readDepthBuffer && drawDepthBuffer)
561 {
562 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
563 {
564 return gl::error(GL_INVALID_OPERATION, false);
565 }
566
567 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
568 {
569 return gl::error(GL_INVALID_OPERATION, false);
570 }
571
572 if (fromAngleExtension)
573 {
Geoff Lang125deab2013-08-09 13:34:16 -0400574 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
575 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400576 {
577 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
578 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
579 }
580
581 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
582 {
583 return gl::error(GL_INVALID_OPERATION, false);
584 }
585 }
586 }
587 }
588
589 if (mask & GL_STENCIL_BUFFER_BIT)
590 {
591 gl::Renderbuffer *readStencilBuffer = readFramebuffer->getStencilbuffer();
592 gl::Renderbuffer *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
593
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400594 if (readStencilBuffer && drawStencilBuffer)
595 {
596 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
597 {
598 return gl::error(GL_INVALID_OPERATION, false);
599 }
600
601 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
602 {
603 return gl::error(GL_INVALID_OPERATION, false);
604 }
605
606 if (fromAngleExtension)
607 {
Geoff Lang125deab2013-08-09 13:34:16 -0400608 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
609 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400610 {
611 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
612 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
613 }
614
615 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
616 {
617 return gl::error(GL_INVALID_OPERATION, false);
618 }
619 }
620 }
621 }
622
623 return true;
624}
625
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400626bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400627{
628 switch (pname)
629 {
630 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
631 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
632 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
633 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
634 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
635 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
636 case GL_CURRENT_VERTEX_ATTRIB:
637 return true;
638
639 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
640 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
641 // the same constant.
642 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
643 return true;
644
645 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
646 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
647
648 default:
649 return gl::error(GL_INVALID_ENUM, false);
650 }
651}
652
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400653bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400654{
655 switch (pname)
656 {
657 case GL_TEXTURE_WRAP_R:
658 case GL_TEXTURE_SWIZZLE_R:
659 case GL_TEXTURE_SWIZZLE_G:
660 case GL_TEXTURE_SWIZZLE_B:
661 case GL_TEXTURE_SWIZZLE_A:
662 case GL_TEXTURE_BASE_LEVEL:
663 case GL_TEXTURE_MAX_LEVEL:
664 case GL_TEXTURE_COMPARE_MODE:
665 case GL_TEXTURE_COMPARE_FUNC:
666 case GL_TEXTURE_MIN_LOD:
667 case GL_TEXTURE_MAX_LOD:
668 if (context->getClientVersion() < 3)
669 {
670 return gl::error(GL_INVALID_ENUM, false);
671 }
672 break;
673
674 default: break;
675 }
676
677 switch (pname)
678 {
679 case GL_TEXTURE_WRAP_S:
680 case GL_TEXTURE_WRAP_T:
681 case GL_TEXTURE_WRAP_R:
682 switch (param)
683 {
684 case GL_REPEAT:
685 case GL_CLAMP_TO_EDGE:
686 case GL_MIRRORED_REPEAT:
687 return true;
688 default:
689 return gl::error(GL_INVALID_ENUM, false);
690 }
691
692 case GL_TEXTURE_MIN_FILTER:
693 switch (param)
694 {
695 case GL_NEAREST:
696 case GL_LINEAR:
697 case GL_NEAREST_MIPMAP_NEAREST:
698 case GL_LINEAR_MIPMAP_NEAREST:
699 case GL_NEAREST_MIPMAP_LINEAR:
700 case GL_LINEAR_MIPMAP_LINEAR:
701 return true;
702 default:
703 return gl::error(GL_INVALID_ENUM, false);
704 }
705 break;
706
707 case GL_TEXTURE_MAG_FILTER:
708 switch (param)
709 {
710 case GL_NEAREST:
711 case GL_LINEAR:
712 return true;
713 default:
714 return gl::error(GL_INVALID_ENUM, false);
715 }
716 break;
717
718 case GL_TEXTURE_USAGE_ANGLE:
719 switch (param)
720 {
721 case GL_NONE:
722 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
723 return true;
724 default:
725 return gl::error(GL_INVALID_ENUM, false);
726 }
727 break;
728
729 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
730 if (!context->supportsTextureFilterAnisotropy())
731 {
732 return gl::error(GL_INVALID_ENUM, false);
733 }
734
735 // we assume the parameter passed to this validation method is truncated, not rounded
736 if (param < 1)
737 {
738 return gl::error(GL_INVALID_VALUE, false);
739 }
740 return true;
741
742 case GL_TEXTURE_MIN_LOD:
743 case GL_TEXTURE_MAX_LOD:
744 // any value is permissible
745 return true;
746
747 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400748 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400749 switch (param)
750 {
751 case GL_NONE:
752 case GL_COMPARE_REF_TO_TEXTURE:
753 return true;
754 default:
755 return gl::error(GL_INVALID_ENUM, false);
756 }
757 break;
758
759 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400760 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 switch (param)
762 {
763 case GL_LEQUAL:
764 case GL_GEQUAL:
765 case GL_LESS:
766 case GL_GREATER:
767 case GL_EQUAL:
768 case GL_NOTEQUAL:
769 case GL_ALWAYS:
770 case GL_NEVER:
771 return true;
772 default:
773 return gl::error(GL_INVALID_ENUM, false);
774 }
775 break;
776
777 case GL_TEXTURE_SWIZZLE_R:
778 case GL_TEXTURE_SWIZZLE_G:
779 case GL_TEXTURE_SWIZZLE_B:
780 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400781 switch (param)
782 {
783 case GL_RED:
784 case GL_GREEN:
785 case GL_BLUE:
786 case GL_ALPHA:
787 case GL_ZERO:
788 case GL_ONE:
789 return true;
790 default:
791 return gl::error(GL_INVALID_ENUM, false);
792 }
793 break;
794
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 case GL_TEXTURE_BASE_LEVEL:
796 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400797 if (param < 0)
798 {
799 return gl::error(GL_INVALID_VALUE, false);
800 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400801 return true;
802
803 default:
804 return gl::error(GL_INVALID_ENUM, false);
805 }
806}
807
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400808bool ValidateSamplerObjectParameter(GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400809{
810 switch (pname)
811 {
812 case GL_TEXTURE_MIN_FILTER:
813 case GL_TEXTURE_MAG_FILTER:
814 case GL_TEXTURE_WRAP_S:
815 case GL_TEXTURE_WRAP_T:
816 case GL_TEXTURE_WRAP_R:
817 case GL_TEXTURE_MIN_LOD:
818 case GL_TEXTURE_MAX_LOD:
819 case GL_TEXTURE_COMPARE_MODE:
820 case GL_TEXTURE_COMPARE_FUNC:
821 return true;
822
823 default:
824 return gl::error(GL_INVALID_ENUM, false);
825 }
826}
827
Jamie Madill26e91952014-03-05 15:01:27 -0500828bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
829 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
830{
831 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
832
833 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
834 {
835 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
836 }
837
838 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
839 {
840 return gl::error(GL_INVALID_OPERATION, false);
841 }
842
843 GLenum currentInternalFormat, currentFormat, currentType;
844 int clientVersion = context->getClientVersion();
845
846 // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
847 // and attempting to read back if that's the case is an error. The error will be registered
848 // by getCurrentReadFormat.
849 // Note: we need to explicitly check for framebuffer completeness here, before we call
850 // getCurrentReadFormatType, because it generates a different (wrong) error for incomplete FBOs
851 if (!context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType))
852 return false;
853
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400854 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
855 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500856
857 if (!(currentFormat == format && currentType == type) && !validReadFormat)
858 {
859 return gl::error(GL_INVALID_OPERATION, false);
860 }
861
862 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format :
863 GetSizedInternalFormat(format, type, clientVersion);
864
865 GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, clientVersion, width, context->getPackAlignment());
866 // sized query sanity check
867 if (bufSize)
868 {
869 int requiredSize = outputPitch * height;
870 if (requiredSize > *bufSize)
871 {
872 return gl::error(GL_INVALID_OPERATION, false);
873 }
874 }
875
876 return true;
877}
878
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400879bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
880{
881 if (!ValidQueryType(context, target))
882 {
883 return gl::error(GL_INVALID_ENUM, false);
884 }
885
886 if (id == 0)
887 {
888 return gl::error(GL_INVALID_OPERATION, false);
889 }
890
891 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
892 // of zero, if the active query object name for <target> is non-zero (for the
893 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
894 // the active query for either target is non-zero), if <id> is the name of an
895 // existing query object whose type does not match <target>, or if <id> is the
896 // active query object name for any query type, the error INVALID_OPERATION is
897 // generated.
898
899 // Ensure no other queries are active
900 // NOTE: If other queries than occlusion are supported, we will need to check
901 // separately that:
902 // a) The query ID passed is not the current active query for any target/type
903 // b) There are no active queries for the requested target (and in the case
904 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
905 // no query may be active for either if glBeginQuery targets either.
906 if (context->isQueryActive())
907 {
908 return gl::error(GL_INVALID_OPERATION, false);
909 }
910
911 Query *queryObject = context->getQuery(id, true, target);
912
913 // check that name was obtained with glGenQueries
914 if (!queryObject)
915 {
916 return gl::error(GL_INVALID_OPERATION, false);
917 }
918
919 // check for type mismatch
920 if (queryObject->getType() != target)
921 {
922 return gl::error(GL_INVALID_OPERATION, false);
923 }
924
925 return true;
926}
927
Jamie Madill45c785d2014-05-13 14:09:34 -0400928bool ValidateEndQuery(gl::Context *context, GLenum target)
929{
930 if (!ValidQueryType(context, target))
931 {
932 return gl::error(GL_INVALID_ENUM, false);
933 }
934
935 const Query *queryObject = context->getActiveQuery(target);
936
937 if (queryObject == NULL)
938 {
939 return gl::error(GL_INVALID_OPERATION, false);
940 }
941
942 if (!queryObject->isStarted())
943 {
944 return gl::error(GL_INVALID_OPERATION, false);
945 }
946
947 return true;
948}
949
Jamie Madill36398922014-05-20 14:51:53 -0400950static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
951 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -0400952{
953 if (count < 0)
954 {
955 return gl::error(GL_INVALID_VALUE, false);
956 }
957
Jamie Madilld7c7bb22014-05-20 10:55:54 -0400958 gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
959 if (!programBinary)
960 {
961 return gl::error(GL_INVALID_OPERATION, false);
962 }
963
964 if (location == -1)
965 {
966 // Silently ignore the uniform command
967 return false;
968 }
969
Jamie Madill36398922014-05-20 14:51:53 -0400970 if (!programBinary->isValidUniformLocation(location))
971 {
972 return gl::error(GL_INVALID_OPERATION, false);
973 }
974
975 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
976
977 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
978 if (uniform->elementCount() == 1 && count > 1)
979 {
980 return gl::error(GL_INVALID_OPERATION, false);
981 }
982
983 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -0400984 return true;
985}
986
Jamie Madillaa981bd2014-05-20 10:55:55 -0400987bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
988{
989 // Check for ES3 uniform entry points
990 if (UniformComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
991 {
992 return gl::error(GL_INVALID_OPERATION, false);
993 }
994
Jamie Madill36398922014-05-20 14:51:53 -0400995 LinkedUniform *uniform = NULL;
996 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
997 {
998 return false;
999 }
1000
1001 GLenum targetBoolType = UniformBoolVectorType(uniformType);
1002 bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1003 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1004 {
1005 return gl::error(GL_INVALID_OPERATION, false);
1006 }
1007
1008 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001009}
1010
1011bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1012 GLboolean transpose)
1013{
1014 // Check for ES3 uniform entry points
1015 int rows = VariableRowCount(matrixType);
1016 int cols = VariableColumnCount(matrixType);
1017 if (rows != cols && context->getClientVersion() < 3)
1018 {
1019 return gl::error(GL_INVALID_OPERATION, false);
1020 }
1021
1022 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1023 {
1024 return gl::error(GL_INVALID_VALUE, false);
1025 }
1026
Jamie Madill36398922014-05-20 14:51:53 -04001027 LinkedUniform *uniform = NULL;
1028 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1029 {
1030 return false;
1031 }
1032
1033 if (uniform->type != matrixType)
1034 {
1035 return gl::error(GL_INVALID_OPERATION, false);
1036 }
1037
1038 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001039}
1040
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001041}