D3D12: Remove extra pre-pass used for RTV/DSV allocation.

Instead of tracking RTV/DSVs before the start of the pass to allocate
memory for CPU descriptors, allocate them at the start of the pass,
removing the need to loop through the entire command buffer each
Submit().

BUG=dawn:256

Change-Id: I72faff8951095c6a45207bfe5b12936715c58abf
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/16261
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 2ab9d8c..c7c42fe 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -270,92 +270,54 @@
         ShaderVisibleDescriptorAllocator* mAllocator;
     };
 
-    class RenderPassDescriptorHeapTracker {
-      public:
-        RenderPassDescriptorHeapTracker(Device* device) : mDevice(device) {
-        }
-
-        // This function must only be called before calling AllocateRTVAndDSVHeaps().
-        void TrackRenderPass(const BeginRenderPassCmd* renderPass) {
-            DAWN_ASSERT(mRTVHeap.Get() == nullptr && mDSVHeap.Get() == nullptr);
-
-            mNumRTVs += static_cast<uint32_t>(
-                renderPass->attachmentState->GetColorAttachmentsMask().count());
-            if (renderPass->attachmentState->HasDepthStencilAttachment()) {
-                ++mNumDSVs;
-            }
-        }
-
-        MaybeError AllocateRTVAndDSVHeaps() {
-            // This function should only be called once.
-            DAWN_ASSERT(mRTVHeap.Get() == nullptr && mDSVHeap.Get() == nullptr);
-            DescriptorHeapAllocator* allocator = mDevice->GetDescriptorHeapAllocator();
-            if (mNumRTVs > 0) {
-                DAWN_TRY_ASSIGN(
-                    mRTVHeap, allocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, mNumRTVs));
-            }
-            if (mNumDSVs > 0) {
-                DAWN_TRY_ASSIGN(
-                    mDSVHeap, allocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, mNumDSVs));
-            }
-            return {};
-        }
+    namespace {
 
         // TODO(jiawei.shao@intel.com): use hash map <RenderPass, OMSetRenderTargetArgs> as
         // cache to avoid redundant RTV and DSV memory allocations.
-        OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(BeginRenderPassCmd* renderPass) {
+        ResultOrError<OMSetRenderTargetArgs> GetSubpassOMSetRenderTargetArgs(
+            BeginRenderPassCmd* renderPass,
+            Device* device) {
             OMSetRenderTargetArgs args = {};
 
-            unsigned int rtvIndex = 0;
             uint32_t rtvCount = static_cast<uint32_t>(
                 renderPass->attachmentState->GetColorAttachmentsMask().count());
-            DAWN_ASSERT(mAllocatedRTVs + rtvCount <= mNumRTVs);
+            DescriptorHeapAllocator* allocator = device->GetDescriptorHeapAllocator();
+            DescriptorHeapHandle rtvHeap;
+            DAWN_TRY_ASSIGN(rtvHeap,
+                            allocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, rtvCount));
+            ASSERT(rtvHeap.Get() != nullptr);
+            ID3D12Device* d3dDevice = device->GetD3D12Device().Get();
+            unsigned int rtvIndex = 0;
             for (uint32_t i :
                  IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
+                ASSERT(rtvIndex < rtvCount);
                 TextureView* view = ToBackend(renderPass->colorAttachments[i].view).Get();
-                D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRTVHeap.GetCPUHandle(mAllocatedRTVs);
+                D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(rtvIndex);
                 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = view->GetRTVDescriptor();
-                mDevice->GetD3D12Device()->CreateRenderTargetView(
-                    ToBackend(view->GetTexture())->GetD3D12Resource(), &rtvDesc, rtvHandle);
-                args.RTVs[i] = rtvHandle;
+                d3dDevice->CreateRenderTargetView(ToBackend(view->GetTexture())->GetD3D12Resource(),
+                                                  &rtvDesc, rtvHandle);
+                args.RTVs[rtvIndex] = rtvHandle;
 
                 ++rtvIndex;
-                ++mAllocatedRTVs;
             }
-            args.numRTVs = rtvIndex;
+            args.numRTVs = rtvCount;
 
             if (renderPass->attachmentState->HasDepthStencilAttachment()) {
-                DAWN_ASSERT(mAllocatedDSVs < mNumDSVs);
+                DescriptorHeapHandle dsvHeap;
+                DAWN_TRY_ASSIGN(dsvHeap,
+                                allocator->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1));
+                ASSERT(dsvHeap.Get() != nullptr);
                 TextureView* view = ToBackend(renderPass->depthStencilAttachment.view).Get();
-                D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDSVHeap.GetCPUHandle(mAllocatedDSVs);
+                D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0);
                 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = view->GetDSVDescriptor();
-                mDevice->GetD3D12Device()->CreateDepthStencilView(
-                    ToBackend(view->GetTexture())->GetD3D12Resource(), &dsvDesc, dsvHandle);
+                d3dDevice->CreateDepthStencilView(ToBackend(view->GetTexture())->GetD3D12Resource(),
+                                                  &dsvDesc, dsvHandle);
                 args.dsv = dsvHandle;
-
-                ++mAllocatedDSVs;
             }
 
             return args;
         }
 
