summaryrefslogtreecommitdiff
path: root/engine/src/shader.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-04-14 16:22:44 +0200
committerHampusM <hampus@hampusmat.com>2026-04-14 16:22:44 +0200
commit484e2295a2fae589c7b5c9ae05aba57867ae681a (patch)
treeef1750db7281676ae7b96d1d3135eb8a291d7498 /engine/src/shader.rs
parent36fa6811c1c8171008bde10127a31be9614d6de8 (diff)
refactor(engine): make mesh vertices dynamic
Diffstat (limited to 'engine/src/shader.rs')
-rw-r--r--engine/src/shader.rs194
1 files changed, 116 insertions, 78 deletions
diff --git a/engine/src/shader.rs b/engine/src/shader.rs
index f23a366..c4bd709 100644
--- a/engine/src/shader.rs
+++ b/engine/src/shader.rs
@@ -1,4 +1,3 @@
-use std::alloc::Layout;
use std::any::type_name;
use std::borrow::Cow;
use std::collections::HashMap;
@@ -19,6 +18,7 @@ use shader_slang::{
GlobalSession as SlangGlobalSession,
Module as SlangModule,
ParameterCategory as SlangParameterCategory,
+ ScalarType as SlangScalarType,
Session as SlangSession,
TypeKind as SlangTypeKind,
};
@@ -32,12 +32,6 @@ use crate::asset::{
Submitter as AssetSubmitter,
};
use crate::builder;
-use crate::mesh::Vertex;
-use crate::reflection::{
- Reflection,
- Struct as StructReflection,
- StructField as StructFieldReflection,
-};
use crate::shader::default::{
ASSET_LABEL,
enqueue_set_shader_bindings as default_shader_enqueue_set_shader_bindings,
@@ -341,6 +335,13 @@ impl<'a> TypeLayout<'a>
TypeKind::from_slang_type_kind(self.inner.kind())
}
+ pub fn scalar_type(&self) -> Option<ScalarType>
+ {
+ Some(ScalarType::from_slang_scalar_type(
+ self.inner.scalar_type()?,
+ ))
+ }
+
pub fn get_field_by_name(&self, name: &str) -> Option<VariableLayout<'a>>
{
let index = self.inner.find_field_index_by_name(name);
@@ -528,6 +529,53 @@ impl TypeKind
}
}
+#[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,
+}
+
+impl ScalarType
+{
+ fn from_slang_scalar_type(scalar_type: SlangScalarType) -> Self
+ {
+ match scalar_type {
+ SlangScalarType::None => Self::None,
+ SlangScalarType::Void => Self::Void,
+ SlangScalarType::Bool => Self::Bool,
+ SlangScalarType::Int32 => Self::Int32,
+ SlangScalarType::Uint32 => Self::Uint32,
+ SlangScalarType::Int64 => Self::Int64,
+ SlangScalarType::Uint64 => Self::Uint64,
+ SlangScalarType::Float16 => Self::Float16,
+ SlangScalarType::Float32 => Self::Float32,
+ SlangScalarType::Float64 => Self::Float64,
+ SlangScalarType::Int8 => Self::Int8,
+ SlangScalarType::Uint8 => Self::Uint8,
+ SlangScalarType::Int16 => Self::Int16,
+ SlangScalarType::Uint16 => Self::Uint16,
+ SlangScalarType::Intptr => Self::Intptr,
+ SlangScalarType::Uintptr => Self::Uintptr,
+ }
+ }
+}
+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum ParameterCategory
{
@@ -728,37 +776,36 @@ impl Context
}
}
+#[derive(Debug)]
+#[non_exhaustive]
pub struct ProgramMetadata
{
- pub vertex_subset: Option<VertexSubset>,
+ /// If the program has a entry point in the vertex stage, this field will contain a
+ /// description of the vertex type passed to the entry point.
+ pub vertex_desc: Option<VertexDescription>,
}
#[derive(Debug)]
-pub struct VertexSubset
+#[non_exhaustive]
+pub struct VertexDescription
{
- pub layout: Layout,
- pub fields: [Option<VertexSubsetField>; const {
- Vertex::TYPE_REFLECTION.as_struct().unwrap().fields.len()
- }],
+ pub fields: Box<[VertexFieldDescription]>,
}
-impl VertexSubset
+impl VertexDescription
{
pub fn new(
vs_entrypoint: &EntryPointReflection<'_>,
- ) -> Result<Self, VertexSubsetError>
+ ) -> Result<Self, VertexDescriptionError>
{
- const VERTEX_REFLECTION: &StructReflection =
- const { Vertex::TYPE_REFLECTION.as_struct().unwrap() };
-
if vs_entrypoint.stage() != Stage::Vertex {
- return Err(VertexSubsetError::EntrypointNotInVertexStage);
+ return Err(VertexDescriptionError::EntrypointNotInVertexStage);
}
let vs_entrypoint_vertex_param = vs_entrypoint
.parameters()
.find(|param| param.semantic_name() == Some(VERTEX_PARAM_SEMANTIC_NAME))
- .ok_or(VertexSubsetError::EntrypointMissingVertexParam)?;
+ .ok_or(VertexDescriptionError::EntrypointMissingVertexParam)?;
let vs_entrypoint_vertex_param = vs_entrypoint_vertex_param
.type_layout()
@@ -767,76 +814,65 @@ impl VertexSubset
if vs_entrypoint_vertex_param.parameter_category()
!= ParameterCategory::VaryingInput
{
- return Err(VertexSubsetError::EntryPointVertexParamNotVaryingInput);
+ return Err(VertexDescriptionError::EntryPointVertexParamNotVaryingInput);
}
if vs_entrypoint_vertex_param.kind() != TypeKind::Struct {
- return Err(VertexSubsetError::EntrypointVertexTypeNotStruct);
+ return Err(VertexDescriptionError::EntrypointVertexTypeNotStruct);
}
- if let Some(unknown_vertex_field_name) = vs_entrypoint_vertex_param
+ let fields = vs_entrypoint_vertex_param
.fields()
- .find_map(|vertex_param_field| {
- let vertex_param_field_name =
- vertex_param_field.name().expect("Not possible");
-
- if VERTEX_REFLECTION
- .fields
- .iter()
- .all(|vertex_field| vertex_field.name != vertex_param_field_name)
- {
- return Some(vertex_param_field_name);
- }
+ .map(|field| {
+ let varying_input_offset =
+ field.varying_input_offset().expect("Not possible");
+
+ let field_ty = field.type_layout().expect("Maybe not possible");
+
+ let scalar_type = match field_ty.kind() {
+ TypeKind::Scalar => field_ty.scalar_type().expect("Not possible"),
+ TypeKind::Vector => {
+ let Some(scalar_type) = field_ty.scalar_type() else {
+ return Err(
+ VertexDescriptionError::UnsupportedVertexFieldType {
+ field_name: field.name().unwrap_or("").to_string(),
+ },
+ );
+ };
+
+ scalar_type
+ }
+ _ => {
+ return Err(VertexDescriptionError::UnsupportedVertexFieldType {
+ field_name: field.name().unwrap_or("").to_string(),
+ });
+ }
+ };
- None
+ Ok(VertexFieldDescription {
+ name: field.name().unwrap_or("").to_string().into_boxed_str(),
+ varying_input_offset,
+ type_kind: field_ty.kind(),
+ scalar_type,
+ })
})
- {
- return Err(VertexSubsetError::EntrypointVertexTypeHasUnknownField {
- field_name: unknown_vertex_field_name.to_string(),
- });
- }
-
- let mut layout = Layout::new::<()>();
-
- let mut fields = [const { None }; const { VERTEX_REFLECTION.fields.len() }];
-
- for vertex_field in const { VERTEX_REFLECTION.fields } {
- let Some(vertex_field_var_layout) =
- vs_entrypoint_vertex_param.get_field_by_name(vertex_field.name)
- else {
- continue;
- };
-
- let (new_layout, vertex_field_offset) =
- layout.extend(vertex_field.layout).expect("Not possible");
-
- layout = new_layout;
-
- fields[vertex_field.index] = Some(VertexSubsetField {
- offset: vertex_field_offset,
- reflection: vertex_field,
- varying_input_offset: vertex_field_var_layout
- .varying_input_offset()
- .expect("Not possible"),
- });
- }
-
- layout = layout.pad_to_align();
+ .collect::<Result<Vec<_>, _>>()?;
- Ok(Self { layout, fields })
+ Ok(Self { fields: fields.into_boxed_slice() })
}
}
#[derive(Debug)]
-pub struct VertexSubsetField
+pub struct VertexFieldDescription
{
- pub offset: usize,
- pub reflection: &'static StructFieldReflection,
+ pub name: Box<str>,
pub varying_input_offset: usize,
+ pub type_kind: TypeKind,
+ pub scalar_type: ScalarType,
}
#[derive(Debug, thiserror::Error)]
-pub enum VertexSubsetError
+pub enum VertexDescriptionError
{
#[error("Entrypoint is not in vertex stage")]
EntrypointNotInVertexStage,
@@ -853,8 +889,8 @@ pub enum VertexSubsetError
#[error("Entrypoint vertex type is not a struct")]
EntrypointVertexTypeNotStruct,
- #[error("Entrypoint vertex type has unknown field {field_name}")]
- EntrypointVertexTypeHasUnknownField
+ #[error("Type of field '{field_name}' of vertex type is not supported")]
+ UnsupportedVertexFieldType
{
field_name: String
},
@@ -1069,11 +1105,11 @@ fn load_modules(mut context: Single<Context>, assets: Single<Assets>)
}
};
- let vertex_subset = if module_source
+ let vertex_desc = if module_source
.link_entrypoints
.contains(EntrypointFlags::VERTEX)
{
- VertexSubset::new(
+ VertexDescription::new(
&shader_program
.reflection(0)
.expect("Not possible")
@@ -1082,7 +1118,9 @@ fn load_modules(mut context: Single<Context>, assets: Single<Assets>)
)
.inspect_err(|err| {
tracing::error!(
- "Failed to create vertex subset for shader {asset_label:?}: {err}"
+ "Failed to create a vertex description for shader {}: {}",
+ asset_label,
+ err
);
})
.ok()
@@ -1092,7 +1130,7 @@ fn load_modules(mut context: Single<Context>, assets: Single<Assets>)
context.programs.insert(
*asset_id,
- (linked_shader_program, ProgramMetadata { vertex_subset }),
+ (linked_shader_program, ProgramMetadata { vertex_desc }),
);
}
}