feat: implement command queue with multi-frame buffering

D3D12 Core:
- Add d3d12_command class for command queue management
- Support Direct/Compute/Copy command queue types
- Implement multi-frame buffering (frame_buffer_count=3)
- Add begin_frame/end_frame rendering cycle
- Add NAME_D3D12_OBJECT_INDEXED macro

Platform Interface:
- Add render function pointer to platform_interface
- Implement render() in Renderer

Documentation:
- Add changelog for command queue implementation
- Update D3D12 Wiki with multi-frame buffering section
- Mark command queue task as completed
This commit is contained in:
SpecialX
2026-03-27 12:30:38 +08:00
parent 3fdc774f3f
commit 7da17ccadd
11 changed files with 406 additions and 23 deletions

View File

@@ -0,0 +1,135 @@
# 变更记录:命令队列与多帧缓冲
**提交日期**: 2026-03-26
**提交哈希**: `26e18bd`
**变更类型**: 功能实现
---
## 变更概述
本次提交实现了 D3D12 命令队列管理类 `d3d12_command`,支持多帧缓冲渲染架构,实现了 CPU-GPU 并行渲染的基础设施。
## 修改文件
### Engine/Graphics/Direct3D12/
| 文件 | 变更说明 |
|------|----------|
| `D3D12Core.cpp` | 添加 `d3d12_command` 类,实现命令队列和命令列表管理 |
| `D3D12Core.h` | 添加 `render()` 函数声明 |
| `D3D12CommonHeader.h` | 添加 `frame_buffer_count` 常量和 `NAME_D3D12_OBJECT_INDEXED` 宏 |
### Engine/Graphics/
| 文件 | 变更说明 |
|------|----------|
| `GraphicsPlatformInterface.h` | 添加 `render` 函数指针 |
| `Renderer.h` | 添加 `render()` 函数声明 |
| `Renderer.cpp` | 实现 `render()` 函数 |
---
## 技术要点
### 1. 多帧缓冲架构
```cpp
constexpr u32 frame_buffer_count{ 3 };
```
采用三重缓冲设计,允许 CPU 提前录制命令GPU 异步执行,最大化硬件利用率。
### 2. d3d12_command 类
```cpp
class d3d12_command
{
// 创建命令队列(支持 Direct/Compute/Copy 三种类型)
// 为每帧创建独立的命令分配器
// 创建命令列表
void begin_frame(); // 等待帧完成,重置分配器和命令列表
void end_frame(); // 关闭命令列表,提交执行
};
```
### 3. 帧索引轮转机制
```cpp
_frame_index = (_frame_index + 1) % frame_buffer_count;
```
环形缓冲区管理帧资源,确保 CPU 不会超前 GPU 超过 3 帧。
### 4. command_frame 结构
```cpp
struct command_frame
{
ID3D12CommandAllocator* cmd_allocator{ nullptr };
void wait(); // 等待 GPU 完成该帧
void release(); // 释放资源
};
```
每帧独立的命令分配器,避免 GPU 执行期间重置冲突。
### 5. 命名调试宏
```cpp
#define NAME_D3D12_OBJECT_INDEXED(obj, n, name) \
obj->SetName(full_name); ...
```
支持为多个同类对象设置带索引的调试名称。
---
## 渲染流程
```
render()
├─► begin_frame()
│ ├─► 等待当前帧 GPU 完成
│ ├─► 重置命令分配器
│ └─► 重置命令列表
└─► end_frame()
├─► 关闭命令列表
├─► 提交命令列表执行
└─► 递增帧索引
```
---
## 设计原理
### 为什么需要多帧缓冲?
1. **CPU-GPU 并行性**: 单缓冲模式下 CPU 必须等待 GPU 完成,多帧缓冲允许 CPU 提前录制 N 帧
2. **命令分配器冲突解决**: D3D12 中命令分配器在 GPU 执行期间不能被重置,每帧独立分配器解决此问题
3. **帧时序稳定性**: 缓冲 N 帧可平滑帧率波动
### 命令列表创建后立即关闭
```cpp
DXCall(_cmd_list->Close());
```
新创建的命令列表处于"录制打开"状态,立即关闭使其进入可提交状态,这是一种防御性编程。
---
## 后续工作
- [ ] 实现 Fence 同步机制
- [ ] 实现交换链
- [ ] 实现描述符堆
---
## 相关文档
- [D3D12学习Wiki](../wiki/D3D12学习Wiki.md)

View File

@@ -16,6 +16,7 @@ changelogs/
| 日期 | 提交 | 变更内容 |
|------|------|----------|
| 2026-03-26 | [命令队列与多帧缓冲](./2026-03/20260326-d3d12-command-queue.md) | D3D12 命令队列和多帧渲染架构 |
| 2026-03-26 | [D3D12设备初始化](./2026-03/20260326-d3d12-device-init.md) | D3D12 设备创建与调试层实现 |
| 2026-03-26 | [Graphics模块](./2026-03/20260326-d3d12-foundation.md) | Graphics 模块与 D3D12 后端框架 |
| 2026-03-19 | [DX12初始框架](./2026-03/20260326-dx12-initial.md) | 初始 DX12 基础框架 |