Files
DX12/docs/changelogs/2026-03/20260326-d3d12-command-queue.md
SpecialX 7da17ccadd 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
2026-03-27 12:31:12 +08:00

3.1 KiB
Raw Permalink Blame History

变更记录:命令队列与多帧缓冲

提交日期: 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. 多帧缓冲架构

constexpr u32 frame_buffer_count{ 3 };

采用三重缓冲设计,允许 CPU 提前录制命令GPU 异步执行,最大化硬件利用率。

2. d3d12_command 类

class d3d12_command
{
    // 创建命令队列(支持 Direct/Compute/Copy 三种类型)
    // 为每帧创建独立的命令分配器
    // 创建命令列表
    
    void begin_frame();  // 等待帧完成,重置分配器和命令列表
    void end_frame();    // 关闭命令列表,提交执行
};

3. 帧索引轮转机制

_frame_index = (_frame_index + 1) % frame_buffer_count;

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

4. command_frame 结构

struct command_frame
{
    ID3D12CommandAllocator* cmd_allocator{ nullptr };
    void wait();   // 等待 GPU 完成该帧
    void release(); // 释放资源
};

每帧独立的命令分配器,避免 GPU 执行期间重置冲突。

5. 命名调试宏

#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 帧可平滑帧率波动

命令列表创建后立即关闭

DXCall(_cmd_list->Close());

新创建的命令列表处于"录制打开"状态,立即关闭使其进入可提交状态,这是一种防御性编程。


后续工作

  • 实现 Fence 同步机制
  • 实现交换链
  • 实现描述符堆

相关文档