Implement depth/stencil texture-to-texture copies for OpenGL ES 3.1.

Bug: dawn:634
Change-Id: I30f0c1496e5443bda9bee1905162eae39ce2461c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/38940
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index ee42593..696fa4f 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -440,6 +440,81 @@
             return validTextureCopyExtent;
         }
 
+        void CopyTextureToTextureWithBlit(const OpenGLFunctions& gl,
+                                          const TextureCopy& src,
+                                          const TextureCopy& dst,
+                                          const Extent3D& copySize) {
+            Texture* srcTexture = ToBackend(src.texture.Get());
+            Texture* dstTexture = ToBackend(dst.texture.Get());
+
+            // Generate temporary framebuffers for the blits.
+            GLuint readFBO = 0, drawFBO = 0;
+            gl.GenFramebuffers(1, &readFBO);
+            gl.GenFramebuffers(1, &drawFBO);
+            gl.BindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
+            gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
+
+            // Reset state that may affect glBlitFramebuffer().
+            gl.Disable(GL_SCISSOR_TEST);
+            GLenum blitMask = 0;
+            if (src.aspect & Aspect::Color) {
+                blitMask |= GL_COLOR_BUFFER_BIT;
+            }
+            if (src.aspect & Aspect::Depth) {
+                blitMask |= GL_DEPTH_BUFFER_BIT;
+            }
+            if (src.aspect & Aspect::Stencil) {
+                blitMask |= GL_STENCIL_BUFFER_BIT;
+            }
+            // Iterate over all layers, doing a single blit for each.
+            for (uint32_t layer = 0; layer < copySize.depth; ++layer) {
+                // Bind all required aspects for this layer.
+                for (Aspect aspect : IterateEnumMask(src.aspect)) {
+                    GLenum glAttachment;
+                    switch (aspect) {
+                        case Aspect::Color:
+                            glAttachment = GL_COLOR_ATTACHMENT0;
+                            break;
+                        case Aspect::Depth:
+                            glAttachment = GL_DEPTH_ATTACHMENT;
+                            break;
+                        case Aspect::Stencil:
+                            glAttachment = GL_STENCIL_ATTACHMENT;
+                            break;
+                        case Aspect::CombinedDepthStencil:
+                        case Aspect::None:
+                            UNREACHABLE();
+                    }
+                    if (srcTexture->GetArrayLayers() == 1) {
+                        gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, glAttachment,
+                                                srcTexture->GetGLTarget(), srcTexture->GetHandle(),
+                                                src.mipLevel);
+                    } else {
+                        gl.FramebufferTextureLayer(GL_READ_FRAMEBUFFER, glAttachment,
+                                                   srcTexture->GetHandle(),
+                                                   static_cast<GLint>(src.mipLevel),
+                                                   static_cast<GLint>(src.origin.z + layer));
+                    }
+                    if (dstTexture->GetArrayLayers() == 1) {
+                        gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment,
+                                                dstTexture->GetGLTarget(), dstTexture->GetHandle(),
+                                                dst.mipLevel);
+                    } else {
+                        gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, glAttachment,
+                                                   dstTexture->GetHandle(),
+                                                   static_cast<GLint>(dst.mipLevel),
+                                                   static_cast<GLint>(dst.origin.z + layer));
+                    }
+                }
+                gl.BlitFramebuffer(src.origin.x, src.origin.y, src.origin.x + copySize.width,
+                                   src.origin.y + copySize.height, dst.origin.x, dst.origin.y,
+                                   dst.origin.x + copySize.width, dst.origin.y + copySize.height,
+                                   blitMask, GL_NEAREST);
+            }
+            gl.Enable(GL_SCISSOR_TEST);
+            gl.DeleteFramebuffers(1, &readFBO);
+            gl.DeleteFramebuffers(1, &drawFBO);
+        }
     }  // namespace
 
     CommandBuffer::CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor)
