09 · GPU Effects
The !gpu effect marks a function as GPU-resident. Functions with !gpu cannot be called directly from CPU code (!io) — the only legal crossing point is a Pipeline object, which the compiler type-checks end-to-end. This eliminates an entire class of runtime GPU errors by turning them into compile errors.
use cssl::gpu::{Pipeline, Buffer, Surface};use cssl::math::{Vec2, Vec3, Vec4};use cssl::space::{Clip, Color};
struct Vertex { pos: Vec2, color: Vec3,}
// Vertex shader — GPU-resident, returns clip-space position.#[shader(vertex)]fn vs_main(v: Vertex) -> Vec4<Clip> !gpu { Vec4::new(v.pos.x, v.pos.y, 0.0, 1.0)}
// Fragment shader — GPU-resident, returns RGBA color.#[shader(fragment)]fn fs_main(color: Vec3) -> Vec4<Color> !gpu { Vec4::new(color.r, color.g, color.b, 1.0)}
fn main() !io { let verts: Buffer<Vertex> = Buffer::from([ Vertex { pos: Vec2::new( 0.0, 0.5), color: Vec3::RED }, Vertex { pos: Vec2::new(-0.5, -0.5), color: Vec3::GREEN }, Vertex { pos: Vec2::new( 0.5, -0.5), color: Vec3::BLUE }, ]);
// Pipeline::new checks that vs_main output matches fs_main input. let pipeline = Pipeline::new(vs_main, fs_main); let surface = Surface::new(800, 600, "GPU Triangle") !io;
surface.run(|frame| !io { frame.clear(Vec4::BLACK); pipeline.draw(&verts, frame); });}Output
Section titled “Output”A window opens showing a single RGB triangle against a black background. No terminal output — the result is visual.
What the compiler sees
Section titled “What the compiler sees”vs_main and fs_main carry !gpu — calling either from main directly is a compile error. Pipeline::new(vs_main, fs_main) is the one place where the compiler checks that the interpolated output of the vertex stage matches the input of the fragment stage; mismatched shader interfaces fail here, not at driver link time. See §B.3 Effect System for the full !gpu / !io incompatibility rules.
Next → 10 · Autodiff