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