Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for setting config in shader's Cargo.toml #34

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

tombh
Copy link
Contributor

@tombh tombh commented Jan 5, 2025

Managed to find quite an elegant solution where serde_json is doing all the heavy lifting. We even have automatic type checking on the config set in the shader crate's Cargo.toml!

Values are set in the TOML section: [package.metadata.rust-gpu.*].
So now the priority, from least to most, is:

  • Workspace metadata
  • Shader crate's metadata
  • CLI args

Fixes #15

Notable changes:

  • All clap args for the build and install subcommands are now
    defined in the spirv-builder-cli crate. This makes passing all the
    config between cargo gpu and spirv-builder-cli trivial as serde
    now does all the heavy lifting of creating and reading the JSON
    arguments.
  • There is no longer a toml subcommand. The shader crate's Cargo.tomls
    are always read and their configs used as the base for CLI args to
    override.

TODO:

@tombh
Copy link
Contributor Author

tombh commented Jan 6, 2025

I'll have a look at those failing tests tomorrow.

@tombh tombh changed the title Support all spirv builder config Support for setting config in shader's Cargo.toml Jan 6, 2025
@tombh tombh force-pushed the support-all-spirv-builder-config branch from 0e871d0 to 1bcaef6 Compare January 6, 2025 11:17
@tmvkrpxl0
Copy link

Neat, I actually have usecase for this. I need to enable some shader features.

@schell
Copy link
Collaborator

schell commented Jan 6, 2025

Great work!

I'm still a bit confused about the target and shader_target
arguments, are they both needed?

They don't have to both exist, but they have to boil down to the same thing (if I'm not mistaken) - we have to be able to determine the target specification file to give to SpirvBuilder. I guess it's difficult because we want to present all of SpirvBuilder's options, but it has two methods of specifying the target specification - the old way of taking the spirv spec (eg spirv-unknown-vulkan1.2) and the new way where we give it a path to a specification file explicitly.

That said, I don't think we'll ever use anything but the explicit path-to-specification-file method.

@schell
Copy link
Collaborator

schell commented Jan 6, 2025

Neat, I actually have usecase for this. I need to enable some shader features.

Yes! This is why we're prioritizing this work :)

@tombh tombh force-pushed the support-all-spirv-builder-config branch 2 times, most recently from 21d6294 to 0b738cd Compare January 6, 2025 22:06
@tombh
Copy link
Contributor Author

tombh commented Jan 6, 2025

Thanks!

So let's see if we can come to a conclusion about the old/new way of defining the target.

  • The old way is just about providing a target name that matches an existing target JSON file in the rust-gpu repo. The downside to that is that it limits the user, they can't provide their own target.
  • The new way allows specifying an arbitrary path. However, I notice that we still unconditionally do target_spec_dir()?.join(format!("{}.json", self.build.shader_target)), which means that an end user still can't provide their own absolute path. So it's currently effectively the same as the old way?

Ideally we want a little automation? For example something like, if the user doesn't provide an absolute path then we assume that the string is the name of an existing target that rust-gpu already has. And if the user provides a path then we just use the file that it points to. I could still be misunderstanding something though?

Either way I think we'll want something like cargo gpu show targets that lists the available known target names?

BTW I've also just pushed a little change that attempts to end-to-end test the changes by altering the output_dir = line in the shader-crate-template's Cargo.toml. But I think it's struggling with sed not being cross platform. Here's the justfile snippet:

cargo install --path crates/cargo-gpu
cargo gpu install --shader-crate crates/shader-crate-template --auto-install-rust-toolchain
sed -i 's/^output-dir =.*/output-dir = \/tmp\/testshaders/' crates/shader-crate-template/Cargo.toml
cargo gpu build --shader-crate crates/shader-crate-template
ls -lah /tmp/test-shaders

It seems a bit hacky. Can anybody think of another way? Like is there another config that we can change and detect in the final built shader?

Edit: the end-to-test is actually surfacing a bug! I think it's to do with - and _ in argument names 🤔

@tombh tombh force-pushed the support-all-spirv-builder-config branch 8 times, most recently from 67bf4a5 to bcd23c2 Compare January 9, 2025 18:30
@schell
Copy link
Collaborator

schell commented Jan 9, 2025

About defining a target - the new way is similar to the old way, but we control the paths at shader crate compile time, as opposed to them being hard coded at SpirvBuilder compile time to point to the target dir of the crate being built. So - yes, you're right that the user cannot supply their own target specification file (at least not without placing a new one into the blessed path in the cache directory).

But I think it would be easy enough to create one more option, something like --target-specification-file that would take precedence, and if it's omitted we construct the path from the target string and the target_spec_dir. That would cover all our bases, even though I think a user-supplied spec file will be very rare.

@schell
Copy link
Collaborator

schell commented Jan 9, 2025

Either way I think we'll want something like cargo gpu show targets that lists the available known target names?

I think that's a fine idea, I'll create an issue for that and we can tackle it after this?

