diff --git a/code/framework/src/graphics/backend/d3d12.cpp b/code/framework/src/graphics/backend/d3d12.cpp index 64de633df..51f172f38 100644 --- a/code/framework/src/graphics/backend/d3d12.cpp +++ b/code/framework/src/graphics/backend/d3d12.cpp @@ -41,12 +41,22 @@ namespace Framework::Graphics { { D3D12_DESCRIPTOR_HEAP_DESC desc {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - desc.NumDescriptors = _frameBufferCount; + desc.NumDescriptors = _frameBufferCount + kExtraSrvSlots; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; if (pD3DDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&_srvHeap)) != S_OK) { return false; } + + // Manage slots that are not reserved for ImGui and headroom + _srvDescriptorSize = pD3DDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + _srvHeapSize = desc.NumDescriptors; + _srvSlotInUse.assign(_srvHeapSize, false); + _freeSrvSlots.clear(); + const auto extraSrvStart = _frameBufferCount - 1; + for (UINT i = kExtraSrvSlots; i > 0; i--) { + _freeSrvSlots.push_back(extraSrvStart + i); + } } // #3 create rtv heap @@ -99,6 +109,7 @@ namespace Framework::Graphics { // release objects _rtvHeap->Release(); _srvHeap->Release(); + _srvHeap = nullptr; _commandList->Release(); for (const auto &frameContext : _frameContext) { frameContext._commandAllocator->Release(); @@ -140,4 +151,59 @@ namespace Framework::Graphics { int D3D12Backend::NumFramesInFlight() const { return _frameBufferCount; } + + int D3D12Backend::AllocateSRVSlot() { + std::lock_guard lock(_srvMutex); + if (!_srvHeap) { + Framework::Logging::GetLogger(FRAMEWORK_INNER_GRAPHICS)->error("D3D12Backend::AllocateSRVSlot, no descriptor heap"); + return -1; + } + if (_freeSrvSlots.empty()) { + Framework::Logging::GetLogger(FRAMEWORK_INNER_GRAPHICS)->error("D3D12Backend::AllocateSRVSlot, heap exhausted"); + return -1; + } + const auto slot = _freeSrvSlots.back(); + _freeSrvSlots.pop_back(); + _srvSlotInUse[slot] = true; + return static_cast(slot); + } + + void D3D12Backend::FreeSRVSlot(int slot) { + std::lock_guard lock(_srvMutex); + // reject out-of-pool indices and double-frees so a bad id can never + // re-enter the free list and alias a live slot + if (slot < static_cast(_frameBufferCount) || slot >= static_cast(_srvHeapSize)) { + Framework::Logging::GetLogger(FRAMEWORK_INNER_GRAPHICS)->error("D3D12Backend::FreeSRVSlot, slot {} out of pool range", slot); + return; + } + if (!_srvSlotInUse[slot]) { + Framework::Logging::GetLogger(FRAMEWORK_INNER_GRAPHICS)->error("D3D12Backend::FreeSRVSlot, slot {} not allocated", slot); + return; + } + _srvSlotInUse[slot] = false; + _freeSrvSlots.push_back(static_cast(slot)); + } + + D3D12_CPU_DESCRIPTOR_HANDLE D3D12Backend::GetSRVSlotCPUHandle(int slot) const { + if (!_srvHeap || slot < 0 || slot >= static_cast(_srvHeapSize)) { + return {}; + } + auto handle = _srvHeap->GetCPUDescriptorHandleForHeapStart(); + handle.ptr += static_cast(slot) * _srvDescriptorSize; + return handle; + } + + D3D12_GPU_DESCRIPTOR_HANDLE D3D12Backend::GetSRVSlotGPUHandle(int slot) const { + if (!_srvHeap || slot < 0 || slot >= static_cast(_srvHeapSize)) { + return {}; + } + auto handle = _srvHeap->GetGPUDescriptorHandleForHeapStart(); + handle.ptr += static_cast(slot) * _srvDescriptorSize; + return handle; + } + + size_t D3D12Backend::GetFreeSRVSlotCount() const { + std::lock_guard lock(_srvMutex); + return _freeSrvSlots.size(); + } } // namespace Framework::Graphics diff --git a/code/framework/src/graphics/backend/d3d12.h b/code/framework/src/graphics/backend/d3d12.h index a885fd3e4..1cbb507f9 100644 --- a/code/framework/src/graphics/backend/d3d12.h +++ b/code/framework/src/graphics/backend/d3d12.h @@ -11,10 +11,16 @@ #include "backend.h" #include +#include #include namespace Framework::Graphics { class D3D12Backend: public Backend { + public: + // Shader-visible SRV slots reserved past the ImGui font descriptors, + // handed to web views via AllocateSRVSlot. + static constexpr UINT kExtraSrvSlots = 64; + private: IDXGISwapChain3 *_swapChain = nullptr; UINT _frameBufferCount = 0; @@ -23,6 +29,12 @@ namespace Framework::Graphics { ID3D12GraphicsCommandList *_commandList = nullptr; ID3D12CommandQueue *_commandQueue = nullptr; + UINT _srvDescriptorSize = 0; + UINT _srvHeapSize = 0; + std::vector _freeSrvSlots; + std::vector _srvSlotInUse; + mutable std::mutex _srvMutex; + struct FrameContext { ID3D12CommandAllocator *_commandAllocator = nullptr; ID3D12Resource *_mainRenderTargetResource = nullptr; @@ -40,6 +52,23 @@ namespace Framework::Graphics { void End(); int NumFramesInFlight() const; + // Bounded, shader-visible SRV slot pool shared with ImGui's heap (so handles + // double as ImTextureID). AllocateSRVSlot returns -1 when exhausted; the + // getters return a null handle for any out-of-range slot. + int AllocateSRVSlot(); + + // Frees an SRV slot from a given slot handle + void FreeSRVSlot(int slot); + + // Retrieves a CPU Descriptor handle from a given @p slot handle + D3D12_CPU_DESCRIPTOR_HANDLE GetSRVSlotCPUHandle(int slot) const; + + // Retrieves a GPU Descriptor handle from a given @p slot handle + D3D12_GPU_DESCRIPTOR_HANDLE GetSRVSlotGPUHandle(int slot) const; + + // Returns number of free SRV slots + size_t GetFreeSRVSlotCount() const; + // TODO: Backend not implemented yet void BeginDrawing() {} void EndDrawing() {}