diff --git a/src/valid/interface.rs b/src/valid/interface.rs index a9fbf82b87..39bf029fff 100644 --- a/src/valid/interface.rs +++ b/src/valid/interface.rs @@ -41,9 +41,9 @@ pub enum VaryingError { InvalidInterpolation, #[error("Interpolation must be specified on vertex shader outputs and fragment shader inputs")] MissingInterpolation, - #[error("BuiltIn {0:?} is not available at this stage")] + #[error("Built-in {0:?} is not available at this stage")] InvalidBuiltInStage(crate::BuiltIn), - #[error("BuiltIn type for {0:?} is invalid")] + #[error("Built-in type for {0:?} is invalid")] InvalidBuiltInType(crate::BuiltIn), #[error("Entry point arguments and return values must all have bindings")] MissingBinding, @@ -51,6 +51,8 @@ pub enum VaryingError { MemberMissingBinding(u32), #[error("Multiple bindings at location {location} are present")] BindingCollision { location: u32 }, + #[error("Built-in {0:?} is present more than once")] + DuplicateBuiltIn(crate::BuiltIn), } #[derive(Clone, Debug, thiserror::Error)] @@ -96,6 +98,7 @@ struct VaryingContext<'a> { output: bool, types: &'a Arena, location_mask: &'a mut BitSet, + built_in_mask: u32, } impl VaryingContext<'_> { @@ -107,6 +110,12 @@ impl VaryingContext<'_> { let ty_inner = &self.types[self.ty].inner; match *binding { crate::Binding::BuiltIn(built_in) => { + let bit = 1 << built_in as u32; + if self.built_in_mask & bit != 0 { + return Err(VaryingError::DuplicateBuiltIn(built_in)); + } + self.built_in_mask |= bit; + let width = 4; let (visible, type_good) = match built_in { Bi::BaseInstance | Bi::BaseVertex | Bi::InstanceIndex | Bi::VertexIndex => ( @@ -257,7 +266,7 @@ impl VaryingContext<'_> { Ok(()) } - fn validate(mut self, binding: Option<&crate::Binding>) -> Result<(), VaryingError> { + fn validate(&mut self, binding: Option<&crate::Binding>) -> Result<(), VaryingError> { match binding { Some(binding) => self.validate_impl(binding), None => { @@ -409,26 +418,30 @@ impl super::Validator { } self.location_mask.clear(); + let mut argument_built_ins = 0; for (index, fa) in ep.function.arguments.iter().enumerate() { - let ctx = VaryingContext { + let mut ctx = VaryingContext { ty: fa.ty, stage: ep.stage, output: false, types: &module.types, location_mask: &mut self.location_mask, + built_in_mask: argument_built_ins, }; ctx.validate(fa.binding.as_ref()) .map_err(|e| EntryPointError::Argument(index as u32, e))?; + argument_built_ins = ctx.built_in_mask; } self.location_mask.clear(); if let Some(ref fr) = ep.function.result { - let ctx = VaryingContext { + let mut ctx = VaryingContext { ty: fr.ty, stage: ep.stage, output: true, types: &module.types, location_mask: &mut self.location_mask, + built_in_mask: 0, }; ctx.validate(fr.binding.as_ref()) .map_err(EntryPointError::Result)?;