@@ -27,17 +27,25 @@ impl fmt::Display for SpirvBuilderError {
27
27
28
28
impl Error for SpirvBuilderError { }
29
29
30
+ pub enum MemoryModel {
31
+ Simple ,
32
+ Vulkan ,
33
+ GLSL450 ,
34
+ }
35
+
30
36
pub struct SpirvBuilder {
31
37
path_to_crate : PathBuf ,
32
38
print_metadata : bool ,
33
39
spirv_version : Option < ( u8 , u8 ) > ,
40
+ memory_model : Option < MemoryModel > ,
34
41
}
35
42
impl SpirvBuilder {
36
43
pub fn new ( path_to_crate : impl AsRef < Path > ) -> Self {
37
44
Self {
38
45
path_to_crate : path_to_crate. as_ref ( ) . to_owned ( ) ,
39
46
print_metadata : true ,
40
47
spirv_version : None ,
48
+ memory_model : None ,
41
49
}
42
50
}
43
51
@@ -47,20 +55,23 @@ impl SpirvBuilder {
47
55
self
48
56
}
49
57
58
+ /// Sets the SPIR-V binary version to use. Defaults to v1.3.
50
59
pub fn spirv_version ( mut self , major : u8 , minor : u8 ) -> Self {
51
60
self . spirv_version = Some ( ( major, minor) ) ;
52
61
self
53
62
}
54
63
64
+ /// Sets the SPIR-V memory model. Defaults to Vulkan.
65
+ pub fn memory_model ( mut self , memory_model : MemoryModel ) -> Self {
66
+ self . memory_model = Some ( memory_model) ;
67
+ self
68
+ }
69
+
55
70
/// Builds the module. Returns the path to the built spir-v file. If print_metadata is true,
56
71
/// you usually don't have to inspect the path, as the environment variable will already be
57
72
/// set.
58
73
pub fn build ( self ) -> Result < PathBuf , SpirvBuilderError > {
59
- let spirv_module = invoke_rustc (
60
- self . path_to_crate . as_ref ( ) ,
61
- self . print_metadata ,
62
- self . spirv_version ,
63
- ) ?;
74
+ let spirv_module = invoke_rustc ( & self ) ?;
64
75
let env_var = spirv_module. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
65
76
if self . print_metadata {
66
77
println ! ( "cargo:rustc-env={}={}" , env_var, spirv_module. display( ) ) ;
@@ -101,11 +112,7 @@ fn find_rustc_codegen_spirv() -> PathBuf {
101
112
panic ! ( "Could not find {} in library path" , filename) ;
102
113
}
103
114
104
- fn invoke_rustc (
105
- path_to_crate : & Path ,
106
- print_metadata : bool ,
107
- spirv_version : Option < ( u8 , u8 ) > ,
108
- ) -> Result < PathBuf , SpirvBuilderError > {
115
+ fn invoke_rustc ( builder : & SpirvBuilder ) -> Result < PathBuf , SpirvBuilderError > {
109
116
// Okay, this is a little bonkers: in a normal world, we'd have the user clone
110
117
// rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab
111
118
// the resulting .so, and pass it into -Z codegen-backend. But that's really gross: the user
@@ -115,14 +122,30 @@ fn invoke_rustc(
115
122
// rustc expects a full path, instead of a filename looked up via LD_LIBRARY_PATH, so we need
116
123
// to copy cargo's understanding of library lookup and find the library and its full path.
117
124
let rustc_codegen_spirv = find_rustc_codegen_spirv ( ) ;
118
- let spirv_version_feture = match spirv_version {
119
- None => "" . to_string ( ) ,
120
- Some ( ( major, minor) ) => format ! ( " -C target-feature=+spirv{}.{}" , major, minor) ,
125
+ let mut target_features = Vec :: new ( ) ;
126
+ // these must match codegen_cx/mod.rs
127
+ if let Some ( ( major, minor) ) = builder. spirv_version {
128
+ target_features. push ( format ! ( "+spirv{}.{}" , major, minor) ) ;
129
+ }
130
+ if let Some ( memory_model) = & builder. memory_model {
131
+ target_features. push (
132
+ match memory_model {
133
+ MemoryModel :: Simple => "+simple" ,
134
+ MemoryModel :: Vulkan => "+vulkan" ,
135
+ MemoryModel :: GLSL450 => "+glsl450" ,
136
+ }
137
+ . to_string ( ) ,
138
+ ) ;
139
+ }
140
+ let feature_flag = if target_features. is_empty ( ) {
141
+ String :: new ( )
142
+ } else {
143
+ format ! ( " -C target-feature={}" , target_features. join( "," ) )
121
144
} ;
122
145
let rustflags = format ! (
123
146
"-Z codegen-backend={}{}" ,
124
147
rustc_codegen_spirv. display( ) ,
125
- spirv_version_feture
148
+ feature_flag ,
126
149
) ;
127
150
let build = Command :: new ( "cargo" )
128
151
. args ( & [
@@ -135,14 +158,14 @@ fn invoke_rustc(
135
158
"--release" ,
136
159
] )
137
160
. stderr ( Stdio :: inherit ( ) )
138
- . current_dir ( path_to_crate)
161
+ . current_dir ( & builder . path_to_crate )
139
162
. env ( "RUSTFLAGS" , rustflags)
140
163
. output ( )
141
164
. expect ( "failed to execute cargo build" ) ;
142
165
if build. status . success ( ) {
143
166
let stdout = String :: from_utf8 ( build. stdout ) . unwrap ( ) ;
144
167
let artifact = get_last_artifact ( & stdout) ;
145
- if print_metadata {
168
+ if builder . print_metadata {
146
169
print_deps_of ( & artifact) ;
147
170
}
148
171
Ok ( artifact)
0 commit comments