Fix Synchronization Bug For Shared Buffers in Bind Groups

Changes how shared buffers are recognized for usage to include shared
buffers used within bind groups. Includes a test.

Bug: 42241325
Change-Id: Ida5f765d596384fc0bb70d91ebd2e8260969a725
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/232256
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Commit-Queue: Brandon1 Jones <brandon1.jones@intel.com>
diff --git a/src/dawn/native/d3d12/BufferD3D12.cpp b/src/dawn/native/d3d12/BufferD3D12.cpp
index 3e454e9..ab9b5f8 100644
--- a/src/dawn/native/d3d12/BufferD3D12.cpp
+++ b/src/dawn/native/d3d12/BufferD3D12.cpp
@@ -340,6 +340,10 @@
 bool Buffer::TrackUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
                                              D3D12_RESOURCE_BARRIER* barrier,
                                              wgpu::BufferUsage newUsage) {
+    if (mResourceAllocation.GetInfo().mMethod == AllocationMethod::kExternal) {
+        commandContext->AddToSharedBufferList(this);
+    }
+
     // Track the underlying heap to ensure residency.
     // There may be no heap if the allocation is an external one.
     Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap());
@@ -424,10 +428,6 @@
 
 void Buffer::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext,
                                         wgpu::BufferUsage newUsage) {
-    if (mResourceAllocation.GetInfo().mMethod == AllocationMethod::kExternal) {
-        commandContext->AddToSharedBufferList(this);
-    }
-
     D3D12_RESOURCE_BARRIER barrier;
 
     if (TrackUsageAndGetResourceBarrier(commandContext, &barrier, newUsage)) {
diff --git a/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp b/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp
index 5b01185..f9d41f9 100644
--- a/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp
+++ b/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp
@@ -573,6 +573,71 @@
     }
 }
 
+// Test to ensure that using a shared buffer in a bind group will trigger a wait for the fence
+// provided to BeginAccess.
+TEST_P(SharedBufferMemoryTests, UseInPassEnsureSynchronization) {
+    wgpu::SharedBufferMemory memory =
+        GetParam().mBackend->CreateSharedBufferMemory(device, kStorageUsages, kBufferSize);
+    wgpu::Buffer buffer = memory.CreateBuffer();
+
+    wgpu::SharedBufferMemoryBeginAccessDescriptor beginAccessDesc;
+    beginAccessDesc.initialized = true;
+    memory.BeginAccess(buffer, &beginAccessDesc);
+
+    wgpu::Buffer srcBuffer =
+        utils::CreateBufferFromData(device, &kBufferData, kBufferSize, wgpu::BufferUsage::CopySrc);
+    wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    encoder.CopyBufferToBuffer(srcBuffer, 0, buffer, 0, kBufferSize);
+    wgpu::CommandBuffer commandBuffer = encoder.Finish();
+    queue.Submit(1, &commandBuffer);
+
+    wgpu::SharedBufferMemoryEndAccessState endState;
+    memory.EndAccess(buffer, &endState);
+
+    // Pass fences from the previous operation to the next BeginAccessDescriptor to ensure
+    // operations are complete.
+    std::vector<wgpu::SharedFence> sharedFences(endState.fenceCount);
+    for (size_t j = 0; j < endState.fenceCount; ++j) {
+        sharedFences[j] = GetParam().mBackend->ImportFenceTo(device, endState.fences[j]);
+    }
+    beginAccessDesc.fenceCount = sharedFences.size();
+    beginAccessDesc.fences = sharedFences.data();
+    beginAccessDesc.signaledValues = endState.signaledValues;
+    beginAccessDesc.initialized = true;
+    wgpu::Buffer buffer2 = memory.CreateBuffer();
+    memory.BeginAccess(buffer2, &beginAccessDesc);
+
+    wgpu::ComputePipelineDescriptor pipelineDescriptor;
+
+    // This compute shader reads from the shared storage buffer and increments it by one.
+    pipelineDescriptor.compute.module = utils::CreateShaderModule(device, R"(
+    struct OutputBuffer {
+        value : u32
+    }
+
+    @group(0) @binding(0) var<storage, read_write> outputBuffer : OutputBuffer;
+
+    @compute @workgroup_size(1) fn main() {
+        outputBuffer.value = outputBuffer.value + 1u;
+    })");
+
+    wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDescriptor);
+    wgpu::BindGroup bindGroup =
+        utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {{0, buffer2}});
+    encoder = device.CreateCommandEncoder();
+    wgpu::CommandBuffer commands;
+    wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+    pass.SetPipeline(pipeline);
+    pass.SetBindGroup(0, bindGroup);
+    pass.DispatchWorkgroups(1);
+    pass.End();
+    commands = encoder.Finish();
+    queue.Submit(1, &commands);
+
+    // The storage buffer should have been incremented by one in the compute shader.
+    EXPECT_BUFFER_U32_EQ(kBufferData + 1, buffer2, 0);
+}
+
 // Test to ensure WriteBuffer waits on a fence provided to BeginAccess.
 TEST_P(SharedBufferMemoryTests, WriteBufferEnsureSynchronization) {
     wgpu::SharedBufferMemory memory =