blob: 1ba759c1d74087d60c21cdfbf6c9460cd3343a32 [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 Woodsb3801742014-03-27 14:59:19 -0400111 case GL_COPY_READ_BUFFER:
112 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500113 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 Lang48dcae72014-02-05 16:28:24 -0500220bool ValidProgram(const Context *context, GLuint id)
221{
222 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
223 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
224 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
225
226 if (context->getProgram(id) != NULL)
227 {
228 return true;
229 }
230 else if (context->getShader(id) != NULL)
231 {
232 // ID is the wrong type
233 return gl::error(GL_INVALID_OPERATION, false);
234 }
235 else
236 {
237 // No shader/program object has this ID
238 return gl::error(GL_INVALID_VALUE, false);
239 }
240}
241
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400242bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400243 GLenum internalformat, GLsizei width, GLsizei height,
244 bool angleExtension)
245{
246 switch (target)
247 {
248 case GL_RENDERBUFFER:
249 break;
250 default:
251 return gl::error(GL_INVALID_ENUM, false);
252 }
253
254 if (width < 0 || height < 0 || samples < 0)
255 {
256 return gl::error(GL_INVALID_VALUE, false);
257 }
258
259 if (!gl::IsValidInternalFormat(internalformat, context))
260 {
261 return gl::error(GL_INVALID_ENUM, false);
262 }
263
264 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
265 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
266 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
267 // internal format must be sized and not an integer format if samples is greater than zero.
268 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
269 {
270 return gl::error(GL_INVALID_ENUM, false);
271 }
272
Geoff Langb2f3d052013-08-13 12:49:27 -0400273 GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion());
274 if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400275 {
276 return gl::error(GL_INVALID_OPERATION, false);
277 }
278
279 if (!gl::IsColorRenderingSupported(internalformat, context) &&
280 !gl::IsDepthRenderingSupported(internalformat, context) &&
281 !gl::IsStencilRenderingSupported(internalformat, context))
282 {
283 return gl::error(GL_INVALID_ENUM, false);
284 }
285
286 if (std::max(width, height) > context->getMaximumRenderbufferDimension())
287 {
288 return gl::error(GL_INVALID_VALUE, false);
289 }
290
291 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
292 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
293 // states that samples must be less than or equal to the maximum samples for the specified
294 // internal format.
295 if (angleExtension)
296 {
297 if (samples > context->getMaxSupportedSamples())
298 {
299 return gl::error(GL_INVALID_VALUE, false);
300 }
301 }
302 else
303 {
304 if (samples > context->getMaxSupportedFormatSamples(internalformat))
305 {
306 return gl::error(GL_INVALID_VALUE, false);
307 }
308 }
309
310 GLuint handle = context->getRenderbufferHandle();
311 if (handle == 0)
312 {
313 return gl::error(GL_INVALID_OPERATION, false);
314 }
315
316 return true;
317}
318
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500319bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
320 GLenum renderbuffertarget, GLuint renderbuffer)
321{
322 gl::Framebuffer *framebuffer = context->getTargetFramebuffer(target);
323 GLuint framebufferHandle = context->getTargetFramebufferHandle(target);
324
325 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
326 {
327 return gl::error(GL_INVALID_OPERATION, false);
328 }
329
330 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
331 {
332 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
333
334 if (colorAttachment >= context->getMaximumRenderTargets())
335 {
336 return gl::error(GL_INVALID_VALUE, false);
337 }
338 }
339 else
340 {
341 switch (attachment)
342 {
343 case GL_DEPTH_ATTACHMENT:
344 break;
345 case GL_STENCIL_ATTACHMENT:
346 break;
347 case GL_DEPTH_STENCIL_ATTACHMENT:
348 if (context->getClientVersion() < 3)
349 {
350 return gl::error(GL_INVALID_ENUM, false);
351 }
352 break;
353 default:
354 return gl::error(GL_INVALID_ENUM, false);
355 }
356 }
357
Jamie Madillab9d82c2014-01-21 16:38:14 -0500358 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
359 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
360 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
361 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
362 if (renderbuffer != 0)
363 {
364 if (!context->getRenderbuffer(renderbuffer))
365 {
366 return gl::error(GL_INVALID_OPERATION, false);
367 }
368 }
369
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500370 return true;
371}
372
Geoff Lang125deab2013-08-09 13:34:16 -0400373static bool IsPartialBlit(gl::Context *context, gl::Renderbuffer *readBuffer, gl::Renderbuffer *writeBuffer,
374 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
375 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
376{
377 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
378 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
379 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
380 {
381 return true;
382 }
383 else if (context->isScissorTestEnabled())
384 {
385 int scissorX, scissorY, scissorWidth, scissorHeight;
386 context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight);
387
388 return scissorX > 0 || scissorY > 0 ||
389 scissorWidth < writeBuffer->getWidth() ||
390 scissorHeight < writeBuffer->getHeight();
391 }
392 else
393 {
394 return false;
395 }
396}
397
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400398bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400399 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
400 GLenum filter, bool fromAngleExtension)
401{
402 switch (filter)
403 {
404 case GL_NEAREST:
405 break;
406 case GL_LINEAR:
407 if (fromAngleExtension)
408 {
409 return gl::error(GL_INVALID_ENUM, false);
410 }
411 break;
412 default:
413 return gl::error(GL_INVALID_ENUM, false);
414 }
415
416 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
417 {
418 return gl::error(GL_INVALID_VALUE, false);
419 }
420
421 if (mask == 0)
422 {
423 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
424 // buffers are copied.
425 return false;
426 }
427
428 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
429 {
430 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
431 return gl::error(GL_INVALID_OPERATION, false);
432 }
433
434 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
435 // color buffer, leaving only nearest being unfiltered from above
436 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
437 {
438 return gl::error(GL_INVALID_OPERATION, false);
439 }
440
441 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
442 {
443 if (fromAngleExtension)
444 {
445 ERR("Blits with the same source and destination framebuffer are not supported by this "
446 "implementation.");
447 }
448 return gl::error(GL_INVALID_OPERATION, false);
449 }
450
451 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
452 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
453 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
454 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
455 {
456 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
457 }
458
459 if (drawFramebuffer->getSamples() != 0)
460 {
461 return gl::error(GL_INVALID_OPERATION, false);
462 }
463
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400464 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
465
466 GLuint clientVersion = context->getClientVersion();
467
468 if (mask & GL_COLOR_BUFFER_BIT)
469 {
470 gl::Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer();
471 gl::Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
472
473 if (readColorBuffer && drawColorBuffer)
474 {
Geoff Lang005df412013-10-16 14:12:50 -0400475 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400476 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400477
478 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
479 {
480 if (drawFramebuffer->isEnabledColorAttachment(i))
481 {
Geoff Lang005df412013-10-16 14:12:50 -0400482 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400483 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400484
Geoff Langb2f3d052013-08-13 12:49:27 -0400485 // The GL ES 3.0.2 spec (pg 193) states that:
486 // 1) If the read buffer is fixed point format, the draw buffer must be as well
487 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
488 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
489 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
490 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400491 {
492 return gl::error(GL_INVALID_OPERATION, false);
493 }
494
Geoff Langb2f3d052013-08-13 12:49:27 -0400495 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400496 {
497 return gl::error(GL_INVALID_OPERATION, false);
498 }
499
Geoff Langb2f3d052013-08-13 12:49:27 -0400500 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400501 {
502 return gl::error(GL_INVALID_OPERATION, false);
503 }
504
Geoff Langb2f3d052013-08-13 12:49:27 -0400505 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400506 {
507 return gl::error(GL_INVALID_OPERATION, false);
508 }
509 }
510 }
511
Geoff Langb2f3d052013-08-13 12:49:27 -0400512 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 {
514 return gl::error(GL_INVALID_OPERATION, false);
515 }
516
517 if (fromAngleExtension)
518 {
519 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
520 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
521 {
522 return gl::error(GL_INVALID_OPERATION, false);
523 }
524
525 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
526 {
527 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
528 {
529 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
530 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
531 {
532 return gl::error(GL_INVALID_OPERATION, false);
533 }
534
535 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
536 {
537 return gl::error(GL_INVALID_OPERATION, false);
538 }
539 }
540 }
Geoff Lang125deab2013-08-09 13:34:16 -0400541 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
542 srcX0, srcY0, srcX1, srcY1,
543 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400544 {
545 return gl::error(GL_INVALID_OPERATION, false);
546 }
547 }
548 }
549 }
550
551 if (mask & GL_DEPTH_BUFFER_BIT)
552 {
553 gl::Renderbuffer *readDepthBuffer = readFramebuffer->getDepthbuffer();
554 gl::Renderbuffer *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
555
556 if (readDepthBuffer && drawDepthBuffer)
557 {
558 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
559 {
560 return gl::error(GL_INVALID_OPERATION, false);
561 }
562
563 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
564 {
565 return gl::error(GL_INVALID_OPERATION, false);
566 }
567
568 if (fromAngleExtension)
569 {
Geoff Lang125deab2013-08-09 13:34:16 -0400570 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
571 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400572 {
573 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
574 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
575 }
576
577 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
578 {
579 return gl::error(GL_INVALID_OPERATION, false);
580 }
581 }
582 }
583 }
584
585 if (mask & GL_STENCIL_BUFFER_BIT)
586 {
587 gl::Renderbuffer *readStencilBuffer = readFramebuffer->getStencilbuffer();
588 gl::Renderbuffer *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
589
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400590 if (readStencilBuffer && drawStencilBuffer)
591 {
592 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
593 {
594 return gl::error(GL_INVALID_OPERATION, false);
595 }
596
597 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
598 {
599 return gl::error(GL_INVALID_OPERATION, false);
600 }
601
602 if (fromAngleExtension)
603 {
Geoff Lang125deab2013-08-09 13:34:16 -0400604 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
605 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400606 {
607 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
608 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
609 }
610
611 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
612 {
613 return gl::error(GL_INVALID_OPERATION, false);
614 }
615 }
616 }
617 }
618
619 return true;
620}
621
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400622bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400623{
624 switch (pname)
625 {
626 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
627 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
628 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
629 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
630 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
631 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
632 case GL_CURRENT_VERTEX_ATTRIB:
633 return true;
634
635 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
636 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
637 // the same constant.
638 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
639 return true;
640
641 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
642 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
643
644 default:
645 return gl::error(GL_INVALID_ENUM, false);
646 }
647}
648
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400649bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650{
651 switch (pname)
652 {
653 case GL_TEXTURE_WRAP_R:
654 case GL_TEXTURE_SWIZZLE_R:
655 case GL_TEXTURE_SWIZZLE_G:
656 case GL_TEXTURE_SWIZZLE_B:
657 case GL_TEXTURE_SWIZZLE_A:
658 case GL_TEXTURE_BASE_LEVEL:
659 case GL_TEXTURE_MAX_LEVEL:
660 case GL_TEXTURE_COMPARE_MODE:
661 case GL_TEXTURE_COMPARE_FUNC:
662 case GL_TEXTURE_MIN_LOD:
663 case GL_TEXTURE_MAX_LOD:
664 if (context->getClientVersion() < 3)
665 {
666 return gl::error(GL_INVALID_ENUM, false);
667 }
668 break;
669
670 default: break;
671 }
672
673 switch (pname)
674 {
675 case GL_TEXTURE_WRAP_S:
676 case GL_TEXTURE_WRAP_T:
677 case GL_TEXTURE_WRAP_R:
678 switch (param)
679 {
680 case GL_REPEAT:
681 case GL_CLAMP_TO_EDGE:
682 case GL_MIRRORED_REPEAT:
683 return true;
684 default:
685 return gl::error(GL_INVALID_ENUM, false);
686 }
687
688 case GL_TEXTURE_MIN_FILTER:
689 switch (param)
690 {
691 case GL_NEAREST:
692 case GL_LINEAR:
693 case GL_NEAREST_MIPMAP_NEAREST:
694 case GL_LINEAR_MIPMAP_NEAREST:
695 case GL_NEAREST_MIPMAP_LINEAR:
696 case GL_LINEAR_MIPMAP_LINEAR:
697 return true;
698 default:
699 return gl::error(GL_INVALID_ENUM, false);
700 }
701 break;
702
703 case GL_TEXTURE_MAG_FILTER:
704 switch (param)
705 {
706 case GL_NEAREST:
707 case GL_LINEAR:
708 return true;
709 default:
710 return gl::error(GL_INVALID_ENUM, false);
711 }
712 break;
713
714 case GL_TEXTURE_USAGE_ANGLE:
715 switch (param)
716 {
717 case GL_NONE:
718 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
719 return true;
720 default:
721 return gl::error(GL_INVALID_ENUM, false);
722 }
723 break;
724
725 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
726 if (!context->supportsTextureFilterAnisotropy())
727 {
728 return gl::error(GL_INVALID_ENUM, false);
729 }
730
731 // we assume the parameter passed to this validation method is truncated, not rounded
732 if (param < 1)
733 {
734 return gl::error(GL_INVALID_VALUE, false);
735 }
736 return true;
737
738 case GL_TEXTURE_MIN_LOD:
739 case GL_TEXTURE_MAX_LOD:
740 // any value is permissible
741 return true;
742
743 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400744 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400745 switch (param)
746 {
747 case GL_NONE:
748 case GL_COMPARE_REF_TO_TEXTURE:
749 return true;
750 default:
751 return gl::error(GL_INVALID_ENUM, false);
752 }
753 break;
754
755 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400756 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400757 switch (param)
758 {
759 case GL_LEQUAL:
760 case GL_GEQUAL:
761 case GL_LESS:
762 case GL_GREATER:
763 case GL_EQUAL:
764 case GL_NOTEQUAL:
765 case GL_ALWAYS:
766 case GL_NEVER:
767 return true;
768 default:
769 return gl::error(GL_INVALID_ENUM, false);
770 }
771 break;
772
773 case GL_TEXTURE_SWIZZLE_R:
774 case GL_TEXTURE_SWIZZLE_G:
775 case GL_TEXTURE_SWIZZLE_B:
776 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400777 switch (param)
778 {
779 case GL_RED:
780 case GL_GREEN:
781 case GL_BLUE:
782 case GL_ALPHA:
783 case GL_ZERO:
784 case GL_ONE:
785 return true;
786 default:
787 return gl::error(GL_INVALID_ENUM, false);
788 }
789 break;
790
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791 case GL_TEXTURE_BASE_LEVEL:
792 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400793 if (param < 0)
794 {
795 return gl::error(GL_INVALID_VALUE, false);
796 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400797 return true;
798
799 default:
800 return gl::error(GL_INVALID_ENUM, false);
801 }
802}
803
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400804bool ValidateSamplerObjectParameter(GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805{
806 switch (pname)
807 {
808 case GL_TEXTURE_MIN_FILTER:
809 case GL_TEXTURE_MAG_FILTER:
810 case GL_TEXTURE_WRAP_S:
811 case GL_TEXTURE_WRAP_T:
812 case GL_TEXTURE_WRAP_R:
813 case GL_TEXTURE_MIN_LOD:
814 case GL_TEXTURE_MAX_LOD:
815 case GL_TEXTURE_COMPARE_MODE:
816 case GL_TEXTURE_COMPARE_FUNC:
817 return true;
818
819 default:
820 return gl::error(GL_INVALID_ENUM, false);
821 }
822}
823
Jamie Madill26e91952014-03-05 15:01:27 -0500824bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
825 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
826{
827 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
828
829 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
830 {
831 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
832 }
833
834 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
835 {
836 return gl::error(GL_INVALID_OPERATION, false);
837 }
838
839 GLenum currentInternalFormat, currentFormat, currentType;
840 int clientVersion = context->getClientVersion();
841
842 // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
843 // and attempting to read back if that's the case is an error. The error will be registered
844 // by getCurrentReadFormat.
845 // Note: we need to explicitly check for framebuffer completeness here, before we call
846 // getCurrentReadFormatType, because it generates a different (wrong) error for incomplete FBOs
847 if (!context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType))
848 return false;
849
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400850 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
851 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500852
853 if (!(currentFormat == format && currentType == type) && !validReadFormat)
854 {
855 return gl::error(GL_INVALID_OPERATION, false);
856 }
857
858 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format :
859 GetSizedInternalFormat(format, type, clientVersion);
860
861 GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, clientVersion, width, context->getPackAlignment());
862 // sized query sanity check
863 if (bufSize)
864 {
865 int requiredSize = outputPitch * height;
866 if (requiredSize > *bufSize)
867 {
868 return gl::error(GL_INVALID_OPERATION, false);
869 }
870 }
871
872 return true;
873}
874
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400875}