diff options
Diffstat (limited to 'src/uniform.rs')
| -rw-r--r-- | src/uniform.rs | 133 |
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 { |
