spirv_cross2/compile/glsl/
mod.rs1use super::CommonOptions;
2use crate::compile::sealed::ApplyCompilerOptions;
3use crate::error::ToContextError;
4use crate::handle::Handle;
5use crate::iter::impl_iterator;
6use crate::sealed::Sealed;
7use crate::targets::Glsl;
8use crate::{error, Compiler, CompilerStr, ContextRooted, PhantomCompiler};
9use spirv_cross_sys as sys;
10use spirv_cross_sys::{spvc_compiler_option, spvc_compiler_options, VariableId};
11use std::marker::PhantomData;
12use std::ops::Range;
13
14impl Sealed for CompilerOptions {}
15#[non_exhaustive]
17#[derive(Debug, spirv_cross2_derive::CompilerOptions)]
18pub struct CompilerOptions {
19 #[expand]
21 pub common: CommonOptions,
22
23 #[expand]
25 pub version: GlslVersion,
26
27 #[option(SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, false)]
30 pub vulkan_semantics: bool,
31
32 #[option(SPVC_COMPILER_OPTION_GLSL_SEPARATE_SHADER_OBJECTS, false)]
37 pub seperate_shader_objects: bool,
38
39 #[option(SPVC_COMPILER_OPTION_GLSL_ENABLE_420PACK_EXTENSION, true)]
46 pub enable_420pack_extension: bool,
47
48 #[option(SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE, true)]
52 pub support_nonzero_base_instance: bool,
53
54 #[option(SPVC_COMPILER_OPTION_GLSL_ES_DEFAULT_FLOAT_PRECISION_HIGHP, false)]
57 pub es_default_float_precision_highp: bool,
58
59 #[option(SPVC_COMPILER_OPTION_GLSL_ES_DEFAULT_INT_PRECISION_HIGHP, true)]
62 pub es_default_int_precision_highp: bool,
63
64 #[option(SPVC_COMPILER_OPTION_GLSL_EMIT_PUSH_CONSTANT_AS_UNIFORM_BUFFER, false)]
66 pub emit_push_constant_as_uniform_buffer: bool,
67
68 #[option(SPVC_COMPILER_OPTION_GLSL_EMIT_UNIFORM_BUFFER_AS_PLAIN_UNIFORMS, false)]
71 pub emit_uniform_buffer_as_plain_uniforms: bool,
72
73 #[option(SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS, false)]
76 pub force_flattened_io_blocks: bool,
77
78 #[option(SPVC_COMPILER_OPTION_GLSL_ENABLE_ROW_MAJOR_LOAD_WORKAROUND, true)]
83 pub enable_row_major_load_workaround: bool,
84
85 #[option(SPVC_COMPILER_OPTION_GLSL_OVR_MULTIVIEW_VIEW_COUNT, 0)]
87 pub ovr_multiview_view_count: u32,
88}
89
90impl Sealed for GlslVersion {}
91
92#[non_exhaustive]
94#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
95pub enum GlslVersion {
96 Glsl110,
98 Glsl120,
100 Glsl130,
102 Glsl140,
104 Glsl150,
106 Glsl330,
108 Glsl400,
110 Glsl410,
112 Glsl420,
114 Glsl430,
116 Glsl440,
118 #[default]
120 Glsl450,
121 Glsl460,
123 Glsl100Es,
125 Glsl300Es,
127 Glsl310Es,
129 Glsl320Es,
131}
132
133impl ApplyCompilerOptions for GlslVersion {
134 unsafe fn apply(
135 &self,
136 options: spvc_compiler_options,
137 root: impl ContextRooted + Copy,
138 ) -> error::Result<()> {
139 let version = match self {
140 GlslVersion::Glsl110 => 110,
141 GlslVersion::Glsl120 => 120,
142 GlslVersion::Glsl130 => 130,
143 GlslVersion::Glsl140 => 140,
144 GlslVersion::Glsl150 => 150,
145 GlslVersion::Glsl330 => 330,
146 GlslVersion::Glsl400 => 400,
147 GlslVersion::Glsl410 => 410,
148 GlslVersion::Glsl420 => 420,
149 GlslVersion::Glsl430 => 430,
150 GlslVersion::Glsl440 => 440,
151 GlslVersion::Glsl450 => 450,
152 GlslVersion::Glsl460 => 460,
153 GlslVersion::Glsl100Es => 100,
154 GlslVersion::Glsl300Es => 300,
155 GlslVersion::Glsl310Es => 310,
156 GlslVersion::Glsl320Es => 320,
157 };
158
159 let es = matches!(
160 self,
161 GlslVersion::Glsl100Es
162 | GlslVersion::Glsl300Es
163 | GlslVersion::Glsl310Es
164 | GlslVersion::Glsl320Es
165 );
166
167 unsafe {
168 sys::spvc_compiler_options_set_uint(
169 options,
170 spvc_compiler_option::SPVC_COMPILER_OPTION_GLSL_VERSION,
171 version,
172 )
173 .ok(root)?;
174 sys::spvc_compiler_options_set_bool(
175 options,
176 spvc_compiler_option::SPVC_COMPILER_OPTION_GLSL_ES,
177 es,
178 )
179 .ok(root)?;
180 }
181
182 Ok(())
183 }
184}
185
186impl Compiler<Glsl> {
187 pub fn flatten_buffer_block(
195 &mut self,
196 block: impl Into<Handle<VariableId>>,
197 ) -> error::Result<()> {
198 let block = block.into();
199 let block = self.yield_id(block)?;
200
201 unsafe { sys::spvc_compiler_flatten_buffer_block(self.ptr.as_ptr(), block).ok(&*self) }
202 }
203
204 pub fn required_extensions(&self) -> GlslExtensionsIter {
209 unsafe {
214 let extension_nums = sys::spvc_compiler_get_num_required_extensions(self.ptr.as_ptr());
215 let range = 0..extension_nums;
216 GlslExtensionsIter(range, self.phantom(), PhantomData)
217 }
218 }
219}
220
221pub struct GlslExtensionsIter<'a>(
223 Range<usize>,
225 PhantomCompiler,
229 PhantomData<&'a Glsl>,
230);
231
232impl_iterator!(GlslExtensionsIter<'c>: CompilerStr<'c> as and_then |s, index: usize| {
233 unsafe {
234 let extension = sys::spvc_compiler_get_required_extension(s.1.ptr.as_ptr(), index);
235 if extension.is_null() {
236 if cfg!(debug_assertions) {
237 panic!("Unexpected null string returned by `spvc_compiler_get_required_extension`.\
238 The index of `spvc_compiler_get_num_required_extensions` did not match, complain to SPIRV-Cross.")
239 };
240 None
241 } else {
242 Some(CompilerStr::from_ptr(extension, s.1.ctx.clone()))
243 }
244 }
245} for <'c> [0]);
246
247#[cfg(test)]
248mod test {
249 use crate::compile::glsl::CompilerOptions;
250 use spirv_cross_sys::spvc_compiler_create_compiler_options;
251
252 use crate::compile::CompilableTarget;
253 use crate::error::{SpirvCrossError, ToContextError};
254 use crate::targets::Glsl;
255 use crate::Compiler;
256 use crate::{targets, Module};
257
258 static BASIC_SPV: &[u8] = include_bytes!("../../../basic.spv");
259
260 #[test]
261 pub fn glsl_opts() -> Result<(), SpirvCrossError> {
262 use crate::compile::sealed::ApplyCompilerOptions;
263
264 let words = Vec::from(BASIC_SPV);
265 let words = Module::from_words(bytemuck::cast_slice(&words));
266
267 let compiler: Compiler<targets::Glsl> = Compiler::new(words)?;
268 let resources = compiler.shader_resources()?.all_resources()?;
269
270 let mut opts_ptr = std::ptr::null_mut();
271
272 unsafe {
273 spvc_compiler_create_compiler_options(compiler.ptr.as_ptr(), &mut opts_ptr)
274 .ok(&compiler)?;
275 }
276
277 let opts = CompilerOptions::default();
279 unsafe {
280 opts.apply(opts_ptr, &compiler)?;
281 }
282
283 Ok(())
284 }
285
286 #[test]
287 pub fn required_extensions() -> Result<(), SpirvCrossError> {
288 let words = Vec::from(BASIC_SPV);
289 let words = Module::from_words(bytemuck::cast_slice(&words));
290
291 let mut compiler: Compiler<targets::Glsl> = Compiler::new(words)?;
292
293 compiler.require_extension("GL_KHR_my_Extension")?;
294 let extensions = compiler.required_extensions();
295 assert_eq!(
296 &["GL_KHR_my_Extension"],
297 extensions.collect::<Vec<_>>().as_slice()
298 );
299
300 compiler.require_extension("GL_KHR_my_ExtensionS")?;
301 compiler.require_extension("GL_KHR_my_ExtensionS")?;
302
303 let extensions: Vec<_> = compiler.required_extensions().collect();
304 assert_eq!(
305 &["GL_KHR_my_Extension", "GL_KHR_my_ExtensionS"],
306 extensions.as_slice()
307 );
308
309 let extensions = compiler.required_extensions();
310 let artifact = compiler.compile(&Glsl::options())?;
311 let extensions = artifact.required_extensions();
312
313 assert_eq!(
314 &["GL_KHR_my_Extension", "GL_KHR_my_ExtensionS"],
315 extensions.collect::<Vec<_>>().as_slice()
316 );
317
318 Ok(())
319 }
320}