spirv_cross2/reflect/combined_image_samplers.rs
1use crate::error::{SpirvCrossError, ToContextError};
2use crate::handle::{Handle, VariableId};
3use crate::iter::impl_iterator;
4use crate::{error, Compiler, PhantomCompiler};
5use spirv_cross_sys as sys;
6use std::slice;
7
8/// A proof that [`Compiler::create_dummy_sampler_for_combined_images`] was called.
9#[derive(Debug, Copy, Clone)]
10pub struct BuiltDummySamplerProof {
11 /// The handle to a sampler object, if one was needed to be created.
12 pub sampler_id: Option<Handle<VariableId>>,
13 label: Handle<()>,
14}
15
16/// Iterator for [`CombinedImageSampler`].
17pub struct CombinedImageSamplerIter<'a>(
18 PhantomCompiler,
19 slice::Iter<'a, sys::spvc_combined_image_sampler>,
20);
21
22impl_iterator!(CombinedImageSamplerIter<'_>: CombinedImageSampler
23 as map |s, c: &sys::spvc_combined_image_sampler| {
24 let combined_id = s.0.create_handle(c.combined_id);
25 let image_id = s.0.create_handle(c.image_id);
26 let sampler_id = s.0.create_handle(c.sampler_id);
27
28 CombinedImageSampler {
29 combined_id,
30 image_id,
31 sampler_id,
32 }
33} for [1]);
34
35/// A combined image sampler.
36pub struct CombinedImageSampler {
37 /// A handle to the created combined image sampler.
38 pub combined_id: Handle<VariableId>,
39 /// A handle to the split image of the combined image sampler.
40 pub image_id: Handle<VariableId>,
41 /// A handle to the split sampler of the combined image sampler.
42 pub sampler_id: Handle<VariableId>,
43}
44
45impl<T> Compiler<T> {
46 /// Analyzes all OpImageFetch (texelFetch) opcodes and checks if there are instances where
47 /// said instruction is used without a combined image sampler.
48 /// GLSL targets do not support the use of texelFetch without a sampler.
49 /// To work around this, we must inject a dummy sampler which can be used to form a sampler2D at the call-site of
50 /// texelFetch as necessary.
51 ///
52 /// This must be called to obtain a proof to call [`Compiler::build_combined_image_samplers`].
53 ///
54 /// The proof contains the ID of a sampler object, if one dummy sampler is necessary. This ID can
55 /// be decorated with set/bindings as desired before compiling.
56 pub fn create_dummy_sampler_for_combined_images(
57 &mut self,
58 ) -> error::Result<BuiltDummySamplerProof> {
59 unsafe {
60 let mut var_id = VariableId::from(0);
61 sys::spvc_compiler_build_dummy_sampler_for_combined_images(
62 self.ptr.as_ptr(),
63 &mut var_id,
64 )
65 .ok(&*self)?;
66
67 let sampler_id = self.create_handle_if_not_zero(var_id);
68
69 Ok(BuiltDummySamplerProof {
70 sampler_id,
71 label: self.create_handle(()),
72 })
73 }
74 }
75
76 /// Analyzes all separate image and samplers used from the currently selected entry point,
77 /// and re-routes them all to a combined image sampler instead.
78 /// This is required to "support" separate image samplers in targets which do not natively support
79 /// this feature, like GLSL/ESSL.
80 ///
81 /// This call will add new sampled images to the SPIR-V,
82 /// so it will appear in reflection if [`Compiler::shader_resources`] is called after.
83 ///
84 /// If any image/sampler remapping was found, no separate image/samplers will appear in the decompiled output,
85 /// but will still appear in reflection.
86 ///
87 /// The resulting samplers will be void of any decorations like name, descriptor sets and binding points,
88 /// so this can be added before compilation if desired.
89 ///
90 /// Combined image samplers originating from this set are always considered active variables.
91 /// Arrays of separate samplers are not supported, but arrays of separate images are supported.
92 /// Array of images + sampler -> Array of combined image samplers.
93 ///
94 /// [`Compiler::create_dummy_sampler_for_combined_images`] must be called before this to obtain
95 /// a proof that a dummy sampler, if necessary, was created. Passing in a smuggled proof from
96 /// a different compiler instance will result in an error.
97 pub fn build_combined_image_samplers(
98 &mut self,
99 proof: BuiltDummySamplerProof,
100 ) -> error::Result<()> {
101 // check for smuggling
102 if !self.handle_is_valid(&proof.label) {
103 return Err(SpirvCrossError::InvalidOperation(String::from(
104 "The provided proof of building combined image samplers is invalid",
105 )));
106 }
107
108 unsafe {
109 sys::spvc_compiler_build_combined_image_samplers(self.ptr.as_ptr()).ok(&*self)?;
110
111 Ok(())
112 }
113 }
114
115 /// Gets a remapping for the combined image samplers.
116 pub fn combined_image_samplers(&self) -> error::Result<CombinedImageSamplerIter<'static>> {
117 unsafe {
118 let mut samplers = std::ptr::null();
119 let mut size = 0;
120
121 // SAFETY: 'ctx is sound here.
122 // https://github.com/KhronosGroup/SPIRV-Cross/blob/main/spirv_cross_c.cpp#L2497
123 sys::spvc_compiler_get_combined_image_samplers(
124 self.ptr.as_ptr(),
125 &mut samplers,
126 &mut size,
127 )
128 .ok(self)?;
129 let slice = slice::from_raw_parts(samplers, size);
130 Ok(CombinedImageSamplerIter(self.phantom(), slice.iter()))
131 }
132 }
133}
134
135#[cfg(test)]
136mod test {
137 use crate::error::SpirvCrossError;
138 use crate::Compiler;
139 use crate::{targets, Module};
140
141 static BASIC_SPV: &[u8] = include_bytes!("../../basic.spv");
142
143 #[test]
144 pub fn test_combined_image_sampler_build() -> Result<(), SpirvCrossError> {
145 let vec = Vec::from(BASIC_SPV);
146 let words = Module::from_words(bytemuck::cast_slice(&vec));
147
148 let mut compiler: Compiler<targets::None> = Compiler::new(words)?;
149
150 let proof = compiler.create_dummy_sampler_for_combined_images()?;
151 compiler.build_combined_image_samplers(proof)?;
152
153 // match ty.inner {
154 // TypeInner::Struct(ty) => {
155 // compiler.get_type(ty.members[0].id)?;
156 // }
157 // TypeInner::Vector { .. } => {}
158 // _ => {}
159 // }
160 Ok(())
161 }
162}