583 lines
22 KiB
C++
583 lines
22 KiB
C++
#pragma once
|
|
#include "CommonInclude.h"
|
|
#include "wiPlatform.h"
|
|
|
|
#ifdef _WIN32
|
|
#define WICKEDENGINE_BUILD_DX12
|
|
#endif // _WIN32
|
|
|
|
#ifdef WICKEDENGINE_BUILD_DX12
|
|
#include "wiGraphicsDevice.h"
|
|
#include "wiSpinLock.h"
|
|
#include "wiContainers.h"
|
|
#include "wiGraphicsDevice_SharedInternals.h"
|
|
|
|
#include <dxgi1_6.h>
|
|
#include <wrl/client.h> // ComPtr
|
|
|
|
#include "Utility/dx12/d3d12.h"
|
|
#define D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
|
|
#include "Utility/D3D12MemAlloc.h"
|
|
|
|
#include <unordered_map>
|
|
#include <deque>
|
|
#include <atomic>
|
|
#include <mutex>
|
|
|
|
|
|
namespace wiGraphics
|
|
{
|
|
class GraphicsDevice_DX12 : public GraphicsDevice
|
|
{
|
|
protected:
|
|
Microsoft::WRL::ComPtr<ID3D12Device5> device;
|
|
Microsoft::WRL::ComPtr<IDXGIAdapter4> adapter;
|
|
Microsoft::WRL::ComPtr<IDXGIFactory6> factory;
|
|
Microsoft::WRL::ComPtr<ID3D12CommandQueue> directQueue;
|
|
Microsoft::WRL::ComPtr<ID3D12Fence> frameFence;
|
|
HANDLE frameFenceEvent;
|
|
|
|
uint32_t backbuffer_index = 0;
|
|
Microsoft::WRL::ComPtr<ID3D12Resource> backBuffers[BACKBUFFER_COUNT];
|
|
|
|
Microsoft::WRL::ComPtr<ID3D12CommandSignature> dispatchIndirectCommandSignature;
|
|
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawInstancedIndirectCommandSignature;
|
|
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawIndexedInstancedIndirectCommandSignature;
|
|
Microsoft::WRL::ComPtr<ID3D12CommandSignature> dispatchMeshIndirectCommandSignature;
|
|
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS features_0;
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS5 features_5;
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS6 features_6;
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS7 features_7;
|
|
|
|
uint32_t rtv_descriptor_size = 0;
|
|
uint32_t dsv_descriptor_size = 0;
|
|
uint32_t resource_descriptor_size = 0;
|
|
uint32_t sampler_descriptor_size = 0;
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE backbufferRTV[BACKBUFFER_COUNT] = {};
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullCBV = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSAM = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_buffer = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_texture1d = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_texture1darray = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_texture2d = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_texture2darray = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_texturecube = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_texturecubearray = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_texture3d = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV_accelerationstructure = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullUAV_buffer = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullUAV_texture1d = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullUAV_texture1darray = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullUAV_texture2d = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullUAV_texture2darray = {};
|
|
D3D12_CPU_DESCRIPTOR_HANDLE nullUAV_texture3d = {};
|
|
|
|
std::vector<D3D12_STATIC_SAMPLER_DESC> common_samplers;
|
|
|
|
struct CopyAllocator
|
|
{
|
|
Microsoft::WRL::ComPtr<ID3D12Device5> device;
|
|
Microsoft::WRL::ComPtr<ID3D12CommandQueue> queue;
|
|
Microsoft::WRL::ComPtr<ID3D12Fence> fence;
|
|
uint64_t fenceValue = 0;
|
|
std::mutex locker;
|
|
bool submitted = false;
|
|
|
|
struct CopyCMD
|
|
{
|
|
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> commandAllocator;
|
|
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList6> commandList;
|
|
uint64_t target = 0;
|
|
GPUBuffer uploadbuffer;
|
|
};
|
|
std::vector<CopyCMD> freelist;
|
|
std::deque<CopyCMD> worklist;
|
|
|
|
void Create(Microsoft::WRL::ComPtr<ID3D12Device5> device)
|
|
{
|
|
this->device = device;
|
|
|
|
D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {};
|
|
copyQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY;
|
|
copyQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
|
|
copyQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
|
copyQueueDesc.NodeMask = 0;
|
|
HRESULT hr = device->CreateCommandQueue(©QueueDesc, IID_PPV_ARGS(&queue));
|
|
assert(SUCCEEDED(hr));
|
|
|
|
hr = device->CreateFence(0, D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS(&fence));
|
|
assert(SUCCEEDED(hr));
|
|
fenceValue = fence->GetCompletedValue();
|
|
}
|
|
|
|
CopyCMD allocate(uint32_t staging_size = 0)
|
|
{
|
|
locker.lock();
|
|
|
|
// pop the finished command lists if there are any:
|
|
while (!worklist.empty() && worklist.front().target <= fence->GetCompletedValue())
|
|
{
|
|
freelist.push_back(worklist.front());
|
|
worklist.pop_front();
|
|
}
|
|
|
|
// create a new command list if there are no free ones:
|
|
if (freelist.empty())
|
|
{
|
|
CopyCMD cmd;
|
|
|
|
HRESULT hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&cmd.commandAllocator));
|
|
assert(SUCCEEDED(hr));
|
|
hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, cmd.commandAllocator.Get(), nullptr, IID_PPV_ARGS(&cmd.commandList));
|
|
assert(SUCCEEDED(hr));
|
|
|
|
hr = static_cast<ID3D12GraphicsCommandList*>(cmd.commandList.Get())->Close();
|
|
assert(SUCCEEDED(hr));
|
|
|
|
freelist.push_back(cmd);
|
|
}
|
|
|
|
CopyCMD cmd = freelist.back();
|
|
if (cmd.uploadbuffer.desc.ByteWidth < staging_size)
|
|
{
|
|
// Try to search for a staging buffer that is good:
|
|
for (size_t i = 0; i < freelist.size(); ++i)
|
|
{
|
|
if (freelist[i].uploadbuffer.desc.ByteWidth >= staging_size)
|
|
{
|
|
cmd = freelist[i];
|
|
std::swap(freelist[i], freelist.back());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// begin command list in valid state:
|
|
HRESULT hr = cmd.commandAllocator->Reset();
|
|
assert(SUCCEEDED(hr));
|
|
hr = static_cast<ID3D12GraphicsCommandList*>(cmd.commandList.Get())->Reset(cmd.commandAllocator.Get(), nullptr);
|
|
assert(SUCCEEDED(hr));
|
|
|
|
freelist.pop_back();
|
|
locker.unlock();
|
|
|
|
return cmd;
|
|
}
|
|
void submit(CopyCMD cmd)
|
|
{
|
|
static_cast<ID3D12GraphicsCommandList*>(cmd.commandList.Get())->Close();
|
|
ID3D12CommandList* commandlists[] = {
|
|
cmd.commandList.Get()
|
|
};
|
|
queue->ExecuteCommandLists(1, commandlists);
|
|
|
|
locker.lock();
|
|
submitted = true;
|
|
|
|
cmd.target = ++fenceValue;
|
|
queue->Signal(fence.Get(), cmd.target);
|
|
|
|
worklist.push_back(cmd);
|
|
locker.unlock();
|
|
}
|
|
};
|
|
CopyAllocator copyAllocator;
|
|
|
|
Microsoft::WRL::ComPtr<ID3D12Fence> directFence;
|
|
HANDLE directFenceEvent;
|
|
UINT64 directFenceValue = 0;
|
|
|
|
RenderPass dummyRenderpass;
|
|
|
|
struct DescriptorHeap
|
|
{
|
|
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
|
|
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> heap_GPU;
|
|
D3D12_CPU_DESCRIPTOR_HANDLE start_cpu = {};
|
|
D3D12_GPU_DESCRIPTOR_HANDLE start_gpu = {};
|
|
|
|
// CPU status:
|
|
std::atomic<uint64_t> allocationOffset{ 0 };
|
|
|
|
// GPU status:
|
|
Microsoft::WRL::ComPtr<ID3D12Fence> fence;
|
|
uint64_t fenceValue = 0;
|
|
uint64_t cached_completedValue = 0;
|
|
};
|
|
DescriptorHeap descriptorheap_res;
|
|
DescriptorHeap descriptorheap_sam;
|
|
|
|
struct FrameResources
|
|
{
|
|
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> commandAllocators[COMMANDLIST_COUNT];
|
|
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList6> commandLists[COMMANDLIST_COUNT];
|
|
|
|
struct ResourceFrameAllocator
|
|
{
|
|
GraphicsDevice_DX12* device = nullptr;
|
|
GPUBuffer buffer;
|
|
uint8_t* dataBegin = nullptr;
|
|
uint8_t* dataCur = nullptr;
|
|
uint8_t* dataEnd = nullptr;
|
|
|
|
void init(GraphicsDevice_DX12* device, size_t size);
|
|
|
|
uint8_t* allocate(size_t dataSize, size_t alignment);
|
|
void clear();
|
|
uint64_t calculateOffset(uint8_t* address);
|
|
};
|
|
ResourceFrameAllocator resourceBuffer[COMMANDLIST_COUNT];
|
|
};
|
|
FrameResources frames[BACKBUFFER_COUNT];
|
|
FrameResources& GetFrameResources() { return frames[GetFrameCount() % BACKBUFFER_COUNT]; }
|
|
inline ID3D12GraphicsCommandList6* GetDirectCommandList(CommandList cmd) { return GetFrameResources().commandLists[cmd].Get(); }
|
|
|
|
struct DescriptorBinder
|
|
{
|
|
GraphicsDevice_DX12* device = nullptr;
|
|
uint32_t ringOffset_res = 0;
|
|
uint32_t ringOffset_sam = 0;
|
|
bool dirty_res = false;
|
|
bool dirty_sam = false;
|
|
|
|
const GPUBuffer* CBV[GPU_RESOURCE_HEAP_CBV_COUNT];
|
|
const GPUResource* SRV[GPU_RESOURCE_HEAP_SRV_COUNT];
|
|
int SRV_index[GPU_RESOURCE_HEAP_SRV_COUNT];
|
|
const GPUResource* UAV[GPU_RESOURCE_HEAP_UAV_COUNT];
|
|
int UAV_index[GPU_RESOURCE_HEAP_UAV_COUNT];
|
|
const Sampler* SAM[GPU_SAMPLER_HEAP_COUNT];
|
|
|
|
uint32_t dirty_root_cbvs_gfx = 0; // bitmask
|
|
uint32_t dirty_root_cbvs_compute = 0; // bitmask
|
|
|
|
struct DescriptorHandles
|
|
{
|
|
D3D12_GPU_DESCRIPTOR_HANDLE sampler_handle = {};
|
|
D3D12_GPU_DESCRIPTOR_HANDLE resource_handle = {};
|
|
};
|
|
|
|
void init(GraphicsDevice_DX12* device);
|
|
|
|
void reset();
|
|
void request_heaps(uint32_t resources, uint32_t samplers, CommandList cmd);
|
|
void validate(bool graphics, CommandList cmd);
|
|
DescriptorHandles commit(const DescriptorTable* table, CommandList cmd);
|
|
};
|
|
DescriptorBinder descriptors[COMMANDLIST_COUNT];
|
|
|
|
Microsoft::WRL::ComPtr<IDXGISwapChain3> swapChain;
|
|
|
|
std::vector<D3D12_RESOURCE_BARRIER> frame_barriers[COMMANDLIST_COUNT];
|
|
|
|
PRIMITIVETOPOLOGY prev_pt[COMMANDLIST_COUNT] = {};
|
|
|
|
std::unordered_map<size_t, Microsoft::WRL::ComPtr<ID3D12RootSignature>> rootsignature_cache;
|
|
std::mutex rootsignature_cache_mutex;
|
|
|
|
std::unordered_map<size_t, Microsoft::WRL::ComPtr<ID3D12PipelineState>> pipelines_global;
|
|
std::vector<std::pair<size_t, Microsoft::WRL::ComPtr<ID3D12PipelineState>>> pipelines_worker[COMMANDLIST_COUNT];
|
|
size_t prev_pipeline_hash[COMMANDLIST_COUNT] = {};
|
|
const PipelineState* active_pso[COMMANDLIST_COUNT] = {};
|
|
const Shader* active_cs[COMMANDLIST_COUNT] = {};
|
|
const RaytracingPipelineState* active_rt[COMMANDLIST_COUNT] = {};
|
|
const ID3D12RootSignature* active_rootsig_graphics[COMMANDLIST_COUNT] = {};
|
|
const ID3D12RootSignature* active_rootsig_compute[COMMANDLIST_COUNT] = {};
|
|
const RenderPass* active_renderpass[COMMANDLIST_COUNT] = {};
|
|
SHADING_RATE prev_shadingrate[COMMANDLIST_COUNT] = {};
|
|
|
|
bool dirty_pso[COMMANDLIST_COUNT] = {};
|
|
void pso_validate(CommandList cmd);
|
|
|
|
void query_flush(CommandList cmd);
|
|
void barrier_flush(CommandList cmd);
|
|
void predraw(CommandList cmd);
|
|
void predispatch(CommandList cmd);
|
|
void preraytrace(CommandList cmd);
|
|
|
|
struct QueryResolver
|
|
{
|
|
const GPUQueryHeap* heap = nullptr;
|
|
uint32_t index = 0;
|
|
uint32_t count = 0;
|
|
};
|
|
std::vector<QueryResolver> query_resolves[COMMANDLIST_COUNT];
|
|
|
|
std::atomic<CommandList> cmd_count{ 0 };
|
|
|
|
public:
|
|
GraphicsDevice_DX12(wiPlatform::window_type window, bool fullscreen = false, bool debuglayer = false);
|
|
virtual ~GraphicsDevice_DX12();
|
|
|
|
bool CreateBuffer(const GPUBufferDesc *pDesc, const SubresourceData* pInitialData, GPUBuffer *pBuffer) override;
|
|
bool CreateTexture(const TextureDesc* pDesc, const SubresourceData *pInitialData, Texture *pTexture) override;
|
|
bool CreateShader(SHADERSTAGE stage, const void *pShaderBytecode, size_t BytecodeLength, Shader *pShader) override;
|
|
bool CreateSampler(const SamplerDesc *pSamplerDesc, Sampler *pSamplerState) override;
|
|
bool CreateQueryHeap(const GPUQueryHeapDesc* pDesc, GPUQueryHeap* pQueryHeap) override;
|
|
bool CreatePipelineState(const PipelineStateDesc* pDesc, PipelineState* pso) override;
|
|
bool CreateRenderPass(const RenderPassDesc* pDesc, RenderPass* renderpass) override;
|
|
bool CreateRaytracingAccelerationStructure(const RaytracingAccelerationStructureDesc* pDesc, RaytracingAccelerationStructure* bvh) override;
|
|
bool CreateRaytracingPipelineState(const RaytracingPipelineStateDesc* pDesc, RaytracingPipelineState* rtpso) override;
|
|
bool CreateDescriptorTable(DescriptorTable* table) override;
|
|
bool CreateRootSignature(RootSignature* rootsig) override;
|
|
|
|
int CreateSubresource(Texture* texture, SUBRESOURCE_TYPE type, uint32_t firstSlice, uint32_t sliceCount, uint32_t firstMip, uint32_t mipCount) override;
|
|
int CreateSubresource(GPUBuffer* buffer, SUBRESOURCE_TYPE type, uint64_t offset, uint64_t size = ~0) override;
|
|
|
|
void WriteShadingRateValue(SHADING_RATE rate, void* dest) override;
|
|
void WriteTopLevelAccelerationStructureInstance(const RaytracingAccelerationStructureDesc::TopLevel::Instance* instance, void* dest) override;
|
|
void WriteShaderIdentifier(const RaytracingPipelineState* rtpso, uint32_t group_index, void* dest) override;
|
|
void WriteDescriptor(const DescriptorTable* table, uint32_t rangeIndex, uint32_t arrayIndex, const GPUResource* resource, int subresource = -1, uint64_t offset = 0) override;
|
|
void WriteDescriptor(const DescriptorTable* table, uint32_t rangeIndex, uint32_t arrayIndex, const Sampler* sampler) override;
|
|
|
|
void Map(const GPUResource* resource, Mapping* mapping) override;
|
|
void Unmap(const GPUResource* resource) override;
|
|
void QueryRead(const GPUQueryHeap* heap, uint32_t index, uint32_t count, uint64_t* results) override;
|
|
|
|
void SetCommonSampler(const StaticSampler* sam) override;
|
|
|
|
void SetName(GPUResource* pResource, const char* name) override;
|
|
|
|
void PresentBegin(CommandList cmd) override;
|
|
void PresentEnd(CommandList cmd) override;
|
|
|
|
CommandList BeginCommandList() override;
|
|
void SubmitCommandLists() override;
|
|
|
|
void WaitForGPU() override;
|
|
void ClearPipelineStateCache() override;
|
|
|
|
void SetResolution(int width, int height) override;
|
|
|
|
Texture GetBackBuffer() override;
|
|
|
|
///////////////Thread-sensitive////////////////////////
|
|
|
|
void RenderPassBegin(const RenderPass* renderpass, CommandList cmd) override;
|
|
void RenderPassEnd(CommandList cmd) override;
|
|
void BindScissorRects(uint32_t numRects, const Rect* rects, CommandList cmd) override;
|
|
void BindViewports(uint32_t NumViewports, const Viewport* pViewports, CommandList cmd) override;
|
|
void BindResource(SHADERSTAGE stage, const GPUResource* resource, uint32_t slot, CommandList cmd, int subresource = -1) override;
|
|
void BindResources(SHADERSTAGE stage, const GPUResource *const* resources, uint32_t slot, uint32_t count, CommandList cmd) override;
|
|
void BindUAV(SHADERSTAGE stage, const GPUResource* resource, uint32_t slot, CommandList cmd, int subresource = -1) override;
|
|
void BindUAVs(SHADERSTAGE stage, const GPUResource *const* resources, uint32_t slot, uint32_t count, CommandList cmd) override;
|
|
void UnbindResources(uint32_t slot, uint32_t num, CommandList cmd) override;
|
|
void UnbindUAVs(uint32_t slot, uint32_t num, CommandList cmd) override;
|
|
void BindSampler(SHADERSTAGE stage, const Sampler* sampler, uint32_t slot, CommandList cmd) override;
|
|
void BindConstantBuffer(SHADERSTAGE stage, const GPUBuffer* buffer, uint32_t slot, CommandList cmd) override;
|
|
void BindVertexBuffers(const GPUBuffer *const* vertexBuffers, uint32_t slot, uint32_t count, const uint32_t* strides, const uint32_t* offsets, CommandList cmd) override;
|
|
void BindIndexBuffer(const GPUBuffer* indexBuffer, const INDEXBUFFER_FORMAT format, uint32_t offset, CommandList cmd) override;
|
|
void BindStencilRef(uint32_t value, CommandList cmd) override;
|
|
void BindBlendFactor(float r, float g, float b, float a, CommandList cmd) override;
|
|
void BindShadingRate(SHADING_RATE rate, CommandList cmd) override;
|
|
void BindPipelineState(const PipelineState* pso, CommandList cmd) override;
|
|
void BindComputeShader(const Shader* cs, CommandList cmd) override;
|
|
void Draw(uint32_t vertexCount, uint32_t startVertexLocation, CommandList cmd) override;
|
|
void DrawIndexed(uint32_t indexCount, uint32_t startIndexLocation, uint32_t baseVertexLocation, CommandList cmd) override;
|
|
void DrawInstanced(uint32_t vertexCount, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation, CommandList cmd) override;
|
|
void DrawIndexedInstanced(uint32_t indexCount, uint32_t instanceCount, uint32_t startIndexLocation, uint32_t baseVertexLocation, uint32_t startInstanceLocation, CommandList cmd) override;
|
|
void DrawInstancedIndirect(const GPUBuffer* args, uint32_t args_offset, CommandList cmd) override;
|
|
void DrawIndexedInstancedIndirect(const GPUBuffer* args, uint32_t args_offset, CommandList cmd) override;
|
|
void Dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ, CommandList cmd) override;
|
|
void DispatchIndirect(const GPUBuffer* args, uint32_t args_offset, CommandList cmd) override;
|
|
void DispatchMesh(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ, CommandList cmd) override;
|
|
void DispatchMeshIndirect(const GPUBuffer* args, uint32_t args_offset, CommandList cmd) override;
|
|
void CopyResource(const GPUResource* pDst, const GPUResource* pSrc, CommandList cmd) override;
|
|
void UpdateBuffer(const GPUBuffer* buffer, const void* data, CommandList cmd, int dataSize = -1) override;
|
|
void QueryBegin(const GPUQueryHeap* heap, uint32_t index, CommandList cmd) override;
|
|
void QueryEnd(const GPUQueryHeap* heap, uint32_t index, CommandList cmd) override;
|
|
void QueryResolve(const GPUQueryHeap* heap, uint32_t index, uint32_t count, CommandList cmd) override;
|
|
void Barrier(const GPUBarrier* barriers, uint32_t numBarriers, CommandList cmd) override;
|
|
void BuildRaytracingAccelerationStructure(const RaytracingAccelerationStructure* dst, CommandList cmd, const RaytracingAccelerationStructure* src = nullptr) override;
|
|
void BindRaytracingPipelineState(const RaytracingPipelineState* rtpso, CommandList cmd) override;
|
|
void DispatchRays(const DispatchRaysDesc* desc, CommandList cmd) override;
|
|
|
|
void BindDescriptorTable(BINDPOINT bindpoint, uint32_t space, const DescriptorTable* table, CommandList cmd) override;
|
|
void BindRootDescriptor(BINDPOINT bindpoint, uint32_t index, const GPUBuffer* buffer, uint32_t offset, CommandList cmd) override;
|
|
void BindRootConstants(BINDPOINT bindpoint, uint32_t index, const void* srcdata, CommandList cmd) override;
|
|
|
|
GPUAllocation AllocateGPU(size_t dataSize, CommandList cmd) override;
|
|
|
|
void EventBegin(const char* name, CommandList cmd) override;
|
|
void EventEnd(CommandList cmd) override;
|
|
void SetMarker(const char* name, CommandList cmd) override;
|
|
|
|
|
|
struct AllocationHandler
|
|
{
|
|
D3D12MA::Allocator* allocator = nullptr;
|
|
Microsoft::WRL::ComPtr<ID3D12Device> device;
|
|
uint64_t framecount = 0;
|
|
std::mutex destroylocker;
|
|
|
|
struct DescriptorAllocator
|
|
{
|
|
GraphicsDevice_DX12* device = nullptr;
|
|
std::mutex locker;
|
|
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
|
std::vector<Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>> heaps;
|
|
uint32_t descriptor_size = 0;
|
|
std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> freelist;
|
|
|
|
void init(GraphicsDevice_DX12* device, D3D12_DESCRIPTOR_HEAP_TYPE type)
|
|
{
|
|
this->device = device;
|
|
desc.Type = type;
|
|
desc.NumDescriptors = 1024;
|
|
descriptor_size = device->device->GetDescriptorHandleIncrementSize(type);
|
|
}
|
|
void block_allocate()
|
|
{
|
|
heaps.emplace_back();
|
|
HRESULT hr = device->device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&heaps.back()));
|
|
assert(SUCCEEDED(hr));
|
|
D3D12_CPU_DESCRIPTOR_HANDLE heap_start = heaps.back()->GetCPUDescriptorHandleForHeapStart();
|
|
for (UINT i = 0; i < desc.NumDescriptors; ++i)
|
|
{
|
|
D3D12_CPU_DESCRIPTOR_HANDLE handle = heap_start;
|
|
handle.ptr += i * descriptor_size;
|
|
freelist.push_back(handle);
|
|
}
|
|
}
|
|
D3D12_CPU_DESCRIPTOR_HANDLE allocate()
|
|
{
|
|
locker.lock();
|
|
if (freelist.empty())
|
|
{
|
|
block_allocate();
|
|
}
|
|
assert(!freelist.empty());
|
|
D3D12_CPU_DESCRIPTOR_HANDLE handle = freelist.back();
|
|
freelist.pop_back();
|
|
locker.unlock();
|
|
return handle;
|
|
}
|
|
void free(D3D12_CPU_DESCRIPTOR_HANDLE index)
|
|
{
|
|
locker.lock();
|
|
freelist.push_back(index);
|
|
locker.unlock();
|
|
}
|
|
};
|
|
DescriptorAllocator descriptors_res;
|
|
DescriptorAllocator descriptors_sam;
|
|
DescriptorAllocator descriptors_rtv;
|
|
DescriptorAllocator descriptors_dsv;
|
|
|
|
std::deque<std::pair<D3D12MA::Allocation*, uint64_t>> destroyer_allocations;
|
|
std::deque<std::pair<Microsoft::WRL::ComPtr<ID3D12Resource>, uint64_t>> destroyer_resources;
|
|
std::deque<std::pair<Microsoft::WRL::ComPtr<ID3D12QueryHeap>, uint64_t>> destroyer_queryheaps;
|
|
std::deque<std::pair<Microsoft::WRL::ComPtr<ID3D12PipelineState>, uint64_t>> destroyer_pipelines;
|
|
std::deque<std::pair<Microsoft::WRL::ComPtr<ID3D12RootSignature>, uint64_t>> destroyer_rootSignatures;
|
|
std::deque<std::pair<Microsoft::WRL::ComPtr<ID3D12StateObject>, uint64_t>> destroyer_stateobjects;
|
|
std::deque<std::pair<Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>, uint64_t>> destroyer_descriptorHeaps;
|
|
|
|
~AllocationHandler()
|
|
{
|
|
Update(~0, 0); // destroy all remaining
|
|
if (allocator) allocator->Release();
|
|
}
|
|
|
|
// Deferred destroy of resources that the GPU is already finished with:
|
|
void Update(uint64_t FRAMECOUNT, uint32_t BACKBUFFER_COUNT)
|
|
{
|
|
destroylocker.lock();
|
|
framecount = FRAMECOUNT;
|
|
while (!destroyer_allocations.empty())
|
|
{
|
|
if (destroyer_allocations.front().second + BACKBUFFER_COUNT < FRAMECOUNT)
|
|
{
|
|
auto item = destroyer_allocations.front();
|
|
destroyer_allocations.pop_front();
|
|
item.first->Release();
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (!destroyer_resources.empty())
|
|
{
|
|
if (destroyer_resources.front().second + BACKBUFFER_COUNT < FRAMECOUNT)
|
|
{
|
|
destroyer_resources.pop_front();
|
|
// comptr auto delete
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (!destroyer_queryheaps.empty())
|
|
{
|
|
if (destroyer_queryheaps.front().second + BACKBUFFER_COUNT < FRAMECOUNT)
|
|
{
|
|
destroyer_queryheaps.pop_front();
|
|
// comptr auto delete
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (!destroyer_pipelines.empty())
|
|
{
|
|
if (destroyer_pipelines.front().second + BACKBUFFER_COUNT < FRAMECOUNT)
|
|
{
|
|
destroyer_pipelines.pop_front();
|
|
// comptr auto delete
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (!destroyer_rootSignatures.empty())
|
|
{
|
|
if (destroyer_rootSignatures.front().second + BACKBUFFER_COUNT < FRAMECOUNT)
|
|
{
|
|
destroyer_rootSignatures.pop_front();
|
|
// comptr auto delete
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (!destroyer_stateobjects.empty())
|
|
{
|
|
if (destroyer_stateobjects.front().second + BACKBUFFER_COUNT < FRAMECOUNT)
|
|
{
|
|
destroyer_stateobjects.pop_front();
|
|
// comptr auto delete
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (!destroyer_descriptorHeaps.empty())
|
|
{
|
|
if (destroyer_descriptorHeaps.front().second + BACKBUFFER_COUNT < FRAMECOUNT)
|
|
{
|
|
destroyer_descriptorHeaps.pop_front();
|
|
// comptr auto delete
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
destroylocker.unlock();
|
|
}
|
|
};
|
|
std::shared_ptr<AllocationHandler> allocationhandler;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif // WICKEDENGINE_BUILD_DX12
|