[wgsl-in] Implement WGSL interpolate syntax from gpuweb PR #1605.

Fixes: #670
This commit is contained in:
Jim Blandy 2021-04-16 18:26:16 -07:00 committed by Dzmitry Malyshau
parent 99a9e1e78e
commit 0910af2718
17 changed files with 392 additions and 232 deletions

View File

@ -1,7 +1,7 @@
use super::{BackendResult, Error, Version, Writer}; use super::{BackendResult, Error, Version, Writer};
use crate::{ use crate::{
Binding, Bytes, Handle, ImageClass, ImageDimension, Interpolation, ScalarKind, ShaderStage, Binding, Bytes, Handle, ImageClass, ImageDimension, Interpolation, Sampling, ScalarKind,
StorageClass, StorageFormat, Type, TypeInner, ShaderStage, StorageClass, StorageFormat, Type, TypeInner,
}; };
use std::io::Write; use std::io::Write;
@ -289,16 +289,16 @@ impl<'a, W> Writer<'a, W> {
} }
_ => { _ => {
if let Some(&Binding::Location { if let Some(&Binding::Location {
interpolation: Some(interpolation), interpolation,
sampling,
.. ..
}) = binding { }) = binding {
match interpolation { if interpolation == Some(Interpolation::Linear) {
Interpolation::Linear => { self.features.request(Features::NOPERSPECTIVE_QUALIFIER);
self.features.request(Features::NOPERSPECTIVE_QUALIFIER) }
} if sampling == Some(Sampling::Sample) {
Interpolation::Sample => self.features.request(Features::SAMPLE_QUALIFIER), self.features.request(Features::SAMPLE_QUALIFIER);
_ => (), }
};
} }
} }
} }

View File

@ -48,9 +48,10 @@ use crate::{
valid::{FunctionInfo, ModuleInfo}, valid::{FunctionInfo, ModuleInfo},
Arena, ArraySize, BinaryOperator, Binding, BuiltIn, Bytes, ConservativeDepth, Constant, Arena, ArraySize, BinaryOperator, Binding, BuiltIn, Bytes, ConservativeDepth, Constant,
ConstantInner, DerivativeAxis, Expression, FastHashMap, Function, GlobalVariable, Handle, ConstantInner, DerivativeAxis, Expression, FastHashMap, Function, GlobalVariable, Handle,
ImageClass, Interpolation, LocalVariable, Module, RelationalFunction, ScalarKind, ScalarValue, ImageClass, Interpolation, LocalVariable, Module, RelationalFunction, Sampling, ScalarKind,
ShaderStage, Statement, StorageAccess, StorageClass, StorageFormat, StructMember, Type, ScalarValue, ShaderStage, Statement, StorageAccess, StorageClass, StorageFormat, StructMember,
TypeInner, UnaryOperator, Type, TypeInner, UnaryOperator,
}; };
use features::FeaturesManager; use features::FeaturesManager;
use std::{ use std::{
@ -232,8 +233,10 @@ impl IdGenerator {
/// Helper wrapper used to get a name for a varying /// Helper wrapper used to get a name for a varying
/// ///
/// Varying have different naming schemes depending on their binding: /// Varying have different naming schemes depending on their binding:
/// - Varyings with builtin bindings get the from [`glsl_built_in`](glsl_built_in) /// - 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 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> { struct VaryingName<'a> {
binding: &'a Binding, binding: &'a Binding,
stage: ShaderStage, stage: ShaderStage,
@ -793,16 +796,22 @@ impl<'a, W: Write> Writer<'a, W> {
} }
} }
_ => { _ => {
let (location, interpolation) = match binding { let (location, interpolation, sampling) = match binding {
Some(&Binding::Location { location, interpolation }) => (location, interpolation), Some(&Binding::Location { location, interpolation, sampling }) => (location, interpolation, sampling),
_ => return Ok(()), _ => return Ok(()),
}; };
// Write the interpolation modifier if needed // Write the interpolation modifier if needed
// //
// We ignore all interpolation modifiers that aren't used in input globals in fragment // We ignore all interpolation and auxiliary modifiers that aren't used in fragment
// shaders or output globals in vertex shaders // 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 let Some(interp) = interpolation {
if self.options.shader_stage == ShaderStage::Fragment { if emit_interpolation_and_auxiliary {
write!(self.out, "{} ", glsl_interpolation(interp))?; write!(self.out, "{} ", glsl_interpolation(interp))?;
} }
} }
@ -811,13 +820,24 @@ impl<'a, W: Write> Writer<'a, W> {
if self.options.version.supports_explicit_locations() { if self.options.version.supports_explicit_locations() {
write!( write!(
self.out, self.out,
"layout(location = {}) {} ", "layout(location = {}) ",
location, location)?;
if output { "out" } else { "in" }
)?;
} else {
write!(self.out, "{} ", if output { "out" } else { "in" })?;
} }
// 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 the type
// `write_type` adds no leading or trailing spaces // `write_type` adds no leading or trailing spaces
self.write_type(ty)?; 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 // Finally write the global name and end the global with a `;` and a newline
// Leading space is important // Leading space is important
let vname = VaryingName { let vname = VaryingName {
binding: &Binding::Location { location, interpolation: None }, binding: &Binding::Location { location, interpolation: None, sampling: None },
stage: self.entry_point.stage, stage: self.entry_point.stage,
output, output,
}; };
@ -2201,8 +2221,15 @@ fn glsl_interpolation(interpolation: Interpolation) -> &'static str {
Interpolation::Perspective => "smooth", Interpolation::Perspective => "smooth",
Interpolation::Linear => "noperspective", Interpolation::Linear => "noperspective",
Interpolation::Flat => "flat", 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",
} }
} }

