summaryrefslogtreecommitdiff
path: root/engine/src/rendering/shader
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/rendering/shader')
-rw-r--r--engine/src/rendering/shader/cursor.rs385
-rw-r--r--engine/src/rendering/shader/reflection.rs713
2 files changed, 1098 insertions, 0 deletions
diff --git a/engine/src/rendering/shader/cursor.rs b/engine/src/rendering/shader/cursor.rs
new file mode 100644
index 0000000..7750623
--- /dev/null
+++ b/engine/src/rendering/shader/cursor.rs
@@ -0,0 +1,385 @@
+use std::borrow::Cow;
+use std::fmt::Display;
+use std::hint::cold_path;
+
+use circular_buffer::HeapCircularBuffer;
+
+use crate::color::{Color, Rgb, Rgba};
+use crate::data_types::matrix::Matrix;
+use crate::data_types::vector::Vec3;
+use crate::rendering::object::Id as RenderingObjectId;
+use crate::rendering::shader::reflection::{
+ ResourceShape,
+ ScalarType,
+ TypeKind,
+ TypeLayout,
+ VariableLayout,
+};
+
+/// Shader cursor
+#[derive(Clone)]
+pub struct Cursor<'a>
+{
+ type_layout: TypeLayout<'a>,
+ binding_location: BindingLocation,
+ location_path: LocationPath,
+}
+
+impl<'a> Cursor<'a>
+{
+ #[must_use]
+ pub fn new(var_layout: VariableLayout<'a>) -> Self
+ {
+ let binding_location = BindingLocation {
+ binding_index: var_layout.binding_index(),
+ binding_size: 0,
+ byte_offset: var_layout.offset(),
+ };
+
+ Self {
+ type_layout: var_layout.type_layout().unwrap(),
+ binding_location,
+ location_path: LocationPath::new(),
+ }
+ }
+
+ #[must_use]
+ pub fn field(&self, name: impl Into<Cow<'static, str>>) -> Self
+ {
+ let name = name.into();
+
+ let Some(field_var_layout) = self.type_layout.get_field_by_name(name.as_ref())
+ else {
+ panic!("Field '{name}' does not exist");
+ };
+
+ let field_type_kind = field_var_layout.ty().unwrap().kind();
+
+ let (new_var_layout, binding_index_offset) = match field_type_kind {
+ TypeKind::ConstantBuffer => {
+ let elem_var_layout = field_var_layout
+ .type_layout()
+ .expect("Constant buffer field has no type layout")
+ .element_var_layout()
+ .expect(
+ "Constant buffer field type layout has no element var layout",
+ );
+
+ (
+ elem_var_layout,
+ field_var_layout.binding_index() + elem_var_layout.binding_index(),
+ )
+ }
+ TypeKind::Array
+ | TypeKind::Matrix
+ | TypeKind::Scalar
+ | TypeKind::Vector
+ | TypeKind::Struct
+ | TypeKind::Resource => (field_var_layout, field_var_layout.binding_index()),
+ type_kind => unimplemented!("Type kind {type_kind:?} is not yet supported"),
+ };
+
+ let mut location_path = self.location_path.clone();
+
+ location_path.push(Location::Field(name));
+
+ Self {
+ type_layout: new_var_layout.type_layout().unwrap(),
+ binding_location: BindingLocation {
+ binding_index: self.binding_location.binding_index + binding_index_offset,
+ binding_size: if field_type_kind == TypeKind::ConstantBuffer {
+ new_var_layout
+ .type_layout()
+ .unwrap()
+ .uniform_size()
+ .unwrap()
+ } else {
+ self.binding_location.binding_size
+ },
+ byte_offset: self.binding_location.byte_offset + new_var_layout.offset(),
+ },
+ location_path,
+ }
+ }
+
+ #[must_use]
+ pub fn element(mut self, index: usize) -> Self
+ {
+ debug_assert_eq!(self.type_layout.kind(), TypeKind::Array);
+
+ debug_assert!(
+ index < self.type_layout.element_cnt().unwrap_or(0),
+ "Array element index {index} is out of bounds"
+ );
+
+ let element_type_layout = self.type_layout.element_type_layout().unwrap();
+
+ self.binding_location.byte_offset += index * element_type_layout.stride();
+
+ self.type_layout = element_type_layout;
+
+ self.location_path.push(Location::Element(index));
+
+ self
+ }
+
+ pub fn binding(self, value: BindingValue) -> Result<Binding, BindingError>
+ {
+ value.validate_for_shader_type(self.type_layout, self.location_path)?;
+
+ Ok(Binding {
+ location: self.binding_location,
+ value,
+ })
+ }
+}
+
+/// Shader cursor location.
+#[derive(Debug, Clone)]
+pub struct LocationPath
+{
+ locations: HeapCircularBuffer<Location>,
+ is_truncated: bool,
+}
+
+impl LocationPath
+{
+ fn new() -> Self
+ {
+ Self {
+ locations: HeapCircularBuffer::with_capacity(16),
+ is_truncated: false,
+ }
+ }
+
+ fn push(&mut self, location: Location)
+ {
+ if self.locations.push_back(location).is_some() {
+ self.is_truncated = true;
+ }
+ }
+}
+
+impl Display for LocationPath
+{
+ fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
+ {
+ if self.is_truncated {
+ write!(formatter, "(...)")?;
+ }
+
+ for location in &self.locations {
+ match location {
+ Location::Field(field) => {
+ write!(formatter, ".{field}")?;
+ }
+ Location::Element(element) => {
+ write!(formatter, "[{element}]")?;
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+/// Shader cursor location.
+#[derive(Debug, Clone)]
+pub enum Location
+{
+ Field(Cow<'static, str>),
+ Element(usize),
+}
+
+impl Display for Location
+{
+ fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
+ {
+ match self {
+ Self::Field(field) => <Cow<'static, str> as Display>::fmt(field, formatter),
+ Self::Element(element) => <usize as Display>::fmt(element, formatter),
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct BindingLocation
+{
+ pub binding_index: u32,
+ pub binding_size: usize,
+ pub byte_offset: usize,
+}
+
+#[derive(Debug, Clone)]
+pub enum BindingValue
+{
+ Uint(u32),
+ Int(i32),
+ Float(f32),
+ FVec3(Vec3<f32>),
+ Color(Color<f32>),
+ FMat4x4(Matrix<f32, 4, 4>),
+ Texture(RenderingObjectId, BindingTextureKind),
+}
+
+impl BindingValue
+{
+ fn validate_for_shader_type(
+ &self,
+ ty: TypeLayout<'_>,
+ location_path: LocationPath,
+ ) -> Result<(), BindingError>
+ {
+ let ty_kind = ty.kind();
+ let scalar_ty = ty.scalar_type();
+
+ let element_scalar_ty = ty
+ .element_type_layout()
+ .and_then(|elem_ty| elem_ty.scalar_type());
+
+ let element_cnt = ty.element_cnt();
+
+ let is_valid = match self {
+ Self::Uint(_) => {
+ ty_kind == TypeKind::Scalar && scalar_ty == Some(ScalarType::Uint32)
+ }
+ Self::Int(_) => {
+ ty_kind == TypeKind::Scalar && scalar_ty == Some(ScalarType::Int32)
+ }
+ Self::Float(_) => {
+ ty_kind == TypeKind::Scalar && scalar_ty == Some(ScalarType::Float32)
+ }
+ Self::FVec3(_) | Self::Color(Color::Rgb(_)) => {
+ ty_kind == TypeKind::Vector
+ && element_scalar_ty == Some(ScalarType::Float32)
+ && element_cnt == Some(3)
+ }
+ Self::Color(Color::Rgba(_)) => {
+ ty_kind == TypeKind::Vector
+ && element_scalar_ty == Some(ScalarType::Float32)
+ && element_cnt == Some(4)
+ }
+ Self::FMat4x4(_) => {
+ ty_kind == TypeKind::Matrix
+ && element_scalar_ty == Some(ScalarType::Float32)
+ && ty.row_cnt() == Some(4)
+ && ty.column_cnt() == Some(4)
+ }
+ Self::Texture(_, BindingTextureKind::Texture2D) => {
+ ty_kind == TypeKind::Resource
+ && ty.resource_shape().is_some_and(|res_shape| {
+ (res_shape & ResourceShape::BASE)
+ .contains(ResourceShape::TEXTURE_2D)
+ })
+ }
+ Self::Texture(_, BindingTextureKind::Cube) => {
+ ty_kind == TypeKind::Resource
+ && ty.resource_shape().is_some_and(|res_shape| {
+ (res_shape & ResourceShape::BASE)
+ .contains(ResourceShape::TEXTURE_CUBE)
+ })
+ }
+ };
+
+ if !is_valid {
+ cold_path();
+ return Err(BindingError::IncorrectValueType {
+ value: self.clone(),
+ location_path,
+ });
+ }
+
+ Ok(())
+ }
+}
+
+impl From<u32> for BindingValue
+{
+ fn from(value: u32) -> Self
+ {
+ BindingValue::Uint(value)
+ }
+}
+
+impl From<i32> for BindingValue
+{
+ fn from(value: i32) -> Self
+ {
+ BindingValue::Int(value)
+ }
+}
+
+impl From<f32> for BindingValue
+{
+ fn from(value: f32) -> Self
+ {
+ BindingValue::Float(value)
+ }
+}
+
+impl From<Vec3<f32>> for BindingValue
+{
+ fn from(vec: Vec3<f32>) -> Self
+ {
+ BindingValue::FVec3(vec)
+ }
+}
+
+impl From<Color<f32>> for BindingValue
+{
+ fn from(color: Color<f32>) -> Self
+ {
+ BindingValue::Color(color)
+ }
+}
+impl From<Rgb<f32>> for BindingValue
+{
+ fn from(color: Rgb<f32>) -> Self
+ {
+ BindingValue::Color(color.into())
+ }
+}
+
+impl From<Rgba<f32>> for BindingValue
+{
+ fn from(color: Rgba<f32>) -> Self
+ {
+ BindingValue::Color(color.into())
+ }
+}
+
+impl From<Matrix<f32, 4, 4>> for BindingValue
+{
+ fn from(matrix: Matrix<f32, 4, 4>) -> Self
+ {
+ BindingValue::FMat4x4(matrix)
+ }
+}
+
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub struct Binding
+{
+ pub location: BindingLocation,
+ pub value: BindingValue,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum BindingTextureKind
+{
+ Texture2D,
+ Cube,
+}
+
+#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
+pub enum BindingError
+{
+ #[error("Value {value:?} has incorrect type for value at {location_path} in shader")]
+ IncorrectValueType
+ {
+ value: BindingValue,
+ location_path: LocationPath,
+ },
+}
diff --git a/engine/src/rendering/shader/reflection.rs b/engine/src/rendering/shader/reflection.rs
new file mode 100644
index 0000000..c6d9248
--- /dev/null
+++ b/engine/src/rendering/shader/reflection.rs
@@ -0,0 +1,713 @@
+use bitflags::bitflags;
+
+pub struct Function<'a>
+{
+ pub(super) inner: &'a shader_slang::reflection::Function,
+}
+
+impl Function<'_>
+{
+ #[must_use]
+ pub fn name(&self) -> Option<&str>
+ {
+ self.inner.name()
+ }
+}
+
+pub struct EntryPointReflection<'a>
+{
+ inner: &'a shader_slang::reflection::EntryPoint,
+}
+
+impl<'a> EntryPointReflection<'a>
+{
+ #[must_use]
+ pub fn name(&self) -> Option<&str>
+ {
+ self.inner.name()
+ }
+
+ #[must_use]
+ pub fn name_override(&self) -> Option<&str>
+ {
+ self.inner.name_override()
+ }
+
+ #[must_use]
+ pub fn stage(&self) -> Stage
+ {
+ Stage::from_slang_stage(self.inner.stage())
+ }
+
+ #[must_use]
+ pub fn parameters(&self) -> impl ExactSizeIterator<Item = VariableLayout<'a>>
+ {
+ self.inner
+ .parameters()
+ .map(|param| VariableLayout { inner: param })
+ }
+
+ #[must_use]
+ pub fn var_layout(&self) -> Option<VariableLayout<'a>>
+ {
+ Some(VariableLayout { inner: self.inner.var_layout()? })
+ }
+}
+
+pub struct Program<'a>
+{
+ pub(super) inner: &'a shader_slang::reflection::Shader,
+}
+
+impl<'a> Program<'a>
+{
+ #[must_use]
+ pub fn get_entry_point_by_index(&self, index: u32)
+ -> Option<EntryPointReflection<'a>>
+ {
+ Some(EntryPointReflection {
+ inner: self.inner.entry_point_by_index(index)?,
+ })
+ }
+
+ #[must_use]
+ pub fn get_entry_point_by_name(&self, name: &str)
+ -> Option<EntryPointReflection<'a>>
+ {
+ Some(EntryPointReflection {
+ inner: self.inner.find_entry_point_by_name(name)?,
+ })
+ }
+
+ #[must_use]
+ pub fn entry_points(
+ &self,
+ ) -> impl ExactSizeIterator<Item = EntryPointReflection<'a>> + use<'a>
+ {
+ self.inner
+ .entry_points()
+ .map(|entry_point| EntryPointReflection { inner: entry_point })
+ }
+
+ #[must_use]
+ pub fn global_params_type_layout(&self) -> Option<TypeLayout<'a>>
+ {
+ Some(TypeLayout {
+ inner: self.inner.global_params_type_layout()?,
+ })
+ }
+
+ #[must_use]
+ pub fn global_params_var_layout(&self) -> Option<VariableLayout<'a>>
+ {
+ Some(VariableLayout {
+ inner: self.inner.global_params_var_layout()?,
+ })
+ }
+
+ #[must_use]
+ pub fn get_type(&self, name: &str) -> Option<TypeReflection<'a>>
+ {
+ Some(TypeReflection {
+ inner: self.inner.find_type_by_name(name)?,
+ })
+ }
+
+ #[must_use]
+ pub fn get_type_layout(&self, ty: &TypeReflection<'a>) -> Option<TypeLayout<'a>>
+ {
+ Some(TypeLayout {
+ inner: self
+ .inner
+ .type_layout(ty.inner, shader_slang::LayoutRules::Default)?,
+ })
+ }
+}
+
+#[derive(Clone, Copy)]
+pub struct VariableLayout<'a>
+{
+ inner: &'a shader_slang::reflection::VariableLayout,
+}
+
+impl<'a> VariableLayout<'a>
+{
+ #[must_use]
+ pub fn name(&self) -> Option<&'a str>
+ {
+ self.inner.name()
+ }
+
+ #[must_use]
+ pub fn semantic_name(&self) -> Option<&str>
+ {
+ self.inner.semantic_name()
+ }
+
+ #[must_use]
+ pub fn binding_index(&self) -> u32
+ {
+ self.inner
+ .offset(shader_slang::ParameterCategory::DescriptorTableSlot) as u32
+
+ // self.inner.binding_index()
+ }
+
+ #[must_use]
+ pub fn varying_input_offset(&self) -> Option<usize>
+ {
+ if !self
+ .inner
+ .categories()
+ .any(|category| category == shader_slang::ParameterCategory::VaryingInput)
+ {
+ return None;
+ }
+
+ Some(
+ self.inner
+ .offset(shader_slang::ParameterCategory::VaryingInput),
+ )
+ }
+
+ #[must_use]
+ pub fn binding_space(&self) -> u32
+ {
+ self.inner.binding_space()
+ }
+
+ #[must_use]
+ pub fn semantic_index(&self) -> usize
+ {
+ self.inner.semantic_index()
+ }
+
+ #[must_use]
+ pub fn offset(&self) -> usize
+ {
+ self.inner.offset(shader_slang::ParameterCategory::Uniform)
+ }
+
+ #[must_use]
+ pub fn ty(&self) -> Option<TypeReflection<'a>>
+ {
+ self.inner.ty().map(|ty| TypeReflection { inner: ty })
+ }
+
+ #[must_use]
+ pub fn type_layout(&self) -> Option<TypeLayout<'a>>
+ {
+ Some(TypeLayout { inner: self.inner.type_layout()? })
+ }
+}
+
+#[derive(Clone, Copy)]
+pub struct TypeLayout<'a>
+{
+ inner: &'a shader_slang::reflection::TypeLayout,
+}
+
+impl<'a> TypeLayout<'a>
+{
+ #[must_use]
+ pub fn kind(&self) -> TypeKind
+ {
+ TypeKind::from_slang_type_kind(self.inner.kind())
+ }
+
+ #[must_use]
+ pub fn scalar_type(&self) -> Option<ScalarType>
+ {
+ Some(ScalarType::from_slang_scalar_type(
+ self.inner.scalar_type()?,
+ ))
+ }
+
+ #[must_use]
+ pub fn resource_shape(&self) -> Option<ResourceShape>
+ {
+ Some(ResourceShape::from_bits_retain(
+ self.inner.resource_shape()? as u32,
+ ))
+ }
+
+ #[must_use]
+ pub fn get_field_by_name(&self, name: &str) -> Option<VariableLayout<'a>>
+ {
+ let index = self.inner.find_field_index_by_name(name);
+
+ if index < 0 {
+ return None;
+ }
+
+ let index = u32::try_from(index.cast_unsigned()).expect("Should not happend");
+
+ let field = self.inner.field_by_index(index)?;
+
+ Some(VariableLayout { inner: field })
+ }
+
+ #[must_use]
+ pub fn parameter_category(&self) -> ParameterCategory
+ {
+ ParameterCategory::from_slang_parameter_category(self.inner.parameter_category())
+ }
+
+ #[must_use]
+ pub fn binding_range_descriptor_set_index(&self, index: i64) -> i64
+ {
+ self.inner.binding_range_descriptor_set_index(index)
+ }
+
+ #[must_use]
+ pub fn get_field_binding_range_offset_by_name(&self, name: &str) -> Option<u64>
+ {
+ let field_index = self.inner.find_field_index_by_name(name);
+
+ if field_index < 0 {
+ return None;
+ }
+
+ let field_binding_range_offset =
+ self.inner.field_binding_range_offset(field_index);
+
+ if field_binding_range_offset < 0 {
+ return None;
+ }
+
+ Some(field_binding_range_offset.cast_unsigned())
+ }
+
+ #[must_use]
+ pub fn ty(&self) -> Option<TypeReflection<'a>>
+ {
+ self.inner.ty().map(|ty| TypeReflection { inner: ty })
+ }
+
+ #[must_use]
+ pub fn fields(&self) -> FieldIter<'a>
+ {
+ FieldIter {
+ type_layout: *self,
+ cnt: self.field_cnt(),
+ index: 0,
+ }
+ }
+
+ #[must_use]
+ pub fn field_cnt(&self) -> u32
+ {
+ self.inner.field_count()
+ }
+
+ #[must_use]
+ pub fn element_cnt(&self) -> Option<usize>
+ {
+ self.inner.element_count()
+ }
+
+ #[must_use]
+ pub fn row_cnt(&self) -> Option<u32>
+ {
+ self.inner.row_count()
+ }
+
+ #[must_use]
+ pub fn column_cnt(&self) -> Option<u32>
+ {
+ self.inner.column_count()
+ }
+
+ #[must_use]
+ pub fn element_type_layout(&self) -> Option<TypeLayout<'a>>
+ {
+ self.inner
+ .element_type_layout()
+ .map(|type_layout| TypeLayout { inner: type_layout })
+ }
+
+ #[must_use]
+ pub fn element_var_layout(&self) -> Option<VariableLayout<'a>>
+ {
+ self.inner
+ .element_var_layout()
+ .map(|var_layout| VariableLayout { inner: var_layout })
+ }
+
+ #[must_use]
+ pub fn container_var_layout(&self) -> Option<VariableLayout<'a>>
+ {
+ self.inner
+ .container_var_layout()
+ .map(|var_layout| VariableLayout { inner: var_layout })
+ }
+
+ #[must_use]
+ pub fn uniform_size(&self) -> Option<usize>
+ {
+ if !self
+ .inner
+ .categories()
+ .any(|category| category == shader_slang::ParameterCategory::Uniform)
+ {
+ return None;
+ }
+
+ Some(self.inner.size(shader_slang::ParameterCategory::Uniform))
+ }
+
+ #[must_use]
+ pub fn stride(&self) -> usize
+ {
+ self.inner.stride(self.inner.categories().next().unwrap())
+ }
+}
+
+pub struct FieldIter<'a>
+{
+ type_layout: TypeLayout<'a>,
+ cnt: u32,
+ index: u32,
+}
+
+impl<'a> Iterator for FieldIter<'a>
+{
+ type Item = VariableLayout<'a>;
+
+ fn next(&mut self) -> Option<Self::Item>
+ {
+ if self.index == self.cnt {
+ return None;
+ }
+
+ let Some(field) = self.type_layout.inner.field_by_index(self.index) else {
+ unreachable!();
+ };
+
+ self.index += 1;
+
+ Some(VariableLayout { inner: field })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>)
+ {
+ let len = (self.cnt - self.index) as usize;
+
+ (len, Some(len))
+ }
+}
+
+impl ExactSizeIterator for FieldIter<'_>
+{
+ fn len(&self) -> usize
+ {
+ (self.cnt - self.index) as usize
+ }
+}
+
+impl DoubleEndedIterator for FieldIter<'_>
+{
+ fn next_back(&mut self) -> Option<Self::Item>
+ {
+ if self.cnt == 0 || self.index == self.cnt - 1 {
+ return None;
+ }
+
+ let Some(field) = self.type_layout.inner.field_by_index(self.cnt - 1) else {
+ unreachable!();
+ };
+
+ self.cnt -= 1;
+
+ Some(VariableLayout { inner: field })
+ }
+}
+
+pub struct TypeReflection<'a>
+{
+ inner: &'a shader_slang::reflection::Type,
+}
+
+impl TypeReflection<'_>
+{
+ #[must_use]
+ pub fn kind(&self) -> TypeKind
+ {
+ TypeKind::from_slang_type_kind(self.inner.kind())
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[non_exhaustive]
+pub enum TypeKind
+{
+ None,
+ Struct,
+ Enum,
+ Array,
+ Matrix,
+ Vector,
+ Scalar,
+ ConstantBuffer,
+ Resource,
+ SamplerState,
+ TextureBuffer,
+ ShaderStorageBuffer,
+ ParameterBlock,
+ GenericTypeParameter,
+ Interface,
+ OutputStream,
+ MeshOutput,
+ Specialized,
+ Feedback,
+ Pointer,
+ DynamicResource,
+ Count,
+}
+
+impl TypeKind
+{
+ fn from_slang_type_kind(type_kind: shader_slang::TypeKind) -> Self
+ {
+ match type_kind {
+ shader_slang::TypeKind::None => Self::None,
+ shader_slang::TypeKind::Struct => Self::Struct,
+ shader_slang::TypeKind::Enum => Self::Enum,
+ shader_slang::TypeKind::Array => Self::Array,
+ shader_slang::TypeKind::Matrix => Self::Matrix,
+ shader_slang::TypeKind::Vector => Self::Vector,
+ shader_slang::TypeKind::Scalar => Self::Scalar,
+ shader_slang::TypeKind::ConstantBuffer => Self::ConstantBuffer,
+ shader_slang::TypeKind::Resource => Self::Resource,
+ shader_slang::TypeKind::SamplerState => Self::SamplerState,
+ shader_slang::TypeKind::TextureBuffer => Self::TextureBuffer,
+ shader_slang::TypeKind::ShaderStorageBuffer => Self::ShaderStorageBuffer,
+ shader_slang::TypeKind::ParameterBlock => Self::ParameterBlock,
+ shader_slang::TypeKind::GenericTypeParameter => Self::GenericTypeParameter,
+ shader_slang::TypeKind::Interface => Self::Interface,
+ shader_slang::TypeKind::OutputStream => Self::OutputStream,
+ shader_slang::TypeKind::MeshOutput => Self::MeshOutput,
+ shader_slang::TypeKind::Specialized => Self::Specialized,
+ shader_slang::TypeKind::Feedback => Self::Feedback,
+ shader_slang::TypeKind::Pointer => Self::Pointer,
+ shader_slang::TypeKind::DynamicResource => Self::DynamicResource,
+ shader_slang::TypeKind::Count => Self::Count,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[non_exhaustive]
+pub enum ScalarType
+{
+ None,
+ Void,
+ Bool,
+ Int32,
+ Uint32,
+ Int64,
+ Uint64,
+ Float16,
+ Float32,
+ Float64,
+ Int8,
+ Uint8,
+ Int16,
+ Uint16,
+ Intptr,
+ Uintptr,
+ Bfloat16,
+ FloatE4m3,
+ FloatE5m2,
+}
+
+impl ScalarType
+{
+ fn from_slang_scalar_type(scalar_type: shader_slang::ScalarType) -> Self
+ {
+ match scalar_type {
+ shader_slang::ScalarType::None => Self::None,
+ shader_slang::ScalarType::Void => Self::Void,
+ shader_slang::ScalarType::Bool => Self::Bool,
+ shader_slang::ScalarType::Int32 => Self::Int32,
+ shader_slang::ScalarType::Uint32 => Self::Uint32,
+ shader_slang::ScalarType::Int64 => Self::Int64,
+ shader_slang::ScalarType::Uint64 => Self::Uint64,
+ shader_slang::ScalarType::Float16 => Self::Float16,
+ shader_slang::ScalarType::Float32 => Self::Float32,
+ shader_slang::ScalarType::Float64 => Self::Float64,
+ shader_slang::ScalarType::Int8 => Self::Int8,
+ shader_slang::ScalarType::Uint8 => Self::Uint8,
+ shader_slang::ScalarType::Int16 => Self::Int16,
+ shader_slang::ScalarType::Uint16 => Self::Uint16,
+ shader_slang::ScalarType::Intptr => Self::Intptr,
+ shader_slang::ScalarType::Uintptr => Self::Uintptr,
+ shader_slang::ScalarType::Bfloat16 => Self::Bfloat16,
+ shader_slang::ScalarType::FloatE4m3 => Self::FloatE4m3,
+ shader_slang::ScalarType::FloatE5m2 => Self::FloatE5m2,
+ #[allow(unreachable_patterns)]
+ _ => unimplemented!("conversion from slang scalar type"),
+ }
+ }
+}
+
+bitflags! {
+#[derive(Debug, Copy, Clone)]
+pub struct ResourceShape: u32 {
+ const BASE = shader_slang::ResourceShape::SlangResourceBaseShapeMask as u32;
+ const NONE = shader_slang::ResourceShape::SlangResourceNone as u32;
+ const TEXTURE_1D = shader_slang::ResourceShape::SlangTexture1d as u32;
+ const TEXTURE_2D = shader_slang::ResourceShape::SlangTexture2d as u32;
+ const TEXTURE_3D = shader_slang::ResourceShape::SlangTexture3d as u32;
+ const TEXTURE_CUBE = shader_slang::ResourceShape::SlangTextureCube as u32;
+ const TEXTURE_BUFFER = shader_slang::ResourceShape::SlangTextureBuffer as u32;
+ const STRUCTURED_BUFFER = shader_slang::ResourceShape::SlangStructuredBuffer as u32;
+ const BYTE_ADDRESS_BUFFER = shader_slang::ResourceShape::SlangByteAddressBuffer as u32;
+ const UNKNOWN = shader_slang::ResourceShape::SlangResourceUnknown as u32;
+ const ACCELERATION_STRUCTURE = shader_slang::ResourceShape::SlangAccelerationStructure as u32;
+ const TEXTURE_SUBPASS = shader_slang::ResourceShape::SlangTextureSubpass as u32;
+ const EXT_SHAPE = shader_slang::ResourceShape::SlangResourceExtShapeMask as u32;
+ const TEXTURE_FEEDBACK_FLAG = shader_slang::ResourceShape::SlangTextureFeedbackFlag as u32;
+ const TEXTURE_SHADOW_FLAG = shader_slang::ResourceShape::SlangTextureShadowFlag as u32;
+ const TEXTURE_ARRAY_FLAG = shader_slang::ResourceShape::SlangTextureArrayFlag as u32;
+ const TEXTURE_MULTISAMPLE_FLAG = shader_slang::ResourceShape::SlangTextureMultisampleFlag as u32;
+ const TEXTURE_COMBINED_FLAG = shader_slang::ResourceShape::SlangTextureCombinedFlag as u32;
+ const TEXTURE_1D_ARRAY = shader_slang::ResourceShape::SlangTexture1dArray as u32;
+ const TEXTURE_2D_ARRAY = shader_slang::ResourceShape::SlangTexture2dArray as u32;
+ const TEXTURE_CUBE_ARRAY = shader_slang::ResourceShape::SlangTextureCubeArray as u32;
+ const TEXTURE_2D_MULTISAMPLE = shader_slang::ResourceShape::SlangTexture2dMultisample as u32;
+ const TEXTURE_2D_MULTISAMPLE_ARRAY = shader_slang::ResourceShape::SlangTexture2dMultisampleArray as u32;
+ const TEXTURE_SUBPASS_MULTISAMPLE = shader_slang::ResourceShape::SlangTextureSubpassMultisample as u32;
+}
+}
+
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum ParameterCategory
+{
+ None,
+ Mixed,
+ ConstantBuffer,
+ ShaderResource,
+ UnorderedAccess,
+ VaryingInput,
+ VaryingOutput,
+ SamplerState,
+ Uniform,
+ DescriptorTableSlot,
+ SpecializationConstant,
+ PushConstantBuffer,
+ RegisterSpace,
+ Generic,
+ RayPayload,
+ HitAttributes,
+ CallablePayload,
+ ShaderRecord,
+ ExistentialTypeParam,
+ ExistentialObjectParam,
+ SubElementRegisterSpace,
+ Subpass,
+ MetalArgumentBufferElement,
+ MetalAttribute,
+ MetalPayload,
+ Count,
+}
+
+impl ParameterCategory
+{
+ fn from_slang_parameter_category(
+ parameter_category: shader_slang::ParameterCategory,
+ ) -> Self
+ {
+ match parameter_category {
+ shader_slang::ParameterCategory::None => Self::None,
+ shader_slang::ParameterCategory::Mixed => Self::Mixed,
+ shader_slang::ParameterCategory::ConstantBuffer => Self::ConstantBuffer,
+ shader_slang::ParameterCategory::ShaderResource => Self::ShaderResource,
+ shader_slang::ParameterCategory::UnorderedAccess => Self::UnorderedAccess,
+ shader_slang::ParameterCategory::VaryingInput => Self::VaryingInput,
+ shader_slang::ParameterCategory::VaryingOutput => Self::VaryingOutput,
+ shader_slang::ParameterCategory::SamplerState => Self::SamplerState,
+ shader_slang::ParameterCategory::Uniform => Self::Uniform,
+ shader_slang::ParameterCategory::DescriptorTableSlot => {
+ Self::DescriptorTableSlot
+ }
+ shader_slang::ParameterCategory::SpecializationConstant => {
+ Self::SpecializationConstant
+ }
+ shader_slang::ParameterCategory::PushConstantBuffer => {
+ Self::PushConstantBuffer
+ }
+ shader_slang::ParameterCategory::RegisterSpace => Self::RegisterSpace,
+ shader_slang::ParameterCategory::Generic => Self::Generic,
+ shader_slang::ParameterCategory::RayPayload => Self::RayPayload,
+ shader_slang::ParameterCategory::HitAttributes => Self::HitAttributes,
+ shader_slang::ParameterCategory::CallablePayload => Self::CallablePayload,
+ shader_slang::ParameterCategory::ShaderRecord => Self::ShaderRecord,
+ shader_slang::ParameterCategory::ExistentialTypeParam => {
+ Self::ExistentialTypeParam
+ }
+ shader_slang::ParameterCategory::ExistentialObjectParam => {
+ Self::ExistentialObjectParam
+ }
+ shader_slang::ParameterCategory::SubElementRegisterSpace => {
+ Self::SubElementRegisterSpace
+ }
+ shader_slang::ParameterCategory::Subpass => Self::Subpass,
+ shader_slang::ParameterCategory::MetalArgumentBufferElement => {
+ Self::MetalArgumentBufferElement
+ }
+ shader_slang::ParameterCategory::MetalAttribute => Self::MetalAttribute,
+ shader_slang::ParameterCategory::MetalPayload => Self::MetalPayload,
+ shader_slang::ParameterCategory::Count => Self::Count,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[non_exhaustive]
+pub enum Stage
+{
+ None,
+ Vertex,
+ Hull,
+ Domain,
+ Geometry,
+ Fragment,
+ Compute,
+ RayGeneration,
+ Intersection,
+ AnyHit,
+ ClosestHit,
+ Miss,
+ Callable,
+ Mesh,
+ Amplification,
+ Dispatch,
+ Count,
+}
+
+impl Stage
+{
+ fn from_slang_stage(stage: shader_slang::Stage) -> Self
+ {
+ match stage {
+ shader_slang::Stage::None => Self::None,
+ shader_slang::Stage::Vertex => Self::Vertex,
+ shader_slang::Stage::Hull => Self::Hull,
+ shader_slang::Stage::Domain => Self::Domain,
+ shader_slang::Stage::Geometry => Self::Geometry,
+ shader_slang::Stage::Fragment => Self::Fragment,
+ shader_slang::Stage::Compute => Self::Compute,
+ shader_slang::Stage::RayGeneration => Self::RayGeneration,
+ shader_slang::Stage::Intersection => Self::Intersection,
+ shader_slang::Stage::AnyHit => Self::AnyHit,
+ shader_slang::Stage::ClosestHit => Self::ClosestHit,
+ shader_slang::Stage::Miss => Self::Miss,
+ shader_slang::Stage::Callable => Self::Callable,
+ shader_slang::Stage::Mesh => Self::Mesh,
+ shader_slang::Stage::Amplification => Self::Amplification,
+ shader_slang::Stage::Dispatch => Self::Dispatch,
+ shader_slang::Stage::Count => Self::Count,
+ }
+ }
+}