#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(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