Building a Custom Game Engine from Scratch (C++ & DX12) - Day 3: Command Queue, Swap Chain & Manual RTV Binding

Hey everyone! :waving_hand:

Today marks Day 3 of my journey building TitanEngine completely from scratch using C++20 and native DirectX 12, with zero bloated third-party templates or high-level helper wrappers.

In this session, we moved past the initial window and device creation to establish the core rendering foundation. Here is what was implemented today:

  • Command Queue Setup: Initialized the direct command queue (D3D12_COMMAND_LIST_TYPE_DIRECT) to open up the communication pipeline between the CPU and GPU.

  • Swap Chain Configuration: Configured a double-buffered swap chain using DXGI_SWAP_EFFECT_FLIP_DISCARD at 720p for modern, efficient frame swapping tied directly to our Win32 window handle.

  • Descriptor Heap (RTV): Allocated a Render Target View descriptor heap to manage our frame buffers in GPU memory.

  • Pure Pointer Arithmetic: Bypassed external helper libraries by querying the hardware descriptor size (GetDescriptorHandleIncrementSize) and manually advancing memory pointers (rtvHandle.ptr += rtvDescriptorSize) to bind our render targets. Full hardware transparency!

You can check out the full step-by-step breakdown and code walkthrough in the latest video update here: :television: Watch Day 3 on YouTube: https://youtu.be/HLN-EQOziYE

Feedback, architectural thoughts, or questions from fellow engine programmers are always welcome. Let’s keep building low-level! :rocket:

Nice progress for day 3, and a good choice to build the command queue and swap chain by hand to understand how they connect.

Two things that are worth adding in the next steps, since you are setting up double buffering: first, a fence with a fence value per frame, so the CPU waits until the GPU has finished with a back buffer before reusing its command allocator; and second, a command allocator for each back buffer, because a single allocator cannot be reset while the GPU is still executing commands recorded with it. Enabling the D3D12 debug layer from the start will also catch resource state mistakes (for example a missing transition from present to render target) with a clear message.

Looking forward to the next day of the series.