← Back to Tutorials
Intermediate~16 min readUE 5.5 / 5.6

PIX on Windows for UE

PIX is the only D3D12 tool that gives you co-resident CPU + GPU + memory + file-IO timelines in one capture. The same instrumentation API works on Xbox via the GDK; tooling investment for one platform pays off twice. This tutorial covers install, the three capture types, the shader-symbol setup, programmatic capture for CI, the comparison layout for regression diffs, and the NVIDIA HAGS caveat that corrupts timings on Lunar Lake / NVIDIA combos.

1

Why PIX still earns its slot in 2026

RenderDoc covers single-frame inspection. Insights covers CPU + light GPU correlation. PIX covers what neither does well: GPU + CPU + memory residency + file IO on the same timeline, with hardware counters on Windows D3D12. For shipping D3D12 games on Windows or Xbox, PIX is the senior dev's daily driver alongside Insights.

Latest PIX: 2603.25 (x64 + Arm64) at time of writing. Latest preview: 2602.25-preview. PIX 2505.09+ supports cross-thread PIXBeginEvent/PIXEndEvent with a D3D context — required for UE 5.5's revised event emission to display correctly.

2

Install & matching DLLs

  1. Download PIX 2603.25 (or current) from Microsoft's PIX download page.
  2. The installer keeps versions side-by-side; multiple PIX versions can coexist on disk.
  3. Verify WinPixGpuCapturer.dll and WinPixEventRuntime.dll from Engine/Binaries/ThirdParty/Windows/ match the installed PIX version. Mismatches cause silent capture failures or stale event names.
  4. The legacy Windows SDK pix.h is obsolete — UE bundles pix3.h from the WinPixEventRuntime NuGet under Engine/Source/ThirdParty/Windows/D3DX12. Don't include the SDK pix.h in your code.
3

Enable PixWinPlugin in UE5

  1. Plugins panel → "PIX on Windows GPU Capture Plugin" → enable.
  2. Build with USE_PIX defined. Development and DebugGame already define it via PROFILE.
  3. For shipping captures: disable Use Io Store in Packaging settings (silently breaks shader-symbol resolution otherwise) and enable Include Debug Files in Shipping.
  4. WinPixEventRuntime instrumentation compiles to no-ops unless one of USE_PIX, DBG, _DEBUG, PROFILE, or PROFILE_BUILD is defined — verify your shipping config.
4

Shader symbols block (DefaultEngine.ini)

For SPIRV-cross / DXIL stepping in PIX:

DefaultEngine.ini (shader debug for PIX)
[/Script/Engine.RendererSettings]
r.Shaders.Symbols=1
r.Shaders.ExtraData=1
r.Shaders.GenerateSymbols=1
r.Shaders.WriteSymbols=1
r.Shaders.SkipCompression=1
r.ShaderDevelopmentMode=1
; Optimize=0 for shader debug, =1 for profiling
r.Shaders.Optimize=0

Configure PIX Home → Symbol paths to point at <project>/Saved/ShaderSymbols (5.6+ split). Without this, timing capture function names show as unknown.

5

Capture workflow: Launch / Attach / Live-attach

  • Launch For GPU Capture (PIX UI). Click "Launch Win32 Application" in PIX, point at your packaged .exe, choose flags. PIX hooks D3D12 from process start.
  • Programmatic / attach. Launch with -attachPIX -d3ddebug command-line + r.D3D12.AutoAttachPIX=1 in ConsoleVariables.ini. Causes the process to call PIXLoadLatestWinPixGpuCapturerLibrary at startup so a later PIXBeginCapture works.
  • Live-attach contract. WinPixGpuCapturer.dll must be loaded before D3D12CreateDevice — this is the rule for attaching to an already-running process.

The most reliable target is a NoEditor Development build. Editor PIE captures are the most fragile path; many "target process was not launched for GPU Capture" errors are PIE-only.

6

Three capture types decoded

  • GPU capture. Single frame, full D3D12 replay. Equivalent to RenderDoc's main capture mode. Use when you need to inspect draws, PSOs, bound resources.
  • Timing capture. Multi-frame timeline with CPU samples + GPU timings + memory residency + file IO. Two modes: Sequential (drive-space-bound, captures everything) and Circular (fixed buffer, can run overnight in CI). Use for hitch hunts, residency thrash investigations, frame-pacing issues.
  • Function summary / Callgraph. Aggregated CPU sampling like a flat profiler. Useful when you don't need the full timeline.

