SV_Position vs User-Defined Semantics in DirectX

In DirectX High-Level Shading Language (HLSL), vertex shader outputs are tagged with semantics that dictate how data travels through the graphics pipeline. While user-defined semantics serve as generic carriers for custom data like texture coordinates or surface normals that simply undergo interpolation, SV_Position is a specialized System Value semantic with a strict, hardware-enforced purpose. This article explains the technical differences between SV_Position and user-defined semantics, covering their coordinate space requirements, pipeline behavior, and hardware integration.

Hardware Consumption vs. Generic Data Passing

The primary difference lies in how the GPU's fixed-function hardware interprets the semantic:

  • SV_Position (System Value): This semantic signals the GPU's rasterizer stage directly. The rasterization hardware requires a position output to determine where a primitive lies on the screen, handle frustum clipping, perform back-face culling, and execute perspective division. It is mandatory for the final pre-rasterization stage (Vertex, Geometry, or Domain Shader).
  • User-Defined Semantics: Semantics such as TEXCOORD, NORMAL, or custom names like TANGENT are not interpreted by the rasterization hardware. The GPU treats them as generic payloads of floating-point or integer data that must be forwarded to the Pixel Shader.

Coordinate Space Requirements

Because SV_Position directly feeds the rasterization stage, it must conform to a strict coordinate format:

  • Clip Space Output: When output by a vertex shader (or the last stage before the rasterizer), SV_Position must be in homogeneous clip space, expressed as a four-component vector \((x, y, z, w)\).
  • User-Defined Flexibility: User-defined semantics can store values in any mathematical space desired by the developer, such as local space, world space, view space, or normalized UV coordinates. The graphics pipeline enforces no mathematical conventions on these values.

Transformation Between Shader Stages

How these values arrive in the Pixel Shader highlights another critical divergence in behavior:

  • SV_Position in the Pixel Shader: Between the vertex and pixel shader stages, the GPU performs perspective divide (dividing \(x, y, z\) by \(w\)) and viewport mapping on SV_Position. Consequently, if a pixel shader reads SV_Position as an input, it receives screen-space (pixel) coordinates where \(x\) and \(y\) correspond to the pixel's location in the render target (with pixel centers offset by 0.5), \(z\) represents the depth buffer value, and \(w\) holds \(1/w\) for perspective interpolation.
  • User-Defined Interpolation: User-defined semantics undergo perspective-correct interpolation across the surface of the triangle. Unless overridden by interpolation modifiers (such as nointerpolation or noperspective), the data arrives at the pixel shader smoothly blended across vertices without any automatic screen-space transformations.

Pipeline Validation and Constraints

The DirectX compiler and runtime enforce strict rules regarding SV_Position:

  • Uniqueness and Presence: Exactly one active position semantic (SV_Position) must be output prior to the rasterizer. Failing to provide SV_Position results in a compilation error or runtime pipeline failure.
  • Arbitrary Definition: User-defined semantics can be arbitrarily declared, named, indexed (e.g., TEXCOORD0 through TEXCOORD7), or omitted entirely depending on the requirements of the rendering pass.