mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-14 15:46:28 +00:00
Track depth/stencil aspects independently
This enables depth-stencil textures to track per aspect state independently. It lifts the restriction that depth and stencil store ops must be the same as they now have independent clear states. It will also enable correct barriers on Vulkan and D3D12. Bug: dawn:439 Change-Id: I8a73187df57a1d7eee6790cb4395bdecf42b63aa Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/26127 Reviewed-by: Jiawei Shao <jiawei.shao@intel.com> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
committed by
Commit Bot service account
parent
fa4b74d479
commit
2cf5a08cfc
@@ -62,9 +62,9 @@ class TextureZeroInitTest : public DawnTest {
|
||||
descriptor.dimension = wgpu::TextureViewDimension::e2D;
|
||||
return descriptor;
|
||||
}
|
||||
wgpu::RenderPipeline CreatePipelineForTest() {
|
||||
wgpu::RenderPipeline CreatePipelineForTest(float depth = 0.f) {
|
||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
|
||||
pipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest();
|
||||
pipelineDescriptor.vertexStage.module = CreateBasicVertexShaderForTest(depth);
|
||||
const char* fs =
|
||||
R"(#version 450
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
@@ -80,8 +80,8 @@ class TextureZeroInitTest : public DawnTest {
|
||||
|
||||
return device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
}
|
||||
wgpu::ShaderModule CreateBasicVertexShaderForTest() {
|
||||
return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(#version 450
|
||||
wgpu::ShaderModule CreateBasicVertexShaderForTest(float depth = 0.f) {
|
||||
std::string source = R"(#version 450
|
||||
const vec2 pos[6] = vec2[6](vec2(-1.0f, -1.0f),
|
||||
vec2(-1.0f, 1.0f),
|
||||
vec2( 1.0f, -1.0f),
|
||||
@@ -91,8 +91,10 @@ class TextureZeroInitTest : public DawnTest {
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
|
||||
})");
|
||||
gl_Position = vec4(pos[gl_VertexIndex], )" +
|
||||
std::to_string(depth) + R"(, 1.0);
|
||||
})";
|
||||
return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, source.c_str());
|
||||
}
|
||||
wgpu::ShaderModule CreateSampledTextureFragmentShaderForTest() {
|
||||
return utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment,
|
||||
@@ -574,6 +576,239 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencil) {
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(srcTexture.Get(), 0, 1, 0, 1));
|
||||
}
|
||||
|
||||
// Test that clear state is tracked independently for depth/stencil textures.
|
||||
TEST_P(TextureZeroInitTest, IndependentDepthStencilLoadAfterDiscard) {
|
||||
// TODO(enga): Figure out why this fails on Metal Intel.
|
||||
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
|
||||
|
||||
wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
|
||||
1, 1, wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc,
|
||||
kDepthStencilFormat);
|
||||
wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
|
||||
|
||||
// Uninitialize only depth
|
||||
{
|
||||
// Clear the stencil to 2 and discard the depth
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor({},
|
||||
depthStencilTexture.CreateView());
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 2;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
pass.EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
|
||||
}
|
||||
|
||||
// "all" subresources are not initialized; Depth is not initialized
|
||||
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
|
||||
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
|
||||
|
||||
// Now load both depth and stencil. Depth should be cleared and stencil should stay the same
|
||||
// at 2.
|
||||
{
|
||||
wgpu::TextureDescriptor colorDescriptor =
|
||||
CreateTextureDescriptor(1, 1,
|
||||
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
|
||||
wgpu::TextureUsage::OutputAttachment,
|
||||
kColorFormat);
|
||||
wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
|
||||
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
|
||||
depthStencilTexture.CreateView());
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
pass.SetPipeline(CreatePipelineForTest());
|
||||
pass.SetStencilReference(2);
|
||||
pass.Draw(6);
|
||||
pass.EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
// No lazy clear because depth will be cleared with a loadOp
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
|
||||
|
||||
// Expect the texture to be red because the depth and stencil tests passed. Depth was 0
|
||||
// and stencil was 2.
|
||||
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), colorTexture, 0, 0, kSize, kSize, 0, 0);
|
||||
}
|
||||
|
||||
// Everything is initialized now
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
|
||||
|
||||
// TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
|
||||
if (IsMetal() || IsVulkan()) {
|
||||
// Check by copy that the stencil data is 2.
|
||||
EXPECT_LAZY_CLEAR(0u, EXPECT_TEXTURE_EQ(uint8_t(2), depthStencilTexture, 0, 0, 0, 0,
|
||||
wgpu::TextureAspect::StencilOnly));
|
||||
}
|
||||
}
|
||||
|
||||
// Uninitialize only stencil
|
||||
{
|
||||
// Clear the depth to 0.7 and discard the stencil.
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor({},
|
||||
depthStencilTexture.CreateView());
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.7;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Clear;
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
pass.EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
|
||||
}
|
||||
|
||||
// "all" subresources are not initialized; Stencil is not initialized
|
||||
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
|
||||
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
|
||||
|
||||
// Now load both depth and stencil. Stencil should be cleared and depth should stay the same
|
||||
// at 0.7.
|
||||
{
|
||||
wgpu::TextureDescriptor colorDescriptor =
|
||||
CreateTextureDescriptor(1, 1,
|
||||
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
|
||||
wgpu::TextureUsage::OutputAttachment,
|
||||
kColorFormat);
|
||||
wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
|
||||
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
|
||||
depthStencilTexture.CreateView());
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
pass.SetPipeline(CreatePipelineForTest(0.7));
|
||||
pass.Draw(6);
|
||||
pass.EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
// No lazy clear because stencil will clear using a loadOp.
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
|
||||
|
||||
// Expect the texture to be red because both the depth a stencil tests passed.
|
||||
// Depth was 0.7 and stencil was 0
|
||||
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), colorTexture, 0, 0, kSize, kSize, 0, 0);
|
||||
}
|
||||
|
||||
// Everything is initialized now
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
|
||||
|
||||
// TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
|
||||
if (IsMetal() || IsVulkan()) {
|
||||
// Check by copy that the stencil data is 0.
|
||||
EXPECT_LAZY_CLEAR(0u, EXPECT_TEXTURE_EQ(uint8_t(0), depthStencilTexture, 0, 0, 0, 0,
|
||||
wgpu::TextureAspect::StencilOnly));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that clear state is tracked independently for depth/stencil textures.
|
||||
// Lazy clear of the stencil aspect via copy should not touch depth.
|
||||
TEST_P(TextureZeroInitTest, IndependentDepthStencilCopyAfterDiscard) {
|
||||
// TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
|
||||
DAWN_SKIP_TEST_IF(!(IsMetal() || IsVulkan()));
|
||||
|
||||
// TODO(enga): Figure out why this fails on Metal Intel.
|
||||
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
|
||||
|
||||
wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
|
||||
1, 1, wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc,
|
||||
kDepthStencilFormat);
|
||||
wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
|
||||
|
||||
// Clear the depth to 0.3 and discard the stencil.
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor({}, depthStencilTexture.CreateView());
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.3;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Clear;
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
pass.EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
|
||||
}
|
||||
|
||||
// "all" subresources are not initialized; Stencil is not initialized
|
||||
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1,
|
||||
0, 1, WGPUTextureAspect_All));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
|
||||
1, WGPUTextureAspect_DepthOnly));
|
||||
EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
|
||||
depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
|
||||
|
||||
// Check by copy that the stencil data is lazily cleared to 0.
|
||||
EXPECT_LAZY_CLEAR(1u, EXPECT_TEXTURE_EQ(uint8_t(0), depthStencilTexture, 0, 0, 0, 0,
|
||||
wgpu::TextureAspect::StencilOnly));
|
||||
|
||||
// Everything is initialized now
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
|
||||
1, WGPUTextureAspect_All));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
|
||||
1, WGPUTextureAspect_DepthOnly));
|
||||
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
|
||||
1, WGPUTextureAspect_StencilOnly));
|
||||
|
||||
// Now load both depth and stencil. Stencil should be cleared and depth should stay the same
|
||||
// at 0.3.
|
||||
{
|
||||
wgpu::TextureDescriptor colorDescriptor =
|
||||
CreateTextureDescriptor(1, 1,
|
||||
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
|
||||
wgpu::TextureUsage::OutputAttachment,
|
||||
kColorFormat);
|
||||
wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
|
||||
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
|
||||
depthStencilTexture.CreateView());
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
pass.SetPipeline(CreatePipelineForTest(0.3));
|
||||
pass.Draw(6);
|
||||
pass.EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
// No lazy clear because stencil will clear using a loadOp.
|
||||
EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
|
||||
|
||||
// Expect the texture to be red because both the depth a stencil tests passed.
|
||||
// Depth was 0.3 and stencil was 0
|
||||
std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), colorTexture, 0, 0, kSize, kSize, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// This tests the color attachments clear to 0s
|
||||
TEST_P(TextureZeroInitTest, ColorAttachmentsClear) {
|
||||
wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
// Depth and stencil storeOps must match
|
||||
// Depth and stencil storeOps can be different
|
||||
TEST_F(RenderPassDescriptorValidationTest, DepthStencilStoreOpMismatch) {
|
||||
constexpr uint32_t kArrayLayers = 1;
|
||||
constexpr uint32_t kLevelCount = 1;
|
||||
@@ -223,15 +223,7 @@ namespace {
|
||||
wgpu::TextureView colorTextureView = colorTexture.CreateView(&descriptor);
|
||||
wgpu::TextureView depthStencilView = depthStencilTexture.CreateView(&descriptor);
|
||||
|
||||
// StoreOps mismatch causing the render pass to error
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
|
||||
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
|
||||
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
|
||||
AssertBeginRenderPassError(&renderPass);
|
||||
}
|
||||
|
||||
// StoreOps match so render pass is a success
|
||||
// Base case: StoreOps match so render pass is a success
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
|
||||
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
|
||||
@@ -239,13 +231,21 @@ namespace {
|
||||
AssertBeginRenderPassSuccess(&renderPass);
|
||||
}
|
||||
|
||||
// StoreOps match so render pass is a success
|
||||
// Base case: StoreOps match so render pass is a success
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
|
||||
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Clear;
|
||||
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
|
||||
AssertBeginRenderPassSuccess(&renderPass);
|
||||
}
|
||||
|
||||
// StoreOps mismatch still is a success
|
||||
{
|
||||
utils::ComboRenderPassDescriptor renderPass({}, depthStencilView);
|
||||
renderPass.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
|
||||
renderPass.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Clear;
|
||||
AssertBeginRenderPassSuccess(&renderPass);
|
||||
}
|
||||
}
|
||||
|
||||
// Currently only texture views with arrayLayerCount == 1 are allowed to be color and depth
|
||||
|
||||
Reference in New Issue
Block a user