Add tests for resource tracking in compute - 1
This patch adds resource usage tracking tests for overwritten
situations within a draw/dispatch when we call multiple
SetBindGroup. We should track the overwritten resources
even though they are not used in render/compute pass.
Bug: dawn:357
Change-Id: I7467db1c0b43fed8513ddb7604adbbd1be55866f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/20160
Commit-Queue: Yunchao He <yunchao.he@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp b/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp
index 04573ac..ac3ceee 100644
--- a/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp
+++ b/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp
@@ -29,7 +29,7 @@
return device.CreateBuffer(&descriptor);
}
- wgpu::Texture CreateTexture(wgpu::TextureUsage usage, wgpu::TextureFormat format) {
+ wgpu::Texture CreateTexture(wgpu::TextureUsage usage) {
wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.size = {1, 1, 1};
@@ -37,10 +37,12 @@
descriptor.sampleCount = 1;
descriptor.mipLevelCount = 1;
descriptor.usage = usage;
- descriptor.format = format;
+ descriptor.format = kFormat;
return device.CreateTexture(&descriptor);
}
+
+ static constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm;
};
// Test that using a single buffer in multiple read usages in the same pass is allowed.
@@ -421,7 +423,67 @@
}
}
- // TODO (yunchao.he@intel.com) test compute pass
+ // test compute pass
+ {
+ // Create buffers that will be used as index and storage buffers
+ wgpu::Buffer buffer0 = CreateBuffer(512, wgpu::BufferUsage::Storage);
+ wgpu::Buffer buffer1 = CreateBuffer(4, wgpu::BufferUsage::Storage);
+
+ // Create the bind group to use the buffer as storage
+ wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
+ device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::StorageBuffer}});
+ wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
+ device,
+ {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ReadonlyStorageBuffer}});
+ wgpu::BindGroup writeBG0 = utils::MakeBindGroup(device, writeBGL, {{0, buffer0, 0, 4}});
+ wgpu::BindGroup readBG0 = utils::MakeBindGroup(device, readBGL, {{0, buffer0, 256, 4}});
+ wgpu::BindGroup readBG1 = utils::MakeBindGroup(device, readBGL, {{0, buffer1, 0, 4}});
+
+ // Create a passthrough compute pipeline
+ wgpu::ShaderModule csModule =
+ utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
+ #version 450
+ void main() {
+ })");
+ wgpu::ComputePipelineDescriptor pipelineDescriptor;
+ pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &writeBGL);
+ pipelineDescriptor.computeStage.module = csModule;
+ pipelineDescriptor.computeStage.entryPoint = "main";
+ wgpu::ComputePipeline cp = device.CreateComputePipeline(&pipelineDescriptor);
+
+ // Set bind group against the same index twice. The second one overwrites the first one.
+ // Then no buffer is used as both read and write in the same pass. But the overwritten
+ // bind group still take effect.
+ {
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.SetBindGroup(0, writeBG0);
+ pass.SetBindGroup(1, readBG0);
+ pass.SetBindGroup(1, readBG1);
+ pass.SetPipeline(cp);
+ pass.Dispatch(1);
+ pass.EndPass();
+ // TODO (yunchao.he@intel.com): add buffer usage tracking for compute
+ // ASSERT_DEVICE_ERROR(encoder.Finish());
+ encoder.Finish();
+ }
+
+ // Set bind group against the same index twice. The second one overwrites the first one.
+ // Then buffer0 is used as both read and write in the same pass
+ {
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.SetBindGroup(0, writeBG0);
+ pass.SetBindGroup(1, readBG1);
+ pass.SetBindGroup(1, readBG0);
+ pass.SetPipeline(cp);
+ pass.Dispatch(1);
+ pass.EndPass();
+ // TODO (yunchao.he@intel.com): add buffer usage tracking for compute
+ // ASSERT_DEVICE_ERROR(encoder.Finish());
+ encoder.Finish();
+ }
+ }
}
// Test that it is invalid to have resource usage conflicts even when all bindings are not
@@ -653,8 +715,7 @@
{
// Create a texture that will be used as both a sampled texture and a render target
wgpu::Texture texture =
- CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment,
- wgpu::TextureFormat::RGBA8Unorm);
+ CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment);
wgpu::TextureView view = texture.CreateView();
// Create the bind group to use the texture as sampled
@@ -684,12 +745,10 @@
{
// Create a texture that will be used both as a sampled texture and a render target
wgpu::Texture t0 =
- CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment,
- wgpu::TextureFormat::RGBA8Unorm);
+ CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment);
wgpu::TextureView v0 = t0.CreateView();
wgpu::Texture t1 =
- CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment,
- wgpu::TextureFormat::RGBA8Unorm);
+ CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment);
wgpu::TextureView v1 = t1.CreateView();
// Create the bind group to use the texture as sampled
@@ -731,12 +790,10 @@
// allowed.
TEST_F(ResourceUsageTrackingTest, TextureCopyAndTextureUsageInPass) {
// Create textures that will be used as both a sampled texture and a render target
- wgpu::Texture texture0 =
- CreateTexture(wgpu::TextureUsage::CopySrc, wgpu::TextureFormat::RGBA8Unorm);
+ wgpu::Texture texture0 = CreateTexture(wgpu::TextureUsage::CopySrc);
wgpu::Texture texture1 =
CreateTexture(wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled |
- wgpu::TextureUsage::OutputAttachment,
- wgpu::TextureFormat::RGBA8Unorm);
+ wgpu::TextureUsage::OutputAttachment);
wgpu::TextureView view0 = texture0.CreateView();
wgpu::TextureView view1 = texture1.CreateView();
@@ -777,12 +834,10 @@
{
// Create textures that will be used as both a sampled texture and a render target
wgpu::Texture texture0 =
- CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment,
- wgpu::TextureFormat::RGBA8Unorm);
+ CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment);
wgpu::TextureView view0 = texture0.CreateView();
wgpu::Texture texture1 =
- CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment,
- wgpu::TextureFormat::RGBA8Unorm);
+ CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment);
wgpu::TextureView view1 = texture1.CreateView();
// Create the bind group to use the texture as sampled
@@ -818,23 +873,87 @@
}
}
- // TODO (yunchao.he@intel.com) Test compute pass. Test code is ready, but it depends on
- // writeonly storage buffer support.
+ // Test compute pass
+ {
+ // Create a texture that will be used both as storage texture
+ wgpu::Texture texture0 = CreateTexture(wgpu::TextureUsage::Storage);
+ wgpu::TextureView view0 = texture0.CreateView();
+ wgpu::Texture texture1 = CreateTexture(wgpu::TextureUsage::Storage);
+ wgpu::TextureView view1 = texture1.CreateView();
+
+ // Create the bind group to use the texture as readonly and writeonly bindings
+ wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
+ device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::WriteonlyStorageTexture,
+ false, false, wgpu::TextureViewDimension::Undefined,
+ wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
+ kFormat}});
+
+ wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
+ device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ReadonlyStorageTexture,
+ false, false, wgpu::TextureViewDimension::Undefined,
+ wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
+ kFormat}});
+
+ wgpu::BindGroup writeBG0 = utils::MakeBindGroup(device, writeBGL, {{0, view0}});
+ wgpu::BindGroup readBG0 = utils::MakeBindGroup(device, readBGL, {{0, view0}});
+ wgpu::BindGroup readBG1 = utils::MakeBindGroup(device, readBGL, {{0, view1}});
+
+ // Create a passthrough compute pipeline
+ wgpu::ShaderModule csModule =
+ utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
+ #version 450
+ void main() {
+ })");
+ wgpu::ComputePipelineDescriptor pipelineDescriptor;
+ pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &writeBGL);
+ pipelineDescriptor.computeStage.module = csModule;
+ pipelineDescriptor.computeStage.entryPoint = "main";
+ wgpu::ComputePipeline cp = device.CreateComputePipeline(&pipelineDescriptor);
+
+ // Set bind group on the same index twice. The second one overwrites the first one.
+ // No texture is used as both readonly and writeonly storage in the same pass. But the
+ // overwritten texture still take effect during resource tracking.
+ {
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.SetBindGroup(0, writeBG0);
+ pass.SetBindGroup(1, readBG0);
+ pass.SetBindGroup(1, readBG1);
+ pass.SetPipeline(cp);
+ pass.Dispatch(1);
+ pass.EndPass();
+ // TODO (yunchao.he@intel.com): add texture usage tracking for compute
+ // ASSERT_DEVICE_ERROR(encoder.Finish());
+ encoder.Finish();
+ }
+
+ // Set bind group on the same index twice. The second one overwrites the first one.
+ // texture0 is used as both writeonly and readonly storage in the same pass.
+ {
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+ pass.SetBindGroup(0, writeBG0);
+ pass.SetBindGroup(1, readBG1);
+ pass.SetBindGroup(1, readBG0);
+ pass.SetPipeline(cp);
+ pass.Dispatch(1);
+ pass.EndPass();
+ // TODO (yunchao.he@intel.com): add texture usage tracking for compute
+ // ASSERT_DEVICE_ERROR(encoder.Finish());
+ encoder.Finish();
+ }
+ }
}
// TODO (yunchao.he@intel.com): Test that all unused bindings bindGroup still take effect for
// resource tracking. Test code is ready, but it depends on writeonly storage buffer support
// TODO (yunchao.he@intel.com):
- // 1. Add tests for overritten tests:
- // 1) multiple SetBindGroup on the same index
- // 2) multiple SetVertexBuffer on the same index
- // 3) multiple SetIndexBuffer
- // 2. useless bindings in bind groups. For example, a bind group includes bindings for compute
+ // * useless bindings in bind groups. For example, a bind group includes bindings for compute
// stage, but the bind group is used in render pass.
- // 3. more read write tracking tests for texture which need readonly storage texture and
+ // * more read write tracking tests for texture which need readonly storage texture and
// writeonly storage texture support
- // 4. resource write and read dependency
+ // * resource write and read dependency
// 1) across passes (render + render, compute + compute, compute and render mixed) is valid
// 2) across draws/dispatches is invalid