diff --git a/src/back/dot/mod.rs b/src/back/dot/mod.rs index d1df175176..75c619a384 100644 --- a/src/back/dot/mod.rs +++ b/src/back/dot/mod.rs @@ -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) diff --git a/src/back/glsl/features.rs b/src/back/glsl/features.rs index 5ae44b71d9..28501b831c 100644 --- a/src/back/glsl/features.rs +++ b/src/back/glsl/features.rs @@ -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); } diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 4a5f5d643f..002777f5e7 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -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 diff --git a/src/back/msl/mod.rs b/src/back/msl/mod.rs index e5652f2327..e38beed88d 100644 --- a/src/back/msl/mod.rs +++ b/src/back/msl/mod.rs @@ -198,7 +198,11 @@ impl Options { ) -> Result { 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, } } diff --git a/src/back/msl/writer.rs b/src/back/msl/writer.rs index 8b2f6901e3..fcf8151056 100644 --- a/src/back/msl/writer.rs +++ b/src/back/msl/writer.rs @@ -611,7 +611,7 @@ impl Writer { 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 Writer { 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); } } diff --git a/src/back/spv/instructions.rs b/src/back/spv/instructions.rs index 90f8b0128e..b8855cda16 100644 --- a/src/back/spv/instructions.rs +++ b/src/back/spv/instructions.rs @@ -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 // diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index 39df6f223a..74a9bade6b 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -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, diff --git a/src/front/glsl/constants.rs b/src/front/glsl/constants.rs index 372ff17041..82221f527c 100644 --- a/src/front/glsl/constants.rs +++ b/src/front/glsl/constants.rs @@ -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() diff --git a/src/front/spv/function.rs b/src/front/spv/function.rs index 15e969d5d3..1116f0e829 100644 --- a/src/front/spv/function.rs +++ b/src/front/spv/function.rs @@ -216,7 +216,8 @@ impl> super::Parser { if let Some(crate::Binding::Location { interpolation: ref mut interpolation @ None, .. - }) = arg.binding { + }) = arg.binding + { *interpolation = Some(crate::Interpolation::Perspective); // default } diff --git a/src/front/spv/mod.rs b/src/front/spv/mod.rs index e4d7a1c715..eaf9dbc094 100644 --- a/src/front/spv/mod.rs +++ b/src/front/spv/mod.rs @@ -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> Parser { 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 { diff --git a/src/front/wgsl/mod.rs b/src/front/wgsl/mod.rs index 8d4baa4c49..cd96de4962 100644 --- a/src/front/wgsl/mod.rs +++ b/src/front/wgsl/mod.rs @@ -379,55 +379,49 @@ impl<'a> ExpressionContext<'a, '_, '_> { } enum Composition { - Single(crate::Expression), - Multi(crate::VectorSize, Vec>), + 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 { + 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) -> Result { + 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, - base_size: crate::VectorSize, name: &str, name_span: Range, ) -> Result { - 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, - base_size: crate::VectorSize, - name: &'a str, - name_span: Range, - expressions: &mut Arena, - ) -> Result> { + fn make(name: &str, name_span: Range) -> Result { 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, 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)), } diff --git a/src/lib.rs b/src/lib.rs index b95fe251b4..f6a4b59f0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -480,7 +480,7 @@ pub enum Binding { Location { location: u32, interpolation: Option, - sampling: Option + sampling: Option, }, } @@ -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, }, + /// Vector swizzle. + Swizzle { + size: VectorSize, + vector: Handle, + pattern: [SwizzleComponent; 4], + }, /// Composite expression. Compose { ty: Handle, diff --git a/src/proc/interpolator.rs b/src/proc/interpolator.rs index 3a5e7e8cb7..7f7296e50d 100644 --- a/src/proc/interpolator.rs +++ b/src/proc/interpolator.rs @@ -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, - ty: Handle, - types: &mut Arena) - { + fn default_binding_or_struct( + binding: &mut Option, + ty: Handle, + types: &mut Arena, + ) { 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; } diff --git a/src/proc/typifier.rs b/src/proc/typifier.rs index 1af4cf8b59..7f90687976 100644 --- a/src/proc/typifier.rs +++ b/src/proc/typifier.rs @@ -93,6 +93,8 @@ pub enum ResolveError { }, #[error("Invalid scalar {0:?}")] InvalidScalar(Handle), + #[error("Invalid vector {0:?}")] + InvalidVector(Handle), #[error("Invalid pointer {0:?}")] InvalidPointer(Handle), #[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) diff --git a/src/valid/analyzer.rs b/src/valid/analyzer.rs index 7b0fff4df7..f206dc3f81 100644 --- a/src/valid/analyzer.rs +++ b/src/valid/analyzer.rs @@ -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() diff --git a/src/valid/expression.rs b/src/valid/expression.rs index 1ec603ce71..5ed5e38539 100644 --- a/src/valid/expression.rs +++ b/src/valid/expression.rs @@ -33,6 +33,10 @@ pub enum ExpressionError { InvalidArrayType(Handle), #[error("Splatting {0:?} can't be done")] InvalidSplatType(Handle), + #[error("Swizzling {0:?} can't be done")] + InvalidVectorType(Handle), + #[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 { diff --git a/src/valid/interface.rs b/src/valid/interface.rs index 63541895b9..aec49e4506 100644 --- a/src/valid/interface.rs +++ b/src/valid/interface.rs @@ -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); } } diff --git a/tests/errors.rs b/tests/errors.rs index e9077220d3..13bf5f1d80 100644 --- a/tests/errors.rs +++ b/tests/errors.rs @@ -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 = vec3(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 - -"###, - ); -} diff --git a/tests/out/image-copy.msl b/tests/out/image-copy.msl index 73407ceefa..2db875cfc6 100644 --- a/tests/out/image-copy.msl +++ b/tests/out/image-copy.msl @@ -9,8 +9,8 @@ kernel void main1( , metal::texture2d image_src [[user(fake0)]] , metal::texture1d image_dst [[user(fake0)]] ) { - metal::int2 _e12 = (int2(image_src.get_width(), image_src.get_height()) * static_cast(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(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; } diff --git a/tests/out/operators.Vertex.glsl b/tests/out/operators.Vertex.glsl index 97d6d3c20e..88898e6efa 100644 --- a/tests/out/operators.Vertex.glsl +++ b/tests/out/operators.Vertex.glsl @@ -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; } diff --git a/tests/out/operators.msl b/tests/out/operators.msl index 79d2ced847..4d3c3d9f30 100644 --- a/tests/out/operators.msl +++ b/tests/out/operators.msl @@ -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(int4(5) % int4(2)) }; + return splatOutput { (((float2(1.0) + float2(2.0)) - float2(3.0)) / float2(4.0)).xyxy + static_cast(int4(5) % int4(2)) }; } diff --git a/tests/out/operators.spvasm b/tests/out/operators.spvasm index 6ee2477c36..cc7c225112 100644 --- a/tests/out/operators.spvasm +++ b/tests/out/operators.spvasm @@ -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 \ No newline at end of file diff --git a/tests/out/shadow.Fragment.glsl b/tests/out/shadow.Fragment.glsl index b045c72508..e1310ca34f 100644 --- a/tests/out/shadow.Fragment.glsl +++ b/tests/out/shadow.Fragment.glsl @@ -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); diff --git a/tests/out/shadow.msl b/tests/out/shadow.msl index 12a5c43bba..0ff4e18f40 100644 --- a/tests/out/shadow.msl +++ b/tests/out/shadow.msl @@ -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(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(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) }; } diff --git a/tests/out/shadow.spvasm b/tests/out/shadow.spvasm index 1016e20605..2fd8716674 100644 --- a/tests/out/shadow.spvasm +++ b/tests/out/shadow.spvasm @@ -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 \ No newline at end of file diff --git a/tests/out/skybox.Vertex.glsl b/tests/out/skybox.Vertex.glsl index e76121da33..e543e836be 100644 --- a/tests/out/skybox.Vertex.glsl +++ b/tests/out/skybox.Vertex.glsl @@ -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; } diff --git a/tests/out/skybox.msl b/tests/out/skybox.msl index bd3763713f..c3ba812137 100644 --- a/tests/out/skybox.msl +++ b/tests/out/skybox.msl @@ -25,8 +25,7 @@ vertex vs_mainOutput vs_main( tmp1_ = static_cast(vertex_index) / 2; tmp2_ = static_cast(vertex_index) & 1; metal::float4 _e24 = metal::float4((static_cast(tmp1_) * 4.0) - 1.0, (static_cast(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 }; } diff --git a/tests/out/skybox.spvasm b/tests/out/skybox.spvasm index c51900db33..ee13bf6fc0 100644 --- a/tests/out/skybox.spvasm +++ b/tests/out/skybox.spvasm @@ -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 \ No newline at end of file