d3d11: enable GpuMemorySynchronizationTests

RTV and UAV in d3d11 pixel shaders share the same resource slots. To
avoid any potential conflicts, this assigns UAV slots reversely.

Bug: dawn:1807
Bug: dawn:1705

Change-Id: Ie0ca20aa0e532736c0534c6810b8a807dde6f972
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/132274
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn/native/d3d11/CommandBufferD3D11.cpp b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
index 919e317..d5a3d09 100644
--- a/src/dawn/native/d3d11/CommandBufferD3D11.cpp
+++ b/src/dawn/native/d3d11/CommandBufferD3D11.cpp
@@ -32,6 +32,7 @@
 #include "dawn/native/d3d11/ComputePipelineD3D11.h"
 #include "dawn/native/d3d11/DeviceD3D11.h"
 #include "dawn/native/d3d11/Forward.h"
+#include "dawn/native/d3d11/PipelineLayoutD3D11.h"
 #include "dawn/native/d3d11/RenderPipelineD3D11.h"
 #include "dawn/native/d3d11/TextureD3D11.h"
 #include "dawn/native/d3d11/UtilsD3D11.h"
@@ -415,6 +416,7 @@
     ityp::array<ColorAttachmentIndex, ID3D11RenderTargetView*, kMaxColorAttachments>
         d3d11RenderTargetViewPtrs = {};
     ColorAttachmentIndex attachmentCount(uint8_t(0));
+    // TODO(dawn:1815): Shrink the sparse attachments to accommodate more UAVs.
     for (ColorAttachmentIndex i :
          IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
         TextureView* colorTextureView = ToBackend(renderPass->colorAttachments[i].view.Get());
diff --git a/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp b/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp
index 7b9b790..a8e18c6 100644
--- a/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp
+++ b/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp
@@ -25,15 +25,23 @@
     Device* device,
     const PipelineLayoutDescriptor* descriptor) {
     Ref<PipelineLayout> pipelineLayout = AcquireRef(new PipelineLayout(device, descriptor));
-    DAWN_TRY(pipelineLayout->Initialize());
+    DAWN_TRY(pipelineLayout->Initialize(device));
     return pipelineLayout;
 }
 
-MaybeError PipelineLayout::Initialize() {
+MaybeError PipelineLayout::Initialize(Device* device) {
     unsigned int constantBufferIndex = 0;
     unsigned int samplerIndex = 0;
     unsigned int shaderResourceViewIndex = 0;
-    unsigned int unorderedAccessViewIndex = 0;
+    // For d3d11 pixel shaders, the render targets and unordered-access views share the same
+    // resource slots when being written out. So we assign UAV binding index decreasingly here.
+    // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-omsetrendertargetsandunorderedaccessviews
+    // TODO(dawn:1818): Support testing on both FL11_0 and FL11_1.
+    uint32_t unorderedAccessViewIndex =
+        device->GetD3D11Device()->GetFeatureLevel() == D3D_FEATURE_LEVEL_11_1
+            ? D3D11_1_UAV_SLOT_COUNT
+            : D3D11_PS_CS_UAV_REGISTER_COUNT;
+    mTotalUAVBindingCount = unorderedAccessViewIndex;
 
     for (BindGroupIndex group : IterateBitSet(GetBindGroupLayoutsMask())) {
         const BindGroupLayoutBase* bgl = GetBindGroupLayout(group);
@@ -49,7 +57,7 @@
                             break;
                         case wgpu::BufferBindingType::Storage:
                         case kInternalStorageBufferBinding:
-                            mIndexInfo[group][bindingIndex] = unorderedAccessViewIndex++;
+                            mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex;
                             break;
                         case wgpu::BufferBindingType::ReadOnlyStorage:
                             mIndexInfo[group][bindingIndex] = shaderResourceViewIndex++;
@@ -69,11 +77,12 @@
                     break;
 
                 case BindingInfoType::StorageTexture:
-                    mIndexInfo[group][bindingIndex] = unorderedAccessViewIndex++;
+                    mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex;
                     break;
             }
         }
     }
+    mUnusedUAVBindingCount = unorderedAccessViewIndex;
 
     return {};
 }
