From 5d6406b0184c62cbae605ccbb5b8536cbc7e661b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 3 Jul 2020 18:27:16 -0400 Subject: [PATCH] Add DepthImage IR type. Fix all the usage of Bytes type to really mean bytes. Have logic in the SPIR-V front-end to detect the comparison properties of samplers and images. --- src/arena.rs | 5 + src/back/msl.rs | 57 +++++++-- src/back/spv/writer.rs | 47 ++++--- src/front/glsl/helpers.rs | 70 +++++------ src/front/glsl/mod.rs | 25 ++-- src/front/spv.rs | 253 +++++++++++++++++++++++++++++++++----- src/front/wgsl.rs | 16 +-- src/lib.rs | 31 ++--- src/proc/interface.rs | 4 + src/proc/validator.rs | 4 +- 10 files changed, 380 insertions(+), 132 deletions(-) diff --git a/src/arena.rs b/src/arena.rs index 0a5706ac3b..66cf171ef0 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -139,6 +139,11 @@ impl Arena { self.append(value) } } + + /// Get a mutable reference to an element in the arena. + pub fn mutate(&mut self, handle: Handle) -> &mut T { + self.data.get_mut(handle.index.get() as usize - 1).unwrap() + } } impl std::ops::Index> for Arena { diff --git a/src/back/msl.rs b/src/back/msl.rs index acd2a13238..f3d909b0ca 100644 --- a/src/back/msl.rs +++ b/src/back/msl.rs @@ -100,6 +100,15 @@ enum LocationMode { Uniform, } +fn dim_str(dim: crate::ImageDimension) -> &'static str { + match dim { + crate::ImageDimension::D1 => "1d", + crate::ImageDimension::D2 => "2d", + crate::ImageDimension::D3 => "3d", + crate::ImageDimension::Cube => "Cube", + } +} + #[derive(Debug, Clone, Copy)] pub struct Options<'a> { pub binding_map: &'a BindingMap, @@ -605,6 +614,7 @@ impl Writer { image, sampler, coordinate, + depth_ref: None, } => { let ty_image = self.put_expression(image, function, module)?; write!(self.out, ".sample(")?; @@ -617,6 +627,25 @@ impl Writer { ref other => Err(Error::UnexpectedImageType(other.clone())), } } + crate::Expression::ImageSample { + image, + sampler, + coordinate, + depth_ref: Some(dref), + } => { + self.put_expression(image, function, module)?; + write!(self.out, ".sample_compare(")?; + self.put_expression(sampler, function, module)?; + write!(self.out, ", ")?; + self.put_expression(coordinate, function, module)?; + write!(self.out, ", ")?; + self.put_expression(dref, function, module)?; + write!(self.out, ")")?; + Ok(MaybeOwned::Owned(crate::TypeInner::Scalar { + kind: crate::ScalarKind::Float, + width: 4, + })) + } crate::Expression::Call { ref name, ref arguments, @@ -887,11 +916,16 @@ impl Writer { } crate::TypeInner::Image { base, dim, flags } => { let base_name = module.types[base].name.or_index(base); - let dim = match dim { - crate::ImageDimension::D1 => "1d", - crate::ImageDimension::D2 => "2d", - crate::ImageDimension::D3 => "3d", - crate::ImageDimension::Cube => "Cube", + let dim_str = dim_str(dim); + let msaa_str = if flags.contains(crate::ImageFlags::MULTISAMPLED) { + "_ms" + } else { + "" + }; + let array_str = if flags.contains(crate::ImageFlags::ARRAYED) { + "_array" + } else { + "" }; let access = if flags.contains(crate::ImageFlags::SAMPLED) { if flags.intersects(crate::ImageFlags::CAN_STORE) { @@ -911,8 +945,17 @@ impl Writer { }; write!( self.out, - "typedef texture{}<{}, access::{}> {}", - dim, base_name, access, name + "typedef texture{}{}{}<{}, access::{}> {}", + dim_str, msaa_str, array_str, base_name, access, name + )?; + } + crate::TypeInner::DepthImage { dim, arrayed } => { + let dim_str = dim_str(dim); + let array_str = if arrayed { "_array" } else { "" }; + write!( + self.out, + "typedef depth{}{} {}", + dim_str, array_str, name )?; } crate::TypeInner::Sampler { comparison: _ } => { diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index e8e76e1e2d..a456d3cd5f 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -40,6 +40,15 @@ impl LookupHelper for FastHashMap> { } } +fn map_dim(dim: crate::ImageDimension) -> spirv::Dim { + match dim { + crate::ImageDimension::D1 => spirv::Dim::Dim1D, + crate::ImageDimension::D2 => spirv::Dim::Dim2D, + crate::ImageDimension::D3 => spirv::Dim::Dim2D, + crate::ImageDimension::Cube => spirv::Dim::DimCube, + } +} + #[derive(Debug, PartialEq)] struct LookupFunctionType { parameter_type_ids: Vec, @@ -413,14 +422,14 @@ impl Writer { sampled_type_id: Word, dim: spirv::Dim, flags: ImageFlags, + comparison: bool, ) -> Instruction { let mut instruction = Instruction::new(Op::TypeImage); instruction.set_result(id); instruction.add_operand(sampled_type_id); instruction.add_operand(dim as u32); - // TODO Add Depth, but how to determine? Not yet in the WGSL spec - instruction.add_operand(1); + instruction.add_operand(if comparison { 1 } else { 0 }); instruction.add_operand(if flags.contains(crate::ImageFlags::ARRAYED) { 1 @@ -765,17 +774,25 @@ impl Writer { } crate::TypeInner::Image { base, dim, flags } => { let type_id = self.get_type_id(arena, base); - let dim = match dim { - crate::ImageDimension::D1 => spirv::Dim::Dim1D, - crate::ImageDimension::D2 => spirv::Dim::Dim2D, - crate::ImageDimension::D3 => spirv::Dim::Dim2D, - crate::ImageDimension::Cube => spirv::Dim::DimCube, - }; + let dim = map_dim(dim); self.try_add_capabilities(dim.required_capabilities()); - instruction = self.instruction_type_image(id, type_id, dim, flags); + instruction = self.instruction_type_image(id, type_id, dim, flags, false); self.lookup_type.insert(id, base); } + crate::TypeInner::DepthImage { dim, arrayed } => { + let type_id = 0; //TODO! + let dim = map_dim(dim); + self.try_add_capabilities(dim.required_capabilities()); + + let flags = if arrayed { + crate::ImageFlags::ARRAYED + } else { + crate::ImageFlags::empty() + }; + instruction = self.instruction_type_image(id, type_id, dim, flags, true); + //self.lookup_type.insert(id, base); + } crate::TypeInner::Sampler { comparison: _ } => { instruction = self.instruction_type_sampler(id); self.lookup_type.insert(id, handle); @@ -845,8 +862,8 @@ impl Writer { let instruction = match ty.inner { crate::TypeInner::Scalar { kind: _, width } => match width { - 32 => self.instruction_constant(type_id, id, &[val as u32]), - 64 => { + 4 => self.instruction_constant(type_id, id, &[val as u32]), + 8 => { let (low, high) = ((val >> 32) as u32, val as u32); self.instruction_constant(type_id, id, &[low, high]) } @@ -862,8 +879,8 @@ impl Writer { let instruction = match ty.inner { crate::TypeInner::Scalar { kind: _, width } => match width { - 32 => self.instruction_constant(type_id, id, &[val as u32]), - 64 => { + 4 => self.instruction_constant(type_id, id, &[val as u32]), + 8 => { let (low, high) = ((val >> 32) as u32, val as u32); self.instruction_constant(type_id, id, &[low, high]) } @@ -880,8 +897,8 @@ impl Writer { let instruction = match ty.inner { crate::TypeInner::Scalar { kind: _, width } => match width { - 32 => self.instruction_constant(type_id, id, &[(val as f32).to_bits()]), - 64 => { + 4 => self.instruction_constant(type_id, id, &[(val as f32).to_bits()]), + 8 => { let bits = f64::to_bits(val); let (low, high) = ((bits >> 32) as u32, bits as u32); self.instruction_constant(type_id, id, &[low, high]) diff --git a/src/front/glsl/helpers.rs b/src/front/glsl/helpers.rs index ea1b1e5b52..1a43ed973a 100644 --- a/src/front/glsl/helpers.rs +++ b/src/front/glsl/helpers.rs @@ -47,49 +47,49 @@ pub fn glsl_to_spirv_type(ty: TypeSpecifierNonArray, types: &mut Arena) -> }, Int => TypeInner::Scalar { kind: ScalarKind::Sint, - width: 32, + width: 4, }, UInt => TypeInner::Scalar { kind: ScalarKind::Uint, - width: 32, + width: 4, }, Float => TypeInner::Scalar { kind: ScalarKind::Float, - width: 32, + width: 4, }, Double => TypeInner::Scalar { kind: ScalarKind::Float, - width: 64, + width: 8, }, Vec2 => TypeInner::Vector { size: VectorSize::Bi, kind: ScalarKind::Float, - width: 32, + width: 4, }, Vec3 => TypeInner::Vector { size: VectorSize::Tri, kind: ScalarKind::Float, - width: 32, + width: 4, }, Vec4 => TypeInner::Vector { size: VectorSize::Quad, kind: ScalarKind::Float, - width: 32, + width: 4, }, DVec2 => TypeInner::Vector { size: VectorSize::Bi, kind: ScalarKind::Float, - width: 64, + width: 8, }, DVec3 => TypeInner::Vector { size: VectorSize::Tri, kind: ScalarKind::Float, - width: 64, + width: 8, }, DVec4 => TypeInner::Vector { size: VectorSize::Quad, kind: ScalarKind::Float, - width: 64, + width: 8, }, BVec2 => TypeInner::Vector { size: VectorSize::Bi, @@ -109,142 +109,142 @@ pub fn glsl_to_spirv_type(ty: TypeSpecifierNonArray, types: &mut Arena) -> IVec2 => TypeInner::Vector { size: VectorSize::Bi, kind: ScalarKind::Sint, - width: 32, + width: 4, }, IVec3 => TypeInner::Vector { size: VectorSize::Tri, kind: ScalarKind::Sint, - width: 32, + width: 4, }, IVec4 => TypeInner::Vector { size: VectorSize::Quad, kind: ScalarKind::Sint, - width: 32, + width: 4, }, UVec2 => TypeInner::Vector { size: VectorSize::Bi, kind: ScalarKind::Uint, - width: 32, + width: 4, }, UVec3 => TypeInner::Vector { size: VectorSize::Tri, kind: ScalarKind::Uint, - width: 32, + width: 4, }, UVec4 => TypeInner::Vector { size: VectorSize::Quad, kind: ScalarKind::Uint, - width: 32, + width: 4, }, // Float Matrices Mat2 => TypeInner::Matrix { columns: VectorSize::Bi, rows: VectorSize::Bi, kind: ScalarKind::Float, - width: 32, + width: 4, }, Mat3 => TypeInner::Matrix { columns: VectorSize::Tri, rows: VectorSize::Tri, kind: ScalarKind::Float, - width: 32, + width: 4, }, Mat4 => TypeInner::Matrix { columns: VectorSize::Quad, rows: VectorSize::Quad, kind: ScalarKind::Float, - width: 32, + width: 4, }, Mat23 => TypeInner::Matrix { columns: VectorSize::Bi, rows: VectorSize::Tri, kind: ScalarKind::Float, - width: 32, + width: 4, }, Mat24 => TypeInner::Matrix { columns: VectorSize::Bi, rows: VectorSize::Quad, kind: ScalarKind::Float, - width: 32, + width: 4, }, Mat32 => TypeInner::Matrix { columns: VectorSize::Tri, rows: VectorSize::Bi, kind: ScalarKind::Float, - width: 32, + width: 4, }, Mat34 => TypeInner::Matrix { columns: VectorSize::Tri, rows: VectorSize::Quad, kind: ScalarKind::Float, - width: 32, + width: 4, }, Mat42 => TypeInner::Matrix { columns: VectorSize::Quad, rows: VectorSize::Bi, kind: ScalarKind::Float, - width: 32, + width: 4, }, Mat43 => TypeInner::Matrix { columns: VectorSize::Quad, rows: VectorSize::Tri, kind: ScalarKind::Float, - width: 32, + width: 4, }, // Double Matrices DMat2 => TypeInner::Matrix { columns: VectorSize::Bi, rows: VectorSize::Bi, kind: ScalarKind::Float, - width: 64, + width: 8, }, DMat3 => TypeInner::Matrix { columns: VectorSize::Tri, rows: VectorSize::Tri, kind: ScalarKind::Float, - width: 64, + width: 8, }, DMat4 => TypeInner::Matrix { columns: VectorSize::Quad, rows: VectorSize::Quad, kind: ScalarKind::Float, - width: 64, + width: 8, }, DMat23 => TypeInner::Matrix { columns: VectorSize::Bi, rows: VectorSize::Tri, kind: ScalarKind::Float, - width: 64, + width: 8, }, DMat24 => TypeInner::Matrix { columns: VectorSize::Bi, rows: VectorSize::Quad, kind: ScalarKind::Float, - width: 64, + width: 8, }, DMat32 => TypeInner::Matrix { columns: VectorSize::Tri, rows: VectorSize::Bi, kind: ScalarKind::Float, - width: 64, + width: 8, }, DMat34 => TypeInner::Matrix { columns: VectorSize::Tri, rows: VectorSize::Quad, kind: ScalarKind::Float, - width: 64, + width: 8, }, DMat42 => TypeInner::Matrix { columns: VectorSize::Quad, rows: VectorSize::Bi, kind: ScalarKind::Float, - width: 64, + width: 8, }, DMat43 => TypeInner::Matrix { columns: VectorSize::Quad, rows: VectorSize::Tri, kind: ScalarKind::Float, - width: 64, + width: 8, }, TypeName(ty_name) => { if let Some(t_pos) = ty_name.0.find("texture") { @@ -258,7 +258,7 @@ pub fn glsl_to_spirv_type(ty: TypeSpecifierNonArray, types: &mut Arena) -> name: None, inner: TypeInner::Scalar { kind: scalar_kind, - width: 32, + width: 4, }, }); diff --git a/src/front/glsl/mod.rs b/src/front/glsl/mod.rs index c5fa049508..0b2d661b5a 100644 --- a/src/front/glsl/mod.rs +++ b/src/front/glsl/mod.rs @@ -558,7 +558,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Sint, - width: 32, + width: 4, }, }), }), @@ -572,7 +572,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Sint, - width: 32, + width: 4, }, }), }), @@ -586,7 +586,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Sint, - width: 32, + width: 4, }, }), }), @@ -600,7 +600,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Sint, - width: 32, + width: 4, }, }), }), @@ -619,7 +619,7 @@ impl<'a> Parser<'a> { inner: TypeInner::Vector { size: VectorSize::Quad, kind: ScalarKind::Float, - width: 32, + width: 4, }, }), }, @@ -633,7 +633,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Float, - width: 32, + width: 4, }, }), }, @@ -647,7 +647,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Float, - width: 32, + width: 4, }, }), }), @@ -684,7 +684,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Sint, - width: 32, + width: 4, }, }), }, @@ -698,7 +698,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Uint, - width: 32, + width: 4, }, }), }, @@ -726,7 +726,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Float, - width: 32, + width: 4, }, }), }, @@ -740,7 +740,7 @@ impl<'a> Parser<'a> { name: None, inner: TypeInner::Scalar { kind: ScalarKind::Float, - width: 64, + width: 8, }, }), }, @@ -796,7 +796,7 @@ impl<'a> Parser<'a> { _ => panic!(), }, kind: ScalarKind::Float, - width: 32, + width: 4, }, }), components: args @@ -858,6 +858,7 @@ impl<'a> Parser<'a> { image: expressions.append(image), sampler: expressions.append(sampler), coordinate: expressions.append(coordinate), + depth_ref: None, //TODO }) } _ => Ok(Expression::Call { diff --git a/src/front/spv.rs b/src/front/spv.rs index 2d7e738c96..ae435eb691 100644 --- a/src/front/spv.rs +++ b/src/front/spv.rs @@ -52,6 +52,13 @@ pub enum Error { InvalidLoadType(spirv::Word), InvalidStoreType(spirv::Word), InvalidBinding(spirv::Word), + InvalidImageExpression(Handle), + InvalidSamplerExpression(Handle), + InvalidSampleImage(Handle), + InvalidSampleSampler(Handle), + InvalidSampleCoordinates(Handle), + InvalidDepthReference(Handle), + InconsistentComparisonSampling(Handle), WrongFunctionResultType(spirv::Word), WrongFunctionParameterType(spirv::Word), MissingDecoration(spirv::Decoration), @@ -145,6 +152,49 @@ fn map_image_dim(word: spirv::Word) -> Result { } } +fn map_width(word: spirv::Word) -> Result { + (word >> 3) // bits to bytes + .try_into() + .map_err(|_| Error::InvalidTypeWidth(word)) +} + +//TODO: this method may need to be gone, depending on whether +// WGSL allows treating images and samplers as expressions and pass them around. +fn reach_global_type( + expr_handle: Handle, + expressions: &Arena, + globals: &Arena, +) -> Option> { + match expressions[expr_handle] { + crate::Expression::GlobalVariable(var) => Some(globals[var].ty), + _ => None, + } +} + +fn check_sample_coordinates( + ty: &crate::Type, + expect_kind: crate::ScalarKind, + dim: crate::ImageDimension, + is_array: bool, +) -> bool { + let base_count = match dim { + crate::ImageDimension::D1 => 1, + crate::ImageDimension::D2 => 2, + crate::ImageDimension::D3 | crate::ImageDimension::Cube => 3, + }; + let extra_count = if is_array { 1 } else { 0 }; + let count = base_count + extra_count; + match ty.inner { + crate::TypeInner::Scalar { kind, width: _ } => count == 1 && kind == expect_kind, + crate::TypeInner::Vector { + size, + kind, + width: _, + } => size as u8 == count && kind == expect_kind, + _ => false, + } +} + type MemberIndex = u32; #[derive(Debug, Default)] @@ -194,6 +244,16 @@ impl Decoration { } } +bitflags::bitflags! { + /// Flags describing sampling method. + pub struct SamplingFlags: u32 { + /// Regular sampling. + const REGULAR = 0x1; + /// Comparison sampling. + const COMPARISON = 0x2; + } +} + #[derive(Debug)] struct LookupFunctionType { parameter_type_ids: Vec, @@ -245,8 +305,10 @@ pub struct Parser { future_decor: FastHashMap, future_member_decor: FastHashMap<(spirv::Word, MemberIndex), Decoration>, lookup_member_type_id: FastHashMap<(spirv::Word, MemberIndex), spirv::Word>, + handle_sampling: FastHashMap, SamplingFlags>, lookup_type: FastHashMap, lookup_void_type: FastHashSet, + // Lookup for samplers and sampled images, storing flags on how they are used. lookup_constant: FastHashMap, lookup_variable: FastHashMap, lookup_expression: FastHashMap, @@ -263,6 +325,7 @@ impl> Parser { temp_bytes: Vec::new(), future_decor: FastHashMap::default(), future_member_decor: FastHashMap::default(), + handle_sampling: FastHashMap::default(), lookup_member_type_id: FastHashMap::default(), lookup_type: FastHashMap::default(), lookup_void_type: FastHashSet::default(), @@ -385,6 +448,7 @@ impl> Parser { fun: &mut crate::Function, type_arena: &Arena, const_arena: &Arena, + global_arena: &Arena, ) -> Result<(), Error> { loop { use spirv::Op; @@ -726,23 +790,113 @@ impl> Parser { let coordinate_id = self.next()?; let si_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?; let coord_lexp = self.lookup_expression.lookup(coordinate_id)?; - let coord_type_lookup = self.lookup_type.lookup(coord_lexp.type_id)?; - match type_arena[coord_type_lookup.handle].inner { - crate::TypeInner::Scalar { - kind: crate::ScalarKind::Float, - .. + let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle; + + let sampler_type_handle = + reach_global_type(si_lexp.sampler, &fun.expressions, global_arena) + .ok_or(Error::InvalidSamplerExpression(si_lexp.sampler))?; + let image_type_handle = + reach_global_type(si_lexp.image, &fun.expressions, global_arena) + .ok_or(Error::InvalidImageExpression(si_lexp.image))?; + *self.handle_sampling.get_mut(&sampler_type_handle).unwrap() |= + SamplingFlags::REGULAR; + *self.handle_sampling.get_mut(&image_type_handle).unwrap() |= + SamplingFlags::REGULAR; + match type_arena[sampler_type_handle].inner { + crate::TypeInner::Sampler { comparison: false } => (), + _ => return Err(Error::InvalidSampleSampler(sampler_type_handle)), + }; + match type_arena[image_type_handle].inner { + //TODO: compare the result type + crate::TypeInner::Image { + base: _, + dim, + flags, + } if flags + & (crate::ImageFlags::MULTISAMPLED | crate::ImageFlags::SAMPLED) + == crate::ImageFlags::SAMPLED => + { + if !check_sample_coordinates( + &type_arena[coord_type_handle], + crate::ScalarKind::Float, + dim, + flags.contains(crate::ImageFlags::ARRAYED), + ) { + return Err(Error::InvalidSampleCoordinates(coord_type_handle)); + } } - | crate::TypeInner::Vector { - kind: crate::ScalarKind::Float, - .. - } => (), - _ => return Err(Error::UnsupportedType(coord_type_lookup.handle)), - } - //TODO: compare the result type + _ => return Err(Error::InvalidSampleImage(image_type_handle)), + }; + let expr = crate::Expression::ImageSample { image: si_lexp.image, sampler: si_lexp.sampler, coordinate: coord_lexp.handle, + depth_ref: None, + }; + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: fun.expressions.append(expr), + type_id: result_type_id, + }, + ); + } + Op::ImageSampleDrefImplicitLod => { + inst.expect_at_least(6)?; + let result_type_id = self.next()?; + let result_id = self.next()?; + let sampled_image_id = self.next()?; + let coordinate_id = self.next()?; + let dref_id = self.next()?; + + let si_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?; + let coord_lexp = self.lookup_expression.lookup(coordinate_id)?; + let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle; + let sampler_type_handle = + reach_global_type(si_lexp.sampler, &fun.expressions, global_arena) + .ok_or(Error::InvalidSamplerExpression(si_lexp.sampler))?; + let image_type_handle = + reach_global_type(si_lexp.image, &fun.expressions, global_arena) + .ok_or(Error::InvalidImageExpression(si_lexp.image))?; + *self.handle_sampling.get_mut(&sampler_type_handle).unwrap() |= + SamplingFlags::COMPARISON; + *self.handle_sampling.get_mut(&image_type_handle).unwrap() |= + SamplingFlags::COMPARISON; + match type_arena[sampler_type_handle].inner { + crate::TypeInner::Sampler { comparison: true } => (), + _ => return Err(Error::InvalidSampleSampler(sampler_type_handle)), + }; + match type_arena[image_type_handle].inner { + //TODO: compare the result type + crate::TypeInner::DepthImage { dim, arrayed } => { + if !check_sample_coordinates( + &type_arena[coord_type_handle], + crate::ScalarKind::Float, + dim, + arrayed, + ) { + return Err(Error::InvalidSampleCoordinates(coord_type_handle)); + } + } + _ => return Err(Error::InvalidSampleImage(image_type_handle)), + }; + + let dref_lexp = self.lookup_expression.lookup(dref_id)?; + let dref_type_handle = self.lookup_type.lookup(dref_lexp.type_id)?.handle; + match type_arena[dref_type_handle].inner { + crate::TypeInner::Scalar { + kind: crate::ScalarKind::Float, + width: _, + } => (), + _ => return Err(Error::InvalidDepthReference(dref_type_handle)), + } + + let expr = crate::Expression::ImageSample { + image: si_lexp.image, + sampler: si_lexp.sampler, + coordinate: coord_lexp.handle, + depth_ref: Some(dref_lexp.handle), }; self.lookup_expression.insert( result_id, @@ -847,6 +1001,34 @@ impl> Parser { }?; } + // Check all the images and samplers to have consistent comparison property. + for (handle, flags) in self.handle_sampling.drain() { + if !flags.contains(SamplingFlags::COMPARISON) { + continue; + } + if flags == SamplingFlags::all() { + return Err(Error::InconsistentComparisonSampling(handle)); + } + let ty = module.types.mutate(handle); + match ty.inner { + crate::TypeInner::Sampler { ref mut comparison } => { + assert!(!*comparison); + *comparison = true; + } + crate::TypeInner::Image { + base: _, + dim, + flags, + } => { + ty.inner = crate::TypeInner::DepthImage { + dim, + arrayed: flags.contains(crate::ImageFlags::ARRAYED), + }; + } + _ => panic!("Unexpected comparison type {:?}", ty), + } + } + if !self.future_decor.is_empty() { log::warn!("Unused item decorations: {:?}", self.future_decor); self.future_decor.clear(); @@ -1044,9 +1226,7 @@ impl> Parser { 1 => crate::ScalarKind::Sint, _ => return Err(Error::InvalidSign(sign)), }, - width: width - .try_into() - .map_err(|_| Error::InvalidTypeWidth(width))?, + width: map_width(width)?, }; self.lookup_type.insert( id, @@ -1072,9 +1252,7 @@ impl> Parser { let width = self.next()?; let inner = crate::TypeInner::Scalar { kind: crate::ScalarKind::Float, - width: width - .try_into() - .map_err(|_| Error::InvalidTypeWidth(width))?, + width: map_width(width)?, }; self.lookup_type.insert( id, @@ -1346,13 +1524,15 @@ impl> Parser { dim: map_image_dim(dim)?, flags, }; + let handle = module.types.append(crate::Type { + name: decor.name, + inner, + }); + self.handle_sampling.insert(handle, SamplingFlags::empty()); self.lookup_type.insert( id, LookupType { - handle: module.types.append(crate::Type { - name: decor.name, - inner, - }), + handle, base_id: Some(sample_type_id), }, ); @@ -1383,14 +1563,18 @@ impl> Parser { inst.expect(2)?; let id = self.next()?; let decor = self.future_decor.remove(&id).unwrap_or_default(); - let inner = crate::TypeInner::Sampler { comparison: false }; //TODO! + // The comparison bit is temporary, will be overwritten based on the + // accumulated sampling flags at the end. + let inner = crate::TypeInner::Sampler { comparison: false }; + let handle = module.types.append(crate::Type { + name: decor.name, + inner, + }); + self.handle_sampling.insert(handle, SamplingFlags::empty()); self.lookup_type.insert( id, LookupType { - handle: module.types.append(crate::Type { - name: decor.name, - inner, - }), + handle, base_id: None, }, ); @@ -1414,7 +1598,7 @@ impl> Parser { width, } => { let low = self.next()?; - let high = if width > 32 { + let high = if width > 4 { inst.expect(4)?; self.next()? } else { @@ -1428,7 +1612,7 @@ impl> Parser { } => { use std::cmp::Ordering; let low = self.next()?; - let high = match width.cmp(&32) { + let high = match width.cmp(&4) { Ordering::Less => return Err(Error::InvalidTypeWidth(u32::from(width))), Ordering::Greater => { inst.expect(4)?; @@ -1444,8 +1628,8 @@ impl> Parser { } => { let low = self.next()?; let extended = match width { - 32 => f64::from(f32::from_bits(low)), - 64 => { + 4 => f64::from(f32::from_bits(low)), + 8 => { inst.expect(4)?; let high = self.next()?; f64::from_bits((u64::from(high) << 32) | u64::from(low)) @@ -1635,7 +1819,12 @@ impl> Parser { spirv::Op::Label => { fun_inst.expect(2)?; let _id = self.next()?; - self.next_block(&mut fun, &module.types, &module.constants)?; + self.next_block( + &mut fun, + &module.types, + &module.constants, + &module.global_variables, + )?; } spirv::Op::FunctionEnd => { fun_inst.expect(1)?; diff --git a/src/front/wgsl.rs b/src/front/wgsl.rs index 15632b10b3..c12a10b2e6 100644 --- a/src/front/wgsl.rs +++ b/src/front/wgsl.rs @@ -232,12 +232,12 @@ impl<'a> Lexer<'a> { } } - fn next_scalar_generic(&mut self) -> Result<(crate::ScalarKind, u8), Error<'a>> { + fn next_scalar_generic(&mut self) -> Result<(crate::ScalarKind, crate::Bytes), Error<'a>> { self.expect(Token::Paren('<'))?; let pair = match self.next() { - Token::Word("f32") => (crate::ScalarKind::Float, 32), - Token::Word("i32") => (crate::ScalarKind::Sint, 32), - Token::Word("u32") => (crate::ScalarKind::Uint, 32), + Token::Word("f32") => (crate::ScalarKind::Float, 4), + Token::Word("i32") => (crate::ScalarKind::Sint, 4), + Token::Word("u32") => (crate::ScalarKind::Uint, 4), other => return Err(Error::Unexpected(other)), }; self.expect(Token::Paren('>'))?; @@ -524,7 +524,7 @@ impl Parser { specialization: None, inner, ty: Typifier::deduce_type_handle( - crate::TypeInner::Scalar { kind, width: 32 }, + crate::TypeInner::Scalar { kind, width: 4 }, ctx.types, ), }); @@ -991,15 +991,15 @@ impl Parser { let inner = match lexer.next() { Token::Word("f32") => crate::TypeInner::Scalar { kind: crate::ScalarKind::Float, - width: 32, + width: 4, }, Token::Word("i32") => crate::TypeInner::Scalar { kind: crate::ScalarKind::Sint, - width: 32, + width: 4, }, Token::Word("u32") => crate::TypeInner::Scalar { kind: crate::ScalarKind::Uint, - width: 32, + width: 4, }, Token::Word("vec2") => { let (kind, width) = lexer.next_scalar_generic()?; diff --git a/src/lib.rs b/src/lib.rs index 49e4703e40..7463e1bc40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,10 +175,7 @@ pub struct Type { #[derive(Clone, Debug, PartialEq)] pub enum TypeInner { /// Number of integral or floating-point kind. - Scalar { - kind: ScalarKind, - width: Bytes, - }, + Scalar { kind: ScalarKind, width: Bytes }, /// Vector of numbers. Vector { size: VectorSize, @@ -204,19 +201,17 @@ pub enum TypeInner { stride: Option, }, /// User-defined structure. - Struct { - members: Vec, - }, - /// Possibly multidimensional array of pixels. + Struct { members: Vec }, + /// Possibly multidimensional array of texels. Image { base: Handle, dim: ImageDimension, flags: ImageFlags, }, + /// Depth-comparison image. + DepthImage { dim: ImageDimension, arrayed: bool }, /// Can be used to sample values from images. - Sampler { - comparison: bool, - }, + Sampler { comparison: bool }, } /// Constant value. @@ -361,14 +356,13 @@ pub enum Expression { /// Reference a local variable. LocalVariable(Handle), /// Load a value indirectly. - Load { - pointer: Handle, - }, + Load { pointer: Handle }, /// Sample a point from an image. ImageSample { image: Handle, sampler: Handle, coordinate: Handle, + depth_ref: Option>, }, /// Apply an unary operator. Unary { @@ -432,19 +426,14 @@ pub enum Statement { default: Block, }, /// Executes a block repeatedly. - Loop { - body: Block, - continuing: Block, - }, + Loop { body: Block, continuing: Block }, //TODO: move terminator variations into a separate enum? /// Exits the loop. Break, /// Skips execution to the next iteration of the loop. Continue, /// Returns from the function (possibly with a value). - Return { - value: Option>, - }, + Return { value: Option> }, /// Aborts the current shader execution. Kill, /// Stores a value at an address. diff --git a/src/proc/interface.rs b/src/proc/interface.rs index e441064092..7459248ea2 100644 --- a/src/proc/interface.rs +++ b/src/proc/interface.rs @@ -34,10 +34,14 @@ impl<'a> Interface<'a> { image, sampler, coordinate, + depth_ref, } => { self.add_inputs(image); self.add_inputs(sampler); self.add_inputs(coordinate); + if let Some(dref) = depth_ref { + self.add_inputs(dref); + } } E::Unary { expr, .. } => { self.add_inputs(expr); diff --git a/src/proc/validator.rs b/src/proc/validator.rs index 7976386fe0..576baea68b 100644 --- a/src/proc/validator.rs +++ b/src/proc/validator.rs @@ -26,7 +26,7 @@ impl Validator { Ti::Scalar { kind, width } | Ti::Vector { kind, width, .. } | Ti::Matrix { kind, width, .. } => { - if width != 32 { + if width != 4 { return Err(ValidationError::InvalidTypeWidth(kind, width)); } } @@ -48,7 +48,7 @@ impl Validator { } } } - Ti::Image { .. } => {} + Ti::Image { .. } | Ti::DepthImage { .. } => {} Ti::Sampler { comparison: _ } => {} } }