D3D12: Enable sub-allocation for RTV/DSV heaps.

Uses the staging descriptor allocator to enable
sub-allocation for RTV/DSVs.

This change also simplifies CPU descriptor heap
 management for render-passes:
- Allocating slot-by-slot removes extra attachment
 pass.
- No need for the slower direct allocation allocator.
- Move RP creation of view handles into RP builder.

BUG=dawn:155

Change-Id: I508492a2e56a897bf8c85f9a45cd13f62fa0a2ef
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/20042
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn
index d11afca..4251196 100644
--- a/src/dawn_native/BUILD.gn
+++ b/src/dawn_native/BUILD.gn
@@ -301,8 +301,6 @@
       "d3d12/D3D12Info.h",
       "d3d12/DescriptorHeapAllocationD3D12.cpp",
       "d3d12/DescriptorHeapAllocationD3D12.h",
-      "d3d12/DescriptorHeapAllocator.cpp",
-      "d3d12/DescriptorHeapAllocator.h",
       "d3d12/DeviceD3D12.cpp",
       "d3d12/DeviceD3D12.h",
       "d3d12/Forward.h",
diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt
index ff46a74..9d78325 100644
--- a/src/dawn_native/CMakeLists.txt
+++ b/src/dawn_native/CMakeLists.txt
@@ -182,8 +182,6 @@
         "d3d12/D3D12Info.h"
         "d3d12/DescriptorHeapAllocationD3D12.cpp"
         "d3d12/DescriptorHeapAllocationD3D12.h"
-        "d3d12/DescriptorHeapAllocator.cpp"
-        "d3d12/DescriptorHeapAllocator.h"
         "d3d12/DeviceD3D12.cpp"
         "d3d12/DeviceD3D12.h"
         "d3d12/Forward.h"
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 14d0f95..2726e5c 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -24,7 +24,6 @@
 #include "dawn_native/d3d12/BufferD3D12.h"
 #include "dawn_native/d3d12/CommandRecordingContext.h"
 #include "dawn_native/d3d12/ComputePipelineD3D12.h"
-#include "dawn_native/d3d12/DescriptorHeapAllocator.h"
 #include "dawn_native/d3d12/DeviceD3D12.h"
 #include "dawn_native/d3d12/PipelineLayoutD3D12.h"
 #include "dawn_native/d3d12/PlatformFunctions.h"
@@ -32,6 +31,7 @@
 #include "dawn_native/d3d12/RenderPipelineD3D12.h"
 #include "dawn_native/d3d12/SamplerD3D12.h"
 #include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h"
+#include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h"
 #include "dawn_native/d3d12/TextureCopySplitter.h"
 #include "dawn_native/d3d12/TextureD3D12.h"
 #include "dawn_native/d3d12/UtilsD3D12.h"
