DirectX Pipeline Statistics: Diagnosing Bottlenecks

DirectX pipeline statistics queries provide granular, hardware-level invocation and primitive metrics across the rendering pipeline, allowing graphics engineers to pinpoint performance bottlenecks such as vertex processing overhead, excessive overdraw, and geometry rejection. By capturing quantitative data directly from the GPU during execution, these queries reveal exactly where the rendering workload stalls. This article details the primary metrics recorded by pipeline statistics in DirectX and explains how developers interpret them to identify and resolve GPU pipeline inefficiencies.

Core Metrics Captured by Pipeline Statistics

In both DirectX 11 and DirectX 12 (D3D12_QUERY_DATA_PIPELINE_STATISTICS), pipeline statistics queries capture execution counts at each major stage of the rendering pipeline:

  • Input Assembler (IA): IAVertices and IAPrimitives record the total raw geometry fed into the pipeline.
  • Vertex Shader (VS): VSInvocations tracks how many times the vertex shader executed.
  • Hull & Domain Shaders (HS/DS): HSInvocations and DSInvocations track tessellation operations.
  • Geometry Shader (GS): GSInvocations and GSPrimitives measure geometry expansion or stream-out workloads.
  • Clipper (C): CInvocations reflects primitives that reached the clipping stage, while CPrimitives counts primitives that survived clipping and proceeded downstream.
  • Pixel Shader (PS): PSInvocations measures the total number of fragments shaded.
  • Compute Shader (CS): CSInvocations tracks compute thread group dispatches.

Identifying Geometry and Culling Bottlenecks

One of the most effective uses of pipeline statistics is detecting inefficient geometry handling:

  1. Ineffective Frustum and Back-Face Culling: If the ratio of CInvocations to CPrimitives is exceptionally high, the GPU is spending excessive cycles processing geometry that is ultimately clipped or discarded outside the viewport. Developers resolve this by implementing coarse CPU frustum culling, GPU-driven occlusion culling (e.g., via compute shaders), or mesh clustering.
  2. Sub-Pixel and Dense Geometry Overhead: A high count of IAPrimitives relative to a low number of resulting pixels shaded often points to over-tessellated meshes or distant objects lacking appropriate Level of Detail (LOD). This indicates that the vertex pipeline is saturated with micro-triangles that yield little visual impact, necessitating more aggressive LOD transitions.
  3. Vertex Cache Misses: Comparing IAVertices to VSInvocations helps evaluate post-transform cache efficiency. If VSInvocations significantly exceeds expected unique vertex counts, the index buffers may not be optimized for spatial locality.

Pinpointing Pixel Shader and Fill-Rate Limitations

The PSInvocations counter reveals the computational load imposed on fragment processing:

  1. Overdraw Detection: By dividing PSInvocations by the target render resolution, developers determine the average overdraw factor per frame or per draw call. An elevated ratio in forward renderers indicates that overlapping geometry is being shaded repeatedly. This prompts solutions like front-to-back sorting, Depth Pre-Passes, or transitioning to deferred rendering paths.
  2. Early-Z Rejection Failures: If PSInvocations matches the total rendered triangle surface area despite occluders being present, the pipeline may have disabled hardware Early-Z optimizations. This commonly happens when shaders write to depth (SV_Depth), use discard/clip instructions, or activate specific blend modes, forcing the engine to fall back to late fragment testing.

Analyzing Shader Expansion Inefficiencies

Pipeline statistics expose the hidden performance costs of programmable stages that dynamically amplify geometry:

  • Geometry Shader Sinks: When GSPrimitives is vastly higher than GSInvocations, the geometry shader may be generating heavy amplification that saturates GPU ring buffers and stalls the rasterizer.
  • Tessellation Balancing: Comparing HSInvocations and DSInvocations ensures tessellation factors are configured correctly. A high domain shader invocation count relative to visual fidelity signals over-tessellation, which can be mitigated by adjusting tessellation factors dynamically based on camera distance.

Practical Diagnostic Implementation

Developers typically wrap critical render passes, draw call batches, or individual debug profiles inside BeginQuery and EndQuery blocks. When paired with timestamp queries, pipeline statistics correlate stage-by-stage counts directly with GPU execution time.

By analyzing these hardware metrics inside in-engine profilers or diagnostic tools, developers can immediately determine whether an underperforming pass is bounded by geometry throughput, rasterization, or fragment shading, avoiding guesswork during engine optimization.