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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
use crate::error;
use crate::handle::{Handle, Id};
use crate::Compiler;
use crate::error::SpirvCrossError;
use crate::string::ContextStr;
use spirv_cross_sys as sys;
use spirv_cross_sys::{SpvId, TypeId, VariableId};
impl<T> Compiler<'_, T> {
/// Gets the identifier (`OpName`) of an ID.
pub fn name<I: Id>(&self, handle: Handle<I>) -> error::Result<Option<ContextStr>> {
let id = self.yield_id(handle)?;
unsafe {
let name = sys::spvc_compiler_get_name(self.ptr.as_ptr(), SpvId(id.id()));
let name = ContextStr::from_ptr(name, self.ctx.clone());
if name.is_empty() {
Ok(None)
} else {
Ok(Some(name))
}
}
}
/// Overrides the identifier OpName of an ID.
///
/// Identifiers beginning with underscores or identifiers which contain double underscores
/// are reserved by the implementation.
pub fn set_name<'str, I: Id>(
&mut self,
handle: Handle<I>,
string: impl Into<ContextStr<'str>>,
) -> error::Result<()> {
let id = self.yield_id(handle)?;
let string = string.into();
unsafe {
let Ok(cstring) = string.to_cstring_ptr() else {
return Err(SpirvCrossError::InvalidString(String::from(
string.as_ref(),
)));
};
sys::spvc_compiler_set_name(self.ptr.as_ptr(), SpvId(id.id()), cstring.as_ptr());
// Sanity drop to show that the lifetime of the cstring is only up until
// we have returned. AFAIK, SPIRV-Cross will do a string copy.
// If it does not, then we'll have to keep this string alive for a while.
drop(cstring);
Ok(())
}
}
/// Given a struct type ID, obtain the identifier for member number "index".
pub fn member_name(
&self,
struct_type: Handle<TypeId>,
index: u32,
) -> error::Result<Option<ContextStr>> {
let struct_type_id = self.yield_id(struct_type)?;
let index = index;
unsafe {
let name = sys::spvc_compiler_get_member_name(self.ptr.as_ptr(), struct_type_id, index);
let name = ContextStr::from_ptr(name, self.ctx.clone());
if name.is_empty() {
Ok(None)
} else {
Ok(Some(name))
}
}
}
/// Sets the member identifier for the given struct member.
pub fn set_member_name<'str>(
&mut self,
struct_type: Handle<TypeId>,
index: u32,
string: impl Into<ContextStr<'str>>,
) -> error::Result<()> {
let struct_type_id = self.yield_id(struct_type)?;
let index = index;
let string = string.into();
unsafe {
let Ok(cstring) = string.to_cstring_ptr() else {
return Err(SpirvCrossError::InvalidString(String::from(
string.as_ref(),
)));
};
sys::spvc_compiler_set_member_name(
self.ptr.as_ptr(),
struct_type_id,
index,
cstring.as_ptr(),
);
// Sanity drop to show that the lifetime of the cstring is only up until
// we have returned. AFAIK, SPIRV-Cross will do a string copy.
// If it does not, then we'll have to keep this string alive for a while.
drop(cstring);
Ok(())
}
}
}
impl<'ctx, T> Compiler<'ctx, T> {
/// When declaring buffer blocks in GLSL, the name declared in the GLSL source
/// might not be the same as the name declared in the SPIR-V module due to naming conflicts.
/// In this case, SPIRV-Cross needs to find a fallback-name, and it might only
/// be possible to know this name after compiling to GLSL.
///
/// This is particularly important for HLSL input and UAVs which tends to reuse the same block type
/// for multiple distinct blocks. For these cases it is not possible to modify the name of the type itself
/// because it might be unique. Instead, you can use this interface to check after compilation which
/// name was actually used if your input SPIR-V tends to have this problem.
///
/// For other names like remapped names for variables, etc., it's generally enough to query the name of the variables
/// after compiling, block names are an exception to this rule.
/// `handle` should be a handle to a variable with a Block-like type.
///
/// This also applies to HLSL cbuffers.
pub fn remapped_declared_block_name(
&self,
handle: impl Into<Handle<VariableId>>,
) -> error::Result<Option<ContextStr<'ctx>>> {
let handle = handle.into();
let handle = self.yield_id(handle)?;
unsafe {
let name =
sys::spvc_compiler_get_remapped_declared_block_name(self.ptr.as_ptr(), handle);
// SAFETY: 'ctx is sound here
// https://github.com/KhronosGroup/SPIRV-Cross/blob/main/spirv_cross_c.cpp#L2773
let name = ContextStr::from_ptr(name, self.ctx.clone());
if name.is_empty() {
Ok(None)
} else {
Ok(Some(name))
}
}
}
}