@@ -296,53 +296,6 @@
     };
 
     namespace {
-
-        // TODO(jiawei.shao@intel.com): use hash map <RenderPass, OMSetRenderTargetArgs> as
-        // cache to avoid redundant RTV and DSV memory allocations.
-        ResultOrError<OMSetRenderTargetArgs> GetSubpassOMSetRenderTargetArgs(
-            BeginRenderPassCmd* renderPass,
-            Device* device) {
-            OMSetRenderTargetArgs args = {};
-
-            uint32_t rtvCount = static_cast<uint32_t>(
-                renderPass->attachmentState->GetColorAttachmentsMask().count());
-            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();
-            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 = rtvHeap.GetCPUHandle(rtvIndex);
-                D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = view->GetRTVDescriptor();
-                d3dDevice->CreateRenderTargetView(ToBackend(view->GetTexture())->GetD3D12Resource(),
-                                                  &rtvDesc, rtvHandle);
-                args.RTVs[rtvIndex] = rtvHandle;
-
-                ++rtvIndex;
-            }
-            args.numRTVs = rtvCount;
-
-            if (renderPass->attachmentState->HasDepthStencilAttachment()) {
-                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 = dsvHeap.GetCPUHandle(0);
-                D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = view->GetDSVDescriptor();
-                d3dDevice->CreateDepthStencilView(ToBackend(view->GetTexture())->GetD3D12Resource(),
-                                                  &dsvDesc, dsvHandle);
-                args.dsv = dsvHandle;
-            }
-
-            return args;
-        }
-
         class VertexBufferTracker {
           public:
             void OnSetVertexBuffer(uint32_t slot, Buffer* buffer, uint64_t offset) {
@@ -839,13 +792,29 @@
         return {};
     }
 
-    void CommandBuffer::SetupRenderPass(CommandRecordingContext* commandContext,
-                                        BeginRenderPassCmd* renderPass,
-                                        RenderPassBuilder* renderPassBuilder) {
+    MaybeError CommandBuffer::SetupRenderPass(CommandRecordingContext* commandContext,
+                                              BeginRenderPassCmd* renderPass,
+                                              RenderPassBuilder* renderPassBuilder) {
+        Device* device = ToBackend(GetDevice());
+
         for (uint32_t i : IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
             RenderPassColorAttachmentInfo& attachmentInfo = renderPass->colorAttachments[i];
             TextureView* view = ToBackend(attachmentInfo.view.Get());
 
+            // Set view attachment.
+            CPUDescriptorHeapAllocation rtvAllocation;
+            DAWN_TRY_ASSIGN(
+                rtvAllocation,
+                device->GetRenderTargetViewAllocator()->AllocateTransientCPUDescriptors());
+
+            const D3D12_RENDER_TARGET_VIEW_DESC viewDesc = view->GetRTVDescriptor();
+            const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor = rtvAllocation.GetBaseDescriptor();
+
+            device->GetD3D12Device()->CreateRenderTargetView(
+                ToBackend(view->GetTexture())->GetD3D12Resource(), &viewDesc, baseDescriptor);
+
+            renderPassBuilder->SetRenderTargetView(i, baseDescriptor);
+
             // Set color load operation.
             renderPassBuilder->SetRenderTargetBeginningAccess(
                 i, attachmentInfo.loadOp, attachmentInfo.clearColor, view->GetD3D12Format());
@@ -871,6 +840,20 @@
                 renderPass->depthStencilAttachment;
             TextureView* view = ToBackend(renderPass->depthStencilAttachment.view.Get());
 
+            // Set depth attachment.
+            CPUDescriptorHeapAllocation dsvAllocation;
+            DAWN_TRY_ASSIGN(
+                dsvAllocation,
+                device->GetDepthStencilViewAllocator()->AllocateTransientCPUDescriptors());
+
+            const D3D12_DEPTH_STENCIL_VIEW_DESC viewDesc = view->GetDSVDescriptor();
+            const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor = dsvAllocation.GetBaseDescriptor();
+
+            device->GetD3D12Device()->CreateDepthStencilView(
+                ToBackend(view->GetTexture())->GetD3D12Resource(), &viewDesc, baseDescriptor);
+
+            renderPassBuilder->SetDepthStencilView(baseDescriptor);
+
             const bool hasDepth = view->GetTexture()->GetFormat().HasDepth();
             const bool hasStencil = view->GetTexture()->GetFormat().HasStencil();
 
@@ -894,6 +877,8 @@
         } else {
             renderPassBuilder->SetDepthStencilNoAccess();
         }
+
+        return {};
     }
 
     void CommandBuffer::EmulateBeginRenderPass(CommandRecordingContext* commandContext,
@@ -958,17 +943,14 @@
                                                BeginRenderPassCmd* renderPass,
                                                const bool passHasUAV) {
         Device* device = ToBackend(GetDevice());
-        OMSetRenderTargetArgs args;
-        DAWN_TRY_ASSIGN(args, GetSubpassOMSetRenderTargetArgs(renderPass, device));
-
         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
         // valid until after EndRenderPass() has been called.
-        RenderPassBuilder renderPassBuilder(args, passHasUAV);
+        RenderPassBuilder renderPassBuilder(passHasUAV);
 
-        SetupRenderPass(commandContext, renderPass, &renderPassBuilder);
+        DAWN_TRY(SetupRenderPass(commandContext, renderPass, &renderPassBuilder));
 
         // Use D3D12's native render pass API if it's available, otherwise emulate the
         // beginning and ending access operations.
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.h b/src/dawn_native/d3d12/CommandBufferD3D12.h
index b49882b..cc53fd5 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.h
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.h
@@ -19,9 +19,7 @@
 #include "dawn_native/CommandAllocator.h"
 #include "dawn_native/CommandBuffer.h"
 #include "dawn_native/Error.h"
-
 #include "dawn_native/d3d12/Forward.h"
-#include "dawn_native/d3d12/d3d12_platform.h"
 
 #include <array>
 
@@ -31,12 +29,6 @@
 
 namespace dawn_native { namespace d3d12 {
 
-    struct OMSetRenderTargetArgs {
-        unsigned int numRTVs = 0;
-        std::array<D3D12_CPU_DESCRIPTOR_HANDLE, kMaxColorAttachments> RTVs = {};
-        D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
-    };
-
     class BindGroupStateTracker;
     class CommandRecordingContext;
     class Device;
@@ -58,9 +50,9 @@
                                     BindGroupStateTracker* bindingTracker,
                                     BeginRenderPassCmd* renderPass,
                                     bool passHasUAV);
-        void SetupRenderPass(CommandRecordingContext* commandContext,
-                             BeginRenderPassCmd* renderPass,
-                             RenderPassBuilder* renderPassBuilder);
+        MaybeError SetupRenderPass(CommandRecordingContext* commandContext,
+                                   BeginRenderPassCmd* renderPass,
+                                   RenderPassBuilder* renderPassBuilder);
         void EmulateBeginRenderPass(CommandRecordingContext* commandContext,
                                     const RenderPassBuilder* renderPassBuilder) const;
 
diff --git a/src/dawn_native/d3d12/DescriptorHeapAllocator.cpp b/src/dawn_native/d3d12/DescriptorHeapAllocator.cpp
deleted file mode 100644
index facc307..0000000
--- a/src/dawn_native/d3d12/DescriptorHeapAllocator.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "dawn_native/d3d12/DescriptorHeapAllocator.h"
-
-#include "common/Assert.h"
-#include "dawn_native/d3d12/D3D12Error.h"
-#include "dawn_native/d3d12/DeviceD3D12.h"
-
-namespace dawn_native { namespace d3d12 {
-
-    DescriptorHeapHandle::DescriptorHeapHandle()
-        : mDescriptorHeap(nullptr), mSizeIncrement(0), mOffset(0) {
-    }
-
-    DescriptorHeapHandle::DescriptorHeapHandle(ComPtr<ID3D12DescriptorHeap> descriptorHeap,
-                                               uint32_t sizeIncrement,
-                                               uint64_t offset)
-        : mDescriptorHeap(descriptorHeap), mSizeIncrement(sizeIncrement), mOffset(offset) {
-    }
-
-    ID3D12DescriptorHeap* DescriptorHeapHandle::Get() const {
-        return mDescriptorHeap.Get();
-    }
-
-    D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapHandle::GetCPUHandle(uint32_t index) const {
-        ASSERT(mDescriptorHeap);
-        auto handle = mDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
-        handle.ptr += mSizeIncrement * (index + mOffset);
-        return handle;
-    }
-
-    D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapHandle::GetGPUHandle(uint32_t index) const {
-        ASSERT(mDescriptorHeap);
-        auto handle = mDescriptorHeap->GetGPUDescriptorHandleForHeapStart();
-        handle.ptr += mSizeIncrement * (index + mOffset);
-        return handle;
-    }
-
-    DescriptorHeapAllocator::DescriptorHeapAllocator(Device* device)
-        : mDevice(device),
-          mSizeIncrements{
-              device->GetD3D12Device()->GetDescriptorHandleIncrementSize(
-                  D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV),
-              device->GetD3D12Device()->GetDescriptorHandleIncrementSize(
-                  D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER),
-              device->GetD3D12Device()->GetDescriptorHandleIncrementSize(
-                  D3D12_DESCRIPTOR_HEAP_TYPE_RTV),
-              device->GetD3D12Device()->GetDescriptorHandleIncrementSize(
-                  D3D12_DESCRIPTOR_HEAP_TYPE_DSV),
-          } {
-    }
-
-    ResultOrError<DescriptorHeapHandle> DescriptorHeapAllocator::Allocate(
-        D3D12_DESCRIPTOR_HEAP_TYPE type,
-        uint32_t count,
-        uint32_t allocationSize,
-        DescriptorHeapInfo* heapInfo,
-        D3D12_DESCRIPTOR_HEAP_FLAGS flags) {
-        const Serial pendingSerial = mDevice->GetPendingCommandSerial();
-        uint64_t startOffset = (heapInfo->heap == nullptr)
-                                   ? RingBufferAllocator::kInvalidOffset
-                                   : heapInfo->allocator.Allocate(count, pendingSerial);
-        if (startOffset != RingBufferAllocator::kInvalidOffset) {
-            return DescriptorHeapHandle{heapInfo->heap, mSizeIncrements[type], startOffset};
-        }
-
-        // If the pool has no more space, replace the pool with a new one of the specified size
-
-        D3D12_DESCRIPTOR_HEAP_DESC heapDescriptor;
-        heapDescriptor.Type = type;
-        heapDescriptor.NumDescriptors = allocationSize;
-        heapDescriptor.Flags = flags;
-        heapDescriptor.NodeMask = 0;
-        ComPtr<ID3D12DescriptorHeap> heap;
-        DAWN_TRY(CheckHRESULT(
-            mDevice->GetD3D12Device()->CreateDescriptorHeap(&heapDescriptor, IID_PPV_ARGS(&heap)),
-            "ID3D12Device::CreateDescriptorHeap"));
-
-        mDevice->ReferenceUntilUnused(heap);
-
-        *heapInfo = {heap, RingBufferAllocator(allocationSize)};
-
-        startOffset = heapInfo->allocator.Allocate(count, pendingSerial);
-
-        ASSERT(startOffset != RingBufferAllocator::kInvalidOffset);
-
-        return DescriptorHeapHandle(heap, mSizeIncrements[type], startOffset);
-    }
-
-    ResultOrError<DescriptorHeapHandle> DescriptorHeapAllocator::AllocateCPUHeap(
-        D3D12_DESCRIPTOR_HEAP_TYPE type,
-        uint32_t count) {
-        return Allocate(type, count, count, &mCpuDescriptorHeapInfos[type],
-                        D3D12_DESCRIPTOR_HEAP_FLAG_NONE);
-    }
-
-    ResultOrError<DescriptorHeapHandle> DescriptorHeapAllocator::AllocateGPUHeap(
-        D3D12_DESCRIPTOR_HEAP_TYPE type,
-        uint32_t count) {
-        ASSERT(type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ||
-               type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
-        unsigned int heapSize = (type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV
-                                     ? D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1
-                                     : D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE);
-        return Allocate(type, count, heapSize, &mGpuDescriptorHeapInfos[type],
-                        D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
-    }
-
-    void DescriptorHeapAllocator::Deallocate(uint64_t lastCompletedSerial) {
-        for (uint32_t i = 0; i < mCpuDescriptorHeapInfos.size(); i++) {
-            if (mCpuDescriptorHeapInfos[i].heap != nullptr) {
-                mCpuDescriptorHeapInfos[i].allocator.Deallocate(lastCompletedSerial);
-            }
-        }
-
-        for (uint32_t i = 0; i < mGpuDescriptorHeapInfos.size(); i++) {
-            if (mGpuDescriptorHeapInfos[i].heap != nullptr) {
-                mGpuDescriptorHeapInfos[i].allocator.Deallocate(lastCompletedSerial);
-            }
-        }
-    }
-}}  // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/DescriptorHeapAllocator.h b/src/dawn_native/d3d12/DescriptorHeapAllocator.h
deleted file mode 100644
index bcb6ff5..0000000
--- a/src/dawn_native/d3d12/DescriptorHeapAllocator.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef DAWNNATIVE_D3D12_DESCRIPTORHEAPALLOCATOR_H_
-#define DAWNNATIVE_D3D12_DESCRIPTORHEAPALLOCATOR_H_
-
-#include "dawn_native/d3d12/d3d12_platform.h"
-
-#include <array>
-#include <vector>
-#include "common/SerialQueue.h"
-
-#include "dawn_native/Error.h"
-#include "dawn_native/RingBufferAllocator.h"
-
-namespace dawn_native { namespace d3d12 {
-
-    class Device;
-
-    class DescriptorHeapHandle {
-      public:
-        DescriptorHeapHandle();
-        DescriptorHeapHandle(ComPtr<ID3D12DescriptorHeap> descriptorHeap,
-                             uint32_t sizeIncrement,
-                             uint64_t offset);
-
-        ID3D12DescriptorHeap* Get() const;
-        D3D12_CPU_DESCRIPTOR_HANDLE GetCPUHandle(uint32_t index) const;
-        D3D12_GPU_DESCRIPTOR_HANDLE GetGPUHandle(uint32_t index) const;
-
-      private:
-        ComPtr<ID3D12DescriptorHeap> mDescriptorHeap;
-        uint32_t mSizeIncrement;
-        uint64_t mOffset;
-    };
-
-    class DescriptorHeapAllocator {
-      public:
-        DescriptorHeapAllocator(Device* device);
-
-        ResultOrError<DescriptorHeapHandle> AllocateGPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE type,
-                                                            uint32_t count);
-        ResultOrError<DescriptorHeapHandle> AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE type,
-                                                            uint32_t count);
-        void Deallocate(uint64_t lastCompletedSerial);
-
-      private:
-        struct DescriptorHeapInfo {
-            ComPtr<ID3D12DescriptorHeap> heap;
-            RingBufferAllocator allocator;
-        };
-
-        ResultOrError<DescriptorHeapHandle> Allocate(D3D12_DESCRIPTOR_HEAP_TYPE type,
-                                                     uint32_t count,
-                                                     uint32_t allocationSize,
-                                                     DescriptorHeapInfo* heapInfo,
-                                                     D3D12_DESCRIPTOR_HEAP_FLAGS flags);
-
-        Device* mDevice;
-
-        std::array<uint32_t, D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES> mSizeIncrements;
-        std::array<DescriptorHeapInfo, D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES>
-            mCpuDescriptorHeapInfos;
-        std::array<DescriptorHeapInfo, D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES>
-            mGpuDescriptorHeapInfos;
-    };
-
-}}  // namespace dawn_native::d3d12
-
-#endif  // DAWNNATIVE_D3D12_DESCRIPTORHEAPALLOCATOR_H_
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 97c09d7..41895b3 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -26,7 +26,6 @@
 #include "dawn_native/d3d12/CommandBufferD3D12.h"
 #include "dawn_native/d3d12/ComputePipelineD3D12.h"
 #include "dawn_native/d3d12/D3D12Error.h"
-#include "dawn_native/d3d12/DescriptorHeapAllocator.h"
 #include "dawn_native/d3d12/PipelineLayoutD3D12.h"
 #include "dawn_native/d3d12/PlatformFunctions.h"
 #include "dawn_native/d3d12/QueueD3D12.h"
@@ -43,8 +42,9 @@
 
 namespace dawn_native { namespace d3d12 {
 
-    // TODO(dawn:155): Figure out this value.
-    static constexpr uint16_t kStagingDescriptorHeapSize = 1024;
+    // TODO(dawn:155): Figure out these values.
+    static constexpr uint16_t kShaderVisibleDescriptorHeapSize = 1024;
+    static constexpr uint8_t kAttachmentDescriptorHeapSize = 64;
 
     // static
     ResultOrError<Device*> Device::Create(Adapter* adapter, const DeviceDescriptor* descriptor) {
@@ -81,7 +81,6 @@
 
         // Initialize backend services
         mCommandAllocatorManager = std::make_unique<CommandAllocatorManager>(this);
-        mDescriptorHeapAllocator = std::make_unique<DescriptorHeapAllocator>(this);
 
         mShaderVisibleDescriptorAllocator =
             std::make_unique<ShaderVisibleDescriptorAllocator>(this);
@@ -91,13 +90,20 @@
         for (uint32_t countIndex = 1; countIndex < kNumOfStagingDescriptorAllocators;
              countIndex++) {
             mViewAllocators[countIndex] = std::make_unique<StagingDescriptorAllocator>(
-                this, countIndex, kStagingDescriptorHeapSize,
+                this, countIndex, kShaderVisibleDescriptorHeapSize,
                 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
 
             mSamplerAllocators[countIndex] = std::make_unique<StagingDescriptorAllocator>(
-                this, countIndex, kStagingDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+                this, countIndex, kShaderVisibleDescriptorHeapSize,
+                D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
         }
 
+        mRenderTargetViewAllocator = std::make_unique<StagingDescriptorAllocator>(
+            this, 1, kAttachmentDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
+
+        mDepthStencilViewAllocator = std::make_unique<StagingDescriptorAllocator>(
+            this, 1, kAttachmentDescriptorHeapSize, D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
+
         mMapRequestTracker = std::make_unique<MapRequestTracker>(this);
         mResidencyManager = std::make_unique<ResidencyManager>(this);
         mResourceAllocatorManager = std::make_unique<ResourceAllocatorManager>(this);
@@ -159,10 +165,6 @@
         return mDrawIndexedIndirectSignature;
     }
 
-    DescriptorHeapAllocator* Device::GetDescriptorHeapAllocator() const {
-        return mDescriptorHeapAllocator.get();
-    }
-
     ComPtr<IDXGIFactory4> Device::GetFactory() const {
         return ToBackend(GetAdapter())->GetBackend()->GetFactory();
     }
@@ -211,6 +213,8 @@
         mResourceAllocatorManager->Tick(mCompletedSerial);
         DAWN_TRY(mCommandAllocatorManager->Tick(mCompletedSerial));
         mShaderVisibleDescriptorAllocator->Tick(mCompletedSerial);
+        mRenderTargetViewAllocator->Tick(mCompletedSerial);
+        mDepthStencilViewAllocator->Tick(mCompletedSerial);
         mMapRequestTracker->Tick(mCompletedSerial);
         mUsedComObjectRefs.ClearUpTo(mCompletedSerial);
         DAWN_TRY(ExecutePendingCommandContext());
@@ -482,4 +486,13 @@
         ASSERT(descriptorCount < kNumOfStagingDescriptorAllocators);
         return mSamplerAllocators[descriptorCount].get();
     }
+
+    StagingDescriptorAllocator* Device::GetRenderTargetViewAllocator() const {
+        return mRenderTargetViewAllocator.get();
+    }
+
+    StagingDescriptorAllocator* Device::GetDepthStencilViewAllocator() const {
+        return mDepthStencilViewAllocator.get();
+    }
+
 }}  // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index a5bff18..f7298b5 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -67,7 +67,6 @@
         ComPtr<ID3D12CommandSignature> GetDrawIndirectSignature() const;
         ComPtr<ID3D12CommandSignature> GetDrawIndexedIndirectSignature() const;
 
-        DescriptorHeapAllocator* GetDescriptorHeapAllocator() const;
         MapRequestTracker* GetMapRequestTracker() const;
         CommandAllocatorManager* GetCommandAllocatorManager() const;
         ResidencyManager* GetResidencyManager() const;
@@ -110,6 +109,10 @@
         StagingDescriptorAllocator* GetSamplerStagingDescriptorAllocator(
             uint32_t descriptorCount) const;
 
+        StagingDescriptorAllocator* GetRenderTargetViewAllocator() const;
+
+        StagingDescriptorAllocator* GetDepthStencilViewAllocator() const;
+
         TextureBase* WrapSharedHandle(const ExternalImageDescriptor* descriptor,
                                       HANDLE sharedHandle,
                                       uint64_t acquireMutexKey,
@@ -173,7 +176,6 @@
         SerialQueue<ComPtr<IUnknown>> mUsedComObjectRefs;
 
         std::unique_ptr<CommandAllocatorManager> mCommandAllocatorManager;
-        std::unique_ptr<DescriptorHeapAllocator> mDescriptorHeapAllocator;
         std::unique_ptr<MapRequestTracker> mMapRequestTracker;
         std::unique_ptr<ResourceAllocatorManager> mResourceAllocatorManager;
         std::unique_ptr<ResidencyManager> mResidencyManager;
@@ -187,6 +189,10 @@
 
         std::array<std::unique_ptr<StagingDescriptorAllocator>, kNumOfStagingDescriptorAllocators>
             mSamplerAllocators;
+
+        std::unique_ptr<StagingDescriptorAllocator> mRenderTargetViewAllocator;
+
+        std::unique_ptr<StagingDescriptorAllocator> mDepthStencilViewAllocator;
     };
 
 }}  // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp b/src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp
index c6846a0..1965784 100644
--- a/src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp
+++ b/src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp
@@ -102,19 +102,24 @@
         }
     }  // anonymous namespace
 
-    RenderPassBuilder::RenderPassBuilder(const OMSetRenderTargetArgs& args, bool hasUAV)
-        : mColorAttachmentCount(args.numRTVs), mRenderTargetViews(args.RTVs.data()) {
-        for (uint32_t i = 0; i < mColorAttachmentCount; i++) {
-            mRenderPassRenderTargetDescriptors[i].cpuDescriptor = args.RTVs[i];
-        }
-
-        mRenderPassDepthStencilDesc.cpuDescriptor = args.dsv;
-
+    RenderPassBuilder::RenderPassBuilder(bool hasUAV) {
         if (hasUAV) {
             mRenderPassFlags = D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES;
         }
     }
 
+    void RenderPassBuilder::SetRenderTargetView(uint32_t attachmentIndex,
+                                                D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor) {
+        ASSERT(mColorAttachmentCount < kMaxColorAttachments);
+        mRenderTargetViews[attachmentIndex] = baseDescriptor;
+        mRenderPassRenderTargetDescriptors[attachmentIndex].cpuDescriptor = baseDescriptor;
+        mColorAttachmentCount++;
+    }
+
+    void RenderPassBuilder::SetDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor) {
+        mRenderPassDepthStencilDesc.cpuDescriptor = baseDescriptor;
+    }
+
     uint32_t RenderPassBuilder::GetColorAttachmentCount() const {
         return mColorAttachmentCount;
     }
@@ -138,7 +143,7 @@
     }
 
     const D3D12_CPU_DESCRIPTOR_HANDLE* RenderPassBuilder::GetRenderTargetViews() const {
-        return mRenderTargetViews;
+        return mRenderTargetViews.data();
     }
 
     void RenderPassBuilder::SetRenderTargetBeginningAccess(uint32_t attachment,
diff --git a/src/dawn_native/d3d12/RenderPassBuilderD3D12.h b/src/dawn_native/d3d12/RenderPassBuilderD3D12.h
index 1ecd87e..aadb2e8 100644
--- a/src/dawn_native/d3d12/RenderPassBuilderD3D12.h
+++ b/src/dawn_native/d3d12/RenderPassBuilderD3D12.h
@@ -25,8 +25,6 @@
 
     class TextureView;
 
-    struct OMSetRenderTargetArgs;
-
     // RenderPassBuilder stores parameters related to render pass load and store operations.
     // When the D3D12 render pass API is available, the needed descriptors can be fetched
     // directly from the RenderPassBuilder. When the D3D12 render pass API is not available, the
@@ -34,7 +32,7 @@
     // operations is extracted from the descriptors.
     class RenderPassBuilder {
       public:
-        RenderPassBuilder(const OMSetRenderTargetArgs& args, bool hasUAV);
+        RenderPassBuilder(bool hasUAV);
 
         uint32_t GetColorAttachmentCount() const;
 
@@ -72,6 +70,10 @@
                               DXGI_FORMAT format);
         void SetStencilNoAccess();
 
+        void SetRenderTargetView(uint32_t attachmentIndex,
+                                 D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor);
+        void SetDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor);
+
       private:
         uint32_t mColorAttachmentCount = 0;
         bool mHasDepth = false;
@@ -79,7 +81,7 @@
         D3D12_RENDER_PASS_DEPTH_STENCIL_DESC mRenderPassDepthStencilDesc;
         std::array<D3D12_RENDER_PASS_RENDER_TARGET_DESC, kMaxColorAttachments>
             mRenderPassRenderTargetDescriptors;
-        const D3D12_CPU_DESCRIPTOR_HANDLE* mRenderTargetViews;
+        std::array<D3D12_CPU_DESCRIPTOR_HANDLE, kMaxColorAttachments> mRenderTargetViews;
         std::array<D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS,
                    kMaxColorAttachments>
             mSubresourceParams;
diff --git a/src/dawn_native/d3d12/StagingDescriptorAllocatorD3D12.cpp b/src/dawn_native/d3d12/StagingDescriptorAllocatorD3D12.cpp
index d7e0653..84fd788 100644
--- a/src/dawn_native/d3d12/StagingDescriptorAllocatorD3D12.cpp
+++ b/src/dawn_native/d3d12/StagingDescriptorAllocatorD3D12.cpp
@@ -29,8 +29,6 @@
           mBlockSize(descriptorCount * mSizeIncrement),
           mHeapSize(RoundUp(heapSize, descriptorCount)),
           mHeapType(heapType) {
-        ASSERT(heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ||
-               heapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
         ASSERT(descriptorCount <= heapSize);
     }
 
@@ -98,6 +96,8 @@
     }
 
     void StagingDescriptorAllocator::Deallocate(CPUDescriptorHeapAllocation* allocation) {
+        ASSERT(allocation->IsValid());
+
         const uint32_t heapIndex = allocation->GetHeapIndex();
 
         ASSERT(heapIndex < mPool.size());
@@ -132,4 +132,21 @@
         return ((mHeapSize * mSizeIncrement) / mBlockSize);
     }
 
+    ResultOrError<CPUDescriptorHeapAllocation>
+    StagingDescriptorAllocator::AllocateTransientCPUDescriptors() {
+        CPUDescriptorHeapAllocation allocation;
+        DAWN_TRY_ASSIGN(allocation, AllocateCPUDescriptors());
+        mAllocationsToDelete.Enqueue(allocation, mDevice->GetPendingCommandSerial());
+        return allocation;
+    }
+
+    void StagingDescriptorAllocator::Tick(Serial completedSerial) {
+        for (CPUDescriptorHeapAllocation& allocation :
+             mAllocationsToDelete.IterateUpTo(completedSerial)) {
+            Deallocate(&allocation);
+        }
+
+        mAllocationsToDelete.ClearUpTo(completedSerial);
+    }
+
 }}  // namespace dawn_native::d3d12