View File

@ -1090,17 +1090,29 @@ impl Writer {
use spirv::{BuiltIn, Decoration}; use spirv::{BuiltIn, Decoration};
match *binding { match *binding {
crate::Binding::Location { location, interpolation } => { crate::Binding::Location { location, interpolation, sampling } => {
self.decorate(id, Decoration::Location, &[location]); self.decorate(id, Decoration::Location, &[location]);
let interp_decoration = match interpolation {
Some(crate::Interpolation::Linear) => Some(Decoration::NoPerspective), match interpolation {
Some(crate::Interpolation::Flat) => Some(Decoration::Flat), // Perspective-correct interpolation is the default in SPIR-V.
Some(crate::Interpolation::Centroid) => Some(Decoration::Centroid), None | Some(crate::Interpolation::Perspective) => (),
Some(crate::Interpolation::Sample) => Some(Decoration::Sample), Some(crate::Interpolation::Flat) => {
Some(crate::Interpolation::Perspective) | None => None, self.decorate(id, Decoration::Flat, &[]);
}; }
if let Some(decoration) = interp_decoration { Some(crate::Interpolation::Linear) => {
self.decorate(id, decoration, &[]); 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) => { crate::Binding::BuiltIn(built_in) => {

View File

@ -2,7 +2,8 @@ use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind};
use crate::{ use crate::{
proc::ResolveContext, Arena, BinaryOperator, Binding, Constant, Expression, FastHashMap, proc::ResolveContext, Arena, BinaryOperator, Binding, Constant, Expression, FastHashMap,
Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, Module, Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, Module,
RelationalFunction, ResourceBinding, ShaderStage, Statement, StorageClass, Type, UnaryOperator, RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, Type,
UnaryOperator,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -226,6 +227,7 @@ pub enum TypeQualifier {
ResourceBinding(ResourceBinding), ResourceBinding(ResourceBinding),
Binding(Binding), Binding(Binding),
Interpolation(Interpolation), Interpolation(Interpolation),
Sampling(Sampling),
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -66,8 +66,8 @@ impl<'a> Iterator for Lexer<'a> {
"flat" => Token::Interpolation((meta, crate::Interpolation::Flat)), "flat" => Token::Interpolation((meta, crate::Interpolation::Flat)),
"noperspective" => Token::Interpolation((meta, crate::Interpolation::Linear)), "noperspective" => Token::Interpolation((meta, crate::Interpolation::Linear)),
"smooth" => Token::Interpolation((meta, crate::Interpolation::Perspective)), "smooth" => Token::Interpolation((meta, crate::Interpolation::Perspective)),
"centroid" => Token::Interpolation((meta, crate::Interpolation::Centroid)), "centroid" => Token::Sampling((meta, crate::Sampling::Centroid)),
"sample" => Token::Interpolation((meta, crate::Interpolation::Sample)), "sample" => Token::Sampling((meta, crate::Sampling::Sample)),
// values // values
"true" => Token::BoolConstant((meta, true)), "true" => Token::BoolConstant((meta, true)),
"false" => Token::BoolConstant((meta, false)), "false" => Token::BoolConstant((meta, false)),

View File

@ -10,7 +10,7 @@ pomelo! {
ConstantInner, Expression, ConstantInner, Expression,
Function, FunctionArgument, FunctionResult, Function, FunctionArgument, FunctionResult,
GlobalVariable, Handle, Interpolation, GlobalVariable, Handle, Interpolation,
LocalVariable, ResourceBinding, ScalarValue, ScalarKind, LocalVariable, ResourceBinding, Sampling, ScalarValue, ScalarKind,
Statement, StorageAccess, StorageClass, StructMember, Statement, StorageAccess, StorageClass, StructMember,
SwitchCase, Type, TypeInner, UnaryOperator, SwitchCase, Type, TypeInner, UnaryOperator,
}; };
@ -120,6 +120,8 @@ pomelo! {
%type storage_qualifier StorageQualifier; %type storage_qualifier StorageQualifier;
%type interpolation_qualifier Interpolation; %type interpolation_qualifier Interpolation;
%type Interpolation Interpolation; %type Interpolation Interpolation;
%type sampling_qualifier Sampling;
%type Sampling Sampling;
// types // types
%type fully_specified_type (Vec<TypeQualifier>, Option<Handle<Type>>); %type fully_specified_type (Vec<TypeQualifier>, Option<Handle<Type>>);
@ -613,10 +615,15 @@ pomelo! {
i i
} }
sampling_qualifier ::= Sampling((_, s)) {
s
}
layout_qualifier ::= Layout LeftParen layout_qualifier_id_list(l) RightParen { layout_qualifier ::= Layout LeftParen layout_qualifier_id_list(l) RightParen {
if let Some(&(_, location)) = l.iter().find(|&q| q.0.as_str() == "location") { if let Some(&(_, location)) = l.iter().find(|&q| q.0.as_str() == "location") {
let interpolation = None; //TODO 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") { } 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") { let group = if let Some(&(_, set)) = l.iter().find(|&q| q.0.as_str() == "set") {
set set
@ -670,6 +677,9 @@ pomelo! {
single_type_qualifier ::= interpolation_qualifier(i) { single_type_qualifier ::= interpolation_qualifier(i) {
TypeQualifier::Interpolation(i) TypeQualifier::Interpolation(i)
} }
single_type_qualifier ::= sampling_qualifier(i) {
TypeQualifier::Sampling(i)
}
// single_type_qualifier ::= invariant_qualifier; // single_type_qualifier ::= invariant_qualifier;
// single_type_qualifier ::= precise_qualifier; // single_type_qualifier ::= precise_qualifier;
@ -1133,8 +1143,16 @@ pomelo! {
let interpolation = d.type_qualifiers.iter().find_map(|tq| { let interpolation = d.type_qualifiers.iter().find_map(|tq| {
if let TypeQualifier::Interpolation(interp) = *tq { Some(interp) } else { None } 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; *interp = interpolation;
*samp = sampling;
} }
for (id, _initializer) in d.ids_initializers { for (id, _initializer) in d.ids_initializers {

View File

@ -220,6 +220,7 @@ struct Decoration {
matrix_stride: Option<NonZeroU32>, matrix_stride: Option<NonZeroU32>,
matrix_major: Option<Majority>, matrix_major: Option<Majority>,
interpolation: Option<crate::Interpolation>, interpolation: Option<crate::Interpolation>,
sampling: Option<crate::Sampling>,
flags: DecorationFlags, flags: DecorationFlags,
} }
@ -253,8 +254,9 @@ impl Decoration {
built_in: None, built_in: None,
location: Some(location), location: Some(location),
interpolation, interpolation,
sampling,
.. ..
} => Ok(crate::Binding::Location { location, interpolation }), } => Ok(crate::Binding::Location { location, interpolation, sampling }),
_ => Err(Error::MissingDecoration(spirv::Decoration::Location)), _ => Err(Error::MissingDecoration(spirv::Decoration::Location)),
} }
} }
@ -504,10 +506,10 @@ impl<I: Iterator<Item = u32>> Parser<I> {
dec.interpolation = Some(crate::Interpolation::Flat); dec.interpolation = Some(crate::Interpolation::Flat);
} }
spirv::Decoration::Centroid => { spirv::Decoration::Centroid => {
dec.interpolation = Some(crate::Interpolation::Centroid); dec.sampling = Some(crate::Sampling::Centroid);
} }
spirv::Decoration::Sample => { spirv::Decoration::Sample => {
dec.interpolation = Some(crate::Interpolation::Sample); dec.sampling = Some(crate::Sampling::Sample);
} }
spirv::Decoration::NonReadable => { spirv::Decoration::NonReadable => {
dec.flags |= DecorationFlags::NON_READABLE; dec.flags |= DecorationFlags::NON_READABLE;

View File

@ -44,13 +44,19 @@ pub fn map_interpolation(word: &str) -> Result<crate::Interpolation, Error<'_>>
match word { match word {
"linear" => Ok(crate::Interpolation::Linear), "linear" => Ok(crate::Interpolation::Linear),
"flat" => Ok(crate::Interpolation::Flat), "flat" => Ok(crate::Interpolation::Flat),
"centroid" => Ok(crate::Interpolation::Centroid),
"sample" => Ok(crate::Interpolation::Sample),
"perspective" => Ok(crate::Interpolation::Perspective), "perspective" => Ok(crate::Interpolation::Perspective),
_ => Err(Error::UnknownAttribute(word)), _ => Err(Error::UnknownAttribute(word)),
} }
} }
pub fn map_sampling(word: &str) -> Result<crate::Sampling, Error<'_>> {
match word {
"centroid" => Ok(crate::Sampling::Centroid),
"sample" => Ok(crate::Sampling::Sample),
_ => Err(Error::UnknownAttribute(word)),
}
}
pub fn map_storage_format(word: &str) -> Result<crate::StorageFormat, Error<'_>> { pub fn map_storage_format(word: &str) -> Result<crate::StorageFormat, Error<'_>> {
use crate::StorageFormat as Sf; use crate::StorageFormat as Sf;
Ok(match word { Ok(match word {

View File

@ -112,11 +112,12 @@ pub enum Error<'a> {
ZeroSizeOrAlign, ZeroSizeOrAlign,
#[error("not a composite type: {0:?}")] #[error("not a composite type: {0:?}")]
NotCompositeType(Handle<crate::Type>), NotCompositeType(Handle<crate::Type>),
#[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( InconsistentBinding(
Option<u32>, Option<u32>,
Option<crate::BuiltIn>, Option<crate::BuiltIn>,
Option<crate::Interpolation>, Option<crate::Interpolation>,
Option<crate::Sampling>,
), ),
#[error("call to local `{0}(..)` can't be resolved")] #[error("call to local `{0}(..)` can't be resolved")]
UnknownLocalFunction(&'a str), UnknownLocalFunction(&'a str),
@ -470,6 +471,7 @@ struct BindingParser {
location: Option<u32>, location: Option<u32>,
built_in: Option<crate::BuiltIn>, built_in: Option<crate::BuiltIn>,
interpolation: Option<crate::Interpolation>, interpolation: Option<crate::Interpolation>,
sampling: Option<crate::Sampling>,
} }
impl BindingParser { impl BindingParser {
@ -490,6 +492,10 @@ impl BindingParser {
lexer.expect(Token::Paren('('))?; lexer.expect(Token::Paren('('))?;
let raw = lexer.next_ident()?; let raw = lexer.next_ident()?;
self.interpolation = Some(conv::map_interpolation(raw)?); 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(')'))?; lexer.expect(Token::Paren(')'))?;
} }
_ => return Err(Error::UnknownAttribute(name)), _ => return Err(Error::UnknownAttribute(name)),
@ -498,16 +504,17 @@ impl BindingParser {
} }
fn finish<'a>(self) -> Result<Option<crate::Binding>, Error<'a>> { fn finish<'a>(self) -> Result<Option<crate::Binding>, Error<'a>> {
match (self.location, self.built_in, self.interpolation) { match (self.location, self.built_in, self.interpolation, self.sampling) {
(None, None, None) => Ok(None), (None, None, None, None) => Ok(None),
(Some(location), None, interpolation) => { (Some(location), None, interpolation, sampling) => {
Ok(Some(crate::Binding::Location { location, interpolation })) Ok(Some(crate::Binding::Location { location, interpolation, sampling }))
} }
(None, Some(bi), None) => Ok(Some(crate::Binding::BuiltIn(bi))), (None, Some(bi), None, None) => Ok(Some(crate::Binding::BuiltIn(bi))),
(location, built_in, interpolation) => Err(Error::InconsistentBinding( (location, built_in, interpolation, sampling) => Err(Error::InconsistentBinding(
location, location,
built_in, built_in,
interpolation, interpolation,
sampling,
)), )),
} }
} }

View File

@ -226,11 +226,23 @@ pub enum Interpolation {
Linear, Linear,
/// Indicates that no interpolation will be performed. /// Indicates that no interpolation will be performed.
Flat, 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, 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, Sample,
} }
@ -465,7 +477,11 @@ pub enum Binding {
/// Built-in shader variable. /// Built-in shader variable.
BuiltIn(BuiltIn), BuiltIn(BuiltIn),
/// Indexed location. /// Indexed location.
Location { location: u32, interpolation: Option<Interpolation> }, Location {
location: u32,
interpolation: Option<Interpolation>,
sampling: Option<Sampling>
},
} }
/// Pipeline binding information for global resources. /// Pipeline binding information for global resources.

View File

@ -206,7 +206,7 @@ impl VaryingContext<'_> {
return Err(VaryingError::InvalidBuiltInType(built_in)); 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) { if !self.location_mask.insert(location as usize) {
return Err(VaryingError::BindingCollision { location }); return Err(VaryingError::BindingCollision { location });
} }
@ -218,6 +218,11 @@ impl VaryingContext<'_> {
if !needs_interpolation && interpolation.is_some() { if !needs_interpolation && interpolation.is_some() {
return Err(VaryingError::InvalidInterpolation); 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() { match ty_inner.scalar_kind() {
Some(crate::ScalarKind::Float) => {} Some(crate::ScalarKind::Float) => {}
Some(_) Some(_)

View File

@ -1,10 +1,12 @@
struct FragmentInput { struct FragmentInput {
[[builtin(position)]] position: vec4<f32>; [[builtin(position)]] position: vec4<f32>;
[[location(0), interpolate(flat)]] flat : u32; [[location(0), interpolate(flat)]] flat : u32;
[[location(1), interpolate(linear)]] linear: f32; [[location(1), interpolate(linear)]] linear : f32;
[[location(2), interpolate(centroid)]] centroid: vec2<f32>; [[location(2), interpolate(linear,centroid)]] linear_centroid : vec2<f32>;
[[location(3), interpolate(sample)]] sample: vec3<f32>; [[location(3), interpolate(linear,sample)]] linear_sample : vec3<f32>;
[[location(4), interpolate(perspective)]] perspective: vec4<f32>; [[location(4), interpolate(perspective)]] perspective : vec4<f32>;
[[location(5), interpolate(perspective,centroid)]] perspective_centroid : f32;
[[location(6), interpolate(perspective,sample)]] perspective_sample : f32;
}; };
[[stage(vertex)]] [[stage(vertex)]]
@ -14,9 +16,11 @@ fn main() -> FragmentInput {
out.position = vec4<f32>(2.0, 4.0, 5.0, 6.0); out.position = vec4<f32>(2.0, 4.0, 5.0, 6.0);
out.flat = 8u32; out.flat = 8u32;
out.linear = 27.0; out.linear = 27.0;
out.centroid = vec2<f32>(64.0, 125.0); out.linear_centroid = vec2<f32>(64.0, 125.0);
out.sample = vec3<f32>(216.0, 343.0, 512.0); out.linear_sample = vec3<f32>(216.0, 343.0, 512.0);
out.perspective = vec4<f32>(729.0, 1000.0, 1331.0, 1728.0); out.perspective = vec4<f32>(729.0, 1000.0, 1331.0, 1728.0);
out.perspective_centroid = 2197.0;
out.perspective_sample = 2744.0;
return out; return out;
} }

View File

@ -3,19 +3,23 @@ struct FragmentInput {
vec4 position; vec4 position;
uint flat1; uint flat1;
float linear; float linear;
vec2 centroid1; vec2 linear_centroid;
vec3 sample1; vec3 linear_sample;
vec4 perspective; vec4 perspective;
float perspective_centroid;
float perspective_sample;
}; };
flat in uint _vs2fs_location0; flat in uint _vs2fs_location0;
noperspective in float _vs2fs_location1; noperspective in float _vs2fs_location1;
centroid in vec2 _vs2fs_location2; noperspective centroid in vec2 _vs2fs_location2;
sample in vec3 _vs2fs_location3; noperspective sample in vec3 _vs2fs_location3;
smooth in vec4 _vs2fs_location4; smooth in vec4 _vs2fs_location4;
smooth centroid in float _vs2fs_location5;
smooth sample in float _vs2fs_location6;
void main() { 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; return;
} }

View File

@ -3,31 +3,39 @@ struct FragmentInput {
vec4 position; vec4 position;
uint flat1; uint flat1;
float linear; float linear;
vec2 centroid1; vec2 linear_centroid;
vec3 sample1; vec3 linear_sample;
vec4 perspective; vec4 perspective;
float perspective_centroid;
float perspective_sample;
}; };
out uint _vs2fs_location0; flat out uint _vs2fs_location0;
out float _vs2fs_location1; noperspective out float _vs2fs_location1;
out vec2 _vs2fs_location2; noperspective centroid out vec2 _vs2fs_location2;
out vec3 _vs2fs_location3; noperspective sample out vec3 _vs2fs_location3;
out vec4 _vs2fs_location4; smooth out vec4 _vs2fs_location4;
smooth centroid out float _vs2fs_location5;
smooth sample out float _vs2fs_location6;
void main() { void main() {
FragmentInput out1; FragmentInput out1;
out1.position = vec4(2.0, 4.0, 5.0, 6.0); out1.position = vec4(2.0, 4.0, 5.0, 6.0);
out1.flat1 = 8u; out1.flat1 = 8u;
out1.linear = 27.0; out1.linear = 27.0;
out1.centroid1 = vec2(64.0, 125.0); out1.linear_centroid = vec2(64.0, 125.0);
out1.sample1 = vec3(216.0, 343.0, 512.0); out1.linear_sample = vec3(216.0, 343.0, 512.0);
out1.perspective = vec4(729.0, 1000.0, 1331.0, 1728.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; gl_Position = out1.position;
_vs2fs_location0 = out1.flat1; _vs2fs_location0 = out1.flat1;
_vs2fs_location1 = out1.linear; _vs2fs_location1 = out1.linear;
_vs2fs_location2 = out1.centroid1; _vs2fs_location2 = out1.linear_centroid;
_vs2fs_location3 = out1.sample1; _vs2fs_location3 = out1.linear_sample;
_vs2fs_location4 = out1.perspective; _vs2fs_location4 = out1.perspective;
_vs2fs_location5 = out1.perspective_centroid;
_vs2fs_location6 = out1.perspective_sample;
return; return;
} }

View File

@ -5,18 +5,22 @@ struct FragmentInput {
metal::float4 position; metal::float4 position;
metal::uint flat; metal::uint flat;
float linear; float linear;
metal::float2 centroid; metal::float2 linear_centroid;
metal::float3 sample; metal::float3 linear_sample;
metal::float4 perspective; metal::float4 perspective;
float perspective_centroid;
float perspective_sample;
}; };
struct main1Output { struct main1Output {
metal::float4 position [[position]]; metal::float4 position [[position]];
metal::uint flat [[user(loc0)]]; metal::uint flat [[user(loc0)]];
float linear [[user(loc1)]]; float linear [[user(loc1)]];
metal::float2 centroid [[user(loc2)]]; metal::float2 linear_centroid [[user(loc2)]];
metal::float3 sample [[user(loc3)]]; metal::float3 linear_sample [[user(loc3)]];
metal::float4 perspective [[user(loc4)]]; metal::float4 perspective [[user(loc4)]];
float perspective_centroid [[user(loc5)]];
float perspective_sample [[user(loc6)]];
}; };
vertex main1Output main1( vertex main1Output main1(
) { ) {
@ -24,25 +28,29 @@ vertex main1Output main1(
out.position = metal::float4(2.0, 4.0, 5.0, 6.0); out.position = metal::float4(2.0, 4.0, 5.0, 6.0);
out.flat = 8u; out.flat = 8u;
out.linear = 27.0; out.linear = 27.0;
out.centroid = metal::float2(64.0, 125.0); out.linear_centroid = metal::float2(64.0, 125.0);
out.sample = metal::float3(216.0, 343.0, 512.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 = metal::float4(729.0, 1000.0, 1331.0, 1728.0);
out.perspective_centroid = 2197.0;
out.perspective_sample = 2744.0;
const auto _tmp = out; 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 { struct main2Input {
metal::uint flat [[user(loc0)]]; metal::uint flat [[user(loc0)]];
float linear [[user(loc1)]]; float linear [[user(loc1)]];
metal::float2 centroid [[user(loc2)]]; metal::float2 linear_centroid [[user(loc2)]];
metal::float3 sample [[user(loc3)]]; metal::float3 linear_sample [[user(loc3)]];
metal::float4 perspective [[user(loc4)]]; metal::float4 perspective [[user(loc4)]];
float perspective_centroid [[user(loc5)]];
float perspective_sample [[user(loc6)]];
}; };
fragment void main2( fragment void main2(
main2Input varyings1 [[stage_in]] main2Input varyings1 [[stage_in]]
, metal::float4 position [[position]] , 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; return;
} }

View File

@ -1,63 +1,83 @@
; SPIR-V ; SPIR-V
; Version: 1.0 ; Version: 1.0
; Generator: rspirv ; Generator: rspirv
; Bound: 95 ; Bound: 109
OpCapability Shader OpCapability Shader
OpCapability SampleRateShading OpCapability SampleRateShading
%1 = OpExtInstImport "GLSL.std.450" %1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450 OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %38 "main" %27 %29 %31 %33 %35 %37 OpEntryPoint Vertex %42 "main" %29 %31 %33 %35 %37 %39 %40 %41
OpEntryPoint Fragment %93 "main" %76 %79 %82 %85 %88 %91 OpEntryPoint Fragment %107 "main" %86 %89 %92 %95 %98 %101 %103 %105
OpExecutionMode %93 OriginUpperLeft OpExecutionMode %107 OriginUpperLeft
OpSource GLSL 450 OpSource GLSL 450
OpName %23 "FragmentInput" OpName %25 "FragmentInput"
OpMemberName %23 0 "position" OpMemberName %25 0 "position"
OpMemberName %23 1 "flat" OpMemberName %25 1 "flat"
OpMemberName %23 2 "linear" OpMemberName %25 2 "linear"
OpMemberName %23 3 "centroid" OpMemberName %25 3 "linear_centroid"
OpMemberName %23 4 "sample" OpMemberName %25 4 "linear_sample"
OpMemberName %23 5 "perspective" OpMemberName %25 5 "perspective"
OpName %24 "out" OpMemberName %25 6 "perspective_centroid"
OpName %27 "position" OpMemberName %25 7 "perspective_sample"
OpName %29 "flat" OpName %26 "out"
OpName %31 "linear" OpName %29 "position"
OpName %33 "centroid" OpName %31 "flat"
OpName %35 "sample" OpName %33 "linear"
OpName %37 "perspective" OpName %35 "linear_centroid"
OpName %38 "main" OpName %37 "linear_sample"
OpName %76 "position" OpName %39 "perspective"
OpName %79 "flat" OpName %40 "perspective_centroid"
OpName %82 "linear" OpName %41 "perspective_sample"
OpName %85 "centroid" OpName %42 "main"
OpName %88 "sample" OpName %86 "position"
OpName %91 "perspective" OpName %89 "flat"
OpName %93 "main" OpName %92 "linear"
OpMemberDecorate %23 0 Offset 0 OpName %95 "linear_centroid"
OpMemberDecorate %23 1 Offset 16 OpName %98 "linear_sample"
OpMemberDecorate %23 2 Offset 20 OpName %101 "perspective"
OpMemberDecorate %23 3 Offset 24 OpName %103 "perspective_centroid"
OpMemberDecorate %23 4 Offset 32 OpName %105 "perspective_sample"
OpMemberDecorate %23 5 Offset 48 OpName %107 "main"
OpDecorate %27 BuiltIn Position OpMemberDecorate %25 0 Offset 0
OpDecorate %29 Location 0 OpMemberDecorate %25 1 Offset 16
OpDecorate %29 Flat OpMemberDecorate %25 2 Offset 20
OpDecorate %31 Location 1 OpMemberDecorate %25 3 Offset 24
OpDecorate %31 NoPerspective OpMemberDecorate %25 4 Offset 32
OpDecorate %33 Location 2 OpMemberDecorate %25 5 Offset 48
OpDecorate %33 Centroid OpMemberDecorate %25 6 Offset 64
OpDecorate %35 Location 3 OpMemberDecorate %25 7 Offset 68
OpDecorate %35 Sample OpDecorate %29 BuiltIn Position
OpDecorate %37 Location 4 OpDecorate %31 Location 0
OpDecorate %76 BuiltIn FragCoord OpDecorate %31 Flat
OpDecorate %79 Location 0 OpDecorate %33 Location 1
OpDecorate %79 Flat OpDecorate %33 NoPerspective
OpDecorate %82 Location 1 OpDecorate %35 Location 2
OpDecorate %82 NoPerspective OpDecorate %35 NoPerspective
OpDecorate %85 Location 2 OpDecorate %35 Centroid
OpDecorate %85 Centroid OpDecorate %37 Location 3
OpDecorate %88 Location 3 OpDecorate %37 NoPerspective
OpDecorate %88 Sample OpDecorate %37 Sample
OpDecorate %91 Location 4 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 %2 = OpTypeVoid
%4 = OpTypeFloat 32 %4 = OpTypeFloat 32
%3 = OpConstant %4 2.0 %3 = OpConstant %4 2.0
@ -76,97 +96,115 @@ OpDecorate %91 Location 4
%17 = OpConstant %4 1000.0 %17 = OpConstant %4 1000.0
%18 = OpConstant %4 1331.0 %18 = OpConstant %4 1331.0
%19 = OpConstant %4 1728.0 %19 = OpConstant %4 1728.0
%20 = OpTypeVector %4 4 %20 = OpConstant %4 2197.0
%21 = OpTypeVector %4 2 %21 = OpConstant %4 2744.0
%22 = OpTypeVector %4 3 %22 = OpTypeVector %4 4
%23 = OpTypeStruct %20 %9 %4 %21 %22 %20 %23 = OpTypeVector %4 2
%25 = OpTypePointer Function %23 %24 = OpTypeVector %4 3
%28 = OpTypePointer Output %20 %25 = OpTypeStruct %22 %9 %4 %23 %24 %22 %4 %4
%27 = OpVariable %28 Output %27 = OpTypePointer Function %25
%30 = OpTypePointer Output %9 %30 = OpTypePointer Output %22
%29 = OpVariable %30 Output %29 = OpVariable %30 Output
%32 = OpTypePointer Output %4 %32 = OpTypePointer Output %9
%31 = OpVariable %32 Output %31 = OpVariable %32 Output
%34 = OpTypePointer Output %21 %34 = OpTypePointer Output %4
%33 = OpVariable %34 Output %33 = OpVariable %34 Output
%36 = OpTypePointer Output %22 %36 = OpTypePointer Output %23
%35 = OpVariable %36 Output %35 = OpVariable %36 Output
%37 = OpVariable %28 Output %38 = OpTypePointer Output %24
%39 = OpTypeFunction %2 %37 = OpVariable %38 Output
%41 = OpTypePointer Function %20 %39 = OpVariable %30 Output
%43 = OpTypeInt 32 1 %40 = OpVariable %34 Output
%44 = OpConstant %43 0 %41 = OpVariable %34 Output
%46 = OpTypePointer Function %9 %43 = OpTypeFunction %2
%47 = OpConstant %43 1 %45 = OpTypePointer Function %22
%49 = OpTypePointer Function %4 %47 = OpTypeInt 32 1
%50 = OpConstant %43 2 %48 = OpConstant %47 0
%52 = OpTypePointer Function %21 %50 = OpTypePointer Function %9
%54 = OpConstant %43 3 %51 = OpConstant %47 1
%56 = OpTypePointer Function %22 %53 = OpTypePointer Function %4
%58 = OpConstant %43 4 %54 = OpConstant %47 2
%61 = OpConstant %43 5 %56 = OpTypePointer Function %23
%66 = OpTypePointer Output %4 %58 = OpConstant %47 3
%77 = OpTypePointer Input %20 %60 = OpTypePointer Function %24
%76 = OpVariable %77 Input %62 = OpConstant %47 4
%80 = OpTypePointer Input %9 %65 = OpConstant %47 5
%79 = OpVariable %80 Input %67 = OpConstant %47 6
%83 = OpTypePointer Input %4 %69 = OpConstant %47 7
%82 = OpVariable %83 Input %74 = OpTypePointer Output %4
%86 = OpTypePointer Input %21 %87 = OpTypePointer Input %22
%85 = OpVariable %86 Input %86 = OpVariable %87 Input
%89 = OpTypePointer Input %22 %90 = OpTypePointer Input %9
%88 = OpVariable %89 Input %89 = OpVariable %90 Input
%91 = OpVariable %77 Input %93 = OpTypePointer Input %4
%38 = OpFunction %2 None %39 %92 = OpVariable %93 Input
%26 = OpLabel %96 = OpTypePointer Input %23
%24 = OpVariable %25 Function %95 = OpVariable %96 Input
OpBranch %40 %99 = OpTypePointer Input %24
%40 = OpLabel %98 = OpVariable %99 Input
%42 = OpCompositeConstruct %20 %3 %5 %6 %7 %101 = OpVariable %87 Input
%45 = OpAccessChain %41 %24 %44 %103 = OpVariable %93 Input
OpStore %45 %42 %105 = OpVariable %93 Input
%48 = OpAccessChain %46 %24 %47 %42 = OpFunction %2 None %43
OpStore %48 %8 %28 = OpLabel
%51 = OpAccessChain %49 %24 %50 %26 = OpVariable %27 Function
OpStore %51 %10 OpBranch %44
%53 = OpCompositeConstruct %21 %11 %12 %44 = OpLabel
%55 = OpAccessChain %52 %24 %54 %46 = OpCompositeConstruct %22 %3 %5 %6 %7
OpStore %55 %53 %49 = OpAccessChain %45 %26 %48
%57 = OpCompositeConstruct %22 %13 %14 %15 OpStore %49 %46
%59 = OpAccessChain %56 %24 %58 %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 OpStore %59 %57
%60 = OpCompositeConstruct %20 %16 %17 %18 %19 %61 = OpCompositeConstruct %24 %13 %14 %15
%62 = OpAccessChain %41 %24 %61 %63 = OpAccessChain %60 %26 %62
OpStore %62 %60 OpStore %63 %61
%63 = OpLoad %23 %24 %64 = OpCompositeConstruct %22 %16 %17 %18 %19
%64 = OpCompositeExtract %20 %63 0 %66 = OpAccessChain %45 %26 %65
OpStore %27 %64 OpStore %66 %64
%65 = OpAccessChain %66 %27 %47 %68 = OpAccessChain %53 %26 %67
%67 = OpLoad %4 %65 OpStore %68 %20
%68 = OpFNegate %4 %67 %70 = OpAccessChain %53 %26 %69
OpStore %65 %68 OpStore %70 %21
%69 = OpCompositeExtract %9 %63 1 %71 = OpLoad %25 %26
OpStore %29 %69 %72 = OpCompositeExtract %22 %71 0
%70 = OpCompositeExtract %4 %63 2 OpStore %29 %72
OpStore %31 %70 %73 = OpAccessChain %74 %29 %51
%71 = OpCompositeExtract %21 %63 3 %75 = OpLoad %4 %73
OpStore %33 %71 %76 = OpFNegate %4 %75
%72 = OpCompositeExtract %22 %63 4 OpStore %73 %76
OpStore %35 %72 %77 = OpCompositeExtract %9 %71 1
%73 = OpCompositeExtract %20 %63 5 OpStore %31 %77
OpStore %37 %73 %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 OpReturn
OpFunctionEnd OpFunctionEnd
%93 = OpFunction %2 None %39 %107 = OpFunction %2 None %43
%74 = OpLabel %84 = OpLabel
%78 = OpLoad %20 %76 %88 = OpLoad %22 %86
%81 = OpLoad %9 %79 %91 = OpLoad %9 %89
%84 = OpLoad %4 %82 %94 = OpLoad %4 %92
%87 = OpLoad %21 %85 %97 = OpLoad %23 %95
%90 = OpLoad %22 %88 %100 = OpLoad %24 %98
%92 = OpLoad %20 %91 %102 = OpLoad %22 %101
%75 = OpCompositeConstruct %23 %78 %81 %84 %87 %90 %92 %104 = OpLoad %4 %103
OpBranch %94 %106 = OpLoad %4 %105
%94 = OpLabel %85 = OpCompositeConstruct %25 %88 %91 %94 %97 %100 %102 %104 %106
OpBranch %108
%108 = OpLabel
OpReturn OpReturn
OpFunctionEnd OpFunctionEnd

View File

@ -1520,6 +1520,7 @@
binding: Some(Location( binding: Some(Location(
location: 0, location: 0,
interpolation: Some(Perspective), interpolation: Some(Perspective),
sampling: None,
)), )),
), ),
( (
@ -1528,6 +1529,7 @@
binding: Some(Location( binding: Some(Location(
location: 1, location: 1,
interpolation: Some(Perspective), interpolation: Some(Perspective),
sampling: None,
)), )),
), ),
], ],
@ -1536,6 +1538,7 @@
binding: Some(Location( binding: Some(Location(
location: 0, location: 0,
interpolation: None, interpolation: None,
sampling: None,
)), )),
)), )),
local_variables: [], local_variables: [],