[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 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);
}
}
}
}

View File

@ -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",
}
}

View File

@ -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) => {

View File

@ -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)]

View File

@ -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)),

View File

@ -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<TypeQualifier>, Option<Handle<Type>>);
@ -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 {

View File

@ -220,6 +220,7 @@ struct Decoration {
matrix_stride: Option<NonZeroU32>,
matrix_major: Option<Majority>,
interpolation: Option<crate::Interpolation>,
sampling: Option<crate::Sampling>,
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<I: Iterator<Item = u32>> Parser<I> {
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;

View File

@ -44,13 +44,19 @@ pub fn map_interpolation(word: &str) -> Result<crate::Interpolation, Error<'_>>
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<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<'_>> {
use crate::StorageFormat as Sf;
Ok(match word {

View File

@ -112,11 +112,12 @@ pub enum Error<'a> {
ZeroSizeOrAlign,
#[error("not a composite type: {0:?}")]
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(
Option<u32>,
Option<crate::BuiltIn>,
Option<crate::Interpolation>,
Option<crate::Sampling>,
),
#[error("call to local `{0}(..)` can't be resolved")]
UnknownLocalFunction(&'a str),
@ -470,6 +471,7 @@ struct BindingParser {
location: Option<u32>,
built_in: Option<crate::BuiltIn>,
interpolation: Option<crate::Interpolation>,
sampling: Option<crate::Sampling>,
}
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<Option<crate::Binding>, 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,
)),
}
}

View File

@ -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<Interpolation> },
Location {
location: u32,
interpolation: Option<Interpolation>,
sampling: Option<Sampling>
},
}
/// Pipeline binding information for global resources.

View File

@ -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(_)

View File

@ -1,10 +1,12 @@
struct FragmentInput {
[[builtin(position)]] position: vec4<f32>;
[[location(0), interpolate(flat)]] flat : u32;
[[location(1), interpolate(linear)]] linear: f32;
[[location(2), interpolate(centroid)]] centroid: vec2<f32>;
[[location(3), interpolate(sample)]] sample: vec3<f32>;
[[location(4), interpolate(perspective)]] perspective: vec4<f32>;
[[location(1), interpolate(linear)]] linear : f32;
[[location(2), interpolate(linear,centroid)]] linear_centroid : vec2<f32>;
[[location(3), interpolate(linear,sample)]] linear_sample : vec3<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)]]
@ -14,9 +16,11 @@ fn main() -> FragmentInput {
out.position = vec4<f32>(2.0, 4.0, 5.0, 6.0);
out.flat = 8u32;
out.linear = 27.0;
out.centroid = vec2<f32>(64.0, 125.0);
out.sample = vec3<f32>(216.0, 343.0, 512.0);
out.linear_centroid = vec2<f32>(64.0, 125.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_centroid = 2197.0;
out.perspective_sample = 2744.0;
return out;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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: [],