From 484e2295a2fae589c7b5c9ae05aba57867ae681a Mon Sep 17 00:00:00 2001 From: HampusM Date: Tue, 14 Apr 2026 16:22:44 +0200 Subject: refactor(engine): make mesh vertices dynamic --- engine/src/shader.rs | 194 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 116 insertions(+), 78 deletions(-) (limited to 'engine/src/shader.rs') 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 + { + Some(ScalarType::from_slang_scalar_type( + self.inner.scalar_type()?, + )) + } + pub fn get_field_by_name(&self, name: &str) -> Option> { 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, + /// 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, } #[derive(Debug)] -pub struct VertexSubset +#[non_exhaustive] +pub struct VertexDescription { - pub layout: Layout, - pub fields: [Option; const { - Vertex::TYPE_REFLECTION.as_struct().unwrap().fields.len() - }], + pub fields: Box<[VertexFieldDescription]>, } -impl VertexSubset +impl VertexDescription { pub fn new( vs_entrypoint: &EntryPointReflection<'_>, - ) -> Result + ) -> Result { - 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::, _>>()?; - 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, 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, assets: Single) } }; - 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, assets: Single) ) .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, assets: Single) context.programs.insert( *asset_id, - (linked_shader_program, ProgramMetadata { vertex_subset }), + (linked_shader_program, ProgramMetadata { vertex_desc }), ); } } -- cgit v1.2.3-18-g5258