🐉 Making Rust a first-class language and ecosystem for GPU shaders 🚧
Go to file
2020-10-22 21:25:12 +02:00
.github Add bug report template (#93) 2020-10-22 14:34:05 +02:00
assets Add sky shader example code and screenshot to README (#83) 2020-10-21 21:42:49 +02:00
examples If statement (#98) 2020-10-22 16:22:17 +02:00
rfcs Simple RFC template, first go (#18) 2020-08-26 14:21:20 +02:00
rustc_codegen_spirv Fixed nested if statements (#88) 2020-10-22 13:29:33 +02:00
spirv-builder Move to a builder struct for spirv-builder (#59) 2020-10-14 15:48:21 +02:00
spirv-std Include example-shader in the workspace (#87) 2020-10-22 12:30:17 +02:00
.gitignore First try at spirv-builder 2020-10-09 17:22:07 +02:00
.mergify.yml Fix mergify branch 2020-10-22 21:25:12 +02:00
Cargo.lock Include example-shader in the workspace (#87) 2020-10-22 12:30:17 +02:00
Cargo.toml Include example-shader in the workspace (#87) 2020-10-22 12:30:17 +02:00
CODE_OF_CONDUCT.md Add license and CoC 2020-08-18 00:17:24 +02:00
CONTRIBUTING.md Document MCP process and add issue template (#80) 2020-10-22 12:43:05 +02:00
LICENSE-APACHE Add license and CoC 2020-08-18 00:17:24 +02:00
LICENSE-MIT Add license and CoC 2020-08-18 00:17:24 +02:00
README.md README tweaks for first release (#96) 2020-10-22 14:34:30 +02:00
rust-toolchain Start work on integrating linker 2020-09-11 13:09:06 +02:00
setup.bat Use the --component option in setup scripts (#104) 2020-10-22 21:20:42 +02:00
setup.sh Use the --component option in setup scripts (#104) 2020-10-22 21:20:42 +02:00

🐉 Rust GPU

Contributor Covenant Embark Embark

This is a very early stage project to make Rust a first-class language and ecosystem for building GPU code 🚀🚧

Current Status: v0.1

Compiling and running very simple shaders works, and a significant portion of the core library also compiles.

However, many things aren't implemented yet: for example, loops and switches aren't supported yet! That means that while being technically usable, this project is far from being production-ready.

Example

Sky shader

#[spirv(entry = "fragment")]
pub fn main_fs(input: Input<Vec4>, mut output: Output<Vec4>) {
    let dir: Vec3 = input.load().truncate();

    let cs_pos = Vec4(dir.0, -dir.1, 1.0, 1.0);
    let ws_pos = {
        let p = clip_to_world.mul_vec4(cs_pos);
        p.truncate() / p.3
    };
    let dir = (ws_pos - eye_pos).normalize();
    
    // evaluate Preetham sky model
    let color = sky(dir, sun_pos);

    output.store(color.extend(0.0))
}

See source for full details.

Background

Historically in games GPU programming has been done through writing either HLSL, or to a lesser extent GLSL. These are simple programming languages that have evolved along with rendering APIs over the years. However, as game engines have evolved, these languages have failed to provide mechanisms for dealing with large codebases, and have generally stayed behind the curve compared to other programming languages.

In part this is because it's a niche language for a niche market, and in part this has been because the industry as a whole has sunk quite a lot of time and effort into the status quo. While over-all better alternatives to both languages exist, none of them are in a place to replace HLSL or GLSL. Either because they are vendor locked, or because they don't support the traditional graphics pipeline. Examples of this include CUDA and OpenCL. And while attempts have been made to create language in this space, none of them have gained any notable traction in the gamedev community.

Our hope with this project is that we push the industry forward by bringing an existing, low-level, safe, and high performance language to the GPU; namely Rust. And with it come some additional benefits that can't be overlooked: a package/module system that's one of the industry's best, built in safety against race-conditions or out of bounds memory access, a wide range of tools and utilities to improve programmer workflows, and many others!

Why Embark?

At Embark, we've been building our own new game engine from the ground up in Rust. We have previous experience in-house developing the RLSL prototype, and we have a team of excellent rendering engineers that are familiar with the problems in current shading languages both from games, game engines and other industries. So, we believe we are uniquely positioned to attempt solving this problem.

We want to streamline our own internal development with a single great language, build an open source graphics ecosystem and community, facilitate code-sharing between GPU and CPU, and most importantly: to enable our (future) users, and fellow developers, to more rapidly build great looking and engaging experiences.

If we do this project right, one wouldn't necessarily need an entire team of rendering engineers to build a good looking game, instead one would simply use a few of the existing open-source crates that provide the graphical effects needed to create the experience you're after. Instead of sharing and copy'n'pasting snippets of TAA code on forum posts, one could simply find and use the right crates from crates.io.

Project scope

The scope of this overall project is quite broad, but is in multiple stages

  • rustc compiler backend to generate SPIR-V, plugging in via -Z codegen-backend.
  • Focus on Vulkan graphics shaders first, then after Vulkan compute shaders
  • Cargo and crates.io support to develop and publish SPIR-V crates
  • High-level render graph to take advantage of this, make it easy for users to develop and use rendering effects.

An in-depth exploration of our roadmap and milestones can be found here.

Process

We use this repo as a monorepo for everything related to the project: crates, tools, shaders, examples, tests, and design documents. This way, we can use issues and PRs covering everything in the same place, cross-reference stuff within the repo, as well as with other GitHub repos such as rspirv and Rust itself.

We meet weekly over a Discord call to discuss design and triage issues. Each meeting has an issue with agenda, links and minutes.

We have a #rust-gpu Discord channel for fast discussion and collaboration.

Structure

There are a few different components to this repo:

  • rfcs for in-depth discussion and specs.
  • rustc_codegen_spirv for the compiler itself.
  • spirv-std for GPU intrinsics, types, and other library items used by GPU crates.
  • spirv-builder for a convenient way of building a GPU crate in a CPU build.rs file.

Getting started

  1. Clone the repository.

  2. Install the prerequisites using the provided setup script. From the root of the project, run:

    MacOS, Linux:

    sh setup.sh
    

    Windows:

    setup.bat
    

    The setup script installs nightly Rust (required for now, see #78 for tracking issue).

  3. Install SPIRV-Tools and add it to your PATH (for now, eventually we will automatically build and link it instead of calling executables)

  4. Next, look at the examples folder. There are two projects here: examples/example-shader and examples/example-runner. The example-shader project is a "GPU crate", one that will be compiled to a SPIR-V module. The example-runner project is a normal, CPU crate that uses vulkan to consume the example-shader SPIR-V module to display a shader.

    Run the example:

    cargo run --bin example-runner
    

    This will build rustc_codegen_spirv, the compiler, then use that compiler to build example-shader into a SPIR-V module, then finally, build a vulkan sample app (taken from ash's examples) using the built SPIR-V module to display the shader in a window.

    All of this is orchestrated by the spirv-builder crate, which is used in example-runner's build.rs file. Please look at that file, as well as both example projects in general, to see how to set up your own shaders!

Be aware that this project is in a very early phase - if the above doesn't work, please file an issue!

Getting started, for power users who don't want to use spirv-builder.

If you would like to build the compiler, rustc_codegen_spirv is the relevant folder. Install the prerequisites, as above, then, cd rustc_codegen_spirv && cargo build. This produces an .so file, located at ./target/debug/librustc_codegen_spirv.so (or .dll/.dylib depending on your platform).

This file is a dynamically loaded backend for rustc - you may tell rustc to use it as a backend through the -Z codegen-backend=... flag. To pass this to rustc through cargo, set the environment variable RUSTFLAGS="-Z codegen-backend=$PATH_TO_FILE".

Then, when building a GPU crate, we need to configure some flags when we call cargo. First, we need to build libcore ourselves - we obviously have no SPIR-V libcore installed on our system! Use the flag -Z build-std=core. Then, we need to tell rustc to generate SPIR-V instead of x86 code: --target spirv-unknown-unknown.

Overall, building your own SPIR-V crate looks like:

export RUSTFLAGS="-Zcodegen-backend=$THIS_REPO/target/debug/librustc_codegen_spirv.so"
cargo build -Z build-std=core --target spirv-unknown-unknown --release

(with an appropriate path for $THIS_REPO, and replacing export with set if you're on windows as well as the proper dll name)

This will produce a target/spirv-unknown-unknown/release/crate_name.spv file.

To create a GPU crate, look at the examples/example-shader crate. In short, reference the spirv-std crate, and use intrinsics defined there to create your shader.

This is all a little convoluted, hence the spirv-builder crate handles a lot of this.

Contributing

We welcome community contributions to this project.

Please read our Contributor Guide for more information on how to get started.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.