| name | shader-edsl-graphics |
| description | Graphics pipeline reference for the rendiation shader EDSL. Covers GraphicsShaderProvider, vertex/fragment stages, semantics (built-in and custom), resource binding (textures, buffers, samplers), render targets, and common graphics recipes. Use when building vertex+fragment shader pipelines. Depends on shader-edsl-core for the stage-agnostic language primitives and shader-edsl-binding-and-typed-container for resource binding.
|
| metadata | {"version":"1.0","updated":"2026-05-16"} |
Rendiation graphics pipeline reference. For the core language see shader-edsl-core. For resource binding see shader-edsl-binding-and-typed-container. For compute pipelines see shader-edsl-compute.
use rendiation_shader_api::*;
Graphics Pipeline Template
impl GraphicsShaderProvider for MyPass {
fn build(&self, builder: &mut ShaderRenderPipelineBuilder) {
builder.fragment(|builder, binding| {
let tex: BindingNode<ShaderTexture2D> = binding.bind_by(&self.input_texture);
let sampler = binding.bind_by(&ImmediateGPUSamplerViewBind);
let uv: Node<Vec2<f32>> = builder.query::<FragmentUv>();
let color = tex.sample(sampler, uv);
builder.store_fragment_out(0, color);
});
}
}
Key methods:
builder.vertex(|builder, binding| { ... }) — enter vertex stage
builder.fragment(|builder, binding| { ... }) — enter fragment stage
binding.bind_by(&resource) — bind resource (texture/buffer)
binding.bind_single_by(&resource) — bind a simple resource
builder.store_fragment_out(slot, value) — write fragment output
builder.store_fragment_out_vec4f(slot, vec4) — write vec4 to 4xf32 output (common convenience)
Full vertex + fragment example
fn build(&self, builder: &mut ShaderRenderPipelineBuilder) {
builder.vertex(|builder, binding| {
let pos = builder.query::<GeometryPosition>();
let mvp = builder.query::<CameraViewNoneTranslationProjectionMatrix>();
builder.set_vertex_out::<GeometryUV>(builder.query::<GeometryUV>());
builder.register::<ClipPosition>(mvp * (pos, val(1.0)).into());
});
builder.fragment(|builder, binding| {
let uv = builder.query_or_interpolate_by::<FragmentUv, GeometryUV>();
let tex = binding.bind_by(&self.tex);
let smp = binding.bind_by(&ImmediateGPUSamplerViewBind);
builder.store_fragment_out_vec4f(0, tex.sample(smp, uv));
});
}
Register vertex buffer (CPU side)
builder.register_vertex::<CommonVertex>(VertexStepMode::Vertex);
Vertex Input & Semantics
Define vertex input layout
#[repr(C)]
#[derive(rendiation_shader_api::ShaderVertex, Clone, Copy, Debug)]
pub struct CommonVertex {
#[semantic(GeometryPosition)]
pub position: Vec3<f32>,
#[semantic(GeometryNormal)]
pub normal: Vec3<f32>,
#[semantic(GeometryUV)]
pub uv: Vec2<f32>,
}
#[semantic(X)] associates a field with a built-in semantic. #[derive(ShaderVertex)] generates the ShaderVertexInProvider impl.
Query vertex inputs
let pos: Node<Vec3<f32>> = builder.query::<GeometryPosition>();
let normal: Node<Vec3<f32>> = builder.query::<GeometryNormal>();
Set vertex outputs
builder.set_vertex_out::<GeometryUV>(uv);
builder.set_vertex_out_with_given_interpolate::<FragmentColor>(color);
builder.register::<ClipPosition>(clip_pos);
Custom semantics
only_vertex!(MyVertexData, Vec4<f32>);
only_fragment!(MyFragData, Vec3<f32>);
both!(MySharedData, f32);
Usage:
builder.query::<MyVertexData>();
builder.register::<MySharedData>(val);
Fragment Shader Patterns
Core methods
let uv: Node<Vec2<f32>> = builder.query::<FragmentUv>();
let color = builder.try_query::<FragmentColor>();
let norm: Node<Vec3<f32>> = builder.query_or_interpolate_by::<FragmentRenderNormal, VertexRenderNormal>();
let val = builder.query_or_insert_default::<FragmentUv>();
builder.register::<FragmentRenderNormal>(normal);
builder.store_fragment_out(0, color);
builder.store_fragment_out_vec4f(0, vec4);
builder.define_out_by(channel(format));
builder.store_fragment_out(1, another_color);
builder.discard();
builder.register::<FragmentDepthOutput>(depth);
builder.get_or_compute_fragment_uv();
builder.get_or_compute_fragment_normal();
Fragment output patterns
builder.store_fragment_out_vec4f(0, color);
builder.define_out_by(channel(TextureFormat::Rgba8Unorm));
builder.define_out_by(channel(TextureFormat::Rgba16Float));
builder.store_fragment_out_vec4f(0, albedo);
builder.store_fragment_out_vec4f(1, normal_and_roughness);
Semantics Quick Reference
Vertex Input (geometry data, CPU-uploaded)
| Semantic | Rust type |
|---|
GeometryPosition | Vec3<f32> |
GeometryPosition2D | Vec2<f32> |
GeometryNormal | Vec3<f32> |
GeometryTangent | Vec4<f32> |
GeometryUV (= GeometryUVChannel<0>) | Vec2<f32> |
GeometryUVChannel<I> | Vec2<f32> |
GeometryColor | Vec3<f32> |
GeometryColorWithAlpha | Vec4<f32> |
JointIndexChannel<I> | Vec4<u32> |
WeightChannel<I> | Vec4<f32> |
Vertex Built-in
| Semantic | Type | Description |
|---|
VertexIndex | u32 | gl_VertexIndex |
VertexInstanceIndex | u32 | gl_InstanceIndex |
Vertex Output
| Semantic | Type | Description |
|---|
ClipPosition | Vec4<f32> | Must write (x, y, z, w) |
VertexRenderPosition | Vec3<f32> | World-space position |
VertexRenderNormal | Vec3<f32> | World-space normal |
Fragment Input (interpolated from Vertex Output)
| Semantic | Type | Description |
|---|
FragmentFrontFacing | bool | Front facing |
FragmentPosition | Vec4<f32> | (x,y) = framebuffer coords |
FragmentSampleIndex | u32 | |
FragmentSampleMaskInput | u32 | |
Fragment Shared (Vertex writes, Fragment reads)
| Semantic | Type | Description |
|---|
FragmentUv | Vec2<f32> | Texture coordinates |
FragmentRenderPosition | Vec3<f32> | World-space position |
FragmentRenderNormal | Vec3<f32> | World-space normal |
FragmentColor | Vec3<f32> | Vertex color |
Fragment Output
| Semantic | Type | Description |
|---|
FragmentDepthOutput | f32 | Depth write |
FragmentSampleMaskOutput | u32 | |
Render Context (auto-provided)
| Semantic | Type | Description |
|---|
ViewportRenderBufferSize | Vec2<f32> | Viewport resolution |
TexelSize | Vec2<f32> | 1 / resolution |
CameraProjectionMatrix | Mat4<f32> | Projection matrix |
CameraProjectionInverseMatrix | Mat4<f32> | Inverse projection |
CameraWorldNoneTranslationMatrix | Mat4<f32> | Camera no-translation matrix |
CameraWorldPositionHP | HighPrecisionTranslation | Camera position (high precision) |
CameraViewNoneTranslationProjectionMatrix | Mat4<f32> | View-Proj matrix |
CameraViewNoneTranslationProjectionInverseMatrix | Mat4<f32> | Inverse View-Proj |
WorldPositionHP | HighPrecisionTranslation | Object world position (high precision) |
WorldNoneTranslationMatrix | Mat4<f32> | Object world matrix |
WorldNormalMatrix | Mat3<f32> | Normal matrix |
Lighting / Rendering
| Semantic | Type | Description |
|---|
ColorChannel | Vec3<f32> | Base color |
EmissiveChannel | Vec3<f32> | Emissive |
AlphaChannel | f32 | Alpha |
HDRLightResult | Vec3<f32> | HDR light result (fragment only) |
LDRLightResult | Vec3<f32> | LDR light result (fragment only) |
ShouldUsePreSetLDRResult | bool | Preset LDR (fragment only) |
DefaultDisplay | Vec4<f32> | Default debug display |
Common Patterns (Recipes)
6.1 Texture bind + sample
let tex: BindingNode<ShaderTexture2D> = binding.bind_by(&self.input);
let sampler = binding.bind_by(&ImmediateGPUSamplerViewBind);
let uv: Node<Vec2<f32>> = builder.query::<FragmentUv>();
let color = tex.sample(sampler, uv);
builder.store_fragment_out_vec4f(0, color);
6.2 Uniform struct
let uniform: BindingNode<ShaderUniformBuffer<Params>> = binding.bind_by(&self.params);
let f = uniform.load().expand();
let value = f.field * val(2.0);
6.3 Post-processing pass (fragment only)
builder.fragment(|builder, binding| {
let uv = builder.query::<FragmentUv>();
let tex = binding.bind_by(&self.input);
let smp = binding.bind_by(&ImmediateGPUSamplerViewBind);
let color = tex.sample(smp, uv);
builder.store_fragment_out_vec4f(0, color);
});
6.4 Multiple Render Targets
builder.define_out_by(channel(TextureFormat::Rgba8Unorm));
builder.define_out_by(channel(TextureFormat::Rgba16Float));
builder.store_fragment_out_vec4f(0, albedo);
builder.store_fragment_out_vec4f(1, normal_roughness);
6.5 SSAO-style: iterate + accumulate
let result = samples
.into_shader_iter()
.clamp_by(sample_count)
.map(|(_, sample): (_, ShaderReadonlyPtrOf<Vec4<f32>>)| {
let s = sample.load();
val(0.0)
})
.sum();
6.6 Dynamic array iteration (e.g. blur weights)
let weight_count: Node<u32> = binding.bind_by(&self.count).load().x();
let sum = weights
.into_shader_iter()
.clamp_by(weight_count)
.map(|(i, weight): (_, ShaderReadonlyPtrOf<Vec4<f32>>)| {
let w = weight.load();
let sample_uv = uv + size * direction * i.into_f32();
tex.sample(sampler, sample_uv) * w
})
.sum();
Gotchas (Graphics-specific)
Fragment Output
- Fragment output slots must be declared before use (auto-declared on first
store_fragment_out)
- Multiple output slots require explicit
define_out_by(channel(format))
Vertex → Fragment sync
- Vertex outputs auto-sync to Fragment inputs (same
both! semantic)
- Use
builder.query_or_interpolate_by::<FragType, VertType>() to declare the dependency
Reference Examples