Files
DX12/docs/wiki/D3D12学习Wiki.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

9.8 KiB
Raw Blame History

Direct3D 12 学习 Wiki

概述

本文档是项目中 Direct3D 12 学习的基础知识汇总,帮助理解 D3D12 的核心概念和项目中的实现方式。

1. D3D12 核心概念

1.1 什么是 Direct3D 12

Direct3D 12 是微软推出的底层图形 API相比 D3D11它提供了

  • 更底层的硬件控制:开发者可以更精细地控制 GPU
  • 更低的 CPU 开销:减少驱动程序的 CPU 时间
  • 更好的多线程支持:支持多线程命令录制
  • 显式的资源管理:开发者完全控制资源生命周期

1.2 核心组件

组件 说明
Device设备 代表物理 GPU 的逻辑抽象,用于创建所有 D3D12 对象
Command Queue命令队列 GPU 执行命令的队列
Command List命令列表 记录 GPU 命令的容器
Swap Chain交换链 管理后台缓冲区和前台显示
Descriptor Heap描述符堆 存储资源描述符(视图)的内存池
Root Signature根签名 定义着色器如何访问资源

2. DXGIDirectX Graphics Infrastructure

2.1 DXGI 的作用

DXGI 是 DirectX 与图形硬件之间的抽象层,负责:

  • 枚举显示适配器
  • 管理显示输出
  • 创建交换链
  • 处理全屏/窗口切换

2.2 关键接口

IDXGIFactory6    // DXGI 工厂,创建其他 DXGI 对象
IDXGIAdapter4    // 代表物理 GPU 适配器
IDXGIOutput      // 代表显示器输出
IDXGISwapChain   // 交换链接口

2.3 项目中的使用

D3D12CommonHeader.h 中引入了 dxgi_6.h

#include <dxgi_6.h>  // DXGI 6.0,支持枚举 GPU、查询显示模式

3. D3D12 初始化流程

3.1 标准初始化步骤

1. 创建 DXGI Factory
       ↓
2. 枚举并选择适配器GPU
       ↓
3. 创建 D3D12 Device
       ↓
4. 创建命令队列
       ↓
5. 创建交换链
       ↓
6. 创建描述符堆
       ↓
7. 创建命令分配器和命令列表
       ↓
8. 创建同步对象Fence

3.2 项目当前状态

D3D12Core.cpp 已实现完整的设备初始化:

namespace {
    ID3D12Device8* main_device{ nullptr };
    IDXGIFactory7* dxgi_factory{ nullptr };
}

bool initialize() {
    // 1. 启用调试层 (DEBUG 模式)
    // 2. 创建 DXGI 工厂
    // 3. 枚举并选择 GPU 适配器
    // 4. 获取最高特性级别
    // 5. 创建 D3D12 设备
    // 6. 配置信息队列 (DEBUG 模式)
}

3.3 调试宏

项目定义了两个重要的调试宏:

// DXCall - 检查 HRESULT 并断点
#define DXCall(x) if(FAILED(x)) { ... __debugbreak(); }

// NAME_D3D12_OBJECT - 为对象设置调试名称
#define NAME_D3D12_OBJECT(obj, name) obj->SetName(name);

4. COM 对象管理

4.1 什么是 COM

COMComponent Object Model是微软的组件对象模型D3D12 对象都是 COM 对象。

4.2 智能指针

项目使用 WRL 库的 ComPtr 管理 COM 对象生命周期:

#include <wrl.h>  // 提供 Microsoft::WRL::ComPtr

// 使用示例
Microsoft::WRL::ComPtr<ID3D12Device8> device;

4.3 ComPtr 的优势

  • 自动引用计数:无需手动 AddRef/Release
  • 异常安全:即使发生异常也能正确释放
  • 代码简洁:减少内存管理代码

5. 平台抽象设计

5.1 设计理念

项目采用平台抽象层设计,将图形 API 的差异封装在统一接口后:

┌────────────────────────────────────┐
│         上层渲染代码                │
│   graphics::initialize(platform)   │
└──────────────┬─────────────────────┘
               │
               ▼
┌────────────────────────────────────┐
│      platform_interface            │
│   - initialize()                   │
│   - shutdown()                     │
└──────────────┬─────────────────────┘
               │
    ┌──────────┼──────────┐
    ▼          ▼          ▼
┌───────┐  ┌───────┐  ┌───────┐
│ D3D12 │  │Vulkan │  │OpenGL │
└───────┘  └───────┘  └───────┘

5.2 接口绑定机制

// D3D12Interface.cpp
void get_platform_interface(platform_interface& pi) {
    pi.initialize = core::initialize;
    pi.shutdown = core::shutdown;
    pi.render = core::render;
}

