Add resource usage tests in a single draw/dispatch

It is invalid to read and write on the same buffer/texture in
a single draw or dispatch. This change adds tests to cover this
situation.

Note that we have already added resource usage tests between passes
in the same command buffer, and tests between draw or dispatch calls
in the same pass. And this patch adds tests inside a draw or dispatch
call.

Bug: dawn:358

Change-Id: Ic52b2e559e9c996e5b76ea960183d80d67c24178
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/20821
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
Yunchao He 2020-05-04 16:23:09 +00:00 committed by Commit Bot service account
parent a8337c378e
commit a6d7f56cf8
1 changed files with 143 additions and 0 deletions

View File

@ -317,6 +317,71 @@ namespace {
} }
} }
// Test that it is invalid to use the same buffer as both readable and writable in a single
// draw or dispatch.
TEST_F(ResourceUsageTrackingTest, BufferWithReadAndWriteUsageInSingleDrawOrDispatch) {
// Test render pass
{
// Create a buffer and a bind group
wgpu::Buffer buffer =
CreateBuffer(4, wgpu::BufferUsage::Storage | wgpu::BufferUsage::Index);
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::StorageBuffer}});
wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, buffer, 0, 4}});
// Create a no-op render pipeline. Note that bind groups can have more bindings
// than pipeline.
wgpu::RenderPipeline rp = CreateNoOpRenderPipeline();
// It is invalid to use the same buffer as both readable and writable usages in a single
// draw
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
DummyRenderPass dummyRenderPass(device);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
pass.SetPipeline(rp);
pass.SetIndexBuffer(buffer);
pass.SetBindGroup(0, writeBG);
pass.Draw(3);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// test compute pass
{
// Create a buffer and bind groups
wgpu::Buffer buffer = CreateBuffer(4, wgpu::BufferUsage::Storage);
wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ReadonlyStorageBuffer}});
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::StorageBuffer}});
wgpu::BindGroup readBG = utils::MakeBindGroup(device, readBGL, {{0, buffer, 0, 4}});
wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, buffer, 0, 4}});
// Create a no-op compute pipeline. Note that bind groups can have more bindings
// than pipeline.
wgpu::ComputePipeline cp = CreateNoOpComputePipeline();
// It is invalid to use the same buffer as both readable and writable usages in a single
// dispatch
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(cp);
pass.SetBindGroup(0, readBG);
pass.SetBindGroup(1, writeBG);
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 using the same buffer as copy src/dst and writable/readable usage is allowed. // Test that using the same buffer as copy src/dst and writable/readable usage is allowed.
TEST_F(ResourceUsageTrackingTest, BufferCopyAndBufferUsageInPass) { TEST_F(ResourceUsageTrackingTest, BufferCopyAndBufferUsageInPass) {
// Create buffers that will be used as both a copy src/dst buffer and a storage buffer // Create buffers that will be used as both a copy src/dst buffer and a storage buffer
@ -744,6 +809,84 @@ namespace {
} }
} }
// Test that it is invalid to use the same texture as both readable and writable in a single
// draw or dispatch.
TEST_F(ResourceUsageTrackingTest, TextureWithReadAndWriteUsageInSingleDrawOrDispatch) {
// Create a texture that will be used both as a sampled texture and a storage texture
wgpu::Texture texture =
CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::Storage);
wgpu::TextureView view = texture.CreateView();
// Test render pass
{
// Create the bind group to use the texture as sampled and writeonly storage bindings
wgpu::BindGroupLayout sampledBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture}});
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::WriteonlyStorageTexture, false,
false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat}});
wgpu::BindGroup sampledBG = utils::MakeBindGroup(device, sampledBGL, {{0, view}});
wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, view}});
// Create a no-op render pipeline. Note that bind groups can have more bindings
// than pipeline.
wgpu::RenderPipeline rp = CreateNoOpRenderPipeline();
// It is invalid to use the same texture as both readable and writable usages in a
// single draw
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
DummyRenderPass dummyRenderPass(device);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
pass.SetPipeline(rp);
pass.SetBindGroup(0, sampledBG);
pass.SetBindGroup(1, writeBG);
pass.Draw(3);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test compute pass
{
// Create the bind group to use the texture as readonly and writeonly storage bindings
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::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::BindGroup readBG = utils::MakeBindGroup(device, readBGL, {{0, view}});
wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, view}});
// Create a no-op compute pipeline. Note that bind groups can have more bindings
// than pipeline.
wgpu::ComputePipeline cp = CreateNoOpComputePipeline();
// It is invalid to use the same texture as both readable and writable usages in a
// single dispatch
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(cp);
pass.SetBindGroup(0, readBG);
pass.SetBindGroup(1, writeBG);
pass.Dispatch(1);
pass.EndPass();
// TODO (yunchao.he@intel.com): add texture usage tracking for compute
// ASSERT_DEVICE_ERROR(encoder.Finish());
encoder.Finish();
}
}
// Test that using the same texture as both readable and writable in the same pass is disallowed // Test that using the same texture as both readable and writable in the same pass is disallowed
TEST_F(ResourceUsageTrackingTest, TextureWithReadAndWriteUsage) { TEST_F(ResourceUsageTrackingTest, TextureWithReadAndWriteUsage) {
// Test render pass // Test render pass