Swizzle expression (#734)

This commit is contained in:
Dzmitry Malyshau 2021-04-20 22:03:54 -04:00 committed by GitHub
parent b08dfe5146
commit 5d1746b0b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 547 additions and 368 deletions

View File

@ -187,6 +187,17 @@ fn write_fun(
edges.insert("value", value);
(Cow::Owned(format!("Splat{:?}", size)), 3)
}
E::Swizzle {
size,
vector,
pattern,
} => {
edges.insert("vector", vector);
(
Cow::Owned(format!("Swizzle{:?}", &pattern[..size as usize])),
3,
)
}
E::Compose { ref components, .. } => {
payload = Some(Payload::Arguments(components));
(Cow::Borrowed("Compose"), 3)

View File

@ -292,7 +292,8 @@ impl<'a, W> Writer<'a, W> {
interpolation,
sampling,
..
}) = binding {
}) = binding
{
if interpolation == Some(Interpolation::Linear) {
self.features.request(Features::NOPERSPECTIVE_QUALIFIER);
}

View File

@ -51,7 +51,6 @@ use crate::{
ImageClass, Interpolation, LocalVariable, Module, RelationalFunction, Sampling, ScalarKind,
ScalarValue, ShaderStage, Statement, StorageAccess, StorageClass, StorageFormat, StructMember,
Type, TypeInner, UnaryOperator,
};
use features::FeaturesManager;
use std::{
@ -72,6 +71,8 @@ pub const SUPPORTED_CORE_VERSIONS: &[u16] = &[330, 400, 410, 420, 430, 440, 450]
pub const SUPPORTED_ES_VERSIONS: &[u16] = &[300, 310, 320];
const INDENT: &str = " ";
const COMPONENTS: &[char] = &['x', 'y', 'z', 'w'];
/// glsl version
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Version {
@ -797,7 +798,11 @@ impl<'a, W: Write> Writer<'a, W> {
}
_ => {
let (location, interpolation, sampling) = match binding {
Some(&Binding::Location { location, interpolation, sampling }) => (location, interpolation, sampling),
Some(&Binding::Location {
location,
interpolation,
sampling,
}) => (location, interpolation, sampling),
_ => return Ok(()),
};
@ -818,10 +823,7 @@ impl<'a, W: Write> Writer<'a, W> {
// Write the storage class
if self.options.version.supports_explicit_locations() {
write!(
self.out,
"layout(location = {}) ",
location)?;
write!(self.out, "layout(location = {}) ", location)?;
}
// Write the sampling auxiliary qualifier.
@ -847,7 +849,11 @@ 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, sampling: None },
binding: &Binding::Location {
location,
interpolation: None,
sampling: None,
},
stage: self.entry_point.stage,
output,
};
@ -1507,6 +1513,18 @@ impl<'a, W: Write> Writer<'a, W> {
self.write_expr(value, ctx)?;
write!(self.out, ")")?
}
// `Swizzle` adds a few letters behind the dot.
Expression::Swizzle {
size,
vector,
pattern,
} => {
self.write_expr(vector, ctx)?;
write!(self.out, ".")?;
for &sc in pattern[..size as usize].iter() {
write!(self.out, "{}", COMPONENTS[sc as usize])?;
}
}
// `Compose` is pretty simple we just write `type(components)` where `components` is a
// comma separated list of expressions
Expression::Compose { ty, ref components } => {
@ -1728,14 +1746,13 @@ impl<'a, W: Write> Writer<'a, W> {
write!(self.out, ")",)?;
}
crate::ImageQuery::NumLayers => {
let selector = ['x', 'y', 'z', 'w'];
let fun_name = match class {
ImageClass::Sampled { .. } | ImageClass::Depth => "textureSize",
ImageClass::Storage(_) => "imageSize",
};
write!(self.out, "{}(", fun_name)?;
self.write_expr(image, ctx)?;
write!(self.out, ",0).{}", selector[components])?;
write!(self.out, ",0).{}", COMPONENTS[components])?;
}
crate::ImageQuery::NumSamples => {
// assumes ARB_shader_texture_image_samples

View File

@ -198,7 +198,11 @@ impl Options {
) -> Result<ResolvedBinding, Error> {
match *binding {
crate::Binding::BuiltIn(built_in) => Ok(ResolvedBinding::BuiltIn(built_in)),
crate::Binding::Location { location, interpolation, sampling } => match mode {
crate::Binding::Location {
location,
interpolation,
sampling,
} => match mode {
LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(location)),
LocationMode::FragmentOutput => Ok(ResolvedBinding::Color(location)),
LocationMode::Intermediate => Ok(ResolvedBinding::User {
@ -351,21 +355,18 @@ impl ResolvedBinding {
}
impl ResolvedInterpolation {
fn from_binding(interpolation: crate::Interpolation,
sampling: crate::Sampling)
-> Self
{
fn from_binding(interpolation: crate::Interpolation, sampling: crate::Sampling) -> Self {
use crate::Interpolation as I;
use crate::Sampling as S;
match (interpolation, sampling) {
(I::Perspective, S::Center) => Self::CenterPerspective,
(I::Perspective, S::Center) => Self::CenterPerspective,
(I::Perspective, S::Centroid) => Self::CentroidPerspective,
(I::Perspective, S::Sample) => Self::SamplePerspective,
(I::Linear, S::Center) => Self::CenterNoPerspective,
(I::Linear, S::Centroid) => Self::CentroidNoPerspective,
(I::Linear, S::Sample) => Self::SampleNoPerspective,
(I::Flat, _) => Self::Flat,
(I::Perspective, S::Sample) => Self::SamplePerspective,
(I::Linear, S::Center) => Self::CenterNoPerspective,
(I::Linear, S::Centroid) => Self::CentroidNoPerspective,
(I::Linear, S::Sample) => Self::SampleNoPerspective,
(I::Flat, _) => Self::Flat,
}
}

View File

@ -611,7 +611,7 @@ impl<W: Write> Writer<W> {
crate::Expression::Splat { size, value } => {
let scalar_kind = match *context.resolve_type(value) {
crate::TypeInner::Scalar { kind, .. } => kind,
_ => return Err(Error::Validation)
_ => return Err(Error::Validation),
};
let scalar = scalar_kind_string(scalar_kind);
let size = vector_size_string(size);
@ -620,6 +620,17 @@ impl<W: Write> Writer<W> {
self.put_expression(value, context, true)?;
write!(self.out, ")")?;
}
crate::Expression::Swizzle {
size,
vector,
pattern,
} => {
self.put_expression(vector, context, is_scoped)?;
write!(self.out, ".")?;
for &sc in pattern[..size as usize].iter() {
write!(self.out, "{}", COMPONENTS[sc as usize])?;
}
}
crate::Expression::Compose { ty, ref components } => {
let inner = &context.module.types[ty].inner;
match *inner {
@ -2168,8 +2179,8 @@ fn test_stack_size() {
}
let stack_size = addresses.end - addresses.start;
// check the size (in debug only)
// last observed macOS value: 20336
if stack_size < 19000 || stack_size > 21000 {
// last observed macOS value: 21584
if stack_size < 20000 || stack_size > 22000 {
panic!("`put_expression` stack size {} has changed!", stack_size);
}
}

View File

@ -659,6 +659,26 @@ impl super::Instruction {
instruction
}
pub(super) fn vector_shuffle(
result_type_id: Word,
id: Word,
v1_id: Word,
v2_id: Word,
components: &[Word],
) -> Self {
let mut instruction = Self::new(Op::VectorShuffle);
instruction.set_type(result_type_id);
instruction.set_result(id);
instruction.add_operand(v1_id);
instruction.add_operand(v2_id);
for &component in components {
instruction.add_operand(component);
}
instruction
}
//
// Arithmetic Instructions
//

View File

@ -418,7 +418,8 @@ impl Writer {
}
fn decorate(&mut self, id: Word, decoration: spirv::Decoration, operands: &[Word]) {
self.annotations.push(Instruction::decorate(id, decoration, operands));
self.annotations
.push(Instruction::decorate(id, decoration, operands));
}
fn write_function(
@ -1090,7 +1091,11 @@ impl Writer {
use spirv::{BuiltIn, Decoration};
match *binding {
crate::Binding::Location { location, interpolation, sampling } => {
crate::Binding::Location {
location,
interpolation,
sampling,
} => {
self.decorate(id, Decoration::Location, &[location]);
match interpolation {
@ -1459,6 +1464,26 @@ impl Writer {
));
id
}
crate::Expression::Swizzle {
size,
vector,
pattern,
} => {
let vector_id = self.cached[vector];
self.temp_list.clear();
for &sc in pattern[..size as usize].iter() {
self.temp_list.push(sc as Word);
}
let id = self.id_gen.next();
block.body.push(Instruction::vector_shuffle(
result_type_id,
id,
vector_id,
vector_id,
&self.temp_list,
));
id
}
crate::Expression::Compose {
ty: _,
ref components,

View File

@ -49,8 +49,8 @@ pub enum ConstantSolvingError {
InvalidUnaryOpArg,
#[error("Cannot apply the binary op to the arguments")]
InvalidBinaryOpArgs,
#[error("Splat type is not registered")]
SplatType,
#[error("Splat/swizzle type is not registered")]
DestinationTypeNotFound,
}
impl<'a> ConstantSolver<'a> {
@ -83,11 +83,52 @@ impl<'a> ConstantSolver<'a> {
name: None,
specialization: None,
inner: ConstantInner::Composite {
ty: ty.ok_or(ConstantSolvingError::SplatType)?,
//TODO: register the new type if needed
ty: ty.ok_or(ConstantSolvingError::DestinationTypeNotFound)?,
components: vec![tgt; size as usize],
},
}))
}
Expression::Swizzle {
size,
vector: src_vector,
pattern,
} => {
let tgt = self.solve(src_vector)?;
let (ty, src_components) = match self.constants[tgt].inner {
ConstantInner::Scalar { .. } => (None, &[][..]),
ConstantInner::Composite {
ty,
components: ref src_components,
} => match self.types[ty].inner {
crate::TypeInner::Vector {
size: _,
kind,
width,
} => {
let dst_ty = self.types.fetch_if(|t| {
t.inner == crate::TypeInner::Vector { size, kind, width }
});
(dst_ty, &src_components[..])
}
_ => (None, &[][..]),
},
};
let components = pattern
.iter()
.map(|&sc| src_components[sc as usize])
.collect();
Ok(self.constants.fetch_or_append(Constant {
name: None,
specialization: None,
inner: ConstantInner::Composite {
//TODO: register the new type if needed
ty: ty.ok_or(ConstantSolvingError::DestinationTypeNotFound)?,
components,
},
}))
}
Expression::Compose { ty, ref components } => {
let components = components
.iter()

View File

@ -216,7 +216,8 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
if let Some(crate::Binding::Location {
interpolation: ref mut interpolation @ None,
..
}) = arg.binding {
}) = arg.binding
{
*interpolation = Some(crate::Interpolation::Perspective);
// default
}

View File

@ -256,7 +256,11 @@ impl Decoration {
interpolation,
sampling,
..
} => Ok(crate::Binding::Location { location, interpolation, sampling }),
} => Ok(crate::Binding::Location {
location,
interpolation,
sampling,
}),
_ => Err(Error::MissingDecoration(spirv::Decoration::Location)),
}
}
@ -1438,41 +1442,78 @@ impl<I: Iterator<Item = u32>> Parser<I> {
let v1_lexp = self.lookup_expression.lookup(v1_id)?;
let v1_lty = self.lookup_type.lookup(v1_lexp.type_id)?;
let v1_handle = v1_lexp.handle;
let n1 = match type_arena[v1_lty.handle].inner {
crate::TypeInner::Vector { size, .. } => size as u8,
crate::TypeInner::Vector { size, .. } => size as u32,
_ => return Err(Error::InvalidInnerType(v1_lexp.type_id)),
};
let v1_handle = v1_lexp.handle;
let v2_lexp = self.lookup_expression.lookup(v2_id)?;
let v2_lty = self.lookup_type.lookup(v2_lexp.type_id)?;
let v2_handle = v2_lexp.handle;
let n2 = match type_arena[v2_lty.handle].inner {
crate::TypeInner::Vector { size, .. } => size as u8,
crate::TypeInner::Vector { size, .. } => size as u32,
_ => return Err(Error::InvalidInnerType(v2_lexp.type_id)),
};
let v2_handle = v2_lexp.handle;
let mut components = Vec::with_capacity(inst.wc as usize - 5);
for _ in 0..components.capacity() {
let index = self.next()?;
let expr = if index < n1 as u32 {
crate::Expression::AccessIndex {
base: v1_handle,
index,
}
} else if index < n1 as u32 + n2 as u32 {
crate::Expression::AccessIndex {
base: v2_handle,
index: index - n1 as u32,
}
} else {
return Err(Error::InvalidAccessIndex(index));
};
components.push(expressions.append(expr));
self.temp_bytes.clear();
let mut max_component = 0;
for _ in 5..inst.wc as usize {
let mut index = self.next()?;
if index == !0 {
// treat Undefined as X
index = 0;
}
max_component = max_component.max(index);
self.temp_bytes.push(index as u8);
}
let expr = crate::Expression::Compose {
ty: self.lookup_type.lookup(result_type_id)?.handle,
components,
// Check for swizzle first.
let expr = if max_component < n1 {
use crate::SwizzleComponent as Sc;
let size = match self.temp_bytes.len() {
2 => crate::VectorSize::Bi,
3 => crate::VectorSize::Tri,
_ => crate::VectorSize::Quad,
};
let mut pattern = [Sc::X; 4];
for (pat, index) in pattern.iter_mut().zip(self.temp_bytes.drain(..)) {
*pat = match index {
0 => Sc::X,
1 => Sc::Y,
2 => Sc::Z,
_ => Sc::W,
};
}
crate::Expression::Swizzle {
size,
vector: v1_handle,
pattern,
}
} else {
// Fall back to access + compose
let mut components = Vec::with_capacity(self.temp_bytes.len());
for index in self.temp_bytes.drain(..).map(|i| i as u32) {
let expr = if index < n1 {
crate::Expression::AccessIndex {
base: v1_handle,
index,
}
} else if index < n1 + n2 {
crate::Expression::AccessIndex {
base: v2_handle,
index: index - n1,
}
} else {
return Err(Error::InvalidAccessIndex(index));
};
components.push(expressions.append(expr));
}
crate::Expression::Compose {
ty: self.lookup_type.lookup(result_type_id)?.handle,
components,
}
};
self.lookup_expression.insert(
result_id,
LookupExpression {

View File

@ -379,55 +379,49 @@ impl<'a> ExpressionContext<'a, '_, '_> {
}
enum Composition {
Single(crate::Expression),
Multi(crate::VectorSize, Vec<Handle<crate::Expression>>),
Single(u32),
Multi(crate::VectorSize, [crate::SwizzleComponent; 4]),
}
impl Composition {
//TODO: could be `const fn` once MSRV allows
fn letter_pos(letter: char) -> u32 {
fn letter_component(letter: char) -> Option<crate::SwizzleComponent> {
use crate::SwizzleComponent as Sc;
match letter {
'x' | 'r' => 0,
'y' | 'g' => 1,
'z' | 'b' => 2,
'w' | 'a' => 3,
_ => !0,
'x' | 'r' => Some(Sc::X),
'y' | 'g' => Some(Sc::Y),
'z' | 'b' => Some(Sc::Z),
'w' | 'a' => Some(Sc::W),
_ => None,
}
}
fn extract_impl(name: &str, name_span: Range<usize>) -> Result<u32, Error> {
let ch = name
.chars()
.next()
.ok_or_else(|| Error::BadAccessor(name_span.clone()))?;
match Self::letter_component(ch) {
Some(sc) => Ok(sc as u32),
None => Err(Error::BadAccessor(name_span)),
}
}
fn extract(
base: Handle<crate::Expression>,
base_size: crate::VectorSize,
name: &str,
name_span: Range<usize>,
) -> Result<crate::Expression, Error> {
let ch = name
.chars()
.next()
.ok_or_else(|| Error::BadAccessor(name_span.clone()))?;
let index = Self::letter_pos(ch);
if index >= base_size as u32 {
return Err(Error::BadAccessor(name_span));
}
Ok(crate::Expression::AccessIndex { base, index })
Self::extract_impl(name, name_span)
.map(|index| crate::Expression::AccessIndex { base, index })
}
fn make<'a>(
base: Handle<crate::Expression>,
base_size: crate::VectorSize,
name: &'a str,
name_span: Range<usize>,
expressions: &mut Arena<crate::Expression>,
) -> Result<Self, Error<'a>> {
fn make(name: &str, name_span: Range<usize>) -> Result<Self, Error> {
if name.len() > 1 {
let mut components = Vec::with_capacity(name.len());
for ch in name.chars() {
let index = Self::letter_pos(ch);
if index >= base_size as u32 {
return Err(Error::BadAccessor(name_span));
}
let expr = crate::Expression::AccessIndex { base, index };
components.push(expressions.append(expr));
let mut components = [crate::SwizzleComponent::X; 4];
for (comp, ch) in components.iter_mut().zip(name.chars()) {
*comp = Self::letter_component(ch)
.ok_or_else(|| Error::BadAccessor(name_span.clone()))?;
}
let size = match name.len() {
@ -438,7 +432,7 @@ impl Composition {
};
Ok(Composition::Multi(size, components))
} else {
Self::extract(base, base_size, name, name_span).map(Composition::Single)
Self::extract_impl(name, name_span).map(Composition::Single)
}
}
}
@ -504,14 +498,23 @@ impl BindingParser {
}
fn finish<'a>(self) -> Result<Option<crate::Binding>, Error<'a>> {
match (self.location, self.built_in, self.interpolation, self.sampling) {
match (
self.location,
self.built_in,
self.interpolation,
self.sampling,
) {
(None, None, None, None) => Ok(None),
(Some(location), None, interpolation, sampling) => {
// Before handing over the completed `Module`, we call
// `apply_common_default_interpolation` to ensure that the interpolation and
// sampling have been explicitly specified on all vertex shader output and fragment
// shader input user bindings, so leaving them potentially `None` here is fine.
Ok(Some(crate::Binding::Location { location, interpolation, sampling }))
Ok(Some(crate::Binding::Location {
location,
interpolation,
sampling,
}))
}
(None, Some(bi), None, None) => Ok(Some(crate::Binding::BuiltIn(bi))),
(location, built_in, interpolation, sampling) => Err(Error::InconsistentBinding(
@ -1251,52 +1254,24 @@ impl Parser {
index,
}
}
crate::TypeInner::Vector { size, kind, width } => {
match Composition::make(handle, size, name, name_span, ctx.expressions)?
{
//TODO: Swizzling in IR
Composition::Multi(size, components) => {
let inner = crate::TypeInner::Vector { size, kind, width };
crate::Expression::Compose {
ty: ctx
.types
.fetch_or_append(crate::Type { name: None, inner }),
components,
crate::TypeInner::Vector { .. } | crate::TypeInner::Matrix { .. } => {
match Composition::make(name, name_span)? {
Composition::Multi(dst_size, pattern) => {
crate::Expression::Swizzle {
size: dst_size,
vector: handle,
pattern,
}
}
Composition::Single(expr) => expr,
Composition::Single(index) => crate::Expression::AccessIndex {
base: handle,
index,
},
}
}
crate::TypeInner::Matrix {
columns,
rows,
width,
} => match Composition::make(
handle,
columns,
name,
name_span,
ctx.expressions,
)? {
//TODO: is this really supported?
Composition::Multi(columns, components) => {
let inner = crate::TypeInner::Matrix {
columns,
rows,
width,
};
crate::Expression::Compose {
ty: ctx
.types
.fetch_or_append(crate::Type { name: None, inner }),
components,
}
}
Composition::Single(expr) => expr,
},
crate::TypeInner::ValuePointer {
size: Some(size), ..
} => Composition::extract(handle, size, name, name_span)?,
crate::TypeInner::ValuePointer { .. } => {
Composition::extract(handle, name, name_span)?
}
crate::TypeInner::Pointer { base, class: _ } => match ctx.types[base].inner
{
crate::TypeInner::Struct { ref members, .. } => {
@ -1310,13 +1285,7 @@ impl Parser {
index,
}
}
crate::TypeInner::Vector { size, .. } => {
Composition::extract(handle, size, name, name_span)?
}
crate::TypeInner::Matrix { columns, .. } => {
Composition::extract(handle, columns, name, name_span)?
}
_ => return Err(Error::BadAccessor(name_span)),
_ => Composition::extract(handle, name, name_span)?,
},
_ => return Err(Error::BadAccessor(name_span)),
}

View File

@ -480,7 +480,7 @@ pub enum Binding {
Location {
location: u32,
interpolation: Option<Interpolation>,
sampling: Option<Sampling>
sampling: Option<Sampling>,
},
}
@ -679,6 +679,21 @@ pub enum ImageQuery {
NumSamples,
}
/// Component selection for a vector swizzle.
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
pub enum SwizzleComponent {
///
X,
///
Y,
///
Z,
///
W,
}
/// An expression that can be evaluated to obtain a value.
///
/// This is a Single Static Assignment (SSA) scheme similar to SPIR-V.
@ -704,6 +719,12 @@ pub enum Expression {
size: VectorSize,
value: Handle<Expression>,
},
/// Vector swizzle.
Swizzle {
size: VectorSize,
vector: Handle<Expression>,
pattern: [SwizzleComponent; 4],
},
/// Composite expression.
Compose {
ty: Handle<Type>,

View File

@ -36,13 +36,16 @@ impl crate::Module {
/// `binding` refers to the `Binding` whose type is `ty`. If `ty` is a struct, then it's the
/// bindings of the struct's members that we care about, and the binding of the struct
/// itself is meaningless, so `binding` should be `None`.
fn default_binding_or_struct(binding: &mut Option<Binding>,
ty: Handle<Type>,
types: &mut Arena<Type>)
{
fn default_binding_or_struct(
binding: &mut Option<Binding>,
ty: Handle<Type>,
types: &mut Arena<Type>,
) {
match types.get_mut(ty).inner {
// A struct. It's the individual members we care about, so recurse.
TypeInner::Struct { members: ref mut m, .. } => {
TypeInner::Struct {
members: ref mut m, ..
} => {
// To choose the right interpolations for `members`, we must consult other
// elements of `types`. But both `members` and the types it refers to are stored
// in `types`, and Rust won't let us mutate one element of the `Arena`'s `Vec`
@ -61,7 +64,9 @@ impl crate::Module {
// afresh here, rather than just using `m`: it's only because `m` was dead that
// we were able to pass `types` to the recursive call.
match types.get_mut(ty).inner {
TypeInner::Struct { members: ref mut m, .. } => replace(m, members),
TypeInner::Struct {
members: ref mut m, ..
} => replace(m, members),
_ => unreachable!("ty must be a struct"),
};
}
@ -71,16 +76,29 @@ impl crate::Module {
// GLSL has 64-bit floats, but it won't interpolate them. WGSL and MSL only have
// 32-bit floats. SPIR-V has 16- and 64-bit float capabilities, but Vulkan is vague
// about what can and cannot be interpolated.
TypeInner::Scalar { kind: ScalarKind::Float, width: 4 } |
TypeInner::Vector { kind: ScalarKind::Float, width: 4, .. } => {
TypeInner::Scalar {
kind: ScalarKind::Float,
width: 4,
}
| TypeInner::Vector {
kind: ScalarKind::Float,
width: 4,
..
} => {
// unwrap: all `EntryPoint` arguments or return values must either be structures
// or have a `Binding`.
let binding = binding.as_mut().unwrap();
if let Binding::Location { ref mut interpolation, ref mut sampling, .. } = *binding {
if let Binding::Location {
ref mut interpolation,
ref mut sampling,
..
} = *binding
{
if interpolation.is_none() {
*interpolation = Some(crate::Interpolation::Perspective);
}
if sampling.is_none() && *interpolation != Some(crate::Interpolation::Flat) {
if sampling.is_none() && *interpolation != Some(crate::Interpolation::Flat)
{
*sampling = Some(crate::Sampling::Center);
}
}
@ -91,7 +109,12 @@ impl crate::Module {
// unwrap: all `EntryPoint` arguments or return values must either be structures
// or have a `Binding`.
let binding = binding.as_mut().unwrap();
if let Binding::Location { ref mut interpolation, ref mut sampling, .. } = *binding {
if let Binding::Location {
ref mut interpolation,
ref mut sampling,
..
} = *binding
{
*interpolation = Some(crate::Interpolation::Flat);
*sampling = None;
}

View File

@ -93,6 +93,8 @@ pub enum ResolveError {
},
#[error("Invalid scalar {0:?}")]
InvalidScalar(Handle<crate::Expression>),
#[error("Invalid vector {0:?}")]
InvalidVector(Handle<crate::Expression>),
#[error("Invalid pointer {0:?}")]
InvalidPointer(Handle<crate::Expression>),
#[error("Invalid image {0:?}")]
@ -288,6 +290,21 @@ impl<'a> ResolveContext<'a> {
return Err(ResolveError::InvalidScalar(value));
}
},
crate::Expression::Swizzle {
size,
vector,
pattern: _,
} => match *past(vector).inner_with(types) {
Ti::Vector {
size: _,
kind,
width,
} => TypeResolution::Value(Ti::Vector { size, kind, width }),
ref other => {
log::error!("Vector type {:?}", other);
return Err(ResolveError::InvalidVector(vector));
}
},
crate::Expression::Compose { ty, .. } => TypeResolution::Handle(ty),
crate::Expression::FunctionArgument(index) => {
TypeResolution::Handle(self.arguments[index as usize].ty)

View File

@ -322,6 +322,10 @@ impl FunctionInfo {
non_uniform_result: self.add_ref(value),
requirements: UniformityRequirements::empty(),
},
E::Swizzle { vector, .. } => Uniformity {
non_uniform_result: self.add_ref(vector),
requirements: UniformityRequirements::empty(),
},
E::Compose { ref components, .. } => {
let non_uniform_result = components
.iter()

View File

@ -33,6 +33,10 @@ pub enum ExpressionError {
InvalidArrayType(Handle<crate::Expression>),
#[error("Splatting {0:?} can't be done")]
InvalidSplatType(Handle<crate::Expression>),
#[error("Swizzling {0:?} can't be done")]
InvalidVectorType(Handle<crate::Expression>),
#[error("Swizzle component {0:?} is outside of vector size {1:?}")]
InvalidSwizzleComponent(crate::SwizzleComponent, crate::VectorSize),
#[error(transparent)]
Compose(#[from] ComposeError),
#[error("Operation {0:?} can't work with {1:?}")]
@ -200,6 +204,25 @@ impl super::Validator {
return Err(ExpressionError::InvalidSplatType(value));
}
},
E::Swizzle {
size,
vector,
pattern,
} => {
let vec_size = match *resolver.resolve(vector)? {
Ti::Vector { size: vec_size, .. } => vec_size,
ref other => {
log::error!("Swizzle vector type {:?}", other);
return Err(ExpressionError::InvalidVectorType(vector));
}
};
for &sc in pattern[..size as usize].iter() {
if sc as u8 >= vec_size as u8 {
return Err(ExpressionError::InvalidSwizzleComponent(sc, vec_size));
}
}
ShaderStages::all()
}
E::Compose { ref components, ty } => {
for &handle in components {
if handle >= root {

View File

@ -208,7 +208,11 @@ impl VaryingContext<'_> {
return Err(VaryingError::InvalidBuiltInType(built_in));
}
}
crate::Binding::Location { location, interpolation, sampling } => {
crate::Binding::Location {
location,
interpolation,
sampling,
} => {
if !self.location_mask.insert(location as usize) {
return Err(VaryingError::BindingCollision { location });
}
@ -235,7 +239,8 @@ impl VaryingContext<'_> {
}
}
Some(_) => {
if needs_interpolation && interpolation != Some(crate::Interpolation::Flat) {
if needs_interpolation && interpolation != Some(crate::Interpolation::Flat)
{
return Err(VaryingError::InvalidInterpolation);
}
}

View File

@ -76,24 +76,3 @@ fn invalid_scalar_width() {
"###,
);
}
#[cfg(feature = "wgsl-in")]
#[test]
fn invalid_accessor() {
check(
r###"
[[stage(vertex)]]
fn vs_main() {
var color: vec3<f32> = vec3<f32>(1.0, 2.0, 3.0);
var i: f32 = color.a;
}
"###,
r###"error: invalid field accessor `a`
wgsl:5:24
5 var i: f32 = color.a;
^ invalid accessor
"###,
);
}

View File

@ -9,8 +9,8 @@ kernel void main1(
, metal::texture2d<uint, metal::access::read> image_src [[user(fake0)]]
, metal::texture1d<uint, metal::access::write> image_dst [[user(fake0)]]
) {
metal::int2 _e12 = (int2(image_src.get_width(), image_src.get_height()) * static_cast<int2>(metal::uint2(local_id.x, local_id.y))) % metal::int2(10, 20);
metal::uint4 _e13 = image_src.read(metal::uint2(_e12));
image_dst.write(_e13, metal::uint(_e12.x));
metal::int2 _e10 = (int2(image_src.get_width(), image_src.get_height()) * static_cast<int2>(local_id.xy)) % metal::int2(10, 20);
metal::uint4 _e11 = image_src.read(metal::uint2(_e10));
image_dst.write(_e11, metal::uint(_e10.x));
return;
}

View File

@ -4,8 +4,7 @@ precision highp float;
void main() {
vec2 _expr10 = (((vec2(1.0) + vec2(2.0)) - vec2(3.0)) / vec2(4.0));
gl_Position = (vec4(_expr10[0], _expr10[1], _expr10[0], _expr10[1]) + vec4((ivec4(5) % ivec4(2))));
gl_Position = ((((vec2(1.0) + vec2(2.0)) - vec2(3.0)) / vec2(4.0)).xyxy + vec4((ivec4(5) % ivec4(2))));
return;
}

View File

@ -7,6 +7,5 @@ struct splatOutput {
};
vertex splatOutput splat(
) {
metal::float2 _e10 = ((float2(1.0) + float2(2.0)) - float2(3.0)) / float2(4.0);
return splatOutput { metal::float4(_e10.x, _e10.y, _e10.x, _e10.y) + static_cast<float4>(int4(5) % int4(2)) };
return splatOutput { (((float2(1.0) + float2(2.0)) - float2(3.0)) / float2(4.0)).xyxy + static_cast<float4>(int4(5) % int4(2)) };
}

View File

@ -1,7 +1,7 @@
; SPIR-V
; Version: 1.0
; Generator: rspirv
; Bound: 37
; Bound: 33
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
@ -36,13 +36,9 @@ OpBranch %17
%27 = OpCompositeConstruct %26 %8 %8 %8 %8
%28 = OpCompositeConstruct %26 %10 %10 %10 %10
%29 = OpSMod %26 %27 %28
%30 = OpCompositeExtract %4 %25 0
%31 = OpCompositeExtract %4 %25 1
%32 = OpCompositeExtract %4 %25 0
%33 = OpCompositeExtract %4 %25 1
%34 = OpCompositeConstruct %11 %30 %31 %32 %33
%35 = OpConvertSToF %11 %29
%36 = OpFAdd %11 %34 %35
OpStore %13 %36
%30 = OpVectorShuffle %11 %25 %25 0 1 0 1
%31 = OpConvertSToF %11 %29
%32 = OpFAdd %11 %30 %31
OpStore %13 %32
OpReturn
OpFunctionEnd

View File

@ -26,8 +26,8 @@ float fetch_shadow(uint light_id, vec4 homogeneous_coords) {
if((homogeneous_coords[3] <= 0.0)) {
return 1.0;
}
float _expr28 = textureGrad(_group_0_binding_2, vec4((((vec2(homogeneous_coords[0], homogeneous_coords[1]) * vec2(0.5, -0.5)) / vec2(homogeneous_coords[3])) + vec2(0.5, 0.5)), int(light_id), (homogeneous_coords[2] / homogeneous_coords[3])), vec2(0, 0), vec2(0,0));
return _expr28;
float _expr26 = textureGrad(_group_0_binding_2, vec4((((homogeneous_coords.xy * vec2(0.5, -0.5)) / vec2(homogeneous_coords[3])) + vec2(0.5, 0.5)), int(light_id), (homogeneous_coords[2] / homogeneous_coords[3])), vec2(0, 0), vec2(0,0));
return _expr26;
}
void main() {
@ -41,7 +41,7 @@ void main() {
}
Light _expr21 = _group_0_binding_1.data[i];
float _expr25 = fetch_shadow(i, (_expr21.proj * position));
color1 = (color1 + ((_expr25 * max(0.0, dot(normalize(raw_normal), normalize((vec3(_expr21.pos[0], _expr21.pos[1], _expr21.pos[2]) - vec3(position[0], position[1], position[2])))))) * vec3(_expr21.color[0], _expr21.color[1], _expr21.color[2])));
color1 = (color1 + ((_expr25 * max(0.0, dot(normalize(raw_normal), normalize((_expr21.pos.xyz - position.xyz))))) * _expr21.color.xyz));
i = (i + 1u);
}
_fs2p_location0 = vec4(color1, 1.0);

View File

@ -25,8 +25,8 @@ float fetch_shadow(
if (homogeneous_coords.w <= 0.0) {
return 1.0;
}
float _e28 = t_shadow.sample_compare(sampler_shadow, ((metal::float2(homogeneous_coords.x, homogeneous_coords.y) * metal::float2(0.5, -0.5)) / float2(homogeneous_coords.w)) + metal::float2(0.5, 0.5), static_cast<int>(light_id), homogeneous_coords.z / homogeneous_coords.w);
return _e28;
float _e26 = t_shadow.sample_compare(sampler_shadow, ((homogeneous_coords.xy * metal::float2(0.5, -0.5)) / float2(homogeneous_coords.w)) + metal::float2(0.5, 0.5), static_cast<int>(light_id), homogeneous_coords.z / homogeneous_coords.w);
return _e26;
}
struct fs_mainInput {
@ -58,7 +58,7 @@ fragment fs_mainOutput fs_main(
}
Light _e21 = s_lights.data[i];
float _e25 = fetch_shadow(i, _e21.proj * position, t_shadow, sampler_shadow);
color1 = color1 + ((_e25 * metal::max(0.0, metal::dot(metal::normalize(raw_normal), metal::normalize(metal::float3(_e21.pos.x, _e21.pos.y, _e21.pos.z) - metal::float3(position.x, position.y, position.z))))) * metal::float3(_e21.color.x, _e21.color.y, _e21.color.z));
color1 = color1 + ((_e25 * metal::max(0.0, metal::dot(metal::normalize(raw_normal), metal::normalize(_e21.pos.xyz - position.xyz)))) * _e21.color.xyz);
}
return fs_mainOutput { metal::float4(color1, 1.0) };
}

View File

@ -1,13 +1,13 @@
; SPIR-V
; Version: 1.2
; Generator: rspirv
; Bound: 137
; Bound: 126
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %82 "fs_main" %74 %77 %80
OpExecutionMode %82 OriginUpperLeft
OpEntryPoint Fragment %80 "fs_main" %72 %75 %78
OpExecutionMode %80 OriginUpperLeft
OpSource GLSL 450
OpName %9 "c_max_lights"
OpName %14 "Globals"
@ -24,11 +24,11 @@ OpName %27 "s_lights"
OpName %29 "t_shadow"
OpName %31 "sampler_shadow"
OpName %36 "fetch_shadow"
OpName %69 "color"
OpName %71 "i"
OpName %74 "raw_normal"
OpName %77 "position"
OpName %82 "fs_main"
OpName %67 "color"
OpName %69 "i"
OpName %72 "raw_normal"
OpName %75 "position"
OpName %80 "fs_main"
OpDecorate %14 Block
OpMemberDecorate %14 0 Offset 0
OpMemberDecorate %17 0 Offset 0
@ -48,9 +48,9 @@ OpDecorate %29 DescriptorSet 0
OpDecorate %29 Binding 2
OpDecorate %31 DescriptorSet 0
OpDecorate %31 Binding 3
OpDecorate %74 Location 0
OpDecorate %77 Location 1
OpDecorate %80 Location 0
OpDecorate %72 Location 0
OpDecorate %75 Location 1
OpDecorate %78 Location 0
%2 = OpTypeVoid
%4 = OpTypeFloat 32
%3 = OpConstant %4 0.0
@ -84,22 +84,22 @@ OpDecorate %80 Location 0
%31 = OpVariable %32 UniformConstant
%37 = OpTypeFunction %4 %10 %16
%42 = OpTypeBool
%56 = OpTypeInt 32 1
%61 = OpTypeSampledImage %20
%68 = OpConstant %4 0.0
%70 = OpTypePointer Function %23
%72 = OpTypePointer Function %10
%75 = OpTypePointer Input %23
%74 = OpVariable %75 Input
%78 = OpTypePointer Input %16
%77 = OpVariable %78 Input
%81 = OpTypePointer Output %16
%80 = OpVariable %81 Output
%83 = OpTypeFunction %2
%93 = OpTypePointer Uniform %13
%94 = OpConstant %56 0
%102 = OpTypePointer StorageBuffer %18
%104 = OpTypePointer StorageBuffer %17
%54 = OpTypeInt 32 1
%59 = OpTypeSampledImage %20
%66 = OpConstant %4 0.0
%68 = OpTypePointer Function %23
%70 = OpTypePointer Function %10
%73 = OpTypePointer Input %23
%72 = OpVariable %73 Input
%76 = OpTypePointer Input %16
%75 = OpVariable %76 Input
%79 = OpTypePointer Output %16
%78 = OpVariable %79 Output
%81 = OpTypeFunction %2
%91 = OpTypePointer Uniform %13
%92 = OpConstant %54 0
%100 = OpTypePointer StorageBuffer %18
%102 = OpTypePointer StorageBuffer %17
%36 = OpFunction %4 None %37
%34 = OpFunctionParameter %10
%35 = OpFunctionParameter %16
@ -116,93 +116,82 @@ OpBranchConditional %43 %45 %44
OpReturnValue %5
%44 = OpLabel
%46 = OpCompositeConstruct %22 %6 %7
%47 = OpCompositeExtract %4 %35 0
%48 = OpCompositeExtract %4 %35 1
%49 = OpCompositeConstruct %22 %47 %48
%50 = OpFMul %22 %49 %46
%51 = OpCompositeExtract %4 %35 3
%52 = OpCompositeConstruct %22 %51 %51
%53 = OpFDiv %22 %50 %52
%54 = OpCompositeConstruct %22 %6 %6
%55 = OpFAdd %22 %53 %54
%57 = OpBitcast %56 %34
%58 = OpCompositeExtract %4 %35 2
%59 = OpCompositeExtract %4 %35 3
%60 = OpFDiv %4 %58 %59
%62 = OpCompositeExtract %4 %55 0
%63 = OpCompositeExtract %4 %55 1
%64 = OpConvertUToF %4 %57
%65 = OpCompositeConstruct %23 %62 %63 %64
%66 = OpSampledImage %61 %38 %39
%67 = OpImageSampleDrefExplicitLod %4 %66 %65 %60 Lod %68
OpReturnValue %67
%47 = OpVectorShuffle %22 %35 %35 0 1
%48 = OpFMul %22 %47 %46
%49 = OpCompositeExtract %4 %35 3
%50 = OpCompositeConstruct %22 %49 %49
%51 = OpFDiv %22 %48 %50
%52 = OpCompositeConstruct %22 %6 %6
%53 = OpFAdd %22 %51 %52
%55 = OpBitcast %54 %34
%56 = OpCompositeExtract %4 %35 2
%57 = OpCompositeExtract %4 %35 3
%58 = OpFDiv %4 %56 %57
%60 = OpCompositeExtract %4 %53 0
%61 = OpCompositeExtract %4 %53 1
%62 = OpConvertUToF %4 %55
%63 = OpCompositeConstruct %23 %60 %61 %62
%64 = OpSampledImage %59 %38 %39
%65 = OpImageSampleDrefExplicitLod %4 %64 %63 %58 Lod %66
OpReturnValue %65
OpFunctionEnd
%82 = OpFunction %2 None %83
%73 = OpLabel
%69 = OpVariable %70 Function %24
%71 = OpVariable %72 Function %11
%76 = OpLoad %23 %74
%79 = OpLoad %16 %77
%84 = OpLoad %20 %29
%85 = OpLoad %21 %31
%80 = OpFunction %2 None %81
%71 = OpLabel
%67 = OpVariable %68 Function %24
%69 = OpVariable %70 Function %11
%74 = OpLoad %23 %72
%77 = OpLoad %16 %75
%82 = OpLoad %20 %29
%83 = OpLoad %21 %31
OpBranch %84
%84 = OpLabel
%85 = OpExtInst %23 %1 Normalize %74
OpBranch %86
%86 = OpLabel
%87 = OpExtInst %23 %1 Normalize %76
OpLoopMerge %87 %89 None
OpBranch %88
%88 = OpLabel
OpLoopMerge %89 %91 None
OpBranch %90
%90 = OpLabel
%92 = OpLoad %10 %71
%95 = OpAccessChain %93 %25 %94
%96 = OpLoad %13 %95
%97 = OpCompositeExtract %10 %96 0
%98 = OpExtInst %10 %1 UMin %97 %9
%99 = OpUGreaterThanEqual %42 %92 %98
OpSelectionMerge %100 None
OpBranchConditional %99 %101 %100
%101 = OpLabel
%90 = OpLoad %10 %69
%93 = OpAccessChain %91 %25 %92
%94 = OpLoad %13 %93
%95 = OpCompositeExtract %10 %94 0
%96 = OpExtInst %10 %1 UMin %95 %9
%97 = OpUGreaterThanEqual %42 %90 %96
OpSelectionMerge %98 None
OpBranchConditional %97 %99 %98
%99 = OpLabel
OpBranch %87
%98 = OpLabel
%101 = OpLoad %10 %69
%103 = OpAccessChain %102 %27 %92 %101
%104 = OpLoad %17 %103
%105 = OpLoad %10 %69
%106 = OpCompositeExtract %15 %104 0
%107 = OpMatrixTimesVector %16 %106 %77
%108 = OpFunctionCall %4 %36 %105 %107
%109 = OpCompositeExtract %16 %104 1
%110 = OpVectorShuffle %23 %109 %109 0 1 2
%111 = OpVectorShuffle %23 %77 %77 0 1 2
%112 = OpFSub %23 %110 %111
%113 = OpExtInst %23 %1 Normalize %112
%114 = OpDot %4 %85 %113
%115 = OpExtInst %4 %1 FMax %3 %114
%116 = OpLoad %23 %67
%117 = OpFMul %4 %108 %115
%118 = OpCompositeExtract %16 %104 2
%119 = OpVectorShuffle %23 %118 %118 0 1 2
%120 = OpVectorTimesScalar %23 %119 %117
%121 = OpFAdd %23 %116 %120
OpStore %67 %121
OpBranch %89
%100 = OpLabel
%103 = OpLoad %10 %71
%105 = OpAccessChain %104 %27 %94 %103
%106 = OpLoad %17 %105
%107 = OpLoad %10 %71
%108 = OpCompositeExtract %15 %106 0
%109 = OpMatrixTimesVector %16 %108 %79
%110 = OpFunctionCall %4 %36 %107 %109
%111 = OpCompositeExtract %16 %106 1
%112 = OpCompositeExtract %4 %111 0
%113 = OpCompositeExtract %4 %111 1
%114 = OpCompositeExtract %4 %111 2
%115 = OpCompositeConstruct %23 %112 %113 %114
%116 = OpCompositeExtract %4 %79 0
%117 = OpCompositeExtract %4 %79 1
%118 = OpCompositeExtract %4 %79 2
%119 = OpCompositeConstruct %23 %116 %117 %118
%120 = OpFSub %23 %115 %119
%121 = OpExtInst %23 %1 Normalize %120
%122 = OpDot %4 %87 %121
%123 = OpExtInst %4 %1 FMax %3 %122
%124 = OpLoad %23 %69
%125 = OpFMul %4 %110 %123
%126 = OpCompositeExtract %16 %106 2
%127 = OpCompositeExtract %4 %126 0
%128 = OpCompositeExtract %4 %126 1
%129 = OpCompositeExtract %4 %126 2
%130 = OpCompositeConstruct %23 %127 %128 %129
%131 = OpVectorTimesScalar %23 %130 %125
%132 = OpFAdd %23 %124 %131
OpStore %69 %132
OpBranch %91
%91 = OpLabel
%133 = OpLoad %10 %71
%134 = OpIAdd %10 %133 %12
OpStore %71 %134
OpBranch %88
%89 = OpLabel
%135 = OpLoad %23 %69
%136 = OpCompositeConstruct %16 %135 %5
OpStore %80 %136
%122 = OpLoad %10 %69
%123 = OpIAdd %10 %122 %12
OpStore %69 %123
OpBranch %86
%87 = OpLabel
%124 = OpLoad %23 %67
%125 = OpCompositeConstruct %16 %124 %5
OpStore %78 %125
OpReturn
OpFunctionEnd

View File

@ -21,9 +21,8 @@ void main() {
tmp1_ = (int(vertex_index) / 2);
tmp2_ = (int(vertex_index) & 1);
vec4 _expr24 = vec4(((float(tmp1_) * 4.0) - 1.0), ((float(tmp2_) * 4.0) - 1.0), 0.0, 1.0);
vec4 _expr50 = (_group_0_binding_0.proj_inv * _expr24);
gl_Position = VertexOutput(_expr24, (transpose(mat3x3(vec3(_group_0_binding_0.view[0][0], _group_0_binding_0.view[0][1], _group_0_binding_0.view[0][2]), vec3(_group_0_binding_0.view[1][0], _group_0_binding_0.view[1][1], _group_0_binding_0.view[1][2]), vec3(_group_0_binding_0.view[2][0], _group_0_binding_0.view[2][1], _group_0_binding_0.view[2][2]))) * vec3(_expr50[0], _expr50[1], _expr50[2]))).position;
_vs2fs_location0 = VertexOutput(_expr24, (transpose(mat3x3(vec3(_group_0_binding_0.view[0][0], _group_0_binding_0.view[0][1], _group_0_binding_0.view[0][2]), vec3(_group_0_binding_0.view[1][0], _group_0_binding_0.view[1][1], _group_0_binding_0.view[1][2]), vec3(_group_0_binding_0.view[2][0], _group_0_binding_0.view[2][1], _group_0_binding_0.view[2][2]))) * vec3(_expr50[0], _expr50[1], _expr50[2]))).uv;
gl_Position = VertexOutput(_expr24, (transpose(mat3x3(_group_0_binding_0.view[0].xyz, _group_0_binding_0.view[1].xyz, _group_0_binding_0.view[2].xyz)) * (_group_0_binding_0.proj_inv * _expr24).xyz)).position;
_vs2fs_location0 = VertexOutput(_expr24, (transpose(mat3x3(_group_0_binding_0.view[0].xyz, _group_0_binding_0.view[1].xyz, _group_0_binding_0.view[2].xyz)) * (_group_0_binding_0.proj_inv * _expr24).xyz)).uv;
return;
}

View File

@ -25,8 +25,7 @@ vertex vs_mainOutput vs_main(
tmp1_ = static_cast<int>(vertex_index) / 2;
tmp2_ = static_cast<int>(vertex_index) & 1;
metal::float4 _e24 = metal::float4((static_cast<float>(tmp1_) * 4.0) - 1.0, (static_cast<float>(tmp2_) * 4.0) - 1.0, 0.0, 1.0);
metal::float4 _e50 = r_data.proj_inv * _e24;
const auto _tmp = VertexOutput {_e24, metal::transpose(metal::float3x3(metal::float3(r_data.view[0].x, r_data.view[0].y, r_data.view[0].z), metal::float3(r_data.view[1].x, r_data.view[1].y, r_data.view[1].z), metal::float3(r_data.view[2].x, r_data.view[2].y, r_data.view[2].z))) * metal::float3(_e50.x, _e50.y, _e50.z)};
const auto _tmp = VertexOutput {_e24, metal::transpose(metal::float3x3(r_data.view[0].xyz, r_data.view[1].xyz, r_data.view[2].xyz)) * (r_data.proj_inv * _e24).xyz};
return vs_mainOutput { _tmp.position, _tmp.uv };
}

View File

@ -1,13 +1,13 @@
; SPIR-V
; Version: 1.0
; Generator: rspirv
; Bound: 105
; Bound: 93
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %36 "vs_main" %29 %32 %34
OpEntryPoint Fragment %97 "fs_main" %90 %93 %96
OpExecutionMode %97 OriginUpperLeft
OpEntryPoint Fragment %85 "fs_main" %78 %81 %84
OpExecutionMode %85 OriginUpperLeft
OpMemberDecorate %12 0 Offset 0
OpMemberDecorate %12 1 Offset 16
OpDecorate %14 Block
@ -26,9 +26,9 @@ OpDecorate %23 Binding 2
OpDecorate %29 BuiltIn VertexIndex
OpDecorate %32 BuiltIn Position
OpDecorate %34 Location 0
OpDecorate %90 BuiltIn FragCoord
OpDecorate %93 Location 0
OpDecorate %96 Location 0
OpDecorate %78 BuiltIn FragCoord
OpDecorate %81 Location 0
OpDecorate %84 Location 0
%2 = OpTypeVoid
%4 = OpTypeInt 32 1
%3 = OpConstant %4 2
@ -61,13 +61,13 @@ OpDecorate %96 Location 0
%34 = OpVariable %35 Output
%37 = OpTypeFunction %2
%52 = OpTypePointer Uniform %13
%76 = OpConstant %4 0
%91 = OpTypePointer Input %10
%90 = OpVariable %91 Input
%94 = OpTypePointer Input %11
%93 = OpVariable %94 Input
%96 = OpVariable %33 Output
%102 = OpTypeSampledImage %17
%67 = OpConstant %4 0
%79 = OpTypePointer Input %10
%78 = OpVariable %79 Input
%82 = OpTypePointer Input %11
%81 = OpVariable %82 Input
%84 = OpVariable %33 Output
%90 = OpTypeSampledImage %17
%36 = OpFunction %2 None %37
%28 = OpLabel
%25 = OpVariable %26 Function
@ -93,53 +93,41 @@ OpStore %27 %42
%53 = OpAccessChain %52 %19 %5
%54 = OpLoad %13 %53
%55 = OpCompositeExtract %10 %54 0
%56 = OpCompositeExtract %7 %55 0
%57 = OpCompositeExtract %7 %55 1
%58 = OpCompositeExtract %7 %55 2
%59 = OpCompositeConstruct %11 %56 %57 %58
%60 = OpAccessChain %52 %19 %5
%61 = OpLoad %13 %60
%62 = OpCompositeExtract %10 %61 1
%63 = OpCompositeExtract %7 %62 0
%64 = OpCompositeExtract %7 %62 1
%65 = OpCompositeExtract %7 %62 2
%66 = OpCompositeConstruct %11 %63 %64 %65
%67 = OpAccessChain %52 %19 %5
%68 = OpLoad %13 %67
%69 = OpCompositeExtract %10 %68 2
%70 = OpCompositeExtract %7 %69 0
%71 = OpCompositeExtract %7 %69 1
%72 = OpCompositeExtract %7 %69 2
%73 = OpCompositeConstruct %11 %70 %71 %72
%74 = OpCompositeConstruct %16 %59 %66 %73
%75 = OpTranspose %16 %74
%77 = OpAccessChain %52 %19 %76
%78 = OpLoad %13 %77
%79 = OpMatrixTimesVector %10 %78 %51
%80 = OpCompositeExtract %7 %79 0
%81 = OpCompositeExtract %7 %79 1
%82 = OpCompositeExtract %7 %79 2
%83 = OpCompositeConstruct %11 %80 %81 %82
%84 = OpMatrixTimesVector %11 %75 %83
%85 = OpCompositeConstruct %12 %51 %84
%86 = OpCompositeExtract %10 %85 0
OpStore %32 %86
%87 = OpCompositeExtract %11 %85 1
OpStore %34 %87
%56 = OpVectorShuffle %11 %55 %55 0 1 2
%57 = OpAccessChain %52 %19 %5
%58 = OpLoad %13 %57
%59 = OpCompositeExtract %10 %58 1
%60 = OpVectorShuffle %11 %59 %59 0 1 2
%61 = OpAccessChain %52 %19 %5
%62 = OpLoad %13 %61
%63 = OpCompositeExtract %10 %62 2
%64 = OpVectorShuffle %11 %63 %63 0 1 2
%65 = OpCompositeConstruct %16 %56 %60 %64
%66 = OpTranspose %16 %65
%68 = OpAccessChain %52 %19 %67
%69 = OpLoad %13 %68
%70 = OpMatrixTimesVector %10 %69 %51
%71 = OpVectorShuffle %11 %70 %70 0 1 2
%72 = OpMatrixTimesVector %11 %66 %71
%73 = OpCompositeConstruct %12 %51 %72
%74 = OpCompositeExtract %10 %73 0
OpStore %32 %74
%75 = OpCompositeExtract %11 %73 1
OpStore %34 %75
OpReturn
OpFunctionEnd
%97 = OpFunction %2 None %37
%85 = OpFunction %2 None %37
%76 = OpLabel
%80 = OpLoad %10 %78
%83 = OpLoad %11 %81
%77 = OpCompositeConstruct %12 %80 %83
%86 = OpLoad %17 %21
%87 = OpLoad %18 %23
OpBranch %88
%88 = OpLabel
%92 = OpLoad %10 %90
%95 = OpLoad %11 %93
%89 = OpCompositeConstruct %12 %92 %95
%98 = OpLoad %17 %21
%99 = OpLoad %18 %23
OpBranch %100
%100 = OpLabel
%101 = OpCompositeExtract %11 %89 1
%103 = OpSampledImage %102 %98 %99
%104 = OpImageSampleImplicitLod %10 %103 %101
OpStore %96 %104
%89 = OpCompositeExtract %11 %77 1
%91 = OpSampledImage %90 %86 %87
%92 = OpImageSampleImplicitLod %10 %91 %89
OpStore %84 %92
OpReturn
OpFunctionEnd