feat(d3d12): 完善描述符堆延迟释放机制与FreeList栈式索引管理

- 添加完整的中文Doxygen注释文档
- 实现process_deferred_release()延迟释放处理
- 添加deferred_release模板函数和current_frame_index()
- 实现延迟释放队列和帧索引管理
- 详细说明FreeList栈式索引分配/释放算法
- 更新D3D12学习Wiki,添加延迟释放机制章节
This commit is contained in:
SpecialX
2026-03-30 16:58:35 +08:00
parent 54916b0ac6
commit b6c0211d6a
6 changed files with 1055 additions and 51 deletions

View File

@@ -1,7 +1,7 @@
#include "D3D12Resources.h"
#include "D3D12Core.h"
namespace XEngine::graphics::d3d12{
namespace XEngine::graphics::d3d12::core{
//////////// DESCRIPTOR HEAP ////////////
// 该类将被多个线程并发访问:资源创建(如纹理)与资源销毁/释放可能发生在不同线程,
// 因此需要同步机制保护内部数据结构
@@ -45,7 +45,8 @@ descriptor_heap::initialize(u32 capacity, bool is_shader_visible)
_size = 0;
for(u32 i = 0; i < capacity; ++i) _free_handles[i] = i;
DEBUG_OP(for(u32 i{0}; i<frame_buffer_count;++i) assert(_deferred_free_indices[i].empty()));
_descriptor_size = device->GetDescriptorHandleIncrementSize(_type);
_cpu_start = _heap->GetCPUDescriptorHandleForHeapStart();
_gpu_start = is_shader_visible
@@ -59,7 +60,39 @@ descriptor_heap::initialize(u32 capacity, bool is_shader_visible)
void
descriptor_heap::release()
{
assert(!_size);
core::deferred_release(_heap);
}
// 处理延迟释放
// 注意这里的free_handles对应的是一整块连续的内存,而不是对应的描述符句柄的索引index
// 描述符自生是记录了自己的地址(通过简单的计算可以得出偏移和索引)
// 所以释放后,只需要指向释放出来的索引index即可,这样下次新增时即可以
// 放在对应的空闲区域.
// 这一切都是应为freelist和内存是一对一对应的关系
// 延迟释放机制确保GPU完成使用后才回收描述符避免GPU仍在访问时重用
// 使用双缓冲/多帧缓冲机制,当前帧释放的描述符会在若干帧后安全回收
// _free_handles作为空闲索引栈_size指向栈顶回收的索引压入栈中供后续分配使用
void
descriptor_heap::process_deferred_release(u32 frame_index)
{
std::lock_guard lock(_mutex);
assert(frame_index < frame_buffer_count);
utl::vector<u32>& indices { _deferred_free_indices[frame_index] };
if(!indices.empty())
{
for(auto index : indices)
{
--_size;
_free_handles[_size] = index;
}
indices.clear();
}
}
descriptor_handle
descriptor_heap::allocate()
{
@@ -95,6 +128,9 @@ descriptor_heap::free(descriptor_handle handle)
const u32 index{ (u32)(handle.cpu.ptr - _cpu_start.ptr) / _descriptor_size };
assert(handle.index == index);
const u32 frame_index{ core::current_frame_index() };
_deferred_free_indices[frame_index].push_back(index);
core::set_deferred_release_flag();
handle = {};
}