Files
FlaxEngine/Source/Engine/GraphicsDevice/DirectX/DX12/DescriptorHeapDX12.cpp
2024-02-26 19:00:48 +01:00

244 lines
6.9 KiB
C++

// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX12
#include "DescriptorHeapDX12.h"
#include "GPUDeviceDX12.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapWithSlotsDX12::Slot::CPU() const
{
ASSERT_LOW_LAYER(Heap);
return Heap->CPU(Index);
}
D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapWithSlotsDX12::Slot::GPU() const
{
ASSERT_LOW_LAYER(Heap);
return Heap->GPU(Index);
}
void DescriptorHeapWithSlotsDX12::Slot::CreateSRV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_SHADER_RESOURCE_VIEW_DESC* desc)
{
if (Heap == nullptr)
device->Heap_CBV_SRV_UAV.AllocateSlot(Heap, Index);
device->GetDevice()->CreateShaderResourceView(resource, desc, CPU());
}
void DescriptorHeapWithSlotsDX12::Slot::CreateRTV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_RENDER_TARGET_VIEW_DESC* desc)
{
if (Heap == nullptr)
device->Heap_RTV.AllocateSlot(Heap, Index);
device->GetDevice()->CreateRenderTargetView(resource, desc, CPU());
}
void DescriptorHeapWithSlotsDX12::Slot::CreateDSV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_DEPTH_STENCIL_VIEW_DESC* desc)
{
if (Heap == nullptr)
device->Heap_DSV.AllocateSlot(Heap, Index);
device->GetDevice()->CreateDepthStencilView(resource, desc, CPU());
}
void DescriptorHeapWithSlotsDX12::Slot::CreateUAV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_UNORDERED_ACCESS_VIEW_DESC* desc, ID3D12Resource* counterResource)
{
if (Heap == nullptr)
device->Heap_CBV_SRV_UAV.AllocateSlot(Heap, Index);
device->GetDevice()->CreateUnorderedAccessView(resource, counterResource, desc, CPU());
}
void DescriptorHeapWithSlotsDX12::Slot::Release()
{
if (Heap)
{
Heap->ReleaseSlot(Index);
Heap = nullptr;
}
}
DescriptorHeapWithSlotsDX12::DescriptorHeapWithSlotsDX12(GPUDeviceDX12* device)
: _device(device)
, _heap(nullptr)
, _descriptorsCount(0)
{
}
bool DescriptorHeapWithSlotsDX12::Create(D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 descriptorsCount, bool shaderVisible)
{
// Create description
D3D12_DESCRIPTOR_HEAP_DESC desc;
desc.Type = type;
desc.NumDescriptors = descriptorsCount;
desc.Flags = shaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 0;
// Create heap
const HRESULT result = _device->GetDevice()->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), reinterpret_cast<void**>(&_heap));
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Setup
_type = type;
_shaderVisible = shaderVisible;
_descriptorsCount = descriptorsCount;
_beginCPU = _heap->GetCPUDescriptorHandleForHeapStart();
if (shaderVisible)
_beginGPU = _heap->GetGPUDescriptorHandleForHeapStart();
else
_beginGPU.ptr = 0;
_incrementSize = _device->GetDevice()->GetDescriptorHandleIncrementSize(desc.Type);
// Setup usage cache
_usage.Resize(static_cast<int32>(_descriptorsCount / 32), false);
Platform::MemorySet(_usage.Get(), _usage.Count() * sizeof(uint32), 0);
_memoryUsage = 1;
return false;
}
bool DescriptorHeapWithSlotsDX12::TryToGetUnusedSlot(uint32& index)
{
for (int32 i = 0; i < _usage.Count(); i++)
{
uint32& value = _usage[i];
if (value != MAX_uint32)
{
// TODO: make it better?
for (int32 bit = 0; bit < 32; bit++)
{
const uint32 mask = 1 << bit;
if ((value & mask) == 0)
{
// Found
index = i * 32 + bit;
value |= mask;
return true;
}
}
}
}
return false;
}
void DescriptorHeapWithSlotsDX12::ReleaseSlot(uint32 index)
{
uint32& value = _usage[index / 32];
const uint32 mask = 1 << (index & 31);
ASSERT_LOW_LAYER((value & mask) == mask);
value &= ~mask;
}
GPUResourceType DescriptorHeapWithSlotsDX12::GetResourceType() const
{
return GPUResourceType::Descriptor;
}
DescriptorHeapPoolDX12::DescriptorHeapPoolDX12(GPUDeviceDX12* device, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 descriptorsCountPerHeap, bool shaderVisible)
: _device(device)
, _type(type)
, _descriptorsCountPerHeap(descriptorsCountPerHeap)
, _shaderVisible(shaderVisible)
{
}
void DescriptorHeapPoolDX12::AllocateSlot(DescriptorHeapWithSlotsDX12*& heap, uint32& slot)
{
for (int32 i = 0; i < _heaps.Count(); i++)
{
if (_heaps[i]->TryToGetUnusedSlot(slot))
{
heap = _heaps[i];
return;
}
}
heap = New<DescriptorHeapWithSlotsDX12>(_device);
if (heap->Create(_type, _descriptorsCountPerHeap, _shaderVisible))
{
Platform::Fatal(TEXT("Failed to allocate descriptor heap."));
}
_heaps.Add(heap);
heap->TryToGetUnusedSlot(slot);
}
void DescriptorHeapPoolDX12::ReleaseGPU()
{
for (auto heap : _heaps)
{
heap->ReleaseGPU();
Delete(heap);
}
_heaps.Clear();
}
void DescriptorHeapWithSlotsDX12::OnReleaseGPU()
{
_usage.SetCapacity(0, false);
DX_SAFE_RELEASE_CHECK(_heap, 0);
_descriptorsCount = 0;
}
DescriptorHeapRingBufferDX12::DescriptorHeapRingBufferDX12(GPUDeviceDX12* device, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 descriptorsCount, bool shaderVisible)
: _device(device)
, _heap(nullptr)
, _type(type)
, _descriptorsCount(descriptorsCount)
, _shaderVisible(shaderVisible)
{
}
bool DescriptorHeapRingBufferDX12::Init()
{
// Create heap
D3D12_DESCRIPTOR_HEAP_DESC desc;
desc.Type = _type;
desc.NumDescriptors = _descriptorsCount;
desc.Flags = _shaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 0;
const HRESULT result = _device->GetDevice()->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&_heap));
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
// Setup
_firstFree = 0;
_beginCPU = _heap->GetCPUDescriptorHandleForHeapStart();
if (_shaderVisible)
_beginGPU = _heap->GetGPUDescriptorHandleForHeapStart();
else
_beginGPU.ptr = 0;
_incrementSize = _device->GetDevice()->GetDescriptorHandleIncrementSize(desc.Type);
_memoryUsage = 1;
return false;
}
DescriptorHeapRingBufferDX12::Allocation DescriptorHeapRingBufferDX12::AllocateTable(uint32 numDesc)
{
Allocation result;
// Move the ring buffer pointer
uint32 index = _firstFree;
_firstFree += numDesc;
// Check for overflow
if (_firstFree >= _descriptorsCount)
{
// Move to the begin
index = 0;
_firstFree = numDesc;
}
// Set pointers
result.CPU.ptr = _beginCPU.ptr + static_cast<SIZE_T>(index * _incrementSize);
result.GPU.ptr = _shaderVisible ? _beginGPU.ptr + index * _incrementSize : 0;
return result;
}
void DescriptorHeapRingBufferDX12::OnReleaseGPU()
{
DX_SAFE_RELEASE_CHECK(_heap, 0);
_firstFree = 0;
}
#endif