summaryrefslogtreecommitdiffstats
path: root/src/uniform.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/uniform.rs')
-rw-r--r--src/uniform.rs133
1 files changed, 51 insertions, 82 deletions
diff --git a/src/uniform.rs b/src/uniform.rs
index 5a66396..c6886b4 100644
--- a/src/uniform.rs
+++ b/src/uniform.rs
@@ -15,6 +15,7 @@ pub struct UniformRef<'a> {
pub enum UniformError {
NotIndexable,
IndexOutOfBounds,
+ NotFound,
TypeMismatch,
SizeMismatch,
}
@@ -24,6 +25,7 @@ impl std::fmt::Display for UniformError {
match self {
Self::NotIndexable => write!(f, "type is not indexable"),
Self::IndexOutOfBounds => write!(f, "index out of bounds"),
+ Self::NotFound => write!(f, "member not found"),
Self::TypeMismatch => write!(f, "scalar type mismatch"),
Self::SizeMismatch => write!(f, "value count mismatch"),
}
@@ -33,28 +35,50 @@ impl std::fmt::Display for UniformError {
impl std::error::Error for UniformError {}
impl<'a> UniformRef<'a> {
- /// Index into a compound type, returning a narrower UniformRef.
- ///
- /// - Vector: index selects a scalar component
- /// - Matrix: index selects a column (vector)
- /// - Array: index selects an element
- /// - Struct: index selects a member by position
+ /// Navigate by path component: struct member by name, or swizzle/numeric index otherwise.
+ pub fn field(self, name: &str) -> Result<UniformRef<'a>, UniformError> {
+ let ty_inner = &self.module.types[self.ty].inner;
+ if let naga::TypeInner::Struct { ref members, .. } = *ty_inner {
+ for member in members {
+ if member.name.as_deref() == Some(name) {
+ let offset = member.offset as usize;
+ let size = self.layouter[member.ty].size as usize;
+ return Ok(UniformRef {
+ module: self.module,
+ layouter: self.layouter,
+ ty: member.ty,
+ data: &mut self.data[offset..offset + size],
+ });
+ }
+ }
+ return Err(UniformError::NotFound);
+ }
+
+ let i = match name {
+ "x" | "r" | "s" => 0,
+ "y" | "g" | "t" => 1,
+ "z" | "b" | "p" => 2,
+ "w" | "a" | "q" => 3,
+ s => s.parse::<usize>().map_err(|_| UniformError::NotIndexable)?,
+ };
+ self.index(i)
+ }
+
+ /// Index into a vector, matrix, or array by position.
pub fn index(self, i: usize) -> Result<UniformRef<'a>, UniformError> {
let ty_inner = &self.module.types[self.ty].inner;
match *ty_inner {
naga::TypeInner::Vector { size, scalar } => {
- let count = size as usize;
- if i >= count {
+ if i >= size as usize {
return Err(UniformError::IndexOutOfBounds);
}
- let scalar_size = scalar.width as usize;
- let offset = i * scalar_size;
+ let w = scalar.width as usize;
let scalar_ty = find_or_expect_scalar_type(self.module, scalar);
Ok(UniformRef {
module: self.module,
layouter: self.layouter,
ty: scalar_ty,
- data: &mut self.data[offset..offset + scalar_size],
+ data: &mut self.data[i * w..][..w],
})
}
naga::TypeInner::Matrix {
@@ -62,20 +86,18 @@ impl<'a> UniformRef<'a> {
rows,
scalar,
} => {
- let col_count = columns as usize;
- if i >= col_count {
+ if i >= columns as usize {
return Err(UniformError::IndexOutOfBounds);
}
let col_ty = find_or_expect_vector_type(self.module, rows, scalar);
let col_layout = self.layouter[col_ty];
- let stride = col_layout.to_stride();
- let offset = i * stride as usize;
+ let stride = col_layout.to_stride() as usize;
let size = col_layout.size as usize;
Ok(UniformRef {
module: self.module,
layouter: self.layouter,
ty: col_ty,
- data: &mut self.data[offset..offset + size],
+ data: &mut self.data[i * stride..][..size],
})
}
naga::TypeInner::Array { base, size, stride } => {
@@ -87,26 +109,11 @@ impl<'a> UniformRef<'a> {
return Err(UniformError::IndexOutOfBounds);
}
let elem_size = self.layouter[base].size as usize;
- let offset = i * stride as usize;
Ok(UniformRef {
module: self.module,
layouter: self.layouter,
ty: base,
- data: &mut self.data[offset..offset + elem_size],
- })
- }
- naga::TypeInner::Struct { ref members, .. } => {
- if i >= members.len() {
- return Err(UniformError::IndexOutOfBounds);
- }
- let member = &members[i];
- let offset = member.offset as usize;
- let size = self.layouter[member.ty].size as usize;
- Ok(UniformRef {
- module: self.module,
- layouter: self.layouter,
- ty: member.ty,
- data: &mut self.data[offset..offset + size],
+ data: &mut self.data[i * stride as usize..][..elem_size],
})
}
_ => Err(UniformError::NotIndexable),
@@ -353,42 +360,23 @@ pub fn types_compatible(
) -> bool {
let a = &a_mod.types[a_ty].inner;
let b = &b_mod.types[b_ty].inner;
+
+ // Uniform types (Scalar, Vector, Matrix) contain no handles or pointers,
+ // so TypeInner's derived PartialEq works directly. Only Array and Struct
+ // need recursion because they contain Handle<Type> from different arenas.
match (a, b) {
- (naga::TypeInner::Scalar(a), naga::TypeInner::Scalar(b)) => a == b,
- (
- naga::TypeInner::Vector {
- size: as_,
- scalar: asc,
- },
- naga::TypeInner::Vector {
- size: bs,
- scalar: bsc,
- },
- ) => as_ == bs && asc == bsc,
- (
- naga::TypeInner::Matrix {
- columns: ac,
- rows: ar,
- scalar: asc,
- },
- naga::TypeInner::Matrix {
- columns: bc,
- rows: br,
- scalar: bsc,
- },
- ) => ac == bc && ar == br && asc == bsc,
(
naga::TypeInner::Array {
base: ab,
- size: naga::ArraySize::Constant(an),
- ..
+ size: asize,
+ stride: astride,
},
naga::TypeInner::Array {
base: bb,
- size: naga::ArraySize::Constant(bn),
- ..
+ size: bsize,
+ stride: bstride,
},
- ) => an == bn && types_compatible(a_mod, *ab, b_mod, *bb),
+ ) => asize == bsize && astride == bstride && types_compatible(a_mod, *ab, b_mod, *bb),
(
naga::TypeInner::Struct {
members: am,
@@ -405,13 +393,11 @@ pub fn types_compatible(
a.offset == b.offset && types_compatible(a_mod, a.ty, b_mod, b.ty)
})
}
- _ => false,
+ _ => a == b,
}
}
/// Manages uniform buffer data for all `var<uniform>` globals in a shader.
-///
-/// Struct members are exposed as individually addressable named uniforms.
pub struct UniformCache {
pub module: naga::Module,
pub layouter: Layouter,
@@ -430,7 +416,6 @@ struct UniformMember {
}
struct BufferState {
- /// @group and @binding
group: u32,
binding: u32,
data: Vec<u8>,
@@ -456,7 +441,7 @@ impl UniformCache {
let mut new_layouter = Layouter::default();
new_layouter.update(new_module.to_ctx()).unwrap();
- let old_module = std::mem::replace(&mut self.module, naga::Module::default());
+ let old_module = std::mem::take(&mut self.module);
let old_uniforms = std::mem::take(&mut self.uniforms);
let old_buffers = std::mem::take(&mut self.buffers);
@@ -472,7 +457,6 @@ impl UniformCache {
None => continue,
};
- let ty_inner = &new_module.types[var.ty].inner;
let layout = new_layouter[var.ty];
let buffer_idx = new_buffers.len();
@@ -484,22 +468,7 @@ impl UniformCache {
gpu_buffer: None,
});
- if let naga::TypeInner::Struct { ref members, .. } = *ty_inner {
- for member in members {
- if let Some(ref name) = member.name {
- let member_size = new_layouter[member.ty].size as usize;
- new_uniforms.insert(
- name.clone(),
- UniformMember {
- buffer_idx,
- ty: member.ty,
- offset: member.offset as usize,
- size: member_size,
- },
- );
- }
- }
- } else if let Some(ref name) = var.name {
+ if let Some(ref name) = var.name {
new_uniforms.insert(
name.clone(),
UniformMember {