← SEARCHABLE ARCHIVE
DirectX 12 · 2026-07-11

DX12 Command Queue and Fence

Synchronize CPU and GPU at the right time

INTERACTIVE READING MODE →

The articles written on this blog were created with the goal of teaching. Also, the information in the article may be incorrect, so please be careful.

In DirectX 12, the CPU records the Command List and the GPU executes it later. Since the two devices move at the same time, they must be synchronized so that the CPU does not overwrite the resources still used by the GPU.

Command Queue and Command List

The Command List is a list that records drawing commands, and the Command Queue submits the completed list to the GPU.

CPU
CommandAllocator initialization
CommandList History
CommandList Close
        ↓
Submit CommandQueue
        ↓
GPU execution

CommandAllocator manages the memory required for recording. The same Allocator should not be reset while the GPU is still reading instructions from the previous frame.

Check completion time with Fence

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

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

When a Signal value is entered into the Queue, the GPU processes all previous commands and then updates the Fence value. The CPU waits for an Event only when the completion value is less than the target.

It's slow if you wait for every frame.

In the triangle example, to make it easier to understand,WaitForGPU()can be called. However, if you do this, the CPU and GPU cannot work together and run serially every frame.

In practice, there are as many Frame Resources as the number of BackBuffers and the Fence value of each frame is recorded separately.

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

It waits only for the fence of the frame resource to be currently used, and allows the GPU to continue processing other frames.

Turn on Debug Layer

In DX12, developers are directly responsible for incorrect state transitions or use of descriptors. If you turn on the Debug Layer before initialization, you can find out which Resource State and command order are wrong much faster.

The purpose of DX12 synchronization is not to wait unconditionally. It allows the CPU and GPU to work as much as possible at the same time, while waiting precisely to use the same resources again.