Validate built-ins to not repeat

This commit is contained in:
Dzmitry Malyshau
2021-05-21 00:35:45 -04:00
committed by Dzmitry Malyshau
parent 50de6ae9ac
commit 652b65cfa9

View File

@@ -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<crate::Type>,
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)?;