Renderer Specialization
A full renderer example specialized via traits and turbofish. Three trait axes (Material, LightModel, NormalSource) are composed in a single generic shade_fragment function. Each concrete configuration (selected via turbofish like shade_fragment::<Gradient, BlinnPhong, PerturbNormal>) monomorphizes into a fully-inlined, specialized WGSL function with zero overhead.
Rust Source
#![allow(unused)] fn main() { #[wgsl] pub mod renderer_specialization { use wgsl_rs::std::*; // ===== Traits: each axis of rendering variation ===== /// How a material produces a surface color at a given UV coordinate. pub trait Material { fn surface_color(uv: Vec2f) -> Vec4f; } /// How lighting is computed for a given surface color and geometry. pub trait LightModel { fn apply_lighting( surface: Vec4f, normal: Vec3f, light_dir: Vec3f, view_dir: Vec3f, ) -> Vec4f; } /// How the surface normal is determined. pub trait NormalSource { fn get_normal(uv: Vec2f, geom_normal: Vec3f) -> Vec3f; } // ===== Strategy structs ===== // // Each struct represents a concrete rendering strategy. In a real // renderer these might hold configuration data; here they serve as // type-level tags that select which code path to monomorphize. /// Simple checkerboard material — procedural, no textures needed. pub struct Checker { pub _tag: u32, } /// Vertical gradient material — warm-to-cool procedural color. pub struct Gradient { pub _tag: u32, } /// Lambert diffuse lighting model. pub struct Lambert { pub _tag: u32, } /// Blinn-Phong lighting with specular highlights. pub struct BlinnPhong { pub _tag: u32, } /// Use the raw geometric normal as-is. pub struct GeomNormal { pub _tag: u32, } /// Perturb the geometric normal (simulates a normal map). pub struct PerturbNormal { pub _tag: u32, } // ===== Trait implementations ===== impl Material for Checker { fn surface_color(uv: Vec2f) -> Vec4f { let checker: f32 = floor(uv.x() * 4.0) + floor(uv.y() * 4.0); let c: f32 = (checker % 2.0) * 0.5 + 0.25; vec4f(c, c, c, 1.0) } } impl Material for Gradient { fn surface_color(uv: Vec2f) -> Vec4f { vec4f(uv.y() * 0.8, 0.3, (1.0 - uv.y()) * 0.9, 1.0) } } impl LightModel for Lambert { fn apply_lighting( surface: Vec4f, normal: Vec3f, light_dir: Vec3f, _view_dir: Vec3f, ) -> Vec4f { let ndotl: f32 = max(dot(normal, light_dir), 0.0); surface * ndotl } } impl LightModel for BlinnPhong { fn apply_lighting( surface: Vec4f, normal: Vec3f, light_dir: Vec3f, view_dir: Vec3f, ) -> Vec4f { let ndotl: f32 = max(dot(normal, light_dir), 0.0); let diffuse: Vec4f = surface * ndotl; let half_vec: Vec3f = normalize(light_dir + view_dir); let spec: f32 = pow(max(dot(normal, half_vec), 0.0), 32.0); diffuse + vec4f(spec, spec, spec, 0.0) } } impl NormalSource for GeomNormal { fn get_normal(_uv: Vec2f, geom_normal: Vec3f) -> Vec3f { normalize(geom_normal) } } impl NormalSource for PerturbNormal { fn get_normal(uv: Vec2f, geom_normal: Vec3f) -> Vec3f { let perturb: Vec3f = vec3f(uv.x() * 0.1 - 0.05, uv.y() * 0.1 - 0.05, 1.0); normalize(geom_normal + perturb) } } // ===== Generic shader pipeline ===== /// The single generic fragment shading function. It composes material, /// lighting, and normal sourcing through trait bounds. After /// monomorphization, each configuration produces a fully-inlined, /// specialized WGSL function with zero overhead. pub fn shade_fragment<M: Material, L: LightModel, N: NormalSource>( uv: Vec2f, geom_normal: Vec3f, light_dir: Vec3f, view_dir: Vec3f, ) -> Vec4f { let normal: Vec3f = N::get_normal(uv, geom_normal); let surface: Vec4f = M::surface_color(uv); L::apply_lighting(surface, normal, light_dir, view_dir) } // ===== Concrete shader variants (each is one turbofish line) ===== /// Fancy renderer: gradient + Blinn-Phong + perturbed normals. pub fn shade_fancy(uv: Vec2f, normal: Vec3f, light_dir: Vec3f, view_dir: Vec3f) -> Vec4f { shade_fragment::<Gradient, BlinnPhong, PerturbNormal>(uv, normal, light_dir, view_dir) } /// Mix-and-match: checkerboard + Blinn-Phong + perturbed normals. /// Demonstrates that each axis of variation is independent. pub fn shade_hybrid(uv: Vec2f, normal: Vec3f, light_dir: Vec3f, view_dir: Vec3f) -> Vec4f { shade_fragment::<Checker, BlinnPhong, PerturbNormal>(uv, normal, light_dir, view_dir) } } }
Generated WGSL
struct Checker {
_tag: u32
}
struct Gradient {
_tag: u32
}
struct Lambert {
_tag: u32
}
struct BlinnPhong {
_tag: u32
}
struct GeomNormal {
_tag: u32
}
struct PerturbNormal {
_tag: u32
}
fn Checker__1surface_color(uv: vec2f) -> vec4f {
let checker: f32 = floor(uv.x * 4.0) + floor(uv.y * 4.0);
let c: f32 = (checker % 2.0) * 0.5 + 0.25;
return vec4f(c, c, c, 1.0);
}
fn Gradient__1surface_color(uv: vec2f) -> vec4f {
return vec4f(uv.y * 0.8, 0.3, (1.0 - uv.y) * 0.9, 1.0);
}
fn Lambert__1apply_lighting(surface: vec4f, normal: vec3f, light_dir: vec3f, _view_dir: vec3f) -> vec4f {
let ndotl: f32 = max(dot(normal, light_dir), 0.0);
return surface * ndotl;
}
fn BlinnPhong__1apply_lighting(surface: vec4f, normal: vec3f, light_dir: vec3f, view_dir: vec3f) -> vec4f {
let ndotl: f32 = max(dot(normal, light_dir), 0.0);
let diffuse: vec4f = surface * ndotl;
let half_vec: vec3f = normalize(light_dir + view_dir);
let spec: f32 = pow(max(dot(normal, half_vec), 0.0), 32.0);
return diffuse + vec4f(spec, spec, spec, 0.0);
}
fn GeomNormal__1get_normal(_uv: vec2f, geom_normal: vec3f) -> vec3f {
return normalize(geom_normal);
}
fn PerturbNormal__1get_normal(uv: vec2f, geom_normal: vec3f) -> vec3f {
let perturb: vec3f = vec3f(uv.x * 0.1 - 0.05, uv.y * 0.1 - 0.05, 1.0);
return normalize(geom_normal + perturb);
}
fn shade_fancy(uv: vec2f, normal: vec3f, light_dir: vec3f, view_dir: vec3f) -> vec4f {
return _1shade_fragment_Gradient_BlinnPhong_PerturbNormal(uv, normal, light_dir, view_dir);
}
fn shade_hybrid(uv: vec2f, normal: vec3f, light_dir: vec3f, view_dir: vec3f) -> vec4f {
return _1shade_fragment_Checker_BlinnPhong_PerturbNormal(uv, normal, light_dir, view_dir);
}
fn _1shade_fragment_Gradient_BlinnPhong_PerturbNormal(uv: vec2f, geom_normal: vec3f, light_dir: vec3f, view_dir: vec3f) -> vec4f {
let normal: vec3f = PerturbNormal__1get_normal(uv, geom_normal);
let surface: vec4f = Gradient__1surface_color(uv);
return BlinnPhong__1apply_lighting(surface, normal, light_dir, view_dir);
}
fn _1shade_fragment_Checker_BlinnPhong_PerturbNormal(uv: vec2f, geom_normal: vec3f, light_dir: vec3f, view_dir: vec3f) -> vec4f {
let normal: vec3f = PerturbNormal__1get_normal(uv, geom_normal);
let surface: vec4f = Checker__1surface_color(uv);
return BlinnPhong__1apply_lighting(surface, normal, light_dir, view_dir);
}
Notes
- Each trait method becomes a free function mangled as
Type__1method(e.g.Checker__1surface_color). - The generic
shade_fragment<M, L, N>is monomorphized into one function per turbofish configuration, named_1shade_fragment_<M>_<L>_<N>. - Strategy structs become empty-tagged WGSL structs; they exist only to drive monomorphization.