Vulkano: Long term issue: running Rust on the GPU

Created on 11 Jan 2017  路  7Comments  路  Source: vulkano-rs/vulkano

This issue is mostly notes.

Some IRC logs: https://botbot.me/mozilla/rustc/2017-01-11/?msg=79199876&page=1

Summary:

  • The GPU code would be written in Rust and embedded inside the regular CPU code.
  • There would be a vulkano plugin that extracts that GPU code and compiles it and turns it into SPIR-V through MIR or trans. The libraries from the Rust compiler repo would be used for the compilation (because we don't want to write a Rust compiler from scratch).
  • https://github.com/msiglreith/inspirv-rust is exactly that and would be a good starting point. It may even be possible to write a prototype today.
  • Isize/usize must be banned because the pointer width may differ between the CPU and the GPU. If you used an isize/usize, the struct layout wouldn't match.
  • Problem: even though all layouts are allowed on the GPU side, some are more optimized than others. We can't ask the user to write their structs in an optimized manner.
  • How do you handle panics?
  • Do not forget that users may want to recompile the GPU code at runtime. How do we do this? Embedding the compiler at runtime isn't a problem, but recompiling only the GPU code is.
hard help wanted enhancement

Most helpful comment

Hi, just stumbled upon this issue! (inspirv-rust author here)

Current state of inspirv:

Doing a larger refactoring to move towards rustc_trans as I got stuck on ICEs after updates to latest nightlies and didn't came up with a solution to fix them. Hoping that updates will be easier after the transition!

Issues with compiling Rust to SPIR-V

  • Output code might be not optimal, current existing optimizer (lunarglass) only returns GLSL code, which you need to translate again, but works.
  • Translating MIR to SPIR-V is difficult due to the need of structured control flow (https://github.com/msiglreith/inspirv-rust/issues/2)
  • Requires some restrictions for references. Current approach I'll implement is to disallow re-assigning references. Edit: not totally sure about this, need to do some testing!

I did some tests with running shaders written in Rust with vulkano and got the teapot example working with some minor changes.

Fragment shader code snippet (without feature annotations):

struct TeapotVarying {
    #[inspirv(location = 0)] v_normal: Float3,
    #[inspirv(builtin = "Position")]
    #[inspirv(location = 1)] position: Float4,
}

struct TeapotFragment {
    #[inspirv(location = 0)] f_color: Float4,
}

#[inspirv(entry_point = "fragment")]
fn main(fragment: Attributes<TeapotVarying>) -> TeapotFragment {
    let light = Float3::new(0.0, 1.0, 1.0);

    let brightness = fragment.v_normal.normalize().dot(light);
    let color = 0.6 + 0.4 * brightness;
    let color = Float3::new(color, 0.0, 0.0);

    TeapotFragment {
        f_color: Float4::from_3_1(color, 1.0),
    }
}

All 7 comments

Hi, just stumbled upon this issue! (inspirv-rust author here)

Current state of inspirv:

Doing a larger refactoring to move towards rustc_trans as I got stuck on ICEs after updates to latest nightlies and didn't came up with a solution to fix them. Hoping that updates will be easier after the transition!

Issues with compiling Rust to SPIR-V

  • Output code might be not optimal, current existing optimizer (lunarglass) only returns GLSL code, which you need to translate again, but works.
  • Translating MIR to SPIR-V is difficult due to the need of structured control flow (https://github.com/msiglreith/inspirv-rust/issues/2)
  • Requires some restrictions for references. Current approach I'll implement is to disallow re-assigning references. Edit: not totally sure about this, need to do some testing!

I did some tests with running shaders written in Rust with vulkano and got the teapot example working with some minor changes.

Fragment shader code snippet (without feature annotations):

struct TeapotVarying {
    #[inspirv(location = 0)] v_normal: Float3,
    #[inspirv(builtin = "Position")]
    #[inspirv(location = 1)] position: Float4,
}

struct TeapotFragment {
    #[inspirv(location = 0)] f_color: Float4,
}

#[inspirv(entry_point = "fragment")]
fn main(fragment: Attributes<TeapotVarying>) -> TeapotFragment {
    let light = Float3::new(0.0, 1.0, 1.0);

    let brightness = fragment.v_normal.normalize().dot(light);
    let color = 0.6 + 0.4 * brightness;
    let color = Float3::new(color, 0.0, 0.0);

    TeapotFragment {
        f_color: Float4::from_3_1(color, 1.0),
    }
}

Very interesting, also computational use.

Rust GPU compile at runtime seems a possible future enhancement. It is more rusty to precompile and let the tools do their work before distribution

Yeah I guess recompiling Rust at runtime would be too hard anyway.

If the link between the GPU code and CPU is put in its own module, and if Rust gets incremental compilation, then only the link would be recompiled if it changes, which would in theory lead to a very fast compile time.

What would the advantage of compiling Rust to SPIR-V be? The main problems Rust solves are memory and thread safety which as far as I'm aware are irrelevant when it comes to writing shaders.

Memory safety is not irrelevant. If you perform an out of bounds access in your shader, you will get a graphics reset (cc #356).

Thread safety is not irrelevant, because it's also easy to create a data race by not using atomic operations when you access memory shared between the work units.

GLSL is like C, in the sense that as long as you do everything correctly you're fine. But if you do one mistake you will get a bug that's likely going to be annoying/hard to debug.

I think that using the Rust compiler at runtime shouldn鈥檛 be a problem. Shaders are generally small, which means they are quick to compile.

The compiler is huge, though. I wouldn't want to ship it with my production game.

Also, probably want to use the LLVM SPIR-V backend.

Was this page helpful?
0 / 5 - 0 ratings