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:
parent
be6cd51888
commit
f3bb4f4f32
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
mDevice->GetD3D12Device()->CreateHeap(&heapDesc, IID_PPV_ARGS(&heap)),
|
||||
"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) {
|
||||
|
|
|
@ -15,11 +15,25 @@
|
|||
#include "dawn_native/d3d12/HeapD3D12.h"
|
||||
|
||||
namespace dawn_native { namespace d3d12 {
|
||||
|
||||
Heap::Heap(ComPtr<ID3D12Heap> heap) : mHeap(std::move(heap)) {
|
||||
Heap::Heap(ComPtr<ID3D12Pageable> 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<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
|
|
@ -22,13 +22,17 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
class Heap : public ResourceHeapBase {
|
||||
public:
|
||||
Heap(ComPtr<ID3D12Heap> heap);
|
||||
Heap(ComPtr<ID3D12Pageable> d3d12Pageable, uint64_t size);
|
||||
~Heap() = default;
|
||||
|
||||
ComPtr<ID3D12Heap> GetD3D12Heap() const;
|
||||
ComPtr<ID3D12Pageable> GetD3D12Pageable() const;
|
||||
|
||||
uint64_t GetSize() const;
|
||||
|
||||
private:
|
||||
ComPtr<ID3D12Heap> mHeap;
|
||||
ComPtr<ID3D12Pageable> mD3d12Pageable;
|
||||
uint64_t mSize = 0;
|
||||
};
|
||||
}} // namespace dawn_native::d3d12
|
||||
|
||||
|
|
|
@ -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<Heap*>(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<ID3D12Resource> 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<ResourceHeapAllocation> 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
|
||||
|
|
|
@ -14,13 +14,17 @@
|
|||
|
||||
#include "dawn_native/d3d12/ResourceHeapAllocationD3D12.h"
|
||||
|
||||
#include "dawn_native/d3d12/HeapD3D12.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dawn_native { namespace d3d12 {
|
||||
ResourceHeapAllocation::ResourceHeapAllocation(const AllocationInfo& info,
|
||||
uint64_t offset,
|
||||
ComPtr<ID3D12Resource> resource)
|
||||
: ResourceMemoryAllocation(info, offset, nullptr), mResource(std::move(resource)) {
|
||||
ComPtr<ID3D12Resource> resource,
|
||||
Heap* heap)
|
||||
: ResourceMemoryAllocation(info, offset, heap), mResource(std::move(resource)) {
|
||||
ASSERT((info.mMethod == AllocationMethod::kExternal) == (heap == nullptr));
|
||||
}
|
||||
|
||||
void ResourceHeapAllocation::Invalidate() {
|
||||
|
|
|
@ -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<ID3D12Resource> resource);
|
||||
ComPtr<ID3D12Resource> resource,
|
||||
Heap* heap);
|
||||
~ResourceHeapAllocation() override = default;
|
||||
|
||||
void Invalidate() override;
|
||||
|
|
|
@ -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<ID3D12Resource> 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);
|
||||
|
|
Loading…
Reference in New Issue