### Run Example and Inspect WGSL Source Source: https://github.com/schell/wgsl-rs/blob/main/AGENTS.md Commands to execute the example crate, display help, list modules, and validate/print WGSL source code for a specific example module. ```bash cargo run -p example # Run the example, showing help text about subcommands ``` ```bash cargo run -p example -- show # Show the names of available example modules ``` ```bash cargo run -p example -- source {name} # Validate and print a single example module's WGSL source ``` -------------------------------- ### Numeric Builtin Function Implementation Strategy Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Provides an example AI prompt for implementing numeric built-in functions in WGSL using Rust. It guides the implementation based on existing traits and suggests strategies for handling glam vector types. ```rust Please add the {fn} function using the module-level documentation table as a guide, following the implementation of `abs` and `acos`, which used the `NumericBuiltinAbs` and `NumericBuiltinAcos` traits, respectively. You should replace {fn} with whatever function you want to implement. Keep in mind that the `VecN` types have `glam` types as their `inner` fields, so you can use that for many of these. Keep in mind that glam vectors are not iterators, you can't call `zip` on them. Instead, you can call `to_array` on each vector and write into one of them, finally calling `.into()` on the array to convert it back to the vector. See the implementations of `NumericBuiltinPow` and `NumericBuiltinStep` for an example of this. I've gone with a "one-trait-per-function" strategy because each function has little differences, and I anticipate having to use generic associated types for some functions. ``` -------------------------------- ### Expand Macro and View Generated WGSL Source: https://github.com/schell/wgsl-rs/blob/main/AGENTS.md Use `cargo expand` to inspect the WGSL code generated by the `wgsl` macro within example modules. ```bash cargo expand -p example -- examples::{name} # Expand the example which uses the `wgsl` macro, showing the generated WGSL_MODULE ``` -------------------------------- ### WGSL Uniform Macro Example Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Demonstrates the usage of the `uniform!` macro for defining shader uniforms with binding and group information. This macro is used for WGSL constructs not directly representable in Rust syntax. ```rust uniform!(binding(0), group(0), BRIGHTNESS: f32); ``` -------------------------------- ### WGSL Uniform Access with get! Macro Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Shows how to access uniform values using `get!(U_TIME)`. The returned `ModuleVarReadGuard` needs to be wrapped with identity type constructors like `f32()` or `vec2f()` for arithmetic operations on the CPU side. ```rust f32(get!(U_TIME)) ``` ```rust vec2f(get!(U_RESOLUTION).x(), get!(U_RESOLUTION).y()) ``` -------------------------------- ### WGSL Module Validation Examples Source: https://github.com/schell/wgsl-rs/blob/main/README.md Demonstrates different validation strategies for WGSL modules. Standalone modules are validated at compile-time, while modules with imports are validated at test-time. The `skip_validation` attribute can be used to disable validation. ```rust pub mod constants { pub const PI: f32 = 3.14159; } // Module with imports - validated at test-time #[wgsl] pub mod shader { use super::constants::*; pub fn circle_area(r: f32) -> f32 { PI * r * r } } // Skip all validation #[wgsl(skip_validation)] pub mod experimental { // ... } ``` -------------------------------- ### WGSL Swizzle Function Example Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Shows how to perform vector swizzling in Rust to mimic WGSL's field accessors. Since Rust requires unaltered code, functions like `.xyz()` are used instead of direct field access. ```rust .xyz() ``` -------------------------------- ### WGSL Switch Statement Example Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md The WGSL equivalent of a Rust match statement, using 'switch', 'case', and 'default'. Handles specific enum variants. ```wgsl switch my_expr { case MyEnum_Variant1: { do_stuff(); } default: {} } ``` -------------------------------- ### Declare GPU Resources with wgsl-rs Macros Source: https://context7.com/schell/wgsl-rs/llms.txt Use macros like uniform!, storage!, texture!, sampler!, and workgroup! within a #[wgsl] module to declare GPU resource bindings. These macros generate WGSL var declarations and thread-safe Rust statics accessible via get!/get_mut!. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod resource_demo { use wgsl_rs::std::*; pub struct Camera { pub view_proj: Mat4x4f, } // @group(0) @binding(0) var CAMERA: Camera; uniform!(group(0), binding(0), CAMERA: Camera); // @group(0) @binding(1) var INPUT: array; storage!(group(0), binding(1), INPUT: [f32; 256]); // @group(0) @binding(2) var OUTPUT: array; storage!(group(0), binding(2), read_write, OUTPUT: [f32; 256]); // @group(1) @binding(0) var DIFFUSE: texture_2d; texture!(group(1), binding(0), DIFFUSE: Texture2D); // @group(1) @binding(1) var SHADOW: texture_depth_2d; texture!(group(1), binding(1), SHADOW: TextureDepth2D); // @group(1) @binding(2) var TEX_SAMPLER: sampler; sampler!(group(1), binding(2), TEX_SAMPLER: Sampler); // var SCRATCH: array; workgroup!(SCRATCH: [u32; 64]); #[compute] #[workgroup_size(64)] pub fn main(#[builtin(global_invocation_id)] gid: Vec3u) { let idx = gid.x() as usize; // get! acquires a read lock on Rust side; stripped to bare identifier in WGSL. let val = get!(INPUT)[idx]; // get_mut! acquires a write lock on Rust side. get_mut!(OUTPUT)[idx] = val * 2.0; } } // CPU-side test: set uniforms and run the shader directly. #[test] fn test_resource_demo() { use resource_demo::*; INPUT.set([1.0f32; 256]); OUTPUT.set([0.0f32; 256]); main(wgsl_rs::std::vec3u(0, 0, 0)); assert!((get!(OUTPUT)[0] - 2.0).abs() < 1e-6); } ``` -------------------------------- ### Runtime-Sized Arrays with `RuntimeArray` Source: https://context7.com/schell/wgsl-rs/llms.txt Utilize `RuntimeArray` for runtime-sized storage in WGSL, transpiling to `array`. It's backed by `Vec` on the CPU and supports `push`, `len`, and indexing. Use `array_length(&arr)` to get the length within WGSL. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod particles { use wgsl_rs::std::*; pub struct Particle { pub position: Vec3f, pub velocity: Vec3f, } pub struct ParticleBuffer { pub count: u32, pub data: RuntimeArray, } storage!(group(0), binding(0), read_write, PARTICLES: ParticleBuffer); #[compute] #[workgroup_size(64)] pub fn integrate(#[builtin(global_invocation_id)] gid: Vec3u) { let n = array_length(&get!(PARTICLES).data); let i = gid.x(); if i < n { let vel = get!(PARTICLES).data[i].velocity; let pos = &mut get_mut!(PARTICLES).data[i].position; *pos = *pos + vel; } } } #[test] fn test_integrate_cpu() { use particles::*; let mut buf = ParticleBuffer { count: 1, data: RuntimeArray::new(), }; buf.data.push(Particle { position: vec3f(0.0, 0.0, 0.0), velocity: vec3f(1.0, 2.0, 3.0), }); PARTICLES.set(buf); integrate(vec3u(0, 0, 0)); let pos = get!(PARTICLES).data[0u32].position; assert_eq!(pos.x, 1.0); assert_eq!(pos.y, 2.0); assert_eq!(pos.z, 3.0); } ``` -------------------------------- ### WGSL Standard Library Usage and Demos Source: https://context7.com/schell/wgsl-rs/llms.txt Imports all WGSL types, constructors, and built-in functions. Demonstrates vector/matrix types, mathematical functions, packing, bitcasting, and derivative functions. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod std_demo { use wgsl_rs::std::*; pub fn phong( normal: Vec3f, light_dir: Vec3f, view_dir: Vec3f, shininess: f32, ) -> f32 { let n = normalize(normal); let l = normalize(light_dir); let v = normalize(view_dir); let r = reflect(-l, n); let diffuse = max(dot(n, l), 0.0); let specular = pow(max(dot(r, v), 0.0), shininess); diffuse + specular } #[fragment] pub fn frag_main() -> Vec4f { let n = vec3f(0.0, 1.0, 0.0); let l = vec3f(0.577, 0.577, 0.577); let v = vec3f(0.0, 0.0, 1.0); let intensity = phong(n, l, v, 32.0); // Packing demo: pack a normalized color into a u32. let color = vec4f(intensity, intensity * 0.5, 0.0, 1.0); let _packed = pack4x8unorm(color); // Bitcast demo. let bits = bitcast_u32(intensity); let _back = bitcast_f32(bits); color } } #[test] fn test_phong_cpu() { let result = std_demo::frag_main(); assert!(result.w == 1.0); } ``` -------------------------------- ### Define Shader Entry Points with wgsl-rs Attributes Source: https://context7.com/schell/wgsl-rs/llms.txt Use `#[vertex]`, `#[fragment]`, and `#[compute]` with `#[workgroup_size]` to declare shader stages. Return types of `Vec4f` for vertex and fragment shaders are automatically assigned `@builtin(position)` and `@location(0)` respectively. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod hello_triangle { use wgsl_rs::std::*; uniform!(group(0), binding(0), FRAME: u32); // vertex_index builtin stripped on Rust side; emitted as @builtin(vertex_index) in WGSL. #[vertex] pub fn vtx_main(#[builtin(vertex_index)] vertex_index: u32) -> Vec4f { const POS: [Vec2f; 3] = [vec2f(0.0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5)]; let pos = POS[vertex_index as usize]; vec4f(pos.x, pos.y, 0.0, 1.0) // Transpiles to: // @vertex fn vtx_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4 } #[fragment] pub fn frag_main() -> Vec4f { // sin() is available from wgsl_rs::std::* vec4f(1.0, sin(wgsl_rs::std::f32(get!(FRAME)) / 128.0), 0.0, 1.0) // Transpiles to: // @fragment fn frag_main() -> @location(0) vec4 } #[compute] #[workgroup_size(64)] pub fn cs_main(#[builtin(global_invocation_id)] gid: Vec3u) { let _idx = gid.x(); // @compute @workgroup_size(64) // fn cs_main(@builtin(global_invocation_id) gid: vec3) } } ``` -------------------------------- ### Build and Test Crates with Cargo Source: https://github.com/schell/wgsl-rs/blob/main/AGENTS.md Standard Cargo commands for building, testing, and linting all crates within the project. Use `-p` to target specific crates. ```bash cargo build # Build all crates ``` ```bash cargo test # Run all tests ``` ```bash cargo test -p wgsl-rs-macros # Test specific crate (wgsl-rs-macros in this case) ``` ```bash cargo test -- test_name # Run a single test by name ``` ```bash cargo fmt && cargo clippy # Format and lint ``` -------------------------------- ### Struct Methods and Constants in WGSL Source: https://context7.com/schell/wgsl-rs/llms.txt Demonstrates how `impl` blocks in Rust are transpiled to free functions and constants in WGSL. Method receivers are passed explicitly, and naming follows `TypeName_member`. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod light_demo { use wgsl_rs::std::*; pub struct Light { pub position: Vec3f, pub intensity: f32, } impl Light { pub const DEFAULT_INTENSITY: f32 = 1.0; // Transpiles to: fn Light_new(position: vec3, intensity: f32) -> Light pub fn new(position: Vec3f, intensity: f32) -> Light { Light { position, intensity } } // Transpiles to: fn Light_attenuate(light: Light, distance: f32) -> f32 pub fn attenuate(light: Light, distance: f32) -> f32 { light.intensity / (distance * distance) } } #[fragment] pub fn frag_main() -> Vec4f { let light = Light::new(vec3f(0.0, 5.0, 0.0), Light::DEFAULT_INTENSITY); let att = Light::attenuate(light, 2.5); vec4f(att, att, att, 1.0) } } #[test] fn test_light_cpu() { let result = light_demo::frag_main(); // 1.0 / (2.5 * 2.5) = 0.16 assert!((result.x - 0.16).abs() < 1e-5); } ``` -------------------------------- ### Rust Match to WGSL Switch Statement Transformation Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Demonstrates how Rust 'match' statements are transpiled to WGSL 'switch' statements. Supports or-patterns and automatically generates a default arm if missing. Match expressions are unsupported. ```rust let __match_result = match my_expr { input @ MyEnum::Variant1 => { do_stuff(); input } }; __ensure_integer(__match_result); ``` -------------------------------- ### Runtime WGSL Module Validation Source: https://github.com/schell/wgsl-rs/blob/main/README.md Shows how to validate a WGSL module at runtime using the `Module::validate()` method. This requires enabling the 'validation' feature for the `wgsl-rs` crate. ```rust use wgsl_rs::wgsl; #[wgsl] pub mod my_shader { // ... } fn main() { // Validate manually (requires "validation" feature) my_shader::WGSL_MODULE.validate().expect("WGSL validation failed"); } ``` -------------------------------- ### Rust Structs for WGSL Shader Inputs and Outputs Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Rust equivalents for WGSL shader input and output structs, using #[location(...)] and #[builtin(...)] attributes. Note that return type annotations are handled by shader stage proc-attribute macros. ```rust pub struct MyInputs { #[location(0)] pub x: Vec4, #[builtin(front_facing)] pub y: bool, #[location(1)] #[interpolate(flat)] pub z: u32 } pub struct MyOutputs { #[builtin(frag_depth)] pub x: f32, #[location(0)] pub y: vec4 } #[fragment] pub fn fragShader(in1: MyInputs) -> MyOutputs { // ... } ``` -------------------------------- ### Bulk Slab Read/Write for Structured Data Source: https://context7.com/schell/wgsl-rs/llms.txt Utilize `slab_read_array!` and `slab_write_array!` for efficient bulk copying of `u32` values between runtime arrays (slabs) and local fixed-size arrays. These macros expand to indexed loops for storage buffers in WGSL and element-by-element copies on the CPU. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::* #[wgsl] pub mod slab_demo { use wgsl_rs::std::*; pub struct Record { pub a: f32, pub b: u32, } impl Record { pub const SLAB_SIZE: usize = 2; pub fn from_array(arr: [u32; Self::SLAB_SIZE]) -> Self { Self { a: bitcast_f32(arr[0]), b: arr[1] } } pub fn to_array(r: Self) -> [u32; Self::SLAB_SIZE] { [bitcast_u32(r.a), r.b] } } storage!(group(0), binding(0), read_write, SLAB: RuntimeArray); #[compute] #[workgroup_size(32)] pub fn process(#[builtin(local_invocation_index)] idx: u32) { let offset = idx * Record::SLAB_SIZE as u32; let mut raw = Record::array_container(); // Read 2 u32s from the slab at `offset` slab_read_array!(get!(SLAB), offset, raw, Record::SLAB_SIZE); let mut rec = Record::from_array(raw); rec.b += 1; // Write back let out = Record::to_array(rec); slab_write_array!(get_mut!(SLAB), offset, out, Record::SLAB_SIZE); } } ``` -------------------------------- ### WGSL Built-in Function Mapping Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Illustrates how Rust function names are mapped to their corresponding WGSL built-in function names, especially for variadic functions. This mapping handles cases where WGSL built-ins have different names or behaviors based on parameters. ```rust texture_sample => textureSample texture_sample_array => textureSample texture_sample_array_offset => textureSample ``` -------------------------------- ### WGSL Numeric Builtin Roundtrip Tests Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Added a `roundtrip-tests` crate to validate GPU vs CPU coherence for core numeric builtins. Includes fixes for `fract` and `round` functions to match WGSL's behavior (using `floor` and rounding half to even, respectively). ```rust self - trunc(self) ``` ```rust self - floor(self) ``` -------------------------------- ### Numeric Builtin Pow/Step Implementation Note Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Highlights a specific implementation detail for numeric built-in functions like `pow` and `step`, involving converting glam vectors to arrays, performing operations, and converting back. This is a workaround for glam vectors not being iterators. ```rust See the implementations of `NumericBuiltinPow` and `NumericBuiltinStep` for an example of this. ``` -------------------------------- ### Access WGSL Specification with xtask Source: https://github.com/schell/wgsl-rs/blob/main/AGENTS.md Utilize `cargo xtask wgsl-spec` for interacting with the WGSL specification. Commands allow listing the table of contents, fetching sections with or without subsections, and retrieving specific subsections. ```bash cargo xtask wgsl-spec toc # List WGSL spec table of contents ``` ```bash cargo xtask wgsl-spec section # Fetch a spec section with subsections ``` ```bash cargo xtask wgsl-spec section --shallow # Fetch section without subsections ``` ```bash cargo xtask wgsl-spec section # Fetch a specific subsection ``` -------------------------------- ### WGSL Synchronization Builtin Functions Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Adds synchronization builtins like `storageBarrier()`, `workgroupBarrier()`, `textureBarrier()`, and `workgroupUniformLoad()`. These are no-ops on the CPU side. The `ptr!` macro is extended for `workgroup` address space. ```rust storageBarrier() ``` ```rust workgroupBarrier() ``` ```rust textureBarrier() ``` ```rust workgroupUniformLoad() ``` -------------------------------- ### Rust For-Loop to WGSL For-Loop Transpilation Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Shows how Rust for-loops with range syntax (e.g., 0..n, 0..=n) are transpiled to WGSL for-loops. Only bounded ranges are supported. Use #[wgsl_allow(non_literal_loop_bounds)] for non-literal bounds. ```rust for i in 0..n { // ... } for i in 0..=n { // ... } ``` -------------------------------- ### WGSL Shader Structs for Inputs and Outputs Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Define custom structs for shader inputs and outputs using #[location(...)] and #[builtin(...)] attributes. Corresponds to WGSL shader definitions. ```wgsl struct MyInputs { @location(0) x: vec4, @builtin(front_facing) y: bool, @location(1) @interpolate(flat) z: u32 } struct MyOutputs { @builtin(frag_depth) x: f32, @location(0) y: vec4 } @fragment fn fragShader(in1: MyInputs) -> MyOutputs { // ... } ``` -------------------------------- ### Transpile Rust Module to WGSL with #[wgsl] Source: https://context7.com/schell/wgsl-rs/llms.txt Apply the `#[wgsl]` macro to a Rust module to generate a `WGSL_MODULE` constant containing the WGSL source. Standalone modules are validated at compile time, while modules importing others are validated at test time. Use `#[wgsl(skip_validation)]` to opt out. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; // Standalone constants module — validated at compile time. #[wgsl] pub mod constants { pub const PI: f32 = 3.14159265; pub const TAU: f32 = 6.28318530; } // Shader that imports from constants — validated at test time. #[wgsl] pub mod circle_shader { use super::constants::*; pub fn circle_area(r: f32) -> f32 { PI * r * r } #[fragment] pub fn frag_main() -> Vec4f { // CPU side: runs normally let area = circle_area(1.0); // = PI vec4f(area / TAU, 0.0, 0.0, 1.0) } } fn main() { // Retrieve the concatenated WGSL source (constants + circle_shader) let source_lines = circle_shader::WGSL_MODULE.wgsl_source(); println!("{}", source_lines.join("\n")); // Output: // const PI: f32 = 3.14159265; // const TAU: f32 = 6.28318530; // fn circle_area(r:f32) -> f32 { return PI*r*r; } // @fragment fn frag_main() -> vec4 { ... } } ``` -------------------------------- ### Retrieve Full WGSL Source with Module::wgsl_source Source: https://context7.com/schell/wgsl-rs/llms.txt The `Module::wgsl_source()` method recursively collects and concatenates WGSL source lines from imported modules, ensuring each imported module appears only once. This is useful for inspecting the complete generated shader code. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod math_helpers { pub fn lerp(a: f32, b: f32, t: f32) -> f32 { a + (b - a) * t } } #[wgsl] pub mod gradient { use super::math_helpers::*; #[fragment] pub fn frag_main() -> Vec4f { let r = lerp(0.0, 1.0, 0.5); vec4f(r, 0.0, 0.0, 1.0) } } fn print_wgsl() { let lines = gradient::WGSL_MODULE.wgsl_source(); // math_helpers source appears first (import), then gradient source. for line in &lines { println!("{}", line); } } ``` -------------------------------- ### WGSL Bit Manipulation and Bitcast Roundtrip Tests Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Extended roundtrip tests for bit manipulation (clz, popcount, ctz, reverse_bits, etc.), scalar and vec4 bitcasts, and pack/unpack operations for 4x8 and 2x16 formats. ```rust firstLeadingBit(0xFFFFFFFF_u) ``` -------------------------------- ### Dispatch Workgroups for CPU Compute Shader Execution Source: https://context7.com/schell/wgsl-rs/llms.txt Use `dispatch_workgroups` to execute compute shaders on the CPU via a rayon thread pool. It's ideal for unit testing and allows for intra-workgroup parallelism with `workgroup_barrier` synchronization. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::* use wgsl_rs::std::runtime::{dispatch_workgroups, ComputeBuiltins}; #[wgsl] pub mod doubler { use wgsl_rs::std::*; storage!(group(0), binding(0), INPUT: [f32; 256]); storage!(group(0), binding(1), read_write, OUTPUT: [f32; 256]); #[compute] #[workgroup_size(64)] pub fn double_it(#[builtin(global_invocation_id)] gid: Vec3u) { let i = gid.x() as usize; get_mut!(OUTPUT)[i] = get!(INPUT)[i] * 2.0; } } #[test] fn test_doubler() { use doubler::*; let input: [f32; 256] = std::array::from_fn(|i| i as f32); INPUT.set(input); OUTPUT.set([0.0f32; 256]); // Dispatch 4 workgroups of 64 threads = 256 total invocations. dispatch_workgroups((4, 1, 1), (64, 1, 1), |b: ComputeBuiltins| { double_it(b.global_invocation_id); }); let out = get!(OUTPUT); for i in 0..256usize { assert!((out[i] - (i as f32 * 2.0)).abs() < 1e-5, "mismatch at {i}"); } } ``` -------------------------------- ### WGSL Pointer Type Support with ptr! Macro Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Use the `ptr!(address_space, T)` macro for WGSL pointer types in function parameters. Supports `function` and `private` address spaces. Expands to `&mut T` in Rust and `ptr` in WGSL. Dereferencing is supported. ```rust pub fn increment(p: ptr!(function, i32)) { *p += 1; } fn main() { let mut x: i32 = 5; increment(&mut x); // x is now 6 } ``` -------------------------------- ### Dispatch Fragments for CPU Fragment Shader Execution Source: https://context7.com/schell/wgsl-rs/llms.txt Execute fragment shaders on the CPU using `dispatch_fragments`, which processes invocations in 2x2 quads to support derivative builtins. It returns a nested vector representing the output, with `None` for discarded fragments. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::* use wgsl_rs::std::runtime::{dispatch_fragments, FragmentBuiltins}; #[wgsl] pub mod gradient_shader { use wgsl_rs::std::*; #[input] pub struct FragInput { #[location(0)] pub uv: Vec2f, } #[fragment] pub fn frag_main(input: FragInput) -> Vec4f { let depth = input.uv.x; if depth < 0.01 { discard!(); } // dpdx/dpdy work correctly because dispatch_fragments uses 2x2 quads. let edge = fwidth(input.uv.x); vec4f(input.uv.x, input.uv.y, edge, 1.0) } } #[test] fn test_gradient_shader() { use gradient_shader::*; let results = dispatch_fragments( 4, 4, |x, y| FragInput { uv: vec2f(x as f32 / 4.0, y as f32 / 4.0) }, |_builtins, input| frag_main(input), ); // Column 0 (uv.x == 0.0) is discarded; others produce output. assert!(results[0][0].is_none()); assert!(results[0][1].is_some()); let pixel = results[1][2].unwrap(); assert!((pixel.x - 2.0 / 4.0).abs() < 1e-5); assert!((pixel.y - 1.0 / 4.0).abs() < 1e-5); } ``` -------------------------------- ### WGSL Discard Statement Support with discard!() Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Provides the `discard!()` macro for the WGSL `discard` statement, used in fragment shaders. It transpiles to `discard;` and on the CPU side, suppresses fragment output without stopping execution. ```rust discard!() ``` -------------------------------- ### Define IO Structs for Shader Stages with wgsl-rs Source: https://context7.com/schell/wgsl-rs/llms.txt Use `#[output]` and `#[input]` to define structs for inter-stage communication. Fields can be annotated with WGSL attributes like `#[builtin(...)]`, `#[location(N)]`, `#[interpolate(type)]`, `#[blend_src(N)]`, and `#[invariant]`, which are emitted in WGSL and stripped from the Rust struct. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod staged_shader { use wgsl_rs::std::*; #[output] pub struct VertexOutput { #[builtin(position)] pub clip_pos: Vec4f, #[location(0)] pub color: Vec4f, #[location(1)] #[interpolate(flat)] pub material_id: u32, } // Transpiles to: // struct VertexOutput { // @builtin(position) clip_pos: vec4, // @location(0) color: vec4, // @location(1) @interpolate(flat) material_id: u32, // } #[input] pub struct FragmentInput { #[location(0)] pub color: Vec4f, #[builtin(front_facing)] pub is_front: bool, } #[vertex] pub fn vs_main(#[builtin(vertex_index)] vi: u32) -> VertexOutput { VertexOutput { clip_pos: vec4f(0.0, 0.0, 0.0, 1.0), color: vec4f(1.0, 0.5, 0.0, 1.0), material_id: 0, } } #[fragment] pub fn fs_main(input: FragmentInput) -> Vec4f { input.color } } ``` -------------------------------- ### WGSL Fragment Shader Input Structs Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Workaround for `#[fragment]` not stripping `#[builtin(...)]` from parameters. Use an `#[input]` struct with `#[builtin(position)]` on the field instead of a direct parameter attribute. ```rust #[input] struct Inputs { #[builtin(position)] position: vec4f, } ``` -------------------------------- ### WGSL RuntimeArray Support Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Enables `RuntimeArray` for WGSL runtime-sized arrays, typically used as the last field in storage buffer structs. On CPU, it's backed by `Vec`. ```rust RuntimeArray ``` -------------------------------- ### WGSL Pointer Types in Function Parameters with ptr! Source: https://context7.com/schell/wgsl-rs/llms.txt The ptr! macro defines WGSL pointer types in function parameters, expanding to &mut Type in Rust for in-place mutation and ptr in WGSL. Supported address spaces include function, private, and workgroup. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod ptr_demo { use wgsl_rs::std::*; // fn increment(p: ptr) { *p += 1; } pub fn increment(p: ptr!(function, i32)) { *p += 1; } // fn swap(a: ptr, b: ptr) { ... } pub fn swap(a: ptr!(function, f32), b: ptr!(function, f32)) { let tmp = *a; *a = *b; *b = tmp; } #[fragment] pub fn frag_main() -> Vec4f { let mut x: i32 = 5; increment(&mut x); // x == 6 let mut a = 1.0f32; let mut b = 2.0f32; swap(&mut a, &mut b); // a == 2.0, b == 1.0 vec4f(wgsl_rs::std::f32(x), a, b, 1.0) } } #[test] fn test_ptr_demo() { let result = ptr_demo::frag_main(); assert_eq!(result.x, 6.0); assert_eq!(result.y, 2.0); assert_eq!(result.z, 1.0); } ``` -------------------------------- ### Runtime WGSL Validation with Module::validate Source: https://context7.com/schell/wgsl-rs/llms.txt The `Module::validate()` method performs runtime validation of the concatenated WGSL source using naga. It returns `Ok(())` on success or an error string detailing any validation failures. This is useful for debugging or validating modules previously generated with `skip_validation`. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl(skip_validation)] pub mod experimental { pub fn untested_fn(x: f32) -> f32 { x * 2.0 } } fn check_experimental() { match experimental::WGSL_MODULE.validate() { Ok(()) => println!("WGSL is valid"), Err(e) => eprintln!("Validation error:\n{}", e), } } ``` -------------------------------- ### WGSL Atomic Types and Workgroup Variables Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Introduces `Atomic` for thread-safe operations and `workgroup!` macro for shared workgroup variables. `Atomic` maps to WGSL `atomic` and Rust's `std::sync::atomic`. `workgroup!` maps to WGSL `var`. ```rust workgroup!(NAME: TYPE) ``` -------------------------------- ### Disabling WGSL Validation Source: https://github.com/schell/wgsl-rs/blob/main/README.md Illustrates how to disable WGSL validation entirely by disabling the 'validation' feature in the `wgsl-rs` dependency within the `Cargo.toml` file. ```toml [dependencies] wgsl-rs = { version = "...", default-features = false } ``` -------------------------------- ### Suppressing Transpiler Warnings with `#[wgsl_allow]` Source: https://context7.com/schell/wgsl-rs/llms.txt Use `#[wgsl_allow(warning_name)]` on loop or match expressions to suppress specific transpiler warnings like `non_literal_loop_bounds` and `non_literal_match_statement_patterns`. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod allow_demo { use wgsl_rs::std::*; pub fn sum_to(n: i32) -> i32 { let mut total = 0i32; // Without #[wgsl_allow] this is a compile error: WGSL only supports // ascending iteration with known bounds. #[wgsl_allow(non_literal_loop_bounds)] for i in 0..n { total += i; } total } const LO: i32 = 0; const HI: i32 = 1; pub fn classify(level: i32) -> f32 { let mut result = 0.0f32; #[wgsl_allow(non_literal_match_statement_patterns)] match level { LO => { result = 0.0; } HI => { result = 1.0; } _ => {} } result } } #[test] fn test_allow_demo() { assert_eq!(allow_demo::sum_to(5), 10); // 0+1+2+3+4 assert_eq!(allow_demo::classify(1), 1.0); } ``` -------------------------------- ### WGSL Typed Literal Suffixes in Rust Source: https://github.com/schell/wgsl-rs/blob/main/DEVLOG.md Demonstrates an issue where typed literal suffixes like `0.0_f32` in Rust are emitted verbatim into WGSL, causing parse errors. Use plain literals like `0.0` instead. ```rust 0.0_f32 ``` -------------------------------- ### WGSL Type Aliases and Constants with #[repr(u32)] Enums Source: https://context7.com/schell/wgsl-rs/llms.txt Enums annotated with #[repr(u32)] transpile to WGSL 'alias' and 'const' declarations. Variants must have explicit non-negative integer discriminants. This allows enums to be used in storage buffers and other WGSL contexts. ```rust use wgsl_rs::wgsl; use wgsl_rs::std::*; #[wgsl] pub mod enum_demo { use wgsl_rs::std::*; #[repr(u32)] pub enum Material { Metal = 0, Wood = 1, Glass = 2, } // Transpiles to: // alias Material = u32; // const Material_Metal: u32 = 0u; // const Material_Wood: u32 = 1u; // const Material_Glass: u32 = 2u; storage!(group(0), binding(0), read_write, MATERIALS: [Material; 64]); #[compute] #[workgroup_size(64)] pub fn classify(#[builtin(global_invocation_id)] gid: Vec3u) { let idx = gid.x() as usize; let mat = &mut get_mut!(MATERIALS)[idx]; #[wgsl_allow(non_literal_match_statement_patterns)] match *mat { Material::Metal => { *mat = Material::Wood; } Material::Wood => { *mat = Material::Glass; } Material::Glass => { *mat = Material::Metal; } } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.