diff --git a/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp b/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp index 6daed270b1..fdbac1ef4f 100644 --- a/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp +++ b/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp @@ -921,7 +921,7 @@ namespace { TEST_F(ResourceUsageTrackingTest, TextureWithReadAndWriteUsageInDifferentPasses) { // Test render pass { - // Create a texture that will be used both as a sampled texture and a render target + // Create textures that will be used as both a sampled texture and a render target wgpu::Texture t0 = CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment); wgpu::TextureView v0 = t0.CreateView(); @@ -929,17 +929,17 @@ namespace { CreateTexture(wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment); wgpu::TextureView v1 = t1.CreateView(); - // Create the bind group to use the texture as sampled + // Create bind groups to use the texture as sampled wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Vertex, wgpu::BindingType::SampledTexture}}); wgpu::BindGroup bg0 = utils::MakeBindGroup(device, bgl, {{0, v0}}); wgpu::BindGroup bg1 = utils::MakeBindGroup(device, bgl, {{0, v1}}); - // Create the render pass that will use the texture as an output attachment + // Create render passes that will use the textures as output attachments utils::ComboRenderPassDescriptor renderPass0({v1}); utils::ComboRenderPassDescriptor renderPass1({v0}); - // Use the texture as both sampeld and output attachment in different passes + // Use the textures as both sampled and output attachments in different passes wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::RenderPassEncoder pass0 = encoder.BeginRenderPass(&renderPass0); @@ -953,16 +953,157 @@ namespace { encoder.Finish(); } - // TODO (yunchao.he@intel.com) Test compute pass. Test code is ready, but it depends on - // writeonly storage texture support. - // TODO (yunchao.he@intel.com) Test compute pass and render pass mixed together with - // resource dependency. Test code is ready, but it depends on writeonly storage texture - // support. + // Test compute pass + { + // Create a texture that will be used storage texture + wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::Storage); + wgpu::TextureView view = texture.CreateView(); + + // Create bind groups to use the texture as readonly and writeonly 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}}); + + // Use the textures as both readonly and writeonly storages in different passes + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + + wgpu::ComputePassEncoder pass0 = encoder.BeginComputePass(); + pass0.SetBindGroup(0, readBG); + pass0.EndPass(); + + wgpu::ComputePassEncoder pass1 = encoder.BeginComputePass(); + pass1.SetBindGroup(0, writeBG); + pass1.EndPass(); + + encoder.Finish(); + } + + // Test compute pass and render pass mixed together with resource dependency + { + // Create a texture that will be used a storage texture + wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::Storage); + wgpu::TextureView view = texture.CreateView(); + + // Create bind groups 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::Fragment, wgpu::BindingType::ReadonlyStorageTexture, + false, false, wgpu::TextureViewDimension::Undefined, + wgpu::TextureViewDimension::Undefined, wgpu::TextureComponentType::Float, + kFormat}}); + wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, view}}); + wgpu::BindGroup readBG = utils::MakeBindGroup(device, readBGL, {{0, view}}); + + // Use the texture as writeonly and readonly storage in compute pass and render + // pass respectively + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + + wgpu::ComputePassEncoder pass0 = encoder.BeginComputePass(); + pass0.SetBindGroup(0, writeBG); + pass0.EndPass(); + + DummyRenderPass dummyRenderPass(device); + wgpu::RenderPassEncoder pass1 = encoder.BeginRenderPass(&dummyRenderPass); + pass1.SetBindGroup(0, readBG); + pass1.EndPass(); + + encoder.Finish(); + } } - // TODO (yunchao.he@intel.com) Test that using the same texture as both readable and writable in - // the different draws/dispatches is disallowed Test code is ready, but it depends on writeonly - // storage texture support. + // Test that it is invalid to use the same texture as both readable and writable in different + // draws in a single render pass. But it is valid in different dispatches in a single compute + // pass. + TEST_F(ResourceUsageTrackingTest, TextureWithReadAndWriteUsageOnDifferentDrawsOrDispatches) { + // 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 bind groups 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 not allowed to use the same texture as both readable and writable in different + // draws within the same render pass. + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + DummyRenderPass dummyRenderPass(device); + wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass); + pass.SetPipeline(rp); + + pass.SetBindGroup(0, sampledBG); + pass.Draw(3); + + pass.SetBindGroup(0, writeBG); + pass.Draw(3); + + pass.EndPass(); + ASSERT_DEVICE_ERROR(encoder.Finish()); + } + + // Test compute pass + { + // Create bind groups 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 valid to use the same texture as both readable and writable in different + // dispatches within the same compute pass. + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + wgpu::ComputePassEncoder pass = encoder.BeginComputePass(); + pass.SetPipeline(cp); + + pass.SetBindGroup(0, readBG); + pass.Dispatch(1); + + pass.SetBindGroup(0, writeBG); + pass.Dispatch(1); + + pass.EndPass(); + encoder.Finish(); + } + } // Test that using a single texture as copy src/dst and writable/readable usage in pass is // allowed.