Implement most of the reflection API

This commit is contained in:
Lauro Oyen 2024-10-28 20:50:45 +01:00
parent 0efe5f8115
commit 7deb377f78
14 changed files with 1030 additions and 5 deletions

View File

@ -1,8 +1,8 @@
# Slang Rust Bindings
Rust bindings for the [Slang](https://github.com/shader-slang/slang/) shader language compiler. In contrast to existing bindings, these internally use Slang's COM/C++ API because the old C API is soon to be deprecated.
Rust bindings for the [Slang](https://github.com/shader-slang/slang/) shader language. Supporting both the modern compilation and reflection API.
Currently mostly reflects the needs of our own [engine](https://github.com/FloatyMonkey/engine) but issues and pull requests are more than welcome.
Currently mostly reflects the needs of our own [engine](https://github.com/FloatyMonkey/engine) but contributions are more than welcome.
## Example
@ -37,6 +37,9 @@ let program = session.create_composite_component_type(&[
let linked_program = program.link().unwrap();
// Entry point to the reflection API.
let reflection = linked_program.layout(0).unwrap();
let shader_bytecode = linked_program.get_entry_point_code(0, 0).unwrap();
```

View File

@ -18,7 +18,8 @@ fn main() {
.header(slang_dir.join("include/slang.h").to_str().unwrap())
.clang_arg("-v")
.clang_arg("-xc++")
.clang_arg("-std=c++14")
.clang_arg("-std=c++17")
.allowlist_function("spReflection.*")
.allowlist_function("slang_.*")
.allowlist_type("slang.*")
.allowlist_var("SLANG_.*")

View File

@ -4,7 +4,7 @@ include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
use std::ffi::{c_char, c_int, c_void};
// Based on Slang version 2024.1.29
// Based on Slang version 2024.14.3
#[repr(C)]
pub struct IBlobVtable {
@ -88,6 +88,8 @@ pub struct IComponentTypeVtable {
pub renameEntryPoint: unsafe extern "C" fn(*mut c_void, newName: *const c_char, outEntryPoint: *mut *mut slang_IComponentType) -> SlangResult,
pub linkWithOptions: unsafe extern "C" fn(*mut c_void, outLinkedComponentType: *mut *mut slang_IComponentType, compilerOptionEntryCount: u32, compilerOptionEntries: *mut slang_CompilerOptionEntry, outDiagnostics: *mut *mut ISlangBlob) -> SlangResult,
pub getTargetCode: unsafe extern "C" fn(*mut c_void, targetIndex: SlangInt, outCode: *mut *mut ISlangBlob, outDiagnostics: *mut *mut ISlangBlob) -> SlangResult,
pub getTargetMetadata: unsafe extern "C" fn(*mut c_void, targetIndex: SlangInt, outMetadata: *mut *mut slang_IMetadata, outDiagnostics: *mut *mut ISlangBlob) -> SlangResult,
pub getEntryPointMetadata: unsafe extern "C" fn(*mut c_void, entryPointIndex: SlangInt, targetIndex: SlangInt, outMetadata: *mut *mut slang_IMetadata, outDiagnostics: *mut *mut ISlangBlob) -> SlangResult,
}
#[repr(C)]
@ -115,4 +117,5 @@ pub struct IModuleVtable {
pub findAndCheckEntryPoint: unsafe extern "C" fn(*mut c_void, name: *const c_char, stage: SlangStage, outEntryPoint: *mut *mut slang_IEntryPoint, outDiagnostics: *mut *mut ISlangBlob) -> SlangResult,
pub getDependencyFileCount: unsafe extern "C" fn(*mut c_void) -> SlangInt32,
pub getDependencyFilePath: unsafe extern "C" fn(*mut c_void, index: SlangInt32) -> *const c_char,
pub getModuleReflection: unsafe extern "C" fn(*mut c_void) -> *mut slang_DeclReflection,
}

View File

@ -1,3 +1,5 @@
pub mod reflection;
use std::ffi::{CStr, CString};
use std::ptr::{null, null_mut};
@ -270,6 +272,19 @@ unsafe impl Interface for ComponentType {
}
impl ComponentType {
pub fn layout(&self, target: i64) -> Result<&reflection::Shader> {
let mut diagnostics = null_mut();
let ptr = vcall!(self, getLayout(target, &mut diagnostics));
if ptr.is_null() {
Err(Error::Blob(Blob(IUnknown(
std::ptr::NonNull::new(diagnostics as *mut _).unwrap(),
))))
} else {
Ok(unsafe { &*(ptr as *const _) })
}
}
pub fn link(&self) -> Result<ComponentType> {
let mut linked_component_type = null_mut();
let mut diagnostics = null_mut();
@ -284,7 +299,7 @@ impl ComponentType {
)))
}
pub fn get_entry_point_code(&self, index: i64, target: i64) -> Result<Blob> {
pub fn entry_point_code(&self, index: i64, target: i64) -> Result<Blob> {
let mut code = null_mut();
let mut diagnostics = null_mut();
@ -300,6 +315,11 @@ impl ComponentType {
std::ptr::NonNull::new(code as *mut _).unwrap(),
)))
}
#[deprecated = "Use `entry_point_code` instead"]
pub fn get_entry_point_code(&self, index: i64, target: i64) -> Result<Blob> {
self.entry_point_code(index, target)
}
}
#[repr(transparent)]
@ -386,6 +406,11 @@ impl Module {
let identity = vcall!(self, getUniqueIdentity());
unsafe { CStr::from_ptr(identity).to_str().unwrap() }
}
pub fn module_reflection(&self) -> &reflection::Decl {
let ptr = vcall!(self, getModuleReflection());
unsafe { &*(ptr as *const _) }
}
}
pub struct TargetDescBuilder {

48
src/reflection/decl.rs Normal file
View File

@ -0,0 +1,48 @@
use super::{rcall, Function, Generic, Type, Variable};
use slang_sys as sys;
#[repr(transparent)]
pub struct Decl(sys::SlangReflectionDecl);
impl Decl {
pub fn name(&self) -> &str {
let name = rcall!(spReflectionDecl_getName(self));
unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }
}
pub fn kind(&self) -> sys::SlangDeclKind {
rcall!(spReflectionDecl_getKind(self))
}
pub fn child_count(&self) -> u32 {
rcall!(spReflectionDecl_getChildrenCount(self))
}
pub fn child_by_index(&self, index: u32) -> Option<&Decl> {
rcall!(spReflectionDecl_getChild(self, index) as Option<&Decl>)
}
pub fn children(&self) -> impl ExactSizeIterator<Item = &Decl> {
(0..self.child_count()).map(move |i| rcall!(spReflectionDecl_getChild(self, i) as &Decl))
}
pub fn ty(&self) -> &Type {
rcall!(spReflection_getTypeFromDecl(self) as &Type)
}
pub fn as_variable(&self) -> &Variable {
rcall!(spReflectionDecl_castToVariable(self) as &Variable)
}
pub fn as_function(&self) -> &Function {
rcall!(spReflectionDecl_castToFunction(self) as &Function)
}
pub fn as_generic(&self) -> &Generic {
rcall!(spReflectionDecl_castToGeneric(self) as &Generic)
}
pub fn parent(&self) -> &Decl {
rcall!(spReflectionDecl_getParent(self) as &Decl)
}
}

View File

@ -0,0 +1,62 @@
use super::{rcall, Function, TypeLayout, VariableLayout};
use slang_sys as sys;
#[repr(transparent)]
pub struct EntryPoint(sys::SlangReflectionEntryPoint);
impl EntryPoint {
pub fn name(&self) -> &str {
let name = rcall!(spReflectionEntryPoint_getName(self));
unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }
}
pub fn name_override(&self) -> Option<&str> {
let name = rcall!(spReflectionEntryPoint_getNameOverride(self));
(!name.is_null()).then(|| unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() })
}
pub fn parameter_count(&self) -> u32 {
rcall!(spReflectionEntryPoint_getParameterCount(self))
}
pub fn parameter_by_index(&self, index: u32) -> Option<&VariableLayout> {
rcall!(spReflectionEntryPoint_getParameterByIndex(self, index) as Option<&VariableLayout>)
}
pub fn parameters(&self) -> impl ExactSizeIterator<Item = &VariableLayout> {
(0..self.parameter_count()).map(move |i| {
rcall!(spReflectionEntryPoint_getParameterByIndex(self, i) as &VariableLayout)
})
}
pub fn function(&self) -> &Function {
rcall!(spReflectionEntryPoint_getFunction(self) as &Function)
}
pub fn stage(&self) -> sys::SlangStage {
rcall!(spReflectionEntryPoint_getStage(self))
}
// TODO: compute_thread_group_size
// TODO: compute_wave_size
pub fn uses_any_sample_rate_input(&self) -> bool {
rcall!(spReflectionEntryPoint_usesAnySampleRateInput(self)) != 0
}
pub fn var_layout(&self) -> &VariableLayout {
rcall!(spReflectionEntryPoint_getVarLayout(self) as &VariableLayout)
}
pub fn type_layout(&self) -> &TypeLayout {
self.var_layout().type_layout()
}
pub fn result_var_layout(&self) -> &VariableLayout {
rcall!(spReflectionEntryPoint_getResultVarLayout(self) as &VariableLayout)
}
pub fn has_default_constant_buffer(&self) -> bool {
rcall!(spReflectionEntryPoint_hasDefaultConstantBuffer(self)) != 0
}
}

View File

@ -0,0 +1,65 @@
use super::{rcall, Type, UserAttribute, Variable};
use slang_sys as sys;
#[repr(transparent)]
pub struct Function(sys::SlangReflectionFunction);
impl Function {
pub fn name(&self) -> &str {
let name = rcall!(spReflectionFunction_GetName(self));
unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }
}
pub fn return_type(&self) -> &Type {
rcall!(spReflectionFunction_GetResultType(self) as &Type)
}
pub fn parameter_count(&self) -> u32 {
rcall!(spReflectionFunction_GetParameterCount(self))
}
pub fn parameter_by_index(&self, index: u32) -> Option<&Variable> {
rcall!(spReflectionFunction_GetParameter(self, index) as Option<&Variable>)
}
pub fn parameters(&self) -> impl ExactSizeIterator<Item = &Variable> {
(0..self.parameter_count())
.map(move |i| rcall!(spReflectionFunction_GetParameter(self, i) as &Variable))
}
pub fn user_attribute_count(&self) -> u32 {
rcall!(spReflectionFunction_GetUserAttributeCount(self))
}
pub fn user_attribute_by_index(&self, index: u32) -> Option<&UserAttribute> {
rcall!(spReflectionFunction_GetUserAttribute(self, index) as Option<&UserAttribute>)
}
pub fn user_attributes(&self) -> impl ExactSizeIterator<Item = &UserAttribute> {
(0..self.user_attribute_count())
.map(move |i| rcall!(spReflectionFunction_GetUserAttribute(self, i) as &UserAttribute))
}
// TODO: find_user_attribute_by_name
// TODO: find_modifier
// TODO: generic_container
// TODO: apply_specializations
// TODO: specialize_with_arg_types
pub fn is_overloaded(&self) -> bool {
rcall!(spReflectionFunction_isOverloaded(self))
}
pub fn overload_count(&self) -> u32 {
rcall!(spReflectionFunction_getOverloadCount(self))
}
pub fn overload_by_index(&self, index: u32) -> Option<&Function> {
rcall!(spReflectionFunction_getOverload(self, index) as Option<&Function>)
}
pub fn overloads(&self) -> impl ExactSizeIterator<Item = &Function> {
(0..self.overload_count())
.map(move |i| rcall!(spReflectionFunction_getOverload(self, i) as &Function))
}
}

91
src/reflection/generic.rs Normal file
View File

@ -0,0 +1,91 @@
use super::{rcall, Decl, Type, TypeParameter, Variable};
use slang_sys as sys;
#[repr(transparent)]
pub struct Generic(sys::SlangReflectionGeneric);
impl Generic {
pub fn as_decl(&self) -> &Decl {
rcall!(spReflectionGeneric_asDecl(self) as &Decl)
}
pub fn name(&self) -> &str {
let name = rcall!(spReflectionGeneric_GetName(self));
unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }
}
pub fn type_parameter_count(&self) -> u32 {
rcall!(spReflectionGeneric_GetTypeParameterCount(self))
}
pub fn type_parameter_by_index(&self, index: u32) -> Option<&TypeParameter> {
rcall!(spReflectionGeneric_GetTypeParameter(self, index) as Option<&TypeParameter>)
}
pub fn type_parameters(&self) -> impl ExactSizeIterator<Item = &TypeParameter> {
(0..self.type_parameter_count())
.map(move |i| rcall!(spReflectionGeneric_GetTypeParameter(self, i) as &TypeParameter))
}
pub fn value_parameter_count(&self) -> u32 {
rcall!(spReflectionGeneric_GetValueParameterCount(self))
}
pub fn value_parameter_by_index(&self, index: u32) -> Option<&Variable> {
rcall!(spReflectionGeneric_GetValueParameter(self, index) as Option<&Variable>)
}
pub fn value_parameters(&self) -> impl ExactSizeIterator<Item = &Variable> {
(0..self.value_parameter_count())
.map(move |i| rcall!(spReflectionGeneric_GetValueParameter(self, i) as &Variable))
}
pub fn type_parameter_constraint_count(&self, type_param: &Variable) -> u32 {
rcall!(spReflectionGeneric_GetTypeParameterConstraintCount(
self,
type_param as *const _ as *mut _
))
}
pub fn type_parameter_constraint_by_index(
&self,
type_param: &Variable,
index: u32,
) -> Option<&Type> {
rcall!(spReflectionGeneric_GetTypeParameterConstraintType(
self,
type_param as *const _ as *mut _,
index
) as Option<&Type>)
}
pub fn inner_decl(&self) -> &Decl {
rcall!(spReflectionGeneric_GetInnerDecl(self) as &Decl)
}
pub fn inner_kind(&self) -> sys::SlangDeclKind {
rcall!(spReflectionGeneric_GetInnerKind(self))
}
pub fn outer_generic_container(&self) -> &Generic {
rcall!(spReflectionGeneric_GetOuterGenericContainer(self) as &Generic)
}
pub fn concrete_type(&self, type_param: &Variable) -> &Type {
rcall!(spReflectionGeneric_GetConcreteType(self, type_param as *const _ as *mut _) as &Type)
}
pub fn concrete_int_val(&self, value_param: &Variable) -> i64 {
rcall!(spReflectionGeneric_GetConcreteIntVal(
self,
value_param as *const _ as *mut _
))
}
pub fn apply_specializations(&self, generic: &Generic) -> &Generic {
rcall!(
spReflectionGeneric_applySpecializations(self, generic as *const _ as *mut _)
as &Generic
)
}
}

38
src/reflection/mod.rs Normal file
View File

@ -0,0 +1,38 @@
mod decl;
mod entry_point;
mod function;
mod generic;
mod shader;
mod ty;
mod type_parameter;
mod user_attribute;
mod variable;
pub use decl::Decl;
pub use entry_point::EntryPoint;
pub use function::Function;
pub use generic::Generic;
pub use shader::Shader;
pub use ty::{Type, TypeLayout};
pub use type_parameter::TypeParameter;
pub use user_attribute::UserAttribute;
pub use variable::{Variable, VariableLayout};
macro_rules! rcall {
($f:ident($s:ident $(,$arg:expr)*)) => {
unsafe { sys::$f($s as *const _ as *mut _ $(,$arg)*) }
};
($f:ident($s:ident $(,$arg:expr)*) as Option<&$cast:ty>) => {
unsafe {
let ptr = sys::$f($s as *const _ as *mut _ $(,$arg)*);
(!ptr.is_null()).then(|| &*(ptr as *const $cast))
}
};
($f:ident($s:ident $(,$arg:expr)*) as &$cast:ty) => {
unsafe { &*(sys::$f($s as *const _ as *mut _ $(,$arg)*) as *const $cast) }
};
}
pub(super) use rcall;

125
src/reflection/shader.rs Normal file
View File

@ -0,0 +1,125 @@
use super::{
rcall, EntryPoint, Function, Type, TypeLayout, TypeParameter, Variable, VariableLayout,
};
use slang_sys as sys;
#[repr(transparent)]
pub struct Shader(sys::SlangReflection);
impl Shader {
pub fn parameter_count(&self) -> u32 {
rcall!(spReflection_GetParameterCount(self))
}
pub fn parameter_by_index(&self, index: u32) -> Option<&VariableLayout> {
rcall!(spReflection_GetParameterByIndex(self, index) as Option<&VariableLayout>)
}
pub fn parameters(&self) -> impl ExactSizeIterator<Item = &VariableLayout> {
(0..self.parameter_count())
.map(move |i| rcall!(spReflection_GetParameterByIndex(self, i) as &VariableLayout))
}
pub fn type_parameter_count(&self) -> u32 {
rcall!(spReflection_GetTypeParameterCount(self))
}
pub fn type_parameter_by_index(&self, index: u32) -> Option<&TypeParameter> {
rcall!(spReflection_GetTypeParameterByIndex(self, index) as Option<&TypeParameter>)
}
pub fn type_parameters(&self) -> impl ExactSizeIterator<Item = &TypeParameter> {
(0..self.type_parameter_count())
.map(move |i| rcall!(spReflection_GetTypeParameterByIndex(self, i) as &TypeParameter))
}
pub fn find_type_parameter_by_name(&self, name: &str) -> Option<&TypeParameter> {
let name = std::ffi::CString::new(name).unwrap();
rcall!(spReflection_FindTypeParameter(self, name.as_ptr()) as Option<&TypeParameter>)
}
pub fn entry_point_count(&self) -> u32 {
rcall!(spReflection_getEntryPointCount(self)) as _
}
pub fn entry_point_by_index(&self, index: u32) -> Option<&EntryPoint> {
rcall!(spReflection_getEntryPointByIndex(self, index as _) as Option<&EntryPoint>)
}
pub fn entry_points(&self) -> impl ExactSizeIterator<Item = &EntryPoint> {
(0..self.entry_point_count())
.map(move |i| rcall!(spReflection_getEntryPointByIndex(self, i as _) as &EntryPoint))
}
pub fn find_entry_point_by_name(&self, name: &str) -> Option<&EntryPoint> {
let name = std::ffi::CString::new(name).unwrap();
rcall!(spReflection_findEntryPointByName(self, name.as_ptr()) as Option<&EntryPoint>)
}
pub fn global_constant_buffer_binding(&self) -> u64 {
rcall!(spReflection_getGlobalConstantBufferBinding(self))
}
pub fn global_constant_buffer_size(&self) -> usize {
rcall!(spReflection_getGlobalConstantBufferSize(self))
}
pub fn find_type_by_name(&self, name: &str) -> Option<&Type> {
let name = std::ffi::CString::new(name).unwrap();
rcall!(spReflection_FindTypeByName(self, name.as_ptr()) as Option<&Type>)
}
pub fn find_function_by_name(&self, name: &str) -> Option<&Function> {
let name = std::ffi::CString::new(name).unwrap();
rcall!(spReflection_FindFunctionByName(self, name.as_ptr()) as Option<&Function>)
}
pub fn find_function_by_name_in_type(&self, ty: &Type, name: &str) -> Option<&Function> {
let name = std::ffi::CString::new(name).unwrap();
rcall!(
spReflection_FindFunctionByNameInType(self, ty as *const _ as *mut _, name.as_ptr())
as Option<&Function>
)
}
pub fn find_var_by_name_in_type(&self, ty: &Type, name: &str) -> Option<&Variable> {
let name = std::ffi::CString::new(name).unwrap();
rcall!(
spReflection_FindVarByNameInType(self, ty as *const _ as *mut _, name.as_ptr())
as Option<&Variable>
)
}
fn type_layout(&self, ty: &Type, rules: sys::SlangLayoutRules) -> Option<&TypeLayout> {
rcall!(
spReflection_GetTypeLayout(self, ty as *const _ as *mut _, rules)
as Option<&TypeLayout>
)
}
// TODO: specialize_type
// TODO: specialize_generic
// TODO: is_sub_type
pub fn hashed_string_count(&self) -> u64 {
rcall!(spReflection_getHashedStringCount(self))
}
pub fn hashed_string(&self, index: u64) -> Option<&str> {
let mut len = 0;
let result = rcall!(spReflection_getHashedString(self, index, &mut len));
(!result.is_null()).then(|| {
let slice = unsafe { std::slice::from_raw_parts(result as *const u8, len as usize) };
std::str::from_utf8(slice).unwrap()
})
}
pub fn global_params_type_layout(&self) -> &TypeLayout {
rcall!(spReflection_getGlobalParamsTypeLayout(self) as &TypeLayout)
}
pub fn global_params_var_layout(&self) -> &VariableLayout {
rcall!(spReflection_getGlobalParamsVarLayout(self) as &VariableLayout)
}
}

376
src/reflection/ty.rs Normal file
View File

@ -0,0 +1,376 @@
use super::{rcall, UserAttribute, Variable, VariableLayout};
use slang_sys as sys;
#[repr(transparent)]
pub struct Type(sys::SlangReflectionType);
impl Type {
pub fn kind(&self) -> sys::SlangTypeKind {
rcall!(spReflectionType_GetKind(self))
}
pub fn field_count(&self) -> u32 {
rcall!(spReflectionType_GetFieldCount(self))
}
pub fn field_by_index(&self, index: u32) -> Option<&Variable> {
rcall!(spReflectionType_GetFieldByIndex(self, index) as Option<&Variable>)
}
pub fn fields(&self) -> impl ExactSizeIterator<Item = &Variable> {
(0..self.field_count())
.map(move |i| rcall!(spReflectionType_GetFieldByIndex(self, i) as &Variable))
}
// TODO: is_array
// TODO: unwrap_array
pub fn element_count(&self) -> usize {
rcall!(spReflectionType_GetElementCount(self))
}
// TODO: total_array_element_count
pub fn element_type(&self) -> &Type {
rcall!(spReflectionType_GetElementType(self) as &Type)
}
pub fn row_count(&self) -> u32 {
rcall!(spReflectionType_GetRowCount(self))
}
pub fn column_count(&self) -> u32 {
rcall!(spReflectionType_GetColumnCount(self))
}
pub fn scalar_type(&self) -> sys::SlangScalarType {
rcall!(spReflectionType_GetScalarType(self))
}
pub fn resource_result_type(&self) -> &Type {
rcall!(spReflectionType_GetResourceResultType(self) as &Type)
}
pub fn resource_shape(&self) -> sys::SlangResourceShape {
rcall!(spReflectionType_GetResourceShape(self))
}
pub fn resource_access(&self) -> sys::SlangResourceAccess {
rcall!(spReflectionType_GetResourceAccess(self))
}
pub fn name(&self) -> &str {
let name = rcall!(spReflectionType_GetName(self));
unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }
}
// TODO: full_name
pub fn user_attribute_count(&self) -> u32 {
rcall!(spReflectionType_GetUserAttributeCount(self))
}
pub fn user_attribute_by_index(&self, index: u32) -> Option<&UserAttribute> {
rcall!(spReflectionType_GetUserAttribute(self, index) as Option<&UserAttribute>)
}
pub fn user_attributes(&self) -> impl ExactSizeIterator<Item = &UserAttribute> {
(0..self.user_attribute_count())
.map(move |i| rcall!(spReflectionType_GetUserAttribute(self, i) as &UserAttribute))
}
pub fn find_user_attribute_by_name(&self, name: &str) -> Option<&UserAttribute> {
let name = std::ffi::CString::new(name).unwrap();
rcall!(
spReflectionType_FindUserAttributeByName(self, name.as_ptr()) as Option<&UserAttribute>
)
}
}
#[repr(transparent)]
pub struct TypeLayout(sys::SlangReflectionTypeLayout);
impl TypeLayout {
pub fn ty(&self) -> &Type {
rcall!(spReflectionTypeLayout_GetType(self) as &Type)
}
pub fn kind(&self) -> sys::SlangTypeKind {
rcall!(spReflectionTypeLayout_getKind(self))
}
pub fn size(&self, category: sys::SlangParameterCategory) -> usize {
rcall!(spReflectionTypeLayout_GetSize(self, category))
}
pub fn stride(&self, category: sys::SlangParameterCategory) -> usize {
rcall!(spReflectionTypeLayout_GetStride(self, category))
}
pub fn alignment(&self, category: sys::SlangParameterCategory) -> i32 {
rcall!(spReflectionTypeLayout_getAlignment(self, category))
}
pub fn field_count(&self) -> u32 {
rcall!(spReflectionTypeLayout_GetFieldCount(self))
}
pub fn field_by_index(&self, index: u32) -> Option<&VariableLayout> {
rcall!(spReflectionTypeLayout_GetFieldByIndex(self, index) as Option<&VariableLayout>)
}
pub fn fields(&self) -> impl ExactSizeIterator<Item = &VariableLayout> {
(0..self.field_count()).map(move |i| {
rcall!(spReflectionTypeLayout_GetFieldByIndex(self, i) as &VariableLayout)
})
}
// TODO: find_field_index_by_name
// TODO: explicit_counter
// TODO: is_array
// TODO: unwrap_array
pub fn element_count(&self) -> usize {
self.ty().element_count()
}
// TODO: total_array_element_count
pub fn element_stride(&self, category: sys::SlangParameterCategory) -> usize {
rcall!(spReflectionTypeLayout_GetElementStride(self, category))
}
pub fn element_type_layout(&self) -> &TypeLayout {
rcall!(spReflectionTypeLayout_GetElementTypeLayout(self) as &TypeLayout)
}
pub fn element_var_layout(&self) -> &VariableLayout {
rcall!(spReflectionTypeLayout_GetElementVarLayout(self) as &VariableLayout)
}
pub fn container_var_layout(&self) -> &VariableLayout {
rcall!(spReflectionTypeLayout_getContainerVarLayout(self) as &VariableLayout)
}
pub fn parameter_category(&self) -> sys::SlangParameterCategory {
rcall!(spReflectionTypeLayout_GetParameterCategory(self))
}
pub fn category_count(&self) -> u32 {
rcall!(spReflectionTypeLayout_GetCategoryCount(self))
}
pub fn category_by_index(&self, index: u32) -> sys::SlangParameterCategory {
rcall!(spReflectionTypeLayout_GetCategoryByIndex(self, index))
}
pub fn categories(&self) -> impl ExactSizeIterator<Item = sys::SlangParameterCategory> + '_ {
(0..self.category_count())
.map(move |i| rcall!(spReflectionTypeLayout_GetCategoryByIndex(self, i)))
}
pub fn row_count(&self) -> u32 {
self.ty().row_count()
}
pub fn column_count(&self) -> u32 {
self.ty().column_count()
}
pub fn scalar_type(&self) -> sys::SlangScalarType {
self.ty().scalar_type()
}
pub fn resource_result_type(&self) -> &Type {
self.ty().resource_result_type()
}
pub fn resource_shape(&self) -> sys::SlangResourceShape {
self.ty().resource_shape()
}
pub fn resource_access(&self) -> sys::SlangResourceAccess {
self.ty().resource_access()
}
pub fn name(&self) -> &str {
self.ty().name()
}
pub fn matrix_layout_mode(&self) -> sys::SlangMatrixLayoutMode {
rcall!(spReflectionTypeLayout_GetMatrixLayoutMode(self))
}
pub fn generic_param_index(&self) -> i32 {
rcall!(spReflectionTypeLayout_getGenericParamIndex(self))
}
pub fn pending_data_type_layout(&self) -> &TypeLayout {
rcall!(spReflectionTypeLayout_getPendingDataTypeLayout(self) as &TypeLayout)
}
pub fn specialized_type_pending_data_var_layout(&self) -> &VariableLayout {
rcall!(
spReflectionTypeLayout_getSpecializedTypePendingDataVarLayout(self) as &VariableLayout
)
}
pub fn binding_range_count(&self) -> i64 {
rcall!(spReflectionTypeLayout_getBindingRangeCount(self))
}
pub fn binding_range_type(&self, index: i64) -> sys::SlangBindingType {
rcall!(spReflectionTypeLayout_getBindingRangeType(self, index))
}
pub fn is_binding_range_specializable(&self, index: i64) -> bool {
rcall!(spReflectionTypeLayout_isBindingRangeSpecializable(
self, index
)) != 0
}
pub fn binding_range_binding_count(&self, index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getBindingRangeBindingCount(
self, index
))
}
pub fn field_binding_range_offset(&self, field_index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getFieldBindingRangeOffset(
self,
field_index
))
}
pub fn explicit_counter_binding_range_offset(&self) -> i64 {
rcall!(spReflectionTypeLayout_getExplicitCounterBindingRangeOffset(
self
))
}
pub fn binding_range_leaf_type_layout(&self, index: i64) -> &TypeLayout {
rcall!(spReflectionTypeLayout_getBindingRangeLeafTypeLayout(self, index) as &TypeLayout)
}
pub fn binding_range_leaf_variable(&self, index: i64) -> &Variable {
rcall!(spReflectionTypeLayout_getBindingRangeLeafVariable(self, index) as &Variable)
}
pub fn binding_range_image_format(&self, index: i64) -> sys::SlangImageFormat {
rcall!(spReflectionTypeLayout_getBindingRangeImageFormat(
self, index
))
}
pub fn binding_range_descriptor_set_index(&self, index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(
self, index
))
}
pub fn binding_range_first_descriptor_range_index(&self, index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex(self, index))
}
pub fn binding_range_descriptor_range_count(&self, index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getBindingRangeDescriptorRangeCount(
self, index
))
}
pub fn descriptor_set_count(&self) -> i64 {
rcall!(spReflectionTypeLayout_getDescriptorSetCount(self))
}
pub fn descriptor_set_space_offset(&self, set_index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getDescriptorSetSpaceOffset(
self, set_index
))
}
pub fn descriptor_set_descriptor_range_count(&self, set_index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount(
self, set_index
))
}
pub fn descriptor_set_descriptor_range_index_offset(
&self,
set_index: i64,
range_index: i64,
) -> i64 {
rcall!(
spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset(
self,
set_index,
range_index
)
)
}
pub fn descriptor_set_descriptor_range_descriptor_count(
&self,
set_index: i64,
range_index: i64,
) -> i64 {
rcall!(
spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount(
self,
set_index,
range_index
)
)
}
pub fn descriptor_set_descriptor_range_type(
&self,
set_index: i64,
range_index: i64,
) -> sys::SlangBindingType {
rcall!(spReflectionTypeLayout_getDescriptorSetDescriptorRangeType(
self,
set_index,
range_index
))
}
pub fn descriptor_set_descriptor_range_category(
&self,
set_index: i64,
range_index: i64,
) -> sys::SlangParameterCategory {
rcall!(
spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory(
self,
set_index,
range_index
)
)
}
pub fn sub_object_range_count(&self) -> i64 {
rcall!(spReflectionTypeLayout_getSubObjectRangeCount(self))
}
pub fn sub_object_range_binding_range_index(&self, sub_object_range_index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(
self,
sub_object_range_index
))
}
pub fn sub_object_range_space_offset(&self, sub_object_range_index: i64) -> i64 {
rcall!(spReflectionTypeLayout_getSubObjectRangeSpaceOffset(
self,
sub_object_range_index
))
}
pub fn sub_object_range_offset(&self, sub_object_range_index: i64) -> &VariableLayout {
rcall!(
spReflectionTypeLayout_getSubObjectRangeOffset(self, sub_object_range_index)
as &VariableLayout
)
}
}

View File

@ -0,0 +1,29 @@
use super::{rcall, Type};
use slang_sys as sys;
#[repr(transparent)]
pub struct TypeParameter(sys::SlangReflectionTypeParameter);
impl TypeParameter {
pub fn name(&self) -> &str {
let name = rcall!(spReflectionTypeParameter_GetName(self));
unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }
}
pub fn index(&self) -> u32 {
rcall!(spReflectionTypeParameter_GetIndex(self))
}
pub fn constraint_count(&self) -> u32 {
rcall!(spReflectionTypeParameter_GetConstraintCount(self))
}
pub fn constraint_by_index(&self, index: u32) -> &Type {
rcall!(spReflectionTypeParameter_GetConstraintByIndex(self, index) as &Type)
}
pub fn constraints(&self) -> impl ExactSizeIterator<Item = &Type> {
(0..self.constraint_count())
.map(move |i| rcall!(spReflectionTypeParameter_GetConstraintByIndex(self, i) as &Type))
}
}

View File

@ -0,0 +1,54 @@
use super::{rcall, Type};
use slang_sys as sys;
fn succeeded(result: sys::SlangResult) -> bool {
result >= 0
}
#[repr(transparent)]
pub struct UserAttribute(sys::SlangReflectionUserAttribute);
impl UserAttribute {
pub fn name(&self) -> &str {
let name = rcall!(spReflectionUserAttribute_GetName(self));
unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }
}
pub fn argument_count(&self) -> u32 {
rcall!(spReflectionUserAttribute_GetArgumentCount(self))
}
pub fn argument_type(&self, index: u32) -> &Type {
rcall!(spReflectionUserAttribute_GetArgumentType(self, index) as &Type)
}
pub fn argument_value_int(&self, index: u32) -> Option<i32> {
let mut out = 0;
let result = rcall!(spReflectionUserAttribute_GetArgumentValueInt(
self, index, &mut out
));
succeeded(result).then(|| out)
}
pub fn argument_value_float(&self, index: u32) -> Option<f32> {
let mut out = 0.0;
let result = rcall!(spReflectionUserAttribute_GetArgumentValueFloat(
self, index, &mut out
));
succeeded(result).then(|| out)
}
pub fn argument_value_string(&self, index: u32) -> Option<&str> {
let mut len = 0;
let result = rcall!(spReflectionUserAttribute_GetArgumentValueString(
self, index, &mut len
));
(!result.is_null()).then(|| {
let slice = unsafe { std::slice::from_raw_parts(result as *const u8, len as usize) };
std::str::from_utf8(slice).unwrap()
})
}
}

105
src/reflection/variable.rs Normal file
View File

@ -0,0 +1,105 @@
use super::{rcall, Type, TypeLayout, UserAttribute};
use slang_sys as sys;
#[repr(transparent)]
pub struct Variable(sys::SlangReflectionVariable);
impl Variable {
pub fn name(&self) -> &str {
let name = rcall!(spReflectionVariable_GetName(self));
unsafe { std::ffi::CStr::from_ptr(name).to_str().unwrap() }
}
pub fn ty(&self) -> &Type {
rcall!(spReflectionVariable_GetType(self) as &Type)
}
// TODO: find_modifier
pub fn user_attribute_count(&self) -> u32 {
rcall!(spReflectionVariable_GetUserAttributeCount(self))
}
pub fn user_attribute_by_index(&self, index: u32) -> Option<&UserAttribute> {
rcall!(spReflectionVariable_GetUserAttribute(self, index) as Option<&UserAttribute>)
}
pub fn user_attributes(&self) -> impl ExactSizeIterator<Item = &UserAttribute> {
(0..self.user_attribute_count())
.map(move |i| rcall!(spReflectionVariable_GetUserAttribute(self, i) as &UserAttribute))
}
// TODO: find_user_attribute_by_name
pub fn has_default_value(&self) -> bool {
rcall!(spReflectionVariable_HasDefaultValue(self))
}
// TODO: generic_container
// TODO: apply_specializations
}
#[repr(transparent)]
pub struct VariableLayout(sys::SlangReflectionVariableLayout);
impl VariableLayout {
pub fn variable(&self) -> &Variable {
rcall!(spReflectionVariableLayout_GetVariable(self) as &Variable)
}
// TODO: get_name
// TODO: find_modifier
pub fn type_layout(&self) -> &TypeLayout {
rcall!(spReflectionVariableLayout_GetTypeLayout(self) as &TypeLayout)
}
pub fn category(&self) -> sys::SlangParameterCategory {
self.type_layout().parameter_category()
}
pub fn category_count(&self) -> u32 {
self.type_layout().category_count()
}
pub fn category_by_index(&self, index: u32) -> sys::SlangParameterCategory {
self.type_layout().category_by_index(index)
}
pub fn offset(&self, category: sys::SlangParameterCategory) -> usize {
rcall!(spReflectionVariableLayout_GetOffset(self, category))
}
pub fn ty(&self) -> &Type {
self.variable().ty()
}
pub fn binding_index(&self) -> u32 {
rcall!(spReflectionParameter_GetBindingIndex(self))
}
pub fn binding_space(&self) -> u32 {
rcall!(spReflectionParameter_GetBindingSpace(self))
}
pub fn binding_space_with_category(&self, category: sys::SlangParameterCategory) -> usize {
rcall!(spReflectionVariableLayout_GetSpace(self, category))
}
pub fn semantic_name(&self) -> Option<&str> {
let name = rcall!(spReflectionVariableLayout_GetSemanticName(self));
unsafe { (!name.is_null()).then(|| std::ffi::CStr::from_ptr(name).to_str().unwrap()) }
}
pub fn semantic_index(&self) -> usize {
rcall!(spReflectionVariableLayout_GetSemanticIndex(self))
}
pub fn stage(&self) -> sys::SlangStage {
rcall!(spReflectionVariableLayout_getStage(self))
}
pub fn pending_data_layout(&self) -> &VariableLayout {
rcall!(spReflectionVariableLayout_getPendingDataLayout(self) as &VariableLayout)
}
}