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>
This commit is contained in:
Corentin Wallez 2023-05-26 15:48:12 +00:00 committed by Dawn LUCI CQ
parent bcf4174c06
commit 1b48cc0d6f
5 changed files with 101 additions and 43 deletions

View File

@ -48,8 +48,9 @@ void Device::DestroyImpl() {
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl( ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const { const Surface* surface) const {
wgpu::TextureUsage usages = wgpu::TextureUsage usages = wgpu::TextureUsage::RenderAttachment |
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding; wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst;
return usages; return usages;
} }

View File

@ -243,8 +243,9 @@ void Device::InitializeRenderPipelineAsyncImpl(Ref<RenderPipelineBase> renderPip
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl( ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const { const Surface* surface) const {
wgpu::TextureUsage usages = wgpu::TextureUsage usages = wgpu::TextureUsage::RenderAttachment |
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding; wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst;
return usages; return usages;
} }

View File

@ -255,8 +255,9 @@ ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl(
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl( ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const { const Surface* surface) const {
wgpu::TextureUsage usages = wgpu::TextureUsage usages = wgpu::TextureUsage::RenderAttachment |
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding; wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst;
return usages; return usages;
} }

View File

@ -223,8 +223,16 @@ ResultOrError<wgpu::TextureUsage> SwapChain::GetSupportedSurfaceUsage(const Devi
fn.GetPhysicalDeviceSurfaceCapabilitiesKHR(vkPhysicalDevice, surfaceVk, &surfaceCapsVk), fn.GetPhysicalDeviceSurfaceCapabilitiesKHR(vkPhysicalDevice, surfaceVk, &surfaceCapsVk),
"GetPhysicalDeviceSurfaceCapabilitiesKHR")); "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) { if (surfaceCapsVk.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
supportedUsages |= wgpu::TextureUsage::TextureBinding; supportedUsages |= wgpu::TextureUsage::TextureBinding;
} }

View File

