gfx-rs / wgpu

A cross-platform, safe, pure-Rust graphics API.
https://wgpu.rs
Apache License 2.0
12.7k stars 932 forks source link

Public Naga IR Builders #4654

Open therealbnut opened 1 year ago

therealbnut commented 1 year ago

Is your feature request related to a problem? Please describe. Hi,

I’d like to use Naga as an IR for a new shader language.

Describe the solution you'd like I can use Naga already without changes, although it would be nice to have builders for blocks, expressions, and types, that ensure the requirements of the types. This sort of thing already appears to partially exist in the various frontends/lowerings. Having shared builders might reduce the amount of repeated code, or make each frontend safer.

I’d prefer to use Naga as it’s already a dependency.

Describe alternatives you've considered I’ve considered making my own AST which is almost an exact copy of the WGSL one, but with utility functions for composing and relocating expressions. I would prefer not to have to maintain a fork, as the AST and utility methods are not public.

I’ve considered restricting myself to composing functions produced by Naga, using the existing IR (Module), although it doesn’t seem like Naga has anything for marking function calls as inlined, and I’d like an optimised output.

I’ve looked a fair bit for other people trying similar things, and haven’t found anything using Naga. It’s possible I missed something.

Additional context I’m happy to build it myself in a fork, but it would be a lot less work for me, and hopefully a lot more useful for others, if I made the changes in a way you’re happy with, and would want to merge.

mikialex commented 1 year ago

I have created my own Naga IR builder. I'm not sure if this is what you are searching for but I put it here for your reference.

In my graphics project, I define the shader logic by an EDSL-like API interface in https://github.com/mikialex/rendiation/tree/master/shader/api/src. By using this shader API, you could directly build a Naga module. The usage of this API, for example, can be found at https://github.com/mikialex/rendiation/blob/master/platform/graphics/webgpu/examples/compute101.rs https://github.com/mikialex/rendiation/blob/master/scene/webgpu/src/rendering/ssao.rs#L100

The only backend I support is Naga, the implementation is https://github.com/mikialex/rendiation/blob/master/shader/backends/naga/src/lib.rs

Actually, I had the same idea to create a new shader language but in the last, it overlapped greatly with the current wgsl design, so I just gave up and embraced the EDSL approach and translate to any backend representation through naga.

therealbnut commented 1 year ago

I'm not sure if this is what you are searching for but I put it here for your reference.

Thank you for sharing! I haven’t looked closely yet, but it sounds very interesting. I notice you haven’t got a license on the repo yet, do we have permission to include parts of the IR builder in Naga if they’re relevant?

I think the main remaining puzzle piece I want to solve is: if a lightweight and safe IR builder exists, could it be merged into Naga, reducing maintenance overheads and making Naga safer, therefore benefiting Naga internally and external projects that use Naga. I’m happy to maintain something suitable for my own needs, but would rather contribute it back.

@cwfitzgerald would the Naga project welcome a lightweight safer IR builder, exposed publicly and used internally? (Sorry if you’re not the right person to ask)

jimblandy commented 1 year ago

I can certainly imagine there being better ways to build modules than what our front ends do right now.

At the moment we can't take on maintenance of anything we're not actively using in our own front ends. So I think we would only be able to incorporate utilities if they were valuable enough in our existing front ends that we would want to have them in their own right.

In other words, if you can contribute a front end cleanup that doesn't hurt performance or build time, and that serves your needs as well, then we'd be happy to take that. But I understand that's a pretty high bar.

therealbnut commented 1 year ago

if you can contribute a front end cleanup that doesn't hurt performance or build time, and that serves your needs as well, then we'd be happy to take that.

Thanks for the clarification! That’s about what I was expecting. Is the performance consideration primarily what’s under the benches folder?

jimblandy commented 1 year ago

