Implement 3D texture copies on OpenGL/ES

Bug: dawn:783
Change-Id: I3c7f0ffc3f45a0d67b411a39342e89c710604d54
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/50244
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Yunchao He <yunchao.he@intel.com>
Reviewed-by: Stephen White <senorblanco@chromium.org>
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 1f988cf..2d7bba4 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -492,7 +492,8 @@
                         case Aspect::Plane1:
                             UNREACHABLE();
                     }
-                    if (srcTexture->GetArrayLayers() == 1) {
+                    if (srcTexture->GetArrayLayers() == 1 &&
+                        srcTexture->GetDimension() == wgpu::TextureDimension::e2D) {
                         gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, glAttachment,
                                                 srcTexture->GetGLTarget(), srcTexture->GetHandle(),
                                                 src.mipLevel);
@@ -502,7 +503,8 @@
                                                    static_cast<GLint>(src.mipLevel),
                                                    static_cast<GLint>(src.origin.z + layer));
                     }
-                    if (dstTexture->GetArrayLayers() == 1) {
+                    if (dstTexture->GetArrayLayers() == 1 &&
+                        dstTexture->GetDimension() == wgpu::TextureDimension::e2D) {
                         gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment,
                                                 dstTexture->GetGLTarget(), dstTexture->GetHandle(),
                                                 dst.mipLevel);
@@ -651,7 +653,7 @@
 
                     buffer->EnsureDataInitializedAsDestination(copy);
 
-                    ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
+                    ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D);
                     SubresourceRange subresources =
                         GetSubresourcesAffectedByCopy(src, copy->copySize);
                     texture->EnsureSubresourceContentInitialized(subresources);
@@ -706,23 +708,25 @@
                                               copySize.height, glFormat, glType, offset);
                                 break;
                             }
+                            // Implementation for 2D array is the same as 3D.
+                            DAWN_FALLTHROUGH;
+                        }
 
+                        case wgpu::TextureDimension::e3D: {
                             const uint64_t bytesPerImage = dst.bytesPerRow * dst.rowsPerImage;
-                            for (uint32_t layer = 0; layer < copySize.depthOrArrayLayers; ++layer) {
+                            for (uint32_t z = 0; z < copySize.depthOrArrayLayers; ++z) {
                                 gl.FramebufferTextureLayer(GL_READ_FRAMEBUFFER, glAttachment,
                                                            texture->GetHandle(), src.mipLevel,
-                                                           src.origin.z + layer);
+                                                           src.origin.z + z);
                                 gl.ReadPixels(src.origin.x, src.origin.y, copySize.width,
                                               copySize.height, glFormat, glType, offset);
 
                                 offset += bytesPerImage;
                             }
-
                             break;
                         }
 
                         case wgpu::TextureDimension::e1D:
-                        case wgpu::TextureDimension::e3D:
                             UNREACHABLE();
                     }
 
@@ -1269,7 +1273,7 @@
                        const TextureDataLayout& dataLayout,
                        const Extent3D& copySize) {
         Texture* texture = ToBackend(destination.texture.Get());
-        ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
+        ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D);
         SubresourceRange range = GetSubresourcesAffectedByCopy(destination, copySize);
         if (IsCompleteSubresourceCopiedTo(texture, copySize, destination.mipLevel)) {
             texture->SetIsSubresourceContentInitialized(true, range);
@@ -1312,7 +1316,8 @@
                 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, blockInfo.height);
                 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 1);
 