@ -69,8 +69,8 @@ class SwapChainTests : public DawnTest {
DawnTest::TearDown(); DawnTest::TearDown();
} }
void ClearTexture(wgpu::TextureView view, wgpu::Color color) { void ClearTexture(wgpu::Texture texture, wgpu::Color color) {
utils::ComboRenderPassDescriptor desc({view}); utils::ComboRenderPassDescriptor desc({texture.CreateView()});
desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear; desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
desc.cColorAttachments[0].clearValue = color; desc.cColorAttachments[0].clearValue = color;
@ -92,35 +92,35 @@ class SwapChainTests : public DawnTest {
// Basic test for creating a swapchain and presenting one frame. // Basic test for creating a swapchain and presenting one frame.
TEST_P(SwapChainTests, Basic) { TEST_P(SwapChainTests, Basic) {
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor); 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(); swapchain.Present();
} }
// Test replacing the swapchain // Test replacing the swapchain
TEST_P(SwapChainTests, ReplaceBasic) { TEST_P(SwapChainTests, ReplaceBasic) {
wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor); 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(); swapchain1.Present();
wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor); 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(); swapchain2.Present();
} }
// Test replacing the swapchain after GetCurrentTextureView // Test replacing the swapchain after GetCurrentTexture
TEST_P(SwapChainTests, ReplaceAfterGet) { TEST_P(SwapChainTests, ReplaceAfterGet) {
wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor); 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); 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(); swapchain2.Present();
} }
// Test destroying the swapchain after GetCurrentTextureView // Test destroying the swapchain after GetCurrentTexture
TEST_P(SwapChainTests, DestroyAfterGet) { TEST_P(SwapChainTests, DestroyAfterGet) {
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor); 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 // Test destroying the surface before the swapchain
@ -129,10 +129,10 @@ TEST_P(SwapChainTests, DestroySurface) {
surface = nullptr; 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) { TEST_P(SwapChainTests, DestroySurfaceAfterGet) {
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor); 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; surface = nullptr;
} }
@ -158,12 +158,12 @@ TEST_P(SwapChainTests, SwitchPresentMode) {
desc.presentMode = mode1; desc.presentMode = mode1;
wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &desc); 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(); swapchain1.Present();
desc.presentMode = mode2; desc.presentMode = mode2;
wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &desc); 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(); swapchain2.Present();
} }
} }
@ -177,7 +177,7 @@ TEST_P(SwapChainTests, ResizingSwapChainOnly) {
desc.height -= i * 10; desc.height -= i * 10;
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc); 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(); swapchain.Present();
} }
} }
@ -190,7 +190,7 @@ TEST_P(SwapChainTests, ResizingWindowOnly) {
glfwSetWindowSize(window, 400 - 10 * i, 400 + 10 * i); glfwSetWindowSize(window, 400 - 10 * i, 400 + 10 * i);
glfwPollEvents(); 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(); swapchain.Present();
} }
} }
@ -212,7 +212,7 @@ TEST_P(SwapChainTests, ResizingWindowAndSwapChain) {
desc.height = height; desc.height = height;
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc); 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(); swapchain.Present();
} }
} }
@ -230,7 +230,7 @@ TEST_P(SwapChainTests, SwitchingDevice) {
} }
wgpu::SwapChain swapchain = deviceToUse.CreateSwapChain(surface, &baseDescriptor); wgpu::SwapChain swapchain = deviceToUse.CreateSwapChain(surface, &baseDescriptor);
swapchain.GetCurrentTextureView(); swapchain.GetCurrentTexture();
swapchain.Present(); swapchain.Present();
} }
} }
@ -281,15 +281,16 @@ class SwapChainWithAdditionalUsageTests : public SwapChainTests {
GTEST_SKIP(); 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})); DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::SurfaceCapabilities}));
} }
void SampleTexture(wgpu::TextureView view, void SampleTexture(wgpu::Texture texture, utils::RGBA8 expectedColor) {
uint32_t width,
uint32_t height,
utils::RGBA8 expectedColor) {
wgpu::TextureDescriptor texDescriptor; wgpu::TextureDescriptor texDescriptor;
texDescriptor.size = {width, height, 1}; texDescriptor.size = {texture.GetWidth(), texture.GetHeight(), 1};
texDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; texDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
texDescriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc | texDescriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst; wgpu::TextureUsage::CopyDst;
@ -329,8 +330,8 @@ class SwapChainWithAdditionalUsageTests : public SwapChainTests {
{ {
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc); wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
wgpu::BindGroup bindGroup = wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {{0, view}}); {{0, texture.CreateView()}});
utils::ComboRenderPassDescriptor renderPassInfo({dstView}); utils::ComboRenderPassDescriptor renderPassInfo({dstView});
@ -345,7 +346,16 @@ class SwapChainWithAdditionalUsageTests : public SwapChainTests {
queue.Submit(1, &commands); queue.Submit(1, &commands);
EXPECT_TEXTURE_EQ(expectedColor, dstTexture, {0, 0}); 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_P(SwapChainWithAdditionalUsageTests, GetSurfaceSupportedUsage) {
// Test that sampling from swapchain is supported. // Test that sampling from swapchain is supported.
TEST_P(SwapChainWithAdditionalUsageTests, SamplingFromSwapChain) { 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 // Skip all tests if readable surface doesn't support texture binding
DAWN_TEST_UNSUPPORTED_IF( DAWN_TEST_UNSUPPORTED_IF(
(device.GetSupportedSurfaceUsage(surface) & wgpu::TextureUsage::TextureBinding) == 0); !(device.GetSupportedSurfaceUsage(surface) & wgpu::TextureUsage::TextureBinding));
auto desc = baseDescriptor; auto desc = baseDescriptor;
desc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment; desc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc); 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, SampleTexture(swapchain.GetCurrentTexture(), utils::RGBA8::kRed);
utils::RGBA8::kRed);
swapchain.Present(); swapchain.Present();
} }
@ -383,7 +388,7 @@ TEST_P(SwapChainWithAdditionalUsageTests, ErrorIncludeUnsupportedUsage) {
auto supportedUsage = device.GetSupportedSurfaceUsage(surface); auto supportedUsage = device.GetSupportedSurfaceUsage(surface);
// Assuming StorageBinding is not supported. // 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; auto desc = baseDescriptor;
desc.usage = supportedUsage | wgpu::TextureUsage::StorageBinding; desc.usage = supportedUsage | wgpu::TextureUsage::StorageBinding;
@ -392,6 +397,48 @@ TEST_P(SwapChainWithAdditionalUsageTests, ErrorIncludeUnsupportedUsage) {
testing::HasSubstr("is not supported")); 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(SwapChainTests, MetalBackend(), VulkanBackend());
DAWN_INSTANTIATE_TEST(SwapChainWithAdditionalUsageTests, DAWN_INSTANTIATE_TEST(SwapChainWithAdditionalUsageTests,
D3D11Backend(), D3D11Backend(),