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 94 95 96
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<'ctx, T> Compiler<'ctx, 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<&'ctx [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)?;
// SAFETY: 'ctx is sound here
// https://github.com/KhronosGroup/SPIRV-Cross/blob/main/spirv_cross_c.cpp#L2575
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_functionality1 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, SpirvCrossContext};
use spirv_cross_sys::ResourceType;
static BASIC_SPV: &[u8] = include_bytes!("../../basic.spv");
#[test]
pub fn get_active_buffer_ranges() -> Result<(), SpirvCrossError> {
let spv = SpirvCrossContext::new()?;
let vec = Vec::from(BASIC_SPV);
let words = Module::from_words(bytemuck::cast_slice(&vec));
let compiler: Compiler<targets::None> = spv.create_compiler(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(())
}
}