Varying Unit Survey
This page surveys how GPUs implement varying interpolation between shader stages: what enters the varying path, how it is parameterized, how perspective correction works, how multiple lanes/instances get different varyings, and where software emulation appears.
Short answer:
- On mainstream hardware, varyings are usually handled by fixed-function or semi-fixed interpolation hardware near the rasterizer, not by ordinary shader ALU.
- The shader core receives already-interpolated values, while software rasterizers can do the same work in CPU code.
- The exact plumbing differs by vendor, but the API-level model is mostly the same: vertex outputs become per-fragment inputs, optionally filtered by interpolation qualifiers and sample/centroid rules.
1) What a varying is
A varying is data written by an earlier stage and read by a later stage. Common examples:
- Vertex shader outputs consumed by the fragment shader
- Tessellation/geometry outputs consumed by later stages
- Per-primitive data such as face orientation, primitive ID, clip distances
- User varyings like color, UVs, normals, tangents, custom payloads
At the API level, varyings are usually declared as:
- GLSL
out/in - HLSL semantics such as
TEXCOORDn,COLORn,SV_Position,SV_IsFrontFace,SV_SampleIndex,SV_Barycentrics - SPIR-V built-ins and user interface variables
2) What the varying unit consumes
The interpolation path typically consumes:
- Per-vertex outputs from the provoking primitive
- Clip-space position (
gl_Position/SV_Position) so it can derive perspective correction - Per-primitive flags (flat shading, provoking vertex selection, face orientation)
- Interpolation qualifiers such as
flat,smooth,noperspective,centroid,sample,center,nointerpolation - Multisample coverage/sample position state when MSAA is enabled
- Optionally, explicit barycentric coordinates exposed to the fragment shader
Common parameterization inputs
| Input | Meaning |
|---|---|
| Per-vertex attribute values | The source values to interpolate |
| Clip-space W | Used for perspective-correct interpolation |
| Primitive coverage | Which pixels/samples are covered |
| Barycentric weights | Triangle-local weights for interpolation |
| Provoking vertex | Source for flat-qualified values |
| Sample position | Used for centroid/sample evaluation and MSAA |
| Interpolation mode | Flat, smooth, noperspective, sample, centroid |
| Primitive ID / face flag | Per-primitive values not interpolated from vertices |
3) Do vendors implement varyings in hardware or software?
For shipping desktop and mobile GPUs, the normal path is hardware-assisted interpolation, not shader-code emulation. That said, there are software paths in the ecosystem:
- Mesa software rasterizers such as llvmpipe/softpipe implement the same behavior in CPU code.
- Driver fallbacks or emulation layers can also synthesize interpolation in shader code when a particular path lacks a dedicated block or when a feature is emulated.
So the practical answer is:
- Dedicated hardware: common on NVIDIA, AMD, Intel, Apple, ARM and others for the normal graphics pipeline.
- Software implementation: common in Mesa software rasterizers and some fallback/emulation paths.
- Shader-ALU implementation: possible in fallback paths, but not the common fast path on modern discrete GPUs.
4) How perspective correction works
For triangle fragments, interpolation is usually barycentric in screen space with perspective correction. The core idea is:
- The rasterizer computes barycentric weights for the fragment within the triangle.
- Each varying is divided by vertex W before interpolation.
- The interpolated result is re-multiplied by the reciprocal of the interpolated 1/W.
Conceptually:
noperspectiveuses screen-space linear interpolation.smooth/ perspective-correct interpolation uses the 1/W correction.flatdoes no interpolation at all; one vertex value is chosen.
Barycentric form
For a triangle with vertices A, B, C and barycentric weights λ0, λ1, λ2:
For noperspective, the denominator is skipped.
5) How multiple shader instances get different varyings
A single shader program usually runs across many pixels at once. Each lane in the wave/warp corresponds to a different pixel/sample, so each lane needs different interpolated values.
The hardware handles this by:
- Computing coverage and barycentric weights per fragment/sample
- Feeding lane-specific interpolants into the fragment shader payload
- Keeping the values lane-local, even though the instruction stream is shared
- Reusing the same vertex outputs across many fragments of the same primitive
This is why varyings scale naturally with SIMT execution:
- One vertex value can feed thousands of fragments
- Each fragment lane receives a different interpolated result
- When MSAA is active, each sample can receive distinct centroid/sample inputs depending on the qualifier
6) How vendors generally expose the varying path
NVIDIA
- Public docs emphasize rasterization plus interpolation into the fragment stage rather than a separate programmer-visible varying block.
- The practical model is classic fixed-function attribute interpolation feeding the fragment warp.
- Perspective-correct interpolation, flat interpolation, centroid/sample behavior, and per-sample shading are all supported through the graphics pipeline.
AMD
- AMD hardware similarly uses attribute interpolation as part of the graphics front end / rasterization path.
- Public tooling and docs focus more on occupancy, wave scheduling, and register pressure than on naming a standalone varying block.
- The interpolated attribute payload is delivered to fragment waves; the wave scheduler then hides latency from memory or complex shading.
Intel
- Intel graphics also follow the standard pipeline model: vertex outputs are rasterized and interpolated before fragment execution.
- The compiler/hardware path emphasizes payload setup and efficient delivery of interpolants to the EUs.
- As on other vendors, perspective correction and qualifiers are handled before the fragment shader consumes the values.
Apple
- Apple’s tile-based GPUs keep much of rasterization local to the tile, but the semantic model is still conventional interpolation of vertex outputs to fragment inputs.
- The implementation is generally tightly integrated with the tile renderer and sampler path.
- Public Metal APIs expose the behavior indirectly through shader inputs and rasterization/sample state.
ARM / Mali
- ARM Mali GPUs (Midgard/Bifrost/Valhall families) follow the same high-level model: rasterization produces fragment-local interpolation inputs and the fragment stage consumes varyings according to qualifiers.
- Public architectural details are limited, but open Panfrost documentation shows explicit varying machinery across generations, including descriptor-driven paths (
AttributeDescriptor/BufferDescriptor) and generation-specific load ops (LD_VAR,LD_VAR_FLAT,LD_VAR_SPECIAL,LD_VAR_BUF). - This suggests a dedicated interpolation/varying path in hardware, with shader instructions selecting how values are fetched/interpreted rather than fully emulating interpolation in generic shader ALU.
- Mali’s tile-based execution model means varyings are naturally consumed per-fragment/per-sample within tile-local raster work, while preserving standard API semantics (
flat, perspective-correct, centroid/sample).
Broadcom (VideoCore / V3D)
- Broadcom public documentation is sparse for newer V3D generations, but Mesa VC4/V3D drivers indicate conventional hardware raster + interpolation behavior feeding fragment execution.
- VC4 and V3D are tiled renderers in common deployments (for example Raspberry Pi stacks), so interpolation is tightly coupled to tile rasterization and fragment payload setup.
- There are software simulation/emulation artifacts in the ecosystem (for example simpenrose-backed workflows), but those are development/testing tools and not representative of the normal hardware fast path.
- Practical takeaway: Broadcom platforms generally match the same pipeline contract as other vendors, while low-level varying block details are less publicly documented than in some other ecosystems.
7) Explicit barycentrics and programmable interpolation
Modern APIs increasingly expose explicit barycentric inputs so the shader can perform custom interpolation or attribute reconstruction.
Examples:
- HLSL
SV_Barycentricsfor fragment shaders - Vulkan fragment shader barycentric extensions
- Shader-level reconstruction of custom perspective or screen-space effects
Advantages:
- Custom interpolation math
- Better control for wireframe, edge-distance, and analytical shading effects
- Useful when the built-in interpolants are not enough
Disadvantages:
- More ALU work in the shader
- More pressure on registers and occupancy
- Potentially lower performance than the fixed-function path
8) Software interpolation paths
Yes: software rasterizers do this in software.
Mesa software paths such as llvmpipe/softpipe can interpolate varyings on the CPU side before the fragment-like shading code runs. This is not unusual for open-source driver stacks because:
- It provides correctness on hardware without a feature
- It simplifies support for edge cases
- It is useful for testing and fallback execution
Trade-off:
- Pros: portability, correctness, feature coverage
- Cons: far slower than dedicated hardware interpolation
9) Vendor-style inputs and qualifier summary
| API concept | Typical input to the varying path | Notes |
|---|---|---|
GLSL smooth |
Per-vertex values + clip-space W | Perspective-correct |
GLSL noperspective |
Per-vertex values | Screen-space linear |
GLSL flat |
Provoking vertex value | No interpolation |
GLSL centroid |
Coverage-aware sample position | Helps avoid edge artifacts |
GLSL sample |
Per-sample interpolation | MSAA-sensitive |
HLSL TEXCOORDn / COLORn |
Generic interpolated payload | Semantics guide linkage |
HLSL SV_Position |
Rasterizer-derived screen position | Can be linear no perspective in pixel stage |
HLSL SV_IsFrontFace |
Per-primitive facing | Not interpolated |
HLSL SV_SampleIndex |
Sample number | Per-sample shading |
HLSL SV_Barycentrics |
Explicit barycentric weights | Programmable interpolation |
| Vulkan/GLSL built-ins | Interface variables + qualifiers | Mirrors the underlying graphics pipeline |
10) Barycentric and centroid handling
Barycentric coordinates are the natural model for triangle interpolation. The hardware typically computes them relative to the covered pixel/sample and then applies the interpolation mode:
center: evaluate at pixel centercentroid: choose a point guaranteed to be inside the covered region when possiblesample: evaluate per MSAA sampleflat: choose a single vertex source
Centroid sampling is mainly about avoiding artifacts at triangle edges when the pixel center falls outside the covered area under MSAA.
11) Practical pros and cons
Dedicated hardware interpolation
Pros:
- Fast and low ALU cost
- Good bandwidth/latency balance
- Scales naturally with many fragments
Cons:
- Less programmable
- Edge cases depend on API qualifiers and hardware rules
Software or shader-ALU interpolation
Pros:
- Portable fallback
- Can expose custom behavior
- Easy to test and emulate
Cons:
- Slower
- Higher register/ALU pressure
- Usually worse occupancy and throughput
12) Bottom line
For normal desktop/mobile GPUs, varyings are usually a hardware-interpolated part of the graphics pipeline, not a dedicated shader-written program block. The shader core generally receives ready-to-use interpolants. Software implementation exists mainly in Mesa software rasterizers and fallback/emulation paths. Perspective correction is typically barycentric with 1/W compensation, while qualifiers such as flat, noperspective, centroid, and sample select the exact behavior.