Convert Figma logo to code with AI

Rust-GPU logorust-gpu

🐉 Making Rust a first-class language and ecosystem for GPU shaders 🚧

1,112
32
1,112
30

Top Related Projects

🐉 Making Rust a first-class language and ecosystem for GPU shaders 🚧

12,901

A cross-platform, safe, pure-Rust graphics API.

4,579

Safe and rich Rust wrapper around the Vulkan API

1,597

The write-once-run-anywhere GPGPU library for Rust

Quick Overview

Rust-GPU is a project that enables developers to write GPU shaders in Rust. It provides a compiler backend and runtime support for compiling Rust code to SPIR-V, allowing for the creation of graphics and compute shaders using Rust's safety and expressiveness features.

Pros

  • Leverages Rust's safety features and powerful type system for GPU programming
  • Provides a more familiar and ergonomic environment for Rust developers to write shaders
  • Enables better integration between CPU and GPU code in Rust projects
  • Supports various graphics APIs through SPIR-V output

Cons

  • Still in early development, with potential stability and feature limitations
  • May have a steeper learning curve for developers not familiar with Rust
  • Limited ecosystem compared to more established shader languages
  • Performance implications compared to hand-optimized GLSL or HLSL shaders are not yet fully known

Code Examples

  1. Basic vertex shader:
#[spirv(vertex)]
pub fn main(
    #[spirv(vertex_index)] vert_id: i32,
    #[spirv(position)] out_pos: &mut Vec4,
) {
    let x = (vert_id - 1) % 2;
    let y = (vert_id - 1) / 2;
    *out_pos = Vec4::new(x as f32 * 2.0 - 1.0, y as f32 * 2.0 - 1.0, 0.0, 1.0);
}
  1. Simple fragment shader:
#[spirv(fragment)]
pub fn main(
    #[spirv(frag_coord)] frag_coord: Vec4,
    output: &mut Vec4,
) {
    let r = (frag_coord.x / 800.0) as f32;
    let g = (frag_coord.y / 600.0) as f32;
    *output = Vec4::new(r, g, 0.0, 1.0);
}
  1. Compute shader example:
#[spirv(compute(threads(64)))]
pub fn main(
    #[spirv(global_invocation_id)] id: UVec3,
    #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] data: &mut [f32],
) {
    let i = id.x as usize;
    if i < data.len() {
        data[i] *= 2.0;
    }
}

Getting Started

  1. Add rust-gpu to your Cargo.toml:

    [dependencies]
    spirv-std = "0.4"
    
    [build-dependencies]
    spirv-builder = "0.4"
    
  2. Create a build script (build.rs):

    use spirv_builder::{MetadataPrintout, SpirvBuilder};
    
    fn main() {
        SpirvBuilder::new("shader", "spirv-unknown-vulkan1.1")
            .print_metadata(MetadataPrintout::Full)
            .build()
            .unwrap();
    }
    
  3. Write your shader code in a separate crate and compile using the build script.

  4. Use the compiled SPIR-V in your main application with your preferred graphics API.

Competitor Comparisons

🐉 Making Rust a first-class language and ecosystem for GPU shaders 🚧

Pros of rust-gpu

  • More active development and frequent updates
  • Broader community support and contributions
  • Better documentation and examples for getting started

Cons of rust-gpu

  • Less stable API, more prone to breaking changes
  • Steeper learning curve for beginners
  • May require more setup and configuration

Code Comparison

rust-gpu:

#[spirv(compute(threads(64)))]
pub fn main(
    #[spirv(global_invocation_id)] id: glam::UVec3,
    #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] output: &mut [f32],
) {
    let i = id.x as usize;
    output[i] = id.x as f32;
}

Rust-GPU:

#[spirv(compute(threads(64)))]
pub fn main(
    #[spirv(global_invocation_id)] id: glam::UVec3,
    #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] output: &mut [f32],
) {
    let i = id.x as usize;
    output[i] = id.x as f32;
}

Both repositories aim to enable Rust for GPU programming, with similar syntax and functionality. The main differences lie in the project structure, maintenance, and community support rather than the core code itself.

12,901

A cross-platform, safe, pure-Rust graphics API.

Pros of wgpu

  • Cross-platform support for multiple graphics APIs (Vulkan, Metal, D3D12, WebGPU)
  • Higher-level abstraction, easier to use for general GPU programming tasks
  • More mature and widely adopted in the Rust ecosystem

Cons of wgpu

  • Less control over low-level GPU operations
  • Potentially higher overhead due to abstraction layer
  • Not specifically designed for Rust-to-GPU compilation

Code Comparison

wgpu example:

let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor { label: None });
{
    let mut render_pass = encoder.begin_render_pass(&RenderPassDescriptor {
        color_attachments: &[RenderPassColorAttachment {
            view: &view,
            resolve_target: None,
            ops: Operations {
                load: LoadOp::Clear(Color::GREEN),
                store: true,
            },
        }],
        depth_stencil_attachment: None,
    });
}

rust-gpu example:

#[spirv(fragment)]
pub fn main_fs(output: &mut Vec4) {
    *output = vec4(1.0, 0.0, 0.0, 1.0);
}

Note: The code examples showcase different levels of abstraction and use cases. wgpu focuses on general GPU programming, while rust-gpu is specifically for writing GPU shaders in Rust.

4,579

Safe and rich Rust wrapper around the Vulkan API

Pros of vulkano

  • More mature and stable project with a larger community
  • Provides a higher-level abstraction over Vulkan, simplifying development
  • Offers better documentation and examples for beginners

