Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
66 changes: 58 additions & 8 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -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`.
16 changes: 2 additions & 14 deletions examples/runners/ash/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 13 additions & 1 deletion examples/runners/wgpu/src/compute.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
//! This crate contains code to print the integer sequence at <https://oeis.org/A006877>:
//!
//! > 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;
Expand Down Expand Up @@ -252,14 +262,16 @@ 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 {
println!("{src}: overflowed");
break;
} else if out > max {
max = out;
// Should produce <https://oeis.org/A006877>
println!("{src}: {out}");
}
}
Expand Down
14 changes: 13 additions & 1 deletion examples/shaders/compute-shader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u32> {
let mut i = 0;
if n == 0 {
Expand All @@ -20,7 +31,8 @@ pub fn collatz(mut n: u32) -> Option<u32> {
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;
Expand Down
9 changes: 7 additions & 2 deletions examples/shaders/compute-shader/src/main.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,15 +18,15 @@ fn main() {
.map(collatz)
.collect::<Vec<_>>();
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 <https://oeis.org/A006877>
println!("{src}: {out}");
}
Some(_) => (),
Some(_) => {}
None => {
println!("{src}: overflowed");
break;
Expand Down