Files
WickedEngine/WickedEngine/wiGraphicsDevice_DX12.h
2025-03-16 10:22:53 +01:00

611 lines
26 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 "wiUnorderedMap.h"
#include "wiVector.h"
#include "wiSpinLock.h"
#include "wiBacklog.h"
#include "wiHelper.h"
#ifdef PLATFORM_XBOX
#include "wiGraphicsDevice_DX12_XBOX.h"
#else
#include "Utility/dx12/d3d12.h"
#include "Utility/dx12/d3d12video.h"
#include <dxgi1_6.h>
#define PPV_ARGS(x) IID_PPV_ARGS(&x)
#endif // PLATFORM_XBOX
#include <wrl/client.h> // ComPtr
#define D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
#define __ID3D12Device1_INTERFACE_DEFINED__
#include "Utility/D3D12MemAlloc.h"
#include <deque>
#include <atomic>
#include <mutex>
#define dx12_assert(cond, fname) { wilog_assert(cond, "DX12 error: %s failed with %s (%s:%d)", fname, wi::helper::GetPlatformErrorString(hr).c_str(), relative_path(__FILE__), __LINE__); }
#define dx12_check(call) [&]() { HRESULT hr = call; dx12_assert(SUCCEEDED(hr), extract_function_name(#call).c_str()); return hr; }()
namespace wi::graphics
{
class GraphicsDevice_DX12 final : public GraphicsDevice
{
protected:
#ifndef PLATFORM_XBOX
Microsoft::WRL::ComPtr<IDXGIFactory4> dxgiFactory;
#endif // PLATFORM_XBOX
Microsoft::WRL::ComPtr<ID3D12Device5> device;
Microsoft::WRL::ComPtr<ID3D12VideoDevice> video_device;
#ifdef PLATFORM_WINDOWS_DESKTOP
Microsoft::WRL::ComPtr<ID3D12Fence> deviceRemovedFence;
HANDLE deviceRemovedWaitHandle = {};
#endif // PLATFORM_WINDOWS_DESKTOP
Microsoft::WRL::ComPtr<ID3D12CommandSignature> dispatchIndirectCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawInstancedIndirectCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawIndexedInstancedIndirectCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> dispatchMeshIndirectCommandSignature;
bool deviceRemoved = false;
bool tearingSupported = false;
bool additionalShadingRatesSupported = false;
bool casting_fully_typed_formats = false;
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_RESOURCE_HEAP_TIER resource_heap_tier = {};
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> nulldescriptorheap_cbv_srv_uav;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> nulldescriptorheap_sampler;
D3D12_CPU_DESCRIPTOR_HANDLE nullCBV = {};
D3D12_CPU_DESCRIPTOR_HANDLE nullSRV = {};
D3D12_CPU_DESCRIPTOR_HANDLE nullUAV = {};
D3D12_CPU_DESCRIPTOR_HANDLE nullSAM = {};
struct Semaphore
{
Microsoft::WRL::ComPtr<ID3D12Fence> fence;
uint64_t fenceValue = 0;
};
struct CommandQueue
{
D3D12_COMMAND_QUEUE_DESC desc = {};
Microsoft::WRL::ComPtr<ID3D12CommandQueue> queue;
wi::vector<ID3D12CommandList*> submit_cmds;
void signal(const Semaphore& semaphore);
void wait(const Semaphore& semaphore);
void submit();
} queues[QUEUE_COUNT];
struct CopyAllocator
{
GraphicsDevice_DX12* device = nullptr;
Microsoft::WRL::ComPtr<ID3D12CommandQueue> queue; // create separate copy queue to reduce interference with main QUEUE_COPY
std::mutex locker;
struct CopyCMD
{
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> commandAllocator;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> commandList;
Microsoft::WRL::ComPtr<ID3D12Fence> fence;
uint64_t fenceValueSignaled = 0;
GPUBuffer uploadbuffer;
inline bool IsValid() const { return commandList != nullptr; }
inline bool IsCompleted() const { return fence->GetCompletedValue() >= fenceValueSignaled; }
};
wi::vector<CopyCMD> freelist;
void init(GraphicsDevice_DX12* device);
CopyCMD allocate(uint64_t staging_size);
void submit(CopyCMD cmd);
};
mutable CopyAllocator copyAllocator;
Microsoft::WRL::ComPtr<ID3D12Fence> frame_fence_cpu[BUFFERCOUNT][QUEUE_COUNT];
Microsoft::WRL::ComPtr<ID3D12Fence> frame_fence_gpu[BUFFERCOUNT][QUEUE_COUNT];
struct DescriptorBinder
{
DescriptorBindingTable table;
GraphicsDevice_DX12* device = nullptr;
const void* optimizer_graphics = nullptr;
uint64_t dirty_graphics = 0ull; // 1 dirty bit flag per root parameter
const void* optimizer_compute = nullptr;
uint64_t dirty_compute = 0ull; // 1 dirty bit flag per root parameter
void init(GraphicsDevice_DX12* device);
void reset();
void flush(bool graphics, CommandList cmd);
};
wi::vector<Semaphore> semaphore_pool;
std::mutex semaphore_pool_locker;
Semaphore new_semaphore()
{
std::scoped_lock lck(semaphore_pool_locker);
if (semaphore_pool.empty())
{
Semaphore& dependency = semaphore_pool.emplace_back();
dx12_check(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, PPV_ARGS(dependency.fence)));
dx12_check(dependency.fence.Get()->SetName(L"DependencySemaphore"));
}
Semaphore semaphore = std::move(semaphore_pool.back());
semaphore_pool.pop_back();
semaphore.fenceValue++;
return semaphore;
}
void free_semaphore(const Semaphore& semaphore)
{
std::scoped_lock lck(semaphore_pool_locker);
semaphore_pool.push_back(semaphore);
}
struct CommandList_DX12
{
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> commandAllocators[BUFFERCOUNT][QUEUE_COUNT];
Microsoft::WRL::ComPtr<ID3D12CommandList> commandLists[QUEUE_COUNT];
using graphics_command_list_version = ID3D12GraphicsCommandList6;
uint32_t buffer_index = 0;
QUEUE_TYPE queue = {};
uint32_t id = 0;
wi::vector<Semaphore> waits;
wi::vector<Semaphore> signals;
DescriptorBinder binder;
GPULinearAllocator frame_allocators[BUFFERCOUNT];
wi::vector<D3D12_RESOURCE_BARRIER> frame_barriers;
struct Discard
{
ID3D12Resource* resource = nullptr;
D3D12_DISCARD_REGION region = {};
};
wi::vector<Discard> discards;
D3D_PRIMITIVE_TOPOLOGY prev_pt = {};
wi::vector<std::pair<PipelineHash, Microsoft::WRL::ComPtr<ID3D12PipelineState>>> pipelines_worker;
PipelineHash prev_pipeline_hash = {};
const PipelineState* active_pso = {};
const Shader* active_cs = {};
const RaytracingPipelineState* active_rt = {};
const ID3D12RootSignature* active_rootsig_graphics = {};
const ID3D12RootSignature* active_rootsig_compute = {};
ShadingRate prev_shadingrate = {};
wi::vector<const SwapChain*> swapchains;
bool dirty_pso = {};
wi::vector<D3D12_RAYTRACING_GEOMETRY_DESC> accelerationstructure_build_geometries;
RenderPassInfo renderpass_info;
wi::vector<D3D12_RESOURCE_BARRIER> renderpass_barriers_begin;
wi::vector<D3D12_RESOURCE_BARRIER> renderpass_barriers_begin_after_discards;
wi::vector<D3D12_RESOURCE_BARRIER> renderpass_barriers_end;
ID3D12Resource* shading_rate_image = nullptr;
ID3D12Resource* resolve_src[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
ID3D12Resource* resolve_dst[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
DXGI_FORMAT resolve_formats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
ID3D12Resource* resolve_src_ds = nullptr;
ID3D12Resource* resolve_dst_ds = nullptr;
DXGI_FORMAT resolve_ds_format = {};
wi::vector<D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS> resolve_subresources[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
wi::vector<D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS> resolve_subresources_dsv = {};
wi::vector<D3D12_RESOURCE_BARRIER> resolve_src_barriers;
void reset(uint32_t bufferindex)
{
buffer_index = bufferindex;
waits.clear();
signals.clear();
binder.reset();
frame_allocators[buffer_index].reset();
prev_pt = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
prev_pipeline_hash = {};
active_pso = nullptr;
active_cs = nullptr;
active_rt = nullptr;
active_rootsig_graphics = nullptr;
active_rootsig_compute = nullptr;
prev_shadingrate = ShadingRate::RATE_INVALID;
dirty_pso = false;
swapchains.clear();
renderpass_info = {};
renderpass_barriers_begin.clear();
renderpass_barriers_end.clear();
for (size_t i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
{
resolve_src[i] = {};
resolve_dst[i] = {};
resolve_subresources[i].clear();
}
resolve_subresources_dsv.clear();
resolve_src_barriers.clear();
resolve_src_ds = nullptr;
resolve_dst_ds = nullptr;
shading_rate_image = nullptr;
}
inline ID3D12CommandAllocator* GetCommandAllocator()
{
return commandAllocators[buffer_index][queue].Get();
}
inline ID3D12CommandList* GetCommandList()
{
return commandLists[queue].Get();
}
inline ID3D12GraphicsCommandList* GetGraphicsCommandList()
{
assert(queue != QUEUE_VIDEO_DECODE);
return (ID3D12GraphicsCommandList*)commandLists[queue].Get();
}
inline graphics_command_list_version* GetGraphicsCommandListLatest()
{
assert(queue != QUEUE_VIDEO_DECODE && queue != QUEUE_COPY);
return (graphics_command_list_version*)commandLists[queue].Get();
}
inline ID3D12VideoDecodeCommandList* GetVideoDecodeCommandList()
{
assert(queue == QUEUE_VIDEO_DECODE);
return (ID3D12VideoDecodeCommandList*)commandLists[queue].Get();
}
};
wi::vector<std::unique_ptr<CommandList_DX12>> commandlists;
uint32_t cmd_count = 0;
wi::SpinLock cmd_locker;
constexpr CommandList_DX12& GetCommandList(CommandList cmd) const
{
assert(cmd.IsValid());
return *(CommandList_DX12*)cmd.internal_state;
}
wi::unordered_map<PipelineHash, Microsoft::WRL::ComPtr<ID3D12PipelineState>> pipelines_global;
void pso_validate(CommandList cmd);
void predraw(CommandList cmd);
void predispatch(CommandList cmd);
public:
GraphicsDevice_DX12(ValidationMode validationMode = ValidationMode::Disabled, GPUPreference preference = GPUPreference::Discrete);
~GraphicsDevice_DX12() override;
bool CreateSwapChain(const SwapChainDesc* desc, wi::platform::window_type window, SwapChain* swapchain) const override;
bool CreateBuffer2(const GPUBufferDesc * desc, const std::function<void(void*)>& init_callback, GPUBuffer* buffer, const GPUResource* alias = nullptr, uint64_t alias_offset = 0ull) const override;
bool CreateTexture(const TextureDesc* desc, const SubresourceData* initial_data, Texture* texture, const GPUResource* alias = nullptr, uint64_t alias_offset = 0ull) const override;
bool CreateShader(ShaderStage stage, const void* shadercode, size_t shadercode_size, Shader* shader) const override;
bool CreateSampler(const SamplerDesc* desc, Sampler* sampler) const override;
bool CreateQueryHeap(const GPUQueryHeapDesc* desc, GPUQueryHeap* queryheap) const override;
bool CreatePipelineState(const PipelineStateDesc* desc, PipelineState* pso, const RenderPassInfo* renderpass_info = nullptr) const override;
bool CreateRaytracingAccelerationStructure(const RaytracingAccelerationStructureDesc* desc, RaytracingAccelerationStructure* bvh) const override;
bool CreateRaytracingPipelineState(const RaytracingPipelineStateDesc* desc, RaytracingPipelineState* rtpso) const override;
bool CreateVideoDecoder(const VideoDesc* desc, VideoDecoder* video_decoder) const override;
int CreateSubresource(Texture* texture, SubresourceType type, uint32_t firstSlice, uint32_t sliceCount, uint32_t firstMip, uint32_t mipCount, const Format* format_change = nullptr, const ImageAspect* aspect = nullptr, const Swizzle* swizzle = nullptr, float min_lod_clamp = 0) const override;
int CreateSubresource(GPUBuffer* buffer, SubresourceType type, uint64_t offset, uint64_t size = ~0, const Format* format_change = nullptr, const uint32_t* structuredbuffer_stride_change = nullptr) const override;
void DeleteSubresources(GPUResource* resource) override;
int GetDescriptorIndex(const GPUResource* resource, SubresourceType type, int subresource = -1) const override;
int GetDescriptorIndex(const Sampler* sampler) const override;
void WriteShadingRateValue(ShadingRate rate, void* dest) const override;
void WriteTopLevelAccelerationStructureInstance(const RaytracingAccelerationStructureDesc::TopLevel::Instance* instance, void* dest) const override;
void WriteShaderIdentifier(const RaytracingPipelineState* rtpso, uint32_t group_index, void* dest) const override;
void SetName(GPUResource* pResource, const char* name) const override;
CommandList BeginCommandList(QUEUE_TYPE queue = QUEUE_GRAPHICS) override;
void SubmitCommandLists() override;
void OnDeviceRemoved();
void WaitForGPU() const override;
void ClearPipelineStateCache() override;
size_t GetActivePipelineCount() const override { return pipelines_global.size(); }
ShaderFormat GetShaderFormat() const override
{
#ifdef PLATFORM_XBOX
return ShaderFormat::HLSL6_XS;
#else
return ShaderFormat::HLSL6;
#endif // PLATFORM_XBOX
}
Texture GetBackBuffer(const SwapChain* swapchain) const override;
ColorSpace GetSwapChainColorSpace(const SwapChain* swapchain) const override;
bool IsSwapChainSupportsHDR(const SwapChain* swapchain) const override;
uint64_t GetMinOffsetAlignment(const GPUBufferDesc* desc) const override
{
uint64_t alignment = 1u;
if (has_flag(desc->bind_flags, BindFlag::CONSTANT_BUFFER))
{
alignment = std::max(alignment, (uint64_t)D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
}
if (has_flag(desc->misc_flags, ResourceMiscFlag::BUFFER_RAW))
{
alignment = std::max(alignment, (uint64_t)D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT);
}
if (has_flag(desc->misc_flags, ResourceMiscFlag::BUFFER_STRUCTURED))
{
alignment = std::max(alignment, (uint64_t)desc->stride);
}
if (desc->format != Format::UNKNOWN || has_flag(desc->misc_flags, ResourceMiscFlag::TYPED_FORMAT_CASTING))
{
alignment = std::max(alignment, 16ull);
}
return alignment;
}
MemoryUsage GetMemoryUsage() const override
{
MemoryUsage retval;
D3D12MA::Budget budget;
allocationhandler->allocator->GetBudget(&budget, nullptr);
retval.budget = budget.BudgetBytes;
retval.usage = budget.UsageBytes;
return retval;
}
uint32_t GetMaxViewportCount() const override { return D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; };
void SparseUpdate(QUEUE_TYPE queue, const SparseUpdateCommand* commands, uint32_t command_count) override;
///////////////Thread-sensitive////////////////////////
void WaitCommandList(CommandList cmd, CommandList wait_for) override;
void RenderPassBegin(const SwapChain* swapchain, CommandList cmd) override;
void RenderPassBegin(const RenderPassImage* images, uint32_t image_count, CommandList cmd, RenderPassFlags flags = RenderPassFlags::NONE) 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(const GPUResource* resource, uint32_t slot, CommandList cmd, int subresource = -1) override;
void BindResources(const GPUResource *const* resources, uint32_t slot, uint32_t count, CommandList cmd) override;
void BindUAV(const GPUResource* resource, uint32_t slot, CommandList cmd, int subresource = -1) override;
void BindUAVs(const GPUResource *const* resources, uint32_t slot, uint32_t count, CommandList cmd) override;
void BindSampler(const Sampler* sampler, uint32_t slot, CommandList cmd) override;
void BindConstantBuffer(const GPUBuffer* buffer, uint32_t slot, CommandList cmd, uint64_t offset = 0ull) override;
void BindVertexBuffers(const GPUBuffer *const* vertexBuffers, uint32_t slot, uint32_t count, const uint32_t* strides, const uint64_t* offsets, CommandList cmd) override;
void BindIndexBuffer(const GPUBuffer* indexBuffer, const IndexBufferFormat format, uint64_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(ShadingRate rate, CommandList cmd) override;
void BindPipelineState(const PipelineState* pso, CommandList cmd) override;
void BindComputeShader(const Shader* cs, CommandList cmd) override;
void BindDepthBounds(float min_bounds, float max_bounds, CommandList cmd) override;
void Draw(uint32_t vertexCount, uint32_t startVertexLocation, CommandList cmd) override;
void DrawIndexed(uint32_t indexCount, uint32_t startIndexLocation, int32_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, int32_t baseVertexLocation, uint32_t startInstanceLocation, CommandList cmd) override;
void DrawInstancedIndirect(const GPUBuffer* args, uint64_t args_offset, CommandList cmd) override;
void DrawIndexedInstancedIndirect(const GPUBuffer* args, uint64_t args_offset, CommandList cmd) override;
void DrawInstancedIndirectCount(const GPUBuffer* args, uint64_t args_offset, const GPUBuffer* count, uint64_t count_offset, uint32_t max_count, CommandList cmd) override;
void DrawIndexedInstancedIndirectCount(const GPUBuffer* args, uint64_t args_offset, const GPUBuffer* count, uint64_t count_offset, uint32_t max_count, CommandList cmd) override;
void Dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ, CommandList cmd) override;
void DispatchIndirect(const GPUBuffer* args, uint64_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, uint64_t args_offset, CommandList cmd) override;
void DispatchMeshIndirectCount(const GPUBuffer* args, uint64_t args_offset, const GPUBuffer* count, uint64_t count_offset, uint32_t max_count, CommandList cmd) override;
void CopyResource(const GPUResource* pDst, const GPUResource* pSrc, CommandList cmd) override;
void CopyBuffer(const GPUBuffer* pDst, uint64_t dst_offset, const GPUBuffer* pSrc, uint64_t src_offset, uint64_t size, CommandList cmd) override;
void CopyTexture(const Texture* dst, uint32_t dstX, uint32_t dstY, uint32_t dstZ, uint32_t dstMip, uint32_t dstSlice, const Texture* src, uint32_t srcMip, uint32_t srcSlice, CommandList cmd, const Box* srcbox, ImageAspect dst_aspect, ImageAspect src_aspect) 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, const GPUBuffer* dest, uint64_t dest_offset, CommandList cmd) override;
void QueryReset(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 PushConstants(const void* data, uint32_t size, CommandList cmd, uint32_t offset = 0) override;
void PredicationBegin(const GPUBuffer* buffer, uint64_t offset, PredicationOp op, CommandList cmd) override;
void PredicationEnd(CommandList cmd) override;
void ClearUAV(const GPUResource* resource, uint32_t value, CommandList cmd) override;
void VideoDecode(const VideoDecoder* video_decoder, const VideoDecodeOperation* op, CommandList cmd) override;
void EventBegin(const char* name, CommandList cmd) override;
void EventEnd(CommandList cmd) override;
void SetMarker(const char* name, CommandList cmd) override;
RenderPassInfo GetRenderPassInfo(CommandList cmd) override
{
return GetCommandList(cmd).renderpass_info;
}
GPULinearAllocator& GetFrameAllocator(CommandList cmd) override
{
return GetCommandList(cmd).frame_allocators[GetBufferIndex()];
}
ID3D12Resource* GetTextureInternalResource(const Texture* texture);
ID3D12CommandQueue* GetGraphicsCommandQueue();
struct DescriptorHeapGPU
{
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;
void SignalGPU(ID3D12CommandQueue* queue)
{
// Descriptor heaps' progress is recorded by the GPU:
fenceValue = allocationOffset.load();
dx12_check(queue->Signal(fence.Get(), fenceValue));
cached_completedValue = fence->GetCompletedValue();
}
};
DescriptorHeapGPU descriptorheap_res;
DescriptorHeapGPU descriptorheap_sam;
struct AllocationHandler
{
Microsoft::WRL::ComPtr<D3D12MA::Allocator> allocator;
Microsoft::WRL::ComPtr<ID3D12Device> device;
uint64_t framecount = 0;
std::mutex destroylocker;
Microsoft::WRL::ComPtr<D3D12MA::Pool> uma_pool;
struct DescriptorAllocator
{
GraphicsDevice_DX12* device = nullptr;
std::mutex locker;
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
wi::vector<Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>> heaps;
uint32_t descriptor_size = 0;
wi::vector<D3D12_CPU_DESCRIPTOR_HANDLE> freelist;
void init(GraphicsDevice_DX12* device, D3D12_DESCRIPTOR_HEAP_TYPE type, UINT numDescriptorsPerBlock)
{
this->device = device;
desc.Type = type;
desc.NumDescriptors = numDescriptorsPerBlock;
descriptor_size = device->device->GetDescriptorHandleIncrementSize(type);
}
void block_allocate()
{
heaps.emplace_back();
dx12_check(device->device->CreateDescriptorHeap(&desc, PPV_ARGS(heaps.back())));
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;
wi::vector<int> free_bindless_res;
wi::vector<int> free_bindless_sam;
std::deque<std::pair<Microsoft::WRL::ComPtr<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<ID3D12VideoDecoderHeap>, uint64_t>> destroyer_video_decoder_heaps;
std::deque<std::pair<Microsoft::WRL::ComPtr<ID3D12VideoDecoder>, uint64_t>> destroyer_video_decoders;
std::deque<std::pair<int, uint64_t>> destroyer_bindless_res;
std::deque<std::pair<int, uint64_t>> destroyer_bindless_sam;
~AllocationHandler()
{
Update(~0ull, 0); // destroy all remaining
}
// Deferred destroy of resources that the GPU is already finished with:
void Update(uint64_t FRAMECOUNT, uint32_t BUFFERCOUNT)
{
std::scoped_lock lck(destroylocker);
framecount = FRAMECOUNT;
while (!destroyer_allocations.empty() && destroyer_allocations.front().second + BUFFERCOUNT < FRAMECOUNT)
{
destroyer_allocations.pop_front();
// comptr auto delete
}
while (!destroyer_resources.empty() && destroyer_resources.front().second + BUFFERCOUNT < FRAMECOUNT)
{
destroyer_resources.pop_front();
// comptr auto delete
}
while (!destroyer_queryheaps.empty() && destroyer_queryheaps.front().second + BUFFERCOUNT < FRAMECOUNT)
{
destroyer_queryheaps.pop_front();
// comptr auto delete
}
while (!destroyer_pipelines.empty() && destroyer_pipelines.front().second + BUFFERCOUNT < FRAMECOUNT)
{
destroyer_pipelines.pop_front();
// comptr auto delete
}
while (!destroyer_rootSignatures.empty() && destroyer_rootSignatures.front().second + BUFFERCOUNT < FRAMECOUNT)
{
destroyer_rootSignatures.pop_front();
// comptr auto delete
}
while (!destroyer_stateobjects.empty() && destroyer_stateobjects.front().second + BUFFERCOUNT < FRAMECOUNT)
{
destroyer_stateobjects.pop_front();
// comptr auto delete
}
while (!destroyer_video_decoder_heaps.empty() && destroyer_video_decoder_heaps.front().second + BUFFERCOUNT < FRAMECOUNT)
{
destroyer_video_decoder_heaps.pop_front();
// comptr auto delete
}
while (!destroyer_video_decoders.empty() && destroyer_video_decoders.front().second + BUFFERCOUNT < FRAMECOUNT)
{
destroyer_video_decoders.pop_front();
// comptr auto delete
}
while (!destroyer_bindless_res.empty() && destroyer_bindless_res.front().second + BUFFERCOUNT < FRAMECOUNT)
{
int index = destroyer_bindless_res.front().first;
destroyer_bindless_res.pop_front();
free_bindless_res.push_back(index);
}
while (!destroyer_bindless_sam.empty() && destroyer_bindless_sam.front().second + BUFFERCOUNT < FRAMECOUNT)
{
int index = destroyer_bindless_sam.front().first;
destroyer_bindless_sam.pop_front();
free_bindless_sam.push_back(index);
}
}
};
std::shared_ptr<AllocationHandler> allocationhandler;
};
}
#endif // WICKEDENGINE_BUILD_DX12