spirv_cross2/reflect/
buffers.rs

1use crate::error;
2use crate::error::ToContextError;
3use crate::handle::Handle;
4use crate::Compiler;
5use spirv_cross_sys as sys;
6use spirv_cross_sys::{SpvId, VariableId};
7
8/// A range over a buffer.
9pub use spirv_cross_sys::BufferRange;
10
11/// Reflection of buffers (UBO, SSBOs, and PushConstant blocks).
12impl<T> Compiler<T> {
13    /// Returns a list of which members of a struct are potentially in use by a
14    /// SPIR-V shader. The granularity of this analysis is per-member of a struct.
15    /// This can be used for Buffer (UBO), BufferBlock/StorageBuffer (SSBO) and PushConstant blocks.
16    pub fn active_buffer_ranges(
17        &self,
18        handle: impl Into<Handle<VariableId>>,
19    ) -> error::Result<&[BufferRange]> {
20        let handle = handle.into();
21        let handle = self.yield_id(handle)?;
22
23        unsafe {
24            let mut ranges = std::ptr::null();
25            let mut size = 0;
26            sys::spvc_compiler_get_active_buffer_ranges(
27                self.ptr.as_ptr(),
28                handle,
29                &mut ranges,
30                &mut size,
31            )
32            .ok(self)?;
33
34            Ok(std::slice::from_raw_parts(ranges, size))
35        }
36    }
37
38    /// Queries if a buffer object has a neighbor "counter" buffer.
39    /// If so, the ID of that counter buffer will be returned.
40    ///
41    /// If `SPV_GOOGLE_hlsl_functionality` is used, this can be used even with a stripped SPIR-V module.
42    /// Otherwise, this query is purely based on `OpName` identifiers as found in the SPIR-V module, and will
43    /// only return true if OpSource was reported HLSL.
44    /// To rely on this functionality, ensure that the SPIR-V module is not stripped.
45    pub fn hlsl_counter_buffer(
46        &self,
47        variable: impl Into<Handle<VariableId>>,
48    ) -> error::Result<Option<Handle<VariableId>>> {
49        let variable = variable.into();
50        let id = self.yield_id(variable)?;
51        unsafe {
52            let mut counter = VariableId(SpvId(0));
53            if sys::spvc_compiler_buffer_get_hlsl_counter_buffer(
54                self.ptr.as_ptr(),
55                id,
56                &mut counter,
57            ) {
58                Ok(Some(self.create_handle(counter)))
59            } else {
60                Ok(None)
61            }
62        }
63    }
64}
65
66#[cfg(test)]
67mod test {
68    use crate::error::SpirvCrossError;
69    use crate::targets;
70    use crate::Compiler;
71    use crate::Module;
72    use spirv_cross_sys::ResourceType;
73
74    static BASIC_SPV: &[u8] = include_bytes!("../../basic.spv");
75
76    #[test]
77    pub fn get_active_buffer_ranges() -> Result<(), SpirvCrossError> {
78        let vec = Vec::from(BASIC_SPV);
79        let words = Module::from_words(bytemuck::cast_slice(&vec));
80
81        let compiler: Compiler<targets::None> = Compiler::new(words)?;
82        let ubo: Vec<_> = compiler
83            .shader_resources()?
84            .resources_for_type(ResourceType::UniformBuffer)?
85            .collect();
86
87        let ubo = ubo[0].id;
88        let ranges = compiler.active_buffer_ranges(ubo)?;
89
90        eprintln!("{:?}", ranges);
91        Ok(())
92    }
93}