From f3bb4f4f3291cd11221536079e5709bfdf905387 Mon Sep 17 00:00:00 2001 From: Brandon Jones Date: Mon, 9 Mar 2020 15:53:19 +0000 Subject: [PATCH] Residency 2: Create a d3d12::Heap During Direct Allocations When creating a directly allocated resource in D3D12, also create a dawn_native::d3d12::Heap to represent that allocation alongside the ResourceHeapAllocation. This matches D3D12's allocation model when using CreateCommittedResource and makes residency management much easier. Bug: dawn:193 Change-Id: I2280863dcfca57bad72962a2b097f8f2d4cc7dad Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/16381 Commit-Queue: Brandon Jones Reviewed-by: Austin Eng --- src/dawn_native/ResourceMemoryAllocation.h | 3 ++ src/dawn_native/d3d12/Forward.h | 2 ++ src/dawn_native/d3d12/HeapAllocatorD3D12.cpp | 2 +- src/dawn_native/d3d12/HeapD3D12.cpp | 20 +++++++++++-- src/dawn_native/d3d12/HeapD3D12.h | 8 +++-- .../d3d12/ResourceAllocatorManagerD3D12.cpp | 29 ++++++++++++++----- .../d3d12/ResourceHeapAllocationD3D12.cpp | 8 +++-- .../d3d12/ResourceHeapAllocationD3D12.h | 5 +++- src/dawn_native/d3d12/TextureD3D12.cpp | 14 ++++++--- 9 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/dawn_native/ResourceMemoryAllocation.h b/src/dawn_native/ResourceMemoryAllocation.h index a66129ac64..1eb68e7552 100644 --- a/src/dawn_native/ResourceMemoryAllocation.h +++ b/src/dawn_native/ResourceMemoryAllocation.h @@ -31,6 +31,9 @@ namespace dawn_native { // Memory sub-divided using one or more blocks of various sizes. kSubAllocated, + // Memory was allocated outside of Dawn. + kExternal, + // Memory not allocated or freed. kInvalid }; diff --git a/src/dawn_native/d3d12/Forward.h b/src/dawn_native/d3d12/Forward.h index ade12e3ac8..1143a4a5ac 100644 --- a/src/dawn_native/d3d12/Forward.h +++ b/src/dawn_native/d3d12/Forward.h @@ -26,6 +26,7 @@ namespace dawn_native { namespace d3d12 { class CommandBuffer; class ComputePipeline; class Device; + class Heap; class PipelineLayout; class Queue; class RenderPipeline; @@ -47,6 +48,7 @@ namespace dawn_native { namespace d3d12 { using PipelineLayoutType = PipelineLayout; using QueueType = Queue; using RenderPipelineType = RenderPipeline; + using ResourceHeapType = Heap; using SamplerType = Sampler; using ShaderModuleType = ShaderModule; using StagingBufferType = StagingBuffer; diff --git a/src/dawn_native/d3d12/HeapAllocatorD3D12.cpp b/src/dawn_native/d3d12/HeapAllocatorD3D12.cpp index e16f380110..dd6c641545 100644 --- a/src/dawn_native/d3d12/HeapAllocatorD3D12.cpp +++ b/src/dawn_native/d3d12/HeapAllocatorD3D12.cpp @@ -46,7 +46,7 @@ namespace dawn_native { namespace d3d12 { mDevice->GetD3D12Device()->CreateHeap(&heapDesc, IID_PPV_ARGS(&heap)), "ID3D12Device::CreateHeap")); - return {std::make_unique(std::move(heap))}; + return {std::make_unique(std::move(heap), size)}; } void HeapAllocator::DeallocateResourceHeap(std::unique_ptr heap) { diff --git a/src/dawn_native/d3d12/HeapD3D12.cpp b/src/dawn_native/d3d12/HeapD3D12.cpp index 2e35bdf7cf..2548ae0da3 100644 --- a/src/dawn_native/d3d12/HeapD3D12.cpp +++ b/src/dawn_native/d3d12/HeapD3D12.cpp @@ -15,11 +15,25 @@ #include "dawn_native/d3d12/HeapD3D12.h" namespace dawn_native { namespace d3d12 { - - Heap::Heap(ComPtr heap) : mHeap(std::move(heap)) { + Heap::Heap(ComPtr d3d12Pageable, uint64_t size) + : mD3d12Pageable(std::move(d3d12Pageable)), mSize(size) { } + // This function should only be used when mD3D12Pageable was initialized from a ID3D12Pageable + // that was initially created as an ID3D12Heap (i.e. SubAllocation). If the ID3D12Pageable was + // initially created as an ID3D12Resource (i.e. DirectAllocation), then use GetD3D12Pageable(). ComPtr Heap::GetD3D12Heap() const { - return mHeap; + ComPtr heap; + HRESULT result = mD3d12Pageable.As(&heap); + ASSERT(SUCCEEDED(result)); + return heap; + } + + ComPtr Heap::GetD3D12Pageable() const { + return mD3d12Pageable; + } + + uint64_t Heap::GetSize() const { + return mSize; } }} // 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 index 834e42ac9f..c3e648e28e 100644 --- a/src/dawn_native/d3d12/HeapD3D12.h +++ b/src/dawn_native/d3d12/HeapD3D12.h @@ -22,13 +22,17 @@ namespace dawn_native { namespace d3d12 { class Heap : public ResourceHeapBase { public: - Heap(ComPtr heap); + Heap(ComPtr d3d12Pageable, uint64_t size); ~Heap() = default; ComPtr GetD3D12Heap() const; + ComPtr GetD3D12Pageable() const; + + uint64_t GetSize() const; private: - ComPtr mHeap; + ComPtr mD3d12Pageable; + uint64_t mSize = 0; }; }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp b/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp index 1fed89f87f..257b00378d 100644 --- a/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp +++ b/src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp @@ -187,6 +187,13 @@ namespace dawn_native { namespace d3d12 { mAllocationsToDelete.Enqueue(allocation, mDevice->GetPendingCommandSerial()); + // Directly allocated ResourceHeapAllocations are created with a heap object that must be + // manually deleted upon deallocation. See ResourceAllocatorManager::CreateCommittedResource + // for more information. + if (allocation.GetInfo().mMethod == AllocationMethod::kDirect) { + delete allocation.GetResourceHeap(); + } + // Invalidate the allocation immediately in case one accidentally // calls DeallocateMemory again using the same allocation. allocation.Invalidate(); @@ -246,7 +253,7 @@ namespace dawn_native { namespace d3d12 { return ResourceHeapAllocation{}; // invalid } - ID3D12Heap* heap = static_cast(allocation.GetResourceHeap())->GetD3D12Heap().Get(); + Heap* heap = ToBackend(allocation.GetResourceHeap()); // With placed resources, a single heap can be reused. // The resource placed at an offset is only reclaimed @@ -256,13 +263,14 @@ namespace dawn_native { namespace d3d12 { // barrier). // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource ComPtr placedResource; - DAWN_TRY(CheckOutOfMemoryHRESULT(mDevice->GetD3D12Device()->CreatePlacedResource( - heap, allocation.GetOffset(), &resourceDescriptor, - initialUsage, nullptr, IID_PPV_ARGS(&placedResource)), - "ID3D12Device::CreatePlacedResource")); + DAWN_TRY(CheckOutOfMemoryHRESULT( + mDevice->GetD3D12Device()->CreatePlacedResource( + heap->GetD3D12Heap().Get(), allocation.GetOffset(), &resourceDescriptor, + initialUsage, nullptr, IID_PPV_ARGS(&placedResource)), + "ID3D12Device::CreatePlacedResource")); return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(), - std::move(placedResource)}; + std::move(placedResource), heap}; } ResultOrError ResourceAllocatorManager::CreateCommittedResource( @@ -297,11 +305,18 @@ namespace dawn_native { namespace d3d12 { initialUsage, nullptr, IID_PPV_ARGS(&committedResource)), "ID3D12Device::CreateCommittedResource")); + // When using CreateCommittedResource, D3D12 creates an implicit heap that contains the + // resource allocation. Because Dawn's memory residency management occurs at the resource + // heap granularity, every directly allocated ResourceHeapAllocation also stores a Heap + // object. This object is created manually, and must be deleted manually upon deallocation + // of the committed resource. + Heap* heap = new Heap(committedResource, resourceInfo.SizeInBytes); + AllocationInfo info; info.mMethod = AllocationMethod::kDirect; return ResourceHeapAllocation{info, - /*offset*/ 0, std::move(committedResource)}; + /*offset*/ 0, std::move(committedResource), heap}; } }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/ResourceHeapAllocationD3D12.cpp b/src/dawn_native/d3d12/ResourceHeapAllocationD3D12.cpp index bf805cb8d0..c3a89f0590 100644 --- a/src/dawn_native/d3d12/ResourceHeapAllocationD3D12.cpp +++ b/src/dawn_native/d3d12/ResourceHeapAllocationD3D12.cpp @@ -14,13 +14,17 @@ #include "dawn_native/d3d12/ResourceHeapAllocationD3D12.h" +#include "dawn_native/d3d12/HeapD3D12.h" + #include namespace dawn_native { namespace d3d12 { ResourceHeapAllocation::ResourceHeapAllocation(const AllocationInfo& info, uint64_t offset, - ComPtr resource) - : ResourceMemoryAllocation(info, offset, nullptr), mResource(std::move(resource)) { + ComPtr resource, + Heap* heap) + : ResourceMemoryAllocation(info, offset, heap), mResource(std::move(resource)) { + ASSERT((info.mMethod == AllocationMethod::kExternal) == (heap == nullptr)); } void ResourceHeapAllocation::Invalidate() { diff --git a/src/dawn_native/d3d12/ResourceHeapAllocationD3D12.h b/src/dawn_native/d3d12/ResourceHeapAllocationD3D12.h index d764a9675f..71b00fd5fd 100644 --- a/src/dawn_native/d3d12/ResourceHeapAllocationD3D12.h +++ b/src/dawn_native/d3d12/ResourceHeapAllocationD3D12.h @@ -20,12 +20,15 @@ namespace dawn_native { namespace d3d12 { + class Heap; + class ResourceHeapAllocation : public ResourceMemoryAllocation { public: ResourceHeapAllocation() = default; ResourceHeapAllocation(const AllocationInfo& info, uint64_t offset, - ComPtr resource); + ComPtr resource, + Heap* heap); ~ResourceHeapAllocation() override = default; void Invalidate() override; diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp index b07c3edf56..84c0cb45e6 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -322,8 +322,11 @@ namespace dawn_native { namespace d3d12 { mDxgiKeyedMutex = std::move(dxgiKeyedMutex); AllocationInfo info; - info.mMethod = AllocationMethod::kDirect; - mResourceAllocation = {info, 0, std::move(d3d12Resource)}; + info.mMethod = AllocationMethod::kExternal; + // When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the + // texture is owned externally. The texture's owning entity must remain responsible for + // memory management. + mResourceAllocation = {info, 0, std::move(d3d12Resource), nullptr}; return {}; } @@ -370,8 +373,11 @@ namespace dawn_native { namespace d3d12 { ComPtr nativeTexture) : TextureBase(device, descriptor, TextureState::OwnedExternal) { AllocationInfo info; - info.mMethod = AllocationMethod::kDirect; - mResourceAllocation = {info, 0, std::move(nativeTexture)}; + info.mMethod = AllocationMethod::kExternal; + // When creating the ResourceHeapAllocation, the resource heap is set to nullptr because the + // texture is owned externally. The texture's owning entity must remain responsible for + // memory management. + mResourceAllocation = {info, 0, std::move(nativeTexture), nullptr}; SetIsSubresourceContentInitialized(true, 0, descriptor->mipLevelCount, 0, descriptor->arrayLayerCount);