Add validation tests for texture resource tracking - 2

This patch adds tests to verify that texture usage tracking is per
each pass for render, and it is per each dispatch for compute.

Bug: dawn:358
Change-Id: I7ed0f470a6457e4cc53b02cd03c3da7d68cbca9a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/20162
Commit-Queue: Yunchao He <yunchao.he@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp b/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp
index 6daed27..fdbac1e 100644
--- a/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp
+++ b/src/tests/unittests/validation/ResourceUsageTrackingTests.cpp
@@ -921,7 +921,7 @@
     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 @@
                 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 @@
             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.