Difference Between dFdxCoarse and dFdxFine in GLSL

This article explores the operational differences, visual characteristics, and performance impacts of coarse derivatives (dFdxCoarse, dFdyCoarse) versus fine derivatives (dFdxFine, dFdyFine) in GLSL fragment shaders. Modern GPUs calculate screen-space derivatives by processing fragments in \(2 \times 2\) pixel clusters (quads). Understanding how coarse and fine operations sample and distribute rates of change across these quads is essential for optimizing texture filtering, procedural shading, and normal map generation.

The GPU Quad Execution Model

Modern graphics hardware executes fragment shaders simultaneously in \(2 \times 2\) pixel groups called "quads." To calculate standard screen-space derivatives—the rate of change of a variable relative to screen coordinates—the hardware compares the values of a variable across the fragments within the same quad:

  • Top-left: \((x_0, y_0)\)
  • Top-right: \((x_1, y_0)\)
  • Bottom-left: \((x_0, y_1)\)
  • Bottom-right: \((x_1, y_1)\)

The default functions dFdx and dFdy allow the GPU driver to choose whether to calculate these rates of change with coarse or fine granularity. Specifying dFdxCoarse or dFdxFine directly controls how differences are evaluated across the quad.

How dFdxFine Works

Fine derivatives calculate distinct derivative values for each adjacent horizontal or vertical pair within the \(2 \times 2\) quad.

  • Horizontal Calculation (dFdxFine):
    • The top-left and top-right pixels calculate \(\Delta x_{\text{top}} = p(x_1, y_0) - p(x_0, y_0)\).
    • The bottom-left and bottom-right pixels calculate \(\Delta x_{\text{bottom}} = p(x_1, y_1) - p(x_0, y_1)\).
  • Result: The top row of pixels receives the top row's difference, and the bottom row receives the bottom row's difference.

Because distinct rates of change are preserved across the individual rows and columns of the quad, dFdxFine yields per-fragment precision.

How dFdxCoarse Works

Coarse derivatives compute a single derivative value for the entire \(2 \times 2\) quad and duplicate it across all four fragments.

  • Horizontal Calculation (dFdxCoarse):
    • The GPU computes one difference across the quad (typically evaluating only the top row: \(p(x_1, y_0) - p(x_0, y_0)\)).
    • This single derivative value is assigned to all four pixels in the quad, ignoring the bottom row's actual rate of change.
  • Result: All four fragments in the \(2 \times 2\) cluster share identical derivative results.

Key Differences

Feature dFdxCoarse / dFdyCoarse dFdxFine / dFdyFine
Precision Low (uniform across \(2 \times 2\) quad) High (distinct per row/column)
Visual Artifacts Can cause blocky \(2 \times 2\) pixel artifacts Smooth, continuous transitions
Arithmetic Cost Minimal (fewer subtraction operations) Slightly higher ALU instruction count
Evaluation Scope One evaluation broadcast to all 4 pixels Independent evaluations per row/column

Practical Use Cases

When to Use Fine Derivatives

Fine derivatives are ideal for high-frequency shading calculations where accuracy is paramount to avoid visual aliasing. Common use cases include:

  • Procedural Normal Mapping: Calculating analytical surface normals from depth or noise functions in screen space.
  • Raymarching and SDF Rendering: Edge detection and gradient estimation where quad-wide averaging causes noticeable stepping artifacts.
  • Anti-Aliasing Functions: Procedural wireframes or step functions (like fwidth combined with smoothstep) that require sharp, sub-pixel accuracy.

When to Use Coarse Derivatives

Coarse derivatives are useful when derivative precision is secondary to performance or uniformity:

  • Texture LOD / Mipmap Selection: Level-of-detail calculations often benefit from uniform derivatives across the quad, preventing adjacent pixels within the same quad from sampling different mip levels.
  • Performance-Critical Post-Processing: Shaders with heavy derivative usage that run on mobile or low-power hardware can benefit from reduced register pressure and ALU overhead.