Files
DX12/docs/changelogs/2026-03/20260330-d3d12-descriptor-heap.md
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

213 lines
5.5 KiB
Markdown
Raw Permalink 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.
# 变更记录:描述符堆实现
**提交日期**: 2026-03-30
**提交哈希**: `a03c544`
**变更类型**: 功能实现
---
## 变更概述
本次提交实现了 D3D12 描述符堆Descriptor Heap管理类提供描述符的分配和释放功能支持多线程安全访问。
## 新增文件
### Engine/Graphics/Direct3D12/
| 文件 | 说明 |
|------|------|
| `D3D12Resources.h` | 描述符句柄和描述符堆类定义 |
| `D3D12Resource.cpp` | 描述符堆实现 |
## 修改文件
| 文件 | 变更说明 |
|------|----------|
| `D3D12Core.h` | 添加 `device()` 函数声明和 `release` 模板函数 |
| `D3D12Core.cpp` | 添加 `device()` 函数实现 |
| `D3D12CommonHeader.h` | 添加 `<mutex>` 头文件 |
---
## 技术要点
### 1. descriptor_handle 结构
```cpp
struct descriptor_handle
{
D3D12_CPU_DESCRIPTOR_HANDLE cpu{}; // CPU 句柄
D3D12_GPU_DESCRIPTOR_HANDLE gpu{}; // GPU 句柄(着色器可见时有效)
constexpr bool is_valid() const { return cpu.ptr != 0; }
constexpr bool is_shader_visible() const { return gpu.ptr != 0; }
};
```
**设计要点**
- 封装 CPU 和 GPU 双句柄
- 提供有效性检查方法
- DEBUG 模式下记录容器和索引用于调试
### 2. descriptor_heap 类
```cpp
class descriptor_heap
{
public:
explicit descriptor_heap(const D3D12_DESCRIPTOR_HEAP_TYPE type);
bool initialize(u32 capacity, bool is_shader_visible);
void release();
descriptor_handle allocate(); // 分配描述符
void free(descriptor_handle handle); // 释放描述符
// 访问器
constexpr ID3D12DescriptorHeap* heap() const;
constexpr D3D12_CPU_DESCRIPTOR_HANDLE cpu_start() const;
constexpr D3D12_GPU_DESCRIPTOR_HANDLE gpu_start() const;
constexpr bool is_shader_visible() const;
private:
ID3D12DescriptorHeap* _heap;
D3D12_CPU_DESCRIPTOR_HANDLE _cpu_start{};
D3D12_GPU_DESCRIPTOR_HANDLE _gpu_start{};
std::unique_ptr<u32[]> _free_handles{}; // 空闲句柄池
std::mutex _mutex; // 线程安全
u32 _capacity{0};
u32 _size{0};
u32 _descriptor_size{0};
const D3D12_DESCRIPTOR_HEAP_TYPE _type;
};
```
### 3. 描述符堆类型
| 类型 | 用途 | 着色器可见 |
|------|------|------------|
| `D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV` | 常量缓冲区、着色器资源、无序访问 | 可选 |
| `D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER` | 采样器 | 可选 |
| `D3D12_DESCRIPTOR_HEAP_TYPE_RTV` | 渲染目标视图 | 否 |
| `D3D12_DESCRIPTOR_HEAP_TYPE_DSV` | 深度模板视图 | 否 |
### 4. 内存模型
```
┌─────────────────────────────────────────────────────┐
│ Shader-Visible 描述符堆 (GPU 显存) │
│ ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ │
│ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │...│ │ │ │ │
│ └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ │
│ ↑ │
│ _cpu_start / _gpu_start │
└─────────────────────────────────────────────────────┘
_free_handles[] = [0, 1, 2, 3, 4, 5, ...] // 空闲索引池
_size = 0 // 已分配数量
```
### 5. 分配算法
```cpp
descriptor_handle allocate()
{
std::lock_guard lock(_mutex); // 线程安全
const u32 index = _free_handles[_size]; // 取空闲索引
const u32 offset = index * _descriptor_size; // 计算偏移
++_size; // 递增已分配数量
descriptor_handle handle{};
handle.cpu.ptr = _cpu_start.ptr + offset; // CPU 句柄
if(is_shader_visible())
handle.gpu.ptr = _gpu_start.ptr + offset; // GPU 句柄
return handle;
}
```
### 6. 线程安全
```cpp
std::mutex _mutex; // 保护并发访问
// 使用 lock_guard 保护
std::lock_guard lock(_mutex);
```
描述符堆可能被多个线程并发访问(资源创建/销毁),需要互斥锁保护。
---
## D3D12Core 扩展
### 新增 device() 函数
```cpp
// D3D12Core.h
ID3D12Device *const device();
// D3D12Core.cpp
ID3D12Device *const device()
{
return main_device;
}
```
提供对 D3D12 设备的访问,用于创建描述符堆等资源。
### 新增 release 模板函数
```cpp
template<typename T>
constexpr void release(T*& resource)
{
if(resource)
{
resource->Release();
resource = nullptr;
}
}
```
通用的 COM 对象释放模板,避免代码重复。
---
## 使用示例
```cpp
// 创建描述符堆
descriptor_heap cbv_srv_heap{D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV};
cbv_srv_heap.initialize(100, true); // 100个描述符着色器可见
// 分配描述符
descriptor_handle handle = cbv_srv_heap.allocate();
// 创建视图
device->CreateShaderResourceView(texture, &srvDesc, handle.cpu);
// 绑定到管线
ID3D12DescriptorHeap* heaps[] = { cbv_srv_heap.heap() };
cmdList->SetDescriptorHeaps(1, heaps);
cmdList->SetGraphicsRootDescriptorTable(0, handle.gpu);
// 释放描述符
cbv_srv_heap.free(handle);
```
---
## 后续工作
- [ ] 实现资源类Texture, Buffer
- [ ] 实现交换链
- [ ] 实现渲染目标视图
---
## 相关文档
- [D3D12学习Wiki](../wiki/D3D12学习Wiki.md)