D3D12: Use ringbuffer allocator for descriptor heaps.

Enable descriptor heap re-use by using ringbuffer.

BUG=dawn:155

Change-Id: I72e3fb98a64dc1af671e185e2114868a577a0554
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9460
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
diff --git a/src/dawn_native/RingBufferAllocator.h b/src/dawn_native/RingBufferAllocator.h
index 82241b3..60ee639 100644
--- a/src/dawn_native/RingBufferAllocator.h
+++ b/src/dawn_native/RingBufferAllocator.h
@@ -25,6 +25,7 @@
 
     class RingBufferAllocator {
       public:
+        RingBufferAllocator() = default;
         RingBufferAllocator(size_t maxSize);
         ~RingBufferAllocator() = default;
 
diff --git a/src/dawn_native/d3d12/DescriptorHeapAllocator.cpp b/src/dawn_native/d3d12/DescriptorHeapAllocator.cpp
index 3f28e5a..29ccab7 100644
--- a/src/dawn_native/d3d12/DescriptorHeapAllocator.cpp
+++ b/src/dawn_native/d3d12/DescriptorHeapAllocator.cpp
@@ -67,24 +67,12 @@
         uint32_t allocationSize,
         DescriptorHeapInfo* heapInfo,
         D3D12_DESCRIPTOR_HEAP_FLAGS flags) {
-        // TODO(enga@google.com): This is just a linear allocator so the heap will quickly run out
-        // of space causing a new one to be allocated We should reuse heap subranges that have been
-        // released
-        if (count == 0) {
-            return DescriptorHeapHandle();
-        }
-
-        {
-            // If the current pool for this type has space, linearly allocate count bytes in the
-            // pool
-            auto& allocationInfo = heapInfo->second;
-            if (allocationInfo.remaining >= count) {
-                DescriptorHeapHandle handle(heapInfo->first, mSizeIncrements[type],
-                                            allocationInfo.size - allocationInfo.remaining);
-                allocationInfo.remaining -= count;
-                Release(handle);
-                return handle;
-            }
+        const Serial pendingSerial = mDevice->GetPendingCommandSerial();
+        size_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
@@ -100,12 +88,15 @@
             return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate heap");
         }
 
-        AllocationInfo allocationInfo = {allocationSize, allocationSize - count};
-        *heapInfo = std::make_pair(heap, allocationInfo);
+        mDevice->ReferenceUntilUnused(heap);
 
-        DescriptorHeapHandle handle(heap, mSizeIncrements[type], 0);
-        Release(handle);
-        return handle;
+        *heapInfo = {heap, RingBufferAllocator(allocationSize)};
+
+        startOffset = heapInfo->allocator.Allocate(count, pendingSerial);
+
+        ASSERT(startOffset != RingBufferAllocator::kInvalidOffset);
+
+        return DescriptorHeapHandle(heap, mSizeIncrements[type], startOffset);
     }
 
     ResultOrError<DescriptorHeapHandle> DescriptorHeapAllocator::AllocateCPUHeap(
@@ -120,18 +111,24 @@
         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 ? kMaxCbvUavSrvHeapSize
-                                                            : kMaxSamplerHeapSize);
+        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::Tick(uint64_t lastCompletedSerial) {
-        mReleasedHandles.ClearUpTo(lastCompletedSerial);
-    }
+    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);
+            }
+        }
 
-    void DescriptorHeapAllocator::Release(DescriptorHeapHandle handle) {
-        mReleasedHandles.Enqueue(handle, mDevice->GetPendingCommandSerial());
+        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
index d98b7a8f..e4949a6 100644
--- a/src/dawn_native/d3d12/DescriptorHeapAllocator.h
+++ b/src/dawn_native/d3d12/DescriptorHeapAllocator.h
@@ -22,6 +22,7 @@
 #include "common/SerialQueue.h"
 
 #include "dawn_native/Error.h"
+#include "dawn_native/RingBufferAllocator.h"
 
 namespace dawn_native { namespace d3d12 {
 
@@ -52,34 +53,27 @@
                                                             uint32_t count);
         ResultOrError<DescriptorHeapHandle> AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE type,
                                                             uint32_t count);
-        void Tick(uint64_t lastCompletedSerial);
+        void Deallocate(uint64_t lastCompletedSerial);
 
       private:
-        static constexpr unsigned int kMaxCbvUavSrvHeapSize = 1000000;
-        static constexpr unsigned int kMaxSamplerHeapSize = 2048;
-        static constexpr unsigned int kDescriptorHeapTypes =
-            D3D12_DESCRIPTOR_HEAP_TYPE::D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES;
-
-        struct AllocationInfo {
-            uint32_t size = 0;
-            uint32_t remaining = 0;
+        struct DescriptorHeapInfo {
+            ComPtr<ID3D12DescriptorHeap> heap;
+            RingBufferAllocator allocator;
         };
 
-        using DescriptorHeapInfo = std::pair<ComPtr<ID3D12DescriptorHeap>, AllocationInfo>;
-
         ResultOrError<DescriptorHeapHandle> Allocate(D3D12_DESCRIPTOR_HEAP_TYPE type,
                                                      uint32_t count,
                                                      uint32_t allocationSize,
                                                      DescriptorHeapInfo* heapInfo,
                                                      D3D12_DESCRIPTOR_HEAP_FLAGS flags);
-        void Release(DescriptorHeapHandle handle);
 
         Device* mDevice;
 
-        std::array<uint32_t, kDescriptorHeapTypes> mSizeIncrements;
-        std::array<DescriptorHeapInfo, kDescriptorHeapTypes> mCpuDescriptorHeapInfos;
-        std::array<DescriptorHeapInfo, kDescriptorHeapTypes> mGpuDescriptorHeapInfos;
-        SerialQueue<DescriptorHeapHandle> mReleasedHandles;
+        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
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index ffc5a7ed..2f535ee 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -221,7 +221,7 @@
 
         mResourceAllocator->Tick(mCompletedSerial);
         mCommandAllocatorManager->Tick(mCompletedSerial);
-        mDescriptorHeapAllocator->Tick(mCompletedSerial);
+        mDescriptorHeapAllocator->Deallocate(mCompletedSerial);
         mMapRequestTracker->Tick(mCompletedSerial);
         mUsedComObjectRefs.ClearUpTo(mCompletedSerial);
         ExecuteCommandList(nullptr);