Add more supported swapchain texture usages.

Adds the CopySrc and CopyDst usages to swapchain textures when
available in backends so that the wgpu::Texture returned from
GetCurrentTexture can be used in copies.

Also adds a swapchain tests to check that these usages indeed
work.

Bug: dawn:1551
Change-Id: I8495075b0bfb5b8dd953a7811a9d75a76096b143
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/133464
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/dawn/native/d3d/DeviceD3D.cpp b/src/dawn/native/d3d/DeviceD3D.cpp
index b92f169..6e9b45d 100644
--- a/src/dawn/native/d3d/DeviceD3D.cpp
+++ b/src/dawn/native/d3d/DeviceD3D.cpp
@@ -48,8 +48,9 @@
 
 ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
     const Surface* surface) const {
-    wgpu::TextureUsage usages =
-        wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding;
+    wgpu::TextureUsage usages = wgpu::TextureUsage::RenderAttachment |
+                                wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
+                                wgpu::TextureUsage::CopyDst;
     return usages;
 }
 
diff --git a/src/dawn/native/metal/DeviceMTL.mm b/src/dawn/native/metal/DeviceMTL.mm
index 9409cb9..116837b 100644
--- a/src/dawn/native/metal/DeviceMTL.mm
+++ b/src/dawn/native/metal/DeviceMTL.mm
@@ -243,8 +243,9 @@
 
 ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
     const Surface* surface) const {
-    wgpu::TextureUsage usages =
-        wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding;
+    wgpu::TextureUsage usages = wgpu::TextureUsage::RenderAttachment |
+                                wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
+                                wgpu::TextureUsage::CopyDst;
     return usages;
 }
 
diff --git a/src/dawn/native/opengl/DeviceGL.cpp b/src/dawn/native/opengl/DeviceGL.cpp
index 356d9c2..4b0cf82 100644
--- a/src/dawn/native/opengl/DeviceGL.cpp
+++ b/src/dawn/native/opengl/DeviceGL.cpp
@@ -255,8 +255,9 @@
 
 ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
     const Surface* surface) const {
-    wgpu::TextureUsage usages =
-        wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding;
+    wgpu::TextureUsage usages = wgpu::TextureUsage::RenderAttachment |
+                                wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
+                                wgpu::TextureUsage::CopyDst;
     return usages;
 }
 
diff --git a/src/dawn/native/vulkan/SwapChainVk.cpp b/src/dawn/native/vulkan/SwapChainVk.cpp
index 72b89db..7794804 100644
--- a/src/dawn/native/vulkan/SwapChainVk.cpp
+++ b/src/dawn/native/vulkan/SwapChainVk.cpp
@@ -223,8 +223,16 @@
         fn.GetPhysicalDeviceSurfaceCapabilitiesKHR(vkPhysicalDevice, surfaceVk, &surfaceCapsVk),
         "GetPhysicalDeviceSurfaceCapabilitiesKHR"));
 
-    wgpu::TextureUsage supportedUsages = wgpu::TextureUsage::RenderAttachment;
-
+    wgpu::TextureUsage supportedUsages = wgpu::TextureUsage::None;
+    if (surfaceCapsVk.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
+        supportedUsages |= wgpu::TextureUsage::CopySrc;
+    }
+    if (surfaceCapsVk.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
+        supportedUsages |= wgpu::TextureUsage::CopyDst;
+    }
+    if (surfaceCapsVk.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
+        supportedUsages |= wgpu::TextureUsage::RenderAttachment;
+    }
     if (surfaceCapsVk.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
         supportedUsages |= wgpu::TextureUsage::TextureBinding;
     }
diff --git a/src/dawn/tests/end2end/SwapChainTests.cpp b/src/dawn/tests/end2end/SwapChainTests.cpp
index 8c10fb4..a626d9f 100644
--- a/src/dawn/tests/end2end/SwapChainTests.cpp
+++ b/src/dawn/tests/end2end/SwapChainTests.cpp
@@ -69,8 +69,8 @@
         DawnTest::TearDown();
     }
 
-    void ClearTexture(wgpu::TextureView view, wgpu::Color color) {
-        utils::ComboRenderPassDescriptor desc({view});
+    void ClearTexture(wgpu::Texture texture, wgpu::Color color) {
+        utils::ComboRenderPassDescriptor desc({texture.CreateView()});
         desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
         desc.cColorAttachments[0].clearValue = color;
 
@@ -92,35 +92,35 @@
 // Basic test for creating a swapchain and presenting one frame.
 TEST_P(SwapChainTests, Basic) {
     wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
-    ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
+    ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
     swapchain.Present();
 }
 
 // Test replacing the swapchain
 TEST_P(SwapChainTests, ReplaceBasic) {
     wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor);
-    ClearTexture(swapchain1.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
+    ClearTexture(swapchain1.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
     swapchain1.Present();
 
     wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor);
-    ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 1.0, 0.0, 1.0});
+    ClearTexture(swapchain2.GetCurrentTexture(), {0.0, 1.0, 0.0, 1.0});
     swapchain2.Present();
 }
 