\ No newline at end of file
diff --git a/src/dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h b/src/dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h
index 292fb10..eebbe2a 100644
--- a/src/dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h
+++ b/src/dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h
@@ -45,10 +45,15 @@
 
         ResultOrError<CPUDescriptorHeapAllocation> AllocateCPUDescriptors();
 
+        // Will call Deallocate when the serial is passed.
+        ResultOrError<CPUDescriptorHeapAllocation> AllocateTransientCPUDescriptors();
+
         void Deallocate(CPUDescriptorHeapAllocation* allocation);
 
         uint32_t GetSizeIncrement() const;
 
+        void Tick(Serial completedSerial);
+
       private:
         using Index = uint16_t;
 
@@ -71,6 +76,8 @@
         uint32_t mHeapSize;       // Size of the heap (in number of descriptors).
 
         D3D12_DESCRIPTOR_HEAP_TYPE mHeapType;
+
+        SerialQueue<CPUDescriptorHeapAllocation> mAllocationsToDelete;
     };
 
 }}  // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index c9242c1..bbcd4e1 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -21,11 +21,11 @@
 #include "dawn_native/d3d12/BufferD3D12.h"
 #include "dawn_native/d3d12/CommandRecordingContext.h"
 #include "dawn_native/d3d12/D3D12Error.h"
