Resource Management 8: placed resource sub-allocation.
- Adds d3d allocators (placed resource + heap).
- Support for heap tier 1 but only buffers.
- Suballocation optimization is enabled for allocations under 4MB.
BUG=dawn:27
Change-Id: I79177830670d1f322bbadf45f797415a3e9208d9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/5680
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
diff --git a/BUILD.gn b/BUILD.gn
index 24c21ca..9211680 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -256,8 +256,6 @@
"src/dawn_native/d3d12/CommandBufferD3D12.h",
"src/dawn_native/d3d12/CommandRecordingContext.cpp",
"src/dawn_native/d3d12/CommandRecordingContext.h",
- "src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp",
- "src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h",
"src/dawn_native/d3d12/ComputePipelineD3D12.cpp",
"src/dawn_native/d3d12/ComputePipelineD3D12.h",
"src/dawn_native/d3d12/D3D12Error.cpp",
@@ -269,6 +267,10 @@
"src/dawn_native/d3d12/DeviceD3D12.cpp",
"src/dawn_native/d3d12/DeviceD3D12.h",
"src/dawn_native/d3d12/Forward.h",
+ "src/dawn_native/d3d12/HeapAllocatorD3D12.cpp",
+ "src/dawn_native/d3d12/HeapAllocatorD3D12.h",
+ "src/dawn_native/d3d12/HeapD3D12.cpp",
+ "src/dawn_native/d3d12/HeapD3D12.h",
"src/dawn_native/d3d12/NativeSwapChainImplD3D12.cpp",
"src/dawn_native/d3d12/NativeSwapChainImplD3D12.h",
"src/dawn_native/d3d12/PipelineLayoutD3D12.cpp",
diff --git a/src/dawn_native/BuddyMemoryAllocator.cpp b/src/dawn_native/BuddyMemoryAllocator.cpp
index 87f4743..8e8272c 100644
--- a/src/dawn_native/BuddyMemoryAllocator.cpp
+++ b/src/dawn_native/BuddyMemoryAllocator.cpp
@@ -34,12 +34,18 @@
}
ResultOrError<ResourceMemoryAllocation> BuddyMemoryAllocator::Allocate(uint64_t allocationSize,
- uint64_t alignment,
- int memoryFlags) {
+ uint64_t alignment) {
ResourceMemoryAllocation invalidAllocation = ResourceMemoryAllocation{};
+ if (allocationSize == 0) {
+ return invalidAllocation;
+ }
+
+ // Round allocation size to nearest power-of-two.
+ allocationSize = NextPowerOfTwo(allocationSize);
+
// Allocation cannot exceed the memory size.
- if (allocationSize == 0 || allocationSize > mMemorySize) {
+ if (allocationSize > mMemorySize) {
return invalidAllocation;
}
@@ -53,7 +59,7 @@
if (mTrackedSubAllocations[memoryIndex].refcount == 0) {
// Transfer ownership to this allocator
std::unique_ptr<ResourceHeapBase> memory;
- DAWN_TRY_ASSIGN(memory, mClient->Allocate(mMemorySize, memoryFlags));
+ DAWN_TRY_ASSIGN(memory, mClient->Allocate(mMemorySize));
mTrackedSubAllocations[memoryIndex] = {/*refcount*/ 0, std::move(memory)};
}
diff --git a/src/dawn_native/BuddyMemoryAllocator.h b/src/dawn_native/BuddyMemoryAllocator.h
index b31b400..b882113 100644
--- a/src/dawn_native/BuddyMemoryAllocator.h
+++ b/src/dawn_native/BuddyMemoryAllocator.h
@@ -44,8 +44,7 @@
~BuddyMemoryAllocator() = default;
ResultOrError<ResourceMemoryAllocation> Allocate(uint64_t allocationSize,
- uint64_t alignment,
- int memoryFlags = 0);
+ uint64_t alignment);
void Deallocate(const ResourceMemoryAllocation& allocation);
uint64_t GetMemorySize() const;
diff --git a/src/dawn_native/MemoryAllocator.h b/src/dawn_native/MemoryAllocator.h
index e932c91..dfb2993 100644
--- a/src/dawn_native/MemoryAllocator.h
+++ b/src/dawn_native/MemoryAllocator.h
@@ -24,8 +24,7 @@
public:
virtual ~MemoryAllocator() = default;
- virtual ResultOrError<std::unique_ptr<ResourceHeapBase>> Allocate(uint64_t size,
- int memoryFlags) = 0;
+ virtual ResultOrError<std::unique_ptr<ResourceHeapBase>> Allocate(uint64_t size) = 0;
virtual void Deallocate(std::unique_ptr<ResourceHeapBase> allocation) = 0;
};
} // namespace dawn_native
diff --git a/src/dawn_native/d3d12/BufferD3D12.cpp b/src/dawn_native/d3d12/BufferD3D12.cpp
index a0a2083..6c0f912 100644
--- a/src/dawn_native/d3d12/BufferD3D12.cpp
+++ b/src/dawn_native/d3d12/BufferD3D12.cpp
@@ -111,8 +111,7 @@
DAWN_TRY_ASSIGN(
mResourceAllocation,
- ToBackend(GetDevice())
- ->AllocateMemory(heapType, resourceDescriptor, bufferUsage, D3D12_HEAP_FLAG_NONE));
+ ToBackend(GetDevice())->AllocateMemory(heapType, resourceDescriptor, bufferUsage));
return {};
}
diff --git a/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp b/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp
deleted file mode 100644
index 9a55e69..0000000
--- a/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2019 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/CommittedResourceAllocatorD3D12.h"
-#include "dawn_native/d3d12/DeviceD3D12.h"
-
-namespace dawn_native { namespace d3d12 {
-
- CommittedResourceAllocator::CommittedResourceAllocator(Device* device, D3D12_HEAP_TYPE heapType)
- : mDevice(device), mHeapType(heapType) {
- }
-
- ResultOrError<ResourceHeapAllocation> CommittedResourceAllocator::Allocate(
- const D3D12_RESOURCE_DESC& resourceDescriptor,
- D3D12_RESOURCE_STATES initialUsage,
- D3D12_HEAP_FLAGS heapFlags) {
- D3D12_HEAP_PROPERTIES heapProperties;
- heapProperties.Type = mHeapType;
- heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
- heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
- heapProperties.CreationNodeMask = 0;
- heapProperties.VisibleNodeMask = 0;
-
- ComPtr<ID3D12Resource> committedResource;
- if (FAILED(mDevice->GetD3D12Device()->CreateCommittedResource(
- &heapProperties, heapFlags, &resourceDescriptor, initialUsage, nullptr,
- IID_PPV_ARGS(&committedResource)))) {
- return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate resource");
- }
-
- AllocationInfo info;
- info.mMethod = AllocationMethod::kDirect;
-
- return ResourceHeapAllocation{info,
- /*offset*/ 0, std::move(committedResource)};
- }
-
- void CommittedResourceAllocator::Deallocate(ResourceHeapAllocation& allocation) {
- mDevice->ReferenceUntilUnused(allocation.GetD3D12Resource());
- }
-}} // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h b/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h
deleted file mode 100644
index 7bfb9d8..0000000
--- a/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2019 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_COMMITTEDRESOURCEALLOCATORD3D12_H_
-#define DAWNNATIVE_D3D12_COMMITTEDRESOURCEALLOCATORD3D12_H_
-
-#include "common/SerialQueue.h"
-#include "dawn_native/Error.h"
-#include "dawn_native/d3d12/ResourceHeapAllocationD3D12.h"
-#include "dawn_native/d3d12/d3d12_platform.h"
-
-namespace dawn_native { namespace d3d12 {
-
- class Device;
-
- // Wrapper to allocate D3D12 committed resource.
- // Committed resources are implicitly backed by a D3D12 heap.
- class CommittedResourceAllocator {
- public:
- CommittedResourceAllocator(Device* device, D3D12_HEAP_TYPE heapType);
- ~CommittedResourceAllocator() = default;
-
- ResultOrError<ResourceHeapAllocation> Allocate(
- const D3D12_RESOURCE_DESC& resourceDescriptor,
- D3D12_RESOURCE_STATES initialUsage,
- D3D12_HEAP_FLAGS heapFlags);
- void Deallocate(ResourceHeapAllocation& allocation);
-
- private:
- Device* mDevice;
- D3D12_HEAP_TYPE mHeapType;
- };
-
-}} // namespace dawn_native::d3d12
-
-#endif // DAWNNATIVE_D3D12_COMMITTEDRESOURCEALLOCATORD3D12_H_
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index f1b2e31..4a2e981 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -213,6 +213,7 @@
mDynamicUploader->Deallocate(mCompletedSerial);
mResourceAllocator->Tick(mCompletedSerial);
+ mResourceAllocatorManager->Tick(mCompletedSerial);
DAWN_TRY(mCommandAllocatorManager->Tick(mCompletedSerial));
mDescriptorHeapAllocator->Deallocate(mCompletedSerial);
mMapRequestTracker->Tick(mCompletedSerial);
@@ -348,10 +349,9 @@
ResultOrError<ResourceHeapAllocation> Device::AllocateMemory(
D3D12_HEAP_TYPE heapType,
const D3D12_RESOURCE_DESC& resourceDescriptor,
- D3D12_RESOURCE_STATES initialUsage,
- D3D12_HEAP_FLAGS heapFlags) {
- return mResourceAllocatorManager->AllocateMemory(heapType, resourceDescriptor, initialUsage,
- heapFlags);
+ D3D12_RESOURCE_STATES initialUsage) {
+ return mResourceAllocatorManager->AllocateMemory(heapType, resourceDescriptor,
+ initialUsage);
}
TextureBase* Device::WrapSharedHandle(const TextureDescriptor* descriptor,
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index 0a00da2..4981c18 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -90,8 +90,7 @@
ResultOrError<ResourceHeapAllocation> AllocateMemory(
D3D12_HEAP_TYPE heapType,
const D3D12_RESOURCE_DESC& resourceDescriptor,
- D3D12_RESOURCE_STATES initialUsage,
- D3D12_HEAP_FLAGS heapFlags);
+ D3D12_RESOURCE_STATES initialUsage);
void DeallocateMemory(ResourceHeapAllocation& allocation);
diff --git a/src/dawn_native/d3d12/HeapAllocatorD3D12.cpp b/src/dawn_native/d3d12/HeapAllocatorD3D12.cpp
new file mode 100644
index 0000000..8cd5640
--- /dev/null
+++ b/src/dawn_native/d3d12/HeapAllocatorD3D12.cpp
@@ -0,0 +1,52 @@
+// Copyright 2019 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/HeapAllocatorD3D12.h"
+#include "dawn_native/d3d12/DeviceD3D12.h"
+#include "dawn_native/d3d12/HeapD3D12.h"
+
+namespace dawn_native { namespace d3d12 {
+
+ HeapAllocator::HeapAllocator(Device* device,
+ D3D12_HEAP_TYPE heapType,
+ D3D12_HEAP_FLAGS heapFlags)
+ : mDevice(device), mHeapType(heapType), mHeapFlags(heapFlags) {
+ }
+
+ ResultOrError<std::unique_ptr<ResourceHeapBase>> HeapAllocator::Allocate(uint64_t size) {
+ D3D12_HEAP_DESC heapDesc;
+ heapDesc.SizeInBytes = size;
+ heapDesc.Properties.Type = mHeapType;
+ heapDesc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ heapDesc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ heapDesc.Properties.CreationNodeMask = 0;
+ heapDesc.Properties.VisibleNodeMask = 0;
+ // MSAA vs non-MSAA resources have separate heap alignments.
+ // TODO(bryan.bernhart@intel.com): Support heap creation containing MSAA resources.
+ heapDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+ heapDesc.Flags = mHeapFlags;
+
+ ComPtr<ID3D12Heap> heap;
+ if (FAILED(mDevice->GetD3D12Device()->CreateHeap(&heapDesc, IID_PPV_ARGS(&heap)))) {
+ return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate heap");
+ }
+
+ return {std::make_unique<Heap>(std::move(heap))};
+ }
+
+ void HeapAllocator::Deallocate(std::unique_ptr<ResourceHeapBase> heap) {
+ mDevice->ReferenceUntilUnused(static_cast<Heap*>(heap.get())->GetD3D12Heap());
+ }
+
+}} // namespace dawn_native::d3d12
\ No newline at end of file
diff --git a/src/dawn_native/d3d12/HeapAllocatorD3D12.h b/src/dawn_native/d3d12/HeapAllocatorD3D12.h
new file mode 100644
index 0000000..2c91333
--- /dev/null
+++ b/src/dawn_native/d3d12/HeapAllocatorD3D12.h
@@ -0,0 +1,42 @@
+// Copyright 2019 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_HEAPALLOCATORD3D12_H_
+#define DAWNNATIVE_D3D12_HEAPALLOCATORD3D12_H_
+
+#include "dawn_native/MemoryAllocator.h"
+#include "dawn_native/d3d12/d3d12_platform.h"
+
+namespace dawn_native { namespace d3d12 {
+
+ class Device;
+
+ // Wrapper to allocate a D3D12 heap.
+ class HeapAllocator : public MemoryAllocator {
+ public:
+ HeapAllocator(Device* device, D3D12_HEAP_TYPE heapType, D3D12_HEAP_FLAGS heapFlags);
+ ~HeapAllocator() override = default;
+
+ ResultOrError<std::unique_ptr<ResourceHeapBase>> Allocate(uint64_t size) override;
+ void Deallocate(std::unique_ptr<ResourceHeapBase> allocation) override;
+
+ private:
+ Device* mDevice;
+ D3D12_HEAP_TYPE mHeapType;
+ D3D12_HEAP_FLAGS mHeapFlags;
+ };
+
+}} // namespace dawn_native::d3d12
+
+#endif // DAWNNATIVE_D3D12_HEAPALLOCATORD3D12_H_
\ No newline at end of file
diff --git a/src/dawn_native/d3d12/HeapD3D12.cpp b/src/dawn_native/d3d12/HeapD3D12.cpp
new file mode 100644
index 0000000..2e35bdf
--- /dev/null
+++ b/src/dawn_native/d3d12/HeapD3D12.cpp
@@ -0,0 +1,25 @@
+// Copyright 2019 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/HeapD3D12.h"
+
+namespace dawn_native { namespace d3d12 {
+
+ Heap::Heap(ComPtr<ID3D12Heap> heap) : mHeap(std::move(heap)) {
+ }
+
+ ComPtr<ID3D12Heap> Heap::GetD3D12Heap() const {
+ return mHeap;
+ }
+}} // namespace dawn_native::d3d12
\ No newline at end of file
diff --git a/src/dawn_native/d3d12/HeapD3D12.h b/src/dawn_native/d3d12/HeapD3D12.h
new file mode 100644
index 0000000..834e42a
--- /dev/null
+++ b/src/dawn_native/d3d12/HeapD3D12.h
@@ -0,0 +1,35 @@
+// Copyright 2019 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_HEAPD3D12_H_
+#define DAWNNATIVE_D3D12_HEAPD3D12_H_
+
+#include "dawn_native/ResourceHeap.h"
+#include "dawn_native/d3d12/d3d12_platform.h"
+
+namespace dawn_native { namespace d3d12 {
+
+ class Heap : public ResourceHeapBase {
+ public:
+ Heap(ComPtr<ID3D12Heap> heap);
+ ~Heap() = default;
+
+ ComPtr<ID3D12Heap> GetD3D12Heap() const;
+
+ private:
+ ComPtr<ID3D12Heap> mHeap;
+ };
+}} // namespace dawn_native::d3d12
+
+#endif // DAWNNATIVE_D3D12_HEAPD3D12_H_
\ No newline at end of file
diff --git a/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp b/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp
index b18c998..afa1bd4 100644
--- a/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp
+++ b/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp
@@ -13,56 +13,218 @@
// limitations under the License.
#include "dawn_native/d3d12/ResourceAllocatorManagerD3D12.h"
-#include "dawn_native/d3d12/Forward.h"
+
+#include "dawn_native/d3d12/DeviceD3D12.h"
+#include "dawn_native/d3d12/HeapAllocatorD3D12.h"
+#include "dawn_native/d3d12/HeapD3D12.h"
namespace dawn_native { namespace d3d12 {
+ namespace {
+ D3D12_HEAP_TYPE GetD3D12HeapType(ResourceHeapKind resourceHeapKind) {
+ switch (resourceHeapKind) {
+ case Readback_OnlyBuffers:
+ return D3D12_HEAP_TYPE_READBACK;
+ case Default_OnlyBuffers:
+ case Default_OnlyNonRenderableOrDepthTextures:
+ case Default_OnlyRenderableOrDepthTextures:
+ return D3D12_HEAP_TYPE_DEFAULT;
+ case Upload_OnlyBuffers:
+ return D3D12_HEAP_TYPE_UPLOAD;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ D3D12_HEAP_FLAGS GetD3D12HeapFlags(ResourceHeapKind resourceHeapKind) {
+ switch (resourceHeapKind) {
+ case Default_OnlyBuffers:
+ case Readback_OnlyBuffers:
+ case Upload_OnlyBuffers:
+ return D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
+ case Default_OnlyNonRenderableOrDepthTextures:
+ return D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
+ case Default_OnlyRenderableOrDepthTextures:
+ return D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ ResourceHeapKind GetResourceHeapKind(D3D12_RESOURCE_DIMENSION dimension,
+ D3D12_HEAP_TYPE heapType,
+ D3D12_RESOURCE_FLAGS flags) {
+ switch (dimension) {
+ case D3D12_RESOURCE_DIMENSION_BUFFER: {
+ switch (heapType) {
+ case D3D12_HEAP_TYPE_UPLOAD:
+ return Upload_OnlyBuffers;
+ case D3D12_HEAP_TYPE_DEFAULT:
+ return Default_OnlyBuffers;
+ case D3D12_HEAP_TYPE_READBACK:
+ return Readback_OnlyBuffers;
+ default:
+ UNREACHABLE();
+ }
+ } break;
+ case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
+ case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
+ case D3D12_RESOURCE_DIMENSION_TEXTURE3D: {
+ switch (heapType) {
+ case D3D12_HEAP_TYPE_DEFAULT: {
+ if ((flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) ||
+ (flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
+ return Default_OnlyRenderableOrDepthTextures;
+ } else {
+ return Default_OnlyNonRenderableOrDepthTextures;
+ }
+ } break;
+ default:
+ UNREACHABLE();
+ }
+ } break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ } // namespace
ResourceAllocatorManager::ResourceAllocatorManager(Device* device) : mDevice(device) {
+ for (uint32_t i = 0; i < ResourceHeapKind::EnumCount; i++) {
+ const ResourceHeapKind resourceHeapKind = static_cast<ResourceHeapKind>(i);
+ mSubAllocatedResourceAllocators[i] = std::make_unique<BuddyMemoryAllocator>(
+ kMaxHeapSize, kMinHeapSize,
+ std::make_unique<HeapAllocator>(mDevice, GetD3D12HeapType(resourceHeapKind),
+ GetD3D12HeapFlags(resourceHeapKind)));
+ }
}
ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::AllocateMemory(
D3D12_HEAP_TYPE heapType,
const D3D12_RESOURCE_DESC& resourceDescriptor,
- D3D12_RESOURCE_STATES initialUsage,
- D3D12_HEAP_FLAGS heapFlags) {
- const size_t heapTypeIndex = GetD3D12HeapTypeToIndex(heapType);
- ASSERT(heapTypeIndex < kNumHeapTypes);
-
- // Get the direct allocator using a tightly sized heap (aka CreateCommittedResource).
- CommittedResourceAllocator* allocator = mDirectResourceAllocators[heapTypeIndex].get();
- if (allocator == nullptr) {
- mDirectResourceAllocators[heapTypeIndex] =
- std::make_unique<CommittedResourceAllocator>(mDevice, heapType);
- allocator = mDirectResourceAllocators[heapTypeIndex].get();
+ D3D12_RESOURCE_STATES initialUsage) {
+ // TODO(bryan.bernhart@intel.com): Conditionally disable sub-allocation.
+ // For very large resources, there is no benefit to suballocate.
+ // For very small resources, it is inefficent to suballocate given the min. heap
+ // size could be much larger then the resource allocation.
+ // Attempt to satisfy the request using sub-allocation (placed resource in a heap).
+ ResourceHeapAllocation subAllocation;
+ DAWN_TRY_ASSIGN(subAllocation,
+ CreatePlacedResource(heapType, resourceDescriptor, initialUsage));
+ if (subAllocation.GetInfo().mMethod != AllocationMethod::kInvalid) {
+ return subAllocation;
}
- ResourceHeapAllocation allocation;
- DAWN_TRY_ASSIGN(allocation,
- allocator->Allocate(resourceDescriptor, initialUsage, heapFlags));
+ // If sub-allocation fails, fall-back to direct allocation (committed resource).
+ ResourceHeapAllocation directAllocation;
+ DAWN_TRY_ASSIGN(directAllocation,
+ CreateCommittedResource(heapType, resourceDescriptor, initialUsage));
- return allocation;
+ return directAllocation;
}
- size_t ResourceAllocatorManager::GetD3D12HeapTypeToIndex(D3D12_HEAP_TYPE heapType) const {
- ASSERT(heapType > 0);
- ASSERT(static_cast<uint32_t>(heapType) <= kNumHeapTypes);
- return heapType - 1;
+ void ResourceAllocatorManager::Tick(Serial completedSerial) {
+ for (ResourceHeapAllocation& allocation :
+ mAllocationsToDelete.IterateUpTo(completedSerial)) {
+ if (allocation.GetInfo().mMethod == AllocationMethod::kSubAllocated) {
+ FreeMemory(allocation);
+ }
+ }
+ mAllocationsToDelete.ClearUpTo(completedSerial);
}
void ResourceAllocatorManager::DeallocateMemory(ResourceHeapAllocation& allocation) {
if (allocation.GetInfo().mMethod == AllocationMethod::kInvalid) {
return;
}
- CommittedResourceAllocator* allocator = nullptr;
- D3D12_HEAP_PROPERTIES heapProp;
- allocation.GetD3D12Resource()->GetHeapProperties(&heapProp, nullptr);
- const size_t heapTypeIndex = GetD3D12HeapTypeToIndex(heapProp.Type);
- ASSERT(heapTypeIndex < kNumHeapTypes);
- allocator = mDirectResourceAllocators[heapTypeIndex].get();
- allocator->Deallocate(allocation);
- // Invalidate the underlying resource heap in case the client accidentally
+ mAllocationsToDelete.Enqueue(allocation, mDevice->GetPendingCommandSerial());
+
+ // Invalidate the allocation immediately in case one accidentally
// calls DeallocateMemory again using the same allocation.
allocation.Invalidate();
}
+
+ void ResourceAllocatorManager::FreeMemory(ResourceHeapAllocation& allocation) {
+ ASSERT(allocation.GetInfo().mMethod == AllocationMethod::kSubAllocated);
+
+ D3D12_HEAP_PROPERTIES heapProp;
+ allocation.GetD3D12Resource()->GetHeapProperties(&heapProp, nullptr);
+
+ const D3D12_RESOURCE_DESC resourceDescriptor = allocation.GetD3D12Resource()->GetDesc();
+
+ const size_t resourceHeapKindIndex = GetResourceHeapKind(
+ resourceDescriptor.Dimension, heapProp.Type, resourceDescriptor.Flags);
+
+ mSubAllocatedResourceAllocators[resourceHeapKindIndex]->Deallocate(allocation);
+ }
+
+ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreatePlacedResource(
+ D3D12_HEAP_TYPE heapType,
+ const D3D12_RESOURCE_DESC& resourceDescriptor,
+ D3D12_RESOURCE_STATES initialUsage) {
+ const size_t resourceHeapKindIndex =
+ GetResourceHeapKind(resourceDescriptor.Dimension, heapType, resourceDescriptor.Flags);
+
+ BuddyMemoryAllocator* allocator =
+ mSubAllocatedResourceAllocators[resourceHeapKindIndex].get();
+
+ const D3D12_RESOURCE_ALLOCATION_INFO resourceInfo =
+ mDevice->GetD3D12Device()->GetResourceAllocationInfo(0, 1, &resourceDescriptor);
+
+ ResourceMemoryAllocation allocation;
+ DAWN_TRY_ASSIGN(allocation,
+ allocator->Allocate(resourceInfo.SizeInBytes, resourceInfo.Alignment));
+ if (allocation.GetInfo().mMethod == AllocationMethod::kInvalid) {
+ return ResourceHeapAllocation{}; // invalid
+ }
+
+ ID3D12Heap* heap = static_cast<Heap*>(allocation.GetResourceHeap())->GetD3D12Heap().Get();
+
+ // With placed resources, a single heap can be reused.
+ // The resource placed at an offset is only reclaimed
+ // upon Tick or after the last command list using the resource has completed
+ // on the GPU. This means the same physical memory is not reused
+ // within the same command-list and does not require additional synchronization (aliasing
+ // barrier).
+ // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource
+ ComPtr<ID3D12Resource> placedResource;
+ if (FAILED(mDevice->GetD3D12Device()->CreatePlacedResource(
+ heap, allocation.GetOffset(), &resourceDescriptor, initialUsage, nullptr,
+ IID_PPV_ARGS(&placedResource)))) {
+ // Note: Heap must already exist before the resource is created. If CreatePlacedResource
+ // fails, it's unlikely to be OOM.
+ return DAWN_DEVICE_LOST_ERROR("Unable to allocate resource");
+ }
+
+ return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(),
+ std::move(placedResource)};
+ }
+
+ ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedResource(
+ D3D12_HEAP_TYPE heapType,
+ const D3D12_RESOURCE_DESC& resourceDescriptor,
+ D3D12_RESOURCE_STATES initialUsage) {
+ D3D12_HEAP_PROPERTIES heapProperties;
+ heapProperties.Type = heapType;
+ heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ heapProperties.CreationNodeMask = 0;
+ heapProperties.VisibleNodeMask = 0;
+
+ // Note: Heap flags are inferred by the resource descriptor and do not need to be explicitly
+ // provided to CreateCommittedResource.
+ ComPtr<ID3D12Resource> committedResource;
+ if (FAILED(mDevice->GetD3D12Device()->CreateCommittedResource(
+ &heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDescriptor, initialUsage, nullptr,
+ IID_PPV_ARGS(&committedResource)))) {
+ return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate resource");
+ }
+
+ AllocationInfo info;
+ info.mMethod = AllocationMethod::kDirect;
+
+ return ResourceHeapAllocation{info,
+ /*offset*/ 0, std::move(committedResource)};
+ }
+
}} // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.h b/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.h
index d8f1cdb..c879425 100644
--- a/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.h
+++ b/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.h
@@ -15,7 +15,10 @@
#ifndef DAWNNATIVE_D3D12_RESOURCEALLOCATORMANAGERD3D12_H_
#define DAWNNATIVE_D3D12_RESOURCEALLOCATORMANAGERD3D12_H_
-#include "dawn_native/d3d12/CommittedResourceAllocatorD3D12.h"
+#include "common/SerialQueue.h"
+
+#include "dawn_native/BuddyMemoryAllocator.h"
+#include "dawn_native/d3d12/ResourceHeapAllocationD3D12.h"
#include <array>
@@ -23,8 +26,23 @@
class Device;
- // Manages a list of resource allocators used by the device to create resources using multiple
- // allocation methods.
+ // Heap types + flags combinations are named after the D3D constants.
+ // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_heap_flags
+ // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_heap_type
+ enum ResourceHeapKind {
+ Readback_OnlyBuffers,
+ Upload_OnlyBuffers,
+ Default_OnlyBuffers,
+
+ Default_OnlyNonRenderableOrDepthTextures,
+ Default_OnlyRenderableOrDepthTextures,
+
+ EnumCount,
+ InvalidEnum = EnumCount,
+ };
+
+ // Manages a list of resource allocators used by the device to create resources using
+ // multiple allocation methods.
class ResourceAllocatorManager {
public:
ResourceAllocatorManager(Device* device);
@@ -32,29 +50,34 @@
ResultOrError<ResourceHeapAllocation> AllocateMemory(
D3D12_HEAP_TYPE heapType,
const D3D12_RESOURCE_DESC& resourceDescriptor,
- D3D12_RESOURCE_STATES initialUsage,
- D3D12_HEAP_FLAGS heapFlags);
+ D3D12_RESOURCE_STATES initialUsage);
void DeallocateMemory(ResourceHeapAllocation& allocation);
+ void Tick(Serial lastCompletedSerial);
+
private:
- size_t GetD3D12HeapTypeToIndex(D3D12_HEAP_TYPE heapType) const;
+ void FreeMemory(ResourceHeapAllocation& allocation);
+
+ ResultOrError<ResourceHeapAllocation> CreatePlacedResource(
+ D3D12_HEAP_TYPE heapType,
+ const D3D12_RESOURCE_DESC& resourceDescriptor,
+ D3D12_RESOURCE_STATES initialUsage);
+
+ ResultOrError<ResourceHeapAllocation> CreateCommittedResource(
+ D3D12_HEAP_TYPE heapType,
+ const D3D12_RESOURCE_DESC& resourceDescriptor,
+ D3D12_RESOURCE_STATES initialUsage);
Device* mDevice;
- static constexpr uint32_t kNumHeapTypes = 4u; // Number of D3D12_HEAP_TYPE
+ static constexpr uint64_t kMaxHeapSize = 32ll * 1024ll * 1024ll * 1024ll; // 32GB
+ static constexpr uint64_t kMinHeapSize = 4ll * 1024ll * 1024ll; // 4MB
- static_assert(D3D12_HEAP_TYPE_READBACK <= kNumHeapTypes,
- "Readback heap type enum exceeds max heap types");
- static_assert(D3D12_HEAP_TYPE_UPLOAD <= kNumHeapTypes,
- "Upload heap type enum exceeds max heap types");
- static_assert(D3D12_HEAP_TYPE_DEFAULT <= kNumHeapTypes,
- "Default heap type enum exceeds max heap types");
- static_assert(D3D12_HEAP_TYPE_CUSTOM <= kNumHeapTypes,
- "Custom heap type enum exceeds max heap types");
+ std::array<std::unique_ptr<BuddyMemoryAllocator>, ResourceHeapKind::EnumCount>
+ mSubAllocatedResourceAllocators;
- std::array<std::unique_ptr<CommittedResourceAllocator>, kNumHeapTypes>
- mDirectResourceAllocators;
+ SerialQueue<ResourceHeapAllocation> mAllocationsToDelete;
};
}} // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/StagingBufferD3D12.cpp b/src/dawn_native/d3d12/StagingBufferD3D12.cpp
index 9e6c2bd..8d21484 100644
--- a/src/dawn_native/d3d12/StagingBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/StagingBufferD3D12.cpp
@@ -35,9 +35,9 @@
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE;
- DAWN_TRY_ASSIGN(mUploadHeap, mDevice->AllocateMemory(
- D3D12_HEAP_TYPE_UPLOAD, resourceDescriptor,
- D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_HEAP_FLAG_NONE));
+ DAWN_TRY_ASSIGN(mUploadHeap,
+ mDevice->AllocateMemory(D3D12_HEAP_TYPE_UPLOAD, resourceDescriptor,
+ D3D12_RESOURCE_STATE_GENERIC_READ));
if (FAILED(GetResource()->Map(0, nullptr, &mMappedPointer))) {
return DAWN_DEVICE_LOST_ERROR("Unable to map staging buffer.");
@@ -47,6 +47,11 @@
}
StagingBuffer::~StagingBuffer() {
+ // Always check if the allocation is valid before Unmap.
+ // The resource would not exist had it failed to allocate.
+ if (mUploadHeap.GetInfo().mMethod == AllocationMethod::kInvalid) {
+ return;
+ }
// Invalidate the CPU virtual address & flush cache (if needed).
GetResource()->Unmap(0, nullptr);
mMappedPointer = nullptr;
diff --git a/src/tests/unittests/BuddyMemoryAllocatorTests.cpp b/src/tests/unittests/BuddyMemoryAllocatorTests.cpp
index 0f85afb..72f6bbe 100644
--- a/src/tests/unittests/BuddyMemoryAllocatorTests.cpp
+++ b/src/tests/unittests/BuddyMemoryAllocatorTests.cpp
@@ -20,8 +20,7 @@
class DummyMemoryAllocator : public MemoryAllocator {
public:
- ResultOrError<std::unique_ptr<ResourceHeapBase>> Allocate(uint64_t size,
- int memoryFlags = 0) override {
+ ResultOrError<std::unique_ptr<ResourceHeapBase>> Allocate(uint64_t size) override {
return std::make_unique<ResourceHeapBase>();
}
void Deallocate(std::unique_ptr<ResourceHeapBase> allocation) override {