diff --git a/src/back/glsl.rs b/src/back/glsl.rs index 628fd8f1fc..132f4d79e0 100644 --- a/src/back/glsl.rs +++ b/src/back/glsl.rs @@ -1041,6 +1041,24 @@ fn write_expression<'a, 'b>( left_ty, ) } + Expression::As(value, kind) => { + let (value_expr, value_ty) = + write_expression(&builder.expressions[value], module, builder)?; + let (width, out_ty) = match *value_ty.as_ref() { + TypeInner::Scalar { width, kind: _ } => { + (width, Cow::Owned(TypeInner::Scalar { kind, width })) + } + TypeInner::Vector { + width, + kind: _, + size, + } => (width, Cow::Owned(TypeInner::Vector { kind, width, size })), + _ => return Err(Error::Custom(format!("Cannot cast {}", value_expr))), + }; + let ty_expr = map_scalar(kind, width, builder.features)?; + + (Cow::Owned(format!("{}({})", ty_expr, value_expr)), out_ty) + } Expression::Derivative { axis, expr } => { let (expr, ty) = write_expression(&builder.expressions[expr], module, builder)?; @@ -1138,6 +1156,28 @@ fn write_constant( }) } +fn map_scalar( + kind: ScalarKind, + width: crate::Bytes, + features: SupportedFeatures, +) -> Result<&'static str, Error> { + Ok(match kind { + ScalarKind::Sint => "int", + ScalarKind::Uint => "uint", + ScalarKind::Float => match width { + 4 => "float", + 8 if features.contains(SupportedFeatures::DOUBLE_TYPE) => "double", + _ => { + return Err(Error::Custom(format!( + "Cannot build float of width {}", + width + ))) + } + }, + ScalarKind::Bool => "bool", + }) +} + fn write_type<'a>( ty: Handle, types: &Arena, @@ -1146,21 +1186,7 @@ fn write_type<'a>( features: SupportedFeatures, ) -> Result, Error> { Ok(match types[ty].inner { - TypeInner::Scalar { kind, width } => match kind { - ScalarKind::Sint => Cow::Borrowed("int"), - ScalarKind::Uint => Cow::Borrowed("uint"), - ScalarKind::Float => match width { - 4 => Cow::Borrowed("float"), - 8 if features.contains(SupportedFeatures::DOUBLE_TYPE) => Cow::Borrowed("double"), - _ => { - return Err(Error::Custom(format!( - "Cannot build float of width {}", - width - ))) - } - }, - ScalarKind::Bool => Cow::Borrowed("bool"), - }, + TypeInner::Scalar { kind, width } => Cow::Borrowed(map_scalar(kind, width, features)?), TypeInner::Vector { size, kind, width } => Cow::Owned(format!( "{}vec{}", match kind { diff --git a/src/front/spv/error.rs b/src/front/spv/error.rs index b467020b5a..0488a83ef9 100644 --- a/src/front/spv/error.rs +++ b/src/front/spv/error.rs @@ -44,6 +44,7 @@ pub enum Error { InvalidSampleSampler(Handle), InvalidSampleCoordinates(Handle), InvalidDepthReference(Handle), + InvalidAsType(Handle), InconsistentComparisonSampling(Handle), WrongFunctionResultType(spirv::Word), WrongFunctionParameterType(spirv::Word), diff --git a/src/front/spv/mod.rs b/src/front/spv/mod.rs index b4ab8c9056..47e4f62499 100644 --- a/src/front/spv/mod.rs +++ b/src/front/spv/mod.rs @@ -1009,6 +1009,29 @@ impl> Parser { }, ); } + Op::ConvertSToF | Op::ConvertUToF | Op::ConvertFToU | Op::ConvertFToS => { + inst.expect_at_least(4)?; + let result_type_id = self.next()?; + let result_id = self.next()?; + let value_id = self.next()?; + + let value_expr = self.lookup_expression.lookup(value_id)?; + let ty_lookup = self.lookup_type.lookup(result_type_id)?; + let kind = match type_arena[ty_lookup.handle].inner { + crate::TypeInner::Scalar { kind, .. } + | crate::TypeInner::Vector { kind, .. } => kind, + _ => return Err(Error::InvalidAsType(ty_lookup.handle)), + }; + + let expr = crate::Expression::As(value_expr.handle, kind); + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: expressions.append(expr), + type_id: result_type_id, + }, + ); + } Op::FunctionCall => { inst.expect_at_least(4)?; let result_type_id = self.next()?; diff --git a/src/lib.rs b/src/lib.rs index 2edbd316e1..8dec8ff0d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -526,6 +526,8 @@ pub enum Expression { DotProduct(Handle, Handle), /// Cross product between two vectors. CrossProduct(Handle, Handle), + /// Cast a scalar or a vector to another kind. + As(Handle, ScalarKind), /// Compute the derivative on an axis. Derivative { axis: DerivativeAxis, diff --git a/src/proc/interface.rs b/src/proc/interface.rs index 3eae87126e..015dd51ce8 100644 --- a/src/proc/interface.rs +++ b/src/proc/interface.rs @@ -80,6 +80,9 @@ impl<'a> Interface<'a> { self.add_inputs(left); self.add_inputs(right); } + E::As(expr, _) => { + self.add_inputs(expr); + } E::Derivative { expr, .. } => { self.add_inputs(expr); } diff --git a/src/proc/typifier.rs b/src/proc/typifier.rs index 3fc2e3e4f8..e5c5a40060 100644 --- a/src/proc/typifier.rs +++ b/src/proc/typifier.rs @@ -182,8 +182,34 @@ impl Typifier { }; types.fetch_or_append(Type { name: None, inner }) } - crate::Expression::DotProduct(_, _) => unimplemented!(), + crate::Expression::DotProduct(left_expr, _) => { + let left_ty = self.types[left_expr.index()]; + let inner = match types[left_ty].inner { + crate::TypeInner::Vector { + kind, + size: _, + width, + } => crate::TypeInner::Scalar { kind, width }, + ref other => panic!("incompatible dot of {:?}", other), + }; + types.fetch_or_append(Type { name: None, inner }) + } crate::Expression::CrossProduct(_, _) => unimplemented!(), + crate::Expression::As(expr, kind) => { + let ty_handle = self.types[expr.index()]; + let inner = match types[ty_handle].inner { + crate::TypeInner::Scalar { kind: _, width } => { + crate::TypeInner::Scalar { kind, width } + } + crate::TypeInner::Vector { + kind: _, + size, + width, + } => crate::TypeInner::Vector { kind, size, width }, + ref other => panic!("incompatible as of {:?}", other), + }; + types.fetch_or_append(Type { name: None, inner }) + } crate::Expression::Derivative { .. } => unimplemented!(), crate::Expression::Call { origin: crate::FunctionOrigin::External(ref name),