From 6480370a19a0f32cf87323b83b97d65833b1590e Mon Sep 17 00:00:00 2001 From: Pelle Johnsen Date: Tue, 3 Nov 2020 21:18:30 +0100 Subject: [PATCH] [spv-out] Handle ImageSample (#261) --- src/back/spv/instructions.rs | 34 ++++++++ src/back/spv/writer.rs | 153 +++++++++++++++++++++++++++++++++-- 2 files changed, 180 insertions(+), 7 deletions(-) diff --git a/src/back/spv/instructions.rs b/src/back/spv/instructions.rs index 077522e917..a69c09b377 100644 --- a/src/back/spv/instructions.rs +++ b/src/back/spv/instructions.rs @@ -235,6 +235,13 @@ pub(super) fn instruction_type_sampler(id: Word) -> Instruction { instruction } +pub(super) fn instruction_type_sampled_image(id: Word, image_type_id: Word) -> Instruction { + let mut instruction = Instruction::new(Op::TypeSampledImage); + instruction.set_result(id); + instruction.add_operand(image_type_id); + instruction +} + pub(super) fn instruction_type_array( id: Word, element_type_id: Word, @@ -449,6 +456,33 @@ pub(super) fn instruction_function_call( // // Image Instructions // +pub(super) fn instruction_sampled_image( + result_type_id: Word, + id: Word, + image: Word, + sampler: Word, +) -> Instruction { + let mut instruction = Instruction::new(Op::SampledImage); + instruction.set_type(result_type_id); + instruction.set_result(id); + instruction.add_operand(image); + instruction.add_operand(sampler); + instruction +} + +pub(super) fn instruction_image_sample_implicit_lod( + result_type_id: Word, + id: Word, + sampled_image: Word, + coordinates: Word, +) -> Instruction { + let mut instruction = Instruction::new(Op::ImageSampleImplicitLod); + instruction.set_type(result_type_id); + instruction.set_result(id); + instruction.add_operand(sampled_image); + instruction.add_operand(coordinates); + instruction +} // // Conversion Instructions diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index b0e0a400c6..159869bec6 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -10,6 +10,12 @@ const BITS_PER_BYTE: crate::Bytes = 8; pub enum Error { #[error("can't find local variable: {0:?}")] UnknownLocalVariable(crate::LocalVariable), + #[error("bad image class for op: {0:?}")] + BadImageClass(crate::ImageClass), + #[error("not an image")] + NotImage, + #[error("empty value")] + EmptyValue, } struct Block { @@ -86,6 +92,9 @@ enum LocalType { base: crate::Handle, class: spirv::StorageClass, }, + SampledImage { + image_type: crate::Handle, + }, } #[derive(Debug, PartialEq, Hash, Eq, Copy, Clone)] @@ -447,6 +456,10 @@ impl Writer { super::instructions::instruction_type_vector(id, scalar_id, size) } LocalType::Pointer { .. } => unimplemented!(), + LocalType::SampledImage { image_type } => { + let image_type_id = self.get_type_id(arena, LookupType::Handle(image_type)); + super::instructions::instruction_type_sampled_image(id, image_type_id) + } }; self.lookup_type.insert(LookupType::Local(local_ty), id); @@ -499,17 +512,14 @@ impl Writer { } => { let width = 4; let local_type = match class { - crate::ImageClass::Sampled { kind, multi: _ } => LocalType::Vector { - size: crate::VectorSize::Quad, - kind, - width, - }, + crate::ImageClass::Sampled { kind, multi: _ } => { + LocalType::Scalar { kind, width } + } crate::ImageClass::Depth => LocalType::Scalar { kind: crate::ScalarKind::Float, width, }, - crate::ImageClass::Storage(format) => LocalType::Vector { - size: crate::VectorSize::Quad, + crate::ImageClass::Storage(format) => LocalType::Scalar { kind: format.into(), width, }, @@ -1189,6 +1199,135 @@ impl Writer { Ok(Some((id, None))) } + crate::Expression::ImageSample { + image, + sampler, + coordinate, + level: _, + depth_ref: _, + } => { + // image + let image_expression = &ir_function.expressions[*image]; + let (image_id, image_ty) = self + .write_expression(ir_module, ir_function, image_expression, block, function)? + .ok_or(Error::EmptyValue)?; + let image_ty = image_ty.ok_or(Error::EmptyValue)?; + let image_result_type_id = + self.get_type_id(&ir_module.types, LookupType::Handle(image_ty)); + let image_id = match *image_expression { + crate::Expression::LocalVariable(_) | crate::Expression::GlobalVariable(_) => { + let load_id = self.generate_id(); + block.body.push(super::instructions::instruction_load( + image_result_type_id, + load_id, + image_id, + None, + )); + load_id + } + _ => image_id, + }; + + // OpTypeSampledImage + let sampled_image_type_id = self.get_type_id( + &ir_module.types, + LookupType::Local(LocalType::SampledImage { + image_type: image_ty, + }), + ); + + // sampler + let sampler_expression = &ir_function.expressions[*sampler]; + let (sampler_id, sampler_ty) = self + .write_expression(ir_module, ir_function, sampler_expression, block, function)? + .ok_or(Error::EmptyValue)?; + let sampler_ty = sampler_ty.ok_or(Error::EmptyValue)?; + let sampler_result_type_id = + self.get_type_id(&ir_module.types, LookupType::Handle(sampler_ty)); + let sampler_id = match *sampler_expression { + crate::Expression::LocalVariable(_) | crate::Expression::GlobalVariable(_) => { + let load_id = self.generate_id(); + block.body.push(super::instructions::instruction_load( + sampler_result_type_id, + load_id, + sampler_id, + None, + )); + load_id + } + _ => sampler_id, + }; + + // coordinate + let coordinate_expression = &ir_function.expressions[*coordinate]; + let (coordinate_id, coordinate_ty) = self + .write_expression( + ir_module, + ir_function, + coordinate_expression, + block, + function, + )? + .ok_or(Error::EmptyValue)?; + let coordinate_ty = coordinate_ty.ok_or(Error::EmptyValue)?; + let coordinate_result_type_id = + self.get_type_id(&ir_module.types, LookupType::Handle(coordinate_ty)); + let coordinate_id = match *coordinate_expression { + crate::Expression::LocalVariable(_) | crate::Expression::GlobalVariable(_) => { + let load_id = self.generate_id(); + block.body.push(super::instructions::instruction_load( + coordinate_result_type_id, + load_id, + coordinate_id, + None, + )); + load_id + } + _ => coordinate_id, + }; + + // component kind + let image_type = &ir_module.types[image_ty]; + let image_sample_result_type = + if let crate::TypeInner::Image { class, .. } = image_type.inner { + let width = 4; + let local_type = match class { + crate::ImageClass::Sampled { kind, multi: _ } => LocalType::Vector { + kind, + width, + size: crate::VectorSize::Quad, + }, + crate::ImageClass::Depth => LocalType::Scalar { + kind: crate::ScalarKind::Float, + width, + }, + _ => return Err(Error::BadImageClass(class)), + }; + self.get_type_id(&ir_module.types, LookupType::Local(local_type)) + } else { + return Err(Error::NotImage); + }; + + let sampled_image_id = self.generate_id(); + block + .body + .push(super::instructions::instruction_sampled_image( + sampled_image_type_id, + sampled_image_id, + image_id, + sampler_id, + )); + let id = self.generate_id(); + block + .body + .push(super::instructions::instruction_image_sample_implicit_lod( + image_sample_result_type, + id, + sampled_image_id, + coordinate_id, + )); + Ok(Some((id, None))) + } _ => unimplemented!("{:?}", expression), } }