# 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.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 // 提供 Microsoft::WRL::ComPtr // 使用示例 Microsoft::WRL::ComPtr 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 _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)