Skip to content

Commit e71a44c

Browse files
committed
wgsl: add spirv-unknown-naga-wgsl target, transpiling with naga 29
1 parent e938af9 commit e71a44c

File tree

6 files changed

+236
-12
lines changed

6 files changed

+236
-12
lines changed

Cargo.lock

Lines changed: 72 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/rustc_codegen_spirv/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ itertools = "0.14.0"
6161
tracing.workspace = true
6262
tracing-subscriber.workspace = true
6363
tracing-tree = "0.4.0"
64+
naga = { version = "29.0.1", features = ["spv-in", "wgsl-out"] }
65+
strum = { version = "0.27.2", features = ["derive"] }
6466

6567
[dev-dependencies]
6668
pretty_assertions = "1.0"

crates/rustc_codegen_spirv/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ mod custom_decorations;
127127
mod custom_insts;
128128
mod link;
129129
mod linker;
130+
mod naga_transpile;
130131
mod spirv_type;
131132
mod spirv_type_constraints;
132133
mod symbols;

crates/rustc_codegen_spirv/src/link.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::maybe_pqp_cg_ssa as rustc_codegen_ssa;
33

44
use crate::codegen_cx::{CodegenArgs, SpirvMetadata};
55
use crate::linker;
6+
use crate::naga_transpile::should_transpile;
67
use crate::target::{SpirvTarget, SpirvTargetVariant};
78
use ar::{Archive, GnuBuilder, Header};
89
use rspirv::binary::Assemble;
@@ -319,6 +320,10 @@ fn post_link_single_module(
319320

320321
drop(save_modules_timer);
321322
}
323+
324+
if let Some(transpile) = should_transpile(sess) {
325+
transpile(sess, cg_args, &spv_binary, out_filename).ok();
326+
}
322327
}
323328

324329
fn do_spirv_opt(
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use crate::codegen_cx::CodegenArgs;
2+
use crate::target::{NagaTarget, SpirvTarget};
3+
use rustc_session::Session;
4+
use rustc_span::ErrorGuaranteed;
5+
use std::path::Path;
6+
7+
pub type NagaTranspile = fn(
8+
sess: &Session,
9+
cg_args: &CodegenArgs,
10+
spv_binary: &[u32],
11+
out_filename: &Path,
12+
) -> Result<(), ErrorGuaranteed>;
13+
14+
pub fn should_transpile(sess: &Session) -> Option<NagaTranspile> {
15+
let target = SpirvTarget::parse_target(sess.opts.target_triple.tuple())
16+
.expect("parsing should fail earlier");
17+
match target {
18+
SpirvTarget::Naga(NagaTarget::NAGA_WGSL) => Some(transpile::wgsl_transpile),
19+
_ => None,
20+
}
21+
}
22+
23+
mod transpile {
24+
use crate::codegen_cx::CodegenArgs;
25+
use naga::error::ShaderError;
26+
use naga::valid::Capabilities;
27+
use rustc_session::Session;
28+
use rustc_span::ErrorGuaranteed;
29+
use std::path::Path;
30+
31+
pub fn wgsl_transpile(
32+
sess: &Session,
33+
_cg_args: &CodegenArgs,
34+
spv_binary: &[u32],
35+
out_filename: &Path,
36+
) -> Result<(), ErrorGuaranteed> {
37+
// these should be params via spirv-builder
38+
let opts = naga::front::spv::Options::default();
39+
let capabilities = Capabilities::all();
40+
let writer_flags = naga::back::wgsl::WriterFlags::empty();
41+
42+
let module = naga::front::spv::parse_u8_slice(bytemuck::cast_slice(spv_binary), &opts)
43+
.map_err(|err| {
44+
sess.dcx().err(format!(
45+
"Naga failed to parse spv: \n{}",
46+
ShaderError {
47+
source: String::new(),
48+
label: None,
49+
inner: Box::new(err),
50+
}
51+
))
52+
})?;
53+
let mut validator =
54+
naga::valid::Validator::new(naga::valid::ValidationFlags::default(), capabilities);
55+
let info = validator.validate(&module).map_err(|err| {
56+
sess.dcx().err(format!(
57+
"Naga validation failed: \n{}",
58+
ShaderError {
59+
source: String::new(),
60+
label: None,
61+
inner: Box::new(err),
62+
}
63+
))
64+
})?;
65+
66+
let wgsl_dst = out_filename.with_extension("wgsl");
67+
let wgsl = naga::back::wgsl::write_string(&module, &info, writer_flags).map_err(|err| {
68+
sess.dcx()
69+
.err(format!("Naga failed to write wgsl : \n{err}"))
70+
})?;
71+
72+
std::fs::write(&wgsl_dst, wgsl).map_err(|err| {
73+
sess.dcx()
74+
.err(format!("failed to write wgsl to file: {err}"))
75+
})?;
76+
77+
Ok(())
78+
}
79+
}

0 commit comments

Comments
 (0)