spirv_tools/opt/
compiled.rs

1use crate::error;
2use spirv_tools_sys::opt;
3
4pub struct Options {
5    pub(crate) inner: *mut opt::OptimizerOptions,
6}
7
8impl From<super::Options> for Options {
9    fn from(o: super::Options) -> Self {
10        unsafe {
11            let inner = opt::optimizer_options_create();
12
13            if let Some(vopts) = o.validator_options {
14                let vopts = crate::val::compiled::Options::from(vopts);
15
16                opt::optimizer_options_run_validator(inner, true);
17
18                // The validator options are copied, so it's fine to drop vopts
19                // after this call
20                opt::optimizer_options_set_validator_options(inner, vopts.inner);
21            }
22
23            if let Some(max_bound) = o.max_id_bound {
24                opt::optimizer_options_set_max_id_bound(inner, max_bound);
25            }
26
27            if o.preserve_bindings {
28                opt::optimizer_options_preserve_bindings(inner, true);
29            }
30
31            if o.preserve_spec_constants {
32                opt::optimizer_options_preserve_spec_constants(inner, true);
33            }
34
35            Self { inner }
36        }
37    }
38}
39
40impl Drop for Options {
41    #[inline]
42    fn drop(&mut self) {
43        unsafe { opt::optimizer_options_destroy(self.inner) }
44    }
45}
46
47pub struct CompiledOptimizer {
48    inner: *mut opt::Optimizer,
49}
50
51use super::Optimizer;
52
53impl Optimizer for CompiledOptimizer {
54    fn with_env(target: crate::TargetEnv) -> Self {
55        Self {
56            inner: unsafe { opt::optimizer_create(target) },
57        }
58    }
59
60    fn optimize<MC: error::MessageCallback>(
61        &self,
62        input: impl AsRef<[u32]>,
63        msg_callback: &mut MC,
64        options: Option<super::Options>,
65    ) -> Result<crate::binary::Binary, crate::Error> {
66        unsafe {
67            struct Ctx<'a> {
68                cb: &'a mut dyn error::MessageCallback,
69            }
70
71            let mut ctx = Ctx { cb: msg_callback };
72
73            let cb_ctx: *mut std::ffi::c_void = (&mut ctx as *mut Ctx<'_>).cast();
74
75            extern "C" fn callback(
76                level: spirv_tools_sys::diagnostics::MessageLevel,
77                source: *const std::os::raw::c_char,
78                source_pos: *const spirv_tools_sys::diagnostics::Position,
79                msg: *const std::os::raw::c_char,
80                ctx: *mut std::ffi::c_void,
81            ) {
82                unsafe {
83                    let ctx: &mut Ctx<'_> = &mut *(ctx.cast::<Ctx<'_>>());
84
85                    let msg = error::Message::from_parts(level, source, source_pos, msg);
86
87                    ctx.cb.on_message(msg);
88                }
89            }
90
91            let mut binary = std::ptr::null_mut();
92
93            let options = options.map(Options::from);
94
95            let options = match &options {
96                Some(opts) => opts.inner,
97                None => std::ptr::null(),
98            };
99
100            let input = input.as_ref();
101
102            let res = opt::optimizer_run(
103                self.inner,
104                input.as_ptr(),
105                input.len(),
106                &mut binary,
107                callback,
108                cb_ctx,
109                options,
110            );
111
112            match res {
113                spirv_tools_sys::shared::SpirvResult::Success => {
114                    if binary.is_null() {
115                        return Err(error::Error {
116                            inner: spirv_tools_sys::shared::SpirvResult::InternalError,
117                            diagnostic: Some(crate::error::Diagnostic {
118                                line: 0,
119                                column: 0,
120                                index: 0,
121                                message: "spirv optimizer indicated success but did not return a valid binary".to_owned(),
122                                notes: String::new(),
123                                is_text: false,
124                            }),
125                        });
126                    }
127
128                    Ok(crate::binary::Binary::External(
129                        crate::binary::external::ExternalBinary::new(binary),
130                    ))
131                }
132                other => Err(error::Error {
133                    inner: other,
134                    diagnostic: None,
135                }),
136            }
137        }
138    }
139
140    /// Register a single pass with the the optimizer.
141    #[inline]
142    fn register_pass(&mut self, pass: super::Passes) -> &mut Self {
143        unsafe { opt::optimizer_register_pass(self.inner, pass) }
144        self
145    }
146
147    /// Registers passes that attempt to improve performance of generated code.
148    /// This sequence of passes is subject to constant review and will change
149    /// from time to time.
150    #[inline]
151    fn register_performance_passes(&mut self) -> &mut Self {
152        unsafe { opt::optimizer_register_performance_passes(self.inner) }
153        self
154    }
155
156    /// Registers passes that attempt to improve the size of generated code.
157    /// This sequence of passes is subject to constant review and will change
158    /// from time to time.
159    #[inline]
160    fn register_size_passes(&mut self) -> &mut Self {
161        unsafe { opt::optimizer_register_size_passes(self.inner) }
162        self
163    }
164
165    // /// Registers passes that have been prescribed for converting from Vulkan to
166    // /// WebGPU. This sequence of passes is subject to constant review and will
167    // /// change from time to time.
168    // #[inline]
169    // pub fn register_vulkan_to_webgpu_passes(&mut self) -> &mut Self {
170    //     unsafe { opt::optimizer_register_vulkan_to_webgpu_passes(self.inner) }
171    //     self
172    // }
173
174    // /// Registers passes that have been prescribed for converting from WebGPU to
175    // /// Vulkan. This sequence of passes is subject to constant review and will
176    // /// change from time to time.
177    // #[inline]
178    // pub fn register_webgpu_to_vulkan_passes(&mut self) -> &mut Self {
179    //     unsafe { opt::optimizer_register_webgpu_to_vulkan_passes(self.inner) }
180    //     self
181    // }
182
183    /// Registers passes that attempt to legalize the generated code.
184    ///
185    /// Note: this recipe is specially designed for legalizing SPIR-V. It should be
186    /// used by compilers after translating HLSL source code literally. It should
187    /// *not* be used by general workloads for performance or size improvement.
188    ///
189    /// This sequence of passes is subject to constant review and will change
190    /// from time to time.
191    #[inline]
192    fn register_hlsl_legalization_passes(&mut self) -> &mut Self {
193        unsafe { opt::optimizer_register_hlsl_legalization_passes(self.inner) }
194        self
195    }
196}
197
198impl Default for CompiledOptimizer {
199    fn default() -> Self {
200        Self::with_env(crate::TargetEnv::default())
201    }
202}
203
204impl Drop for CompiledOptimizer {
205    #[inline]
206    fn drop(&mut self) {
207        unsafe { opt::optimizer_destroy(self.inner) }
208    }
209}