-#include "dawn_native/d3d12/DescriptorHeapAllocator.h"
 #include "dawn_native/d3d12/DeviceD3D12.h"
 #include "dawn_native/d3d12/HeapD3D12.h"
 #include "dawn_native/d3d12/ResourceAllocatorManagerD3D12.h"
 #include "dawn_native/d3d12/StagingBufferD3D12.h"
+#include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h"
 #include "dawn_native/d3d12/TextureCopySplitter.h"
 #include "dawn_native/d3d12/UtilsD3D12.h"
 
@@ -622,7 +622,6 @@
         ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
 
         Device* device = ToBackend(GetDevice());
-        DescriptorHeapAllocator* descriptorHeapAllocator = device->GetDescriptorHeapAllocator();
 
         uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
         float fClearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0.f : 1.f;
@@ -642,13 +641,14 @@
                             continue;
                         }
 
-                        DescriptorHeapHandle dsvHeap;
-                        DAWN_TRY_ASSIGN(dsvHeap, descriptorHeapAllocator->AllocateCPUHeap(
-                                                     D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1));
-                        D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0);
+                        CPUDescriptorHeapAllocation dsvHandle;
+                        DAWN_TRY_ASSIGN(dsvHandle, device->GetDepthStencilViewAllocator()
+                                                       ->AllocateTransientCPUDescriptors());
+                        const D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor =
+                            dsvHandle.GetBaseDescriptor();
                         D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = GetDSVDescriptor(level, layer, 1);
                         device->GetD3D12Device()->CreateDepthStencilView(GetD3D12Resource(),
-                                                                         &dsvDesc, dsvHandle);
+                                                                         &dsvDesc, baseDescriptor);
 
                         if (GetFormat().HasDepth()) {
                             clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
@@ -657,7 +657,7 @@
                             clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
                         }
 
-                        commandList->ClearDepthStencilView(dsvHandle, clearFlags, fClearColor,
+                        commandList->ClearDepthStencilView(baseDescriptor, clearFlags, fClearColor,
                                                            clearColor, 0, nullptr);
                     }
                 }
@@ -676,10 +676,10 @@
                             continue;
                         }
 
-                        DescriptorHeapHandle rtvHeap;
-                        DAWN_TRY_ASSIGN(rtvHeap, descriptorHeapAllocator->AllocateCPUHeap(
-                                                     D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1));
-                        D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(0);
+                        CPUDescriptorHeapAllocation rtvHeap;
+                        DAWN_TRY_ASSIGN(rtvHeap, device->GetRenderTargetViewAllocator()
+                                                     ->AllocateTransientCPUDescriptors());
+                        const D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetBaseDescriptor();
 
                         D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = GetRTVDescriptor(level, layer, 1);
                         device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(),