Opening it¶
The debug window only exists on a -debug boot: debug_ui::enabled() gates every part of it, and without that flag the hide key does nothing and no ImGui frame for the window is ever opened (runtime/debug_window/DebugUi.h). The launcher adds -debug when its own "Debug mode" checkbox is on, which is itself only visible once a separate Debug switch is enabled.
F2 alone is the ordinary screenshot hotkey, and it works on every boot, debug or not. Alt+F2 dumps a frame for the frame oracle, Ctrl+Alt+F2 dumps the render tree, and Ctrl+Alt+F9 dumps the event profiler's trace. The key that shows or hides the whole debug UI is hide_imgui_key, F3 by default, changed from Left Alt so that Alt+Tab stopped toggling it (runtime/settings/settings.h). All five are rebindable from the window's own System and Capture tabs, and any of them can share a key, since a command fires on its key whatever else is held.
Layout¶
One fixed-size window, one header strip of clickable stat cells, thirteen tabs (Overview, Presets, Temporal, Lighting, RT, Post, World, Retail, Profiler, Capture, System, Log, Warnings), and one footer line naming the hovered card or the current tab's one live fact (runtime/debug_window/RendererWindow.h). The header strip's cells, dropped from the end as the window narrows, are FRAME, WORST, GPU, RENDER THREAD, EE, EE WAIT, DRAWS, TRIS, BUCKETS, PASSES ON and WARNINGS; clicking GPU toggles the Measure GPU instrument on. Ctrl+F puts the keyboard in a filter box that narrows every tab's own rows and opens a cross-tab search popup grouped by tab and card.
Overview¶
The first tab a reader opens. A Verdict band leads it: a pure function over one frame's numbers (interval, render thread, GPU, present wait, the EE thread's own work) that names what is actually bounding the frame, capped, game-side bound, GPU bound, render thread bound, present bound, headroom, or "not enough to say", with a confidence level and at most one lever to try (runtime/debug_window/DebugFrameVerdict.h). Under it sit three bands: Frame (this frame's cost, the four costliest passes, the render thread's category split, the EE thread's clocks), Picture (the internal and output size, the temporal mode and its ratio, the AA pass, every lever standing off the chosen preset), and World (the loader's state, the pause contract, light and vehicle lamp counts, ray tracing structures, and the level table). A Memory card closes it: a VRAM bar and a process working-set bar, each with its own explanation, refreshed once a second.
Presets¶
Retail faithful, Enhanced and Custom, compared lever by lever in a fixed table that always lists every lever, whether or not it differs from the chosen preset (runtime/debug_window/DebugPresets.h). This is separate from the in-game options screens: it writes straight into the renderer's global settings rather than through *pc-settings*, and it is the only place in the tree that can turn on the temporal upscalers or the cutscene upscaler. "Save current as Custom" writes the live levers to debug.json; "Load Custom" reads them back.
Profiler¶
The render thread's 300-frame window (now, average, worst, frames per second), a fixed pass table with a GPU column that only fills once the Measure GPU instrument is on, the threaded-recording pool's own three readouts, and an instrument checklist (Measure GPU, Serialize the GPU, threaded recording, the frame-time overlay, the small profiler overlay, the profiler tree window) (runtime/debug_window/tabs/TabProfiler.h).
Retail¶
Five retail-faithful levers (no multidraw, fog intensity, sky-on-CPU, occlusion culling, fast blackout loads), a census of every bucket renderer registered this frame (drew, empty, switched off, open, pinned), and a scrolling list with one entry per bucket renderer plus the texture pool, the texture animator and the eye renderers as tools, each opening that renderer's own ImGui window (runtime/debug_window/tabs/TabRetail.h).
System¶
Hardware readouts (GPU, driver, API), a fixed-height, filterable level table (state: Loaded, Init, Wanted or Idle; idle frames; resident textures; resident merc models) built from the loader's own rows (runtime/graphics/renderer/loader/Loader.h), per-thread CPU sampling rows, and the capture keys tip. The level heap audit itself is a log line, not a tab: at the end of every level load the runtime logs each heap's size, use and margin under the level subsystem, and warns when one overruns; the Log tab's tail shows it.
Capture¶
Four captures, each with its own file-name template and rebindable chord: Screenshot (F2), the frame oracle dump (Alt+F2), the render tree (Ctrl+Alt+F2), and the event profiler dump (Ctrl+Alt+F9) (runtime/debug_window/DebugCapture.h). A template takes variables like {game}, {date}, {time}, {frame}, {level}, {preset} and {seq}; each card's Last line says what its last press wrote or why it wrote nothing.
Log, Warnings and toasts¶
The Log tab keeps the last 200 lines the logger wrote in a filterable, scrollable tail: a level floor (print, info, warn, error), comma-separated text excludes, right-click mutes by message class, Follow/Pause/Wrap/Time view options, and a "N new lines" pill while scrolled up (runtime/debug_window/DebugLogTail.h). The Warnings tab lists every condition the window knows how to detect, each with a Copy button, whether or not it currently holds. Toasts are the small cards that slide in from the right: the once-per-boot debug message and every runtime notice, stacked newest at the bottom, each fading after six seconds unless dismissed by the hide key, and drawn every ImGui frame regardless of whether the rest of the debug UI is visible (runtime/debug_window/DebugToast.h). Texture thumbnails, used on the Retail tab's tool windows, draw a fixed 64-point square whether or not a texture exists behind it, with the full picture offered on hover.