1 #include "precompiled.h"
3 // Copyright (c) 2013-2014 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.
8 // validationES.h: Validation functions for generic OpenGL ES entry point parameters
10 #include "libGLESv2/validationES.h"
11 #include "libGLESv2/validationES2.h"
12 #include "libGLESv2/validationES3.h"
13 #include "libGLESv2/Context.h"
14 #include "libGLESv2/Texture.h"
15 #include "libGLESv2/Framebuffer.h"
16 #include "libGLESv2/FramebufferAttachment.h"
17 #include "libGLESv2/formatutils.h"
18 #include "libGLESv2/main.h"
19 #include "libGLESv2/Query.h"
20 #include "libGLESv2/ProgramBinary.h"
21 #include "libGLESv2/TransformFeedback.h"
22 #include "libGLESv2/VertexArray.h"
24 #include "common/mathutil.h"
25 #include "common/utilities.h"
30 bool ValidCap(const Context *context, GLenum cap)
35 case GL_POLYGON_OFFSET_FILL:
36 case GL_SAMPLE_ALPHA_TO_COVERAGE:
37 case GL_SAMPLE_COVERAGE:
44 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
45 case GL_RASTERIZER_DISCARD:
46 return (context->getClientVersion() >= 3);
52 bool ValidTextureTarget(const Context *context, GLenum target)
57 case GL_TEXTURE_CUBE_MAP:
61 case GL_TEXTURE_2D_ARRAY:
62 return (context->getClientVersion() >= 3);
69 // This function differs from ValidTextureTarget in that the target must be
70 // usable as the destination of a 2D operation-- so a cube face is valid, but
71 // GL_TEXTURE_CUBE_MAP is not.
72 // Note: duplicate of IsInternalTextureTarget
73 bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
78 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
79 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
80 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
81 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
82 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
83 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
85 case GL_TEXTURE_2D_ARRAY:
87 return (context->getClientVersion() >= 3);
93 bool ValidFramebufferTarget(GLenum target)
95 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
99 case GL_FRAMEBUFFER: return true;
100 case GL_READ_FRAMEBUFFER: return true;
101 case GL_DRAW_FRAMEBUFFER: return true;
102 default: return false;
106 bool ValidBufferTarget(const Context *context, GLenum target)
110 case GL_ARRAY_BUFFER:
111 case GL_ELEMENT_ARRAY_BUFFER:
114 case GL_PIXEL_PACK_BUFFER:
115 case GL_PIXEL_UNPACK_BUFFER:
116 return context->getExtensions().pixelBufferObject;
118 case GL_COPY_READ_BUFFER:
119 case GL_COPY_WRITE_BUFFER:
120 case GL_TRANSFORM_FEEDBACK_BUFFER:
121 case GL_UNIFORM_BUFFER:
122 return (context->getClientVersion() >= 3);
129 bool ValidBufferParameter(const Context *context, GLenum pname)
133 case GL_BUFFER_USAGE:
137 // GL_BUFFER_MAP_POINTER is a special case, and may only be
138 // queried with GetBufferPointerv
139 case GL_BUFFER_ACCESS_FLAGS:
140 case GL_BUFFER_MAPPED:
141 case GL_BUFFER_MAP_OFFSET:
142 case GL_BUFFER_MAP_LENGTH:
143 return (context->getClientVersion() >= 3);
150 bool ValidMipLevel(const Context *context, GLenum target, GLint level)
152 size_t maxDimension = 0;
155 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
156 case GL_TEXTURE_CUBE_MAP:
157 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
158 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
159 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
160 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
161 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
162 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
163 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
164 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
165 default: UNREACHABLE();
168 return level <= gl::log2(maxDimension);
171 bool ValidImageSize(const gl::Context *context, GLenum target, GLint level,
172 GLsizei width, GLsizei height, GLsizei depth)
174 if (level < 0 || width < 0 || height < 0 || depth < 0)
179 if (!context->getExtensions().textureNPOT &&
180 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
185 if (!ValidMipLevel(context, target, level))
193 bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
195 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
196 if (!formatInfo.compressed)
201 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
202 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
210 bool ValidQueryType(const Context *context, GLenum queryType)
212 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
213 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
217 case GL_ANY_SAMPLES_PASSED:
218 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
220 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
221 return (context->getClientVersion() >= 3);
227 bool ValidProgram(const Context *context, GLuint id)
229 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
230 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
231 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
233 if (context->getProgram(id) != NULL)
237 else if (context->getShader(id) != NULL)
239 // ID is the wrong type
240 return gl::error(GL_INVALID_OPERATION, false);
244 // No shader/program object has this ID
245 return gl::error(GL_INVALID_VALUE, false);
249 bool ValidateAttachmentTarget(const gl::Context *context, GLenum attachment)
251 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
253 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
255 if (colorAttachment >= context->getCaps().maxColorAttachments)
257 return gl::error(GL_INVALID_VALUE, false);
264 case GL_DEPTH_ATTACHMENT:
265 case GL_STENCIL_ATTACHMENT:
268 case GL_DEPTH_STENCIL_ATTACHMENT:
269 if (context->getClientVersion() < 3)
271 return gl::error(GL_INVALID_ENUM, false);
276 return gl::error(GL_INVALID_ENUM, false);
283 bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
284 GLenum internalformat, GLsizei width, GLsizei height,
289 case GL_RENDERBUFFER:
292 return gl::error(GL_INVALID_ENUM, false);
295 if (width < 0 || height < 0 || samples < 0)
297 return gl::error(GL_INVALID_VALUE, false);
300 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
301 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
303 return gl::error(GL_INVALID_ENUM, false);
306 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
307 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
308 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
309 // internal format must be sized and not an integer format if samples is greater than zero.
310 if (formatInfo.pixelBytes == 0)
312 return gl::error(GL_INVALID_ENUM, false);
315 if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
317 return gl::error(GL_INVALID_OPERATION, false);
320 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
321 if (!formatCaps.renderable)
323 return gl::error(GL_INVALID_ENUM, false);
326 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
328 return gl::error(GL_INVALID_VALUE, false);
331 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
332 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
333 // states that samples must be less than or equal to the maximum samples for the specified
337 ASSERT(context->getExtensions().framebufferMultisample);
338 if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
340 return gl::error(GL_INVALID_VALUE, false);
343 // Check if this specific format supports enough samples
344 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
346 return gl::error(GL_OUT_OF_MEMORY, false);
351 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
353 return gl::error(GL_INVALID_VALUE, false);
357 GLuint handle = context->getState().getRenderbufferId();
360 return gl::error(GL_INVALID_OPERATION, false);
366 bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
367 GLenum renderbuffertarget, GLuint renderbuffer)
369 if (!ValidFramebufferTarget(target))
371 return gl::error(GL_INVALID_ENUM, false);
374 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
375 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
377 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
379 return gl::error(GL_INVALID_OPERATION, false);
382 if (!ValidateAttachmentTarget(context, attachment))
387 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
388 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
389 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
390 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
391 if (renderbuffer != 0)
393 if (!context->getRenderbuffer(renderbuffer))
395 return gl::error(GL_INVALID_OPERATION, false);
402 static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
403 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
404 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
406 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
407 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
408 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
412 else if (context->getState().isScissorTestEnabled())
414 const Rectangle &scissor = context->getState().getScissor();
416 return scissor.x > 0 || scissor.y > 0 ||
417 scissor.width < writeBuffer->getWidth() ||
418 scissor.height < writeBuffer->getHeight();
426 bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
427 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
428 GLenum filter, bool fromAngleExtension)
435 if (fromAngleExtension)
437 return gl::error(GL_INVALID_ENUM, false);
441 return gl::error(GL_INVALID_ENUM, false);
444 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
446 return gl::error(GL_INVALID_VALUE, false);
451 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
452 // buffers are copied.
456 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
458 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
459 return gl::error(GL_INVALID_OPERATION, false);
462 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
463 // color buffer, leaving only nearest being unfiltered from above
464 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
466 return gl::error(GL_INVALID_OPERATION, false);
469 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
471 if (fromAngleExtension)
473 ERR("Blits with the same source and destination framebuffer are not supported by this "
476 return gl::error(GL_INVALID_OPERATION, false);
479 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
480 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
481 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
482 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
484 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
487 if (drawFramebuffer->getSamples() != 0)
489 return gl::error(GL_INVALID_OPERATION, false);
492 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
494 if (mask & GL_COLOR_BUFFER_BIT)
496 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
497 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
499 if (readColorBuffer && drawColorBuffer)
501 GLenum readInternalFormat = readColorBuffer->getActualFormat();
502 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
504 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
506 if (drawFramebuffer->isEnabledColorAttachment(i))
508 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
509 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
511 // The GL ES 3.0.2 spec (pg 193) states that:
512 // 1) If the read buffer is fixed point format, the draw buffer must be as well
513 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
514 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
515 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
516 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
518 return gl::error(GL_INVALID_OPERATION, false);
521 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
523 return gl::error(GL_INVALID_OPERATION, false);
526 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
528 return gl::error(GL_INVALID_OPERATION, false);
531 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
533 return gl::error(GL_INVALID_OPERATION, false);
538 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
540 return gl::error(GL_INVALID_OPERATION, false);
543 if (fromAngleExtension)
545 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
546 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
548 return gl::error(GL_INVALID_OPERATION, false);
551 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
553 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
555 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
558 if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
560 return gl::error(GL_INVALID_OPERATION, false);
563 if (attachment->getActualFormat() != readColorBuffer->getActualFormat())
565 return gl::error(GL_INVALID_OPERATION, false);
569 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
570 srcX0, srcY0, srcX1, srcY1,
571 dstX0, dstY0, dstX1, dstY1))
573 return gl::error(GL_INVALID_OPERATION, false);
579 if (mask & GL_DEPTH_BUFFER_BIT)
581 gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
582 gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
584 if (readDepthBuffer && drawDepthBuffer)
586 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
588 return gl::error(GL_INVALID_OPERATION, false);
591 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
593 return gl::error(GL_INVALID_OPERATION, false);
596 if (fromAngleExtension)
598 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
599 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
601 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
602 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
605 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
607 return gl::error(GL_INVALID_OPERATION, false);
613 if (mask & GL_STENCIL_BUFFER_BIT)
615 gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
616 gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
618 if (readStencilBuffer && drawStencilBuffer)
620 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
622 return gl::error(GL_INVALID_OPERATION, false);
625 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
627 return gl::error(GL_INVALID_OPERATION, false);
630 if (fromAngleExtension)
632 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
633 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
635 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
636 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
639 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
641 return gl::error(GL_INVALID_OPERATION, false);
650 bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
654 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
655 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
656 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
657 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
658 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
659 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
660 case GL_CURRENT_VERTEX_ATTRIB:
663 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
664 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
665 // the same constant.
666 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
669 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
670 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
673 return gl::error(GL_INVALID_ENUM, false);
677 bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
681 case GL_TEXTURE_WRAP_R:
682 case GL_TEXTURE_SWIZZLE_R:
683 case GL_TEXTURE_SWIZZLE_G:
684 case GL_TEXTURE_SWIZZLE_B:
685 case GL_TEXTURE_SWIZZLE_A:
686 case GL_TEXTURE_BASE_LEVEL:
687 case GL_TEXTURE_MAX_LEVEL:
688 case GL_TEXTURE_COMPARE_MODE:
689 case GL_TEXTURE_COMPARE_FUNC:
690 case GL_TEXTURE_MIN_LOD:
691 case GL_TEXTURE_MAX_LOD:
692 if (context->getClientVersion() < 3)
694 return gl::error(GL_INVALID_ENUM, false);
703 case GL_TEXTURE_WRAP_S:
704 case GL_TEXTURE_WRAP_T:
705 case GL_TEXTURE_WRAP_R:
709 case GL_CLAMP_TO_EDGE:
710 case GL_MIRRORED_REPEAT:
713 return gl::error(GL_INVALID_ENUM, false);
716 case GL_TEXTURE_MIN_FILTER:
721 case GL_NEAREST_MIPMAP_NEAREST:
722 case GL_LINEAR_MIPMAP_NEAREST:
723 case GL_NEAREST_MIPMAP_LINEAR:
724 case GL_LINEAR_MIPMAP_LINEAR:
727 return gl::error(GL_INVALID_ENUM, false);
731 case GL_TEXTURE_MAG_FILTER:
738 return gl::error(GL_INVALID_ENUM, false);
742 case GL_TEXTURE_USAGE_ANGLE:
746 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
749 return gl::error(GL_INVALID_ENUM, false);
753 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
754 if (!context->getExtensions().textureFilterAnisotropic)
756 return gl::error(GL_INVALID_ENUM, false);
759 // we assume the parameter passed to this validation method is truncated, not rounded
762 return gl::error(GL_INVALID_VALUE, false);
766 case GL_TEXTURE_MIN_LOD:
767 case GL_TEXTURE_MAX_LOD:
768 // any value is permissible
771 case GL_TEXTURE_COMPARE_MODE:
772 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
776 case GL_COMPARE_REF_TO_TEXTURE:
779 return gl::error(GL_INVALID_ENUM, false);
783 case GL_TEXTURE_COMPARE_FUNC:
784 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
797 return gl::error(GL_INVALID_ENUM, false);
801 case GL_TEXTURE_SWIZZLE_R:
802 case GL_TEXTURE_SWIZZLE_G:
803 case GL_TEXTURE_SWIZZLE_B:
804 case GL_TEXTURE_SWIZZLE_A:
815 return gl::error(GL_INVALID_ENUM, false);
819 case GL_TEXTURE_BASE_LEVEL:
820 case GL_TEXTURE_MAX_LEVEL:
823 return gl::error(GL_INVALID_VALUE, false);
828 return gl::error(GL_INVALID_ENUM, false);
832 bool ValidateSamplerObjectParameter(GLenum pname)
836 case GL_TEXTURE_MIN_FILTER:
837 case GL_TEXTURE_MAG_FILTER:
838 case GL_TEXTURE_WRAP_S:
839 case GL_TEXTURE_WRAP_T:
840 case GL_TEXTURE_WRAP_R:
841 case GL_TEXTURE_MIN_LOD:
842 case GL_TEXTURE_MAX_LOD:
843 case GL_TEXTURE_COMPARE_MODE:
844 case GL_TEXTURE_COMPARE_FUNC:
848 return gl::error(GL_INVALID_ENUM, false);
852 bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
853 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
855 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
858 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
860 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
863 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
865 return gl::error(GL_INVALID_OPERATION, false);
868 if (!framebuffer->getReadColorbuffer())
870 return gl::error(GL_INVALID_OPERATION, false);
873 GLenum currentInternalFormat, currentFormat, currentType;
874 GLuint clientVersion = context->getClientVersion();
876 context->getCurrentReadFormatType(¤tInternalFormat, ¤tFormat, ¤tType);
878 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
879 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
881 if (!(currentFormat == format && currentType == type) && !validReadFormat)
883 return gl::error(GL_INVALID_OPERATION, false);
886 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
887 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
889 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
890 // sized query sanity check
893 int requiredSize = outputPitch * height;
894 if (requiredSize > *bufSize)
896 return gl::error(GL_INVALID_OPERATION, false);
903 bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
905 if (!ValidQueryType(context, target))
907 return gl::error(GL_INVALID_ENUM, false);
912 return gl::error(GL_INVALID_OPERATION, false);
915 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
916 // of zero, if the active query object name for <target> is non-zero (for the
917 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
918 // the active query for either target is non-zero), if <id> is the name of an
919 // existing query object whose type does not match <target>, or if <id> is the
920 // active query object name for any query type, the error INVALID_OPERATION is
923 // Ensure no other queries are active
924 // NOTE: If other queries than occlusion are supported, we will need to check
926 // a) The query ID passed is not the current active query for any target/type
927 // b) There are no active queries for the requested target (and in the case
928 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
929 // no query may be active for either if glBeginQuery targets either.
930 if (context->getState().isQueryActive())
932 return gl::error(GL_INVALID_OPERATION, false);
935 Query *queryObject = context->getQuery(id, true, target);
937 // check that name was obtained with glGenQueries
940 return gl::error(GL_INVALID_OPERATION, false);
943 // check for type mismatch
944 if (queryObject->getType() != target)
946 return gl::error(GL_INVALID_OPERATION, false);
952 bool ValidateEndQuery(gl::Context *context, GLenum target)
954 if (!ValidQueryType(context, target))
956 return gl::error(GL_INVALID_ENUM, false);
959 const Query *queryObject = context->getState().getActiveQuery(target);
961 if (queryObject == NULL)
963 return gl::error(GL_INVALID_OPERATION, false);
966 if (!queryObject->isStarted())
968 return gl::error(GL_INVALID_OPERATION, false);
974 static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
975 GLint location, GLsizei count, LinkedUniform **uniformOut)
979 return gl::error(GL_INVALID_VALUE, false);
982 gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
985 return gl::error(GL_INVALID_OPERATION, false);
990 // Silently ignore the uniform command
994 if (!programBinary->isValidUniformLocation(location))
996 return gl::error(GL_INVALID_OPERATION, false);
999 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1001 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1002 if (uniform->elementCount() == 1 && count > 1)
1004 return gl::error(GL_INVALID_OPERATION, false);
1007 *uniformOut = uniform;
1011 bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1013 // Check for ES3 uniform entry points
1014 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
1016 return gl::error(GL_INVALID_OPERATION, false);
1019 LinkedUniform *uniform = NULL;
1020 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1025 GLenum targetBoolType = VariableBoolVectorType(uniformType);
1026 bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1027 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1029 return gl::error(GL_INVALID_OPERATION, false);
1035 bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1036 GLboolean transpose)
1038 // Check for ES3 uniform entry points
1039 int rows = VariableRowCount(matrixType);
1040 int cols = VariableColumnCount(matrixType);
1041 if (rows != cols && context->getClientVersion() < 3)
1043 return gl::error(GL_INVALID_OPERATION, false);
1046 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1048 return gl::error(GL_INVALID_VALUE, false);
1051 LinkedUniform *uniform = NULL;
1052 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1057 if (uniform->type != matrixType)
1059 return gl::error(GL_INVALID_OPERATION, false);
1065 bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1067 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1069 return gl::error(GL_INVALID_ENUM, false);
1072 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1074 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1076 if (colorAttachment >= context->getCaps().maxDrawBuffers)
1078 return gl::error(GL_INVALID_OPERATION, false);
1084 case GL_TEXTURE_BINDING_2D:
1085 case GL_TEXTURE_BINDING_CUBE_MAP:
1086 case GL_TEXTURE_BINDING_3D:
1087 case GL_TEXTURE_BINDING_2D_ARRAY:
1088 if (context->getState().getActiveSampler() >= context->getMaximumCombinedTextureImageUnits())
1090 return gl::error(GL_INVALID_OPERATION, false);
1094 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1095 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1097 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
1098 ASSERT(framebuffer);
1099 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1101 return gl::error(GL_INVALID_OPERATION, false);
1104 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1107 return gl::error(GL_INVALID_OPERATION, false);
1116 // pname is valid, but there are no parameters to return
1125 bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1126 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1127 GLint border, GLenum *textureFormatOut)
1130 if (!ValidTexture2DDestinationTarget(context, target))
1132 return gl::error(GL_INVALID_ENUM, false);
1135 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1137 return gl::error(GL_INVALID_VALUE, false);
1140 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1142 return gl::error(GL_INVALID_VALUE, false);
1147 return gl::error(GL_INVALID_VALUE, false);
1150 if (!ValidMipLevel(context, target, level))
1152 return gl::error(GL_INVALID_VALUE, false);
1155 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
1156 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1158 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
1161 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
1163 return gl::error(GL_INVALID_OPERATION, false);
1166 const gl::Caps &caps = context->getCaps();
1168 gl::Texture *texture = NULL;
1169 GLenum textureInternalFormat = GL_NONE;
1170 GLint textureLevelWidth = 0;
1171 GLint textureLevelHeight = 0;
1172 GLint textureLevelDepth = 0;
1173 GLuint maxDimension = 0;
1179 gl::Texture2D *texture2d = context->getTexture2D();
1182 textureInternalFormat = texture2d->getInternalFormat(level);
1183 textureLevelWidth = texture2d->getWidth(level);
1184 textureLevelHeight = texture2d->getHeight(level);
1185 textureLevelDepth = 1;
1186 texture = texture2d;
1187 maxDimension = caps.max2DTextureSize;
1192 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1193 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1194 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1195 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1196 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1197 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1199 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1202 textureInternalFormat = textureCube->getInternalFormat(target, level);
1203 textureLevelWidth = textureCube->getWidth(target, level);
1204 textureLevelHeight = textureCube->getHeight(target, level);
1205 textureLevelDepth = 1;
1206 texture = textureCube;
1207 maxDimension = caps.maxCubeMapTextureSize;
1212 case GL_TEXTURE_2D_ARRAY:
1214 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1217 textureInternalFormat = texture2dArray->getInternalFormat(level);
1218 textureLevelWidth = texture2dArray->getWidth(level);
1219 textureLevelHeight = texture2dArray->getHeight(level);
1220 textureLevelDepth = texture2dArray->getLayers(level);
1221 texture = texture2dArray;
1222 maxDimension = caps.max2DTextureSize;
1229 gl::Texture3D *texture3d = context->getTexture3D();
1232 textureInternalFormat = texture3d->getInternalFormat(level);
1233 textureLevelWidth = texture3d->getWidth(level);
1234 textureLevelHeight = texture3d->getHeight(level);
1235 textureLevelDepth = texture3d->getDepth(level);
1236 texture = texture3d;
1237 maxDimension = caps.max3DTextureSize;
1243 return gl::error(GL_INVALID_ENUM, false);
1248 return gl::error(GL_INVALID_OPERATION, false);
1251 if (texture->isImmutable() && !isSubImage)
1253 return gl::error(GL_INVALID_OPERATION, false);
1256 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1258 if (formatInfo.depthBits > 0)
1260 return gl::error(GL_INVALID_OPERATION, false);
1263 if (formatInfo.compressed)
1265 if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1266 ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
1268 return gl::error(GL_INVALID_OPERATION, false);
1274 if (xoffset + width > textureLevelWidth ||
1275 yoffset + height > textureLevelHeight ||
1276 zoffset >= textureLevelDepth)
1278 return gl::error(GL_INVALID_VALUE, false);
1283 if (IsCubemapTextureTarget(target) && width != height)
1285 return gl::error(GL_INVALID_VALUE, false);
1288 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
1290 return gl::error(GL_INVALID_ENUM, false);
1293 int maxLevelDimension = (maxDimension >> level);
1294 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1296 return gl::error(GL_INVALID_VALUE, false);
1300 *textureFormatOut = textureInternalFormat;
1304 static bool ValidateDrawBase(const gl::State &state, GLenum mode, GLsizei count)
1313 case GL_TRIANGLE_STRIP:
1314 case GL_TRIANGLE_FAN:
1317 return gl::error(GL_INVALID_ENUM, false);
1322 return gl::error(GL_INVALID_VALUE, false);
1325 // Check for mapped buffers
1326 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
1328 return gl::error(GL_INVALID_OPERATION, false);
1331 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
1332 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
1333 state.getStencilRef() != state.getStencilBackRef() ||
1334 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1336 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1337 // See Section 6.10 of the WebGL 1.0 spec
1338 ERR("This ANGLE implementation does not support separate front/back stencil "
1339 "writemasks, reference values, or stencil mask values.");
1340 return gl::error(GL_INVALID_OPERATION, false);
1343 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
1344 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
1346 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
1349 if (state.getCurrentProgramId() == 0)
1351 return gl::error(GL_INVALID_OPERATION, false);
1354 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
1355 if (!programBinary->validateSamplers(NULL))
1357 return gl::error(GL_INVALID_OPERATION, false);
1360 // No-op if zero count
1364 bool ValidateDrawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count)
1368 return gl::error(GL_INVALID_VALUE, false);
1371 const State &state = context->getState();
1372 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
1373 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1374 curTransformFeedback->getDrawMode() != mode)
1376 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1377 // that does not match the current transform feedback object's draw mode (if transform feedback
1378 // is active), (3.0.2, section 2.14, pg 86)
1379 return gl::error(GL_INVALID_OPERATION, false);
1382 if (!ValidateDrawBase(state, mode, count))
1390 bool ValidateDrawArraysInstanced(const gl::Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1394 return gl::error(GL_INVALID_VALUE, false);
1397 if (!ValidateDrawArrays(context, mode, first, count))
1402 // No-op if zero primitive count
1403 return (primcount > 0);
1406 bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
1410 case GL_UNSIGNED_BYTE:
1411 case GL_UNSIGNED_SHORT:
1413 case GL_UNSIGNED_INT:
1414 if (!context->getExtensions().elementIndexUint)
1416 return gl::error(GL_INVALID_ENUM, false);
1420 return gl::error(GL_INVALID_ENUM, false);
1423 const State &state = context->getState();
1425 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
1426 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1428 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1429 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
1430 return gl::error(GL_INVALID_OPERATION, false);
1433 // Check for mapped buffers
1434 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
1436 return gl::error(GL_INVALID_OPERATION, false);
1439 gl::VertexArray *vao = state.getVertexArray();
1440 if (!indices && !vao->getElementArrayBuffer())
1442 return gl::error(GL_INVALID_OPERATION, false);
1445 if (!ValidateDrawBase(state, mode, count))
1453 bool ValidateDrawElementsInstanced(const gl::Context *context, GLenum mode, GLsizei count, GLenum type,
1454 const GLvoid *indices, GLsizei primcount)
1458 return gl::error(GL_INVALID_VALUE, false);
1461 if (!ValidateDrawElements(context, mode, count, type, indices))
1466 // No-op zero primitive count
1467 return (primcount > 0);
1470 bool ValidateFramebufferTextureBase(const gl::Context *context, GLenum target, GLenum attachment,
1471 GLuint texture, GLint level)
1473 if (!ValidFramebufferTarget(target))
1475 return gl::error(GL_INVALID_ENUM, false);
1478 if (!ValidateAttachmentTarget(context, attachment))
1485 gl::Texture *tex = context->getTexture(texture);
1489 return gl::error(GL_INVALID_OPERATION, false);
1494 return gl::error(GL_INVALID_VALUE, false);
1498 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1499 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
1501 if (framebufferHandle == 0 || !framebuffer)
1503 return gl::error(GL_INVALID_OPERATION, false);
1509 bool ValidateFramebufferTexture2D(const gl::Context *context, GLenum target, GLenum attachment,
1510 GLenum textarget, GLuint texture, GLint level)
1512 // Attachments are required to be bound to level 0 in ES2
1513 if (context->getClientVersion() < 3 && level != 0)
1515 return gl::error(GL_INVALID_VALUE, false);
1518 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
1525 gl::Texture *tex = context->getTexture(texture);
1528 const gl::Caps &caps = context->getCaps();
1534 if (level > gl::log2(caps.max2DTextureSize))
1536 return gl::error(GL_INVALID_VALUE, false);
1538 if (tex->getTarget() != GL_TEXTURE_2D)
1540 return gl::error(GL_INVALID_OPERATION, false);
1542 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1543 if (tex2d->isCompressed(level))
1545 return gl::error(GL_INVALID_OPERATION, false);
1550 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1551 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1552 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1553 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1554 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1555 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1557 if (level > gl::log2(caps.maxCubeMapTextureSize))
1559 return gl::error(GL_INVALID_VALUE, false);
1561 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1563 return gl::error(GL_INVALID_OPERATION, false);
1565 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1566 if (texcube->isCompressed(textarget, level))
1568 return gl::error(GL_INVALID_OPERATION, false);
1574 return gl::error(GL_INVALID_ENUM, false);