Add ResourceAllocationManager to create and track lifetimes of d3d12 resources
This commit is contained in:
parent
78f1619446
commit
f96ce23628
|
@ -233,6 +233,8 @@ if (WIN32)
|
|||
${D3D12_DIR}/PipelineLayoutD3D12.h
|
||||
${D3D12_DIR}/QueueD3D12.cpp
|
||||
${D3D12_DIR}/QueueD3D12.h
|
||||
${D3D12_DIR}/ResourceAllocator.cpp
|
||||
${D3D12_DIR}/ResourceAllocator.h
|
||||
${D3D12_DIR}/ResourceUploader.cpp
|
||||
${D3D12_DIR}/ResourceUploader.h
|
||||
${D3D12_DIR}/ShaderModuleD3D12.cpp
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "BufferD3D12.h"
|
||||
|
||||
#include "D3D12Backend.h"
|
||||
#include "ResourceAllocator.h"
|
||||
|
||||
namespace backend {
|
||||
namespace d3d12 {
|
||||
|
@ -59,22 +60,11 @@ namespace d3d12 {
|
|||
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProperties;
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProperties.CreationNodeMask = 0;
|
||||
heapProperties.VisibleNodeMask = 0;
|
||||
resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12BufferUsage(GetUsage()));
|
||||
}
|
||||
|
||||
// TODO(enga@google.com): Use a ResourceAllocationManager
|
||||
ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommittedResource(
|
||||
&heapProperties,
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&resourceDescriptor,
|
||||
D3D12BufferUsage(GetUsage()),
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&resource)
|
||||
));
|
||||
Buffer::~Buffer() {
|
||||
device->GetResourceAllocator()->Release(resource);
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> Buffer::GetD3D12Resource() {
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace d3d12 {
|
|||
class Buffer : public BufferBase {
|
||||
public:
|
||||
Buffer(Device* device, BufferBuilder* builder);
|
||||
~Buffer();
|
||||
|
||||
ComPtr<ID3D12Resource> GetD3D12Resource();
|
||||
D3D12_GPU_VIRTUAL_ADDRESS GetVA() const;
|
||||
|
@ -34,7 +35,6 @@ namespace d3d12 {
|
|||
|
||||
private:
|
||||
Device* device;
|
||||
ComPtr<ID3D12Resource> uploadResource;
|
||||
ComPtr<ID3D12Resource> resource;
|
||||
|
||||
// NXT API
|
||||
|
|
|
@ -76,6 +76,7 @@ namespace d3d12 {
|
|||
Device::Device(ComPtr<ID3D12Device> d3d12Device)
|
||||
: d3d12Device(d3d12Device),
|
||||
commandAllocatorManager(this),
|
||||
resourceAllocator(this),
|
||||
resourceUploader(this),
|
||||
pendingCommands{ commandAllocatorManager.ReserveCommandAllocator() } {
|
||||
|
||||
|
@ -109,6 +110,18 @@ namespace d3d12 {
|
|||
return commandQueue;
|
||||
}
|
||||
|
||||
CommandAllocatorManager* Device::GetCommandAllocatorManager() {
|
||||
return &commandAllocatorManager;
|
||||
}
|
||||
|
||||
ResourceAllocator* Device::GetResourceAllocator() {
|
||||
return &resourceAllocator;
|
||||
}
|
||||
|
||||
ResourceUploader* Device::GetResourceUploader() {
|
||||
return &resourceUploader;
|
||||
}
|
||||
|
||||
ComPtr<ID3D12GraphicsCommandList> Device::GetPendingCommandList() {
|
||||
// Callers of GetPendingCommandList do so to record commands. Only reserve a command allocator when it is needed so we don't submit empty command lists
|
||||
if (!pendingCommands.open) {
|
||||
|
@ -123,14 +136,6 @@ namespace d3d12 {
|
|||
return renderTargetDescriptor;
|
||||
}
|
||||
|
||||
ResourceUploader* Device::GetResourceUploader() {
|
||||
return &resourceUploader;
|
||||
}
|
||||
|
||||
CommandAllocatorManager* Device::GetCommandAllocatorManager() {
|
||||
return &commandAllocatorManager;
|
||||
}
|
||||
|
||||
void Device::SetNextRenderTargetDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor) {
|
||||
this->renderTargetDescriptor = renderTargetDescriptor;
|
||||
}
|
||||
|
@ -138,7 +143,7 @@ namespace d3d12 {
|
|||
void Device::TickImpl() {
|
||||
// Perform cleanup operations to free unused objects
|
||||
const uint64_t lastCompletedSerial = fence->GetCompletedValue();
|
||||
resourceUploader.FreeCompletedResources(lastCompletedSerial);
|
||||
resourceAllocator.FreeUnusedResources(lastCompletedSerial);
|
||||
commandAllocatorManager.ResetCompletedAllocators(lastCompletedSerial);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,9 @@
|
|||
#include "common/ToBackend.h"
|
||||
|
||||
#include "d3d12_platform.h"
|
||||
#include "ResourceUploader.h"
|
||||
#include "CommandAllocatorManager.h"
|
||||
#include "ResourceAllocator.h"
|
||||
#include "ResourceUploader.h"
|
||||
|
||||
namespace backend {
|
||||
namespace d3d12 {
|
||||
|
@ -110,7 +111,9 @@ namespace d3d12 {
|
|||
|
||||
ComPtr<ID3D12Device> GetD3D12Device();
|
||||
ComPtr<ID3D12CommandQueue> GetCommandQueue();
|
||||
|
||||
CommandAllocatorManager* GetCommandAllocatorManager();
|
||||
ResourceAllocator* GetResourceAllocator();
|
||||
ResourceUploader* GetResourceUploader();
|
||||
|
||||
ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
|
||||
|
@ -137,6 +140,7 @@ namespace d3d12 {
|
|||
ComPtr<ID3D12CommandQueue> commandQueue;
|
||||
|
||||
CommandAllocatorManager commandAllocatorManager;
|
||||
ResourceAllocator resourceAllocator;
|
||||
ResourceUploader resourceUploader;
|
||||
|
||||
struct PendingCommandList {
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright 2017 The NXT 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 "ResourceAllocator.h"
|
||||
|
||||
#include "D3D12Backend.h"
|
||||
|
||||
namespace backend {
|
||||
namespace d3d12 {
|
||||
|
||||
namespace {
|
||||
static constexpr D3D12_HEAP_PROPERTIES kDefaultHeapProperties = {
|
||||
D3D12_HEAP_TYPE_DEFAULT,
|
||||
D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
D3D12_MEMORY_POOL_UNKNOWN,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static constexpr D3D12_HEAP_PROPERTIES kUploadHeapProperties = {
|
||||
D3D12_HEAP_TYPE_UPLOAD,
|
||||
D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
D3D12_MEMORY_POOL_UNKNOWN,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static constexpr D3D12_HEAP_PROPERTIES kReadbackHeapProperties = {
|
||||
D3D12_HEAP_TYPE_READBACK,
|
||||
D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
D3D12_MEMORY_POOL_UNKNOWN,
|
||||
0,
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
ResourceAllocator::ResourceAllocator(Device* device) : device(device) {
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> ResourceAllocator::Allocate(D3D12_HEAP_TYPE heapType, const D3D12_RESOURCE_DESC &resourceDescriptor, D3D12_RESOURCE_STATES initialUsage) {
|
||||
const D3D12_HEAP_PROPERTIES* heapProperties = nullptr;
|
||||
switch(heapType) {
|
||||
case D3D12_HEAP_TYPE_DEFAULT:
|
||||
heapProperties = &kDefaultHeapProperties;
|
||||
break;
|
||||
case D3D12_HEAP_TYPE_UPLOAD:
|
||||
heapProperties = &kUploadHeapProperties;
|
||||
break;
|
||||
case D3D12_HEAP_TYPE_READBACK:
|
||||
heapProperties = &kReadbackHeapProperties;
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> resource;
|
||||
|
||||
// TODO(enga@google.com): Use CreatePlacedResource
|
||||
ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommittedResource(
|
||||
heapProperties,
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&resourceDescriptor,
|
||||
initialUsage,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&resource)
|
||||
));
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
void ResourceAllocator::Release(ComPtr<ID3D12Resource> resource) {
|
||||
// Resources may still be in use on the GPU. Enqueue them so that we hold onto them until GPU execution has completed
|
||||
releasedResources.Enqueue(resource, device->GetSerial());
|
||||
}
|
||||
|
||||
void ResourceAllocator::FreeUnusedResources(uint64_t lastCompletedSerial) {
|
||||
releasedResources.ClearUpTo(lastCompletedSerial);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2017 The NXT 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 BACKEND_D3D12_RESOURCEALLOCATIONMANAGER_H_
|
||||
#define BACKEND_D3D12_RESOURCEALLOCATIONMANAGER_H_
|
||||
|
||||
#include "d3d12_platform.h"
|
||||
|
||||
#include "common/SerialQueue.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace backend {
|
||||
namespace d3d12 {
|
||||
|
||||
class Device;
|
||||
|
||||
class ResourceAllocator {
|
||||
|
||||
public:
|
||||
ResourceAllocator(Device* device);
|
||||
|
||||
ComPtr<ID3D12Resource> Allocate(D3D12_HEAP_TYPE heapType, const D3D12_RESOURCE_DESC &resourceDescriptor, D3D12_RESOURCE_STATES initialUsage);
|
||||
void Release(ComPtr<ID3D12Resource> resource);
|
||||
void FreeUnusedResources(uint64_t lastCompletedSerial);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
|
||||
SerialQueue<ComPtr<ID3D12Resource>> releasedResources;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BACKEND_D3D12_RESOURCEALLOCATIONMANAGER_H_
|
|
@ -23,10 +23,20 @@ namespace d3d12 {
|
|||
}
|
||||
|
||||
void ResourceUploader::UploadToBuffer(ComPtr<ID3D12Resource> resource, uint32_t start, uint32_t count, const uint8_t* data) {
|
||||
// TODO(enga@google.com): Use a handle to a subset of a large ring buffer. On Release, decrease reference count on the ring buffer and free when 0.
|
||||
// Alternatively, the SerialQueue could be used to track which last point of the ringbuffer is in use, and start reusing chunks of it that aren't in flight.
|
||||
UploadHandle uploadHandle = GetUploadBuffer(count);
|
||||
memcpy(uploadHandle.mappedBuffer, data, count);
|
||||
device->GetPendingCommandList()->CopyBufferRegion(resource.Get(), start, uploadHandle.resource.Get(), 0, count);
|
||||
Release(uploadHandle);
|
||||
}
|
||||
|
||||
ResourceUploader::UploadHandle ResourceUploader::GetUploadBuffer(uint32_t requiredSize) {
|
||||
// TODO(enga@google.com): This will find or create a mapped buffer of sufficient size and return a handle to a mapped range
|
||||
D3D12_RESOURCE_DESC resourceDescriptor;
|
||||
resourceDescriptor.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resourceDescriptor.Alignment = 0;
|
||||
resourceDescriptor.Width = count;
|
||||
resourceDescriptor.Width = requiredSize;
|
||||
resourceDescriptor.Height = 1;
|
||||
resourceDescriptor.DepthOrArraySize = 1;
|
||||
resourceDescriptor.MipLevels = 1;
|
||||
|
@ -36,45 +46,19 @@ namespace d3d12 {
|
|||
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
resourceDescriptor.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
ComPtr<ID3D12Resource> uploadResource;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProperties;
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProperties.CreationNodeMask = 0;
|
||||
heapProperties.VisibleNodeMask = 0;
|
||||
|
||||
// TODO(enga@google.com): Use a ResourceAllocationManager
|
||||
ASSERT_SUCCESS(device->GetD3D12Device()->CreateCommittedResource(
|
||||
&heapProperties,
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&resourceDescriptor,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&uploadResource)
|
||||
));
|
||||
|
||||
UploadHandle uploadHandle;
|
||||
uploadHandle.resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_UPLOAD, resourceDescriptor, D3D12_RESOURCE_STATE_GENERIC_READ);
|
||||
D3D12_RANGE readRange;
|
||||
readRange.Begin = 0;
|
||||
readRange.End = 0;
|
||||
|
||||
D3D12_RANGE writeRange;
|
||||
writeRange.Begin = 0;
|
||||
writeRange.End = count;
|
||||
|
||||
uint8_t* mappedResource = nullptr;
|
||||
|
||||
ASSERT_SUCCESS(uploadResource->Map(0, &readRange, reinterpret_cast<void**>(&mappedResource)));
|
||||
memcpy(mappedResource, data, count);
|
||||
uploadResource->Unmap(0, &writeRange);
|
||||
device->GetPendingCommandList()->CopyBufferRegion(resource.Get(), start, uploadResource.Get(), 0, count);
|
||||
|
||||
uploadingResources.Enqueue(std::move(uploadResource), device->GetSerial());
|
||||
uploadHandle.resource->Map(0, &readRange, reinterpret_cast<void**>(&uploadHandle.mappedBuffer));
|
||||
return uploadHandle;
|
||||
}
|
||||
|
||||
void ResourceUploader::FreeCompletedResources(const uint64_t lastCompletedSerial) {
|
||||
uploadingResources.ClearUpTo(lastCompletedSerial);
|
||||
void ResourceUploader::Release(UploadHandle uploadHandle) {
|
||||
uploadHandle.resource->Unmap(0, nullptr);
|
||||
device->GetResourceAllocator()->Release(uploadHandle.resource);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,10 +17,7 @@
|
|||
|
||||
#include "d3d12_platform.h"
|
||||
|
||||
#include "common/SerialQueue.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "common/Forward.h"
|
||||
|
||||
namespace backend {
|
||||
namespace d3d12 {
|
||||
|
@ -32,14 +29,18 @@ namespace d3d12 {
|
|||
ResourceUploader(Device* device);
|
||||
|
||||
void UploadToBuffer(ComPtr<ID3D12Resource> resource, uint32_t start, uint32_t count, const uint8_t* data);
|
||||
void FreeCompletedResources(const uint64_t lastCompletedSerial);
|
||||
|
||||
private:
|
||||
Device* device;
|
||||
|
||||
SerialQueue<ComPtr<ID3D12Resource>> uploadingResources;
|
||||
struct UploadHandle {
|
||||
ComPtr<ID3D12Resource> resource;
|
||||
uint8_t* mappedBuffer;
|
||||
};
|
||||
|
||||
UploadHandle GetUploadBuffer(uint32_t requiredSize);
|
||||
void Release(UploadHandle uploadHandle);
|
||||
|
||||
Device* device;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue