spirv_cross2/reflect/
buffers.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use crate::error;
use crate::error::ToContextError;
use crate::handle::Handle;
use crate::Compiler;
use spirv_cross_sys as sys;
use spirv_cross_sys::{SpvId, VariableId};

/// A range over a buffer.
pub use spirv_cross_sys::BufferRange;

/// Reflection of buffers (UBO, SSBOs, and PushConstant blocks).
impl<T> Compiler<T> {
    /// Returns a list of which members of a struct are potentially in use by a
    /// SPIR-V shader. The granularity of this analysis is per-member of a struct.
    /// This can be used for Buffer (UBO), BufferBlock/StorageBuffer (SSBO) and PushConstant blocks.
    pub fn active_buffer_ranges(
        &self,
        handle: impl Into<Handle<VariableId>>,
    ) -> error::Result<&[BufferRange]> {
        let handle = handle.into();
        let handle = self.yield_id(handle)?;

        unsafe {
            let mut ranges = std::ptr::null();
            let mut size = 0;
            sys::spvc_compiler_get_active_buffer_ranges(
                self.ptr.as_ptr(),
                handle,
                &mut ranges,
                &mut size,
            )
            .ok(self)?;

            Ok(std::slice::from_raw_parts(ranges, size))
        }
    }

    /// Queries if a buffer object has a neighbor "counter" buffer.
    /// If so, the ID of that counter buffer will be returned.
    ///
    /// If `SPV_GOOGLE_hlsl_functionality` is used, this can be used even with a stripped SPIR-V module.
    /// Otherwise, this query is purely based on `OpName` identifiers as found in the SPIR-V module, and will
    /// only return true if OpSource was reported HLSL.
    /// To rely on this functionality, ensure that the SPIR-V module is not stripped.
    pub fn hlsl_counter_buffer(
        &self,
        variable: impl Into<Handle<VariableId>>,
    ) -> error::Result<Option<Handle<VariableId>>> {
        let variable = variable.into();
        let id = self.yield_id(variable)?;
        unsafe {
            let mut counter = VariableId(SpvId(0));
            if sys::spvc_compiler_buffer_get_hlsl_counter_buffer(
                self.ptr.as_ptr(),
                id,
                &mut counter,
            ) {
                Ok(Some(self.create_handle(counter)))
            } else {
                Ok(None)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use crate::error::SpirvCrossError;
    use crate::targets;
    use crate::Compiler;
    use crate::Module;
    use spirv_cross_sys::ResourceType;

    static BASIC_SPV: &[u8] = include_bytes!("../../basic.spv");

    #[test]
    pub fn get_active_buffer_ranges() -> Result<(), SpirvCrossError> {
        let vec = Vec::from(BASIC_SPV);
        let words = Module::from_words(bytemuck::cast_slice(&vec));

        let compiler: Compiler<targets::None> = Compiler::new(words)?;
        let ubo: Vec<_> = compiler
            .shader_resources()?
            .resources_for_type(ResourceType::UniformBuffer)?
            .collect();

        let ubo = ubo[0].id;
        let ranges = compiler.active_buffer_ranges(ubo)?;

        eprintln!("{:?}", ranges);
        Ok(())
    }
}