fix(🐛): Route surfaces configured with viewFormats through the blit path

The Vulkan swapchain creates its images without
VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT and wraps them in a texture
descriptor that omits the configuration's viewFormats, so the first
GetCurrentTexture() fails the viewFormats consistency DAWN_CHECK and
aborts. Any non-empty viewFormats now sets needsBlit, like an
unsupported extent or usage: the user-facing texture becomes the
intermediate blit texture, a regular texture created from the full
descriptor, which supports reinterpretation.

Metal already builds the swapchain texture from the full descriptor and
is unaffected. Adds a SurfaceTests end2end case; the file previously
only exercised viewFormatCount = 0, which is why this went unnoticed.

Change-Id: If09df3749bb4de9c9ed011bf924141ea1fbfe15b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/325476
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/vulkan/SwapChainVk.cpp b/src/dawn/native/vulkan/SwapChainVk.cpp
index 7090b4a..90d3b00 100644
--- a/src/dawn/native/vulkan/SwapChainVk.cpp
+++ b/src/dawn/native/vulkan/SwapChainVk.cpp
@@ -271,7 +271,10 @@
     VkImageUsageFlags targetUsages =
         VulkanImageUsage(GetDevice(), GetUsage(), GetDevice()->GetValidInternalFormat(GetFormat()));
     VkImageUsageFlags supportedUsages = surfaceInfo.capabilities.supportedUsageFlags;
-    if (!IsSubset(targetUsages, supportedUsages)) {
+    // The swapchain images are also unable to satisfy viewFormats: they are created without
+    // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, so they cannot be reinterpreted. The blit texture is a
+    // regular texture and can.
+    if (!IsSubset(targetUsages, supportedUsages) || !GetViewFormats().empty()) {
         config.needsBlit = true;
     } else {
         config.usage = targetUsages;
diff --git a/src/dawn/tests/end2end/SurfaceTests.cpp b/src/dawn/tests/end2end/SurfaceTests.cpp
index 44a7d09..24d9710 100644
--- a/src/dawn/tests/end2end/SurfaceTests.cpp
+++ b/src/dawn/tests/end2end/SurfaceTests.cpp
@@ -859,6 +859,39 @@
     ASSERT_EQ(wgpu::Status::Success, surface.Present());
 }
 
+// Test acquiring a texture from a surface configured with viewFormats.
+TEST_P(SurfaceTests, ConfigureWithViewFormats) {
+    // Reinterpreting the surface format as its srgb counterpart isn't allowed in compatibility
+    // mode: viewFormats must match the format there.
+    DAWN_TEST_UNSUPPORTED_IF(IsCompatibilityMode());
+
+    wgpu::Surface surface = CreateTestSurface();
+    wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+
+    // Reinterpretation between a format and its srgb counterpart is always
+    // allowed; pick the counterpart of whatever the surface prefers.
+    wgpu::TextureFormat viewFormat;
+    switch (config.format) {
+        case wgpu::TextureFormat::BGRA8Unorm:
+            viewFormat = wgpu::TextureFormat::BGRA8UnormSrgb;
+            break;
+        case wgpu::TextureFormat::RGBA8Unorm:
+            viewFormat = wgpu::TextureFormat::RGBA8UnormSrgb;
+            break;
+        default:
+            // Add a case above if a platform starts preferring another format.
+            DAWN_UNREACHABLE();
+    }
+    config.viewFormatCount = 1;
+    config.viewFormats = &viewFormat;
+    surface.Configure(&config);
+
+    wgpu::SurfaceTexture surfaceTexture;
+    surface.GetCurrentTexture(&surfaceTexture);
+    ClearTexture(surfaceTexture.texture, {1.0, 0.0, 0.0, 1.0});
+    surface.Present();
+}
+
 // TODO(crbug.com/465183957): Implement swap chain for WebGPUBackend.
 DAWN_INSTANTIATE_TEST(SurfaceTests,
                       D3D11Backend(),