summaryrefslogtreecommitdiff
path: root/engine/src/rendering/shader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/rendering/shader.rs')
-rw-r--r--engine/src/rendering/shader.rs268
1 files changed, 190 insertions, 78 deletions
diff --git a/engine/src/rendering/shader.rs b/engine/src/rendering/shader.rs
index 3bcf73e..3142400 100644
--- a/engine/src/rendering/shader.rs
+++ b/engine/src/rendering/shader.rs
@@ -38,10 +38,6 @@ use crate::ecs::{declare_entity, pair, Component, Sole};
pub mod cursor;
pub mod default;
-/// The vertex parameter of a vertex entrypoint function in a shader should have this
-/// semantic name.
-pub const VERTEX_PARAM_SEMANTIC_NAME: &str = "VERTEX";
-
#[derive(Debug, Clone, Component)]
pub struct Shader
{
@@ -88,6 +84,11 @@ impl Module
Some(EntryPoint { inner: entry_point })
}
+
+ pub fn file_path(&self) -> &str
+ {
+ self.inner.file_path()
+ }
}
pub struct EntryPoint
@@ -405,11 +406,13 @@ impl<'a> TypeLayout<'a>
self.inner.ty().map(|ty| TypeReflection { inner: ty })
}
- pub fn fields(&self) -> impl ExactSizeIterator<Item = VariableLayout<'a>>
+ pub fn fields(&self) -> FieldIter<'a>
{
- self.inner
- .fields()
- .map(|field| VariableLayout { inner: field })
+ FieldIter {
+ type_layout: self.clone(),
+ cnt: self.field_cnt(),
+ index: 0,
+ }
}
pub fn field_cnt(&self) -> u32
@@ -487,6 +490,66 @@ impl<'a> TypeLayout<'a>
}
}
+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,
@@ -816,6 +879,7 @@ impl Context
self.programs.get(asset_id)
}
+ #[tracing::instrument(skip_all, fields(module_file = module.file_path()))]
pub fn compose_into_program(
&self,
module: Module,
@@ -889,11 +953,12 @@ pub struct ProgramMetadata
#[non_exhaustive]
pub struct VertexDescription
{
- pub fields: Arc<[VertexFieldDescription]>,
+ pub inputs: Arc<[VertexInputDescription]>,
}
impl VertexDescription
{
+ #[tracing::instrument(skip_all, fields(vs_entry_point_name = vs_entrypoint.name()))]
pub fn new(
vs_entrypoint: &EntryPointReflection<'_>,
) -> Result<Self, VertexDescriptionError>
@@ -902,71 +967,65 @@ impl VertexDescription
return Err(VertexDescriptionError::EntrypointNotInVertexStage);
}
- let vs_entrypoint_vertex_param = vs_entrypoint
- .parameters()
- .find(|param| param.semantic_name() == Some(VERTEX_PARAM_SEMANTIC_NAME))
- .ok_or(VertexDescriptionError::EntrypointMissingVertexParam)?;
-
- let vs_entrypoint_vertex_param = vs_entrypoint_vertex_param
- .type_layout()
- .expect("Not possible");
-
- if vs_entrypoint_vertex_param.parameter_category()
- != ParameterCategory::VaryingInput
- {
- return Err(VertexDescriptionError::EntryPointVertexParamNotVaryingInput);
- }
-
- if vs_entrypoint_vertex_param.kind() != TypeKind::Struct {
- return Err(VertexDescriptionError::EntrypointVertexTypeNotStruct);
- }
-
- let fields = vs_entrypoint_vertex_param
- .fields()
- .map(|field| {
- let varying_input_offset =
- field.varying_input_offset().expect("Not possible");
+ let inputs = VarInputDfsIter::new(vs_entrypoint).inspect(|var_input| {
+ if var_input.type_layout.kind() != TypeKind::Struct {
+ return;
+ }
- let field_ty = field.type_layout().expect("Maybe not possible");
+ let Some(semantic_name) = var_input.var_layout.semantic_name() else {
+ return;
+ };
- 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 {
+ tracing::warn!(
+ "Semantic name '{}' of '{}' will be inherited by it's fields",
+ semantic_name,
+ var_input.var_layout.name().unwrap_or("<unnamed>")
+ );
+ });
+
+ Ok(Self {
+ inputs: inputs
+ .filter(|var_input| var_input.type_layout.kind() != TypeKind::Struct)
+ .map(|var_input| {
+ let name = var_input
+ .var_layout
+ .name()
+ .unwrap_or("<unnamed>")
+ .to_string();
+
+ let scalar_type = match (
+ var_input.type_layout.kind(),
+ var_input.type_layout.scalar_type(),
+ ) {
+ (TypeKind::Scalar, Some(scalar_type)) => scalar_type,
+ (TypeKind::Vector, Some(scalar_type)) => scalar_type,
+ _ => {
return Err(
- VertexDescriptionError::UnsupportedVertexFieldType {
- field_name: field.name().unwrap_or("").to_string(),
+ VertexDescriptionError::UnsupportedVertexInputType {
+ name,
},
);
- };
-
- scalar_type
- }
- _ => {
- return Err(VertexDescriptionError::UnsupportedVertexFieldType {
- field_name: field.name().unwrap_or("").to_string(),
- });
- }
- };
-
- Ok(VertexFieldDescription {
- name: field.name().unwrap_or("").to_string().into_boxed_str(),
- varying_input_offset,
- type_kind: field_ty.kind(),
- scalar_type,
+ }
+ };
+
+ Ok(VertexInputDescription {
+ name: name.into_boxed_str(),
+ index: var_input.index,
+ type_kind: var_input.type_layout.kind(),
+ scalar_type,
+ })
})
- })
- .collect::<Result<Vec<_>, _>>()?;
-
- Ok(Self { fields: fields.into() })
+ .collect::<Result<Vec<_>, _>>()?
+ .into(),
+ })
}
}
#[derive(Debug)]
-pub struct VertexFieldDescription
+pub struct VertexInputDescription
{
pub name: Box<str>,
- pub varying_input_offset: usize,
+ pub index: usize,
pub type_kind: TypeKind,
pub scalar_type: ScalarType,
}
@@ -977,22 +1036,10 @@ pub enum VertexDescriptionError
#[error("Entrypoint is not in vertex stage")]
EntrypointNotInVertexStage,
- #[error(
- "Entrypoint does not have a vertex parameter (parameter with semantic name {})",
- VERTEX_PARAM_SEMANTIC_NAME
- )]
- EntrypointMissingVertexParam,
-
- #[error("Entrypoint vertex parameter is not a varying input")]
- EntryPointVertexParamNotVaryingInput,
-
- #[error("Entrypoint vertex type is not a struct")]
- EntrypointVertexTypeNotStruct,
-
- #[error("Type of field '{field_name}' of vertex type is not supported")]
- UnsupportedVertexFieldType
+ #[error("Type of vertex input '{name}' is not supported")]
+ UnsupportedVertexInputType
{
- field_name: String
+ name: String
},
}
@@ -1016,6 +1063,68 @@ pub enum ComposeProgramError
#[error(transparent)]
pub struct Error(#[from] shader_slang::Error);
+struct VarInputDfsIter<'a>
+{
+ stack: Vec<(VariableLayout<'a>, TypeLayout<'a>, usize)>,
+}
+
+impl<'a> VarInputDfsIter<'a>
+{
+ fn new(entry_point: &EntryPointReflection<'a>) -> Self
+ {
+ Self {
+ stack: entry_point
+ .parameters()
+ .map(|param| {
+ let Some(param_type_layout) = param.type_layout() else {
+ // I do not know in which cases type_layout can return None
+ unimplemented!();
+ };
+
+ (param, param_type_layout, 0)
+ })
+ .collect(),
+ }
+ }
+}
+
+impl<'a> Iterator for VarInputDfsIter<'a>
+{
+ type Item = VarInput<'a>;
+
+ fn next(&mut self) -> Option<Self::Item>
+ {
+ let (var_layout, type_layout, index) = loop {
+ let (var_layout, type_layout, acc_offset) = self.stack.pop()?;
+
+ if let Some(offset) = var_layout.varying_input_offset() {
+ break (var_layout, type_layout, acc_offset + offset);
+ }
+ };
+
+ if type_layout.kind() == TypeKind::Struct {
+ self.stack.extend(type_layout.fields().map(|field| {
+ let Some(field_type_layout) = field.type_layout() else {
+ // I do not know in which cases type_layout can return
+ // None
+ unimplemented!();
+ };
+
+ (field, field_type_layout, index)
+ }));
+ }
+
+ Some(VarInput { var_layout, type_layout, index })
+ }
+}
+
+struct VarInput<'a>
+{
+ var_layout: VariableLayout<'a>,
+ type_layout: TypeLayout<'a>,
+ index: usize,
+}
+
fn import_slang_asset(
asset_submitter: &mut AssetSubmitter<'_>,
file_path: &Path,
@@ -1171,7 +1280,10 @@ fn load_modules(
{
Ok(shader_program) => shader_program,
Err(err) => {
- tracing::error!("Failed to compose shader into program: {err}");
+ tracing::error!(
+ "Failed to compose shader into program: {:#}",
+ crate::Error::new(err)
+ );
continue;
}
};