Files
DX12/Engine/Graphics/Direct3D12/D3D12Resource.cpp
SpecialX 54916b0ac6 feat: implement descriptor heap with thread-safe allocation
D3D12 Resources:
- Add descriptor_handle struct with CPU/GPU handles
- Add descriptor_heap class for descriptor management
- Implement allocate() and free() methods
- Add mutex for thread-safe access
- Support all D3D12 descriptor heap types

D3D12 Core:
- Add device() function to expose main device
- Add release() template function for COM objects

Documentation:
- Add changelog for descriptor heap implementation
- Update D3D12 Wiki with descriptor heap section
- Mark descriptor heap task as completed
2026-03-30 14:04:34 +08:00

101 lines
3.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "D3D12Resources.h"
#include "D3D12Core.h"
namespace XEngine::graphics::d3d12{
//////////// DESCRIPTOR HEAP ////////////
// 该类将被多个线程并发访问:资源创建(如纹理)与资源销毁/释放可能发生在不同线程,
// 因此需要同步机制保护内部数据结构
bool
descriptor_heap::initialize(u32 capacity, bool is_shader_visible)
{
std::lock_guard lock(_mutex);
// 检查容量有效性必须大于0且不超过最大限制
assert(capacity && capacity <= D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2);
// 对于采样器描述符堆,需要额外检查容量是否超过最大采样器堆大小限制
assert(!(_type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER &&
capacity > D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE));
// 对于DSV和RTV他们在描述符堆的内存模型中本身就是GPU不可见的
if(_type == D3D12_DESCRIPTOR_HEAP_TYPE_DSV ||
_type == D3D12_DESCRIPTOR_HEAP_TYPE_RTV)
{
is_shader_visible = false;
}
// 应为这个功能将被调用多次,所以需要先释放之前的资源
release();
ID3D12Device *const device {core::device()};
assert(device);
D3D12_DESCRIPTOR_HEAP_DESC desc{};
desc.Flags = is_shader_visible
? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE
: D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NumDescriptors = capacity;
desc.Type = _type;
desc.NodeMask = 0;
HRESULT hr {S_OK};
DXCall(hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&_heap)));
if(FAILED(hr)) return false;
_free_handles = std::move(std::make_unique<u32[]>(capacity));
_capacity = capacity;
_size = 0;
for(u32 i = 0; i < capacity; ++i) _free_handles[i] = i;
_descriptor_size = device->GetDescriptorHandleIncrementSize(_type);
_cpu_start = _heap->GetCPUDescriptorHandleForHeapStart();
_gpu_start = is_shader_visible
? _heap->GetGPUDescriptorHandleForHeapStart()
: D3D12_GPU_DESCRIPTOR_HANDLE{0};
return true;
}
void
descriptor_heap::release()
{
}
descriptor_handle
descriptor_heap::allocate()
{
std::lock_guard lock(_mutex);
assert(_heap);
assert(_size < _capacity);
const u32 index { _free_handles[_size] };
const u32 offset { index * _descriptor_size };
++_size;
descriptor_handle handle{};
handle.cpu.ptr = _cpu_start.ptr + offset;
if(is_shader_visible())
{
handle.gpu.ptr = _gpu_start.ptr + offset;
}
DEBUG_OP(handle.container = this);
DEBUG_OP(handle.index = index);
return handle;
}
void
descriptor_heap::free(descriptor_handle handle)
{
if(!handle.is_valid()) return;
std::lock_guard lock(_mutex);
assert(_heap && _size);
assert(handle.container == this);
assert(handle.cpu.ptr >= _cpu_start.ptr);
assert((handle.cpu.ptr - _cpu_start.ptr) % _descriptor_size == 0);
assert(handle.index < _capacity);
const u32 index{ (u32)(handle.cpu.ptr - _cpu_start.ptr) / _descriptor_size };
assert(handle.index == index);
handle = {};
}
} //XEngine::graphics::d3d12