← SEARCHABLE ARCHIVE
DirectX 12 · 2026-07-11

DX12 命令队列和栅栏

在正确的时间同步 CPU 和 GPU

INTERACTIVE READING MODE →

该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。

在 DirectX 12 中,CPU 记录命令列表,GPU 稍后执行。 由于两个设备同时移动,因此它们必须同步,以便 CPU 不会覆盖 GPU 仍在使用的资源。

命令队列和命令列表

Command List是记录绘图命令的列表,Command Queue将完成的列表提交给GPU。

CPU
命令分配器初始化
命令列表历史记录
CommandList Close
        ↓
提交命令队列
        ↓
GPU执行

CommandAllocator 管理录制所需的内存。 当 GPU 仍在读取前一帧的指令时,不应重置同一个分配器。

使用 Fence 检查完成时间

void WaitForGPU()
{
    const UINT64 SignalValue = ++FenceValue;
    CommandQueue->Signal(Fence, SignalValue);

    if (Fence->GetCompletedValue() < SignalValue)
    {
        Fence->SetEventOnCompletion(SignalValue, FenceEvent);
        WaitForSingleObject(FenceEvent, INFINITE);
    }
}

当信号值进入队列时,GPU 会处理之前的所有命令,然后更新 Fence 值。 仅当完成值小于目标时,CPU 才会等待事件。

如果你等待每一帧,那么速度会很慢。

在三角形的例子中,为了更容易理解,WaitForGPU()可以调用。 但是,如果这样做,CPU 和 GPU 就无法协同工作并在每一帧串行运行。

在实际应用中,BackBuffer的个数就有多少个Frame Resources,并且单独记录每帧的Fence值。

struct FrameContext
{
    ComPtr<ID3D12CommandAllocator> Allocator;
    UINT64 FenceValue = 0;
};

它只等待当前使用的帧资源的栅栏,并允许GPU继续处理其他帧。

打开调试层

在 DX12 中,开发人员对错误的状态转换或描述符的使用负有直接责任。 如果在初始化之前打开调试层,您可以更快地找出哪些资源状态和命令顺序错误。

DX12同步的目的不是无条件等待。 它允许CPU和GPU尽可能同时工作,同时精确地等待再次使用相同的资源。