From 99662f250760373c2bd0af45d0ec4ebfc70f5c86 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 19 Sep 2025 13:25:42 +1000 Subject: [PATCH 1/4] Improve the documentation of the compute shader example. Also make it include `1` in the output sequence, because that is the first number according to https://oeis.org/A006877. --- examples/runners/wgpu/src/compute.rs | 14 +++++++++++++- examples/shaders/compute-shader/src/lib.rs | 14 +++++++++++++- examples/shaders/compute-shader/src/main.rs | 9 +++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/examples/runners/wgpu/src/compute.rs b/examples/runners/wgpu/src/compute.rs index 3bf624865c..8dfa8308a2 100644 --- a/examples/runners/wgpu/src/compute.rs +++ b/examples/runners/wgpu/src/compute.rs @@ -1,3 +1,13 @@ +//! This crate contains code to print the integer sequence at : +//! +//! > In the '3x+1' problem, these values for the starting value set new records for number of +//! > steps to reach 1. +//! +//! each starting value is paired with the number of steps to reach 1 (a.k.a the "Collatz +//! sequence length"). +//! +//! The individual Collatz sequence lengths are computed via a computer shader on the GPU. + use crate::{CompiledShaderModules, Options, maybe_watch}; use std::time::Duration; @@ -252,6 +262,9 @@ async fn start_internal(options: &Options, compiled_shader_modules: CompiledShad drop(data); readback_buffer.unmap(); + // Our `max` computation excludes `1`, so print that manually as the first number in the + // sequence. + println!("1: 0"); let mut max = 0; for (src, out) in src_range.zip(result.iter().copied()) { if out == u32::MAX { @@ -259,7 +272,6 @@ async fn start_internal(options: &Options, compiled_shader_modules: CompiledShad break; } else if out > max { max = out; - // Should produce println!("{src}: {out}"); } } diff --git a/examples/shaders/compute-shader/src/lib.rs b/examples/shaders/compute-shader/src/lib.rs index b57bdd5d26..4bba286bc7 100644 --- a/examples/shaders/compute-shader/src/lib.rs +++ b/examples/shaders/compute-shader/src/lib.rs @@ -7,6 +7,17 @@ use spirv_std::{glam, spirv}; // Adapted from the wgpu hello-compute example +/// Returns the length of the Collatz sequence (excluding the starting number) for `n`. Returns +/// `None` if (a) `n` is zero, or (b) a number in the sequence overflows a `u32`. +/// +/// # Examples +/// +/// The sequence for 3 (excluding the starting number) is `[10, 5, 16, 8, 4, 2, 1]`, which has +/// length 7. +/// ``` +/// # use compute_shader::collatz; +/// assert_eq!(collatz(3), Some(7)); +/// ``` pub fn collatz(mut n: u32) -> Option { let mut i = 0; if n == 0 { @@ -20,7 +31,8 @@ pub fn collatz(mut n: u32) -> Option { if n >= 0x5555_5555 { return None; } - // TODO: Use this instead when/if checked add/mul can work: n.checked_mul(3)?.checked_add(1)? + // TODO: Use this instead when/if checked add/mul can work: + // n.checked_mul(3)?.checked_add(1)? 3 * n + 1 }; i += 1; diff --git a/examples/shaders/compute-shader/src/main.rs b/examples/shaders/compute-shader/src/main.rs index 104cf9a26f..594236aa12 100644 --- a/examples/shaders/compute-shader/src/main.rs +++ b/examples/shaders/compute-shader/src/main.rs @@ -1,3 +1,8 @@ +//! Code for running the Collatz problem on the CPU. See the wgpu compute runner +//! for the equivalent GPU code. +//! +//! Currently it's not actually built or tested, and is just here for reference. + use std::time::Instant; use compute_shader::collatz; @@ -13,15 +18,15 @@ fn main() { .map(collatz) .collect::>(); let took = start.elapsed(); + println!("1: 0"); let mut max = 0; for (src, out) in src_range.zip(result.iter().copied()) { match out { Some(out) if out > max => { max = out; - // Should produce println!("{src}: {out}"); } - Some(_) => (), + Some(_) => {} None => { println!("{src}: overflowed"); break; From 32667ead6e01f872b8843d1a2ad94dde0d0b6148 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 19 Sep 2025 14:40:48 +1000 Subject: [PATCH 2/4] Change the intensity keys in the sky-on-shader example. Currently you can use '+'/'-' on the numeric keypad to adjust the intensity, but lots of keyboards lack a numeric keypad. This commit changes it to use the up and down arrows instead. --- examples/runners/ash/src/main.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/examples/runners/ash/src/main.rs b/examples/runners/ash/src/main.rs index 0e67ec7c22..f7beae0aee 100644 --- a/examples/runners/ash/src/main.rs +++ b/examples/runners/ash/src/main.rs @@ -210,22 +210,10 @@ pub fn main() { }); } } - _ => {} - }, - WindowEvent::KeyboardInput { - event: - winit::event::KeyEvent { - physical_key: winit::keyboard::PhysicalKey::Code(key_code), - state: winit::event::ElementState::Pressed, - .. - }, - .. - } => match key_code { - winit::keyboard::KeyCode::NumpadAdd - | winit::keyboard::KeyCode::NumpadSubtract => { + winit::keyboard::NamedKey::ArrowUp | winit::keyboard::NamedKey::ArrowDown => { let factor = &mut ctx.sky_fs_spec_id_0x5007_sun_intensity_extra_spec_const_factor; - *factor = if key_code == winit::keyboard::KeyCode::NumpadAdd { + *factor = if key == winit::keyboard::NamedKey::ArrowUp { factor.saturating_add(1) } else { factor.saturating_sub(1) From 46dcfc7ffa6ac9c9842d7958fecd5dbe60d62120 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 22 Sep 2025 08:43:46 +1000 Subject: [PATCH 3/4] Change examples link in the main README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 06aa72266a..056561f8a4 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ pub fn main( } ``` -See [source](examples/shaders/sky-shader/src/lib.rs) for full details. +See [the examples](examples/) for full details. ## Getting started From a373bdc9bb82829d39538fda82b320321f1c7cd9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 19 Sep 2025 14:22:27 +1000 Subject: [PATCH 4/4] Improve examples documentation. Better explain the shaders and runners, and explain how to invoke them, and even document the `+`/`-` feature of the sky shader on ash, which is currently invisible unless you read the code. --- examples/README.md | 66 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/examples/README.md b/examples/README.md index 61931ced5b..73762867c3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,10 +1,60 @@ # Examples -The examples here are split into a few categories: - -- The shaders folder contain various rust-gpu shaders, and are examples of how to use rust-gpu. -- The runners folder contains programs that build and execute the shaders in the shaders folder using, for example, - Vulkan. These programs are not exactly examples of how to use rust-gpu, as they're rather generic vulkan sample apps, - but they do contain some infrastructure examples of how to integrate rust-gpu shaders into a build system (although - both aren't the cleanest of examples, as they're also testing some of the more convoluted ways of consuming rust-gpu). -- Finally, the multibuilder folder is a very short sample app of how to use the `multimodule` feature of `spirv-builder`. +This directory contains several examples of rust-gpu use. There are shader +examples in `shaders`, and runner programs that build and execute the shaders +in a variety of ways in `runners`. + +The shaders: +- **sky:** draws a landscape with a small white sun, blue sky, and yellow + ground. This is the default shader. +- **simplest:** draws a red triangle on a green background. +- **mouse:** a swirling animation that can be influenced by clicking and + dragging the mouse cursor. +- **compute:** a compute shader that prints a sequence of integers from the + '3x+1' problem. + +The runners: +- **WGPU:** runs the shader code on the GPU using [wgpu](https://wgpu.rs), a + graphics crate based on WebGPU. +- **WGPU+wasm:** like WGPU but runs in a web browser using + [wasm](https://webassembly.org/). +- **ash:** runs the shader code on the GPU using + [ash](https://crates.io/crates/ash), a Vulkan wrapper crate for Rust. +- **CPU:** runs the shader code directly on the CPU, using rayon for + parallelism. + +Not all shaders work with all runners. The following combinations are +supported. + +- WGPU runner: + - `cargo run --release -p example-runner-wgpu` runs the sky shader. + - `cargo run --release -p example-runner-wgpu -- --shader=sky` also runs the + sky shader. + - `cargo run --release -p example-runner-wgpu -- --shader=simplest` runs the + simplest shader. + - `cargo run --release -p example-runner-wgpu -- --shader=mouse` runs the + mouse shader. + - `cargo run --release -p example-runner-wgpu -- --shader=compute` runs the + compute shader. + +- WGPU+wasm runner in the browser (requires browser WebGPU support, most + recently tested with Chromium 140 on Linux): + - `rustup target add wasm32-unknown-unknown` installs the necessary wasm + support for Rust. + - `cargo run-wasm -p example-runner-wgpu` runs the local server hosting the + mouse shader. + - `chromium --enable-unsafe-webgpu http://localhost:8000` runs Chromium with + WebGPU enabled and views the mouse shader. (The mouse shader is the default + on WGPU+wasm.) + +- ash runner: + - `cargo run --release -p example-runner-ash` runs the sky shader. Use the up and + down arrows to adjust the sun's intensity. Use F5 to recompile the shader + code (but note that the image won't redraw afterwards unless the intensity is + adjusted). + +- CPU runner: + - `cargo run --release -p example-runner-cpu` runs the sky shader. + +Finally, the `multibuilder` folder is a very short example of how to use the +`multimodule` feature of `spirv-builder`.