-// Test replacing the swapchain after GetCurrentTextureView
+// Test replacing the swapchain after GetCurrentTexture
 TEST_P(SwapChainTests, ReplaceAfterGet) {
     wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor);
-    ClearTexture(swapchain1.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
+    ClearTexture(swapchain1.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
 
     wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor);
-    ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 1.0, 0.0, 1.0});
+    ClearTexture(swapchain2.GetCurrentTexture(), {0.0, 1.0, 0.0, 1.0});
     swapchain2.Present();
 }
 
-// Test destroying the swapchain after GetCurrentTextureView
+// Test destroying the swapchain after GetCurrentTexture
 TEST_P(SwapChainTests, DestroyAfterGet) {
     wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
-    ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
+    ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
 }
 
 // Test destroying the surface before the swapchain
@@ -129,10 +129,10 @@
     surface = nullptr;
 }
 
-// Test destroying the surface before the swapchain but after GetCurrentTextureView
+// Test destroying the surface before the swapchain but after GetCurrentTexture
 TEST_P(SwapChainTests, DestroySurfaceAfterGet) {
     wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
-    ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
+    ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
     surface = nullptr;
 }
 
@@ -158,12 +158,12 @@
 
             desc.presentMode = mode1;
             wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &desc);
-            ClearTexture(swapchain1.GetCurrentTextureView(), {0.0, 0.0, 0.0, 1.0});
+            ClearTexture(swapchain1.GetCurrentTexture(), {0.0, 0.0, 0.0, 1.0});
             swapchain1.Present();
 
             desc.presentMode = mode2;
             wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &desc);
-            ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 0.0, 0.0, 1.0});
+            ClearTexture(swapchain2.GetCurrentTexture(), {0.0, 0.0, 0.0, 1.0});
             swapchain2.Present();
         }
     }
@@ -177,7 +177,7 @@
         desc.height -= i * 10;
 
         wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
-        ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
+        ClearTexture(swapchain.GetCurrentTexture(), {0.05f * i, 0.0f, 0.0f, 1.0f});
         swapchain.Present();
     }
 }
@@ -190,7 +190,7 @@
         glfwSetWindowSize(window, 400 - 10 * i, 400 + 10 * i);
         glfwPollEvents();
 
-        ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
+        ClearTexture(swapchain.GetCurrentTexture(), {0.05f * i, 0.0f, 0.0f, 1.0f});
         swapchain.Present();
     }
 }
@@ -212,7 +212,7 @@
         desc.height = height;
 
         wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
-        ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
+        ClearTexture(swapchain.GetCurrentTexture(), {0.05f * i, 0.0f, 0.0f, 1.0f});
         swapchain.Present();
     }
 }
@@ -230,7 +230,7 @@
         }
 
         wgpu::SwapChain swapchain = deviceToUse.CreateSwapChain(surface, &baseDescriptor);
-        swapchain.GetCurrentTextureView();
+        swapchain.GetCurrentTexture();
         swapchain.Present();
     }
 }
@@ -281,15 +281,16 @@
             GTEST_SKIP();
         }
 
+        // TODO(dawn:1551): Reenable on D3D11 after suppressing the D3D11 debug layer warning for
+        // setting the same private data multiple times.
+        DAWN_SUPPRESS_TEST_IF(IsD3D11());
+
         DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::SurfaceCapabilities}));
     }
 
-    void SampleTexture(wgpu::TextureView view,
-                       uint32_t width,
-                       uint32_t height,
-                       utils::RGBA8 expectedColor) {
+    void SampleTexture(wgpu::Texture texture, utils::RGBA8 expectedColor) {
         wgpu::TextureDescriptor texDescriptor;
-        texDescriptor.size = {width, height, 1};
+        texDescriptor.size = {texture.GetWidth(), texture.GetHeight(), 1};
         texDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
         texDescriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
                               wgpu::TextureUsage::CopyDst;
@@ -329,8 +330,8 @@
         {
             wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
 
-            wgpu::BindGroup bindGroup =
-                utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {{0, view}});
+            wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
+                                                             {{0, texture.CreateView()}});
 
             utils::ComboRenderPassDescriptor renderPassInfo({dstView});
 
@@ -345,7 +346,16 @@
         queue.Submit(1, &commands);
 
         EXPECT_TEXTURE_EQ(expectedColor, dstTexture, {0, 0});
-        EXPECT_TEXTURE_EQ(expectedColor, dstTexture, {width - 1, height - 1});
+        EXPECT_TEXTURE_EQ(expectedColor, dstTexture,
+                          {texture.GetWidth() - 1, texture.GetHeight() - 1});
+    }
+
+    void WriteTexture(wgpu::Texture texture, const utils::RGBA8& data) {
+        wgpu::Extent3D writeSize = {1, 1, 1};
+        wgpu::ImageCopyTexture dest = {};
+        dest.texture = texture;
+        wgpu::TextureDataLayout dataLayout = {};
+        queue.WriteTexture(&dest, &data, sizeof(utils::RGBA8), &dataLayout, &writeSize);
     }
 };
 
