1
1
//! naga transpiling to wgsl support, hidden behind feature `naga`
2
2
3
- use crate :: linkage:: spv_entry_point_to_wgsl;
4
3
use anyhow:: Context as _;
5
4
use naga:: error:: ShaderError ;
6
5
pub use naga:: valid:: Capabilities ;
7
- use spirv_builder:: { CompileResult , ModuleResult } ;
8
- use std:: collections:: BTreeMap ;
6
+ use naga:: valid:: ModuleInfo ;
7
+ use naga:: Module ;
8
+ use spirv_builder:: { CompileResult , GenericCompileResult } ;
9
9
use std:: path:: { Path , PathBuf } ;
10
10
11
+ /// Naga [`Module`] with [`ModuleInfo`]
12
+ #[ derive( Clone , Debug ) ]
13
+ #[ expect(
14
+ clippy:: exhaustive_structs,
15
+ reason = "never adding private members to this struct"
16
+ ) ]
17
+ pub struct NagaModule {
18
+ /// path to the original spv
19
+ pub spv_path : PathBuf ,
20
+ /// naga shader [`Module`]
21
+ pub module : Module ,
22
+ /// naga [`ModuleInfo`] from validation
23
+ pub info : ModuleInfo ,
24
+ }
25
+
11
26
/// convert a single spv file to a wgsl file using naga
12
- fn spv_to_wgsl ( spv_src : & Path , wgsl_dst : & Path , capabilities : Capabilities ) -> anyhow:: Result < ( ) > {
13
- let inner = || -> anyhow:: Result < ( ) > {
27
+ fn parse_spv ( spv_src : & Path , capabilities : Capabilities ) -> anyhow:: Result < NagaModule > {
28
+ let inner = || -> anyhow:: Result < _ > {
14
29
let spv_bytes = std:: fs:: read ( spv_src) . context ( "could not read spv file" ) ?;
15
30
let opts = naga:: front:: spv:: Options :: default ( ) ;
16
31
let module = naga:: front:: spv:: parse_u8_slice ( & spv_bytes, & opts)
@@ -30,69 +45,68 @@ fn spv_to_wgsl(spv_src: &Path, wgsl_dst: &Path, capabilities: Capabilities) -> a
30
45
inner : Box :: new ( err) ,
31
46
} )
32
47
. context ( "validation of naga module failed" ) ?;
33
- let wgsl =
34
- naga :: back :: wgsl :: write_string ( & module, & info , naga :: back :: wgsl :: WriterFlags :: empty ( ) )
35
- . context ( "naga conversion to wgsl failed" ) ? ;
36
- std :: fs :: write ( wgsl_dst , wgsl ) . context ( "failed to write wgsl file" ) ? ;
37
- Ok ( ( ) )
48
+ Ok ( NagaModule {
49
+ module,
50
+ info ,
51
+ spv_path : PathBuf :: from ( spv_src ) ,
52
+ } )
38
53
} ;
39
- inner ( ) . with_context ( || {
40
- format ! (
41
- "converting spv '{}' to wgsl '{}' failed " ,
42
- spv_src. display( ) ,
43
- wgsl_dst. display( )
44
- )
45
- } )
46
- }
47
-
48
- /// convert spv file path to a valid unique wgsl file path
49
- fn wgsl_file_name ( path : & Path ) -> PathBuf {
50
- path. with_extension ( "wgsl" )
54
+ inner ( ) . with_context ( || format ! ( "parsing spv '{}' failed" , spv_src. display( ) ) )
51
55
}
52
56
53
57
/// Extension trait for naga transpiling
54
58
pub trait CompileResultNagaExt {
55
- /// Transpile the spirv binaries to wgsl source code using [`naga`], typically for webgpu compatibility.
56
- ///
57
- /// Converts this [`CompileResult`] of spirv binaries and entry points to a [`CompileResult`] pointing to wgsl source code files and their associated wgsl entry
58
- /// points.
59
+ /// Transpile the spirv binaries to some other format using [`naga`].
59
60
///
60
61
/// # Errors
61
62
/// [`naga`] transpile may error in various ways
62
- fn transpile_to_wgsl ( & self , capabilities : Capabilities ) -> anyhow:: Result < CompileResult > ;
63
+ fn naga_transpile ( & self , capabilities : Capabilities ) -> anyhow:: Result < NagaTranspile > ;
63
64
}
64
65
65
66
impl CompileResultNagaExt for CompileResult {
66
67
#[ inline]
67
- fn transpile_to_wgsl ( & self , capabilities : Capabilities ) -> anyhow:: Result < CompileResult > {
68
- Ok ( match & self . module {
69
- ModuleResult :: SingleModule ( spv) => {
70
- let wgsl = wgsl_file_name ( spv) ;
71
- spv_to_wgsl ( spv, & wgsl, capabilities) ?;
72
- let entry_points = self
73
- . entry_points
74
- . iter ( )
75
- . map ( |entry| spv_entry_point_to_wgsl ( entry) )
76
- . collect ( ) ;
77
- Self {
78
- entry_points,
79
- module : ModuleResult :: SingleModule ( wgsl) ,
80
- }
81
- }
82
- ModuleResult :: MultiModule ( map) => {
83
- let new_map: BTreeMap < String , PathBuf > = map
84
- . iter ( )
85
- . map ( |( entry_point, spv) | {
86
- let wgsl = wgsl_file_name ( spv) ;
87
- spv_to_wgsl ( spv, & wgsl, capabilities) ?;
88
- Ok ( ( spv_entry_point_to_wgsl ( entry_point) , wgsl) )
89
- } )
90
- . collect :: < anyhow:: Result < _ > > ( ) ?;
91
- Self {
92
- entry_points : new_map. keys ( ) . cloned ( ) . collect ( ) ,
93
- module : ModuleResult :: MultiModule ( new_map) ,
94
- }
95
- }
96
- } )
68
+ fn naga_transpile ( & self , capabilities : Capabilities ) -> anyhow:: Result < NagaTranspile > {
69
+ Ok ( NagaTranspile ( self . try_map (
70
+ |entry| Ok ( entry. clone ( ) ) ,
71
+ |spv| parse_spv ( spv, capabilities) ,
72
+ ) ?) )
73
+ }
74
+ }
75
+
76
+ /// Main struct for naga transpilation
77
+ #[ expect(
78
+ clippy:: exhaustive_structs,
79
+ reason = "never adding private members to this struct"
80
+ ) ]
81
+ pub struct NagaTranspile ( pub GenericCompileResult < NagaModule > ) ;
82
+
83
+ impl NagaTranspile {
84
+ /// Transpile to wgsl source code, typically for webgpu compatibility.
85
+ ///
86
+ /// Returns a [`CompileResult`] of wgsl source code files and their associated wgsl entry points.
87
+ ///
88
+ /// # Errors
89
+ /// converting naga module to wgsl may fail
90
+ #[ inline]
91
+ #[ cfg( feature = "wgsl-out" ) ]
92
+ pub fn to_wgsl (
93
+ & self ,
94
+ writer_flags : naga:: back:: wgsl:: WriterFlags ,
95
+ ) -> anyhow:: Result < CompileResult > {
96
+ self . 0 . try_map (
97
+ |entry| Ok ( crate :: linkage:: spv_entry_point_to_wgsl ( entry) ) ,
98
+ |module| {
99
+ let inner = || -> anyhow:: Result < _ > {
100
+ let wgsl_dst = module. spv_path . with_extension ( "wgsl" ) ;
101
+ let wgsl =
102
+ naga:: back:: wgsl:: write_string ( & module. module , & module. info , writer_flags)
103
+ . context ( "naga conversion to wgsl failed" ) ?;
104
+ std:: fs:: write ( & wgsl_dst, wgsl) . context ( "failed to write wgsl file" ) ?;
105
+ Ok ( wgsl_dst)
106
+ } ;
107
+ inner ( )
108
+ . with_context ( || format ! ( "transpiling to wgsl '{}'" , module. spv_path. display( ) ) )
109
+ } ,
110
+ )
97
111
}
98
112
}
0 commit comments