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
9 changes: 7 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ The runners:
[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.
- **CPU:** runs the shader code on the CPU, using rayon for parallelism.

Not all shaders work with all runners. The following combinations are
supported.
Expand Down Expand Up @@ -52,6 +51,12 @@ supported.
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).
- `cargo run --release -p example-runner-ash -- --shader=sky` also runs the sky shader.
- `cargo run --release -p example-runner-ash -- --shader=simplest` runs the simplest shader.
- `cargo run --release -p example-runner-ash -- --shader=mouse` runs the
mouse shader. The click-and-drag functionality is missing and the image
only animates on mouse or keyboard input, but it still is a useful example.
A pull request to fix these shortcomings would be welcome!

- CPU runner:
- `cargo run --release -p example-runner-cpu` runs the sky shader.
Expand Down
100 changes: 69 additions & 31 deletions examples/runners/ash/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,51 @@ use std::{
ffi::{CStr, CString},
fs::File,
os::raw::c_char,
path::PathBuf,
sync::mpsc::{TryRecvError, TrySendError, sync_channel},
thread,
};

use clap::Parser;
use clap::{Parser, ValueEnum};

use spirv_builder::{MetadataPrintout, SpirvBuilder};

use shared::ShaderConstants;

// This runner currently doesn't run the `compute` shader example.
#[derive(Debug, PartialEq, Eq, Copy, Clone, ValueEnum)]
pub enum RustGPUShader {
Simplest,
Sky,
Mouse,
}

impl RustGPUShader {
// The form with dashes, e.g. `sky-shader`.
fn crate_name(&self) -> &'static str {
match self {
RustGPUShader::Simplest => "simplest-shader",
RustGPUShader::Sky => "sky-shader",
RustGPUShader::Mouse => "mouse-shader",
}
}

// The form with underscores, e.g. `sky_shader`.
fn crate_ident(&self) -> &'static str {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably just be self.crate_name().replace("-", "_") (it's only used w/ format! AFAICT, so there's already an inherent string allocation cost anyway).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh, but it has to return a String, which would make it different to crate_name, and I have a follow-up that will eliminate this anyway. So I'll leave it as is.

match self {
RustGPUShader::Simplest => "simplest_shader",
RustGPUShader::Sky => "sky_shader",
RustGPUShader::Mouse => "mouse_shader",
}
}
}

#[derive(Debug, Parser)]
#[command()]
pub struct Options {
#[arg(short, long, default_value = "sky")]
shader: RustGPUShader,

/// Use Vulkan debug layer (requires Vulkan SDK installed)
#[arg(short, long)]
debug_layer: bool,
Expand All @@ -115,7 +147,7 @@ pub fn main() {
}

let options = Options::parse();
let shaders = compile_shaders();
let shaders = compile_shaders(&options.shader);

// runtime setup
let event_loop = EventLoop::new().unwrap();
Expand All @@ -138,17 +170,17 @@ pub fn main() {
for SpvFile { name, data } in shaders {
ctx.insert_shader_module(name, &data);
}

let crate_ident = options.shader.crate_ident();
ctx.build_pipelines(
vk::PipelineCache::null(),
vec![(
// HACK(eddyb) used to be `module: "sky_shader"` but we need `multimodule`
// for `debugPrintf` instrumentation to work (see `compile_shaders`).
VertexShaderEntryPoint {
module: "sky_shader::main_vs".into(),
module: format!("{crate_ident}::main_vs"),
entry_point: "main_vs".into(),
},
FragmentShaderEntryPoint {
module: "sky_shader::main_fs".into(),
module: format!("{crate_ident}::main_fs"),
entry_point: "main_fs".into(),
},
)],
Expand Down Expand Up @@ -203,7 +235,7 @@ pub fn main() {
let compiler_sender = compiler_sender.clone();
thread::spawn(move || {
if let Err(TrySendError::Disconnected(_)) =
compiler_sender.try_send(compile_shaders())
compiler_sender.try_send(compile_shaders(&options.shader))
{
panic!("compiler sender disconnected unexpectedly");
};
Expand Down Expand Up @@ -236,29 +268,34 @@ pub fn main() {
.unwrap();
}

pub fn compile_shaders() -> Vec<SpvFile> {
SpirvBuilder::new(
concat!(env!("CARGO_MANIFEST_DIR"), "/../../shaders/sky-shader"),
"spirv-unknown-vulkan1.1",
)
.print_metadata(MetadataPrintout::None)
.shader_panic_strategy(spirv_builder::ShaderPanicStrategy::DebugPrintfThenExit {
print_inputs: true,
print_backtrace: true,
})
// HACK(eddyb) needed because of `debugPrintf` instrumentation limitations
// (see https://github.com/KhronosGroup/SPIRV-Tools/issues/4892).
.multimodule(true)
.build()
.unwrap()
.module
.unwrap_multi()
.iter()
.map(|(name, path)| SpvFile {
name: format!("sky_shader::{name}"),
data: read_spv(&mut File::open(path).unwrap()).unwrap(),
})
.collect()
pub fn compile_shaders(shader: &RustGPUShader) -> Vec<SpvFile> {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let crate_path = [manifest_dir, "..", "..", "shaders", shader.crate_name()]
.iter()
.copied()
.collect::<PathBuf>();
let crate_ident = shader.crate_ident();

SpirvBuilder::new(crate_path, "spirv-unknown-vulkan1.1")
.print_metadata(MetadataPrintout::None)
.shader_panic_strategy(spirv_builder::ShaderPanicStrategy::DebugPrintfThenExit {
print_inputs: true,
print_backtrace: true,
})
// TODO: `multimodule` is no longer needed since
// https://github.com/KhronosGroup/SPIRV-Tools/issues/4892 was fixed, but removing it is
// non-trivial and hasn't been done et.
.multimodule(true)
.build()
.unwrap()
.module
.unwrap_multi()
.iter()
.map(|(name, path)| SpvFile {
name: format!("{crate_ident}::{name}"),
data: read_spv(&mut File::open(path).unwrap()).unwrap(),
})
.collect()
}

#[derive(Debug)]
Expand Down Expand Up @@ -685,6 +722,7 @@ pub struct RenderCtx {
pub recompiling_shaders: bool,
pub start: std::time::Instant,

// Only used for sky-shader.
// NOTE(eddyb) this acts like an integration test for specialization constants.
pub sky_fs_spec_id_0x5007_sun_intensity_extra_spec_const_factor: u32,
}
Expand Down Expand Up @@ -951,7 +989,7 @@ impl RenderCtx {
let framebuffer = self.framebuffers[present_index as usize];
let clear_values = [vk::ClearValue {
color: vk::ClearColorValue {
float32: [0.0, 0.0, 1.0, 0.0],
float32: [0.0, 1.0, 0.0, 0.0],
},
}];

Expand Down
Loading