spirv_cross2/compile/
mod.rs1use crate::error::{Result, ToContextError};
2use crate::sealed::Sealed;
3use crate::targets::Target;
4use crate::{error, Compiler, CompilerStr, ContextRooted};
5use spirv_cross_sys as sys;
6use std::fmt::{Display, Formatter};
7use std::ops::Deref;
8
9#[cfg(feature = "glsl")]
11#[cfg_attr(docsrs, doc(cfg(feature = "glsl")))]
12pub mod glsl;
13
14#[cfg(feature = "hlsl")]
16#[cfg_attr(docsrs, doc(cfg(feature = "hlsl")))]
17pub mod hlsl;
18
19#[cfg(feature = "msl")]
21#[cfg_attr(docsrs, doc(cfg(feature = "msl")))]
22pub mod msl;
23
24impl Sealed for CommonOptions {}
25
26#[derive(Debug, spirv_cross2_derive::CompilerOptions)]
28pub struct CommonOptions {
29 #[option(SPVC_COMPILER_OPTION_FORCE_TEMPORARY, false)]
32 pub force_temporary: bool,
33
34 #[option(SPVC_COMPILER_OPTION_FLATTEN_MULTIDIMENSIONAL_ARRAYS, false)]
40 pub flatten_multidimensional_arrays: bool,
41
42 #[option(SPVC_COMPILER_OPTION_FLIP_VERTEX_Y, false)]
44 pub flip_vertex_y: bool,
45
46 #[option(SPVC_COMPILER_OPTION_FIXUP_DEPTH_CONVENTION, false)]
50 pub fixup_clipspace: bool,
51
52 #[option(SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES, false)]
55 pub emit_line_directives: bool,
56
57 #[option(SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES, false)]
61 pub force_zero_initialized_variables: bool,
62
63 #[option(SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION, true)]
69 pub enable_storage_image_qualifier_deduction: bool,
70
71 #[option(SPVC_COMPILER_OPTION_RELAX_NAN_CHECKS, false)]
77 pub relax_nan_checks: bool,
78}
79
80pub struct CompiledArtifact<T> {
88 compiler: Compiler<T>,
89 source: CompilerStr<'static>,
90}
91
92impl<T> AsRef<str> for CompiledArtifact<T> {
93 fn as_ref(&self) -> &str {
94 self.source.as_ref()
95 }
96}
97
98impl<T> Display for CompiledArtifact<T> {
99 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
100 Display::fmt(&self.source, f)
101 }
102}
103
104impl<'a, T> Deref for CompiledArtifact<T> {
105 type Target = Compiler<T>;
106
107 fn deref(&self) -> &Self::Target {
108 &self.compiler
109 }
110}
111
112impl<T: CompilableTarget> Compiler<T> {
114 pub fn add_header_line<'str>(&mut self, line: impl Into<CompilerStr<'str>>) -> Result<()> {
127 let line = line.into();
128 let cstring = line.into_cstring_ptr()?;
129 unsafe {
130 sys::spvc_compiler_add_header_line(self.ptr.as_ptr(), cstring.as_ptr()).ok(&*self)
131 }
132 }
133
134 pub fn require_extension<'str>(&mut self, ext: impl Into<CompilerStr<'str>>) -> Result<()> {
137 let ext = ext.into();
138 let cstring = ext.into_cstring_ptr()?;
139
140 unsafe {
141 sys::spvc_compiler_require_extension(self.ptr.as_ptr(), cstring.as_ptr().cast())
142 .ok(&*self)
143 }
144 }
145
146 fn set_compiler_options(&mut self, options: &T::Options) -> error::Result<()> {
148 use crate::compile::sealed::ApplyCompilerOptions;
149 unsafe {
150 let mut handle = std::ptr::null_mut();
151
152 sys::spvc_compiler_create_compiler_options(self.ptr.as_ptr(), &mut handle)
153 .ok(&*self)?;
154
155 options.apply(handle, &*self)?;
156
157 sys::spvc_compiler_install_compiler_options(self.ptr.as_ptr(), handle).ok(&*self)?;
158
159 Ok(())
160 }
161 }
162
163 pub fn compile(mut self, options: &T::Options) -> error::Result<CompiledArtifact<T>> {
166 self.set_compiler_options(options)?;
167
168 unsafe {
169 let mut src = std::ptr::null();
170 sys::spvc_compiler_compile(self.ptr.as_ptr(), &mut src).ok(&self)?;
171
172 let src = CompilerStr::from_ptr(src, self.ctx.drop_guard());
175 Ok(CompiledArtifact {
176 compiler: self,
177 source: src,
178 })
179 }
180 }
181}
182
183pub trait CompilerOptions: Default + sealed::ApplyCompilerOptions {}
185
186pub(crate) mod sealed {
187 use crate::error;
188 use crate::error::ContextRooted;
189 use crate::sealed::Sealed;
190 use spirv_cross_sys::spvc_compiler_options;
191
192 pub trait ApplyCompilerOptions: Sealed {
193 #[doc(hidden)]
194 unsafe fn apply(
195 &self,
196 options: spvc_compiler_options,
197 root: impl ContextRooted + Copy,
198 ) -> error::Result<()>;
199 }
200}
201
202#[cfg(test)]
203mod test {
204 use crate::error::SpirvCrossError;
205 use crate::targets;
206 use crate::Compiler;
207 use crate::Module;
208
209 const BASIC_SPV: &[u8] = include_bytes!("../../basic.spv");
210
211 #[test]
212 pub fn create_compiler() -> Result<(), SpirvCrossError> {
213 let vec = Vec::from(BASIC_SPV);
214 let words = Module::from_words(bytemuck::cast_slice(&vec));
215
216 let compiler: Compiler<targets::None> = Compiler::new(words)?;
217 Ok(())
218 }
219}
220
221impl Sealed for NoOptions {}
222
223#[derive(Debug, Default, spirv_cross2_derive::CompilerOptions)]
227pub struct NoOptions;
228
229pub trait CompilableTarget: Target {
231 type Options: CompilerOptions;
233
234 fn options() -> Self::Options {
236 Self::Options::default()
237 }
238}