Refactor CopyTexImage validation.

Move the common validation code to a shared base function.

BUG=angle:571

Change-Id: Id70b413b408a21f0a8933cfd4a09e261e637bae1
Reviewed-on: https://chromium-review.googlesource.com/200559
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/validationES.cpp b/src/libGLESv2/validationES.cpp
index a6ae90a..91df2be 100644
--- a/src/libGLESv2/validationES.cpp
+++ b/src/libGLESv2/validationES.cpp
@@ -67,6 +67,7 @@
 // This function differs from ValidTextureTarget in that the target must be
 // usable as the destination of a 2D operation-- so a cube face is valid, but
 // GL_TEXTURE_CUBE_MAP is not.
+// Note: duplicate of IsInternalTextureTarget
 bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
 {
     switch (target)
@@ -1098,4 +1099,172 @@
     return true;
 }
 
+bool ValidateCopyTexImageParametersBase(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, GLenum *textureFormatOut)
+{
+
+    if (!ValidTexture2DDestinationTarget(context, target))
+    {
+        return gl::error(GL_INVALID_ENUM, false);
+    }
+
+    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 (border != 0)
+    {
+        return gl::error(GL_INVALID_VALUE, false);
+    }
+
+    if (!ValidMipLevel(context, target, level))
+    {
+        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->getLayers(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)
+    {
+        int clientVersion = context->getClientVersion();
+        GLint blockWidth = GetCompressedBlockWidth(textureInternalFormat, clientVersion);
+        GLint blockHeight = GetCompressedBlockHeight(textureInternalFormat, clientVersion);
+
+        if (((width % blockWidth) != 0 && width != textureLevelWidth) ||
+            ((height % blockHeight) != 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);
+        }
+    }
+
+    *textureFormatOut = textureInternalFormat;
+    return true;
+}
+
 }