Maps to UE bug classes: hitch → Timing capture, GPU-bound frame → GPU or Timing, residency thrash → Timing, "where is my CPU going on a stable frame" → Callgraph.

7

PIX events in UE5

UE wraps RHI work in SCOPED_DRAW_EVENT[F] macros which surface as PIX GPU events. RHI_DRAW_CALL_INC, FCpuProfilerTrace::OutputBeginEvent, and friends emit PIX markers (PIXBeginEvent / PIXSetMarker) on the command list.

UE 5.5 changed how Epic emits these markers across threads. On PIX < 2505.09, GPU events still appear but CPU-thread arrows are wrong; older blog tutorials look broken until you upgrade PIX. Always pair recent UE versions with recent PIX.

8

Comparison Layout (regression workflow)

PIX 2408.05+ added a Comparison Layout for timing captures — the central reason to prefer PIX over RenderDoc for regression diffs.

  1. Capture baseline timing capture as baseline.wpix.
  2. Capture candidate timing capture under identical conditions.
  3. Open both in PIX; switch to Comparison Layout.
  4. Diff PIX-event hierarchies side-by-side; PIX shows Delta% and a P-value (statistical significance) per event.

The P-value is the cross-capture statistical comparison (PIX 2408.05+ feature). Treat <0.05 as significant, >0.1 as noise. Don't confuse statistical significance with visual significance — a 0.2 ms regression with p=0.01 is real but might not matter; use Delta% for the second-pass triage.

9

Programmatic capture for CI

For automated CI workflows (which is where this overlaps with PerfGuard), capture programmatically:

C++ programmatic capture
// At process start, before D3D12CreateDevice:
PIXLoadLatestWinPixGpuCapturerLibrary();

// Later, when ready to capture:
PIXCaptureParameters Params = {};
Params.GpuCaptureParameters.FileName = TEXT("ci_capture_build_42.wpix");
PIXBeginCapture(PIX_CAPTURE_GPU, &Params);

// Drive the gameplay scenario (PerfGuard-style)

PIXEndCapture(/*discard=*/false);

// Or capture next N frames automatically:
PIXGpuCaptureNextFrames(TEXT("ci_capture.wpix"), 10);

Drop the .wpix file as a CI artifact. Headless-friendly even on dedicated test hardware. PerfGuard ingests these natively.

Driver / hardware caveats & Xbox GDK

  • Disable Hardware-accelerated GPU Scheduling (HAGS) on NVIDIA + Intel Lunar Lake — HAGS corrupts GPU timings in PIX captures on these combos. Confirmed PIX known issue.
  • AMD dual-GPU rigs need primary-GPU pinning — PIX may attach to the wrong adapter otherwise.
  • ExecuteIndirect non-determinism — some PIX versions have an experimental "make ExecuteIndirect deterministic" toggle for debugging.
  • HoloLens projects must stay on PIX 2308.30 — main branch dropped HoloLens support.
  • Multi-process launchers (Steam, EOS bootstrappers) — PIX follows the process tree only for GPU captures; Timing captures only see the launched process. Bypass the launcher.
  • AMD high-frequency hardware counters can crash PIX after Debug-Layer warnings analysis runs — collect counters in a dedicated re-replay.
  • Combining -gpucrashdebugging with -d3ddebug — produces unusable Aftermath/PIX output. Use one or the other when chasing a TDR vs a perf regression.

Xbox via GDK: same pix3.h API, MSGamingRuntime plugin. GPU Trace and timing captures with PIXCaptureParameters (memory size, MemoryCircular ring buffer). NDA-gated, but UE5 GDK target reuses the same instrumentation macros — your annotation work pays off twice.

PerfGuard can ingest two .wpix timing captures (baseline + candidate from CI's PIXBeginCapture artifact), run regression analysis on the PIX-event hierarchy with PIX's statistical comparison, and emit standard PerfGuard HTML reports with Delta% per draw event — surfacing D3D12-level regressions (state transitions, ExecuteIndirect, residency migrations) that pure UE-side stat tracing never sees.