If we ignore stability issues, I would like Naga IR to be useful to third parties. What are the problems preventing your maintaining your builders as a separate crate (other than the obvious advantage that Naga developers would be responsible for updating them along with whatever other work they're doing)? If there's something we could make public that would unblock you, that's certainly something we're open to.

Naga IR has not been very stable, lately, though. And in general something as detailed as an IR is very hard to make stable at all.

jimblandy commented 1 year ago

Yes, the benches folder is a good place to start. Some of them are not working ATM; I had started working on that but got pulled off to deal with other things.

therealbnut commented 1 year ago

What are the problems preventing your maintaining your builders as a separate crate?

I was imagining something very lightweight that makes it easier to compose expressions, and resolve types, probably something for SSA form. I don’t believe there’s anything stopping me making builders for that. Although I thought if I do that I should ask if it could be helpful upstream and take your design constraints into consideration. It seemed when I started to make it that there was a lot of overlap with what’s already in each frontend, and those frontends have a bit of overlap between each other.

I’d be aiming to make any builders a net benefit, and any additional maintenance overheads for Naga devs would ideally be offset by reduced redundancy between frontends, and maybe having a builder that can be more stable than the thing it emits.

If there's something we could make public

My other thing was similar to what mikialex mentioned, that I could probably get away with using wgsl. If the AST was exposed that would get me a long way, but while that might be more in line with what you’d expect in a WGPU public api, I didn’t think it was something Naga would want to maintain a public api for. It’s also a little too stringly typed for what I want, iirc.

And in general something as detailed as an IR is very hard to make stable at all.

Yeah, I understand that, I don’t think that will be a problem for me. Although if you think this will make the maintenance burden of builders too high let me know. I expect the general structure of SSA, functions, blocks, statements, expressions, will stay pretty similar.

jimblandy commented 1 year ago

There's also the more subjective concern of "complexity". Our problem domain, driving modern GPUs, is ferociously hard already. Imagine someone who knows the problem domain, but is entirely new to Naga: how much time do they need to put in before they can use Naga productively?

therealbnut commented 1 year ago

I agree, although I’m not sure whether this was in relation to something specific (I may have misunderstood your point).

I imagine reducing complexity would be in favour of builders though, so a user of the IR doesn’t also have to understand the implementation details, how things are split up and referenced, stored, representation details like SSA, etc.

therealbnut commented 1 year ago

Perhaps it’s best, now I’ve got some guidelines, to just have a go, that way we have something more concrete to evaluate.

therealbnut commented 1 year ago

@jimblandy there's a relatively small diff to get the tests and benchmarks running without error. However I'm running them with hlsl-out and msl-out disabled. I think that should be enough for me to get a feel for performance regressions. Let me know if you want this patch as a PR.

The diff:

diff --git a/naga/benches/criterion.rs b/naga/benches/criterion.rs
index 697467faa..fdacefaee 100644
--- a/naga/benches/criterion.rs
+++ b/naga/benches/criterion.rs
@@ -28,6 +28,7 @@ fn gather_inputs(folder: &str, extension: &str) -> Vec<Box<[u8]>> {
     list
 }

+#[cfg(feature = "glsl-in")]
 fn parse_glsl(stage: naga::ShaderStage, inputs: &[Box<[u8]>]) {
     let mut parser = naga::front::glsl::Frontend::default();
     let options = naga::front::glsl::Options {
diff --git a/naga/tests/snapshots.rs b/naga/tests/snapshots.rs
index ed75805ae..4feb2199d 100644
--- a/naga/tests/snapshots.rs
+++ b/naga/tests/snapshots.rs
@@ -385,7 +385,7 @@ fn check_targets(
     }
 }

-#[cfg(feature = "spv-out")]
+#[cfg(all(feature = "deserialize", feature = "spv-out"))]
 fn write_output_spv(
     input: &Input,
     module: &naga::Module,

I'm running with:

cargo test -p naga --all-features
cargo bench -p naga --features="glsl-in,glsl-out,spv-in,spv-out,wgsl-in,wgsl-out,validate"