diff --git a/src/back/glsl/features.rs b/src/back/glsl/features.rs index 0404ee03f1..d5c835f9d0 100644 --- a/src/back/glsl/features.rs +++ b/src/back/glsl/features.rs @@ -1,7 +1,7 @@ use super::{BackendResult, Error, Version, Writer}; use crate::{ - Binding, Bytes, Handle, ImageClass, ImageDimension, Interpolation, ScalarKind, ShaderStage, - StorageClass, StorageFormat, Type, TypeInner, + Binding, Bytes, Handle, ImageClass, ImageDimension, Interpolation, Sampling, ScalarKind, + ShaderStage, StorageClass, StorageFormat, Type, TypeInner, }; use std::io::Write; @@ -289,16 +289,16 @@ impl<'a, W> Writer<'a, W> { } _ => { if let Some(&Binding::Location { - interpolation: Some(interpolation), + interpolation, + sampling, .. }) = binding { - match interpolation { - Interpolation::Linear => { - self.features.request(Features::NOPERSPECTIVE_QUALIFIER) - } - Interpolation::Sample => self.features.request(Features::SAMPLE_QUALIFIER), - _ => (), - }; + if interpolation == Some(Interpolation::Linear) { + self.features.request(Features::NOPERSPECTIVE_QUALIFIER); + } + if sampling == Some(Sampling::Sample) { + self.features.request(Features::SAMPLE_QUALIFIER); + } } } } diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index f58e6a7289..b8541e0d4d 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -48,9 +48,10 @@ use crate::{ valid::{FunctionInfo, ModuleInfo}, Arena, ArraySize, BinaryOperator, Binding, BuiltIn, Bytes, ConservativeDepth, Constant, ConstantInner, DerivativeAxis, Expression, FastHashMap, Function, GlobalVariable, Handle, - ImageClass, Interpolation, LocalVariable, Module, RelationalFunction, ScalarKind, ScalarValue, - ShaderStage, Statement, StorageAccess, StorageClass, StorageFormat, StructMember, Type, - TypeInner, UnaryOperator, + ImageClass, Interpolation, LocalVariable, Module, RelationalFunction, Sampling, ScalarKind, + ScalarValue, ShaderStage, Statement, StorageAccess, StorageClass, StorageFormat, StructMember, + Type, TypeInner, UnaryOperator, + }; use features::FeaturesManager; use std::{ @@ -232,8 +233,10 @@ impl IdGenerator { /// Helper wrapper used to get a name for a varying /// /// Varying have different naming schemes depending on their binding: -/// - Varyings with builtin bindings get the from [`glsl_built_in`](glsl_built_in) -/// - Varyings with location bindings are named `_location_X` where `X` is the location +/// - Varyings with builtin bindings get the from [`glsl_built_in`](glsl_built_in). +/// - Varyings with location bindings are named `_S_location_X` where `S` is a +/// prefix identifying which pipeline stage the varying connects, and `X` is +/// the location. struct VaryingName<'a> { binding: &'a Binding, stage: ShaderStage, @@ -793,16 +796,22 @@ impl<'a, W: Write> Writer<'a, W> { } } _ => { - let (location, interpolation) = match binding { - Some(&Binding::Location { location, interpolation }) => (location, interpolation), + let (location, interpolation, sampling) = match binding { + Some(&Binding::Location { location, interpolation, sampling }) => (location, interpolation, sampling), _ => return Ok(()), }; + // Write the interpolation modifier if needed // - // We ignore all interpolation modifiers that aren't used in input globals in fragment - // shaders or output globals in vertex shaders + // We ignore all interpolation and auxiliary modifiers that aren't used in fragment + // shaders' input globals or vertex shaders' output globals. + let emit_interpolation_and_auxiliary = match self.options.shader_stage { + ShaderStage::Vertex => output, + ShaderStage::Fragment => !output, + _ => false, + }; if let Some(interp) = interpolation { - if self.options.shader_stage == ShaderStage::Fragment { + if emit_interpolation_and_auxiliary { write!(self.out, "{} ", glsl_interpolation(interp))?; } } @@ -811,13 +820,24 @@ impl<'a, W: Write> Writer<'a, W> { if self.options.version.supports_explicit_locations() { write!( self.out, - "layout(location = {}) {} ", - location, - if output { "out" } else { "in" } - )?; - } else { - write!(self.out, "{} ", if output { "out" } else { "in" })?; + "layout(location = {}) ", + location)?; } + + // Write the sampling auxiliary qualifier. + // + // Before GLSL 4.2, the `centroid` and `sample` qualifiers were required to appear + // immediately before the `in` / `out` qualifier, so we'll just follow that rule + // here, regardless of the version. + if let Some(sampling) = sampling { + if emit_interpolation_and_auxiliary { + write!(self.out, "{} ", glsl_sampling(sampling))?; + } + } + + // Write the input/output qualifier. + write!(self.out, "{} ", if output { "out" } else { "in" })?; + // Write the type // `write_type` adds no leading or trailing spaces self.write_type(ty)?; @@ -825,7 +845,7 @@ impl<'a, W: Write> Writer<'a, W> { // Finally write the global name and end the global with a `;` and a newline // Leading space is important let vname = VaryingName { - binding: &Binding::Location { location, interpolation: None }, + binding: &Binding::Location { location, interpolation: None, sampling: None }, stage: self.entry_point.stage, output, }; @@ -2201,8 +2221,15 @@ fn glsl_interpolation(interpolation: Interpolation) -> &'static str { Interpolation::Perspective => "smooth", Interpolation::Linear => "noperspective", Interpolation::Flat => "flat", - Interpolation::Centroid => "centroid", - Interpolation::Sample => "sample", + } +} + +/// Return the GLSL auxiliary qualifier for the given sampling value. +fn glsl_sampling(sampling: Sampling) -> &'static str { + match sampling { + Sampling::Center => "", + Sampling::Centroid => "centroid", + Sampling::Sample => "sample", } } diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index 123c0d36c7..39df6f223a 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -1090,17 +1090,29 @@ impl Writer { use spirv::{BuiltIn, Decoration}; match *binding { - crate::Binding::Location { location, interpolation } => { + crate::Binding::Location { location, interpolation, sampling } => { self.decorate(id, Decoration::Location, &[location]); - let interp_decoration = match interpolation { - Some(crate::Interpolation::Linear) => Some(Decoration::NoPerspective), - Some(crate::Interpolation::Flat) => Some(Decoration::Flat), - Some(crate::Interpolation::Centroid) => Some(Decoration::Centroid), - Some(crate::Interpolation::Sample) => Some(Decoration::Sample), - Some(crate::Interpolation::Perspective) | None => None, - }; - if let Some(decoration) = interp_decoration { - self.decorate(id, decoration, &[]); + + match interpolation { + // Perspective-correct interpolation is the default in SPIR-V. + None | Some(crate::Interpolation::Perspective) => (), + Some(crate::Interpolation::Flat) => { + self.decorate(id, Decoration::Flat, &[]); + } + Some(crate::Interpolation::Linear) => { + self.decorate(id, Decoration::NoPerspective, &[]); + } + } + + match sampling { + // Center sampling is the default in SPIR-V. + None | Some(crate::Sampling::Center) => (), + Some(crate::Sampling::Centroid) => { + self.decorate(id, Decoration::Centroid, &[]); + } + Some(crate::Sampling::Sample) => { + self.decorate(id, Decoration::Sample, &[]); + } } } crate::Binding::BuiltIn(built_in) => { diff --git a/src/front/glsl/ast.rs b/src/front/glsl/ast.rs index 78f914af58..a832a6fde2 100644 --- a/src/front/glsl/ast.rs +++ b/src/front/glsl/ast.rs @@ -2,7 +2,8 @@ use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind}; use crate::{ proc::ResolveContext, Arena, BinaryOperator, Binding, Constant, Expression, FastHashMap, Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, Module, - RelationalFunction, ResourceBinding, ShaderStage, Statement, StorageClass, Type, UnaryOperator, + RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, Type, + UnaryOperator, }; #[derive(Debug)] @@ -226,6 +227,7 @@ pub enum TypeQualifier { ResourceBinding(ResourceBinding), Binding(Binding), Interpolation(Interpolation), + Sampling(Sampling), } #[derive(Debug)] diff --git a/src/front/glsl/lex.rs b/src/front/glsl/lex.rs index 6f72c5c80f..08874dfeea 100644 --- a/src/front/glsl/lex.rs +++ b/src/front/glsl/lex.rs @@ -66,8 +66,8 @@ impl<'a> Iterator for Lexer<'a> { "flat" => Token::Interpolation((meta, crate::Interpolation::Flat)), "noperspective" => Token::Interpolation((meta, crate::Interpolation::Linear)), "smooth" => Token::Interpolation((meta, crate::Interpolation::Perspective)), - "centroid" => Token::Interpolation((meta, crate::Interpolation::Centroid)), - "sample" => Token::Interpolation((meta, crate::Interpolation::Sample)), + "centroid" => Token::Sampling((meta, crate::Sampling::Centroid)), + "sample" => Token::Sampling((meta, crate::Sampling::Sample)), // values "true" => Token::BoolConstant((meta, true)), "false" => Token::BoolConstant((meta, false)), diff --git a/src/front/glsl/parser.rs b/src/front/glsl/parser.rs index d20a9302fb..276529b0b4 100644 --- a/src/front/glsl/parser.rs +++ b/src/front/glsl/parser.rs @@ -10,7 +10,7 @@ pomelo! { ConstantInner, Expression, Function, FunctionArgument, FunctionResult, GlobalVariable, Handle, Interpolation, - LocalVariable, ResourceBinding, ScalarValue, ScalarKind, + LocalVariable, ResourceBinding, Sampling, ScalarValue, ScalarKind, Statement, StorageAccess, StorageClass, StructMember, SwitchCase, Type, TypeInner, UnaryOperator, }; @@ -120,6 +120,8 @@ pomelo! { %type storage_qualifier StorageQualifier; %type interpolation_qualifier Interpolation; %type Interpolation Interpolation; + %type sampling_qualifier Sampling; + %type Sampling Sampling; // types %type fully_specified_type (Vec, Option>); @@ -613,10 +615,15 @@ pomelo! { i } + sampling_qualifier ::= Sampling((_, s)) { + s + } + layout_qualifier ::= Layout LeftParen layout_qualifier_id_list(l) RightParen { if let Some(&(_, location)) = l.iter().find(|&q| q.0.as_str() == "location") { let interpolation = None; //TODO - StructLayout::Binding(Binding::Location { location, interpolation }) + let sampling = None; //TODO + StructLayout::Binding(Binding::Location { location, interpolation, sampling }) } else if let Some(&(_, binding)) = l.iter().find(|&q| q.0.as_str() == "binding") { let group = if let Some(&(_, set)) = l.iter().find(|&q| q.0.as_str() == "set") { set @@ -670,6 +677,9 @@ pomelo! { single_type_qualifier ::= interpolation_qualifier(i) { TypeQualifier::Interpolation(i) } + single_type_qualifier ::= sampling_qualifier(i) { + TypeQualifier::Sampling(i) + } // single_type_qualifier ::= invariant_qualifier; // single_type_qualifier ::= precise_qualifier; @@ -1133,8 +1143,16 @@ pomelo! { let interpolation = d.type_qualifiers.iter().find_map(|tq| { if let TypeQualifier::Interpolation(interp) = *tq { Some(interp) } else { None } }); - if let Some(Binding::Location { interpolation: ref mut interp, .. }) = binding { + let sampling = d.type_qualifiers.iter().find_map(|tq| { + if let TypeQualifier::Sampling(samp) = *tq { Some(samp) } else { None } + }); + if let Some(Binding::Location { + interpolation: ref mut interp, + sampling: ref mut samp, + .. + }) = binding { *interp = interpolation; + *samp = sampling; } for (id, _initializer) in d.ids_initializers { diff --git a/src/front/spv/mod.rs b/src/front/spv/mod.rs index a0943eed52..e4d7a1c715 100644 --- a/src/front/spv/mod.rs +++ b/src/front/spv/mod.rs @@ -220,6 +220,7 @@ struct Decoration { matrix_stride: Option, matrix_major: Option, interpolation: Option, + sampling: Option, flags: DecorationFlags, } @@ -253,8 +254,9 @@ impl Decoration { built_in: None, location: Some(location), interpolation, + sampling, .. - } => Ok(crate::Binding::Location { location, interpolation }), + } => Ok(crate::Binding::Location { location, interpolation, sampling }), _ => Err(Error::MissingDecoration(spirv::Decoration::Location)), } } @@ -504,10 +506,10 @@ impl> Parser { dec.interpolation = Some(crate::Interpolation::Flat); } spirv::Decoration::Centroid => { - dec.interpolation = Some(crate::Interpolation::Centroid); + dec.sampling = Some(crate::Sampling::Centroid); } spirv::Decoration::Sample => { - dec.interpolation = Some(crate::Interpolation::Sample); + dec.sampling = Some(crate::Sampling::Sample); } spirv::Decoration::NonReadable => { dec.flags |= DecorationFlags::NON_READABLE; diff --git a/src/front/wgsl/conv.rs b/src/front/wgsl/conv.rs index cd84c0b579..227327ad5e 100644 --- a/src/front/wgsl/conv.rs +++ b/src/front/wgsl/conv.rs @@ -44,13 +44,19 @@ pub fn map_interpolation(word: &str) -> Result> match word { "linear" => Ok(crate::Interpolation::Linear), "flat" => Ok(crate::Interpolation::Flat), - "centroid" => Ok(crate::Interpolation::Centroid), - "sample" => Ok(crate::Interpolation::Sample), "perspective" => Ok(crate::Interpolation::Perspective), _ => Err(Error::UnknownAttribute(word)), } } +pub fn map_sampling(word: &str) -> Result> { + match word { + "centroid" => Ok(crate::Sampling::Centroid), + "sample" => Ok(crate::Sampling::Sample), + _ => Err(Error::UnknownAttribute(word)), + } +} + pub fn map_storage_format(word: &str) -> Result> { use crate::StorageFormat as Sf; Ok(match word { diff --git a/src/front/wgsl/mod.rs b/src/front/wgsl/mod.rs index 2bd5497fdb..cea66700ca 100644 --- a/src/front/wgsl/mod.rs +++ b/src/front/wgsl/mod.rs @@ -112,11 +112,12 @@ pub enum Error<'a> { ZeroSizeOrAlign, #[error("not a composite type: {0:?}")] NotCompositeType(Handle), - #[error("Input/output binding is not consistent: location {0:?}, built-in {1:?} and interpolation {2:?}")] + #[error("Input/output binding is not consistent: location {0:?}, built-in {1:?}, interpolation {2:?}, and sampling {3:?}")] InconsistentBinding( Option, Option, Option, + Option, ), #[error("call to local `{0}(..)` can't be resolved")] UnknownLocalFunction(&'a str), @@ -470,6 +471,7 @@ struct BindingParser { location: Option, built_in: Option, interpolation: Option, + sampling: Option, } impl BindingParser { @@ -490,6 +492,10 @@ impl BindingParser { lexer.expect(Token::Paren('('))?; let raw = lexer.next_ident()?; self.interpolation = Some(conv::map_interpolation(raw)?); + if lexer.skip(Token::Separator(',')) { + let raw = lexer.next_ident()?; + self.sampling = Some(conv::map_sampling(raw)?); + } lexer.expect(Token::Paren(')'))?; } _ => return Err(Error::UnknownAttribute(name)), @@ -498,16 +504,17 @@ impl BindingParser { } fn finish<'a>(self) -> Result, Error<'a>> { - match (self.location, self.built_in, self.interpolation) { - (None, None, None) => Ok(None), - (Some(location), None, interpolation) => { - Ok(Some(crate::Binding::Location { location, interpolation })) + match (self.location, self.built_in, self.interpolation, self.sampling) { + (None, None, None, None) => Ok(None), + (Some(location), None, interpolation, sampling) => { + Ok(Some(crate::Binding::Location { location, interpolation, sampling })) } - (None, Some(bi), None) => Ok(Some(crate::Binding::BuiltIn(bi))), - (location, built_in, interpolation) => Err(Error::InconsistentBinding( + (None, Some(bi), None, None) => Ok(Some(crate::Binding::BuiltIn(bi))), + (location, built_in, interpolation, sampling) => Err(Error::InconsistentBinding( location, built_in, interpolation, + sampling, )), } } diff --git a/src/lib.rs b/src/lib.rs index 918f285ce5..b95fe251b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -226,11 +226,23 @@ pub enum Interpolation { Linear, /// Indicates that no interpolation will be performed. Flat, - /// When used with multi-sampling rasterization, allow - /// a single interpolation location for an entire pixel. +} + +/// The sampling qualifiers of a binding or struct field. +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub enum Sampling { + /// Interpolate the value at the center of the pixel. + Center, + + /// Interpolate the value at a point that lies within all samples covered by + /// the fragment within the current primitive. In multisampling, use a + /// single value for all samples in the primitive. Centroid, - /// When used with multi-sampling rasterization, require - /// per-sample interpolation. + + /// Interpolate the value at each sample location. In multisampling, invoke + /// the fragment shader once per sample. Sample, } @@ -465,7 +477,11 @@ pub enum Binding { /// Built-in shader variable. BuiltIn(BuiltIn), /// Indexed location. - Location { location: u32, interpolation: Option }, + Location { + location: u32, + interpolation: Option, + sampling: Option + }, } /// Pipeline binding information for global resources. diff --git a/src/valid/interface.rs b/src/valid/interface.rs index 350939a07f..c041169956 100644 --- a/src/valid/interface.rs +++ b/src/valid/interface.rs @@ -206,7 +206,7 @@ impl VaryingContext<'_> { return Err(VaryingError::InvalidBuiltInType(built_in)); } } - crate::Binding::Location { location, interpolation } => { + crate::Binding::Location { location, interpolation, sampling } => { if !self.location_mask.insert(location as usize) { return Err(VaryingError::BindingCollision { location }); } @@ -218,6 +218,11 @@ impl VaryingContext<'_> { if !needs_interpolation && interpolation.is_some() { return Err(VaryingError::InvalidInterpolation); } + // It doesn't make sense to specify a sampling when + // `interpolation` is `Flat`, but SPIR-V and GLSL both + // explicitly tolerate such combinations of decorators / + // qualifiers, so we won't complain about that here. + let _ = sampling; match ty_inner.scalar_kind() { Some(crate::ScalarKind::Float) => {} Some(_) diff --git a/tests/in/interpolate.wgsl b/tests/in/interpolate.wgsl index 0bdad96922..51eb4fde74 100644 --- a/tests/in/interpolate.wgsl +++ b/tests/in/interpolate.wgsl @@ -1,10 +1,12 @@ struct FragmentInput { [[builtin(position)]] position: vec4; [[location(0), interpolate(flat)]] flat : u32; - [[location(1), interpolate(linear)]] linear: f32; - [[location(2), interpolate(centroid)]] centroid: vec2; - [[location(3), interpolate(sample)]] sample: vec3; - [[location(4), interpolate(perspective)]] perspective: vec4; + [[location(1), interpolate(linear)]] linear : f32; + [[location(2), interpolate(linear,centroid)]] linear_centroid : vec2; + [[location(3), interpolate(linear,sample)]] linear_sample : vec3; + [[location(4), interpolate(perspective)]] perspective : vec4; + [[location(5), interpolate(perspective,centroid)]] perspective_centroid : f32; + [[location(6), interpolate(perspective,sample)]] perspective_sample : f32; }; [[stage(vertex)]] @@ -14,9 +16,11 @@ fn main() -> FragmentInput { out.position = vec4(2.0, 4.0, 5.0, 6.0); out.flat = 8u32; out.linear = 27.0; - out.centroid = vec2(64.0, 125.0); - out.sample = vec3(216.0, 343.0, 512.0); + out.linear_centroid = vec2(64.0, 125.0); + out.linear_sample = vec3(216.0, 343.0, 512.0); out.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0); + out.perspective_centroid = 2197.0; + out.perspective_sample = 2744.0; return out; } diff --git a/tests/out/interpolate.Fragment.glsl b/tests/out/interpolate.Fragment.glsl index 6ec1a66ad7..b415997304 100644 --- a/tests/out/interpolate.Fragment.glsl +++ b/tests/out/interpolate.Fragment.glsl @@ -3,19 +3,23 @@ struct FragmentInput { vec4 position; uint flat1; float linear; - vec2 centroid1; - vec3 sample1; + vec2 linear_centroid; + vec3 linear_sample; vec4 perspective; + float perspective_centroid; + float perspective_sample; }; flat in uint _vs2fs_location0; noperspective in float _vs2fs_location1; -centroid in vec2 _vs2fs_location2; -sample in vec3 _vs2fs_location3; +noperspective centroid in vec2 _vs2fs_location2; +noperspective sample in vec3 _vs2fs_location3; smooth in vec4 _vs2fs_location4; +smooth centroid in float _vs2fs_location5; +smooth sample in float _vs2fs_location6; void main() { - FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location1, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4); + FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location1, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4, _vs2fs_location5, _vs2fs_location6); return; } diff --git a/tests/out/interpolate.Vertex.glsl b/tests/out/interpolate.Vertex.glsl index 3f105dccf3..e287089a15 100644 --- a/tests/out/interpolate.Vertex.glsl +++ b/tests/out/interpolate.Vertex.glsl @@ -3,31 +3,39 @@ struct FragmentInput { vec4 position; uint flat1; float linear; - vec2 centroid1; - vec3 sample1; + vec2 linear_centroid; + vec3 linear_sample; vec4 perspective; + float perspective_centroid; + float perspective_sample; }; -out uint _vs2fs_location0; -out float _vs2fs_location1; -out vec2 _vs2fs_location2; -out vec3 _vs2fs_location3; -out vec4 _vs2fs_location4; +flat out uint _vs2fs_location0; +noperspective out float _vs2fs_location1; +noperspective centroid out vec2 _vs2fs_location2; +noperspective sample out vec3 _vs2fs_location3; +smooth out vec4 _vs2fs_location4; +smooth centroid out float _vs2fs_location5; +smooth sample out float _vs2fs_location6; void main() { FragmentInput out1; out1.position = vec4(2.0, 4.0, 5.0, 6.0); out1.flat1 = 8u; out1.linear = 27.0; - out1.centroid1 = vec2(64.0, 125.0); - out1.sample1 = vec3(216.0, 343.0, 512.0); + out1.linear_centroid = vec2(64.0, 125.0); + out1.linear_sample = vec3(216.0, 343.0, 512.0); out1.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0); + out1.perspective_centroid = 2197.0; + out1.perspective_sample = 2744.0; gl_Position = out1.position; _vs2fs_location0 = out1.flat1; _vs2fs_location1 = out1.linear; - _vs2fs_location2 = out1.centroid1; - _vs2fs_location3 = out1.sample1; + _vs2fs_location2 = out1.linear_centroid; + _vs2fs_location3 = out1.linear_sample; _vs2fs_location4 = out1.perspective; + _vs2fs_location5 = out1.perspective_centroid; + _vs2fs_location6 = out1.perspective_sample; return; } diff --git a/tests/out/interpolate.msl b/tests/out/interpolate.msl index 713dc4ef94..d1f7514a4e 100644 --- a/tests/out/interpolate.msl +++ b/tests/out/interpolate.msl @@ -5,18 +5,22 @@ struct FragmentInput { metal::float4 position; metal::uint flat; float linear; - metal::float2 centroid; - metal::float3 sample; + metal::float2 linear_centroid; + metal::float3 linear_sample; metal::float4 perspective; + float perspective_centroid; + float perspective_sample; }; struct main1Output { metal::float4 position [[position]]; metal::uint flat [[user(loc0)]]; float linear [[user(loc1)]]; - metal::float2 centroid [[user(loc2)]]; - metal::float3 sample [[user(loc3)]]; + metal::float2 linear_centroid [[user(loc2)]]; + metal::float3 linear_sample [[user(loc3)]]; metal::float4 perspective [[user(loc4)]]; + float perspective_centroid [[user(loc5)]]; + float perspective_sample [[user(loc6)]]; }; vertex main1Output main1( ) { @@ -24,25 +28,29 @@ vertex main1Output main1( out.position = metal::float4(2.0, 4.0, 5.0, 6.0); out.flat = 8u; out.linear = 27.0; - out.centroid = metal::float2(64.0, 125.0); - out.sample = metal::float3(216.0, 343.0, 512.0); + out.linear_centroid = metal::float2(64.0, 125.0); + out.linear_sample = metal::float3(216.0, 343.0, 512.0); out.perspective = metal::float4(729.0, 1000.0, 1331.0, 1728.0); + out.perspective_centroid = 2197.0; + out.perspective_sample = 2744.0; const auto _tmp = out; - return main1Output { _tmp.position, _tmp.flat, _tmp.linear, _tmp.centroid, _tmp.sample, _tmp.perspective }; + return main1Output { _tmp.position, _tmp.flat, _tmp.linear, _tmp.linear_centroid, _tmp.linear_sample, _tmp.perspective, _tmp.perspective_centroid, _tmp.perspective_sample }; } struct main2Input { metal::uint flat [[user(loc0)]]; float linear [[user(loc1)]]; - metal::float2 centroid [[user(loc2)]]; - metal::float3 sample [[user(loc3)]]; + metal::float2 linear_centroid [[user(loc2)]]; + metal::float3 linear_sample [[user(loc3)]]; metal::float4 perspective [[user(loc4)]]; + float perspective_centroid [[user(loc5)]]; + float perspective_sample [[user(loc6)]]; }; fragment void main2( main2Input varyings1 [[stage_in]] , metal::float4 position [[position]] ) { - const FragmentInput val = { position, varyings1.flat, varyings1.linear, varyings1.centroid, varyings1.sample, varyings1.perspective }; + const FragmentInput val = { position, varyings1.flat, varyings1.linear, varyings1.linear_centroid, varyings1.linear_sample, varyings1.perspective, varyings1.perspective_centroid, varyings1.perspective_sample }; return; } diff --git a/tests/out/interpolate.spvasm b/tests/out/interpolate.spvasm index 112bd1f0f5..1fa0dfbd4d 100644 --- a/tests/out/interpolate.spvasm +++ b/tests/out/interpolate.spvasm @@ -1,63 +1,83 @@ ; SPIR-V ; Version: 1.0 ; Generator: rspirv -; Bound: 95 +; Bound: 109 OpCapability Shader OpCapability SampleRateShading %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %38 "main" %27 %29 %31 %33 %35 %37 -OpEntryPoint Fragment %93 "main" %76 %79 %82 %85 %88 %91 -OpExecutionMode %93 OriginUpperLeft +OpEntryPoint Vertex %42 "main" %29 %31 %33 %35 %37 %39 %40 %41 +OpEntryPoint Fragment %107 "main" %86 %89 %92 %95 %98 %101 %103 %105 +OpExecutionMode %107 OriginUpperLeft OpSource GLSL 450 -OpName %23 "FragmentInput" -OpMemberName %23 0 "position" -OpMemberName %23 1 "flat" -OpMemberName %23 2 "linear" -OpMemberName %23 3 "centroid" -OpMemberName %23 4 "sample" -OpMemberName %23 5 "perspective" -OpName %24 "out" -OpName %27 "position" -OpName %29 "flat" -OpName %31 "linear" -OpName %33 "centroid" -OpName %35 "sample" -OpName %37 "perspective" -OpName %38 "main" -OpName %76 "position" -OpName %79 "flat" -OpName %82 "linear" -OpName %85 "centroid" -OpName %88 "sample" -OpName %91 "perspective" -OpName %93 "main" -OpMemberDecorate %23 0 Offset 0 -OpMemberDecorate %23 1 Offset 16 -OpMemberDecorate %23 2 Offset 20 -OpMemberDecorate %23 3 Offset 24 -OpMemberDecorate %23 4 Offset 32 -OpMemberDecorate %23 5 Offset 48 -OpDecorate %27 BuiltIn Position -OpDecorate %29 Location 0 -OpDecorate %29 Flat -OpDecorate %31 Location 1 -OpDecorate %31 NoPerspective -OpDecorate %33 Location 2 -OpDecorate %33 Centroid -OpDecorate %35 Location 3 -OpDecorate %35 Sample -OpDecorate %37 Location 4 -OpDecorate %76 BuiltIn FragCoord -OpDecorate %79 Location 0 -OpDecorate %79 Flat -OpDecorate %82 Location 1 -OpDecorate %82 NoPerspective -OpDecorate %85 Location 2 -OpDecorate %85 Centroid -OpDecorate %88 Location 3 -OpDecorate %88 Sample -OpDecorate %91 Location 4 +OpName %25 "FragmentInput" +OpMemberName %25 0 "position" +OpMemberName %25 1 "flat" +OpMemberName %25 2 "linear" +OpMemberName %25 3 "linear_centroid" +OpMemberName %25 4 "linear_sample" +OpMemberName %25 5 "perspective" +OpMemberName %25 6 "perspective_centroid" +OpMemberName %25 7 "perspective_sample" +OpName %26 "out" +OpName %29 "position" +OpName %31 "flat" +OpName %33 "linear" +OpName %35 "linear_centroid" +OpName %37 "linear_sample" +OpName %39 "perspective" +OpName %40 "perspective_centroid" +OpName %41 "perspective_sample" +OpName %42 "main" +OpName %86 "position" +OpName %89 "flat" +OpName %92 "linear" +OpName %95 "linear_centroid" +OpName %98 "linear_sample" +OpName %101 "perspective" +OpName %103 "perspective_centroid" +OpName %105 "perspective_sample" +OpName %107 "main" +OpMemberDecorate %25 0 Offset 0 +OpMemberDecorate %25 1 Offset 16 +OpMemberDecorate %25 2 Offset 20 +OpMemberDecorate %25 3 Offset 24 +OpMemberDecorate %25 4 Offset 32 +OpMemberDecorate %25 5 Offset 48 +OpMemberDecorate %25 6 Offset 64 +OpMemberDecorate %25 7 Offset 68 +OpDecorate %29 BuiltIn Position +OpDecorate %31 Location 0 +OpDecorate %31 Flat +OpDecorate %33 Location 1 +OpDecorate %33 NoPerspective +OpDecorate %35 Location 2 +OpDecorate %35 NoPerspective +OpDecorate %35 Centroid +OpDecorate %37 Location 3 +OpDecorate %37 NoPerspective +OpDecorate %37 Sample +OpDecorate %39 Location 4 +OpDecorate %40 Location 5 +OpDecorate %40 Centroid +OpDecorate %41 Location 6 +OpDecorate %41 Sample +OpDecorate %86 BuiltIn FragCoord +OpDecorate %89 Location 0 +OpDecorate %89 Flat +OpDecorate %92 Location 1 +OpDecorate %92 NoPerspective +OpDecorate %95 Location 2 +OpDecorate %95 NoPerspective +OpDecorate %95 Centroid +OpDecorate %98 Location 3 +OpDecorate %98 NoPerspective +OpDecorate %98 Sample +OpDecorate %101 Location 4 +OpDecorate %103 Location 5 +OpDecorate %103 Centroid +OpDecorate %105 Location 6 +OpDecorate %105 Sample %2 = OpTypeVoid %4 = OpTypeFloat 32 %3 = OpConstant %4 2.0 @@ -76,97 +96,115 @@ OpDecorate %91 Location 4 %17 = OpConstant %4 1000.0 %18 = OpConstant %4 1331.0 %19 = OpConstant %4 1728.0 -%20 = OpTypeVector %4 4 -%21 = OpTypeVector %4 2 -%22 = OpTypeVector %4 3 -%23 = OpTypeStruct %20 %9 %4 %21 %22 %20 -%25 = OpTypePointer Function %23 -%28 = OpTypePointer Output %20 -%27 = OpVariable %28 Output -%30 = OpTypePointer Output %9 +%20 = OpConstant %4 2197.0 +%21 = OpConstant %4 2744.0 +%22 = OpTypeVector %4 4 +%23 = OpTypeVector %4 2 +%24 = OpTypeVector %4 3 +%25 = OpTypeStruct %22 %9 %4 %23 %24 %22 %4 %4 +%27 = OpTypePointer Function %25 +%30 = OpTypePointer Output %22 %29 = OpVariable %30 Output -%32 = OpTypePointer Output %4 +%32 = OpTypePointer Output %9 %31 = OpVariable %32 Output -%34 = OpTypePointer Output %21 +%34 = OpTypePointer Output %4 %33 = OpVariable %34 Output -%36 = OpTypePointer Output %22 +%36 = OpTypePointer Output %23 %35 = OpVariable %36 Output -%37 = OpVariable %28 Output -%39 = OpTypeFunction %2 -%41 = OpTypePointer Function %20 -%43 = OpTypeInt 32 1 -%44 = OpConstant %43 0 -%46 = OpTypePointer Function %9 -%47 = OpConstant %43 1 -%49 = OpTypePointer Function %4 -%50 = OpConstant %43 2 -%52 = OpTypePointer Function %21 -%54 = OpConstant %43 3 -%56 = OpTypePointer Function %22 -%58 = OpConstant %43 4 -%61 = OpConstant %43 5 -%66 = OpTypePointer Output %4 -%77 = OpTypePointer Input %20 -%76 = OpVariable %77 Input -%80 = OpTypePointer Input %9 -%79 = OpVariable %80 Input -%83 = OpTypePointer Input %4 -%82 = OpVariable %83 Input -%86 = OpTypePointer Input %21 -%85 = OpVariable %86 Input -%89 = OpTypePointer Input %22 -%88 = OpVariable %89 Input -%91 = OpVariable %77 Input -%38 = OpFunction %2 None %39 -%26 = OpLabel -%24 = OpVariable %25 Function -OpBranch %40 -%40 = OpLabel -%42 = OpCompositeConstruct %20 %3 %5 %6 %7 -%45 = OpAccessChain %41 %24 %44 -OpStore %45 %42 -%48 = OpAccessChain %46 %24 %47 -OpStore %48 %8 -%51 = OpAccessChain %49 %24 %50 -OpStore %51 %10 -%53 = OpCompositeConstruct %21 %11 %12 -%55 = OpAccessChain %52 %24 %54 -OpStore %55 %53 -%57 = OpCompositeConstruct %22 %13 %14 %15 -%59 = OpAccessChain %56 %24 %58 +%38 = OpTypePointer Output %24 +%37 = OpVariable %38 Output +%39 = OpVariable %30 Output +%40 = OpVariable %34 Output +%41 = OpVariable %34 Output +%43 = OpTypeFunction %2 +%45 = OpTypePointer Function %22 +%47 = OpTypeInt 32 1 +%48 = OpConstant %47 0 +%50 = OpTypePointer Function %9 +%51 = OpConstant %47 1 +%53 = OpTypePointer Function %4 +%54 = OpConstant %47 2 +%56 = OpTypePointer Function %23 +%58 = OpConstant %47 3 +%60 = OpTypePointer Function %24 +%62 = OpConstant %47 4 +%65 = OpConstant %47 5 +%67 = OpConstant %47 6 +%69 = OpConstant %47 7 +%74 = OpTypePointer Output %4 +%87 = OpTypePointer Input %22 +%86 = OpVariable %87 Input +%90 = OpTypePointer Input %9 +%89 = OpVariable %90 Input +%93 = OpTypePointer Input %4 +%92 = OpVariable %93 Input +%96 = OpTypePointer Input %23 +%95 = OpVariable %96 Input +%99 = OpTypePointer Input %24 +%98 = OpVariable %99 Input +%101 = OpVariable %87 Input +%103 = OpVariable %93 Input +%105 = OpVariable %93 Input +%42 = OpFunction %2 None %43 +%28 = OpLabel +%26 = OpVariable %27 Function +OpBranch %44 +%44 = OpLabel +%46 = OpCompositeConstruct %22 %3 %5 %6 %7 +%49 = OpAccessChain %45 %26 %48 +OpStore %49 %46 +%52 = OpAccessChain %50 %26 %51 +OpStore %52 %8 +%55 = OpAccessChain %53 %26 %54 +OpStore %55 %10 +%57 = OpCompositeConstruct %23 %11 %12 +%59 = OpAccessChain %56 %26 %58 OpStore %59 %57 -%60 = OpCompositeConstruct %20 %16 %17 %18 %19 -%62 = OpAccessChain %41 %24 %61 -OpStore %62 %60 -%63 = OpLoad %23 %24 -%64 = OpCompositeExtract %20 %63 0 -OpStore %27 %64 -%65 = OpAccessChain %66 %27 %47 -%67 = OpLoad %4 %65 -%68 = OpFNegate %4 %67 -OpStore %65 %68 -%69 = OpCompositeExtract %9 %63 1 -OpStore %29 %69 -%70 = OpCompositeExtract %4 %63 2 -OpStore %31 %70 -%71 = OpCompositeExtract %21 %63 3 -OpStore %33 %71 -%72 = OpCompositeExtract %22 %63 4 -OpStore %35 %72 -%73 = OpCompositeExtract %20 %63 5 -OpStore %37 %73 +%61 = OpCompositeConstruct %24 %13 %14 %15 +%63 = OpAccessChain %60 %26 %62 +OpStore %63 %61 +%64 = OpCompositeConstruct %22 %16 %17 %18 %19 +%66 = OpAccessChain %45 %26 %65 +OpStore %66 %64 +%68 = OpAccessChain %53 %26 %67 +OpStore %68 %20 +%70 = OpAccessChain %53 %26 %69 +OpStore %70 %21 +%71 = OpLoad %25 %26 +%72 = OpCompositeExtract %22 %71 0 +OpStore %29 %72 +%73 = OpAccessChain %74 %29 %51 +%75 = OpLoad %4 %73 +%76 = OpFNegate %4 %75 +OpStore %73 %76 +%77 = OpCompositeExtract %9 %71 1 +OpStore %31 %77 +%78 = OpCompositeExtract %4 %71 2 +OpStore %33 %78 +%79 = OpCompositeExtract %23 %71 3 +OpStore %35 %79 +%80 = OpCompositeExtract %24 %71 4 +OpStore %37 %80 +%81 = OpCompositeExtract %22 %71 5 +OpStore %39 %81 +%82 = OpCompositeExtract %4 %71 6 +OpStore %40 %82 +%83 = OpCompositeExtract %4 %71 7 +OpStore %41 %83 OpReturn OpFunctionEnd -%93 = OpFunction %2 None %39 -%74 = OpLabel -%78 = OpLoad %20 %76 -%81 = OpLoad %9 %79 -%84 = OpLoad %4 %82 -%87 = OpLoad %21 %85 -%90 = OpLoad %22 %88 -%92 = OpLoad %20 %91 -%75 = OpCompositeConstruct %23 %78 %81 %84 %87 %90 %92 -OpBranch %94 -%94 = OpLabel +%107 = OpFunction %2 None %43 +%84 = OpLabel +%88 = OpLoad %22 %86 +%91 = OpLoad %9 %89 +%94 = OpLoad %4 %92 +%97 = OpLoad %23 %95 +%100 = OpLoad %24 %98 +%102 = OpLoad %22 %101 +%104 = OpLoad %4 %103 +%106 = OpLoad %4 %105 +%85 = OpCompositeConstruct %25 %88 %91 %94 %97 %100 %102 %104 %106 +OpBranch %108 +%108 = OpLabel OpReturn OpFunctionEnd \ No newline at end of file diff --git a/tests/out/shadow.ron b/tests/out/shadow.ron index fe4976907a..8a4a267749 100644 --- a/tests/out/shadow.ron +++ b/tests/out/shadow.ron @@ -1520,6 +1520,7 @@ binding: Some(Location( location: 0, interpolation: Some(Perspective), + sampling: None, )), ), ( @@ -1528,6 +1529,7 @@ binding: Some(Location( location: 1, interpolation: Some(Perspective), + sampling: None, )), ), ], @@ -1536,6 +1538,7 @@ binding: Some(Location( location: 0, interpolation: None, + sampling: None, )), )), local_variables: [],