docs/src/writing-shader-crates.md
This is section is going to walk you through writing a shader in Rust and setting up your shader crate.
Be aware that this project is in a very early phase, please file an issue if there's something not working or unclear.
You can now test out and try building shaders with rust-gpu from the browser!
There are two main ways to setup your shader project locally.
spirv-builder crate.
The spirv-builder is a crate designed to automate the process of building
and linking the rust-gpu to be able to compile SPIR-V shaders into your
main Rust crate..cargo/config.
Alternatively if you're willing to do the setup yourself you can manually set
flags in your cargo configuration to enable you to run cargo build in your
shader crate.spirv-builderIf you're writing a bigger application and you want to integrate SPIR-V shader
crates to display, it's recommended to use spirv-builder in a build script.
rust-toolchain.toml file to your project. (You must use the same
version of Rust as rust-gpu. Utimately, the build will fail with a nice
error message when you don't use the exact same version)spirv-builder in your Cargo.toml:
[build-dependencies]
spirv-builder = "0.9"
build.rs in your project root.build.rsPaste the following into build.rs
use spirv_builder::{MetadataPrintout, SpirvBuilder};
fn main() -> Result<(), Box<dyn std::error::Error>> {
SpirvBuilder::new(shader_crate, target)
.print_metadata(MetadataPrintout::Full)
.build()?;
Ok(())
}
Substituting shader_crate with a relative path to your shader crate. The values available for the target parameter are available
here. For example, if building for vulkan 1.1, use
"spirv-unknown-vulkan1.1".
The SpirvBuilder struct has numerous configuration options available, see
documentation.
main.rsThe following will directly include the shader module binary into your application.
const SHADER: &[u8] = include_bytes!(env!("<shader_crate>.spv"));
Note If your shader name contains hyphens, the name of environment variable will be the name with hyphens changed to underscores.
Keep in mind that by default, build-dependencies are built in debug mode. This
means that the rust-gpu compiler (rustc_codegen_spirv) will be built in debug
mode, and will be incredibly slow. You can solve this by placing this bit of
configuration in your workspace Cargo.toml:
# Compile build-dependencies in release mode with
# the same settings as regular dependencies.
[profile.release.build-override]
opt-level = 3
codegen-units = 16
[profile.dev.build-override]
opt-level = 3
Keep in mind this will optimize all build script dependencies as release, which may slow down full rebuilds a bit. Please read this issue for more information, there's a few important caveats to know about this.
.cargo/configNote This method will require manually rebuilding
rust-gpueach time there has been changes to the repository.
If you just want to build a shader crate, and don't need to automatically
compile the SPIR-V binary at build time, you can use .cargo/config to set the
necessary flags. Before you can do that however you need to do a couple of steps
first to build the compiler backend.
rust-gpu repositorycargo build --release in rust-gpu.Now you should have a librustc_codegen_spirv dynamic library available in
target/release. You'll need to keep this somewhere stable that you can
reference from your shader project.
Now we need to add our .cargo/config file. This is a configuration file that
tells cargo how to build for SPIR-V. You need provide the target you're
compiling for (see platform support) and provide a path
to your built rustc_codegen_spirv dynamic library. We have to also provide
some additional options.
[build]
target = "spirv-unknown-spv1.3"
rustflags = [
"-Zcodegen-backend=<path_to_librustc_codegen_spirv>",
"-Zbinary-dep-depinfo",
"-Csymbol-mangling-version=v0",
"-Zcrate-attr=feature(register_tool)",
"-Zcrate-attr=register_tool(rust_gpu)"
]
[unstable]
build-std=["core"]
build-std-features=["compiler-builtins-mem"]
Now we can build our crate with cargo as normal.
cargo build
Now you should have <project_name>.spv SPIR-V file in target/debug that you
can give to a renderer.
Configure your shader crate as a "dylib" type crate, and add spirv-std to its dependencies:
[lib]
crate-type = ["dylib"]
[dependencies]
spirv-std = { version = "0.9" }
Make sure your shader code uses the no_std attribute and makes the spirv attribute visibile in the global scope. Then, you're ready to write your first shader. Here's a very simple fragment shader called main_fs as an example that outputs the color red:
#![no_std]
use spirv_std::spirv;
use spirv_std::glam::{vec4, Vec4};
#[spirv(fragment)]
pub fn main_fs(output: &mut Vec4) {
*output = vec4(1.0, 0.0, 0.0, 1.0);
}