@@ -793,42 +868,7 @@
                                             dst.mipLevel, dst.origin.x, dst.origin.y, dst.origin.z,
                                             copySize.width, copySize.height, copy->copySize.depth);
                     } else {
-                        GLuint readFBO = 0, drawFBO = 0;
-                        gl.GenFramebuffers(1, &readFBO);
-                        gl.GenFramebuffers(1, &drawFBO);
-                        gl.BindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
-                        gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
-                        gl.Disable(GL_SCISSOR_TEST);
-                        for (uint32_t layer = 0; layer < copy->copySize.depth; ++layer) {
-                            if (srcTexture->GetArrayLayers() == 1) {
-                                gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                                        srcTexture->GetGLTarget(),
-                                                        srcTexture->GetHandle(), src.mipLevel);
-                            } else {
-                                gl.FramebufferTextureLayer(
-                                    GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                    srcTexture->GetHandle(), static_cast<GLint>(src.mipLevel),
-                                    static_cast<GLint>(src.origin.z + layer));
-                            }
-                            if (dstTexture->GetArrayLayers() == 1) {
-                                gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                                        dstTexture->GetGLTarget(),
-                                                        dstTexture->GetHandle(), dst.mipLevel);
-                            } else {
-                                gl.FramebufferTextureLayer(
-                                    GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                    dstTexture->GetHandle(), static_cast<GLint>(dst.mipLevel),
-                                    static_cast<GLint>(dst.origin.z + layer));
-                            }
-                            gl.BlitFramebuffer(
-                                src.origin.x, src.origin.y, src.origin.x + copySize.width,
-                                src.origin.y + copySize.height, dst.origin.x, dst.origin.y,
-                                dst.origin.x + copySize.width, dst.origin.y + copySize.height,
-                                GL_COLOR_BUFFER_BIT, GL_NEAREST);
-                        }
-                        gl.Enable(GL_SCISSOR_TEST);
-                        gl.DeleteFramebuffers(1, &readFBO);
-                        gl.DeleteFramebuffers(1, &drawFBO);
+                        CopyTextureToTextureWithBlit(gl, src, dst, copySize);
                     }
                     break;
                 }
diff --git a/src/dawn_native/opengl/CommandBufferGL.h b/src/dawn_native/opengl/CommandBufferGL.h
index c21f574..8f300be 100644
--- a/src/dawn_native/opengl/CommandBufferGL.h
+++ b/src/dawn_native/opengl/CommandBufferGL.h
@@ -24,6 +24,7 @@
 namespace dawn_native { namespace opengl {
 
     class Device;
+    struct OpenGLFunctions;
 
     class CommandBuffer final : public CommandBufferBase {
       public:
diff --git a/src/tests/end2end/DepthStencilCopyTests.cpp b/src/tests/end2end/DepthStencilCopyTests.cpp
index 936dcaa..799eb9b 100644
--- a/src/tests/end2end/DepthStencilCopyTests.cpp
+++ b/src/tests/end2end/DepthStencilCopyTests.cpp
@@ -475,9 +475,6 @@
 
 // Test copying both aspects in a T2T copy, then copying only depth.
 TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepth) {
-    // TODO(crbug.com/dawn/634): Diagnose and fix ANGLE failure.
-    DAWN_SKIP_TEST_IF(IsANGLE());
-
     constexpr uint32_t kWidth = 4;
     constexpr uint32_t kHeight = 4;
 
@@ -496,9 +493,6 @@
 
 // Test copying both aspects in a T2T copy, then copying only depth at a nonzero mip.
 TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyNonZeroMipDepth) {
-    // TODO(crbug.com/dawn/634): Diagnose and fix ANGLE failure.
-    DAWN_SKIP_TEST_IF(IsANGLE());
-
     wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
         0.1f, 0.3f, 1u, 3u, 8, 8, wgpu::TextureUsage::RenderAttachment, 1);