Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion code/framework/src/graphics/backend/d3d12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -140,4 +151,59 @@ namespace Framework::Graphics {
int D3D12Backend::NumFramesInFlight() const {
return _frameBufferCount;
}

int D3D12Backend::AllocateSRVSlot() {
std::lock_guard<std::mutex> 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<int>(slot);
}

void D3D12Backend::FreeSRVSlot(int slot) {
std::lock_guard<std::mutex> 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<int>(_frameBufferCount) || slot >= static_cast<int>(_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<UINT>(slot));
}

D3D12_CPU_DESCRIPTOR_HANDLE D3D12Backend::GetSRVSlotCPUHandle(int slot) const {
if (!_srvHeap || slot < 0 || slot >= static_cast<int>(_srvHeapSize)) {
return {};
}
auto handle = _srvHeap->GetCPUDescriptorHandleForHeapStart();
handle.ptr += static_cast<SIZE_T>(slot) * _srvDescriptorSize;
return handle;
}

D3D12_GPU_DESCRIPTOR_HANDLE D3D12Backend::GetSRVSlotGPUHandle(int slot) const {
if (!_srvHeap || slot < 0 || slot >= static_cast<int>(_srvHeapSize)) {
return {};
}
auto handle = _srvHeap->GetGPUDescriptorHandleForHeapStart();
handle.ptr += static_cast<UINT64>(slot) * _srvDescriptorSize;
return handle;
}

size_t D3D12Backend::GetFreeSRVSlotCount() const {
std::lock_guard<std::mutex> lock(_srvMutex);
return _freeSrvSlots.size();
}
} // namespace Framework::Graphics
29 changes: 29 additions & 0 deletions code/framework/src/graphics/backend/d3d12.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@
#include "backend.h"

#include <memory>
#include <mutex>
#include <vector>

namespace Framework::Graphics {
class D3D12Backend: public Backend<ID3D12Device *, ID3D12DeviceContext *, IDXGISwapChain3 *, ID3D12CommandQueue *> {
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;
Expand All @@ -23,6 +29,12 @@ namespace Framework::Graphics {
ID3D12GraphicsCommandList *_commandList = nullptr;
ID3D12CommandQueue *_commandQueue = nullptr;

UINT _srvDescriptorSize = 0;
UINT _srvHeapSize = 0;
std::vector<UINT> _freeSrvSlots;
std::vector<bool> _srvSlotInUse;
mutable std::mutex _srvMutex;

struct FrameContext {
ID3D12CommandAllocator *_commandAllocator = nullptr;
ID3D12Resource *_mainRenderTargetResource = nullptr;
Expand All @@ -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() {}
Expand Down