diff --git a/src/dawn/native/d3d11/PipelineLayoutD3D11.h b/src/dawn/native/d3d11/PipelineLayoutD3D11.h
index 46f6100..d25f7fa 100644
--- a/src/dawn/native/d3d11/PipelineLayoutD3D11.h
+++ b/src/dawn/native/d3d11/PipelineLayoutD3D11.h
@@ -28,7 +28,9 @@
 
 // For D3D11, uniform buffers, samplers, sampled textures, and storage buffers are bind to
 // different kind of slots. The number of slots for each type is limited by the D3D11 spec.
-// So we need to pack the bindings by type into the slots tightly.
+// So we need to pack the bindings by type into the slots tightly. UAV slots are a little
+// different. They are assigned to storage buffers and textures decreasingly from the end,
+// as color attachments also use them increasingly from the begin.
 // And D3D11 uses SM 5.0 which doesn't support spaces(binding groups). so we need to flatten
 // the binding groups into a single array.
 class PipelineLayout final : public PipelineLayoutBase {
@@ -46,14 +48,20 @@
         ityp::array<BindGroupIndex, ityp::vector<BindingIndex, uint32_t>, kMaxBindGroups>;
     const BindingIndexInfo& GetBindingIndexInfo() const;
 
+    uint32_t GetUnusedUAVBindingCount() const { return mUnusedUAVBindingCount; }
+    uint32_t GetTotalUAVBindingCount() const { return mTotalUAVBindingCount; }
+
   private:
     using PipelineLayoutBase::PipelineLayoutBase;
 
     ~PipelineLayout() override = default;
 
-    MaybeError Initialize();
+    MaybeError Initialize(Device* device);
 
     BindingIndexInfo mIndexInfo;
+
+    uint32_t mUnusedUAVBindingCount = 0u;
+    uint32_t mTotalUAVBindingCount = 0u;
 };
 
 }  // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/RenderPipelineD3D11.cpp b/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
index 3c51fb0..7267c61 100644
--- a/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
+++ b/src/dawn/native/d3d11/RenderPipelineD3D11.cpp
@@ -183,6 +183,19 @@
     DAWN_TRY(InitializeShaders());
     DAWN_TRY(InitializeDepthStencilState());
 
+    // RTVs and UAVs share the same resoure slots. Make sure here we are not going to run out of
+    // slots.
+    uint32_t colorAttachments =
+        static_cast<uint8_t>(GetHighestBitIndexPlusOne(GetColorAttachmentsMask()));
+    uint32_t unusedUAVs = ToBackend(GetLayout())->GetUnusedUAVBindingCount();
+    uint32_t usedUAVs = ToBackend(GetLayout())->GetTotalUAVBindingCount() - unusedUAVs;
+    // TODO(dawn:1814): Move the validation to the frontend, if we eventually regard it as a compat
+    // restriction.
+    DAWN_INVALID_IF(colorAttachments > unusedUAVs,
+                    "The pipeline uses up to color attachment %u, but there are only %u remaining "
+                    "slots because the pipeline uses %u UAVs",
+                    colorAttachments, unusedUAVs, usedUAVs);
+
     SetLabelImpl();
     return {};
 }
diff --git a/src/dawn/tests/end2end/GpuMemorySynchronizationTests.cpp b/src/dawn/tests/end2end/GpuMemorySynchronizationTests.cpp
index 4b93539..f19f888 100644
--- a/src/dawn/tests/end2end/GpuMemorySynchronizationTests.cpp
+++ b/src/dawn/tests/end2end/GpuMemorySynchronizationTests.cpp
@@ -214,6 +214,7 @@
 }
 
 DAWN_INSTANTIATE_TEST(GpuMemorySyncTests,
+                      D3D11Backend(),
                       D3D12Backend(),
                       MetalBackend(),
                       OpenGLBackend(),
@@ -385,6 +386,7 @@
 }
 
 DAWN_INSTANTIATE_TEST(StorageToUniformSyncTests,
+                      D3D11Backend(),
                       D3D12Backend(),
                       MetalBackend(),
                       OpenGLBackend(),
@@ -646,6 +648,7 @@
 }
 
 DAWN_INSTANTIATE_TEST(MultipleWriteThenMultipleReadTests,
+                      D3D11Backend(),
                       D3D12Backend(),
                       MetalBackend(),
                       OpenGLBackend(),