From 7ffd2346f8fad7d63091ea278d36e3f28177167b Mon Sep 17 00:00:00 2001 From: Bryan Bernhart Date: Tue, 27 Aug 2019 23:36:26 +0000 Subject: [PATCH] Resource Management 5: D3D support for resource allocation. Refactor existing resource allocators by adding a memory type and memory handle. BUG=dawn:27, dawn:153 Change-Id: I090b6ab40e7eaa0d7ea5ce1e8b760e961be9b559 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9420 Commit-Queue: Bryan Bernhart Reviewed-by: Kai Ninomiya --- BUILD.gn | 7 +++ src/dawn_native/Forward.h | 1 + src/dawn_native/ResourceHeap.h | 31 ++++++++++ src/dawn_native/ResourceMemoryAllocation.cpp | 53 ++++++++++++++++ src/dawn_native/ResourceMemoryAllocation.h | 60 +++++++++++++++++++ src/dawn_native/ToBackend.h | 5 ++ src/dawn_native/d3d12/BufferD3D12.cpp | 37 ++++++------ src/dawn_native/d3d12/BufferD3D12.h | 7 ++- .../d3d12/CommittedResourceAllocatorD3D12.cpp | 52 ++++++++++++++++ .../d3d12/CommittedResourceAllocatorD3D12.h | 47 +++++++++++++++ src/dawn_native/d3d12/DeviceD3D12.cpp | 58 +++++++++++++++++- src/dawn_native/d3d12/DeviceD3D12.h | 25 ++++++++ src/dawn_native/d3d12/Forward.h | 2 + src/dawn_native/d3d12/ResourceHeapD3D12.cpp | 30 ++++++++++ src/dawn_native/d3d12/ResourceHeapD3D12.h | 38 ++++++++++++ src/dawn_native/d3d12/StagingBufferD3D12.cpp | 17 +++--- src/dawn_native/d3d12/StagingBufferD3D12.h | 3 +- 17 files changed, 442 insertions(+), 31 deletions(-) create mode 100644 src/dawn_native/ResourceHeap.h create mode 100644 src/dawn_native/ResourceMemoryAllocation.cpp create mode 100644 src/dawn_native/ResourceMemoryAllocation.h create mode 100644 src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp create mode 100644 src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h create mode 100644 src/dawn_native/d3d12/ResourceHeapD3D12.cpp create mode 100644 src/dawn_native/d3d12/ResourceHeapD3D12.h diff --git a/BUILD.gn b/BUILD.gn index b84ba59fd7..b83b8bb158 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -204,6 +204,9 @@ source_set("libdawn_native_sources") { "src/dawn_native/RenderPassEncoder.h", "src/dawn_native/RenderPipeline.cpp", "src/dawn_native/RenderPipeline.h", + "src/dawn_native/ResourceHeap.h", + "src/dawn_native/ResourceMemoryAllocation.cpp", + "src/dawn_native/ResourceMemoryAllocation.h", "src/dawn_native/RingBuffer.cpp", "src/dawn_native/RingBuffer.h", "src/dawn_native/Sampler.cpp", @@ -239,6 +242,8 @@ source_set("libdawn_native_sources") { "src/dawn_native/d3d12/CommandAllocatorManager.h", "src/dawn_native/d3d12/CommandBufferD3D12.cpp", "src/dawn_native/d3d12/CommandBufferD3D12.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/D3D12Info.cpp", @@ -260,6 +265,8 @@ source_set("libdawn_native_sources") { "src/dawn_native/d3d12/RenderPipelineD3D12.h", "src/dawn_native/d3d12/ResourceAllocator.cpp", "src/dawn_native/d3d12/ResourceAllocator.h", + "src/dawn_native/d3d12/ResourceHeapD3D12.cpp", + "src/dawn_native/d3d12/ResourceHeapD3D12.h", "src/dawn_native/d3d12/SamplerD3D12.cpp", "src/dawn_native/d3d12/SamplerD3D12.h", "src/dawn_native/d3d12/ShaderModuleD3D12.cpp", diff --git a/src/dawn_native/Forward.h b/src/dawn_native/Forward.h index 1ba29da079..ad73beffac 100644 --- a/src/dawn_native/Forward.h +++ b/src/dawn_native/Forward.h @@ -36,6 +36,7 @@ namespace dawn_native { class RenderBundleEncoderBase; class RenderPassEncoderBase; class RenderPipelineBase; + class ResourceHeapBase; class SamplerBase; class ShaderModuleBase; class StagingBufferBase; diff --git a/src/dawn_native/ResourceHeap.h b/src/dawn_native/ResourceHeap.h new file mode 100644 index 0000000000..c4d6707032 --- /dev/null +++ b/src/dawn_native/ResourceHeap.h @@ -0,0 +1,31 @@ +// 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_RESOURCEHEAP_H_ +#define DAWNNATIVE_RESOURCEHEAP_H_ + +#include "dawn_native/Error.h" + +namespace dawn_native { + + // Wrapper for a resource backed by a heap. + class ResourceHeapBase { + protected: + ResourceHeapBase() = default; + virtual ~ResourceHeapBase() = default; + }; + +} // namespace dawn_native + +#endif // DAWNNATIVE_RESOURCEHEAP_H_ \ No newline at end of file diff --git a/src/dawn_native/ResourceMemoryAllocation.cpp b/src/dawn_native/ResourceMemoryAllocation.cpp new file mode 100644 index 0000000000..1ace4d48fa --- /dev/null +++ b/src/dawn_native/ResourceMemoryAllocation.cpp @@ -0,0 +1,53 @@ +// 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/ResourceMemoryAllocation.h" +#include "common/Assert.h" + +#include + +namespace dawn_native { + + static constexpr uint64_t INVALID_OFFSET = std::numeric_limits::max(); + + ResourceMemoryAllocation::ResourceMemoryAllocation() + : mMethod(AllocationMethod::kInvalid), mOffset(INVALID_OFFSET), mResourceHeap(nullptr) { + } + + ResourceMemoryAllocation::ResourceMemoryAllocation(uint64_t offset, + ResourceHeapBase* resourceHeap, + AllocationMethod method) + : mMethod(method), mOffset(offset), mResourceHeap(resourceHeap) { + } + + ResourceHeapBase* ResourceMemoryAllocation::GetResourceHeap() const { + ASSERT(mMethod != AllocationMethod::kInvalid); + return mResourceHeap; + } + + uint64_t ResourceMemoryAllocation::GetOffset() const { + ASSERT(mMethod != AllocationMethod::kInvalid); + return mOffset; + } + + AllocationMethod ResourceMemoryAllocation::GetAllocationMethod() const { + ASSERT(mMethod != AllocationMethod::kInvalid); + return mMethod; + } + + void ResourceMemoryAllocation::Invalidate() { + mResourceHeap = nullptr; + mMethod = AllocationMethod::kInvalid; + } +} // namespace dawn_native \ No newline at end of file diff --git a/src/dawn_native/ResourceMemoryAllocation.h b/src/dawn_native/ResourceMemoryAllocation.h new file mode 100644 index 0000000000..4e69a2290e --- /dev/null +++ b/src/dawn_native/ResourceMemoryAllocation.h @@ -0,0 +1,60 @@ +// Copyright 2018 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_RESOURCEMEMORYALLOCATION_H_ +#define DAWNNATIVE_RESOURCEMEMORYALLOCATION_H_ + +#include + +namespace dawn_native { + + class ResourceHeapBase; + + // Allocation method determines how memory was sub-divided. + // Used by the device to get the allocator that was responsible for the allocation. + enum class AllocationMethod { + + // Memory not sub-divided. + kDirect, + + // Memory sub-divided using one or more blocks of various sizes. + kSubAllocated, + + // Memory not allocated or freed. + kInvalid + }; + + // Handle into a resource heap pool. + class ResourceMemoryAllocation { + public: + ResourceMemoryAllocation(); + ResourceMemoryAllocation(uint64_t offset, + ResourceHeapBase* resourceHeap, + AllocationMethod method); + ~ResourceMemoryAllocation() = default; + + ResourceHeapBase* GetResourceHeap() const; + uint64_t GetOffset() const; + AllocationMethod GetAllocationMethod() const; + + void Invalidate(); + + private: + AllocationMethod mMethod; + uint64_t mOffset; + ResourceHeapBase* mResourceHeap; + }; +} // namespace dawn_native + +#endif // DAWNNATIVE_RESOURCEMEMORYALLOCATION_H_ \ No newline at end of file diff --git a/src/dawn_native/ToBackend.h b/src/dawn_native/ToBackend.h index 4f11fd45ae..b9940aba2b 100644 --- a/src/dawn_native/ToBackend.h +++ b/src/dawn_native/ToBackend.h @@ -73,6 +73,11 @@ namespace dawn_native { using BackendType = typename BackendTraits::RenderPipelineType; }; + template + struct ToBackendTraits { + using BackendType = typename BackendTraits::ResourceHeapType; + }; + template struct ToBackendTraits { using BackendType = typename BackendTraits::SamplerType; diff --git a/src/dawn_native/d3d12/BufferD3D12.cpp b/src/dawn_native/d3d12/BufferD3D12.cpp index 585c24f991..148a7408a3 100644 --- a/src/dawn_native/d3d12/BufferD3D12.cpp +++ b/src/dawn_native/d3d12/BufferD3D12.cpp @@ -18,7 +18,7 @@ #include "common/Constants.h" #include "common/Math.h" #include "dawn_native/d3d12/DeviceD3D12.h" -#include "dawn_native/d3d12/ResourceAllocator.h" +#include "dawn_native/d3d12/ResourceHeapD3D12.h" namespace dawn_native { namespace d3d12 { @@ -71,6 +71,9 @@ namespace dawn_native { namespace d3d12 { Buffer::Buffer(Device* device, const BufferDescriptor* descriptor) : BufferBase(device, descriptor) { + } + + MaybeError Buffer::Initialize() { D3D12_RESOURCE_DESC resourceDescriptor; resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; resourceDescriptor.Alignment = 0; @@ -105,8 +108,11 @@ namespace dawn_native { namespace d3d12 { mLastUsage = dawn::BufferUsage::CopySrc; } - mResource = - device->GetResourceAllocator()->Allocate(heapType, resourceDescriptor, bufferUsage); + DAWN_TRY_ASSIGN( + mResourceAllocation, + ToBackend(GetDevice()) + ->AllocateMemory(heapType, resourceDescriptor, bufferUsage, D3D12_HEAP_FLAG_NONE)); + return {}; } Buffer::~Buffer() { @@ -118,8 +124,8 @@ namespace dawn_native { namespace d3d12 { return Align(GetSize(), 256); } - ComPtr Buffer::GetD3D12Resource() { - return mResource; + ComPtr Buffer::GetD3D12Resource() const { + return ToBackend(mResourceAllocation.GetResourceHeap())->GetD3D12Resource(); } // When true is returned, a D3D12_RESOURCE_BARRIER has been created and must be used in a @@ -174,7 +180,7 @@ namespace dawn_native { namespace d3d12 { barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier->Transition.pResource = mResource.Get(); + barrier->Transition.pResource = GetD3D12Resource().Get(); barrier->Transition.StateBefore = lastState; barrier->Transition.StateAfter = newState; barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; @@ -192,7 +198,7 @@ namespace dawn_native { namespace d3d12 { } D3D12_GPU_VIRTUAL_ADDRESS Buffer::GetVA() const { - return mResource->GetGPUVirtualAddress(); + return ToBackend(mResourceAllocation.GetResourceHeap())->GetGPUPointer(); } void Buffer::OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite) { @@ -210,8 +216,8 @@ namespace dawn_native { namespace d3d12 { MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) { mWrittenMappedRange = {0, GetSize()}; - ASSERT_SUCCESS( - mResource->Map(0, &mWrittenMappedRange, reinterpret_cast(mappedPointer))); + ASSERT_SUCCESS(GetD3D12Resource()->Map(0, &mWrittenMappedRange, + reinterpret_cast(mappedPointer))); return {}; } @@ -219,8 +225,7 @@ namespace dawn_native { namespace d3d12 { mWrittenMappedRange = {}; D3D12_RANGE readRange = {0, GetSize()}; char* data = nullptr; - ASSERT_SUCCESS(mResource->Map(0, &readRange, reinterpret_cast(&data))); - + ASSERT_SUCCESS(GetD3D12Resource()->Map(0, &readRange, reinterpret_cast(&data))); // There is no need to transition the resource to a new state: D3D12 seems to make the GPU // writes available when the fence is passed. MapRequestTracker* tracker = ToBackend(GetDevice())->GetMapRequestTracker(); @@ -231,8 +236,8 @@ namespace dawn_native { namespace d3d12 { MaybeError Buffer::MapWriteAsyncImpl(uint32_t serial) { mWrittenMappedRange = {0, GetSize()}; char* data = nullptr; - ASSERT_SUCCESS(mResource->Map(0, &mWrittenMappedRange, reinterpret_cast(&data))); - + ASSERT_SUCCESS( + GetD3D12Resource()->Map(0, &mWrittenMappedRange, reinterpret_cast(&data))); // There is no need to transition the resource to a new state: D3D12 seems to make the CPU // writes available on queue submission. MapRequestTracker* tracker = ToBackend(GetDevice())->GetMapRequestTracker(); @@ -241,14 +246,12 @@ namespace dawn_native { namespace d3d12 { } void Buffer::UnmapImpl() { - mResource->Unmap(0, &mWrittenMappedRange); - ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource); + GetD3D12Resource()->Unmap(0, &mWrittenMappedRange); mWrittenMappedRange = {}; } void Buffer::DestroyImpl() { - ToBackend(GetDevice())->GetResourceAllocator()->Release(mResource); - mResource = nullptr; + ToBackend(GetDevice())->DeallocateMemory(mResourceAllocation); } MapRequestTracker::MapRequestTracker(Device* device) : mDevice(device) { diff --git a/src/dawn_native/d3d12/BufferD3D12.h b/src/dawn_native/d3d12/BufferD3D12.h index 1b8b177987..7a9b433091 100644 --- a/src/dawn_native/d3d12/BufferD3D12.h +++ b/src/dawn_native/d3d12/BufferD3D12.h @@ -18,6 +18,7 @@ #include "common/SerialQueue.h" #include "dawn_native/Buffer.h" +#include "dawn_native/ResourceMemoryAllocation.h" #include "dawn_native/d3d12/d3d12_platform.h" namespace dawn_native { namespace d3d12 { @@ -29,8 +30,10 @@ namespace dawn_native { namespace d3d12 { Buffer(Device* device, const BufferDescriptor* descriptor); ~Buffer(); + MaybeError Initialize(); + uint32_t GetD3D12Size() const; - ComPtr GetD3D12Resource(); + ComPtr GetD3D12Resource() const; D3D12_GPU_VIRTUAL_ADDRESS GetVA() const; void OnMapCommandSerialFinished(uint32_t mapSerial, void* data, bool isWrite); bool TransitionUsageAndGetResourceBarrier(D3D12_RESOURCE_BARRIER* barrier, @@ -48,7 +51,7 @@ namespace dawn_native { namespace d3d12 { bool IsMapWritable() const override; virtual MaybeError MapAtCreationImpl(uint8_t** mappedPointer) override; - ComPtr mResource; + ResourceMemoryAllocation mResourceAllocation; bool mFixedResourceState = false; dawn::BufferUsage mLastUsage = dawn::BufferUsage::None; Serial mLastUsedSerial = UINT64_MAX; diff --git a/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp b/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.cpp new file mode 100644 index 0000000000..772f5d21f4 --- /dev/null +++ b/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.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/CommittedResourceAllocatorD3D12.h" +#include "dawn_native/d3d12/DeviceD3D12.h" +#include "dawn_native/d3d12/ResourceHeapD3D12.h" + +namespace dawn_native { namespace d3d12 { + + CommittedResourceAllocator::CommittedResourceAllocator(Device* device, D3D12_HEAP_TYPE heapType) + : mDevice(device), mHeapType(heapType) { + } + + ResultOrError 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 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"); + } + + return ResourceMemoryAllocation( + /*offset*/ 0, new ResourceHeap(std::move(committedResource)), + AllocationMethod::kDirect); + } + + void CommittedResourceAllocator::Deallocate(ResourceMemoryAllocation& allocation) { + std::unique_ptr resourceHeap(ToBackend(allocation.GetResourceHeap())); + mDevice->ReferenceUntilUnused(resourceHeap->GetD3D12Resource()); + } +}} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h b/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h new file mode 100644 index 0000000000..419d1c6cbd --- /dev/null +++ b/src/dawn_native/d3d12/CommittedResourceAllocatorD3D12.h @@ -0,0 +1,47 @@ +// 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/ResourceMemoryAllocation.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 Allocate( + const D3D12_RESOURCE_DESC& resourceDescriptor, + D3D12_RESOURCE_STATES initialUsage, + D3D12_HEAP_FLAGS heapFlags); + void Deallocate(ResourceMemoryAllocation& 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 1f23108800..16554b80a6 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/src/dawn_native/d3d12/DeviceD3D12.cpp @@ -31,6 +31,7 @@ #include "dawn_native/d3d12/QueueD3D12.h" #include "dawn_native/d3d12/RenderPipelineD3D12.h" #include "dawn_native/d3d12/ResourceAllocator.h" +#include "dawn_native/d3d12/ResourceHeapD3D12.h" #include "dawn_native/d3d12/SamplerD3D12.h" #include "dawn_native/d3d12/ShaderModuleD3D12.h" #include "dawn_native/d3d12/StagingBufferD3D12.h" @@ -110,12 +111,17 @@ namespace dawn_native { namespace d3d12 { } NextSerial(); WaitForSerial(mLastSubmittedSerial); // Wait for all in-flight commands to finish executing - TickImpl(); // Call tick one last time so resources are cleaned up + TickImpl(); // Call tick one last time so resources are cleaned up // Free services explicitly so that they can free D3D12 resources before destruction of the // device. mDynamicUploader = nullptr; + // GPU is no longer executing commands. Existing objects do not get freed until the device + // is destroyed. To ensure objects are always released, force the completed serial to be + // MAX. + mCompletedSerial = std::numeric_limits::max(); + // Releasing the uploader enqueues buffers to be released. // Call Tick() again to clear them before releasing the allocator. mResourceAllocator->Tick(mCompletedSerial); @@ -124,6 +130,8 @@ namespace dawn_native { namespace d3d12 { ::CloseHandle(mFenceEvent); } + mUsedComObjectRefs.ClearUpTo(mCompletedSerial); + ASSERT(mUsedComObjectRefs.Empty()); ASSERT(mPendingCommands.commandList == nullptr); } @@ -264,7 +272,9 @@ namespace dawn_native { namespace d3d12 { return new BindGroupLayout(this, descriptor); } ResultOrError Device::CreateBufferImpl(const BufferDescriptor* descriptor) { - return new Buffer(this, descriptor); + std::unique_ptr buffer = std::make_unique(this, descriptor); + DAWN_TRY(buffer->Initialize()); + return buffer.release(); } CommandBufferBase* Device::CreateCommandBuffer(CommandEncoderBase* encoder, const CommandBufferDescriptor* descriptor) { @@ -326,4 +336,48 @@ namespace dawn_native { namespace d3d12 { return {}; } + size_t Device::GetD3D12HeapTypeToIndex(D3D12_HEAP_TYPE heapType) const { + ASSERT(heapType > 0); + ASSERT(heapType <= kNumHeapTypes); + return heapType - 1; + } + + void Device::DeallocateMemory(ResourceMemoryAllocation& allocation) { + CommittedResourceAllocator* allocator = nullptr; + D3D12_HEAP_PROPERTIES heapProp; + ToBackend(allocation.GetResourceHeap()) + ->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 + // calls DeallocateMemory again using the same allocation. + allocation.Invalidate(); + } + + ResultOrError Device::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(this, heapType); + allocator = mDirectResourceAllocators[heapTypeIndex].get(); + } + + ResourceMemoryAllocation allocation; + DAWN_TRY_ASSIGN(allocation, + allocator->Allocate(resourceDescriptor, initialUsage, heapFlags)); + + return allocation; + } }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h index e45e8116be..847fe35048 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.h +++ b/src/dawn_native/d3d12/DeviceD3D12.h @@ -19,6 +19,7 @@ #include "common/SerialQueue.h" #include "dawn_native/Device.h" +#include "dawn_native/d3d12/CommittedResourceAllocatorD3D12.h" #include "dawn_native/d3d12/Forward.h" #include "dawn_native/d3d12/d3d12_platform.h" @@ -81,6 +82,14 @@ namespace dawn_native { namespace d3d12 { uint64_t destinationOffset, uint64_t size) override; + ResultOrError AllocateMemory( + D3D12_HEAP_TYPE heapType, + const D3D12_RESOURCE_DESC& resourceDescriptor, + D3D12_RESOURCE_STATES initialUsage, + D3D12_HEAP_FLAGS heapFlags); + + void DeallocateMemory(ResourceMemoryAllocation& allocation); + private: ResultOrError CreateBindGroupImpl( const BindGroupDescriptor* descriptor) override; @@ -104,6 +113,8 @@ namespace dawn_native { namespace d3d12 { TextureBase* texture, const TextureViewDescriptor* descriptor) override; + size_t GetD3D12HeapTypeToIndex(D3D12_HEAP_TYPE heapType) const; + Serial mCompletedSerial = 0; Serial mLastSubmittedSerial = 0; ComPtr mFence; @@ -128,6 +139,20 @@ namespace dawn_native { namespace d3d12 { std::unique_ptr mMapRequestTracker; std::unique_ptr mResourceAllocator; + static constexpr uint32_t kNumHeapTypes = 4u; // Number of D3D12_HEAP_TYPE + + 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, kNumHeapTypes> + mDirectResourceAllocators; + dawn_native::PCIInfo mPCIInfo; }; diff --git a/src/dawn_native/d3d12/Forward.h b/src/dawn_native/d3d12/Forward.h index ade12e3ac8..f42f82430f 100644 --- a/src/dawn_native/d3d12/Forward.h +++ b/src/dawn_native/d3d12/Forward.h @@ -29,6 +29,7 @@ namespace dawn_native { namespace d3d12 { class PipelineLayout; class Queue; class RenderPipeline; + class ResourceHeap; class Sampler; class ShaderModule; class StagingBuffer; @@ -47,6 +48,7 @@ namespace dawn_native { namespace d3d12 { using PipelineLayoutType = PipelineLayout; using QueueType = Queue; using RenderPipelineType = RenderPipeline; + using ResourceHeapType = ResourceHeap; using SamplerType = Sampler; using ShaderModuleType = ShaderModule; using StagingBufferType = StagingBuffer; diff --git a/src/dawn_native/d3d12/ResourceHeapD3D12.cpp b/src/dawn_native/d3d12/ResourceHeapD3D12.cpp new file mode 100644 index 0000000000..5aec4b3256 --- /dev/null +++ b/src/dawn_native/d3d12/ResourceHeapD3D12.cpp @@ -0,0 +1,30 @@ +// 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/ResourceHeapD3D12.h" +#include "dawn_native/d3d12/DeviceD3D12.h" + +namespace dawn_native { namespace d3d12 { + + ResourceHeap::ResourceHeap(ComPtr resource) : mResource(resource) { + } + + ComPtr ResourceHeap::GetD3D12Resource() const { + return mResource; + } + + D3D12_GPU_VIRTUAL_ADDRESS ResourceHeap::GetGPUPointer() const { + return mResource->GetGPUVirtualAddress(); + } +}} // namespace dawn_native::d3d12 \ No newline at end of file diff --git a/src/dawn_native/d3d12/ResourceHeapD3D12.h b/src/dawn_native/d3d12/ResourceHeapD3D12.h new file mode 100644 index 0000000000..18b342a691 --- /dev/null +++ b/src/dawn_native/d3d12/ResourceHeapD3D12.h @@ -0,0 +1,38 @@ +// 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_RESOURCEHEAPD3D12_H_ +#define DAWNNATIVE_D3D12_RESOURCEHEAPD3D12_H_ + +#include "dawn_native/ResourceHeap.h" +#include "dawn_native/d3d12/d3d12_platform.h" + +namespace dawn_native { namespace d3d12 { + + // Wrapper for physical memory used with or without a resource object. + class ResourceHeap : public ResourceHeapBase { + public: + ResourceHeap(ComPtr resource); + + ~ResourceHeap() = default; + + ComPtr GetD3D12Resource() const; + D3D12_GPU_VIRTUAL_ADDRESS GetGPUPointer() const; + + private: + ComPtr mResource; + }; +}} // namespace dawn_native::d3d12 + +#endif // DAWNNATIVE_D3D12_RESOURCEHEAPD3D12_H_ \ No newline at end of file diff --git a/src/dawn_native/d3d12/StagingBufferD3D12.cpp b/src/dawn_native/d3d12/StagingBufferD3D12.cpp index 6b6adfa4d8..cab3a18413 100644 --- a/src/dawn_native/d3d12/StagingBufferD3D12.cpp +++ b/src/dawn_native/d3d12/StagingBufferD3D12.cpp @@ -14,7 +14,7 @@ #include "dawn_native/d3d12/StagingBufferD3D12.h" #include "dawn_native/d3d12/DeviceD3D12.h" -#include "dawn_native/d3d12/ResourceAllocator.h" +#include "dawn_native/d3d12/ResourceHeapD3D12.h" namespace dawn_native { namespace d3d12 { @@ -36,12 +36,11 @@ namespace dawn_native { namespace d3d12 { resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE; - mUploadHeap = mDevice->GetResourceAllocator()->Allocate( - D3D12_HEAP_TYPE_UPLOAD, resourceDescriptor, D3D12_RESOURCE_STATE_GENERIC_READ); + DAWN_TRY_ASSIGN(mUploadHeap, mDevice->AllocateMemory( + D3D12_HEAP_TYPE_UPLOAD, resourceDescriptor, + D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_HEAP_FLAG_NONE)); - // TODO(bryan.bernhart@intel.com): Record the GPU pointer for generic non-upload usage. - - if (FAILED(mUploadHeap->Map(0, nullptr, &mMappedPointer))) { + if (FAILED(GetResource()->Map(0, nullptr, &mMappedPointer))) { return DAWN_DEVICE_LOST_ERROR("Unable to map staging buffer."); } @@ -50,14 +49,14 @@ namespace dawn_native { namespace d3d12 { StagingBuffer::~StagingBuffer() { // Invalidate the CPU virtual address & flush cache (if needed). - mUploadHeap->Unmap(0, nullptr); + GetResource()->Unmap(0, nullptr); mMappedPointer = nullptr; - mDevice->GetResourceAllocator()->Release(mUploadHeap); + mDevice->DeallocateMemory(mUploadHeap); } ID3D12Resource* StagingBuffer::GetResource() const { - return mUploadHeap.Get(); + return ToBackend(mUploadHeap.GetResourceHeap())->GetD3D12Resource().Get(); } }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/StagingBufferD3D12.h b/src/dawn_native/d3d12/StagingBufferD3D12.h index b689df4a95..633be53c32 100644 --- a/src/dawn_native/d3d12/StagingBufferD3D12.h +++ b/src/dawn_native/d3d12/StagingBufferD3D12.h @@ -15,6 +15,7 @@ #ifndef DAWNNATIVE_STAGINGBUFFERD3D12_H_ #define DAWNNATIVE_STAGINGBUFFERD3D12_H_ +#include "dawn_native/ResourceMemoryAllocation.h" #include "dawn_native/StagingBuffer.h" #include "dawn_native/d3d12/d3d12_platform.h" @@ -33,7 +34,7 @@ namespace dawn_native { namespace d3d12 { private: Device* mDevice; - ComPtr mUploadHeap; + ResourceMemoryAllocation mUploadHeap; }; }} // namespace dawn_native::d3d12