Fix CopyTexSubImage validation.

Now that we preserve the sized-ness information, we can validate
CopyTexSubImage and related methods correctly.

Fixed a lot of WebGL 2 tests when using ANGLE.

BUG=angleproject:1228

Change-Id: I959322c0a9bb16a2f16d60dce7cd1e63ca95b45a
Reviewed-on: https://chromium-review.googlesource.com/362618
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index ab575f1..1bbfe86 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -1649,7 +1649,7 @@
                                         GLsizei width,
                                         GLsizei height,
                                         GLint border,
-                                        GLenum *textureFormatOut)
+                                        Format *textureFormatOut)
 {
     if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
     {
@@ -1786,7 +1786,10 @@
         }
     }
 
-    *textureFormatOut = texture->getFormat(target, level).asSized();
+    if (textureFormatOut)
+    {
+        *textureFormatOut = texture->getFormat(target, level);
+    }
     return true;
 }
 
diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h
index 56f88cb..a2b3601 100644
--- a/src/libANGLE/validationES.h
+++ b/src/libANGLE/validationES.h
@@ -23,6 +23,7 @@
 namespace gl
 {
 class Context;
+struct Format;
 class Program;
 class Shader;
 class ValidationContext;
@@ -143,7 +144,7 @@
                                         GLsizei width,
                                         GLsizei height,
                                         GLint border,
-                                        GLenum *textureInternalFormatOut);
+                                        Format *textureFormatOut);
 
 bool ValidateDrawArrays(ValidationContext *context,
                         GLenum mode,
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index 540ed1a..c25d1e5 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -630,29 +630,28 @@
                                        GLsizei height,
                                        GLint border)
 {
-    GLenum textureInternalFormat = GL_NONE;
-
     if (!ValidTexture2DDestinationTarget(context, target))
     {
         context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
         return false;
     }
 
+    Format textureFormat = Format::Invalid();
     if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
-                                            xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat))
+                                            xoffset, yoffset, 0, x, y, width, height, border,
+                                            &textureFormat))
     {
         return false;
     }
 
     const gl::Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
     GLenum colorbufferFormat           = framebuffer->getReadColorbuffer()->getFormat().asSized();
-    const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat);
-    GLenum textureFormat = internalFormatInfo.format;
+    const auto &formatInfo             = *textureFormat.info;
 
     // [OpenGL ES 2.0.24] table 3.9
     if (isSubImage)
     {
-        switch (textureFormat)
+        switch (formatInfo.format)
         {
           case GL_ALPHA:
             if (colorbufferFormat != GL_ALPHA8_EXT &&
@@ -750,8 +749,7 @@
             return false;
         }
 
-        if (internalFormatInfo.type == GL_FLOAT &&
-            !context->getExtensions().textureFloat)
+        if (formatInfo.type == GL_FLOAT && !context->getExtensions().textureFloat)
         {
             context->handleError(Error(GL_INVALID_OPERATION));
             return false;
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index a1e11cd..bb9827a 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -770,36 +770,42 @@
     return first == 0 || first == second;
 }
 
-static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle)
+static bool IsValidES3CopyTexImageCombination(const Format &textureFormat,
+                                              const Format &framebufferFormat,
+                                              GLuint readBufferHandle)
 {
-    const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat);
-    const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat);
+    const auto &textureFormatInfo     = *textureFormat.info;
+    const auto &framebufferFormatInfo = *framebufferFormat.info;
 
     static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations();
-    if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end())
+    if (conversionSet.find(CopyConversion(textureFormatInfo.format,
+                                          framebufferFormatInfo.format)) != conversionSet.end())
     {
         // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats
         // must both be signed, unsigned, or fixed point and both source and destinations
         // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed
         // conversion between fixed and floating point.
 
-        if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB))
+        if ((textureFormatInfo.colorEncoding == GL_SRGB) !=
+            (framebufferFormatInfo.colorEncoding == GL_SRGB))
         {
             return false;
         }
 
-        if (((textureInternalFormatInfo.componentType == GL_INT)          != (framebufferInternalFormatInfo.componentType == GL_INT         )) ||
-            ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT)))
+        if (((textureFormatInfo.componentType == GL_INT) !=
+             (framebufferFormatInfo.componentType == GL_INT)) ||
+            ((textureFormatInfo.componentType == GL_UNSIGNED_INT) !=
+             (framebufferFormatInfo.componentType == GL_UNSIGNED_INT)))
         {
             return false;
         }
 
-        if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
-             textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
-             textureInternalFormatInfo.componentType == GL_FLOAT) &&
-            !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
-              framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
-              framebufferInternalFormatInfo.componentType == GL_FLOAT))
+        if ((textureFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
+             textureFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
+             textureFormatInfo.componentType == GL_FLOAT) &&
+            !(framebufferFormatInfo.componentType == GL_UNSIGNED_NORMALIZED ||
+              framebufferFormatInfo.componentType == GL_SIGNED_NORMALIZED ||
+              framebufferFormatInfo.componentType == GL_FLOAT))
         {
             return false;
         }
@@ -821,15 +827,16 @@
         if (readBufferHandle != 0)
         {
             // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer
-            if (framebufferInternalFormatInfo.pixelBytes > 0)
+            if (framebufferFormat.sized)
             {
-                sourceEffectiveFormat = &framebufferInternalFormatInfo;
+                sourceEffectiveFormat = &framebufferFormatInfo;
             }
             else
             {
                 // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format
                 // texture. We can use the same table we use when creating textures to get its effective sized format.
-                GLenum sizedInternalFormat = GetSizedInternalFormat(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type);
+                GLenum sizedInternalFormat = GetSizedInternalFormat(framebufferFormatInfo.format,
+                                                                    framebufferFormatInfo.type);
                 sourceEffectiveFormat = &GetInternalFormatInfo(sizedInternalFormat);
             }
         }
@@ -837,10 +844,11 @@
         {
             // The effective internal format must be derived from the source framebuffer's channel sizes.
             // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17)
-            if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR)
+            if (framebufferFormatInfo.colorEncoding == GL_LINEAR)
             {
                 GLenum effectiveFormat;
-                if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat))
+                if (GetEffectiveInternalFormat(framebufferFormatInfo, textureFormatInfo,
+                                               &effectiveFormat))
                 {
                     sourceEffectiveFormat = &GetInternalFormatInfo(effectiveFormat);
                 }
@@ -849,14 +857,15 @@
                     return false;
                 }
             }
-            else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)
+            else if (framebufferFormatInfo.colorEncoding == GL_SRGB)
             {
                 // SRGB buffers can only be copied to sized format destinations according to table 3.18
-                if ((textureInternalFormatInfo.pixelBytes > 0) &&
-                    (framebufferInternalFormatInfo.redBits   >= 1 && framebufferInternalFormatInfo.redBits   <= 8) &&
-                    (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) &&
-                    (framebufferInternalFormatInfo.blueBits  >= 1 && framebufferInternalFormatInfo.blueBits  <= 8) &&
-                    (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8))
+                if (textureFormat.sized &&
+                    (framebufferFormatInfo.redBits >= 1 && framebufferFormatInfo.redBits <= 8) &&
+                    (framebufferFormatInfo.greenBits >= 1 &&
+                     framebufferFormatInfo.greenBits <= 8) &&
+                    (framebufferFormatInfo.blueBits >= 1 && framebufferFormatInfo.blueBits <= 8) &&
+                    (framebufferFormatInfo.alphaBits >= 1 && framebufferFormatInfo.alphaBits <= 8))
                 {
                     sourceEffectiveFormat = &GetInternalFormatInfo(GL_SRGB8_ALPHA8);
                 }
@@ -872,25 +881,20 @@
             }
         }
 
-        if (textureInternalFormatInfo.pixelBytes > 0)
+        if (textureFormat.sized)
         {
             // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination
             // format is sized, component sizes of the source and destination formats must exactly
             // match if the destination format exists.
-            if (!EqualOrFirstZero(textureInternalFormatInfo.redBits,
-                                  sourceEffectiveFormat->redBits) ||
-                !EqualOrFirstZero(textureInternalFormatInfo.greenBits,
-                                  sourceEffectiveFormat->greenBits) ||
-                !EqualOrFirstZero(textureInternalFormatInfo.blueBits,
-                                  sourceEffectiveFormat->blueBits) ||
-                !EqualOrFirstZero(textureInternalFormatInfo.alphaBits,
-                                  sourceEffectiveFormat->alphaBits))
+            if (!EqualOrFirstZero(textureFormatInfo.redBits, sourceEffectiveFormat->redBits) ||
+                !EqualOrFirstZero(textureFormatInfo.greenBits, sourceEffectiveFormat->greenBits) ||
+                !EqualOrFirstZero(textureFormatInfo.blueBits, sourceEffectiveFormat->blueBits) ||
+                !EqualOrFirstZero(textureFormatInfo.alphaBits, sourceEffectiveFormat->alphaBits))
             {
                 return false;
             }
         }
 
