Derivatives
Derivatives compute per-pixel rate-of-change of a value with respect to screen-space coordinates. They are only valid inside fragment shaders; calling them from any other stage is a WGSL error.
Fine / coarse variants
WGSL provides three precision tiers. wgsl-rs exposes all of them:
| Function | WGSL Equivalent | Description |
|---|---|---|
dpdx(p) | dpdx | Default precision dpCoarse. |
dpdy(p) | dpdy | Default precision dpCoarse. |
fwidth(p) | fwidth | abs(dpdx) + abs(dpdy), default precision. |
dpdx_fine(p) | dpdxFine | Fine precision dpFine. |
dpdy_fine(p) | dpdyFine | Fine precision. |
fwidth_fine(p) | fwidthFine | Fine precision. |
dpdx_coarse(p) | dpdxCoarse | Coarse precision dpCoarse. |
dpdy_coarse(p) | dpdyCoarse | Coarse precision. |
fwidth_coarse(p) | fwidthCoarse | Coarse precision. |
The bare dpdx/dpdy/fwidth map to WGSL’s default-precision builtins, which
WGSL defines as coarse. Prefer the explicit _fine / _coarse variants when
the choice matters for your application.
Common uses
- Mip selection in non-fragment-aware sampling: pass gradients to
textureSampleGradfromdpdx/dpdyof the texture coordinates. - Edge detection / anti-aliasing:
fwidthto compute pixel-local width. - Screen-space dependent branching: compare
fwidthagainst a threshold.
Example
#![allow(unused)]
fn main() {
#[wgsl]
pub mod derivatives_example {
use wgsl_rs::std::*;
uniform!(FRAME, Frame);
texture!(COLOR_TEX, Texture2d);
sampler!(COLOR_SMP, Sampler);
pub struct Frame {
pub time: f32,
}
#[fragment]
pub fn fs(in: VertexOutput) -> Vec4f {
let uv = in.uv;
let dx = dpdx_fine(uv);
let dy = dpdy_fine(uv);
let w = fwidth_fine(uv);
let color = textureSampleGrad(COLOR_TEX, COLOR_SMP, uv, dx, dy);
color
}
}
}
CPU behavior
On the CPU, derivatives return zero for dpdx/dpdy and the input value’s
magnitude for fwidth — enough to keep CPU tests running without panic. The
GPU is the source of truth for derivative accuracy.