@tombh tombh force-pushed the support-all-spirv-builder-config branch 5 times, most recently from 4d9b238 to 6eee8b3 Compare January 10, 2025 02:53
@tombh tombh force-pushed the support-all-spirv-builder-config branch from 6eee8b3 to 743cb3d Compare January 10, 2025 03:02
@tombh
Copy link
Contributor Author

tombh commented Jan 10, 2025

Okay, for now I've just hidden the --target argument (because SpirvBuilder::new() still needs a target string, maybe it can just be "" for now?), so then we just have the --shader-target argument. And we can add the --target-specification-file another time. Though spirv-builder::SpirvBuilder still has both the old and new "*target" arguments, but that's another repo, so maybe that should be discussed up there.

From my side this looks ready to merge, or at least ready to give a good testing to. I still want to add the cargo gpu show capabilities/extensions commands. But they don't strictly need to be included in this PR.

@tombh tombh force-pushed the support-all-spirv-builder-config branch from 743cb3d to 7564036 Compare January 10, 2025 14:44
tombh added 3 commits January 10, 2025 11:45
This is particularly useful when `--auto-install-rust-toolchain` is used
as the consent prompt isn't show and no indication at all of what's
happening was given.
Values are set in the TOML section: `[package.metadata.rust-gpu.*]`.
So now the priority, from least to most, is:
* Workspace metadata
* Shader crate's metadata
* CLI args

Fixes Rust-GPU#15

Notable changes:
* All `clap` args for the `build` and `install` subcommands are now
  defined in the `spirv-builder-cli` crate. This makes passing all the
  config between `cargo gpu` and `spirv-builder-cli` trivial as `serde`
  now does all the heavy lifting of creating and reading the JSON
  arguments.
* There is no longer a `toml` subcommand. The shader crate's `Cargo.toml`s
  are always read and their configs used as the base for CLI args to
  override.
@tombh tombh force-pushed the support-all-spirv-builder-config branch from 7564036 to cfdf4ed Compare January 10, 2025 14:47
@tombh
Copy link
Contributor Author

tombh commented Jan 10, 2025

I added the cargo gpu show capabilities command. I ended up just copy-pasting the spirv::Capability enum. It seems the only way to serialise an enum is with the strum crate's EnumIter derive macro, and that can't be added to external types. We could send a PR to https://github.com/gfx-rs/rspirv but it seems like it's not an active repo.

I also looked into a cargo gpu show extensions command, but there's no machine-readable source. So I think it's okay to just include the https://github.com/KhronosGroup/SPIRV-Registry link in the CLI help output.

@schell
Copy link
Collaborator

schell commented Jan 10, 2025

@tombh could we write a small wrapper over the enum just to provide our own (de)serialization? Would that be easier?

@tombh
Copy link
Contributor Author

tombh commented Jan 10, 2025

I'd love to! I'm not sure how though, do you have any ideas? spirv::Capabiltiies (the original type in the external crate) has #[derive(serde::serialize)] on it, so I feel like there should be a way. But I think the reality is just that serde can only serialize/deserialize specific values of an enum, not the the whole enum itself.

Another thing I tried was to type alias, making the external type internal, so type MyCapability = serde::Capability, which does work, but then derives can't be added to type aliases, namely, we need: #[derive(strum_macros::EnumIter)].

I'm very open to trying other ideas 🤓

Because our `spirv-builder-cli` can modify itself to comply with various
versions of `spirv-builder` from `rust-gpu`, then we also need to match
the version of `spirv` that we use to get `spirv::Capabilities`.

Namely that `rust-gpu <= v0.9.0` uses `spirv = "0.2.0"` and that
`rust-gpu >= "v0.9.0"` uses `spirv = "0.3.0".

Another solution to this could be to re-export `spirv` from `spirv-builder`.
But I'm not sure that would avoid compiling the entirety of `spirv-builder`
(which depends on specific Rust nightly versions), and besides, it's not
trivial to retroactively add re-exports to already-published version of
`rust-gpu`.
@tombh
Copy link
Contributor Author

tombh commented Jan 12, 2025

Found another bug and pushed the fix. Copypasting the new commit's message:

Feature-gate `gfx-rs/rspirv` dependency

Because our `spirv-builder-cli` can modify itself to comply with various
versions of `spirv-builder` from `rust-gpu`, then we also need to match
the version of `spirv` that we use to get `spirv::Capabilities`.

Namely that `rust-gpu <= v0.9.0` uses `spirv = "0.2.0"` and that
`rust-gpu >= "v0.9.0"` uses `spirv = "0.3.0".

Another solution to this could be to re-export `spirv` from `spirv-builder`.
But I'm not sure that would avoid compiling the entirety of `spirv-builder`
(which depends on specific Rust nightly versions), and besides, it's not
trivial to retroactively add re-exports to already-published version of
`rust-gpu`.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add more SpirvBuilder fields as cli arguments
3 participants