-
         return true; // A conversion function exists, and no rule in the specification has precluded conversion
                      // between these formats.
     }
@@ -912,14 +916,14 @@
                                            GLsizei height,
                                            GLint border)
 {
-    GLenum textureInternalFormat = GL_NONE;
+    Format textureFormat = Format::Invalid();
     if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
-                                            xoffset, yoffset, zoffset, x, y, width, height,
-                                            border, &textureInternalFormat))
+                                            xoffset, yoffset, zoffset, x, y, width, height, border,
+                                            &textureFormat))
     {
         return false;
     }
-    ASSERT(textureInternalFormat != GL_NONE || !isSubImage);
+    ASSERT(textureFormat.valid() || !isSubImage);
 
     const auto &state            = context->getGLState();
     gl::Framebuffer *framebuffer = state.getReadFramebuffer();
@@ -937,12 +941,11 @@
         return false;
     }
 
-    const gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
-    GLenum colorbufferInternalFormat        = source->getFormat().asSized();
+    const FramebufferAttachment *source = framebuffer->getReadColorbuffer();
 
     if (isSubImage)
     {
-        if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
+        if (!IsValidES3CopyTexImageCombination(textureFormat, source->getFormat(),
                                                readFramebufferID))
         {
             context->handleError(Error(GL_INVALID_OPERATION));
@@ -951,8 +954,10 @@
     }
     else
     {
-        if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat,
-                                                   readFramebufferID))
+        // Use format/type from the source FBO. (Might not be perfect for all cases?)
+        const auto framebufferFormat = source->getFormat();
+        Format copyFormat(internalformat, framebufferFormat.format, framebufferFormat.type);
+        if (!IsValidES3CopyTexImageCombination(copyFormat, framebufferFormat, readFramebufferID))
         {
             context->handleError(Error(GL_INVALID_OPERATION));
             return false;
diff --git a/src/tests/deqp_support/deqp_gles2_test_expectations.txt b/src/tests/deqp_support/deqp_gles2_test_expectations.txt
index 209d8f9..5ea0f13 100644
--- a/src/tests/deqp_support/deqp_gles2_test_expectations.txt
+++ b/src/tests/deqp_support/deqp_gles2_test_expectations.txt
@@ -80,7 +80,6 @@
 1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.projected.linear_nearest = FAIL
 1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_nearest = FAIL
 1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.bias.linear_linear = FAIL
-1021 WIN : dEQP-GLES2.functional.texture.specification.basic_copyteximage2d.cube_luminance = FAIL
 1025 WIN : dEQP-GLES2.functional.fragment_ops.depth_stencil.stencil_depth_funcs.stencil_* = FAIL
 1025 WIN : dEQP-GLES2.functional.fragment_ops.depth_stencil.stencil_ops.* = FAIL
 1025 WIN : dEQP-GLES2.functional.fragment_ops.depth_stencil.write_mask.* = FAIL
diff --git a/src/tests/deqp_support/deqp_gles3_test_expectations.txt b/src/tests/deqp_support/deqp_gles3_test_expectations.txt
index 6a32c03..31a53b3 100644
--- a/src/tests/deqp_support/deqp_gles3_test_expectations.txt
+++ b/src/tests/deqp_support/deqp_gles3_test_expectations.txt
@@ -122,14 +122,6 @@
 1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureoffset.sampler3d_float_fragment = FAIL
 1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureprojoffset.sampler3d_fixed_fragment = FAIL
 1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureprojoffset.sampler3d_float_fragment = FAIL
-1095 WIN : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.2d_rgba = FAIL
-1095 WIN : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.2d_alpha = FAIL
-1095 WIN : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.2d_luminance_alpha = FAIL
-1095 WIN : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.2d_rgb = FAIL
-1095 WIN : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_rgba = FAIL
-1095 WIN : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_alpha = FAIL
-1095 WIN : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_luminance_alpha = FAIL
-1095 WIN : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_rgb = FAIL
 1096 WIN : dEQP-GLES3.functional.fragment_ops.depth_stencil.stencil_depth_funcs.stencil_* = FAIL
 1096 WIN : dEQP-GLES3.functional.fragment_ops.depth_stencil.stencil_ops.* = FAIL
 1096 WIN : dEQP-GLES3.functional.fragment_ops.depth_stencil.write_mask.* = FAIL