blob: 05ef0d6919db6c159c4c5ced6e0f71a4fbddb149 [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
109 case GL_COPY_READ_BUFFER:
110 case GL_COPY_WRITE_BUFFER:
111 case GL_PIXEL_PACK_BUFFER:
112 case GL_PIXEL_UNPACK_BUFFER:
113 case GL_TRANSFORM_FEEDBACK_BUFFER:
114 case GL_UNIFORM_BUFFER:
115 return (context->getClientVersion() >= 3);
116
117 default:
118 return false;
119 }
120}
121
Jamie Madill70656a62014-03-05 15:01:26 -0500122bool ValidBufferParameter(const Context *context, GLenum pname)
123{
124 switch (pname)
125 {
126 case GL_BUFFER_USAGE:
127 case GL_BUFFER_SIZE:
128 return true;
129
130 // GL_BUFFER_MAP_POINTER is a special case, and may only be
131 // queried with GetBufferPointerv
132 case GL_BUFFER_ACCESS_FLAGS:
133 case GL_BUFFER_MAPPED:
134 case GL_BUFFER_MAP_OFFSET:
135 case GL_BUFFER_MAP_LENGTH:
136 return (context->getClientVersion() >= 3);
137
138 default:
139 return false;
140 }
141}
142
Jamie Madill8c96d582014-03-05 15:01:23 -0500143bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400144{
145 int maxLevel = 0;
146 switch (target)
147 {
148 case GL_TEXTURE_2D: maxLevel = context->getMaximum2DTextureLevel(); break;
149 case GL_TEXTURE_CUBE_MAP:
150 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
151 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
152 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
153 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
154 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
155 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxLevel = context->getMaximumCubeTextureLevel(); break;
156 case GL_TEXTURE_3D: maxLevel = context->getMaximum3DTextureLevel(); break;
157 case GL_TEXTURE_2D_ARRAY: maxLevel = context->getMaximum2DArrayTextureLevel(); break;
158 default: UNREACHABLE();
159 }
160
161 return level < maxLevel;
162}
163
164bool ValidImageSize(const gl::Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth)
165{
166 if (level < 0 || width < 0 || height < 0 || depth < 0)
167 {
168 return false;
169 }
170
171 if (!context->supportsNonPower2Texture() && (level != 0 || !gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))
172 {
173 return false;
174 }
175
176 if (!ValidMipLevel(context, target, level))
177 {
178 return false;
179 }
180
181 return true;
182}
183
Geoff Lang005df412013-10-16 14:12:50 -0400184bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400185{
186 GLuint clientVersion = context->getClientVersion();
187 if (!IsFormatCompressed(internalFormat, clientVersion))
188 {
189 return false;
190 }
191
192 GLint blockWidth = GetCompressedBlockWidth(internalFormat, clientVersion);
193 GLint blockHeight = GetCompressedBlockHeight(internalFormat, clientVersion);
194 if (width < 0 || (width > blockWidth && width % blockWidth != 0) ||
195 height < 0 || (height > blockHeight && height % blockHeight != 0))
196 {
197 return false;
198 }
199
200 return true;
201}
202
Geoff Lang37dde692014-01-31 16:34:54 -0500203bool ValidQueryType(const Context *context, GLenum queryType)
204{
205 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
206 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
207
208 switch (queryType)
209 {
210 case GL_ANY_SAMPLES_PASSED:
211 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
212 return true;
213 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
214 return (context->getClientVersion() >= 3);
215 default:
216 return false;
217 }
218}
219
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400220bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400221 GLenum internalformat, GLsizei width, GLsizei height,
222 bool angleExtension)
223{
224 switch (target)
225 {
226 case GL_RENDERBUFFER:
227 break;
228 default:
229 return gl::error(GL_INVALID_ENUM, false);
230 }
231
232 if (width < 0 || height < 0 || samples < 0)
233 {
234 return gl::error(GL_INVALID_VALUE, false);
235 }
236
237 if (!gl::IsValidInternalFormat(internalformat, context))
238 {
239 return gl::error(GL_INVALID_ENUM, false);
240 }
241
242 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
243 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
244 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
245 // internal format must be sized and not an integer format if samples is greater than zero.
246 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
247 {
248 return gl::error(GL_INVALID_ENUM, false);
249 }
250
Geoff Langb2f3d052013-08-13 12:49:27 -0400251 GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion());
252 if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400253 {
254 return gl::error(GL_INVALID_OPERATION, false);
255 }
256
257 if (!gl::IsColorRenderingSupported(internalformat, context) &&
258 !gl::IsDepthRenderingSupported(internalformat, context) &&
259 !gl::IsStencilRenderingSupported(internalformat, context))
260 {
261 return gl::error(GL_INVALID_ENUM, false);
262 }
263
264 if (std::max(width, height) > context->getMaximumRenderbufferDimension())
265 {
266 return gl::error(GL_INVALID_VALUE, false);
267 }
268
269 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
270 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
271 // states that samples must be less than or equal to the maximum samples for the specified
272 // internal format.
273 if (angleExtension)
274 {
275 if (samples > context->getMaxSupportedSamples())
276 {
277 return gl::error(GL_INVALID_VALUE, false);
278 }
279 }
280 else
281 {
282 if (samples > context->getMaxSupportedFormatSamples(internalformat))
283 {
284 return gl::error(GL_INVALID_VALUE, false);
285 }
286 }
287
288 GLuint handle = context->getRenderbufferHandle();
289 if (handle == 0)
290 {
291 return gl::error(GL_INVALID_OPERATION, false);
292 }
293
294 return true;
295}
296
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500297bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
298 GLenum renderbuffertarget, GLuint renderbuffer)
299{
300 gl::Framebuffer *framebuffer = context->getTargetFramebuffer(target);
301 GLuint framebufferHandle = context->getTargetFramebufferHandle(target);
302
303 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
304 {
305 return gl::error(GL_INVALID_OPERATION, false);
306 }
307
308 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
309 {
310 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
311
312 if (colorAttachment >= context->getMaximumRenderTargets())
313 {
314 return gl::error(GL_INVALID_VALUE, false);
315 }
316 }
317 else
318 {
319 switch (attachment)
320 {
321 case GL_DEPTH_ATTACHMENT:
322 break;
323 case GL_STENCIL_ATTACHMENT:
324 break;
325 case GL_DEPTH_STENCIL_ATTACHMENT:
326 if (context->getClientVersion() < 3)
327 {
328 return gl::error(GL_INVALID_ENUM, false);
329 }
330 break;
331 default:
332 return gl::error(GL_INVALID_ENUM, false);
333 }
334 }
335
Jamie Madillab9d82c2014-01-21 16:38:14 -0500336 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
337 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
338 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
339 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
340 if (renderbuffer != 0)
341 {
342 if (!context->getRenderbuffer(renderbuffer))
343 {
344 return gl::error(GL_INVALID_OPERATION, false);
345 }
346 }
347
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500348 return true;
349}
350
Geoff Lang125deab2013-08-09 13:34:16 -0400351static bool IsPartialBlit(gl::Context *context, gl::Renderbuffer *readBuffer, gl::Renderbuffer *writeBuffer,
352 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
353 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
354{
355 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
356 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
357 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
358 {
359 return true;
360 }
361 else if (context->isScissorTestEnabled())
362 {
363 int scissorX, scissorY, scissorWidth, scissorHeight;
364 context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight);
365
366 return scissorX > 0 || scissorY > 0 ||
367 scissorWidth < writeBuffer->getWidth() ||
368 scissorHeight < writeBuffer->getHeight();
369 }
370 else
371 {
372 return false;
373 }
374}
375
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400376bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400377 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
378 GLenum filter, bool fromAngleExtension)
379{
380 switch (filter)
381 {
382 case GL_NEAREST:
383 break;
384 case GL_LINEAR:
385 if (fromAngleExtension)
386 {
387 return gl::error(GL_INVALID_ENUM, false);
388 }
389 break;
390 default:
391 return gl::error(GL_INVALID_ENUM, false);
392 }
393
394 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
395 {
396 return gl::error(GL_INVALID_VALUE, false);
397 }
398
399 if (mask == 0)
400 {
401 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
402 // buffers are copied.
403 return false;
404 }
405
406 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
407 {
408 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
409 return gl::error(GL_INVALID_OPERATION, false);
410 }
411
412 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
413 // color buffer, leaving only nearest being unfiltered from above
414 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
415 {
416 return gl::error(GL_INVALID_OPERATION, false);
417 }
418
419 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
420 {
421 if (fromAngleExtension)
422 {
423 ERR("Blits with the same source and destination framebuffer are not supported by this "
424 "implementation.");
425 }
426 return gl::error(GL_INVALID_OPERATION, false);
427 }
428
429 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
430 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
431 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
432 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
433 {
434 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
435 }
436
437 if (drawFramebuffer->getSamples() != 0)
438 {
439 return gl::error(GL_INVALID_OPERATION, false);
440 }
441
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400442 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
443
444 GLuint clientVersion = context->getClientVersion();
445
446 if (mask & GL_COLOR_BUFFER_BIT)
447 {
448 gl::Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer();
449 gl::Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
450
451 if (readColorBuffer && drawColorBuffer)
452 {
Geoff Lang005df412013-10-16 14:12:50 -0400453 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400454 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400455
456 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
457 {
458 if (drawFramebuffer->isEnabledColorAttachment(i))
459 {
Geoff Lang005df412013-10-16 14:12:50 -0400460 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400461 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400462
Geoff Langb2f3d052013-08-13 12:49:27 -0400463 // The GL ES 3.0.2 spec (pg 193) states that:
464 // 1) If the read buffer is fixed point format, the draw buffer must be as well
465 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
466 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
467 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
468 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400469 {
470 return gl::error(GL_INVALID_OPERATION, false);
471 }
472
Geoff Langb2f3d052013-08-13 12:49:27 -0400473 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400474 {
475 return gl::error(GL_INVALID_OPERATION, false);
476 }
477
Geoff Langb2f3d052013-08-13 12:49:27 -0400478 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400479 {
480 return gl::error(GL_INVALID_OPERATION, false);
481 }
482
Geoff Langb2f3d052013-08-13 12:49:27 -0400483 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400484 {
485 return gl::error(GL_INVALID_OPERATION, false);
486 }
487 }
488 }
489
Geoff Langb2f3d052013-08-13 12:49:27 -0400490 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400491 {
492 return gl::error(GL_INVALID_OPERATION, false);
493 }
494
495 if (fromAngleExtension)
496 {
497 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
498 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
499 {
500 return gl::error(GL_INVALID_OPERATION, false);
501 }
502
503 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
504 {
505 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
506 {
507 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
508 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
509 {
510 return gl::error(GL_INVALID_OPERATION, false);
511 }
512
513 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
514 {
515 return gl::error(GL_INVALID_OPERATION, false);
516 }
517 }
518 }
Geoff Lang125deab2013-08-09 13:34:16 -0400519 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
520 srcX0, srcY0, srcX1, srcY1,
521 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 {
523 return gl::error(GL_INVALID_OPERATION, false);
524 }
525 }
526 }
527 }
528
529 if (mask & GL_DEPTH_BUFFER_BIT)
530 {
531 gl::Renderbuffer *readDepthBuffer = readFramebuffer->getDepthbuffer();
532 gl::Renderbuffer *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
533
534 if (readDepthBuffer && drawDepthBuffer)
535 {
536 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
537 {
538 return gl::error(GL_INVALID_OPERATION, false);
539 }
540
541 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
542 {
543 return gl::error(GL_INVALID_OPERATION, false);
544 }
545
546 if (fromAngleExtension)
547 {
Geoff Lang125deab2013-08-09 13:34:16 -0400548 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
549 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400550 {
551 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
552 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
553 }
554
555 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
556 {
557 return gl::error(GL_INVALID_OPERATION, false);
558 }
559 }
560 }
561 }
562
563 if (mask & GL_STENCIL_BUFFER_BIT)
564 {
565 gl::Renderbuffer *readStencilBuffer = readFramebuffer->getStencilbuffer();
566 gl::Renderbuffer *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
567
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400568 if (readStencilBuffer && drawStencilBuffer)
569 {
570 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
571 {
572 return gl::error(GL_INVALID_OPERATION, false);
573 }
574
575 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
576 {
577 return gl::error(GL_INVALID_OPERATION, false);
578 }
579
580 if (fromAngleExtension)
581 {
Geoff Lang125deab2013-08-09 13:34:16 -0400582 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
583 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400584 {
585 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
586 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
587 }
588
589 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
590 {
591 return gl::error(GL_INVALID_OPERATION, false);
592 }
593 }
594 }
595 }
596
597 return true;
598}
599
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400600bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400601{
602 switch (pname)
603 {
604 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
605 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
606 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
607 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
608 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
609 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
610 case GL_CURRENT_VERTEX_ATTRIB:
611 return true;
612
613 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
614 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
615 // the same constant.
616 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
617 return true;
618
619 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
620 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
621
622 default:
623 return gl::error(GL_INVALID_ENUM, false);
624 }
625}
626
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400627bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400628{
629 switch (pname)
630 {
631 case GL_TEXTURE_WRAP_R:
632 case GL_TEXTURE_SWIZZLE_R:
633 case GL_TEXTURE_SWIZZLE_G:
634 case GL_TEXTURE_SWIZZLE_B:
635 case GL_TEXTURE_SWIZZLE_A:
636 case GL_TEXTURE_BASE_LEVEL:
637 case GL_TEXTURE_MAX_LEVEL:
638 case GL_TEXTURE_COMPARE_MODE:
639 case GL_TEXTURE_COMPARE_FUNC:
640 case GL_TEXTURE_MIN_LOD:
641 case GL_TEXTURE_MAX_LOD:
642 if (context->getClientVersion() < 3)
643 {
644 return gl::error(GL_INVALID_ENUM, false);
645 }
646 break;
647
648 default: break;
649 }
650
651 switch (pname)
652 {
653 case GL_TEXTURE_WRAP_S:
654 case GL_TEXTURE_WRAP_T:
655 case GL_TEXTURE_WRAP_R:
656 switch (param)
657 {
658 case GL_REPEAT:
659 case GL_CLAMP_TO_EDGE:
660 case GL_MIRRORED_REPEAT:
661 return true;
662 default:
663 return gl::error(GL_INVALID_ENUM, false);
664 }
665
666 case GL_TEXTURE_MIN_FILTER:
667 switch (param)
668 {
669 case GL_NEAREST:
670 case GL_LINEAR:
671 case GL_NEAREST_MIPMAP_NEAREST:
672 case GL_LINEAR_MIPMAP_NEAREST:
673 case GL_NEAREST_MIPMAP_LINEAR:
674 case GL_LINEAR_MIPMAP_LINEAR:
675 return true;
676 default:
677 return gl::error(GL_INVALID_ENUM, false);
678 }
679 break;
680
681 case GL_TEXTURE_MAG_FILTER:
682 switch (param)
683 {
684 case GL_NEAREST:
685 case GL_LINEAR:
686 return true;
687 default:
688 return gl::error(GL_INVALID_ENUM, false);
689 }
690 break;
691
692 case GL_TEXTURE_USAGE_ANGLE:
693 switch (param)
694 {
695 case GL_NONE:
696 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
697 return true;
698 default:
699 return gl::error(GL_INVALID_ENUM, false);
700 }
701 break;
702
703 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
704 if (!context->supportsTextureFilterAnisotropy())
705 {
706 return gl::error(GL_INVALID_ENUM, false);
707 }
708
709 // we assume the parameter passed to this validation method is truncated, not rounded
710 if (param < 1)
711 {
712 return gl::error(GL_INVALID_VALUE, false);
713 }
714 return true;
715
716 case GL_TEXTURE_MIN_LOD:
717 case GL_TEXTURE_MAX_LOD:
718 // any value is permissible
719 return true;
720
721 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400722 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400723 switch (param)
724 {
725 case GL_NONE:
726 case GL_COMPARE_REF_TO_TEXTURE:
727 return true;
728 default:
729 return gl::error(GL_INVALID_ENUM, false);
730 }
731 break;
732
733 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400734 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400735 switch (param)
736 {
737 case GL_LEQUAL:
738 case GL_GEQUAL:
739 case GL_LESS:
740 case GL_GREATER:
741 case GL_EQUAL:
742 case GL_NOTEQUAL:
743 case GL_ALWAYS:
744 case GL_NEVER:
745 return true;
746 default:
747 return gl::error(GL_INVALID_ENUM, false);
748 }
749 break;
750
751 case GL_TEXTURE_SWIZZLE_R:
752 case GL_TEXTURE_SWIZZLE_G:
753 case GL_TEXTURE_SWIZZLE_B:
754 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400755 switch (param)
756 {
757 case GL_RED:
758 case GL_GREEN:
759 case GL_BLUE:
760 case GL_ALPHA:
761 case GL_ZERO:
762 case GL_ONE:
763 return true;
764 default:
765 return gl::error(GL_INVALID_ENUM, false);
766 }
767 break;
768
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400769 case GL_TEXTURE_BASE_LEVEL:
770 case GL_TEXTURE_MAX_LEVEL:
771 UNIMPLEMENTED();
772 return true;
773
774 default:
775 return gl::error(GL_INVALID_ENUM, false);
776 }
777}
778
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400779bool ValidateSamplerObjectParameter(GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780{
781 switch (pname)
782 {
783 case GL_TEXTURE_MIN_FILTER:
784 case GL_TEXTURE_MAG_FILTER:
785 case GL_TEXTURE_WRAP_S:
786 case GL_TEXTURE_WRAP_T:
787 case GL_TEXTURE_WRAP_R:
788 case GL_TEXTURE_MIN_LOD:
789 case GL_TEXTURE_MAX_LOD:
790 case GL_TEXTURE_COMPARE_MODE:
791 case GL_TEXTURE_COMPARE_FUNC:
792 return true;
793
794 default:
795 return gl::error(GL_INVALID_ENUM, false);
796 }
797}
798
Jamie Madill26e91952014-03-05 15:01:27 -0500799bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
800 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
801{
802 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
803
804 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
805 {
806 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
807 }
808
809 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
810 {
811 return gl::error(GL_INVALID_OPERATION, false);
812 }
813
814 GLenum currentInternalFormat, currentFormat, currentType;
815 int clientVersion = context->getClientVersion();
816
817 // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
818 // and attempting to read back if that's the case is an error. The error will be registered
819 // by getCurrentReadFormat.
820 // Note: we need to explicitly check for framebuffer completeness here, before we call
821 // getCurrentReadFormatType, because it generates a different (wrong) error for incomplete FBOs
822 if (!context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType))
823 return false;
824
825 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(format, type) :
826 ValidES3ReadFormatType(currentInternalFormat, format, type);
827
828 if (!(currentFormat == format && currentType == type) && !validReadFormat)
829 {
830 return gl::error(GL_INVALID_OPERATION, false);
831 }
832
833 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format :
834 GetSizedInternalFormat(format, type, clientVersion);
835
836 GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, clientVersion, width, context->getPackAlignment());
837 // sized query sanity check
838 if (bufSize)
839 {
840 int requiredSize = outputPitch * height;
841 if (requiredSize > *bufSize)
842 {
843 return gl::error(GL_INVALID_OPERATION, false);
844 }
845 }
846
847 return true;
848}
849
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400850}