diff --git a/src/back/glsl/features.rs b/src/back/glsl/features.rs index 345d514366..408046fc8e 100644 --- a/src/back/glsl/features.rs +++ b/src/back/glsl/features.rs @@ -404,7 +404,7 @@ impl<'a, W> Writer<'a, W> { _ => { if let Some(binding) = binding { match *binding { - Binding::BuiltIn { built_in, .. } => match built_in { + Binding::BuiltIn(built_in) => match built_in { crate::BuiltIn::ClipDistance => { self.features.request(Features::CLIP_DISTANCE) } diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 5ec9f4f615..b5750fb941 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -336,7 +336,7 @@ impl fmt::Display for VaryingName<'_> { }; write!(f, "_{}_location{}", prefix, location,) } - crate::Binding::BuiltIn { built_in, .. } => { + crate::Binding::BuiltIn(built_in) => { write!(f, "{}", glsl_built_in(built_in, self.output)) } } @@ -1170,11 +1170,8 @@ impl<'a, W: Write> Writer<'a, W> { interpolation, sampling, } => (location, interpolation, sampling), - crate::Binding::BuiltIn { - built_in, - invariant, - } => { - if invariant { + crate::Binding::BuiltIn(built_in) => { + if let crate::BuiltIn::Position { invariant: true } = built_in { writeln!(self.out, "invariant {};", glsl_built_in(built_in, output))?; } return Ok(()); @@ -1830,10 +1827,8 @@ impl<'a, W: Write> Writer<'a, W> { for (index, member) in members.iter().enumerate() { // TODO: handle builtin in better way - if let Some(crate::Binding::BuiltIn { - built_in: builtin, - .. - }) = member.binding + if let Some(crate::Binding::BuiltIn(builtin)) = + member.binding { match builtin { crate::BuiltIn::ClipDistance @@ -3170,7 +3165,7 @@ fn glsl_built_in(built_in: crate::BuiltIn, output: bool) -> &'static str { use crate::BuiltIn as Bi; match built_in { - Bi::Position => { + Bi::Position { .. } => { if output { "gl_Position" } else { diff --git a/src/back/hlsl/conv.rs b/src/back/hlsl/conv.rs index 547b7632f0..d799c0b981 100644 --- a/src/back/hlsl/conv.rs +++ b/src/back/hlsl/conv.rs @@ -151,7 +151,7 @@ impl crate::StorageFormat { impl crate::BuiltIn { pub(super) fn to_hlsl_str(self) -> Result<&'static str, Error> { Ok(match self { - Self::Position => "SV_Position", + Self::Position { .. } => "SV_Position", // vertex Self::ClipDistance => "SV_ClipDistance", Self::CullDistance => "SV_CullDistance", diff --git a/src/back/hlsl/writer.rs b/src/back/hlsl/writer.rs index b3e61e7f53..3338c652a2 100644 --- a/src/back/hlsl/writer.rs +++ b/src/back/hlsl/writer.rs @@ -60,7 +60,7 @@ impl InterfaceKey { fn new(binding: Option<&crate::Binding>) -> Self { match binding { Some(&crate::Binding::Location { location, .. }) => Self::Location(location), - Some(&crate::Binding::BuiltIn { built_in, .. }) => Self::BuiltIn(built_in), + Some(&crate::Binding::BuiltIn(built_in)) => Self::BuiltIn(built_in), None => Self::Other, } } @@ -309,9 +309,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { fn write_modifier(&mut self, binding: &crate::Binding) -> BackendResult { match *binding { - crate::Binding::BuiltIn { - invariant: true, .. - } => { + crate::Binding::BuiltIn(crate::BuiltIn::Position { invariant: true }) => { write!(self.out, "precise ")?; } crate::Binding::Location { @@ -345,9 +343,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { stage: Option<(ShaderStage, Io)>, ) -> BackendResult { match *binding { - crate::Binding::BuiltIn { - built_in: builtin, .. - } => { + crate::Binding::BuiltIn(builtin) => { let builtin_str = builtin.to_hlsl_str()?; write!(self.out, " : {}", builtin_str)?; } @@ -963,9 +959,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { if let Some(crate::FunctionResult { binding: Some( - ref binding @ crate::Binding::BuiltIn { - invariant: true, .. - }, + ref binding @ crate::Binding::BuiltIn(crate::BuiltIn::Position { + invariant: true, + }), ), .. }) = func.result diff --git a/src/back/mod.rs b/src/back/mod.rs index 0dc010f1b7..9802e5acfe 100644 --- a/src/back/mod.rs +++ b/src/back/mod.rs @@ -96,14 +96,14 @@ impl<'a> FunctionCtx<'_> { match self.expressions[expression] { crate::Expression::FunctionArgument(arg_index) => { return match ep_function.arguments[arg_index as usize].binding { - Some(crate::Binding::BuiltIn { built_in: bi, .. }) => Some(bi), + Some(crate::Binding::BuiltIn(bi)) => Some(bi), _ => built_in, }; } crate::Expression::AccessIndex { base, index } => { match *self.info[base].ty.inner_with(&module.types) { crate::TypeInner::Struct { ref members, .. } => { - if let Some(crate::Binding::BuiltIn { built_in: bi, .. }) = + if let Some(crate::Binding::BuiltIn(bi)) = members[index as usize].binding { built_in = Some(bi); diff --git a/src/back/msl/mod.rs b/src/back/msl/mod.rs index e4b323e686..28cff04762 100644 --- a/src/back/msl/mod.rs +++ b/src/back/msl/mod.rs @@ -100,10 +100,7 @@ impl ops::Index for PerStageMap { } enum ResolvedBinding { - BuiltIn { - built_in: crate::BuiltIn, - invariant: bool, - }, + BuiltIn(crate::BuiltIn), Attribute(u32), Color(u32), User { @@ -241,20 +238,20 @@ impl Options { mode: LocationMode, ) -> Result { match *binding { - crate::Binding::BuiltIn { - built_in, - invariant, - } => { - if invariant && self.lang_version < (2, 1) { - return Err(Error::UnsupportedAttribute("invariant".to_string())); + crate::Binding::BuiltIn(mut built_in) => { + if let crate::BuiltIn::Position { ref mut invariant } = built_in { + if *invariant && self.lang_version < (2, 1) { + return Err(Error::UnsupportedAttribute("invariant".to_string())); + } + + // The 'invariant' attribute may only appear on vertex + // shader outputs, not fragment shader inputs. + if !matches!(mode, LocationMode::VertexOutput) { + *invariant = false; + } } - // The 'invariant' attribute can only appear on vertex - // shader outputs, but not fragment shader inputs. - Ok(ResolvedBinding::BuiltIn { - built_in, - invariant: invariant && matches!(mode, LocationMode::VertexOutput), - }) + Ok(ResolvedBinding::BuiltIn(built_in)) } crate::Binding::Location { location, @@ -369,13 +366,11 @@ impl ResolvedBinding { fn try_fmt(&self, out: &mut W) -> Result<(), Error> { write!(out, " [[")?; match *self { - Self::BuiltIn { - built_in, - invariant, - } => { + Self::BuiltIn(built_in) => { use crate::BuiltIn as Bi; let name = match built_in { - Bi::Position => "position", + Bi::Position { invariant: false } => "position", + Bi::Position { invariant: true } => "position, invariant", // vertex Bi::BaseInstance => "base_instance", Bi::BaseVertex => "base_vertex", @@ -401,10 +396,6 @@ impl ResolvedBinding { } }; write!(out, "{}", name)?; - - if invariant { - write!(out, ", invariant")?; - } } Self::Attribute(index) => write!(out, "attribute({})", index)?, Self::Color(index) => write!(out, "color({})", index)?, diff --git a/src/back/msl/writer.rs b/src/back/msl/writer.rs index 9d591b6ebf..3d1a109725 100644 --- a/src/back/msl/writer.rs +++ b/src/back/msl/writer.rs @@ -2136,19 +2136,13 @@ impl Writer { for (index, member) in members.iter().enumerate() { match member.binding { - Some(crate::Binding::BuiltIn { - built_in: crate::BuiltIn::PointSize, - .. - }) => { + Some(crate::Binding::BuiltIn(crate::BuiltIn::PointSize)) => { has_point_size = true; if !context.pipeline_options.allow_point_size { continue; } } - Some(crate::Binding::BuiltIn { - built_in: crate::BuiltIn::CullDistance, - .. - }) => { + Some(crate::Binding::BuiltIn(crate::BuiltIn::CullDistance)) => { log::warn!("Ignoring CullDistance built-in"); continue; } @@ -3437,10 +3431,7 @@ impl Writer { match *binding { // Point size is only supported in VS of pipelines with // point primitive topology. - crate::Binding::BuiltIn { - built_in: crate::BuiltIn::PointSize, - .. - } => { + crate::Binding::BuiltIn(crate::BuiltIn::PointSize) => { has_point_size = true; if !pipeline_options.allow_point_size { continue; @@ -3450,10 +3441,7 @@ impl Writer { // But we can't return UnsupportedBuiltIn error to user. // Because otherwise we can't generate msl shader from any glslang SPIR-V shaders. // glslang generates gl_PerVertex struct with gl_CullDistance builtin inside by default. - crate::Binding::BuiltIn { - built_in: crate::BuiltIn::CullDistance, - .. - } => { + crate::Binding::BuiltIn(crate::BuiltIn::CullDistance) => { log::warn!("Ignoring CullDistance BuiltIn"); continue; } diff --git a/src/back/spv/block.rs b/src/back/spv/block.rs index 0ab9c4a71f..15bd07bea0 100644 --- a/src/back/spv/block.rs +++ b/src/back/spv/block.rs @@ -144,7 +144,7 @@ impl Writer { body.push(Instruction::store(res_member.id, member_value_id, None)); match res_member.built_in { - Some(crate::BuiltIn::Position) + Some(crate::BuiltIn::Position { .. }) if self.flags.contains(WriterFlags::ADJUST_COORDINATE_SPACE) => { self.write_epilogue_position_y_flip(res_member.id, body)?; diff --git a/src/back/spv/helpers.rs b/src/back/spv/helpers.rs index 5580fec2c7..acde9504d9 100644 --- a/src/back/spv/helpers.rs +++ b/src/back/spv/helpers.rs @@ -38,7 +38,7 @@ pub(super) fn contains_builtin( arena: &UniqueArena, built_in: crate::BuiltIn, ) -> bool { - if let Some(&crate::Binding::BuiltIn { built_in: bi, .. }) = binding { + if let Some(&crate::Binding::BuiltIn(bi)) = binding { bi == built_in } else if let crate::TypeInner::Struct { ref members, .. } = arena[ty].inner { members diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index 88d70345f5..19d788b8a6 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -398,11 +398,8 @@ impl Writer { let mut has_point_size = false; let class = spirv::StorageClass::Output; if let Some(ref binding) = result.binding { - has_point_size |= *binding - == crate::Binding::BuiltIn { - built_in: crate::BuiltIn::PointSize, - invariant: false, - }; + has_point_size |= + *binding == crate::Binding::BuiltIn(crate::BuiltIn::PointSize); let type_id = self.get_type_id(LookupType::Handle(result.ty)); let varying_id = self.write_varying(ir_module, class, None, result.ty, binding)?; @@ -419,11 +416,8 @@ impl Writer { let type_id = self.get_type_id(LookupType::Handle(member.ty)); let name = member.name.as_ref().map(AsRef::as_ref); let binding = member.binding.as_ref().unwrap(); - has_point_size |= *binding - == crate::Binding::BuiltIn { - built_in: crate::BuiltIn::PointSize, - invariant: false, - }; + has_point_size |= + *binding == crate::Binding::BuiltIn(crate::BuiltIn::PointSize); let varying_id = self.write_varying(ir_module, class, name, member.ty, binding)?; iface.varying_ids.push(varying_id); @@ -1180,13 +1174,14 @@ impl Writer { } } } - crate::Binding::BuiltIn { - built_in, - invariant, - } => { + crate::Binding::BuiltIn(built_in) => { use crate::BuiltIn as Bi; let built_in = match built_in { - Bi::Position => { + Bi::Position { invariant } => { + if invariant { + self.decorate(id, Decoration::Invariant, &[]); + } + if class == spirv::StorageClass::Output { BuiltIn::Position } else { @@ -1234,10 +1229,6 @@ impl Writer { }; self.decorate(id, Decoration::BuiltIn, &[built_in as u32]); - - if invariant { - self.decorate(id, Decoration::Invariant, &[]); - } } } @@ -1365,13 +1356,7 @@ impl Writer { crate::TypeInner::Struct { ref members, .. } => members.iter().any(|member| { has_view_index_check(ir_module, member.binding.as_ref(), member.ty) }), - _ => { - binding - == Some(&crate::Binding::BuiltIn { - built_in: crate::BuiltIn::ViewIndex, - invariant: false, - }) - } + _ => binding == Some(&crate::Binding::BuiltIn(crate::BuiltIn::ViewIndex)), } } diff --git a/src/back/wgsl/writer.rs b/src/back/wgsl/writer.rs index 1b03665722..ef93192d08 100644 --- a/src/back/wgsl/writer.rs +++ b/src/back/wgsl/writer.rs @@ -402,7 +402,7 @@ impl Writer { writeln!(self.out)?; for (index, member) in members.iter().enumerate() { // Skip struct member with unsupported built in - if let Some(crate::Binding::BuiltIn { built_in, .. }) = member.binding { + if let Some(crate::Binding::BuiltIn(built_in)) = member.binding { if builtin_str(built_in).is_none() { log::warn!("Skip member with unsupported builtin {:?}", built_in); continue; @@ -1747,7 +1747,7 @@ impl Writer { // Write the comma separated constants for (index, constant) in components.iter().enumerate() { - if let Some(&crate::Binding::BuiltIn { built_in, .. }) = + if let Some(&crate::Binding::BuiltIn(built_in)) = members.and_then(|members| members.get(index)?.binding.as_ref()) { if builtin_str(built_in).is_none() { @@ -1849,7 +1849,7 @@ fn builtin_str(built_in: crate::BuiltIn) -> Option<&'static str> { match built_in { Bi::VertexIndex => Some("vertex_index"), Bi::InstanceIndex => Some("instance_index"), - Bi::Position => Some("position"), + Bi::Position { .. } => Some("position"), Bi::FrontFacing => Some("front_facing"), Bi::FragDepth => Some("frag_depth"), Bi::LocalInvocationId => Some("local_invocation_id"), @@ -1977,11 +1977,8 @@ fn map_binding_to_attribute( scalar_kind: Option, ) -> Vec { match *binding { - crate::Binding::BuiltIn { - built_in, - invariant, - } => { - if invariant { + crate::Binding::BuiltIn(built_in) => { + if let crate::BuiltIn::Position { invariant: true } = built_in { vec![Attribute::BuiltIn(built_in), Attribute::Invariant] } else { vec![Attribute::BuiltIn(built_in)] @@ -2017,8 +2014,7 @@ fn access_to_unsupported_builtin( { // Let's check that we try to access a struct member with unsupported built-in and skip it. if let TypeInner::Struct { ref members, .. } = module.types[pointer_base_handle].inner { - if let Some(crate::Binding::BuiltIn { built_in, .. }) = members[index as usize].binding - { + if let Some(crate::Binding::BuiltIn(built_in)) = members[index as usize].binding { if builtin_str(built_in).is_none() { log::warn!("Skip component with unsupported builtin {:?}", built_in); return true; diff --git a/src/front/glsl/variables.rs b/src/front/glsl/variables.rs index 02995e2bb3..0e446a9a76 100644 --- a/src/front/glsl/variables.rs +++ b/src/front/glsl/variables.rs @@ -67,10 +67,7 @@ impl Parser { let idx = self.entry_args.len(); self.entry_args.push(EntryArg { name: None, - binding: Binding::BuiltIn { - built_in: data.builtin, - invariant: false, - }, + binding: Binding::BuiltIn(data.builtin), handle, storage: data.storage, }); @@ -120,7 +117,7 @@ impl Parser { kind: ScalarKind::Float, width: 4, }, - builtin: BuiltIn::Position, + builtin: BuiltIn::Position { invariant: false }, mutable: true, storage: StorageQualifier::Output, }, @@ -130,7 +127,7 @@ impl Parser { kind: ScalarKind::Float, width: 4, }, - builtin: BuiltIn::Position, + builtin: BuiltIn::Position { invariant: false }, mutable: false, storage: StorageQualifier::Input, }, @@ -240,11 +237,10 @@ impl Parser { ) { if let Some(var) = self.lookup_variable(ctx, body, name, meta) { if let Some(index) = var.entry_arg { - if let Binding::BuiltIn { built_in, .. } = self.entry_args[index].binding { - self.entry_args[index].binding = Binding::BuiltIn { - built_in, - invariant: built_in == BuiltIn::Position, - }; + if let Binding::BuiltIn(BuiltIn::Position { ref mut invariant }) = + self.entry_args[index].binding + { + *invariant = true; } } } diff --git a/src/front/spv/convert.rs b/src/front/spv/convert.rs index 22283fff06..9ffc3880d9 100644 --- a/src/front/spv/convert.rs +++ b/src/front/spv/convert.rs @@ -121,10 +121,10 @@ pub(super) fn map_width(word: spirv::Word) -> Result { .map_err(|_| Error::InvalidTypeWidth(word)) } -pub(super) fn map_builtin(word: spirv::Word) -> Result { +pub(super) fn map_builtin(word: spirv::Word, invariant: bool) -> Result { use spirv::BuiltIn as Bi; Ok(match spirv::BuiltIn::from_u32(word) { - Some(Bi::Position) | Some(Bi::FragCoord) => crate::BuiltIn::Position, + Some(Bi::Position) | Some(Bi::FragCoord) => crate::BuiltIn::Position { invariant }, Some(Bi::ViewIndex) => crate::BuiltIn::ViewIndex, // vertex Some(Bi::BaseInstance) => crate::BuiltIn::BaseInstance, diff --git a/src/front/spv/function.rs b/src/front/spv/function.rs index b8e6c6615c..c57695601f 100644 --- a/src/front/spv/function.rs +++ b/src/front/spv/function.rs @@ -377,7 +377,7 @@ impl> super::Parser { } => { for (index, sm) in sub_members.iter().enumerate() { match sm.binding { - Some(crate::Binding::BuiltIn { built_in, .. }) => { + Some(crate::Binding::BuiltIn(built_in)) => { // Cull unused builtins to preserve performances if !self.builtin_usage.contains(&built_in) { continue; @@ -414,10 +414,9 @@ impl> super::Parser { for (member_index, member) in members.iter().enumerate() { match member.binding { - Some(crate::Binding::BuiltIn { - built_in: crate::BuiltIn::Position, - .. - }) if self.options.adjust_coordinate_space => { + Some(crate::Binding::BuiltIn(crate::BuiltIn::Position { .. })) + if self.options.adjust_coordinate_space => + { let mut emitter = Emitter::default(); emitter.start(&function.expressions); let global_expr = components[member_index]; diff --git a/src/front/spv/mod.rs b/src/front/spv/mod.rs index 9c963fa04d..6c270dcbb7 100644 --- a/src/front/spv/mod.rs +++ b/src/front/spv/mod.rs @@ -235,10 +235,7 @@ impl Decoration { location: None, invariant, .. - } => map_builtin(built_in).map(|built_in| crate::Binding::BuiltIn { - built_in, - invariant: invariant && built_in == crate::BuiltIn::Position, - }), + } => Ok(crate::Binding::BuiltIn(map_builtin(built_in, invariant)?)), Decoration { built_in: None, location: Some(location), @@ -1475,7 +1472,7 @@ impl> Parser { span, ); - if let Some(crate::Binding::BuiltIn { built_in, .. }) = + if let Some(crate::Binding::BuiltIn(built_in)) = members[index as usize].binding { self.builtin_usage.insert(built_in); @@ -4646,7 +4643,7 @@ impl> Parser { ExtendedClass::Input => { let mut binding = dec.io_binding()?; let mut unsigned_ty = effective_ty; - if let crate::Binding::BuiltIn { built_in, .. } = binding { + if let crate::Binding::BuiltIn(built_in) = binding { let needs_inner_uint = match built_in { crate::BuiltIn::BaseInstance | crate::BuiltIn::BaseVertex @@ -4699,7 +4696,7 @@ impl> Parser { // For output interface blocks, this would be a structure. let mut binding = dec.io_binding().ok(); let init = match binding { - Some(crate::Binding::BuiltIn { built_in, .. }) => { + Some(crate::Binding::BuiltIn(built_in)) => { match null::generate_default_built_in( Some(built_in), effective_ty, @@ -4722,9 +4719,7 @@ impl> Parser { .iter() .map(|member| { let built_in = match member.binding { - Some(crate::Binding::BuiltIn { built_in, .. }) => { - Some(built_in) - } + Some(crate::Binding::BuiltIn(built_in)) => Some(built_in), _ => None, }; (built_in, member.ty) diff --git a/src/front/spv/null.rs b/src/front/spv/null.rs index 5d40dfa913..b0a8579a2f 100644 --- a/src/front/spv/null.rs +++ b/src/front/spv/null.rs @@ -121,7 +121,7 @@ pub fn generate_default_built_in( span: crate::Span, ) -> Result, Error> { let inner = match built_in { - Some(crate::BuiltIn::Position) => { + Some(crate::BuiltIn::Position { .. }) => { let zero = constant_arena.fetch_or_append( crate::Constant { name: None, diff --git a/src/front/wgsl/conv.rs b/src/front/wgsl/conv.rs index 3039d98fe9..6d4dd954a7 100644 --- a/src/front/wgsl/conv.rs +++ b/src/front/wgsl/conv.rs @@ -16,7 +16,7 @@ pub fn map_address_space(word: &str, span: Span) -> Result Result> { Ok(match word { - "position" => crate::BuiltIn::Position, + "position" => crate::BuiltIn::Position { invariant: false }, // vertex "vertex_index" => crate::BuiltIn::VertexIndex, "instance_index" => crate::BuiltIn::InstanceIndex, diff --git a/src/front/wgsl/mod.rs b/src/front/wgsl/mod.rs index a41f217334..511f6b66f9 100644 --- a/src/front/wgsl/mod.rs +++ b/src/front/wgsl/mod.rs @@ -1254,16 +1254,14 @@ impl BindingParser { sampling, })) } - (None, Some(crate::BuiltIn::Position), None, None, true) => { - Ok(Some(crate::Binding::BuiltIn { - built_in: crate::BuiltIn::Position, - invariant: true, - })) + (None, Some(crate::BuiltIn::Position { .. }), None, None, invariant) => { + Ok(Some(crate::Binding::BuiltIn(crate::BuiltIn::Position { + invariant, + }))) + } + (None, Some(built_in), None, None, false) => { + Ok(Some(crate::Binding::BuiltIn(built_in))) } - (None, Some(built_in), None, None, false) => Ok(Some(crate::Binding::BuiltIn { - built_in, - invariant: false, - })), (_, _, _, _, _) => Err(Error::InconsistentBinding(span)), } } diff --git a/src/lib.rs b/src/lib.rs index a90673895b..5ab1449fd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -325,7 +325,7 @@ pub enum AddressSpace { #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub enum BuiltIn { - Position, + Position { invariant: bool }, ViewIndex, // vertex BaseInstance, @@ -748,11 +748,7 @@ pub enum ConstantInner { #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub enum Binding { /// Built-in shader variable. - BuiltIn { - built_in: BuiltIn, - /// can only be `true` for [`BuiltIn::Position`] - invariant: bool, - }, + BuiltIn(BuiltIn), /// Indexed location. /// diff --git a/src/proc/mod.rs b/src/proc/mod.rs index 4e11a24e14..bc15268f4d 100644 --- a/src/proc/mod.rs +++ b/src/proc/mod.rs @@ -390,7 +390,7 @@ impl crate::Constant { impl crate::Binding { pub fn to_built_in(&self) -> Option { match *self { - crate::Binding::BuiltIn { built_in, .. } => Some(built_in), + crate::Binding::BuiltIn(built_in) => Some(built_in), Self::Location { .. } => None, } } diff --git a/src/valid/analyzer.rs b/src/valid/analyzer.rs index 7a31c32601..28a0f8a8ab 100644 --- a/src/valid/analyzer.rs +++ b/src/valid/analyzer.rs @@ -455,7 +455,7 @@ impl FunctionInfo { E::FunctionArgument(index) => { let arg = &resolve_context.arguments[index as usize]; let uniform = match arg.binding { - Some(crate::Binding::BuiltIn { built_in, .. }) => match built_in { + Some(crate::Binding::BuiltIn(built_in)) => match built_in { // per-polygon built-ins are uniform crate::BuiltIn::FrontFacing // per-work-group built-ins are uniform diff --git a/src/valid/interface.rs b/src/valid/interface.rs index eb2471a7ba..edaf7cca83 100644 --- a/src/valid/interface.rs +++ b/src/valid/interface.rs @@ -103,7 +103,7 @@ struct VaryingContext<'a> { output: bool, types: &'a UniqueArena, location_mask: &'a mut BitSet, - built_in_mask: u32, + built_ins: &'a mut crate::FastHashSet, capabilities: Capabilities, } @@ -115,12 +115,19 @@ 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 { + crate::Binding::BuiltIn(built_in) => { + // Ignore the `invariant` field for the sake of duplicate checks, + // but use the original in error messages. + let canonical = if let crate::BuiltIn::Position { .. } = built_in { + crate::BuiltIn::Position { invariant: false } + } else { + built_in + }; + + if self.built_ins.contains(&canonical) { return Err(VaryingError::DuplicateBuiltIn(built_in)); } - self.built_in_mask |= bit; + self.built_ins.insert(canonical); let width = 4; let (visible, type_good) = match built_in { @@ -153,7 +160,7 @@ impl VaryingContext<'_> { width, }, ), - Bi::Position => ( + Bi::Position { .. } => ( match self.stage { St::Vertex => self.output, St::Fragment => !self.output, @@ -457,7 +464,7 @@ impl super::Validator { } self.location_mask.clear(); - let mut argument_built_ins = 0; + let mut argument_built_ins = crate::FastHashSet::default(); // TODO: add span info to function arguments for (index, fa) in ep.function.arguments.iter().enumerate() { let mut ctx = VaryingContext { @@ -466,23 +473,23 @@ impl super::Validator { output: false, types: &module.types, location_mask: &mut self.location_mask, - built_in_mask: argument_built_ins, + built_ins: &mut argument_built_ins, capabilities: self.capabilities, }; ctx.validate(fa.binding.as_ref()) .map_err_inner(|e| EntryPointError::Argument(index as u32, e).with_span())?; - argument_built_ins = ctx.built_in_mask; } self.location_mask.clear(); if let Some(ref fr) = ep.function.result { + let mut result_built_ins = crate::FastHashSet::default(); 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, + built_ins: &mut result_built_ins, capabilities: self.capabilities, }; ctx.validate(fr.binding.as_ref()) diff --git a/tests/out/ir/collatz.ron b/tests/out/ir/collatz.ron index a4d86445bb..50860b2cb7 100644 --- a/tests/out/ir/collatz.ron +++ b/tests/out/ir/collatz.ron @@ -284,10 +284,7 @@ ( name: Some("global_id"), ty: 4, - binding: Some(BuiltIn( - built_in: GlobalInvocationId, - invariant: false, - )), + binding: Some(BuiltIn(GlobalInvocationId)), ), ], result: None, diff --git a/tests/out/spv/interface.fragment.spvasm b/tests/out/spv/interface.fragment.spvasm index 7dc246b00e..154747e5f2 100644 --- a/tests/out/spv/interface.fragment.spvasm +++ b/tests/out/spv/interface.fragment.spvasm @@ -17,8 +17,8 @@ OpMemberDecorate %14 2 Offset 8 OpDecorate %16 ArrayStride 4 OpMemberDecorate %18 0 Offset 0 OpMemberDecorate %19 0 Offset 0 -OpDecorate %22 BuiltIn FragCoord OpDecorate %22 Invariant +OpDecorate %22 BuiltIn FragCoord OpDecorate %25 Location 1 OpDecorate %28 BuiltIn FrontFacing OpDecorate %31 BuiltIn SampleId diff --git a/tests/out/spv/interface.vertex.spvasm b/tests/out/spv/interface.vertex.spvasm index de082608df..645077ca26 100644 --- a/tests/out/spv/interface.vertex.spvasm +++ b/tests/out/spv/interface.vertex.spvasm @@ -18,8 +18,8 @@ OpDecorate %21 BuiltIn VertexIndex OpDecorate %24 BuiltIn InstanceIndex OpDecorate %26 Location 10 OpDecorate %26 Flat -OpDecorate %28 BuiltIn Position OpDecorate %28 Invariant +OpDecorate %28 BuiltIn Position OpDecorate %30 Location 1 OpDecorate %32 BuiltIn PointSize %2 = OpTypeVoid diff --git a/tests/out/spv/interface.vertex_two_structs.spvasm b/tests/out/spv/interface.vertex_two_structs.spvasm index ea5313db0b..190f391c39 100644 --- a/tests/out/spv/interface.vertex_two_structs.spvasm +++ b/tests/out/spv/interface.vertex_two_structs.spvasm @@ -16,8 +16,8 @@ OpMemberDecorate %18 0 Offset 0 OpMemberDecorate %19 0 Offset 0 OpDecorate %24 BuiltIn VertexIndex OpDecorate %28 BuiltIn InstanceIndex -OpDecorate %30 BuiltIn Position OpDecorate %30 Invariant +OpDecorate %30 BuiltIn Position OpDecorate %32 BuiltIn PointSize %2 = OpTypeVoid %4 = OpTypeFloat 32