-        bool IsHeapAllocationCompleted() const {
-            return mNumRTVs == mAllocatedRTVs && mNumDSVs == mAllocatedDSVs;
-        }
-
-      private:
-        Device* mDevice;
-        DescriptorHeapHandle mRTVHeap = {};
-        DescriptorHeapHandle mDSVHeap = {};
-        uint32_t mNumRTVs = 0;
-        uint32_t mNumDSVs = 0;
-
-        uint32_t mAllocatedRTVs = 0;
-        uint32_t mAllocatedDSVs = 0;
-    };
-
-    namespace {
-
         class VertexBufferTracker {
           public:
             void OnSetVertexBuffer(uint32_t slot, Buffer* buffer, uint64_t offset) {
@@ -448,51 +410,6 @@
             D3D12_INDEX_BUFFER_VIEW mD3D12BufferView = {};
         };
 
-        MaybeError AllocateAndSetDescriptorHeaps(Device* device,
-                                                 BindGroupStateTracker* bindingTracker,
-                                                 RenderPassDescriptorHeapTracker* renderPassTracker,
-                                                 CommandIterator* commands) {
-            {
-                Command type;
-
-                auto HandleCommand = [&](CommandIterator* commands, Command type) {
-                    switch (type) {
-                        case Command::BeginRenderPass: {
-                            BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
-                            renderPassTracker->TrackRenderPass(cmd);
-                        } break;
-                        default:
-                            SkipCommand(commands, type);
-                    }
-                };
-
-                while (commands->NextCommandId(&type)) {
-                    switch (type) {
-                        case Command::ExecuteBundles: {
-                            ExecuteBundlesCmd* cmd = commands->NextCommand<ExecuteBundlesCmd>();
-                            auto bundles = commands->NextData<Ref<RenderBundleBase>>(cmd->count);
-
-                            for (uint32_t i = 0; i < cmd->count; ++i) {
-                                CommandIterator* commands = bundles[i]->GetCommands();
-                                commands->Reset();
-                                while (commands->NextCommandId(&type)) {
-                                    HandleCommand(commands, type);
-                                }
-                            }
-                        } break;
-                        default:
-                            HandleCommand(commands, type);
-                            break;
-                    }
-                }
-
-                commands->Reset();
-            }
-
-            DAWN_TRY(renderPassTracker->AllocateRTVAndDSVHeaps());
-            return {};
-        }
-
         void ResolveMultisampledRenderPass(CommandRecordingContext* commandContext,
                                            BeginRenderPassCmd* renderPass) {
             ASSERT(renderPass != nullptr);
@@ -540,19 +457,9 @@
     MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext) {
         Device* device = ToBackend(GetDevice());
         BindGroupStateTracker bindingTracker(device);
-        RenderPassDescriptorHeapTracker renderPassTracker(device);
 
         ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
 
-        // Precompute the allocation of bindgroups in descriptor heaps
-        // TODO(cwallez@chromium.org): Iterating over all the commands here is inefficient. We
-        // should have a system where commands and descriptors are recorded in parallel then the
-        // heaps set using a small CommandList inserted just before the main CommandList.
-        {
-            DAWN_TRY(AllocateAndSetDescriptorHeaps(device, &bindingTracker, &renderPassTracker,
-                                                   &mCommands));
-        }
-
         // Make sure we use the correct descriptors for this command list. Could be done once per
         // actual command list but here is ok because there should be few command buffers.
         bindingTracker.SetID3D12DescriptorHeaps(commandList);
@@ -633,8 +540,8 @@
                     bindingTracker.SetInComputePass(false);
 
                     LazyClearRenderPassAttachments(beginRenderPassCmd);
-                    DAWN_TRY(RecordRenderPass(commandContext, &bindingTracker, &renderPassTracker,
-                                              beginRenderPassCmd, passHasUAV));
+                    DAWN_TRY(RecordRenderPass(commandContext, &bindingTracker, beginRenderPassCmd,
+                                              passHasUAV));
 
                     nextPassNumber++;
                 } break;
@@ -779,7 +686,6 @@
             }
         }
 
