Add tests for texture usage tracking - 3

This change added tests for invisible and unsed bindings for
texture usage tracking. It also removed one buffer test, which
is not useful.

Bug: dawn:365

Change-Id: I01232836fb150ecea011a5fcbc250fa1eb7207cf
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/21120
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-07 16:49:05 +00:00 committed by Commit Bot service account
parent 071fe56ffe
commit 17e1e197e8
1 changed files with 213 additions and 51 deletions

View File

@ -685,46 +685,6 @@ namespace {
} }
} }
// Test that it is valid for multiple readonly usages upon the same buffer even though some
// bindings are not used/visible.
TEST_F(ResourceUsageTrackingTest, MultipleReadonlyBufferUsagesWithInvisibleStage) {
// Test render pass for bind group and index buffer with invisible binding, no conflict
// happens because all buffer usages are readonly.
{
wgpu::Buffer buffer =
CreateBuffer(4, wgpu::BufferUsage::Storage | wgpu::BufferUsage::Index);
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ReadonlyStorageBuffer}});
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, buffer}});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
DummyRenderPass dummyRenderPass(device);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
pass.SetIndexBuffer(buffer);
pass.SetBindGroup(0, bg);
pass.EndPass();
encoder.Finish();
}
// Test compute pass for bind group with invisible binding, no conflict happens because all
// buffer usages are readonly.
{
wgpu::Buffer buffer =
CreateBuffer(4, wgpu::BufferUsage::Storage | wgpu::BufferUsage::Uniform);
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::ReadonlyStorageBuffer},
{1, wgpu::ShaderStage::Compute, wgpu::BindingType::UniformBuffer}});
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, buffer}, {1, buffer}});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetBindGroup(0, bg);
pass.EndPass();
encoder.Finish();
}
}
// Test that it is invalid to have resource usage conflicts even when one of the bindings is not // Test that it is invalid to have resource usage conflicts even when one of the bindings is not
// used in the pipeline. // used in the pipeline.
TEST_F(ResourceUsageTrackingTest, BufferUsageConflictWithUnusedPipelineBindings) { TEST_F(ResourceUsageTrackingTest, BufferUsageConflictWithUnusedPipelineBindings) {
@ -1263,21 +1223,223 @@ namespace {
} }
} }
// TODO (yunchao.he@intel.com): Test that all unused bindings bindGroup still take effect for // Test that it is invalid to have resource usage conflicts even when all bindings are not
// resource tracking. Test code is ready, but it depends on writeonly storage buffer support // visible to the programmable pass where it is used.
TEST_F(ResourceUsageTrackingTest, TextureUsageConflictBetweenInvisibleStagesInBindGroup) {
// Create texture and texture view
wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::Storage);
wgpu::TextureView view = texture.CreateView();
// Test render pass for bind group. The conflict of readonly storage and writeonly storage
// usage doesn't reside in render related stages at all
{
// Create a bind group whose bindings are not visible in render pass
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ReadonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat},
{1, wgpu::ShaderStage::None, wgpu::BindingType::WriteonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat}});
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}});
// These two bindings are invisible in render pass. But we still track these bindings.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
DummyRenderPass dummyRenderPass(device);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
pass.SetBindGroup(0, bg);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test compute pass for bind group. The conflict of readonly storage and writeonly storage
// usage doesn't reside in compute related stage at all
{
// Create a bind group whose bindings are not visible in compute pass
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::ReadonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat},
{1, wgpu::ShaderStage::None, wgpu::BindingType::WriteonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat}});
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}});
// Create a no-op compute pipeline.
wgpu::ComputePipeline cp = CreateNoOpComputePipeline();
// These two bindings are invisible in compute pass. But we still track these bindings.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(cp);
pass.SetBindGroup(0, bg);
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 it is invalid to have resource usage conflicts even when one of the bindings is not
// visible to the programmable pass where it is used.
TEST_F(ResourceUsageTrackingTest, TextureUsageConflictWithInvisibleStageInBindGroup) {
// Create texture and texture view
wgpu::Texture texture =
CreateTexture(wgpu::TextureUsage::Storage | wgpu::TextureUsage::OutputAttachment);
wgpu::TextureView view = texture.CreateView();
// Test render pass
{
// Create the render pass that will use the texture as an output attachment
utils::ComboRenderPassDescriptor renderPass({view});
// Create a bind group which use the texture as readonly storage in compute stage
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ReadonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat}});
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}});
// Texture usage in compute stage in bind group conflicts with render target. And
// binding for compute stage is not visible in render pass. But we still track this
// binding.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.SetBindGroup(0, bg);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test compute pass
{
// Create a bind group which contains both fragment and compute stages
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::ReadonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat},
{1, wgpu::ShaderStage::Compute, wgpu::BindingType::WriteonlyStorageTexture,
false, false, wgpu::TextureViewDimension::Undefined,
wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float,
kFormat}});
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}});
// Create a no-op compute pipeline.
wgpu::ComputePipeline cp = CreateNoOpComputePipeline();
// Texture usage in compute stage conflicts with texture usage in fragment stage. And
// binding for fragment stage is not visible in compute pass. But we still track this
// invisible binding.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(cp);
pass.SetBindGroup(0, bg);
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 it is invalid to have resource usage conflicts even when one of the bindings is not
// used in the pipeline.
TEST_F(ResourceUsageTrackingTest, TextureUsageConflictWithUnusedPipelineBindings) {
// Create texture and texture view
wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::Storage);
wgpu::TextureView view = texture.CreateView();
// Create bind groups.
wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment | 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::Fragment | 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}});
// Test render pass
{
// Create a passthrough render pipeline with a readonly storage texture
wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450
void main() {
})");
wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450
layout(set = 0, binding = 0, rgba8) uniform readonly image2D image;
void main() {
})");
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
pipelineDescriptor.vertexStage.module = vsModule;
pipelineDescriptor.cFragmentStage.module = fsModule;
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &readBGL);
wgpu::RenderPipeline rp = device.CreateRenderPipeline(&pipelineDescriptor);
// Texture binding in readBG conflicts with texture binding in writeBG. The binding
// in writeBG is not used in pipeline. But we still track this binding.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
DummyRenderPass dummyRenderPass(device);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
pass.SetBindGroup(0, readBG);
pass.SetBindGroup(1, writeBG);
pass.SetPipeline(rp);
pass.Draw(3);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test compute pass
{
// Create a passthrough compute pipeline with a readonly storage texture
wgpu::ShaderModule csModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
#version 450
layout(set = 0, binding = 0, rgba8) uniform readonly image2D image;
void main() {
})");
wgpu::ComputePipelineDescriptor pipelineDescriptor;
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &readBGL);
pipelineDescriptor.computeStage.module = csModule;
pipelineDescriptor.computeStage.entryPoint = "main";
wgpu::ComputePipeline cp = device.CreateComputePipeline(&pipelineDescriptor);
// Texture binding in readBG conflicts with texture binding in writeBG. The binding
// in writeBG is not used in pipeline. But we still track this binding.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetBindGroup(0, readBG);
pass.SetBindGroup(1, writeBG);
pass.SetPipeline(cp);
pass.Dispatch(1);
pass.EndPass();
// TODO (yunchao.he@intel.com): add resource tracking per dispatch for compute pass
// ASSERT_DEVICE_ERROR(encoder.Finish());
encoder.Finish();
}
}
// TODO (yunchao.he@intel.com): // TODO (yunchao.he@intel.com):
// * useless bindings in bind groups. For example, a bind group includes bindings for compute
// stage, but the bind group is used in render pass.
//
// * more read write tracking tests for texture which need readonly storage texture and
// writeonly storage texture support
//
// * resource write and read dependency
// 1) across passes (render + render, compute + compute, compute and render mixed) is valid
// 2) across draws/dispatches is invalid
// //
// * Add tests for multiple encoders upon the same resource simultaneously. This situation fits // * Add tests for multiple encoders upon the same resource simultaneously. This situation fits
// some cases like VR, multi-threading, etc. // some cases like VR, multi-threading, etc.
//
// * Add tests for indirect buffer
//
// * Add tests for bundle
} // anonymous namespace } // anonymous namespace