-                if (texture->GetArrayLayers() == 1) {
+                if (texture->GetArrayLayers() == 1 &&
+                    texture->GetDimension() == wgpu::TextureDimension::e2D) {
                     gl.CompressedTexSubImage2D(target, destination.mipLevel, x, y, width, height,
                                                format.internalFormat, imageSize, data);
                 } else {
@@ -1330,7 +1335,8 @@
                 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, 0);
                 gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 0);
             } else {
-                if (texture->GetArrayLayers() == 1) {
+                if (texture->GetArrayLayers() == 1 &&
+                    texture->GetDimension() == wgpu::TextureDimension::e2D) {
                     const uint8_t* d = static_cast<const uint8_t*>(data);
 
                     for (; y < destination.origin.y + copySize.height; y += blockInfo.height) {
@@ -1364,7 +1370,8 @@
             if (dataLayout.bytesPerRow % blockInfo.byteSize == 0) {
                 gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
                                dataLayout.bytesPerRow / blockInfo.byteSize * blockInfo.width);
-                if (texture->GetArrayLayers() == 1) {
+                if (texture->GetArrayLayers() == 1 &&
+                    texture->GetDimension() == wgpu::TextureDimension::e2D) {
                     gl.TexSubImage2D(target, destination.mipLevel, x, y, width, height,
                                      format.format, format.type, data);
                 } else {
@@ -1376,7 +1383,8 @@
                 }
                 gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
             } else {
-                if (texture->GetArrayLayers() == 1) {
+                if (texture->GetArrayLayers() == 1 &&
+                    texture->GetDimension() == wgpu::TextureDimension::e2D) {
                     const uint8_t* d = static_cast<const uint8_t*>(data);
                     for (; y < destination.origin.y + height; ++y) {
                         gl.TexSubImage2D(target, destination.mipLevel, x, y, width, 1,
diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp
index c7fc9ef..8ec43dc 100644
--- a/src/dawn_native/opengl/TextureGL.cpp
+++ b/src/dawn_native/opengl/TextureGL.cpp
@@ -339,7 +339,8 @@
                             GLuint framebuffer = 0;
                             gl.GenFramebuffers(1, &framebuffer);
                             gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
-                            if (GetArrayLayers() == 1) {
+                            if (GetArrayLayers() == 1 &&
+                                GetDimension() == wgpu::TextureDimension::e2D) {
                                 gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                                         GetGLTarget(), GetHandle(), level);
                             } else {
diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp
index 0684597..9ab814d 100644
--- a/src/tests/end2end/CopyTests.cpp
+++ b/src/tests/end2end/CopyTests.cpp
@@ -968,10 +968,6 @@
 
 // Test that copying whole 3D texture in one texture-to-buffer-copy works.
 TEST_P(CopyTests_T2B, Texture3DFull) {
-    // TODO(yunchao.he@intel.com): implement 3D texture copy on OpenGL and OpenGLES
-    // backend.
-    DAWN_SKIP_TEST_IF(IsOpenGL() || IsOpenGLES());
-
     constexpr uint32_t kWidth = 256;
     constexpr uint32_t kHeight = 128;
     constexpr uint32_t kDepth = 6u;
@@ -985,10 +981,6 @@
 
 // Test that copying a range of texture 3D depths in one texture-to-buffer-copy works.
 TEST_P(CopyTests_T2B, Texture3DSubRegion) {
-    // TODO(yunchao.he@intel.com): implement 3D texture copy on OpenGL and OpenGLES
-    // backend.
-    DAWN_SKIP_TEST_IF(IsOpenGL() || IsOpenGLES());
-
     constexpr uint32_t kWidth = 256;
     constexpr uint32_t kHeight = 128;
     constexpr uint32_t kDepth = 6u;
@@ -1445,10 +1437,6 @@
 
 // Test that copying whole texture 3D in one buffer-to-texture-copy works.
 TEST_P(CopyTests_B2T, Texture3DFull) {
-    // TODO(yunchao.he@intel.com): implement 3D texture copy on OpenGL and OpenGLES
-    // backend.
-    DAWN_SKIP_TEST_IF(IsOpenGL() || IsOpenGLES());
-
     constexpr uint32_t kWidth = 256;
     constexpr uint32_t kHeight = 128;
     constexpr uint32_t kDepth = 6u;
@@ -1462,10 +1450,6 @@
 
 // Test that copying a range of texture 3D Depths in one texture-to-buffer-copy works.
 TEST_P(CopyTests_B2T, Texture3DSubRegion) {
-    // TODO(yunchao.he@intel.com): implement 3D texture copy on OpenGL and OpenGLES
-    // backend.
-    DAWN_SKIP_TEST_IF(IsOpenGL() || IsOpenGLES());
-
     constexpr uint32_t kWidth = 256;
     constexpr uint32_t kHeight = 128;
     constexpr uint32_t kDepth = 6u;
@@ -1799,10 +1783,6 @@
 
 // Test that copying whole 3D texture in one texture-to-texture-copy works.
 TEST_P(CopyTests_T2T, Texture3DFull) {
-    // TODO(yunchao.he@intel.com): implement 3D texture copy on OpenGL and OpenGLES
-    // backend.
-    DAWN_SKIP_TEST_IF(IsOpenGL() || IsOpenGLES());
-
     constexpr uint32_t kWidth = 256;
     constexpr uint32_t kHeight = 128;
     constexpr uint32_t kDepth = 6u;