-        DAWN_ASSERT(renderPassTracker.IsHeapAllocationCompleted());
         return {};
     }
 
@@ -998,16 +904,15 @@
                 : nullptr);
     }
 
-    MaybeError CommandBuffer::RecordRenderPass(
-        CommandRecordingContext* commandContext,
-        BindGroupStateTracker* bindingTracker,
-        RenderPassDescriptorHeapTracker* renderPassDescriptorHeapTracker,
-        BeginRenderPassCmd* renderPass,
-        const bool passHasUAV) {
-        OMSetRenderTargetArgs args =
-            renderPassDescriptorHeapTracker->GetSubpassOMSetRenderTargetArgs(renderPass);
+    MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* commandContext,
+                                               BindGroupStateTracker* bindingTracker,
+                                               BeginRenderPassCmd* renderPass,
+                                               const bool passHasUAV) {
+        Device* device = ToBackend(GetDevice());
+        OMSetRenderTargetArgs args;
+        DAWN_TRY_ASSIGN(args, GetSubpassOMSetRenderTargetArgs(renderPass, device));
 
-        const bool useRenderPass = GetDevice()->IsToggleEnabled(Toggle::UseD3D12RenderPass);
+        const bool useRenderPass = device->IsToggleEnabled(Toggle::UseD3D12RenderPass);
 
         // renderPassBuilder must be scoped to RecordRenderPass because any underlying
         // D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS structs must remain
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.h b/src/dawn_native/d3d12/CommandBufferD3D12.h
index eba2505..6a021f1 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.h
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.h
@@ -54,12 +54,10 @@
       private:
         MaybeError RecordComputePass(CommandRecordingContext* commandContext,
                                      BindGroupStateTracker* bindingTracker);
-        MaybeError RecordRenderPass(
-            CommandRecordingContext* commandContext,
-            BindGroupStateTracker* bindingTracker,
-            RenderPassDescriptorHeapTracker* renderPassDescriptorHeapTracker,
-            BeginRenderPassCmd* renderPass,
-            bool passHasUAV);
+        MaybeError RecordRenderPass(CommandRecordingContext* commandContext,
+                                    BindGroupStateTracker* bindingTracker,
+                                    BeginRenderPassCmd* renderPass,
+                                    bool passHasUAV);
         void SetupRenderPass(CommandRecordingContext* commandContext,
                              BeginRenderPassCmd* renderPass,
                              RenderPassBuilder* renderPassBuilder);