blob: 82cba3d712f28613e5eace82cd5bbb6b65a6ef9c [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"
19
20#include "common/mathutil.h"
21#include "common/utilities.h"
22
23namespace gl
24{
25
Geoff Lang0550d032014-01-30 11:29:07 -050026bool ValidCap(const Context *context, GLenum cap)
27{
28 switch (cap)
29 {
30 case GL_CULL_FACE:
31 case GL_POLYGON_OFFSET_FILL:
32 case GL_SAMPLE_ALPHA_TO_COVERAGE:
33 case GL_SAMPLE_COVERAGE:
34 case GL_SCISSOR_TEST:
35 case GL_STENCIL_TEST:
36 case GL_DEPTH_TEST:
37 case GL_BLEND:
38 case GL_DITHER:
39 return true;
40 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
41 case GL_RASTERIZER_DISCARD:
42 return (context->getClientVersion() >= 3);
43 default:
44 return false;
45 }
46}
47
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050048bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040049{
Jamie Madilld7460c72014-01-21 16:38:14 -050050 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040051 {
Jamie Madilld7460c72014-01-21 16:38:14 -050052 case GL_TEXTURE_2D:
53 case GL_TEXTURE_CUBE_MAP:
54 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040055
Jamie Madilld7460c72014-01-21 16:38:14 -050056 case GL_TEXTURE_3D:
57 case GL_TEXTURE_2D_ARRAY:
58 return (context->getClientVersion() >= 3);
59
60 default:
61 return false;
62 }
Jamie Madill35d15012013-10-07 10:46:37 -040063}
64
Shannon Woods4dfed832014-03-17 20:03:39 -040065// This function differs from ValidTextureTarget in that the target must be
66// usable as the destination of a 2D operation-- so a cube face is valid, but
67// GL_TEXTURE_CUBE_MAP is not.
68bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
69{
70 switch (target)
71 {
72 case GL_TEXTURE_2D:
73 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
74 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
75 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
76 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
77 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
78 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
79 return true;
80 case GL_TEXTURE_2D_ARRAY:
81 case GL_TEXTURE_3D:
82 return (context->getClientVersion() >= 3);
83 default:
84 return false;
85 }
86}
87
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050088bool ValidFramebufferTarget(GLenum target)
89{
90 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
91
92 switch (target)
93 {
94 case GL_FRAMEBUFFER: return true;
95 case GL_READ_FRAMEBUFFER: return true;
96 case GL_DRAW_FRAMEBUFFER: return true;
97 default: return false;
98 }
99}
100
Jamie Madill8c96d582014-03-05 15:01:23 -0500101bool ValidBufferTarget(const Context *context, GLenum target)
102{
103 switch (target)
104 {
105 case GL_ARRAY_BUFFER:
106 case GL_ELEMENT_ARRAY_BUFFER:
107 return true;
108
Jamie Madill8c96d582014-03-05 15:01:23 -0500109 case GL_PIXEL_PACK_BUFFER:
110 case GL_PIXEL_UNPACK_BUFFER:
Shannon Woods158c4382014-05-06 13:00:07 -0400111 return context->supportsPBOs();
112
Shannon Woodsb3801742014-03-27 14:59:19 -0400113 case GL_COPY_READ_BUFFER:
114 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500115 case GL_TRANSFORM_FEEDBACK_BUFFER:
116 case GL_UNIFORM_BUFFER:
117 return (context->getClientVersion() >= 3);
118
119 default:
120 return false;
121 }
122}
123
Jamie Madill70656a62014-03-05 15:01:26 -0500124bool ValidBufferParameter(const Context *context, GLenum pname)
125{
126 switch (pname)
127 {
128 case GL_BUFFER_USAGE:
129 case GL_BUFFER_SIZE:
130 return true;
131
132 // GL_BUFFER_MAP_POINTER is a special case, and may only be
133 // queried with GetBufferPointerv
134 case GL_BUFFER_ACCESS_FLAGS:
135 case GL_BUFFER_MAPPED:
136 case GL_BUFFER_MAP_OFFSET:
137 case GL_BUFFER_MAP_LENGTH:
138 return (context->getClientVersion() >= 3);
139
140 default:
141 return false;
142 }
143}
144
Jamie Madill8c96d582014-03-05 15:01:23 -0500145bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400146{
147 int maxLevel = 0;
148 switch (target)
149 {
150 case GL_TEXTURE_2D: maxLevel = context->getMaximum2DTextureLevel(); break;
151 case GL_TEXTURE_CUBE_MAP:
152 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
153 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
154 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
155 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
156 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
157 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxLevel = context->getMaximumCubeTextureLevel(); break;
158 case GL_TEXTURE_3D: maxLevel = context->getMaximum3DTextureLevel(); break;
159 case GL_TEXTURE_2D_ARRAY: maxLevel = context->getMaximum2DArrayTextureLevel(); break;
160 default: UNREACHABLE();
161 }
162
163 return level < maxLevel;
164}
165
166bool ValidImageSize(const gl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth)
167{
168 if (level < 0 || width < 0 || height < 0 || depth < 0)
169 {
170 return false;
171 }
172
173 if (!context->supportsNonPower2Texture() && (level != 0 || !gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))
174 {
175 return false;
176 }
177
178 if (!ValidMipLevel(context, target, level))
179 {
180 return false;
181 }
182
183 return true;
184}
185
Geoff Lang005df412013-10-16 14:12:50 -0400186bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400187{
188 GLuint clientVersion = context->getClientVersion();
189 if (!IsFormatCompressed(internalFormat, clientVersion))
190 {
191 return false;
192 }
193
194 GLint blockWidth = GetCompressedBlockWidth(internalFormat, clientVersion);
195 GLint blockHeight = GetCompressedBlockHeight(internalFormat, clientVersion);
196 if (width < 0 || (width > blockWidth && width % blockWidth != 0) ||
197 height < 0 || (height > blockHeight && height % blockHeight != 0))
198 {
199 return false;
200 }
201
202 return true;
203}
204
Geoff Lang37dde692014-01-31 16:34:54 -0500205bool ValidQueryType(const Context *context, GLenum queryType)
206{
207 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
208 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
209
210 switch (queryType)
211 {
212 case GL_ANY_SAMPLES_PASSED:
213 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
214 return true;
215 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
216 return (context->getClientVersion() >= 3);
217 default:
218 return false;
219 }
220}
221
Geoff Lang48dcae72014-02-05 16:28:24 -0500222bool ValidProgram(const Context *context, GLuint id)
223{
224 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
225 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
226 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
227
228 if (context->getProgram(id) != NULL)
229 {
230 return true;
231 }
232 else if (context->getShader(id) != NULL)
233 {
234 // ID is the wrong type
235 return gl::error(GL_INVALID_OPERATION, false);
236 }
237 else
238 {
239 // No shader/program object has this ID
240 return gl::error(GL_INVALID_VALUE, false);
241 }
242}
243
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400244bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400245 GLenum internalformat, GLsizei width, GLsizei height,
246 bool angleExtension)
247{
248 switch (target)
249 {
250 case GL_RENDERBUFFER:
251 break;
252 default:
253 return gl::error(GL_INVALID_ENUM, false);
254 }
255
256 if (width < 0 || height < 0 || samples < 0)
257 {
258 return gl::error(GL_INVALID_VALUE, false);
259 }
260
261 if (!gl::IsValidInternalFormat(internalformat, context))
262 {
263 return gl::error(GL_INVALID_ENUM, false);
264 }
265
266 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
267 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
268 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
269 // internal format must be sized and not an integer format if samples is greater than zero.
270 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
271 {
272 return gl::error(GL_INVALID_ENUM, false);
273 }
274
Geoff Langb2f3d052013-08-13 12:49:27 -0400275 GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion());
276 if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400277 {
278 return gl::error(GL_INVALID_OPERATION, false);
279 }
280
281 if (!gl::IsColorRenderingSupported(internalformat, context) &&
282 !gl::IsDepthRenderingSupported(internalformat, context) &&
283 !gl::IsStencilRenderingSupported(internalformat, context))
284 {
285 return gl::error(GL_INVALID_ENUM, false);
286 }
287
288 if (std::max(width, height) > context->getMaximumRenderbufferDimension())
289 {
290 return gl::error(GL_INVALID_VALUE, false);
291 }
292
293 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
294 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
295 // states that samples must be less than or equal to the maximum samples for the specified
296 // internal format.
297 if (angleExtension)
298 {
299 if (samples > context->getMaxSupportedSamples())
300 {
301 return gl::error(GL_INVALID_VALUE, false);
302 }
303 }
304 else
305 {
306 if (samples > context->getMaxSupportedFormatSamples(internalformat))
307 {
308 return gl::error(GL_INVALID_VALUE, false);
309 }
310 }
311
312 GLuint handle = context->getRenderbufferHandle();
313 if (handle == 0)
314 {
315 return gl::error(GL_INVALID_OPERATION, false);
316 }
317
318 return true;
319}
320
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500321bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
322 GLenum renderbuffertarget, GLuint renderbuffer)
323{
324 gl::Framebuffer *framebuffer = context->getTargetFramebuffer(target);
325 GLuint framebufferHandle = context->getTargetFramebufferHandle(target);
326
327 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
328 {
329 return gl::error(GL_INVALID_OPERATION, false);
330 }
331
332 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
333 {
334 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
335
336 if (colorAttachment >= context->getMaximumRenderTargets())
337 {
338 return gl::error(GL_INVALID_VALUE, false);
339 }
340 }
341 else
342 {
343 switch (attachment)
344 {
345 case GL_DEPTH_ATTACHMENT:
346 break;
347 case GL_STENCIL_ATTACHMENT:
348 break;
349 case GL_DEPTH_STENCIL_ATTACHMENT:
350 if (context->getClientVersion() < 3)
351 {
352 return gl::error(GL_INVALID_ENUM, false);
353 }
354 break;
355 default:
356 return gl::error(GL_INVALID_ENUM, false);
357 }
358 }
359
Jamie Madillab9d82c2014-01-21 16:38:14 -0500360 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
361 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
362 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
363 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
364 if (renderbuffer != 0)
365 {
366 if (!context->getRenderbuffer(renderbuffer))
367 {
368 return gl::error(GL_INVALID_OPERATION, false);
369 }
370 }
371
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500372 return true;
373}
374
Geoff Lang125deab2013-08-09 13:34:16 -0400375static bool IsPartialBlit(gl::Context *context, gl::Renderbuffer *readBuffer, gl::Renderbuffer *writeBuffer,
376 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
377 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
378{
379 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
380 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
381 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
382 {
383 return true;
384 }
385 else if (context->isScissorTestEnabled())
386 {
387 int scissorX, scissorY, scissorWidth, scissorHeight;
388 context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight);
389
390 return scissorX > 0 || scissorY > 0 ||
391 scissorWidth < writeBuffer->getWidth() ||
392 scissorHeight < writeBuffer->getHeight();
393 }
394 else
395 {
396 return false;
397 }
398}
399
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400400bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400401 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
402 GLenum filter, bool fromAngleExtension)
403{
404 switch (filter)
405 {
406 case GL_NEAREST:
407 break;
408 case GL_LINEAR:
409 if (fromAngleExtension)
410 {
411 return gl::error(GL_INVALID_ENUM, false);
412 }
413 break;
414 default:
415 return gl::error(GL_INVALID_ENUM, false);
416 }
417
418 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
419 {
420 return gl::error(GL_INVALID_VALUE, false);
421 }
422
423 if (mask == 0)
424 {
425 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
426 // buffers are copied.
427 return false;
428 }
429
430 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
431 {
432 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
433 return gl::error(GL_INVALID_OPERATION, false);
434 }
435
436 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
437 // color buffer, leaving only nearest being unfiltered from above
438 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
439 {
440 return gl::error(GL_INVALID_OPERATION, false);
441 }
442
443 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
444 {
445 if (fromAngleExtension)
446 {
447 ERR("Blits with the same source and destination framebuffer are not supported by this "
448 "implementation.");
449 }
450 return gl::error(GL_INVALID_OPERATION, false);
451 }
452
453 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
454 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
455 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
456 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
457 {
458 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
459 }
460
461 if (drawFramebuffer->getSamples() != 0)
462 {
463 return gl::error(GL_INVALID_OPERATION, false);
464 }
465
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400466 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
467
468 GLuint clientVersion = context->getClientVersion();
469
470 if (mask & GL_COLOR_BUFFER_BIT)
471 {
472 gl::Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer();
473 gl::Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
474
475 if (readColorBuffer && drawColorBuffer)
476 {
Geoff Lang005df412013-10-16 14:12:50 -0400477 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400478 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400479
480 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
481 {
482 if (drawFramebuffer->isEnabledColorAttachment(i))
483 {
Geoff Lang005df412013-10-16 14:12:50 -0400484 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400485 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400486
Geoff Langb2f3d052013-08-13 12:49:27 -0400487 // The GL ES 3.0.2 spec (pg 193) states that:
488 // 1) If the read buffer is fixed point format, the draw buffer must be as well
489 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
490 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
491 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
492 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400493 {
494 return gl::error(GL_INVALID_OPERATION, false);
495 }
496
Geoff Langb2f3d052013-08-13 12:49:27 -0400497 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400498 {
499 return gl::error(GL_INVALID_OPERATION, false);
500 }
501
Geoff Langb2f3d052013-08-13 12:49:27 -0400502 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400503 {
504 return gl::error(GL_INVALID_OPERATION, false);
505 }
506
Geoff Langb2f3d052013-08-13 12:49:27 -0400507 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400508 {
509 return gl::error(GL_INVALID_OPERATION, false);
510 }
511 }
512 }
513
Geoff Langb2f3d052013-08-13 12:49:27 -0400514 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400515 {
516 return gl::error(GL_INVALID_OPERATION, false);
517 }
518
519 if (fromAngleExtension)
520 {
521 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
522 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
523 {
524 return gl::error(GL_INVALID_OPERATION, false);
525 }
526
527 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
528 {
529 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
530 {
531 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
532 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
533 {
534 return gl::error(GL_INVALID_OPERATION, false);
535 }
536
537 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
538 {
539 return gl::error(GL_INVALID_OPERATION, false);
540 }
541 }
542 }
Geoff Lang125deab2013-08-09 13:34:16 -0400543 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
544 srcX0, srcY0, srcX1, srcY1,
545 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400546 {
547 return gl::error(GL_INVALID_OPERATION, false);
548 }
549 }
550 }
551 }
552
553 if (mask & GL_DEPTH_BUFFER_BIT)
554 {
555 gl::Renderbuffer *readDepthBuffer = readFramebuffer->getDepthbuffer();
556 gl::Renderbuffer *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
557
558 if (readDepthBuffer && drawDepthBuffer)
559 {
560 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
561 {
562 return gl::error(GL_INVALID_OPERATION, false);
563 }
564
565 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
566 {
567 return gl::error(GL_INVALID_OPERATION, false);
568 }
569
570 if (fromAngleExtension)
571 {
Geoff Lang125deab2013-08-09 13:34:16 -0400572 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
573 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400574 {
575 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
576 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
577 }
578
579 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
580 {
581 return gl::error(GL_INVALID_OPERATION, false);
582 }
583 }
584 }
585 }
586
587 if (mask & GL_STENCIL_BUFFER_BIT)
588 {
589 gl::Renderbuffer *readStencilBuffer = readFramebuffer->getStencilbuffer();
590 gl::Renderbuffer *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
591
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400592 if (readStencilBuffer && drawStencilBuffer)
593 {
594 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
595 {
596 return gl::error(GL_INVALID_OPERATION, false);
597 }
598
599 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
600 {
601 return gl::error(GL_INVALID_OPERATION, false);
602 }
603
604 if (fromAngleExtension)
605 {
Geoff Lang125deab2013-08-09 13:34:16 -0400606 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
607 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400608 {
609 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
610 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
611 }
612
613 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
614 {
615 return gl::error(GL_INVALID_OPERATION, false);
616 }
617 }
618 }
619 }
620
621 return true;
622}
623
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400624bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400625{
626 switch (pname)
627 {
628 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
629 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
630 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
631 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
632 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
633 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
634 case GL_CURRENT_VERTEX_ATTRIB:
635 return true;
636
637 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
638 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
639 // the same constant.
640 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
641 return true;
642
643 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
644 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
645
646 default:
647 return gl::error(GL_INVALID_ENUM, false);
648 }
649}
650
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400651bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652{
653 switch (pname)
654 {
655 case GL_TEXTURE_WRAP_R:
656 case GL_TEXTURE_SWIZZLE_R:
657 case GL_TEXTURE_SWIZZLE_G:
658 case GL_TEXTURE_SWIZZLE_B:
659 case GL_TEXTURE_SWIZZLE_A:
660 case GL_TEXTURE_BASE_LEVEL:
661 case GL_TEXTURE_MAX_LEVEL:
662 case GL_TEXTURE_COMPARE_MODE:
663 case GL_TEXTURE_COMPARE_FUNC:
664 case GL_TEXTURE_MIN_LOD:
665 case GL_TEXTURE_MAX_LOD:
666 if (context->getClientVersion() < 3)
667 {
668 return gl::error(GL_INVALID_ENUM, false);
669 }
670 break;
671
672 default: break;
673 }
674
675 switch (pname)
676 {
677 case GL_TEXTURE_WRAP_S:
678 case GL_TEXTURE_WRAP_T:
679 case GL_TEXTURE_WRAP_R:
680 switch (param)
681 {
682 case GL_REPEAT:
683 case GL_CLAMP_TO_EDGE:
684 case GL_MIRRORED_REPEAT:
685 return true;
686 default:
687 return gl::error(GL_INVALID_ENUM, false);
688 }
689
690 case GL_TEXTURE_MIN_FILTER:
691 switch (param)
692 {
693 case GL_NEAREST:
694 case GL_LINEAR:
695 case GL_NEAREST_MIPMAP_NEAREST:
696 case GL_LINEAR_MIPMAP_NEAREST:
697 case GL_NEAREST_MIPMAP_LINEAR:
698 case GL_LINEAR_MIPMAP_LINEAR:
699 return true;
700 default:
701 return gl::error(GL_INVALID_ENUM, false);
702 }
703 break;
704
705 case GL_TEXTURE_MAG_FILTER:
706 switch (param)
707 {
708 case GL_NEAREST:
709 case GL_LINEAR:
710 return true;
711 default:
712 return gl::error(GL_INVALID_ENUM, false);
713 }
714 break;
715
716 case GL_TEXTURE_USAGE_ANGLE:
717 switch (param)
718 {
719 case GL_NONE:
720 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
721 return true;
722 default:
723 return gl::error(GL_INVALID_ENUM, false);
724 }
725 break;
726
727 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
728 if (!context->supportsTextureFilterAnisotropy())
729 {
730 return gl::error(GL_INVALID_ENUM, false);
731 }
732
733 // we assume the parameter passed to this validation method is truncated, not rounded
734 if (param < 1)
735 {
736 return gl::error(GL_INVALID_VALUE, false);
737 }
738 return true;
739
740 case GL_TEXTURE_MIN_LOD:
741 case GL_TEXTURE_MAX_LOD:
742 // any value is permissible
743 return true;
744
745 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400746 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400747 switch (param)
748 {
749 case GL_NONE:
750 case GL_COMPARE_REF_TO_TEXTURE:
751 return true;
752 default:
753 return gl::error(GL_INVALID_ENUM, false);
754 }
755 break;
756
757 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400758 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 switch (param)
760 {
761 case GL_LEQUAL:
762 case GL_GEQUAL:
763 case GL_LESS:
764 case GL_GREATER:
765 case GL_EQUAL:
766 case GL_NOTEQUAL:
767 case GL_ALWAYS:
768 case GL_NEVER:
769 return true;
770 default:
771 return gl::error(GL_INVALID_ENUM, false);
772 }
773 break;
774
775 case GL_TEXTURE_SWIZZLE_R:
776 case GL_TEXTURE_SWIZZLE_G:
777 case GL_TEXTURE_SWIZZLE_B:
778 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400779 switch (param)
780 {
781 case GL_RED:
782 case GL_GREEN:
783 case GL_BLUE:
784 case GL_ALPHA:
785 case GL_ZERO:
786 case GL_ONE:
787 return true;
788 default:
789 return gl::error(GL_INVALID_ENUM, false);
790 }
791 break;
792
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793 case GL_TEXTURE_BASE_LEVEL:
794 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400795 if (param < 0)
796 {
797 return gl::error(GL_INVALID_VALUE, false);
798 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400799 return true;
800
801 default:
802 return gl::error(GL_INVALID_ENUM, false);
803 }
804}
805
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400806bool ValidateSamplerObjectParameter(GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400807{
808 switch (pname)
809 {
810 case GL_TEXTURE_MIN_FILTER:
811 case GL_TEXTURE_MAG_FILTER:
812 case GL_TEXTURE_WRAP_S:
813 case GL_TEXTURE_WRAP_T:
814 case GL_TEXTURE_WRAP_R:
815 case GL_TEXTURE_MIN_LOD:
816 case GL_TEXTURE_MAX_LOD:
817 case GL_TEXTURE_COMPARE_MODE:
818 case GL_TEXTURE_COMPARE_FUNC:
819 return true;
820
821 default:
822 return gl::error(GL_INVALID_ENUM, false);
823 }
824}
825
Jamie Madill26e91952014-03-05 15:01:27 -0500826bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
827 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
828{
829 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
830
831 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
832 {
833 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
834 }
835
836 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
837 {
838 return gl::error(GL_INVALID_OPERATION, false);
839 }
840
841 GLenum currentInternalFormat, currentFormat, currentType;
842 int clientVersion = context->getClientVersion();
843
844 // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
845 // and attempting to read back if that's the case is an error. The error will be registered
846 // by getCurrentReadFormat.
847 // Note: we need to explicitly check for framebuffer completeness here, before we call
848 // getCurrentReadFormatType, because it generates a different (wrong) error for incomplete FBOs
849 if (!context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType))
850 return false;
851
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400852 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
853 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500854
855 if (!(currentFormat == format && currentType == type) && !validReadFormat)
856 {
857 return gl::error(GL_INVALID_OPERATION, false);
858 }
859
860 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format :
861 GetSizedInternalFormat(format, type, clientVersion);
862
863 GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, clientVersion, width, context->getPackAlignment());
864 // sized query sanity check
865 if (bufSize)
866 {
867 int requiredSize = outputPitch * height;
868 if (requiredSize > *bufSize)
869 {
870 return gl::error(GL_INVALID_OPERATION, false);
871 }
872 }
873
874 return true;
875}
876
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400877}