A Direct3D 11 playground using the Win32 API, built with CMake and C++.
- LearnD3D11 - DirectX11 Tutorial
- DirectXTutorial - DirectX11 Tutorial
- Vulkan Tutorial - Vulkan Tutorial as a reference
- RenderDoc - Graphics Pipeline Debugger
- CMake 3.21+
- Visual Studio or a Ninja-compatible compiler
- Windows 10 SDK or later
- Graphics API: Direct3D 11, Direct3D 12
- Language: C++23
- Target platform: Windows 10+
Libraries linked from the Windows 10 SDK, detected automatically at configure time.
| Library | Description |
|---|---|
OpenGL32.lib |
OpenGL |
d3d11.lib |
Direct3D 11 |
d3d12.lib |
Direct3D 12 |
dxgi.lib |
Swap chains, adapters, and display modes |
d3dcompiler.lib |
Runtime HLSL shader compilation |
dxguid.lib |
GUIDs for DirectX interfaces |
winmm.lib |
High-resolution timers and multimedia |
dwmapi.lib |
Desktop Window Manager (dark mode, etc.) |
Generate the project files.
cmake -S . -BbuildOpen the project in Visual Studio.
cmake --open buildBuild the application.
cmake --build buildGenerate the build files specifying the build type.
cmake -S . -Bbuild -GNinja -DCMAKE_BUILD_TYPE=DebugBuild the application.
ninja -C buildCapture a frame using the CLI. The working directory must be set to the project root so the application can find its shader files.
renderdoccli capture --working-dir . ./build/hellodirectxBelow shows a typical graphics pipeline.
Memory Resources
(Buffer, Texture, Constant Buffer)
┌─────────────────────┐ ┌────────────────┐
│ Input-Assembler │ CBuf│█████▀█▓█▀▀█▀▓▀█│
│ Stage │ │▓▓█████▓█▓▓█████│
└──────────┬──────────┘ │█▓▓▓▓██████▓▓█▓█│
▼ │█▓▄█▄▓██▓▓▄▓▄▄▄▓│
┌─────────────────────┐ VBuf│ ░ ░ ░░│
│ Vertex Shader │🞀────────────────────────🞂│▒█▒▒▓▒▓▄▓▀▒▒▀▓█▓│
│ Stage │ │▓██▓█▓▓▓▓█▓███▀▒│
└──────────┬──────────┘ │█▓▓▓▓▓▓█▓▓████▒▌│
▼ │▄▓▓█▓█▓██████▓▓▌│
┌─────────────────────┐ │▀▀▓██▓█▓▓▓█▓██▒▒│
│ Hull Shader Stage │🞀────────────────────────🞂│▀█▓▄▄▓▀▄█▒▄▄▄▓██│
└──────────┬──────────┘ │█▀▄▒▒▀█▀▀▓▓▒▀▓▄▀│
┌────────────┤ │░ ░ ░ │
│ ▼ IBuf│█▓▀█▀▓▄▒▒▄▄░▀▀▌ │
│ ┌─────────────────────┐ │▒█▓▐▄█▀▒▄▄▀░▀▀▓▌│
│ │ Tessellator Stage │ │█▄▀▀▒▓▒▒░▌░▄▒▐░▀│
│ └──────────┬──────────┘ │ ░ ░ │
└───────────🞂│ Tex │▀▒░░ ▐ ▐▌▌▄ ▐ ▀▐│
▼ │▓▒▀▓▄▒▀▒▄▀▀▓▀▀▐▄│
┌─────────────────────┐ │▀██▓█▓▓█▓▓▓▓███▒│
│ Domain Shader │🞀────────────────────────🞂│▒███▓█▓██▓█▓█▓▓▒│
│ Stage │ │▓████▓▓████▓▓█▓▓│
└──────────┬──────────┘ │▒█████████▓▓▓██▌│
│ │▒▓██▓█▓██▓▓█▓▓██│
▼ │▓▒▒▐▀▓▀▓▓▒▒▓▌█▒▀│
┌─────────────────────┐ │▒▒█▓▒▀▄▓▓▒█▀▒▒▒▓│
│ Geometry Shader │🞀────────────────────────🞂│▒▓▒▄▄▀▓▄▄▌▓█▒▓▄▒│
│ Stage │ │▀▓▓▌▓▓▀▄▄▀▓▓▓█▒▓│
└──────────┬──────────┘ │▓▒▐▄▀▒▒▄██▀▒▀▒▌▓│
├───────────🞂┌─────────────────┐ │▄▌▀▀█▄▀▒░░▓▄▀▀▒▒│
│ │ Stream Output │ │ ░ ░ │
│ │ Stage │ Free│ ░ ░ ░ ░ ░│
▼ └─────────────────┘ │ ░░ ░ │
┌─────────────────────┐ │ ░ ░ │
│ Rasterizer Stage │🞀────────────────────────🞂│░ ░ ░ ░ │
└──────────┬──────────┘ Stg│ ▌ ▓░▐ ▌ ▄░▓ ▒░▄│
│ │▄ ▄ ▐░▒░▒░▄ ▄░▒ │
▼ │ ▒ ▒ ▒ ▓ ▐ ▀ ▒ ▀│
┌─────────────────────┐ │▓░▒ ▒ ▄ ▀ ▄ ▄░▄ │
│ Pixel Shader Stage │🞀────────────────────────🞂│░▒ ▀░▄ ▒ ▀ ▒░▒ ▌│
└──────────┬──────────┘ │ ░ │
│ │░ ░░░▐ ▀ ░▐ │
▼ │▄░░ ░░░ ▄░░▄ ▒░│
┌─────────────────────┐ Desc│█▓▓▀▀▀▓▓█▀█▓▀▀█▀│
│ Output-Merger Stage │🞀────────────────────────🞂│▄▄▄█▓▓█▄▄▄▄▄██▓█│
└─────────────────────┘ └────────────────┘
- Input-Assembler: Reads vertex and index data from buffers and assembles them into geometric primitives (triangles, lines, etc.)
- Vertex Shader: Runs once per vertex, typically transforms positions from object space to clip space
- Hull Shader: Controls tessellation, determines how much to subdivide a patch (optional)
- Tessellator: Fixed-function stage that subdivides geometry based on hull shader output (optional)
- Domain Shader: Runs once per tessellated vertex to compute its final position (optional)
- Geometry Shader: Runs once per primitive, can emit or discard primitives (optional)
- Stream Output: Optionally writes primitive data back to a buffer for later reuse
- Rasterizer: Converts vector geometry into discrete pixel fragments, clips, and interpolates attributes
- Pixel Shader: Runs once per pixel fragment, computes the final color, samples textures, lighting, etc.
- Output-Merger: Combines pixel shader output with the render target using depth/stencil testing and blending
Typical GPU memory resource layout
- CBuf - Constant Buffer (dense, solid)
- VBuf - Vertex Buffer with hot position/normal data regions
- IBuf - Index Buffer (compact, mixed density)
- Tex - Texture data with mip levels (densest at top, tapering down)
- Free - Unallocated padding
- Stg - Staging buffer (fragmented, partially mapped)
- Desc - Descriptor/guard footer
Above diagram is a typical graphics pipeline:
graphics_pipeline = [
input_assembler,
vertex_shader,
hull_shader,
tessellator,
domain_shader,
geometry_shader,
stream_output,
rasterizer,
pixel_shader,
output_merger,
]
Some techniques also make use of compute shaders, which run outside the graphics pipeline:
[
compute_shader, // DLSS, ray tracing (DXR), particle simulation,
// physics, culling, post-processing (bloom, SSAO)
]
Compute shaders don't insert into the pipeline - they run as separate dispatch calls. The typical order is:
frame = [
compute_shader, // before: culling, physics, build ray tracing acceleration structures
...graphics_pipeline,
compute_shader, // after: DLSS, bloom, SSAO, tone mapping
present,
]
