Skip to content

Support for single-file host with shader compilation #659

Open

Description

@LiveDuo

Hey

I was looking for a way to compile a shader and its host code in a single file.

All examples I’ve seen so far require a separate shader crate.

The cuda-rust project appears to support it https://github.com/NVIDIA/cuda-rust/blob/main/cuda-oxide/crates/rustc-codegen-cuda/examples/vecadd/src/main.rs

Activity

  1. LiveDuo commented on Oct 4, 2026

    @LiveDuo
    Author

    The cuda-rust crate is seems to be one file because they use a custom CLI tool to build cargo oxide run vecadd which arguably is worse.

  2. Firestar99 commented on Oct 5, 2026

    @Firestar99
    Member

    To add to this, cubecl and cutile-rs also have single file support, but both are proc-macro based so can never support the "entirety of rustc".

    Putting both CPU and GPU code in one crate also has some disadvantages. Like, how do you declare dependencies and keep CPU and GPU dependencies separate? Like it can be done today but it's usually super ugly. So it's not just an implementation issue, but also a design issue.

    The best implementation of single crate I've seen so far is std::offload, at the expense of doing 3 separate rustc invocations. I'm personally interested in this approach and there may be a chance to get it's functionality general enough where it can be applied to rust-gpu as well. (But I likely won't have the time to implement it)

    It's all tradeoffs, all the way down...

  3. LiveDuo commented on Oct 5, 2026

    @LiveDuo
    Author

    Putting both CPU and GPU code in one crate also has some disadvantages. Like, how do you declare dependencies and keep CPU and GPU dependencies separate? Like it can be done today but it's usually super ugly. So it's not just an implementation issue, but also a design issue.

    In practise it might not be a big issue as most shaders are a few lines long without dependencies (at least with glsl and wglsl shaders). So it makes for an easy get started and later in the life of that project it can be separated into two crates.

    The best implementation of single crate I've seen so far is std::offload, at the expense of doing 3 separate rustc invocations. I'm personally interested in this approach and there may be a chance to get it's functionality general enough where it can be applied to rust-gpu as well. (But I likely won't have the time to implement it)

    The current implementation of std::offload does not seem to support different shaders (or any shaders given it's OpenMP) so there are a lot of different questions, like what happens with statics, are they accessible to both host and shader. Another issue is about imports that you mention earlier that might need to be behind #[cfg(target_arch = "spirv")]. But it's surely interesting to explore.

    I'm reopening the issue as others might finding it useful. Feel free to close if appropriate.

  4. reopened this on Oct 5, 2026
  5. Firestar99 commented on Oct 7, 2026

    @Firestar99
    Member

    most shaders are a few lines long without dependencies

    You do need to at least depend on spirv-std, and you need some way to declare which version of spirv-std since that also selects the version of rust-gpu cargo-gpu will install for you. We do reexport spirv_std::glam so at least you won't need an explicit glam dependency.

  6. LiveDuo commented on Oct 7, 2026

    @LiveDuo
    Author

    You do need to at least depend on spirv-std, and you need some way to declare which version of spirv-std since that also selects the version of rust-gpu cargo-gpu will install for you. We do reexport spirv_std::glam so at least you won't need an explicit glam dependency.

    I was thinking about this since your reply, and started considering a design. I haven't worked with rustc before so this is just speculating.

    But the idea is:

    • Build spirv-std in a cache folder directly (ie. ~/.cache/cargo-gpu/spirv-std/<version-hash>/) and build it with cargo build --target spirv-unknown-spv1.5.
    • Inject that folder into the shader's build via RUSTC_WRAPPER, by appending --extern spirv_std=<cached rlib> and -L dependency=<cached deps> so Cargo.toml stays untouched.

    Ofc I might be missing something obvious which invalidates the whole thing. But it can be tested on the current code independently before trying for single-file host.

  7. Firestar99 commented on Oct 7, 2026

    @Firestar99
    Member

    That sounds reasonable. You'd be loosing all capabilities that cargo gives you, but you're already fine trading that away. The biggest problem IMO is splitting shader code from CPU code, as shader code must not depend on std. And how this interacts with structs shared between both.

  8. nazar-pc commented on Oct 10, 2026

    @nazar-pc
    Contributor

    It is most certainly possible to do, just use standard conditional compilation tricks. The biggest annoyance is compiling host-side stuff twice, for which you simply add a feature like build-shader and make cargo-gpu-install conditional on that.

    Works quite well for me, standard idiomatic Rust, not sure how much else could be done to improve it beyond reducing build.rs-side boilerplate further (there is quite a bit right now).

    CUDA is a different model where host and guest code is intentionally mixed, while with rust-gpu you're simply producing SPIR-V, and how you run it (or whether you run it at all) is up to you.

    I think I prefer rust-gpu's approach, it makes it very clear where the boundary between CPU and GPU is and when you cross it is very explicit. Though I can also see the appeal of CUDA approach in its ease of use.

    Here is a complete example where shader and its host side is combined into a single crate, including the build-shader feature optimization I mentioned. I'll be building more of these in the future and do not plan for splitting them.

    Maybe worth having an example like this somewhere for people to mimic? I found existing examples, especially those in this repository, being quite involved and not very straightforward to follow.

  9. Firestar99 commented on Oct 12, 2026

    @Firestar99
    Member

    To complete the list, https://graphite.art/ has the raster-nodes crate that is also compiled for both CPU and GPU.

    For examples, I made minimal workspaces in rust-gpu-template a while ago and would add new examples and templates there. But I'm not sure if I'll have the time to make such a template rn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions