diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml new file mode 100644 index 0000000..62f638e --- /dev/null +++ b/.github/workflows/push.yaml @@ -0,0 +1,41 @@ +name: push + +on: + push: + branches: + - main + pull_request: + +env: + # For setup-rust, see https://github.com/moonrepo/setup-rust/issues/22 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + install-and-build-shaders: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash + env: + RUST_LOG: debug + steps: + - uses: actions/checkout@v2 + - uses: moonrepo/setup-rust@v1 + - run: rustup default stable + - run: rustup update + - run: cargo test + - run: cargo install --path crates/cargo-gpu + - run: cargo gpu install + - run: cargo gpu build --shader-crate crates/shader-crate-template --output-dir test-shaders + - run: ls -lah test-shaders + - run: cat test-shaders/manifest.json + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: moonrepo/setup-rust@v1 + - run: cargo clippy diff --git a/Cargo.lock b/Cargo.lock index 501e23e..e27864f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" @@ -134,7 +140,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.87", ] [[package]] @@ -206,6 +212,24 @@ dependencies = [ "wasi", ] +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" +dependencies = [ + "libm", +] + +[[package]] +name = "glam" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" +dependencies = [ + "libm", +] + [[package]] name = "hashbrown" version = "0.15.1" @@ -269,13 +293,19 @@ version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags", + "bitflags 2.6.0", "libc", ] @@ -298,6 +328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -370,6 +401,14 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +[[package]] +name = "rust-gpu-shader-crate-template" +version = "0.1.0" +dependencies = [ + "glam 0.29.2", + "spirv-std", +] + [[package]] name = "ryu" version = "1.0.18" @@ -393,7 +432,7 @@ checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.87", ] [[package]] @@ -429,12 +468,54 @@ dependencies = [ "toml", ] +[[package]] +name = "spirv-std" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c3c0972a2df79abe2c8af2fe7f7937a9aa558b6a1f78fc5edf93f4d480d757" +dependencies = [ + "bitflags 1.3.2", + "glam 0.24.2", + "num-traits", + "spirv-std-macros", + "spirv-std-types", +] + +[[package]] +name = "spirv-std-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f776bf9f2897ea7acff15d7753711fdf1693592bd7459a01c394262b1df45c" +dependencies = [ + "proc-macro2", + "quote", + "spirv-std-types", + "syn 1.0.109", +] + +[[package]] +name = "spirv-std-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a73417b7d72d95b4995c840dceb4e3b4bcbad4ff7f35df9c1655b6826c18d3a9" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.87" @@ -472,7 +553,7 @@ checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.87", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2c5db4b..7272a77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "crates/cargo-gpu", + "crates/shader-crate-template" ] exclude = [ diff --git a/crates/cargo-gpu/src/main.rs b/crates/cargo-gpu/src/main.rs index aab6d71..4f0a9ad 100644 --- a/crates/cargo-gpu/src/main.rs +++ b/crates/cargo-gpu/src/main.rs @@ -135,6 +135,15 @@ struct Spirv { channel: String, } +impl Default for Spirv { + fn default() -> Self { + Self { + dep: Self::DEFAULT_DEP.into(), + channel: Self::DEFAULT_CHANNEL.into(), + } + } +} + impl core::fmt::Display for Spirv { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { format!("{}+{}", self.dep, self.channel).fmt(f) @@ -142,12 +151,18 @@ impl core::fmt::Display for Spirv { } impl Spirv { + const DEFAULT_DEP: &str = r#"{ git = "https://github.com/Rust-GPU/rust-gpu.git" }"#; + const DEFAULT_CHANNEL: &str = "nightly-2024-04-24"; + /// Returns a string suitable to use as a directory. /// /// Created from the spirv-builder source dep and the rustc channel. fn to_dirname(&self) -> String { self.to_string() - .replace([std::path::MAIN_SEPARATOR, '.', ':', '@', '='], "_") + .replace( + [std::path::MAIN_SEPARATOR, '\\', '/', '.', ':', '@', '='], + "_", + ) .split(['{', '}', ' ', '\n', '"', '\'']) .collect::>() .concat() @@ -258,16 +273,13 @@ fn target_spec_dir() -> std::path::PathBuf { #[derive(Parser, Debug)] struct Install { /// spirv-builder dependency, written just like in a Cargo.toml file. - #[clap( - long, - default_value = r#"{ git = "https://github.com/Rust-GPU/rust-gpu.git" }"# - )] + #[clap(long, default_value = Spirv::DEFAULT_DEP)] spirv_builder: String, /// Rust toolchain channel to use to build `spirv-builder`. /// /// This must match the `spirv_builder` argument. - #[clap(long, default_value = "nightly-2024-04-24")] + #[clap(long, default_value = Spirv::DEFAULT_CHANNEL)] rust_toolchain: String, /// Force `spirv-builder-cli` and `rustc_codegen_spirv` to be rebuilt. @@ -312,6 +324,7 @@ impl Install { fn run(&self) -> (std::path::PathBuf, std::path::PathBuf) { // Ensure the cache dir exists let cache_dir = cache_dir(); + log::info!("cache directory is '{}'", cache_dir.display()); std::fs::create_dir_all(&cache_dir).unwrap_or_else(|e| { log::error!( "could not create cache directory '{}': {e}", @@ -381,12 +394,21 @@ impl Install { panic!("spirv-builder-cli build failed"); } - let cli_path = release.join("spirv-builder-cli"); + let cli_path = if cfg!(target_os = "windows") { + release.join("spirv-builder-cli").with_extension("exe") + } else { + release.join("spirv-builder-cli") + }; if cli_path.is_file() { log::info!("successfully built {}", cli_path.display()); std::fs::rename(&cli_path, &dest_cli_path).unwrap(); } else { log::error!("could not find {}", cli_path.display()); + log::debug!("contents of '{}':", release.display()); + for entry in std::fs::read_dir(&release).unwrap() { + let entry = entry.unwrap(); + log::debug!("{}", entry.file_name().to_string_lossy()); + } panic!("spirv-builder-cli build failed"); } } @@ -757,7 +779,7 @@ fn dump_full_usage_for_readme() { println!("{}", buffer); } -fn write_help(buffer: &mut impl std::io::Write, cmd: &mut clap::Command, depth: usize) { +fn write_help(buffer: &mut impl std::io::Write, cmd: &mut clap::Command, _depth: usize) { if cmd.get_name() == "help" { return; } @@ -774,7 +796,7 @@ fn write_help(buffer: &mut impl std::io::Write, cmd: &mut clap::Command, depth: for sub in cmd.get_subcommands_mut() { let _ = writeln!(buffer); - write_help(buffer, sub, depth + 1); + write_help(buffer, sub, _depth + 1); } } @@ -782,6 +804,23 @@ fn write_help(buffer: &mut impl std::io::Write, cmd: &mut clap::Command, depth: mod test { use super::*; + #[test] + fn cached_checkout_dir_sanity() { + // Test that + let spirv = Spirv::default(); + let dir = spirv.cached_checkout_path(); + let name = dir + .file_name() + .unwrap() + .to_str() + .map(|s| s.to_string()) + .unwrap(); + assert_eq!( + "git_https___github_com_Rust-GPU_rust-gpu_git+nightly-2024-04-24", + &name + ); + } + #[test] fn builder_from_params() { let shader_crate = std::path::PathBuf::from("../shader-crate-template"); diff --git a/crates/shader-crate-template/.gitignore b/crates/shader-crate-template/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/crates/shader-crate-template/.gitignore @@ -0,0 +1 @@ +/target diff --git a/crates/shader-crate-template/Cargo.lock b/crates/shader-crate-template/Cargo.lock new file mode 100644 index 0000000..d7a52c4 --- /dev/null +++ b/crates/shader-crate-template/Cargo.lock @@ -0,0 +1,123 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" +dependencies = [ + "libm", +] + +[[package]] +name = "glam" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480c9417a5dc586fc0c0cb67891170e59cc11e9dc79ba1c11ddd2c56ca3f3b90" +dependencies = [ + "libm", +] + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rust-gpu-shader-crate-template" +version = "0.1.0" +dependencies = [ + "glam 0.29.1", + "spirv-std", +] + +[[package]] +name = "spirv-std" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c3c0972a2df79abe2c8af2fe7f7937a9aa558b6a1f78fc5edf93f4d480d757" +dependencies = [ + "bitflags", + "glam 0.24.2", + "num-traits", + "spirv-std-macros", + "spirv-std-types", +] + +[[package]] +name = "spirv-std-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f776bf9f2897ea7acff15d7753711fdf1693592bd7459a01c394262b1df45c" +dependencies = [ + "proc-macro2", + "quote", + "spirv-std-types", + "syn", +] + +[[package]] +name = "spirv-std-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a73417b7d72d95b4995c840dceb4e3b4bcbad4ff7f35df9c1655b6826c18d3a9" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" diff --git a/crates/shader-crate-template/Cargo.toml b/crates/shader-crate-template/Cargo.toml new file mode 100644 index 0000000..5d62ebf --- /dev/null +++ b/crates/shader-crate-template/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "rust-gpu-shader-crate-template" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["rlib", "cdylib"] + +# Dependencies for CPU and GPU code +[dependencies] +spirv-std = { version = "0.9" } + +# dependencies for GPU code +[target.'cfg(target_arch = "spirv")'.dependencies] +glam = { version = "0.29", default-features = false, features = ["libm"] } + + +# dependencies for CPU code +[target.'cfg(not(target_arch = "spirv"))'.dependencies] +glam = { version = "0.29", features = ["std"] } + diff --git a/crates/shader-crate-template/README.md b/crates/shader-crate-template/README.md new file mode 100644 index 0000000..847967e --- /dev/null +++ b/crates/shader-crate-template/README.md @@ -0,0 +1,5 @@ +# shader-crate + +This is a shader crate that can be compiled to SPIR-V using `rust-gpu`. + +This crate can also be used from CPU Rust code, just like any other crate. diff --git a/crates/shader-crate-template/src/lib.rs b/crates/shader-crate-template/src/lib.rs new file mode 100644 index 0000000..e98f03d --- /dev/null +++ b/crates/shader-crate-template/src/lib.rs @@ -0,0 +1,42 @@ +//! Shader entry points. +//! +//! Contains an example vertex shader, fragment shader and one example compute +//! shader. +#![no_std] +use glam::{Vec2, Vec4}; +use spirv_std::spirv; + +pub const CLIP_SPACE_COORD_QUAD_CCW: [Vec4; 6] = { + let tl = Vec4::new(-1.0, 1.0, 0.5, 1.0); + let tr = Vec4::new(1.0, 1.0, 0.5, 1.0); + let bl = Vec4::new(-1.0, -1.0, 0.5, 1.0); + let br = Vec4::new(1.0, -1.0, 0.5, 1.0); + [bl, br, tr, tr, tl, bl] +}; + +pub const UV_COORD_QUAD_CCW: [Vec2; 6] = { + let tl = Vec2::new(0.0, 0.0); + let tr = Vec2::new(1.0, 0.0); + let bl = Vec2::new(0.0, 1.0); + let br = Vec2::new(1.0, 1.0); + [bl, br, tr, tr, tl, bl] +}; + +/// Vertex shader that renders an implicit quad. +#[spirv(vertex)] +pub fn vertex( + #[spirv(vertex_index)] vertex_id: u32, + out_uv: &mut Vec2, + #[spirv(position)] clip_pos: &mut Vec4, +) { + let index = vertex_id as usize % 6; + *out_uv = UV_COORD_QUAD_CCW[index]; + *clip_pos = CLIP_SPACE_COORD_QUAD_CCW[index]; +} + +/// Fragment shader that uses UV coords passed in from the vertex shader +/// to render a simple gradient. +#[spirv(fragment)] +pub fn fragment(in_uv: Vec2, frag_color: &mut Vec4) { + *frag_color = Vec4::new(in_uv.x, in_uv.y, 0.0, 1.0); +}