Understanding Frame Pacing with DirectX Timestamps
Frame pacing is the measure of consistency with which consecutive frames are rendered and presented to the display, where uneven intervals produce visual stutter even at high average frame rates. This article defines frame pacing, examines why temporal consistency is critical for smooth visual performance, and details how developers use DirectX timestamp queries to measure, diagnose, and resolve delivery irregularities across the CPU and GPU rendering pipeline.
What Is Frame Pacing?
Frame pacing refers to the temporal uniformity of frame delivery to a display. While frame rate is measured as an aggregate average (frames per second, or FPS), frame pacing measures the exact duration each individual frame remains on screen (frame time, measured in milliseconds).
For example, a steady 60 FPS target requires a new frame every 16.67 milliseconds. If a rendering engine produces 60 frames in a single second, but alternates between 8 ms and 25 ms intervals, the user perceives judder and micro-stutter. Smooth motion relies on predictable, uniform delivery intervals that match or divide evenly into the display's refresh rate.
Common causes of erratic frame pacing include:
- Spikes in CPU simulation or draw call generation.
- Asymmetric GPU workloads (such as sudden compute passes or heavy post-processing).
- Inefficient buffer queuing within the graphics swap chain.
- Lock contention and thread synchronization delays between render threads.
What Are DirectX Timestamps?
DirectX timestamps are hardware-level profiling counters generated directly by the graphics pipeline. In DirectX 11 and DirectX 12, developers record these markers into command lists to measure execution duration without introducing CPU-side measurement overhead or blocking execution.
In modern DirectX 12, timestamps are managed through an
ID3D12QueryHeap configured with the type
D3D12_QUERY_HEAP_TYPE_TIMESTAMP. Unlike CPU timers, which
only track when work is submitted to the driver, DirectX timestamps
capture the exact moments the GPU begins and finishes processing
specific batches of work. To convert these raw hardware ticks into
absolute time, the API provides the command queue frequency via
ID3D12CommandQueue::GetTimestampFrequency.
Evaluating Pacing Irregularities Using Timestamps
Evaluating frame pacing requires mapping the lifecycle of each frame across two domains: workload generation (CPU) and execution/presentation (GPU).
1. Instrumenting the Command Stream
To isolate frame time deviations, developers insert timestamp queries at critical boundaries within the frame:
- At the beginning of the command list (GPU frame start).
- Before and after specific passes (e.g., shadow generation, G-buffer, compute tasks).
- Immediately before the final presentation call (work complete).
These timestamps are resolved into a buffer via
ResolveQueryData and read back asynchronously on the CPU to
prevent pipeline stalls.
2. Measuring Inter-Frame Deltas
By comparing the start timestamp of frame \(N\) to frame \(N+1\), developers calculate the exact GPU frame-to-frame delta:
\[\Delta t_{\text{frame}} = \frac{\text{Timestamp}_{\text{Frame } N+1} - \text{Timestamp}_{\text{Frame } N}}{\text{Frequency}}\]
A steady baseline graph indicates good pacing. Spikes indicate an execution bottleneck, while sharp dips followed by spikes indicate pipeline bubbles—where the GPU exhausted work because the CPU was late submitting the next frame.
3. Correlating Presentation and Flip Times
Timestamp data must be evaluated alongside swap chain behavior. Using
DirectX Graphics Infrastructure (DXGI) interfaces—such as
IDXGISwapChain::GetFrameStatistics—or tracing frameworks
like PresentMon, developers cross-reference the GPU finish timestamp
with the display presentation time
(PresentRefreshCount).
If DirectX timestamps show that the GPU finishes rendering
consistently every 16.67 ms, but the display flip occurs erratically
across 16.67 ms and 33.33 ms boundaries, the pacing issue is typically
located in swap chain backbuffer configuration, presentation flags
(e.g., DXGI_PRESENT_DO_NOT_WAIT), or synchronization with
the display refresh cycle (V-Sync).
4. Isolating Pipeline Variance
Because timestamps can be placed around individual render passes, calculating the variance (\(\sigma^2\)) of each pass over hundreds of frames isolates which specific system causes pacing jitter. If the total frame time fluctuates by 10 ms, evaluating per-pass timestamp intervals reveals whether the issue stems from variable shadow casting, dynamic compute dispatches, or state-clearing overhead.
By utilizing DirectX timestamps, developers eliminate guesswork and isolate whether frame pacing irregularities stem from CPU command submission delays, variable GPU work complexity, or swap chain backpressure.