@@ -356,22 +366,17 @@
 
 // Test that sampling from swapchain is supported.
 TEST_P(SwapChainWithAdditionalUsageTests, SamplingFromSwapChain) {
-    // TODO(dawn:1551): Reenable on D3D11 after suppressing the D3D11 debug layer warning for
-    // setting the same private data multiple times.
-    DAWN_SUPPRESS_TEST_IF(IsD3D11());
-
     // Skip all tests if readable surface doesn't support texture binding
     DAWN_TEST_UNSUPPORTED_IF(
-        (device.GetSupportedSurfaceUsage(surface) & wgpu::TextureUsage::TextureBinding) == 0);
+        !(device.GetSupportedSurfaceUsage(surface) & wgpu::TextureUsage::TextureBinding));
 
     auto desc = baseDescriptor;
     desc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
 
     wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
-    ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
+    ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
 
-    SampleTexture(swapchain.GetCurrentTextureView(), baseDescriptor.width, baseDescriptor.height,
-                  utils::RGBA8::kRed);
+    SampleTexture(swapchain.GetCurrentTexture(), utils::RGBA8::kRed);
 
     swapchain.Present();
 }
@@ -383,7 +388,7 @@
     auto supportedUsage = device.GetSupportedSurfaceUsage(surface);
 
     // Assuming StorageBinding is not supported.
-    DAWN_TEST_UNSUPPORTED_IF((supportedUsage & wgpu::TextureUsage::StorageBinding) != 0);
+    DAWN_TEST_UNSUPPORTED_IF(supportedUsage & wgpu::TextureUsage::StorageBinding);
 
     auto desc = baseDescriptor;
     desc.usage = supportedUsage | wgpu::TextureUsage::StorageBinding;
@@ -392,6 +397,48 @@
                             testing::HasSubstr("is not supported"));
 }
 
+// Test copying to a swapchain texture when it is supported.
+TEST_P(SwapChainWithAdditionalUsageTests, CopyingToSwapChain) {
+    wgpu::TextureUsage supportedUsages = device.GetSupportedSurfaceUsage(surface);
+    // We need the swapchain to support copying to the texture and at least one readback method.
+    DAWN_TEST_UNSUPPORTED_IF(!(supportedUsages & wgpu::TextureUsage::CopyDst));
+    DAWN_TEST_UNSUPPORTED_IF(
+        !(supportedUsages & (wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding)));
+
+    wgpu::SwapChainDescriptor desc = baseDescriptor;
+    desc.usage |= supportedUsages;
+    desc.width = 1;
+    desc.height = 1;
+
+    wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
+    wgpu::Texture texture = swapchain.GetCurrentTexture();
+    WriteTexture(texture, utils::RGBA8::kRed);
+
+    if (supportedUsages & wgpu::TextureUsage::CopySrc) {
+        EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8::kRed, swapchain.GetCurrentTexture(), 0, 0);
+    } else {
+        // kBlue because the texture is actually BGRA
+        SampleTexture(texture, utils::RGBA8::kBlue);
+    }
+}
+
+// Test copying from a swapchain texture when it is supported.
+TEST_P(SwapChainWithAdditionalUsageTests, CopyingFromSwapChain) {
+    // We need the swapchain to support copying from the texture
+    DAWN_TEST_UNSUPPORTED_IF(
+        !(device.GetSupportedSurfaceUsage(surface) & wgpu::TextureUsage::CopySrc));
+
+    wgpu::SwapChainDescriptor desc = baseDescriptor;
+    desc.usage |= wgpu::TextureUsage::CopySrc;
+
+    wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
+    wgpu::Texture texture = swapchain.GetCurrentTexture();
+
+    ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
+    // kBlue because the texture is actually BGRA8
+    EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8::kBlue, swapchain.GetCurrentTexture(), 0, 0);
+}
+
 DAWN_INSTANTIATE_TEST(SwapChainTests, MetalBackend(), VulkanBackend());
 DAWN_INSTANTIATE_TEST(SwapChainWithAdditionalUsageTests,
                       D3D11Backend(),