这种设计允许:

  • 编译时或运行时切换图形后端
  • 各后端独立开发和测试
  • 上层代码与具体 API 解耦

6. 命令队列与多帧缓冲

6.1 d3d12_command 类

项目实现了命令队列管理类,支持多帧缓冲渲染:

class d3d12_command
{
    void begin_frame();  // 等待帧完成,重置分配器和命令列表
    void end_frame();    // 关闭命令列表,提交执行
private:
    ID3D12CommandQueue* _cmd_queue;
    ID3D12GraphicsCommandList6* _cmd_list;
    command_frame _cmd_frames[frame_buffer_count];
    u32 _frame_index;
};

6.2 多帧缓冲原理

constexpr u32 frame_buffer_count{ 3 };

采用三重缓冲设计:

  • CPU 提前录制命令
  • GPU 异步执行
  • 最大化硬件利用率

6.3 帧索引轮转

_frame_index = (_frame_index + 1) % frame_buffer_count;

环形缓冲区管理帧资源,确保 CPU 不会超前 GPU 超过 3 帧。

6.4 Fence 同步机制

项目实现了 Fence围栏同步确保 CPU-GPU 帧同步:

struct command_frame
{
    ID3D12CommandAllocator* cmd_allocator{ nullptr };
    u64 fence_value{ 0 };  // 该帧的围栏值

    void wait(HANDLE fence_event, ID3D12Fence1* fence);
};

同步流程

  1. begin_frame() - 检查 GPU 是否完成当前帧,未完成则等待
  2. end_frame() - 递增围栏值,向 GPU 发送信号
// 帧结束信号
++_fence_value;
_cmd_frames[_frame_index].fence_value = _fence_value;
_cmd_queue->Signal(_fence, _fence_value);

围栏值溢出64位无符号整数每秒1000帧需要5.8亿年才回绕,无需担心。

7. 描述符堆

7.1 什么是描述符堆?

描述符堆是一块连续内存用于存储描述符Descriptor。描述符是告诉 GPU 如何访问资源的数据结构。

7.2 描述符堆类型

类型 用途 着色器可见
CBV_SRV_UAV 常量缓冲区、着色器资源、无序访问 可选
SAMPLER 采样器 可选
RTV 渲染目标视图
DSV 深度模板视图

7.3 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; }
};

7.4 descriptor_heap 类

class descriptor_heap
{
    bool initialize(u32 capacity, bool is_shader_visible);
    descriptor_handle allocate();  // 分配描述符
    void free(descriptor_handle);  // 释放描述符
    
private:
    ID3D12DescriptorHeap* _heap;
    std::unique_ptr<u32[]> _free_handles{};  // 空闲索引池
    std::mutex _mutex;  // 线程安全
};

7.5 内存模型

描述符堆内存布局:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │...│   │   │   │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
↑
_cpu_start / _gpu_start

_free_handles[] = [0, 1, 2, 3, ...]  // 空闲索引池

7.6 线程安全

描述符堆可能被多线程并发访问,使用互斥锁保护:

std::lock_guard lock(_mutex);

8. 渲染表面与窗口

8.1 render_surface 结构

struct render_surface {
    platform::window window{};  // 平台窗口
    surface surface{};          // 渲染表面
};

8.2 多窗口支持

TestRenderer 测试展示了多窗口渲染:

graphics::render_surface _surfaces[4];  // 支持 4 个窗口

// 创建多个渲染表面
for (u32 i{0}; i < _countof(_surfaces); ++i) {
    create_render_surface(_surfaces[i], info[i]);
}

8.3 全屏切换

通过 WM_SYSCHAR 消息处理 Alt+Enter

if (wparam == VK_RETURN && (HIWORD(lparam) & KF_ALTDOWN)) {
    win.set_fullscreen(!win.is_fullscreen());
}

9. 后续学习路径

9.1 基础阶段

  • 完成设备创建和适配器枚举
  • 创建命令队列和命令列表
  • 描述符堆管理
  • 实现交换链和后台缓冲区
  • 渲染第一个三角形

9.2 进阶阶段

  • 根签名和管线状态对象
  • 资源屏障和同步
  • 常量缓冲区和着色器资源

9.3 高级阶段

  • 多线程渲染
  • 资源绑定策略
  • 动态资源管理
  • 性能优化

10. 参考资源

10.1 官方文档

10.2 推荐书籍

  • 《Introduction to 3D Game Programming with DirectX 12》
  • 《Real-Time 3D Rendering with DirectX and HLSL》

10.3 项目相关文档