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 <brandon1.jones@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Brandon Jones 2020-03-09 15:53:19 +00:00 committed by Commit Bot service account
parent be6cd51888
commit f3bb4f4f32
9 changed files with 71 additions and 20 deletions

View File

@ -31,6 +31,9 @@ namespace dawn_native {
// Memory sub-divided using one or more blocks of various sizes. // Memory sub-divided using one or more blocks of various sizes.
kSubAllocated, kSubAllocated,
// Memory was allocated outside of Dawn.
kExternal,
// Memory not allocated or freed. // Memory not allocated or freed.
kInvalid kInvalid
}; };

View File

@ -26,6 +26,7 @@ namespace dawn_native { namespace d3d12 {
class CommandBuffer; class CommandBuffer;
class ComputePipeline; class ComputePipeline;
class Device; class Device;
class Heap;
class PipelineLayout; class PipelineLayout;
class Queue; class Queue;
class RenderPipeline; class RenderPipeline;
@ -47,6 +48,7 @@ namespace dawn_native { namespace d3d12 {
using PipelineLayoutType = PipelineLayout; using PipelineLayoutType = PipelineLayout;
using QueueType = Queue; using QueueType = Queue;
using RenderPipelineType = RenderPipeline; using RenderPipelineType = RenderPipeline;
using ResourceHeapType = Heap;
using SamplerType = Sampler; using SamplerType = Sampler;
using ShaderModuleType = ShaderModule; using ShaderModuleType = ShaderModule;
using StagingBufferType = StagingBuffer; using StagingBufferType = StagingBuffer;

View File

@ -46,7 +46,7 @@ namespace dawn_native { namespace d3d12 {
mDevice->GetD3D12Device()->CreateHeap(&heapDesc, IID_PPV_ARGS(&heap)), mDevice->GetD3D12Device()->CreateHeap(&heapDesc, IID_PPV_ARGS(&heap)),
"ID3D12Device::CreateHeap")); "ID3D12Device::CreateHeap"));
return {std::make_unique<Heap>(std::move(heap))}; return {std::make_unique<Heap>(std::move(heap), size)};
} }
void HeapAllocator::DeallocateResourceHeap(std::unique_ptr<ResourceHeapBase> heap) { void HeapAllocator::DeallocateResourceHeap(std::unique_ptr<ResourceHeapBase> heap) {

View File

@ -15,11 +15,25 @@
#include "dawn_native/d3d12/HeapD3D12.h" #include "dawn_native/d3d12/HeapD3D12.h"
namespace dawn_native { namespace d3d12 { namespace dawn_native { namespace d3d12 {
Heap::Heap(ComPtr<ID3D12Pageable> d3d12Pageable, uint64_t size)
Heap::Heap(ComPtr<ID3D12Heap> heap) : mHeap(std::move(heap)) { : 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<ID3D12Heap> Heap::GetD3D12Heap() const { ComPtr<ID3D12Heap> Heap::GetD3D12Heap() const {
return mHeap; ComPtr<ID3D12Heap> heap;
HRESULT result = mD3d12Pageable.As(&heap);
ASSERT(SUCCEEDED(result));
return heap;
}
ComPtr<ID3D12Pageable> Heap::GetD3D12Pageable() const {
return mD3d12Pageable;
}
uint64_t Heap::GetSize() const {
return mSize;
} }
}} // namespace dawn_native::d3d12 }} // namespace dawn_native::d3d12

View File

@ -22,13 +22,17 @@ namespace dawn_native { namespace d3d12 {
class Heap : public ResourceHeapBase { class Heap : public ResourceHeapBase {
public: public:
Heap(ComPtr<ID3D12Heap> heap); Heap(ComPtr<ID3D12Pageable> d3d12Pageable, uint64_t size);
~Heap() = default; ~Heap() = default;
ComPtr<ID3D12Heap> GetD3D12Heap() const; ComPtr<ID3D12Heap> GetD3D12Heap() const;
ComPtr<ID3D12Pageable> GetD3D12Pageable() const;
uint64_t GetSize() const;
private: private:
ComPtr<ID3D12Heap> mHeap; ComPtr<ID3D12Pageable> mD3d12Pageable;
uint64_t mSize = 0;
}; };
}} // namespace dawn_native::d3d12 }} // namespace dawn_native::d3d12

View File

@ -187,6 +187,13 @@ namespace dawn_native { namespace d3d12 {
mAllocationsToDelete.Enqueue(allocation, mDevice->GetPendingCommandSerial()); 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 // Invalidate the allocation immediately in case one accidentally
// calls DeallocateMemory again using the same allocation. // calls DeallocateMemory again using the same allocation.
allocation.Invalidate(); allocation.Invalidate();
@ -246,7 +253,7 @@ namespace dawn_native { namespace d3d12 {
return ResourceHeapAllocation{}; // invalid return ResourceHeapAllocation{}; // invalid
} }
ID3D12Heap* heap = static_cast<Heap*>(allocation.GetResourceHeap())->GetD3D12Heap().Get(); Heap* heap = ToBackend(allocation.GetResourceHeap());
// With placed resources, a single heap can be reused. // With placed resources, a single heap can be reused.
// The resource placed at an offset is only reclaimed // The resource placed at an offset is only reclaimed
@ -256,13 +263,14 @@ namespace dawn_native { namespace d3d12 {
// barrier). // barrier).
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource
ComPtr<ID3D12Resource> placedResource; ComPtr<ID3D12Resource> placedResource;
DAWN_TRY(CheckOutOfMemoryHRESULT(mDevice->GetD3D12Device()->CreatePlacedResource( DAWN_TRY(CheckOutOfMemoryHRESULT(
heap, allocation.GetOffset(), &resourceDescriptor, mDevice->GetD3D12Device()->CreatePlacedResource(
initialUsage, nullptr, IID_PPV_ARGS(&placedResource)), heap->GetD3D12Heap().Get(), allocation.GetOffset(), &resourceDescriptor,
"ID3D12Device::CreatePlacedResource")); initialUsage, nullptr, IID_PPV_ARGS(&placedResource)),
"ID3D12Device::CreatePlacedResource"));
return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(), return ResourceHeapAllocation{allocation.GetInfo(), allocation.GetOffset(),
std::move(placedResource)}; std::move(placedResource), heap};
} }
ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedResource( ResultOrError<ResourceHeapAllocation> ResourceAllocatorManager::CreateCommittedResource(
@ -297,11 +305,18 @@ namespace dawn_native { namespace d3d12 {
initialUsage, nullptr, IID_PPV_ARGS(&committedResource)), initialUsage, nullptr, IID_PPV_ARGS(&committedResource)),
"ID3D12Device::CreateCommittedResource")); "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; AllocationInfo info;
info.mMethod = AllocationMethod::kDirect; info.mMethod = AllocationMethod::kDirect;
return ResourceHeapAllocation{info, return ResourceHeapAllocation{info,
/*offset*/ 0, std::move(committedResource)}; /*offset*/ 0, std::move(committedResource), heap};
} }
}} // namespace dawn_native::d3d12 }} // namespace dawn_native::d3d12

View File

@ -14,13 +14,17 @@
#include "dawn_native/d3d12/ResourceHeapAllocationD3D12.h" #include "dawn_native/d3d12/ResourceHeapAllocationD3D12.h"
#include "dawn_native/d3d12/HeapD3D12.h"
#include <utility> #include <utility>
namespace dawn_native { namespace d3d12 { namespace dawn_native { namespace d3d12 {
ResourceHeapAllocation::ResourceHeapAllocation(const AllocationInfo& info, ResourceHeapAllocation::ResourceHeapAllocation(const AllocationInfo& info,
uint64_t offset, uint64_t offset,
ComPtr<ID3D12Resource> resource) ComPtr<ID3D12Resource> resource,
: ResourceMemoryAllocation(info, offset, nullptr), mResource(std::move(resource)) { Heap* heap)
: ResourceMemoryAllocation(info, offset, heap), mResource(std::move(resource)) {
ASSERT((info.mMethod == AllocationMethod::kExternal) == (heap == nullptr));
} }
void ResourceHeapAllocation::Invalidate() { void ResourceHeapAllocation::Invalidate() {

View File

@ -20,12 +20,15 @@
namespace dawn_native { namespace d3d12 { namespace dawn_native { namespace d3d12 {
class Heap;
class ResourceHeapAllocation : public ResourceMemoryAllocation { class ResourceHeapAllocation : public ResourceMemoryAllocation {
public: public:
ResourceHeapAllocation() = default; ResourceHeapAllocation() = default;
ResourceHeapAllocation(const AllocationInfo& info, ResourceHeapAllocation(const AllocationInfo& info,
uint64_t offset, uint64_t offset,
ComPtr<ID3D12Resource> resource); ComPtr<ID3D12Resource> resource,
Heap* heap);
~ResourceHeapAllocation() override = default; ~ResourceHeapAllocation() override = default;
void Invalidate() override; void Invalidate() override;

View File

@ -322,8 +322,11 @@ namespace dawn_native { namespace d3d12 {
mDxgiKeyedMutex = std::move(dxgiKeyedMutex); mDxgiKeyedMutex = std::move(dxgiKeyedMutex);
AllocationInfo info; AllocationInfo info;
info.mMethod = AllocationMethod::kDirect; info.mMethod = AllocationMethod::kExternal;
mResourceAllocation = {info, 0, std::move(d3d12Resource)}; // 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 {}; return {};
} }
@ -370,8 +373,11 @@ namespace dawn_native { namespace d3d12 {
ComPtr<ID3D12Resource> nativeTexture) ComPtr<ID3D12Resource> nativeTexture)
: TextureBase(device, descriptor, TextureState::OwnedExternal) { : TextureBase(device, descriptor, TextureState::OwnedExternal) {
AllocationInfo info; AllocationInfo info;
info.mMethod = AllocationMethod::kDirect; info.mMethod = AllocationMethod::kExternal;
mResourceAllocation = {info, 0, std::move(nativeTexture)}; // 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, SetIsSubresourceContentInitialized(true, 0, descriptor->mipLevelCount, 0,
descriptor->arrayLayerCount); descriptor->arrayLayerCount);