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
381 lines
9.8 KiB
Markdown
381 lines
9.8 KiB
Markdown
# 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. DXGI(DirectX Graphics Infrastructure)
|
||
|
||
### 2.1 DXGI 的作用
|
||
|
||
DXGI 是 DirectX 与图形硬件之间的抽象层,负责:
|
||
|
||
- 枚举显示适配器
|
||
- 管理显示输出
|
||
- 创建交换链
|
||
- 处理全屏/窗口切换
|
||
|
||
### 2.2 关键接口
|
||
|
||
```cpp
|
||
IDXGIFactory6 // DXGI 工厂,创建其他 DXGI 对象
|
||
IDXGIAdapter4 // 代表物理 GPU 适配器
|
||
IDXGIOutput // 代表显示器输出
|
||
IDXGISwapChain // 交换链接口
|
||
```
|
||
|
||
### 2.3 项目中的使用
|
||
|
||
在 [D3D12CommonHeader.h](file:///d:/AllWX/AllC/FeatureExtractDemo/Engine/Graphics/Direct3D12/D3D12CommonHeader.h) 中引入了 `dxgi_6.h`:
|
||
|
||
```cpp
|
||
#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](file:///d:/AllWX/AllC/FeatureExtractDemo/Engine/Graphics/Direct3D12/D3D12Core.cpp) 已实现完整的设备初始化:
|
||
|
||
```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 调试宏
|
||
|
||
项目定义了两个重要的调试宏:
|
||
|
||
```cpp
|
||
// 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?
|
||
|
||
COM(Component Object Model)是微软的组件对象模型,D3D12 对象都是 COM 对象。
|
||
|
||
### 4.2 智能指针
|
||
|
||
项目使用 WRL 库的 `ComPtr` 管理 COM 对象生命周期:
|
||
|
||
```cpp
|
||
#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 接口绑定机制
|
||
|
||
```cpp
|
||
// 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 类
|
||
|
||
项目实现了命令队列管理类,支持多帧缓冲渲染:
|
||
|
||
```cpp
|
||
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 多帧缓冲原理
|
||
|
||
```cpp
|
||
constexpr u32 frame_buffer_count{ 3 };
|
||
```
|
||
|
||
采用三重缓冲设计:
|
||
- CPU 提前录制命令
|
||
- GPU 异步执行
|
||
- 最大化硬件利用率
|
||
|
||
### 6.3 帧索引轮转
|
||
|
||
```cpp
|
||
_frame_index = (_frame_index + 1) % frame_buffer_count;
|
||
```
|
||
|
||
环形缓冲区管理帧资源,确保 CPU 不会超前 GPU 超过 3 帧。
|
||
|
||
### 6.4 Fence 同步机制
|
||
|
||
项目实现了 Fence(围栏)同步,确保 CPU-GPU 帧同步:
|
||
|
||
```cpp
|
||
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 发送信号
|
||
|
||
```cpp
|
||
// 帧结束信号
|
||
++_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 结构
|
||
|
||
项目封装了描述符句柄:
|
||
|
||
```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; }
|
||
};
|
||
```
|
||
|
||
### 7.4 descriptor_heap 类
|
||
|
||
```cpp
|
||
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 线程安全
|
||
|
||
描述符堆可能被多线程并发访问,使用互斥锁保护:
|
||
|
||
```cpp
|
||
std::lock_guard lock(_mutex);
|
||
```
|
||
|
||
## 8. 渲染表面与窗口
|
||
|
||
### 8.1 render_surface 结构
|
||
|
||
```cpp
|
||
struct render_surface {
|
||
platform::window window{}; // 平台窗口
|
||
surface surface{}; // 渲染表面
|
||
};
|
||
```
|
||
|
||
### 8.2 多窗口支持
|
||
|
||
TestRenderer 测试展示了多窗口渲染:
|
||
|
||
```cpp
|
||
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:
|
||
|
||
```cpp
|
||
if (wparam == VK_RETURN && (HIWORD(lparam) & KF_ALTDOWN)) {
|
||
win.set_fullscreen(!win.is_fullscreen());
|
||
}
|
||
```
|
||
|
||
## 9. 后续学习路径
|
||
|
||
### 9.1 基础阶段
|
||
|
||
- [x] 完成设备创建和适配器枚举
|
||
- [x] 创建命令队列和命令列表
|
||
- [x] 描述符堆管理
|
||
- [ ] 实现交换链和后台缓冲区
|
||
- [ ] 渲染第一个三角形
|
||
|
||
### 9.2 进阶阶段
|
||
|
||
- [ ] 根签名和管线状态对象
|
||
- [ ] 资源屏障和同步
|
||
- [ ] 常量缓冲区和着色器资源
|
||
|
||
### 9.3 高级阶段
|
||
|
||
- [ ] 多线程渲染
|
||
- [ ] 资源绑定策略
|
||
- [ ] 动态资源管理
|
||
- [ ] 性能优化
|
||
|
||
## 10. 参考资源
|
||
|
||
### 10.1 官方文档
|
||
|
||
- [Microsoft D3D12 文档](https://docs.microsoft.com/en-us/windows/win32/direct3d12/direct3d-12-graphics)
|
||
- [DXGI 文档](https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dx-graphics-dxgi)
|
||
|
||
### 10.2 推荐书籍
|
||
|
||
- 《Introduction to 3D Game Programming with DirectX 12》
|
||
- 《Real-Time 3D Rendering with DirectX and HLSL》
|
||
|
||
### 10.3 项目相关文档
|
||
|
||
- [Graphics渲染架构分析](./Graphics渲染架构分析.md)
|
||
- [项目约定规范](./项目约定规范.md)
|