Refactored entry point validation functions into their own files.

TRAC #23629

Signed-off-by: Nicolas Capens
Signed-off-by: Shannon Woods
Author: Geoff Lang
diff --git a/src/libGLESv2/validationES3.cpp b/src/libGLESv2/validationES3.cpp
new file mode 100644
index 0000000..8c6b531
--- /dev/null
+++ b/src/libGLESv2/validationES3.cpp
@@ -0,0 +1,852 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters
+
+#include "libGLESv2/validationES3.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/formatutils.h"
+#include "libGLESv2/main.h"
+
+#include "common/mathutil.h"
+
+namespace gl
+{
+
+static bool validImageSize(const gl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth)
+{
+    if (level < 0 || width < 0 || height < 0 || depth < 0)
+    {
+        return false;
+    }
+
+    if (context->supportsNonPower2Texture())
+    {
+        return true;
+    }
+
+    if (level == 0)
+    {
+        return true;
+    }
+
+    if (gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth))
+    {
+        return true;
+    }
+
+    return false;
+}
+
+static bool validCompressedImageSize(GLsizei width, GLsizei height)
+{
+    if (width != 1 && width != 2 && width % 4 != 0)
+    {
+        return false;
+    }
+
+    if (height != 1 && height != 2 && height % 4 != 0)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLint internalformat, bool isCompressed, bool isSubImage,
+                                   GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
+                                   GLint border, GLenum format, GLenum type)
+{
+    // Validate image size
+    if (!validImageSize(context, level, width, height, depth))
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    if (isCompressed && !validCompressedImageSize(width, height))
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    // Verify zero border
+    if (border != 0)
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    // Validate dimensions based on Context limits and validate the texture
+    if (level > context->getMaximumTextureLevel())
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    gl::Texture *texture = NULL;
+    bool textureCompressed = false;
+    GLenum textureInternalFormat = GL_NONE;
+    GLint textureLevelWidth = 0;
+    GLint textureLevelHeight = 0;
+    GLint textureLevelDepth = 0;
+    switch (target)
+    {
+      case GL_TEXTURE_2D:
+        {
+            if (width > (context->getMaximum2DTextureDimension() >> level) ||
+                height > (context->getMaximum2DTextureDimension() >> level))
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+
+            gl::Texture2D *texture2d = context->getTexture2D();
+            if (texture2d)
+            {
+                textureCompressed = texture2d->isCompressed(level);
+                textureInternalFormat = texture2d->getInternalFormat(level);
+                textureLevelWidth = texture2d->getWidth(level);
+                textureLevelHeight = texture2d->getHeight(level);
+                textureLevelDepth = 1;
+                texture = texture2d;
+            }
+        }
+        break;
+
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        {
+            if (!isSubImage && width != height)
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+
+            if (width > (context->getMaximumCubeTextureDimension() >> level))
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+
+            gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
+            if (textureCube)
+            {
+                textureCompressed = textureCube->isCompressed(target, level);
+                textureInternalFormat = textureCube->getInternalFormat(target, level);
+                textureLevelWidth = textureCube->getWidth(target, level);
+                textureLevelHeight = textureCube->getHeight(target, level);
+                textureLevelDepth = 1;
+                texture = textureCube;
+            }
+        }
+        break;
+
+      case GL_TEXTURE_3D:
+        {
+            if (width > (context->getMaximum3DTextureDimension() >> level) ||
+                height > (context->getMaximum3DTextureDimension() >> level) ||
+                depth > (context->getMaximum3DTextureDimension() >> level))
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+
+            gl::Texture3D *texture3d = context->getTexture3D();
+            if (texture3d)
+            {
+                textureCompressed = texture3d->isCompressed(level);
+                textureInternalFormat = texture3d->getInternalFormat(level);
+                textureLevelWidth = texture3d->getWidth(level);
+                textureLevelHeight = texture3d->getHeight(level);
+                textureLevelDepth = texture3d->getDepth(level);
+                texture = texture3d;
+            }
+        }
+        break;
+
+        case GL_TEXTURE_2D_ARRAY:
+          {
+              if (width > (context->getMaximum2DTextureDimension() >> level) ||
+                  height > (context->getMaximum2DTextureDimension() >> level) ||
+                  depth > (context->getMaximum2DArrayTextureLayers() >> level))
+              {
+                  return gl::error(GL_INVALID_VALUE, false);
+              }
+
+              gl::Texture2DArray *texture2darray = context->getTexture2DArray();
+              if (texture2darray)
+              {
+                  textureCompressed = texture2darray->isCompressed(level);
+                  textureInternalFormat = texture2darray->getInternalFormat(level);
+                  textureLevelWidth = texture2darray->getWidth(level);
+                  textureLevelHeight = texture2darray->getHeight(level);
+                  textureLevelDepth = texture2darray->getDepth(level);
+                  texture = texture2darray;
+              }
+          }
+          break;
+
+      default:
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    if (!texture)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    if (texture->isImmutable() && !isSubImage)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    // Validate texture formats
+    GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
+    if (isCompressed)
+    {
+        if (!gl::IsFormatCompressed(actualInternalFormat, context->getClientVersion()))
+        {
+            return gl::error(GL_INVALID_ENUM, false);
+        }
+
+        if (target == GL_TEXTURE_3D)
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+    }
+    else
+    {
+        if (!gl::IsValidInternalFormat(actualInternalFormat, context) ||
+            !gl::IsValidFormat(format, context->getClientVersion()) ||
+            !gl::IsValidType(type, context->getClientVersion()))
+        {
+            return gl::error(GL_INVALID_ENUM, false);
+        }
+
+        if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getClientVersion()))
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+
+        if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+    }
+
+    // Validate sub image parameters
+    if (isSubImage)
+    {
+        if (isCompressed != textureCompressed)
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+
+        if (format != GL_NONE)
+        {
+            GLenum internalformat = gl::GetSizedInternalFormat(format, type, context->getClientVersion());
+            if (internalformat != textureInternalFormat)
+            {
+                return gl::error(GL_INVALID_OPERATION, false);
+            }
+        }
+
+        if (isCompressed)
+        {
+            if ((width % 4 != 0 && width != textureLevelWidth) ||
+                (height % 4 != 0 && height != textureLevelHeight))
+            {
+                return gl::error(GL_INVALID_OPERATION, false);
+            }
+        }
+
+        if (width == 0 || height == 0 || depth == 0)
+        {
+            return false;
+        }
+
+        if (xoffset < 0 || yoffset < 0 || zoffset < 0)
+        {
+            return gl::error(GL_INVALID_VALUE, false);
+        }
+
+        if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
+            std::numeric_limits<GLsizei>::max() - yoffset < height ||
+            std::numeric_limits<GLsizei>::max() - zoffset < depth)
+        {
+            return gl::error(GL_INVALID_VALUE, false);
+        }
+
+        if (xoffset + width > textureLevelWidth ||
+            yoffset + height > textureLevelHeight ||
+            zoffset + depth > textureLevelDepth)
+        {
+            return gl::error(GL_INVALID_VALUE, false);
+        }
+    }
+
+    return true;
+}
+
+bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
+                                       bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
+                                       GLsizei width, GLsizei height, GLint border)
+{
+    if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    if (width == 0 || height == 0)
+    {
+        return false;
+    }
+
+    if (border != 0)
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    if (level > context->getMaximumTextureLevel())
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    gl::Framebuffer *framebuffer = context->getReadFramebuffer();
+
+    if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+    {
+        return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
+    }
+
+    if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
+    GLenum colorbufferInternalFormat = source->getInternalFormat();
+    gl::Texture *texture = NULL;
+    GLenum textureInternalFormat = GL_NONE;
+    bool textureCompressed = false;
+    bool textureIsDepth = false;
+    GLint textureLevelWidth = 0;
+    GLint textureLevelHeight = 0;
+    GLint textureLevelDepth = 0;
+    switch (target)
+    {
+      case GL_TEXTURE_2D:
+        {
+            gl::Texture2D *texture2d = context->getTexture2D();
+            if (texture2d)
+            {
+                textureInternalFormat = texture2d->getInternalFormat(level);
+                textureCompressed = texture2d->isCompressed(level);
+                textureIsDepth = texture2d->isDepth(level);
+                textureLevelWidth = texture2d->getWidth(level);
+                textureLevelHeight = texture2d->getHeight(level);
+                textureLevelDepth = 1;
+                texture = texture2d;
+            }
+        }
+        break;
+
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        {
+            gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
+            if (textureCube)
+            {
+                textureInternalFormat = textureCube->getInternalFormat(target, level);
+                textureCompressed = textureCube->isCompressed(target, level);
+                textureIsDepth = false;
+                textureLevelWidth = textureCube->getWidth(target, level);
+                textureLevelHeight = textureCube->getHeight(target, level);
+                textureLevelDepth = 1;
+                texture = textureCube;
+            }
+        }
+        break;
+
+      case GL_TEXTURE_2D_ARRAY:
+        {
+            gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
+            if (texture2dArray)
+            {
+                textureInternalFormat = texture2dArray->getInternalFormat(level);
+                textureCompressed = texture2dArray->isCompressed(level);
+                textureIsDepth = texture2dArray->isDepth(level);
+                textureLevelWidth = texture2dArray->getWidth(level);
+                textureLevelHeight = texture2dArray->getHeight(level);
+                textureLevelDepth = texture2dArray->getDepth(level);
+                texture = texture2dArray;
+            }
+        }
+        break;
+
+      case GL_TEXTURE_3D:
+        {
+            gl::Texture3D *texture3d = context->getTexture3D();
+            if (texture3d)
+            {
+                textureInternalFormat = texture3d->getInternalFormat(level);
+                textureCompressed = texture3d->isCompressed(level);
+                textureIsDepth = texture3d->isDepth(level);
+                textureLevelWidth = texture3d->getWidth(level);
+                textureLevelHeight = texture3d->getHeight(level);
+                textureLevelDepth = texture3d->getDepth(level);
+                texture = texture3d;
+            }
+        }
+        break;
+
+      default:
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    if (!texture)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    if (texture->isImmutable() && !isSubImage)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    if (textureIsDepth)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    if (textureCompressed)
+    {
+        if ((width % 4 != 0 && width != textureLevelWidth) ||
+            (height % 4 != 0 && height != textureLevelHeight))
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+    }
+
+    if (isSubImage)
+    {
+        if (xoffset + width > textureLevelWidth ||
+            yoffset + height > textureLevelHeight ||
+            zoffset >= textureLevelDepth)
+        {
+            return gl::error(GL_INVALID_VALUE, false);
+        }
+
+        if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
+                                                context->getClientVersion()))
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+    }
+
+    return true;
+}
+
+bool validateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
+                                     GLsizei width, GLsizei height, GLsizei depth)
+{
+    if (width < 1 || height < 1 || depth < 1 || levels < 1)
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    gl::Texture *texture = NULL;
+    switch (target)
+    {
+      case GL_TEXTURE_2D:
+        {
+            texture = context->getTexture2D();
+
+            if (width > (context->getMaximum2DTextureDimension()) ||
+                height > (context->getMaximum2DTextureDimension()))
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+        }
+        break;
+
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        {
+            texture = context->getTextureCubeMap();
+
+            if (width != height)
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+
+            if (width > (context->getMaximumCubeTextureDimension()))
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+        }
+        break;
+
+      case GL_TEXTURE_3D:
+        {
+            texture = context->getTexture3D();
+
+            if (width > (context->getMaximum3DTextureDimension()) ||
+                height > (context->getMaximum3DTextureDimension()) ||
+                depth > (context->getMaximum3DTextureDimension()))
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+        }
+        break;
+
+      case GL_TEXTURE_2D_ARRAY:
+        {
+            texture = context->getTexture2DArray();
+
+            if (width > (context->getMaximum2DTextureDimension()) ||
+                height > (context->getMaximum2DTextureDimension()) ||
+                depth > (context->getMaximum2DArrayTextureLayers()))
+            {
+                return gl::error(GL_INVALID_VALUE, false);
+            }
+        }
+        break;
+
+      default:
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    if (!texture || texture->id() == 0)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    if (texture->isImmutable())
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    if (!gl::IsValidInternalFormat(internalformat, context))
+    {
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
+    {
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    return true;
+}
+
+bool validateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
+                                             GLenum textarget, GLuint texture, GLint level, GLint layer,
+                                             bool layerCall)
+{
+    if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
+    {
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
+    {
+        const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
+        if (colorAttachment >= context->getMaximumRenderTargets())
+        {
+            return gl::error(GL_INVALID_VALUE, false);
+        }
+    }
+    else
+    {
+        switch (attachment)
+        {
+          case GL_DEPTH_ATTACHMENT:
+          case GL_STENCIL_ATTACHMENT:
+          case GL_DEPTH_STENCIL_ATTACHMENT:
+            break;
+          default:
+            return gl::error(GL_INVALID_ENUM, false);
+        }
+    }
+
+    if (texture != 0)
+    {
+        gl::Texture *tex = context->getTexture(texture);
+
+        if (tex == NULL)
+        {
+            return gl::error(GL_INVALID_OPERATION, false);
+        }
+
+        if (level < 0)
+        {
+            return gl::error(GL_INVALID_VALUE, false);
+        }
+
+        if (layer < 0)
+        {
+            return gl::error(GL_INVALID_VALUE, false);
+        }
+
+        if (!layerCall)
+        {
+            switch (textarget)
+            {
+              case GL_TEXTURE_2D:
+                {
+                    if (level > gl::log2(context->getMaximum2DTextureDimension()))
+                    {
+                        return gl::error(GL_INVALID_VALUE, false);
+                    }
+                    if (tex->getTarget() != GL_TEXTURE_2D)
+                    {
+                        return gl::error(GL_INVALID_OPERATION, false);
+                    }
+                    gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
+                    if (tex2d->isCompressed(level))
+                    {
+                        return gl::error(GL_INVALID_OPERATION, false);
+                    }
+                    break;
+                }
+
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+                {
+                    if (level > gl::log2(context->getMaximumCubeTextureDimension()))
+                    {
+                        return gl::error(GL_INVALID_VALUE, false);
+                    }
+                    if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
+                    {
+                        return gl::error(GL_INVALID_OPERATION, false);
+                    }
+                    gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
+                    if (texcube->isCompressed(textarget, level))
+                    {
+                        return gl::error(GL_INVALID_OPERATION, false);
+                    }
+                    break;
+                }
+
+              default:
+                return gl::error(GL_INVALID_ENUM, false);
+            }
+        }
+        else
+        {
+            switch (tex->getTarget())
+            {
+              case GL_TEXTURE_2D_ARRAY:
+                {
+                    if (level > gl::log2(context->getMaximum2DTextureDimension()))
+                    {
+                        return gl::error(GL_INVALID_VALUE, false);
+                    }
+
+                    if (layer >= context->getMaximum2DArrayTextureLayers())
+                    {
+                        return gl::error(GL_INVALID_VALUE, false);
+                    }
+
+                    gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
+                    if (texArray->isCompressed(level))
+                    {
+                        return gl::error(GL_INVALID_OPERATION, false);
+                    }
+
+                    break;
+                }
+
+              case GL_TEXTURE_3D:
+                {
+                    if (level > gl::log2(context->getMaximum3DTextureDimension()))
+                    {
+                        return gl::error(GL_INVALID_VALUE, false);
+                    }
+
+                    if (layer >= context->getMaximum3DTextureDimension())
+                    {
+                        return gl::error(GL_INVALID_VALUE, false);
+                    }
+
+                    gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
+                    if (tex3d->isCompressed(level))
+                    {
+                        return gl::error(GL_INVALID_OPERATION, false);
+                    }
+
+                    break;
+                }
+
+              default:
+                return gl::error(GL_INVALID_OPERATION, false);
+            }
+        }
+    }
+
+    gl::Framebuffer *framebuffer = NULL;
+    GLuint framebufferHandle = 0;
+    if (target == GL_READ_FRAMEBUFFER)
+    {
+        framebuffer = context->getReadFramebuffer();
+        framebufferHandle = context->getReadFramebufferHandle();
+    }
+    else
+    {
+        framebuffer = context->getDrawFramebuffer();
+        framebufferHandle = context->getDrawFramebufferHandle();
+    }
+
+    if (framebufferHandle == 0 || !framebuffer)
+    {
+        return gl::error(GL_INVALID_OPERATION, false);
+    }
+
+    return true;
+}
+
+bool validES3ReadFormatType(GLenum internalFormat, GLenum format, GLenum type)
+{
+    switch (format)
+    {
+      case GL_RGBA:
+        switch (type)
+        {
+          case GL_UNSIGNED_BYTE:
+            break;
+          case GL_UNSIGNED_INT_2_10_10_10_REV:
+            if (internalFormat != GL_RGB10_A2)
+            {
+                return false;
+            }
+            break;
+          default:
+            return false;
+        }
+        break;
+      case GL_RGBA_INTEGER:
+        switch (type)
+        {
+          case GL_INT:
+            if (!gl::IsSignedIntegerFormat(internalFormat, 3))
+            {
+                return false;
+            }
+            break;
+          case GL_UNSIGNED_INT:
+            if (!gl::IsUnsignedIntegerFormat(internalFormat, 3))
+            {
+                return false;
+            }
+            break;
+          default:
+            return false;
+        }
+        break;
+      case GL_BGRA_EXT:
+        switch (type)
+        {
+          case GL_UNSIGNED_BYTE:
+          case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
+          case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
+            break;
+          default:
+            return false;
+        }
+        break;
+      default:
+        return false;
+    }
+    return true;
+}
+
+bool validateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
+                                             const GLenum* attachments)
+{
+    bool defaultFramebuffer = false;
+
+    switch (target)
+    {
+      case GL_DRAW_FRAMEBUFFER:
+      case GL_FRAMEBUFFER:
+        defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
+        break;
+      case GL_READ_FRAMEBUFFER:
+        defaultFramebuffer = context->getReadFramebufferHandle() == 0;
+        break;
+      default:
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    for (int i = 0; i < numAttachments; ++i)
+    {
+        if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
+        {
+            if (defaultFramebuffer)
+            {
+                return gl::error(GL_INVALID_ENUM, false);
+            }
+
+            if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
+            {
+                return gl::error(GL_INVALID_OPERATION, false);
+            }
+        }
+        else
+        {
+            switch (attachments[i])
+            {
+              case GL_DEPTH_ATTACHMENT:
+              case GL_STENCIL_ATTACHMENT:
+              case GL_DEPTH_STENCIL_ATTACHMENT:
+                if (defaultFramebuffer)
+                {
+                    return gl::error(GL_INVALID_ENUM, false);
+                }
+                break;
+              case GL_COLOR:
+              case GL_DEPTH:
+              case GL_STENCIL:
+                if (!defaultFramebuffer)
+                {
+                    return gl::error(GL_INVALID_ENUM, false);
+                }
+                break;
+              default:
+                return gl::error(GL_INVALID_ENUM, false);
+            }
+        }
+    }
+
+    return true;
+}
+
+}