Allow CHROMIUM_copy_texture to copy to non-zero mips.

Fix some errors in the GL backend related to source and destination mipmap
targets.

BUG=angleproject:1356

Change-Id: I030529c8626f3bc30dbb4f7f859a02ba56e315e3
Reviewed-on: https://chromium-review.googlesource.com/527653
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp
index 338dd0b..736a802 100644
--- a/src/libANGLE/renderer/gl/TextureGL.cpp
+++ b/src/libANGLE/renderer/gl/TextureGL.cpp
@@ -633,12 +633,12 @@
                                  const gl::Texture *source)
 {
     const TextureGL *sourceGL            = GetImplAs<TextureGL>(source);
-    const gl::ImageDesc &sourceImageDesc = sourceGL->mState.getImageDesc(source->getTarget(), 0);
+    const gl::ImageDesc &sourceImageDesc =
+        sourceGL->mState.getImageDesc(source->getTarget(), sourceLevel);
     gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height);
 
-    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
-    reserveTexImageToBeFilled(getTarget(), 0, internalFormatInfo.sizedInternalFormat,
-                              sourceImageDesc.size, internalFormatInfo.format, type);
+    reserveTexImageToBeFilled(target, level, internalFormat, sourceImageDesc.size,
+                              gl::GetUnsizedFormat(internalFormat), type);
 
     return copySubTextureHelper(target, level, gl::Offset(0, 0, 0), sourceLevel, sourceArea,
                                 internalFormat, unpackFlipY, unpackPremultiplyAlpha,
@@ -656,7 +656,7 @@
                                     bool unpackUnmultiplyAlpha,
                                     const gl::Texture *source)
 {
-    GLenum destFormat = mState.getImageDesc(mState.mTarget, 0).format.info->format;
+    GLenum destFormat = mState.getImageDesc(target, level).format.info->format;
     return copySubTextureHelper(target, level, destOffset, sourceLevel, sourceArea, destFormat,
                                 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source);
 }
@@ -673,10 +673,11 @@
                                           const gl::Texture *source)
 {
     TextureGL *sourceGL                  = GetImplAs<TextureGL>(source);
-    const gl::ImageDesc &sourceImageDesc = sourceGL->mState.getImageDesc(source->getTarget(), 0);
+    const gl::ImageDesc &sourceImageDesc =
+        sourceGL->mState.getImageDesc(source->getTarget(), sourceLevel);
 
     // Check is this is a simple copySubTexture that can be done with a copyTexSubImage
-    bool needsLumaWorkaround = sourceGL->mLevelInfo[0].lumaWorkaround.enabled;
+    bool needsLumaWorkaround = sourceGL->mLevelInfo[sourceLevel].lumaWorkaround.enabled;
 
     GLenum sourceFormat = sourceImageDesc.format.info->format;
     bool sourceFormatContainSupersetOfDestFormat =
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index 80aa0fb..08fbc50 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -361,11 +361,6 @@
         return false;
     }
 
-    if (level > 0 && context->getClientVersion() < ES_3_0)
-    {
-        return false;
-    }
-
     const Caps &caps = context->getCaps();
     if (target == GL_TEXTURE_2D)
     {
diff --git a/src/tests/gl_tests/CopyTextureTest.cpp b/src/tests/gl_tests/CopyTextureTest.cpp
index c87474c..96e0482 100644
--- a/src/tests/gl_tests/CopyTextureTest.cpp
+++ b/src/tests/gl_tests/CopyTextureTest.cpp
@@ -651,51 +651,70 @@
 }
 
 // Test that copying to non-zero mipmaps works
-TEST_P(CopyTextureTestES3, CopyToMipmap)
+TEST_P(CopyTextureTest, CopyToMipmap)
 {
     if (!checkExtensions())
     {
         return;
     }
 
+    if (getClientMajorVersion() < 3 && !extensionEnabled("GL_OES_fbo_render_mipmap"))
+    {
+        std::cout << "Test skipped because ES3 or GL_OES_fbo_render_mipmap is missing."
+                  << std::endl;
+        return;
+    }
+
     if (IsOSX() && IsIntel())
     {
         std::cout << "Test skipped on Mac Intel." << std::endl;
         return;
     }
 
-    GLColor pixels = GLColor::red;
+    GLColor pixels[] = {GLColor::red, GLColor::red, GLColor::red, GLColor::red};
 
     GLTexture textures[2];
 
-    const GLint sourceLevel = 1;
-    const GLint destLevel   = 2;
-
     glBindTexture(GL_TEXTURE_2D, textures[0]);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
-    glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixels);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+    glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 
     glBindTexture(GL_TEXTURE_2D, textures[1]);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
     glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
 
-    glCopySubTextureCHROMIUM(textures[0], sourceLevel, GL_TEXTURE_2D, textures[1], destLevel, 0, 0,
-                             0, 0, 1, 1, false, false, false);
+    std::vector<std::pair<GLint, GLint>> soureDestPairs;
+    soureDestPairs.push_back(std::make_pair(0, 1));
 
-    EXPECT_GL_NO_ERROR();
+    // ES3 allows copying from non-zero mips
+    if (getClientMajorVersion() >= 3)
+    {
+        soureDestPairs.push_back(std::make_pair(1, 2));
+    }
 
-    GLFramebuffer fbo;
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
-                           destLevel);
+    for (const auto &sourceDestPair : soureDestPairs)
+    {
+        const GLint sourceLevel = sourceDestPair.first;
+        const GLint destLevel   = sourceDestPair.second;
 
-    // Check that FB is complete.
-    EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+        glCopyTextureCHROMIUM(textures[0], sourceLevel, GL_TEXTURE_2D, textures[1], destLevel,
+                              GL_RGBA, GL_UNSIGNED_BYTE, false, false, false);
 
-    EXPECT_PIXEL_COLOR_EQ(0, 0, pixels);
+        EXPECT_GL_NO_ERROR();
 
-    EXPECT_GL_NO_ERROR();
+        GLFramebuffer fbo;
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
+                               destLevel);
+
+        // Check that FB is complete.
+        EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+        EXPECT_PIXEL_COLOR_EQ(0, 0, pixels[0]);
+
+        EXPECT_GL_NO_ERROR();
+    }
 }
 
 // Test the newly added ES3 unorm formats