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

5.5 KiB
Raw Permalink Blame History

变更记录:描述符堆实现

提交日期: 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 结构

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 类

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. 分配算法

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. 线程安全

std::mutex _mutex;  // 保护并发访问

// 使用 lock_guard 保护
std::lock_guard lock(_mutex);

描述符堆可能被多个线程并发访问(资源创建/销毁),需要互斥锁保护。


D3D12Core 扩展

新增 device() 函数

// D3D12Core.h
ID3D12Device *const device();

// D3D12Core.cpp
ID3D12Device *const device()
{
    return main_device;
}

提供对 D3D12 设备的访问,用于创建描述符堆等资源。

新增 release 模板函数

template<typename T>
constexpr void release(T*& resource)
{
    if(resource)
    {
        resource->Release();
        resource = nullptr;
    }
}

通用的 COM 对象释放模板,避免代码重复。


使用示例

// 创建描述符堆
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
  • 实现交换链
  • 实现渲染目标视图

相关文档