Cons of vulkano

  • Less flexible for advanced GPU programming compared to rust-gpu
  • May introduce some overhead due to its abstraction layer
  • Limited to Vulkan-specific functionality

Code Comparison

vulkano:

let device = vulkano::device::Device::new(
    physical,
    &vulkano::device::Features::none(),
    &vulkano::device::DeviceExtensions::none(),
    None,
).unwrap();

rust-gpu:

#[spirv(compute(threads(64)))]
pub fn main(
    #[spirv(global_invocation_id)] id: glam::UVec3,
    #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] data: &mut [f32],
) {
    let idx = id.x as usize;
    data[idx] *= 2.0;
}

The vulkano example shows device initialization, while the rust-gpu example demonstrates a compute shader function. rust-gpu allows writing GPU code directly in Rust, whereas vulkano provides a higher-level API for Vulkan operations.

1,597

The write-once-run-anywhere GPGPU library for Rust

Pros of emu

  • Focuses on high-level GPU programming abstractions
  • Supports multiple backends (CUDA, OpenCL, CPU)
  • Easier to learn for developers new to GPU programming

Cons of emu

  • Less mature and actively maintained compared to rust-gpu
  • Limited community support and ecosystem
  • May have performance overhead due to higher-level abstractions

Code Comparison

emu:

#[gpu_use]
fn add(a: f32, b: f32) -> f32 {
    a + b
}

rust-gpu:

#[spirv(compute(threads(64)))]
fn main(
    #[spirv(global_invocation_id)] id: glam::UVec3,
    #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] buffer: &mut [f32],
) {
    buffer[id.x as usize] += 1.0;
}

Summary

emu provides a higher-level abstraction for GPU programming, making it more accessible to developers new to the field. It supports multiple backends, offering flexibility in deployment. However, it may have performance overhead and lacks the maturity and community support of rust-gpu.

rust-gpu, on the other hand, offers a lower-level approach with direct SPIR-V generation, potentially providing better performance and closer integration with graphics APIs. It has a more active development community but may have a steeper learning curve for beginners.

The choice between the two depends on the specific project requirements, performance needs, and the developer's familiarity with GPU programming concepts.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

🐉 rust-gpu

Rust as a first-class language and ecosystem for GPU graphics & compute shaders

Build status Documentation

Current Status 🚧

Note: This project is still heavily in development and is at an early stage.

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

However, many things aren't implemented yet. That means that while being technically usable, this project is not yet production-ready.

Example

Sky shader

use glam::{Vec3, Vec4, vec2, vec3};

#[spirv(fragment)]
pub fn main(
    #[spirv(frag_coord)] in_frag_coord: &Vec4,
    #[spirv(push_constant)] constants: &ShaderConstants,
    output: &mut Vec4,
) {
    let frag_coord = vec2(in_frag_coord.x, in_frag_coord.y);
    let mut uv = (frag_coord - 0.5 * vec2(constants.width as f32, constants.height as f32))
        / constants.height as f32;
    uv.y = -uv.y;

    let eye_pos = vec3(0.0, 0.0997, 0.2);
    let sun_pos = vec3(0.0, 75.0, -1000.0);
    let dir = get_ray_dir(uv, eye_pos, sun_pos);

    // evaluate Preetham sky model
    let color = sky(dir, sun_pos);

    *output = tonemap(color).extend(1.0)
}

See source for full details.

Getting started

Check out The rust-gpu Dev Guide for information on how to get started with using it in your projects.

Experiment with rust-gpu shaders in-browser at SHADERed.

Getting help

For questions and comments, we use GitHub discussions to keep conversations organized and searchable. This also makes it easy to escalate relevant topics to GitHub issues if needed. We do not have an official chat room.

Background

Historically in games GPU programming has been done through writing either HLSL, or to a lesser extent GLSL and WGSL. These are simple programming languages that have evolved along with rendering APIs over the years. However, 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.

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!

Embark

This project was originally created and supported by the folks at Embark. We thank them for their foresight and contributions.

Embark wanted to streamline their 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 their (future) users, and fellow developers, to more rapidly build great looking and engaging experiences.

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.
  • Cargo and crates.io support to develop and publish SPIR-V crates

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.

Backwards compatibility, breaking changes and deprecation

Right now because the project is in an early state of development, we might introduce temporary changes as stop-gap measures, or implement features or APIs that might not work exactly in a way we end up liking. Therefore it is expected that some (if not most) of the user facing code will change and evolve over time. At the moment this means that we make no guarantees about backwards compatibility and have no formal deprecation model in place. Effectively meaning that currently we only support building from source with the latest main branch in our repository. We appreciate our early adopters and would ask them to evolve their code along with ours.

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.

Related Projects

Historical and other related projects for compiling Rust code to GPUs.

  • SPIR-V LLVM backend Compiles to OpenCL SPIR-V, which differs from Vulkan SPIR-V used by Rust GPU.
  • 2016: glassful Compiles a subset of Rust to GLSL.
  • 2017: inspirv-rust Experimental Rust to SPIR-V compiler.
  • 2018: nvptx Rust to PTX compiler.
  • 2020: accel GPGPU library for Rust.
  • 2020: rlsl Predeccesor to rust_gpu, Rust to SPIR-V compiler.
  • 2021: Rust CUDA Rust to PTX compiler, similar mechanism to rustc_codegen_spirv.
  • 2024 Embark transitions maintenance of rust-gpu to the open source community.

Contributing

Contributor Covenant

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.