From cf0a86afd4a6bbfdffcb90d8f4504bfa72f0b636 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 8 Feb 2021 12:13:12 -0500 Subject: [PATCH] [spv-in] move all the image-related logic into a sub-module --- src/front/spv/function.rs | 13 +- src/front/spv/image.rs | 511 ++++++++++++++++++++++++++++++++++++ src/front/spv/mod.rs | 529 +++----------------------------------- 3 files changed, 549 insertions(+), 504 deletions(-) create mode 100644 src/front/spv/image.rs diff --git a/src/front/spv/function.rs b/src/front/spv/function.rs index 78e87f677d..c0283eb23c 100644 --- a/src/front/spv/function.rs +++ b/src/front/spv/function.rs @@ -1,7 +1,6 @@ -use crate::arena::Handle; +use crate::arena::{Arena, Handle}; -use super::flow::*; -use super::*; +use super::{flow::*, Error, Instruction, LookupExpression, LookupHelper as _}; pub type BlockId = u32; @@ -50,13 +49,7 @@ pub enum Terminator { } impl> super::Parser { - pub fn parse_function( - &mut self, - inst: Instruction, - module: &mut crate::Module, - ) -> Result<(), Error> { - self.switch(ModuleState::Function, inst.op)?; - inst.expect(5)?; + pub fn parse_function(&mut self, module: &mut crate::Module) -> Result<(), Error> { let result_type_id = self.next()?; let fun_id = self.next()?; let _fun_control = self.next()?; diff --git a/src/front/spv/image.rs b/src/front/spv/image.rs new file mode 100644 index 0000000000..3453e7048a --- /dev/null +++ b/src/front/spv/image.rs @@ -0,0 +1,511 @@ +use crate::arena::{Arena, Handle}; + +use super::{Error, LookupExpression, LookupHelper as _}; + +#[derive(Clone, Debug)] +pub(super) struct LookupSampledImage { + image: Handle, + sampler: Handle, +} + +bitflags::bitflags! { + /// Flags describing sampling method. + pub struct SamplingFlags: u32 { + /// Regular sampling. + const REGULAR = 0x1; + /// Comparison sampling. + const COMPARISON = 0x2; + } +} + +/// Return the texture coordinates separated from the array layer, +/// and/or divided by the projection term. +/// +/// The Proj sampling ops expect an extra coordinate for the W. +/// The arrayed (can't be Proj!) images expect an extra coordinate for the layer. +fn extract_image_coordinates( + image_dim: crate::ImageDimension, + image_arrayed: bool, + base: Handle, + coordinate_ty: Handle, + type_arena: &Arena, + expressions: &mut Arena, +) -> (Handle, Option>) { + let (given_size, kind) = match type_arena[coordinate_ty].inner { + crate::TypeInner::Scalar { kind, .. } => (None, kind), + crate::TypeInner::Vector { size, kind, .. } => (Some(size), kind), + ref other => unreachable!("Unexpected texture coordinate {:?}", other), + }; + + let required_size = image_dim.required_coordinate_size(); + let required_ty = required_size.map(|size| { + type_arena + .fetch_if(|ty| { + ty.inner + == crate::TypeInner::Vector { + size, + kind, + width: 4, + } + }) + .expect("Required coordinate type should have been set up by `parse_type_image`!") + }); + let extra_expr = crate::Expression::AccessIndex { + base, + index: required_size.map_or(1, |size| size as u32), + }; + + if given_size == required_size { + // fast path, no complications + (base, None) + } else if image_arrayed { + // extra coordinate for the array index + let extracted = match required_size { + None => expressions.append(crate::Expression::AccessIndex { base, index: 0 }), + Some(size) => { + let mut components = Vec::with_capacity(size as usize); + for index in 0..size as u32 { + let comp = expressions.append(crate::Expression::AccessIndex { base, index }); + components.push(comp); + } + expressions.append(crate::Expression::Compose { + ty: required_ty.unwrap(), + components, + }) + } + }; + let array_index_f32 = expressions.append(extra_expr); + let array_index = expressions.append(crate::Expression::As { + kind: crate::ScalarKind::Uint, + expr: array_index_f32, + convert: true, + }); + (extracted, Some(array_index)) + } else { + // extra coordinate for the projection W + let projection = expressions.append(extra_expr); + let divided = match required_size { + None => { + let temp = expressions.append(crate::Expression::AccessIndex { base, index: 0 }); + expressions.append(crate::Expression::Binary { + op: crate::BinaryOperator::Divide, + left: temp, + right: projection, + }) + } + Some(size) => { + let mut components = Vec::with_capacity(size as usize); + for index in 0..size as u32 { + let temp = expressions.append(crate::Expression::AccessIndex { base, index }); + let comp = expressions.append(crate::Expression::Binary { + op: crate::BinaryOperator::Divide, + left: temp, + right: projection, + }); + components.push(comp); + } + expressions.append(crate::Expression::Compose { + ty: required_ty.unwrap(), + components, + }) + } + }; + (divided, None) + } +} + +pub(super) fn patch_comparison_type( + flags: SamplingFlags, + var: &mut crate::GlobalVariable, + arena: &mut Arena, +) -> bool { + if !flags.contains(SamplingFlags::COMPARISON) { + return true; + } + if flags == SamplingFlags::all() { + return false; + } + + log::debug!("Flipping comparison for {:?}", var); + let original_ty = &arena[var.ty]; + let ty_inner = match original_ty.inner { + crate::TypeInner::Image { + class: _, + dim, + arrayed, + } => crate::TypeInner::Image { + class: crate::ImageClass::Depth, + dim, + arrayed, + }, + crate::TypeInner::Sampler { .. } => crate::TypeInner::Sampler { comparison: true }, + ref other => unreachable!("Unexpected type for comparison mutation: {:?}", other), + }; + + let name = original_ty.name.clone(); + var.ty = arena.append(crate::Type { + name, + inner: ty_inner, + }); + true +} + +impl> super::Parser { + pub(super) fn parse_image_couple(&mut self) -> Result<(), Error> { + let _result_type_id = self.next()?; + let result_id = self.next()?; + let image_id = self.next()?; + let sampler_id = self.next()?; + let image_lexp = self.lookup_expression.lookup(image_id)?; + let sampler_lexp = self.lookup_expression.lookup(sampler_id)?; + self.lookup_sampled_image.insert( + result_id, + LookupSampledImage { + image: image_lexp.handle, + sampler: sampler_lexp.handle, + }, + ); + Ok(()) + } + + pub(super) fn parse_image_uncouple(&mut self) -> Result<(), Error> { + let result_type_id = self.next()?; + let result_id = self.next()?; + let sampled_image_id = self.next()?; + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: self.lookup_sampled_image.lookup(sampled_image_id)?.image, + type_id: result_type_id, + }, + ); + Ok(()) + } + + pub(super) fn parse_image_fetch( + &mut self, + mut words_left: u16, + type_arena: &Arena, + global_arena: &Arena, + expressions: &mut Arena, + ) -> Result<(), Error> { + let result_type_id = self.next()?; + let result_id = self.next()?; + let image_id = self.next()?; + let coordinate_id = self.next()?; + + let mut index = None; + while words_left != 0 { + let image_ops = self.next()?; + words_left -= 1; + match spirv::ImageOperands::from_bits_truncate(image_ops) { + spirv::ImageOperands::LOD => { + let lod_expr = self.next()?; + let lod_handle = self.lookup_expression.lookup(lod_expr)?.handle; + index = Some(lod_handle); + words_left -= 1; + } + spirv::ImageOperands::SAMPLE => { + let sample_expr = self.next()?; + let sample_handle = self.lookup_expression.lookup(sample_expr)?.handle; + index = Some(sample_handle); + words_left -= 1; + } + other => { + log::warn!("Skipping {:?}", other); + for _ in 0..words_left { + self.next()?; + } + break; + } + } + } + + let image_lexp = self.lookup_expression.lookup(image_id)?; + let image_var_handle = expressions[image_lexp.handle].as_global_var()?; + let image_var = &global_arena[image_var_handle]; + + let coord_lexp = self.lookup_expression.lookup(coordinate_id)?; + let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle; + let (coordinate, array_index) = match type_arena[image_var.ty].inner { + crate::TypeInner::Image { + dim, + arrayed, + class: _, + } => extract_image_coordinates( + dim, + arrayed, + coord_lexp.handle, + coord_type_handle, + type_arena, + expressions, + ), + _ => return Err(Error::InvalidSampleImage(image_var.ty)), + }; + + let expr = crate::Expression::ImageLoad { + image: image_lexp.handle, + coordinate, + array_index, + index, + }; + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: expressions.append(expr), + type_id: result_type_id, + }, + ); + Ok(()) + } + + pub(super) fn parse_image_sample( + &mut self, + mut words_left: u16, + type_arena: &Arena, + global_arena: &Arena, + expressions: &mut Arena, + ) -> Result<(), Error> { + let result_type_id = self.next()?; + let result_id = self.next()?; + let sampled_image_id = self.next()?; + let coordinate_id = self.next()?; + + let mut level = crate::SampleLevel::Auto; + while words_left != 0 { + let image_ops = self.next()?; + words_left -= 1; + match spirv::ImageOperands::from_bits_truncate(image_ops) { + spirv::ImageOperands::BIAS => { + let bias_expr = self.next()?; + let bias_handle = self.lookup_expression.lookup(bias_expr)?.handle; + level = crate::SampleLevel::Bias(bias_handle); + words_left -= 1; + } + spirv::ImageOperands::LOD => { + let lod_expr = self.next()?; + let lod_handle = self.lookup_expression.lookup(lod_expr)?.handle; + level = crate::SampleLevel::Exact(lod_handle); + words_left -= 1; + } + other => { + log::warn!("Skipping {:?}", other); + for _ in 0..words_left { + self.next()?; + } + break; + } + } + } + + 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 image_var_handle = expressions[si_lexp.image].as_global_var()?; + let sampler_var_handle = expressions[si_lexp.sampler].as_global_var()?; + log::debug!( + "\t\t\tImage {:?} sampled with {:?}", + image_var_handle, + sampler_var_handle + ); + if let Some(flags) = self.handle_sampling.get_mut(&image_var_handle) { + *flags |= SamplingFlags::REGULAR; + } + *self.handle_sampling.get_mut(&sampler_var_handle).unwrap() |= SamplingFlags::REGULAR; + + let image_var = &global_arena[image_var_handle]; + let (coordinate, array_index) = match type_arena[image_var.ty].inner { + crate::TypeInner::Image { + dim, + arrayed, + class: _, + } => extract_image_coordinates( + dim, + arrayed, + coord_lexp.handle, + coord_type_handle, + type_arena, + expressions, + ), + _ => return Err(Error::InvalidSampleImage(image_var.ty)), + }; + + let expr = crate::Expression::ImageSample { + image: si_lexp.image, + sampler: si_lexp.sampler, + coordinate, + array_index, + offset: None, //TODO + level, + depth_ref: None, + }; + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: expressions.append(expr), + type_id: result_type_id, + }, + ); + Ok(()) + } + + pub(super) fn parse_image_sample_dref( + &mut self, + mut words_left: u16, + type_arena: &Arena, + global_arena: &Arena, + expressions: &mut Arena, + ) -> Result<(), Error> { + 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 mut level = crate::SampleLevel::Auto; + while words_left != 0 { + let image_ops = self.next()?; + words_left -= 1; + match spirv::ImageOperands::from_bits_truncate(image_ops) { + spirv::ImageOperands::BIAS => { + let bias_expr = self.next()?; + let bias_handle = self.lookup_expression.lookup(bias_expr)?.handle; + level = crate::SampleLevel::Bias(bias_handle); + words_left -= 1; + } + spirv::ImageOperands::LOD => { + let lod_expr = self.next()?; + let lod_handle = self.lookup_expression.lookup(lod_expr)?.handle; + level = crate::SampleLevel::Exact(lod_handle); + words_left -= 1; + } + other => { + log::warn!("Skipping {:?}", other); + for _ in 0..words_left { + self.next()?; + } + break; + } + } + } + + 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 image_var_handle = expressions[si_lexp.image].as_global_var()?; + let sampler_var_handle = expressions[si_lexp.sampler].as_global_var()?; + log::debug!( + "\t\t\tImage {:?} sampled with comparison {:?}", + image_var_handle, + sampler_var_handle + ); + if let Some(flags) = self.handle_sampling.get_mut(&image_var_handle) { + *flags |= SamplingFlags::COMPARISON; + } + *self.handle_sampling.get_mut(&sampler_var_handle).unwrap() |= SamplingFlags::COMPARISON; + + 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 image_var = &global_arena[image_var_handle]; + let (coordinate, array_index) = match type_arena[image_var.ty].inner { + crate::TypeInner::Image { + dim, + arrayed, + class: _, + } => extract_image_coordinates( + dim, + arrayed, + coord_lexp.handle, + coord_type_handle, + type_arena, + expressions, + ), + _ => return Err(Error::InvalidSampleImage(image_var.ty)), + }; + + let expr = crate::Expression::ImageSample { + image: si_lexp.image, + sampler: si_lexp.sampler, + coordinate, + array_index, + offset: None, //TODO + level, + depth_ref: Some(dref_lexp.handle), + }; + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: expressions.append(expr), + type_id: result_type_id, + }, + ); + Ok(()) + } + + pub(super) fn parse_image_query_size( + &mut self, + at_level: bool, + expressions: &mut Arena, + ) -> Result<(), Error> { + let result_type_id = self.next()?; + let result_id = self.next()?; + let image_id = self.next()?; + let level = if at_level { + let level_id = self.next()?; + let level_lexp = self.lookup_expression.lookup(level_id)?; + Some(level_lexp.handle) + } else { + None + }; + + //TODO: handle arrays and cubes + let image_lexp = self.lookup_expression.lookup(image_id)?; + + let expr = crate::Expression::ImageQuery { + image: image_lexp.handle, + query: crate::ImageQuery::Size { level }, + }; + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: expressions.append(expr), + type_id: result_type_id, + }, + ); + Ok(()) + } + + pub(super) fn parse_image_query_other( + &mut self, + query: crate::ImageQuery, + expressions: &mut Arena, + ) -> Result<(), Error> { + let result_type_id = self.next()?; + let result_id = self.next()?; + let image_id = self.next()?; + + let image_lexp = self.lookup_expression.lookup(image_id)?.clone(); + + let expr = crate::Expression::ImageQuery { + image: image_lexp.handle, + query, + }; + self.lookup_expression.insert( + result_id, + LookupExpression { + handle: expressions.append(expr), + type_id: result_type_id, + }, + ); + Ok(()) + } +} diff --git a/src/front/spv/mod.rs b/src/front/spv/mod.rs index 223b1373b7..e37f94972e 100644 --- a/src/front/spv/mod.rs +++ b/src/front/spv/mod.rs @@ -15,6 +15,7 @@ mod convert; mod error; mod flow; mod function; +mod image; #[cfg(all(test, feature = "serialize"))] mod rosetta; @@ -55,12 +56,10 @@ impl Instruction { } } - fn expect_at_least(self, count: u16) -> Result<(), Error> { - if self.wc >= count { - Ok(()) - } else { - Err(Error::InvalidOperandCount(self.op, self.wc)) - } + fn expect_at_least(self, count: u16) -> Result { + self.wc + .checked_sub(count) + .ok_or(Error::InvalidOperandCount(self.op, self.wc)) } } @@ -163,102 +162,6 @@ impl crate::ImageDimension { } } -/// Return the texture coordinates separated from the array layer, -/// and/or divided by the projection term. -/// -/// The Proj sampling ops expect an extra coordinate for the W. -/// The arrayed (can't be Proj!) images expect an extra coordinate for the layer. -fn extract_image_coordinates( - image_dim: crate::ImageDimension, - image_arrayed: bool, - base: Handle, - coordinate_ty: Handle, - type_arena: &Arena, - expressions: &mut Arena, -) -> (Handle, Option>) { - let (given_size, kind) = match type_arena[coordinate_ty].inner { - crate::TypeInner::Scalar { kind, .. } => (None, kind), - crate::TypeInner::Vector { size, kind, .. } => (Some(size), kind), - ref other => unreachable!("Unexpected texture coordinate {:?}", other), - }; - - let required_size = image_dim.required_coordinate_size(); - let required_ty = required_size.map(|size| { - type_arena - .fetch_if(|ty| { - ty.inner - == crate::TypeInner::Vector { - size, - kind, - width: 4, - } - }) - .expect("Required coordinate type should have been set up by `parse_type_image`!") - }); - let extra_expr = crate::Expression::AccessIndex { - base, - index: required_size.map_or(1, |size| size as u32), - }; - - if given_size == required_size { - // fast path, no complications - (base, None) - } else if image_arrayed { - // extra coordinate for the array index - let extracted = match required_size { - None => expressions.append(crate::Expression::AccessIndex { base, index: 0 }), - Some(size) => { - let mut components = Vec::with_capacity(size as usize); - for index in 0..size as u32 { - let comp = expressions.append(crate::Expression::AccessIndex { base, index }); - components.push(comp); - } - expressions.append(crate::Expression::Compose { - ty: required_ty.unwrap(), - components, - }) - } - }; - let array_index_f32 = expressions.append(extra_expr); - let array_index = expressions.append(crate::Expression::As { - kind: crate::ScalarKind::Uint, - expr: array_index_f32, - convert: true, - }); - (extracted, Some(array_index)) - } else { - // extra coordinate for the projection W - let projection = expressions.append(extra_expr); - let divided = match required_size { - None => { - let temp = expressions.append(crate::Expression::AccessIndex { base, index: 0 }); - expressions.append(crate::Expression::Binary { - op: crate::BinaryOperator::Divide, - left: temp, - right: projection, - }) - } - Some(size) => { - let mut components = Vec::with_capacity(size as usize); - for index in 0..size as u32 { - let temp = expressions.append(crate::Expression::AccessIndex { base, index }); - let comp = expressions.append(crate::Expression::Binary { - op: crate::BinaryOperator::Divide, - left: temp, - right: projection, - }); - components.push(comp); - } - expressions.append(crate::Expression::Compose { - ty: required_ty.unwrap(), - components, - }) - } - }; - (divided, None) - } -} - type MemberIndex = u32; #[derive(Clone, Debug, Default, PartialEq)] @@ -313,7 +216,7 @@ impl Decoration { desc_set: None, desc_index: None, .. - } => match convert::map_builtin(built_in, is_output) { + } => match map_builtin(built_in, is_output) { Ok(built_in) => Some(crate::Binding::BuiltIn(built_in)), Err(e) => { log::warn!("{:?}", e); @@ -339,16 +242,6 @@ 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, @@ -389,12 +282,6 @@ struct LookupExpression { type_id: spirv::Word, } -#[derive(Clone, Debug)] -struct LookupSampledImage { - image: Handle, - sampler: Handle, -} - #[derive(Clone, Debug)] pub struct Assignment { to: Handle, @@ -414,7 +301,7 @@ pub struct Parser { future_decor: FastHashMap, future_member_decor: FastHashMap<(spirv::Word, MemberIndex), Decoration>, lookup_member_type_id: FastHashMap<(Handle, MemberIndex), spirv::Word>, - handle_sampling: FastHashMap, SamplingFlags>, + handle_sampling: FastHashMap, image::SamplingFlags>, lookup_type: FastHashMap, lookup_void_type: Option, lookup_storage_buffer_types: FastHashSet>, @@ -422,7 +309,7 @@ pub struct Parser { lookup_constant: FastHashMap, lookup_variable: FastHashMap, lookup_expression: FastHashMap, - lookup_sampled_image: FastHashMap, + lookup_sampled_image: FastHashMap, lookup_function_type: FastHashMap, lookup_function: FastHashMap>, lookup_entry_point: FastHashMap, @@ -1104,378 +991,47 @@ impl> Parser { // Sampling Op::Image => { inst.expect(4)?; - let result_type_id = self.next()?; - let result_id = self.next()?; - let sampled_image_id = self.next()?; - self.lookup_expression.insert( - result_id, - LookupExpression { - handle: self.lookup_sampled_image.lookup(sampled_image_id)?.image, - type_id: result_type_id, - }, - ); + self.parse_image_uncouple()?; } Op::SampledImage => { inst.expect(5)?; - let _result_type_id = self.next()?; - let result_id = self.next()?; - let image_id = self.next()?; - let sampler_id = self.next()?; - let image_lexp = self.lookup_expression.lookup(image_id)?; - let sampler_lexp = self.lookup_expression.lookup(sampler_id)?; - //TODO: compare the result type - self.lookup_sampled_image.insert( - result_id, - LookupSampledImage { - image: image_lexp.handle, - sampler: sampler_lexp.handle, - }, - ); + self.parse_image_couple()?; } Op::ImageFetch => { - inst.expect_at_least(5)?; - let result_type_id = self.next()?; - let result_id = self.next()?; - let image_id = self.next()?; - let coordinate_id = self.next()?; - - let mut index = None; - let mut base_wc = 5; - while base_wc < inst.wc { - let image_ops = self.next()?; - base_wc += 1; - match spirv::ImageOperands::from_bits_truncate(image_ops) { - spirv::ImageOperands::LOD => { - let lod_expr = self.next()?; - let lod_handle = self.lookup_expression.lookup(lod_expr)?.handle; - index = Some(lod_handle); - base_wc += 1; - } - spirv::ImageOperands::SAMPLE => { - let sample_expr = self.next()?; - let sample_handle = - self.lookup_expression.lookup(sample_expr)?.handle; - index = Some(sample_handle); - base_wc += 1; - } - other => { - log::warn!("Skipping {:?}", other); - for _ in base_wc..inst.wc { - self.next()?; - } - break; - } - } - } - - let image_lexp = self.lookup_expression.lookup(image_id)?; - let image_var_handle = expressions[image_lexp.handle].as_global_var()?; - let image_var = &global_arena[image_var_handle]; - - let coord_lexp = self.lookup_expression.lookup(coordinate_id)?; - let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle; - let (coordinate, array_index) = match type_arena[image_var.ty].inner { - crate::TypeInner::Image { - dim, - arrayed, - class: _, - } => extract_image_coordinates( - dim, - arrayed, - coord_lexp.handle, - coord_type_handle, - type_arena, - expressions, - ), - _ => return Err(Error::InvalidSampleImage(image_var.ty)), - }; - - let expr = crate::Expression::ImageLoad { - image: image_lexp.handle, - coordinate, - array_index, - index, - }; - self.lookup_expression.insert( - result_id, - LookupExpression { - handle: expressions.append(expr), - type_id: result_type_id, - }, - ); + let extra = inst.expect_at_least(5)?; + self.parse_image_fetch(extra, type_arena, global_arena, expressions)?; } Op::ImageSampleImplicitLod | Op::ImageSampleExplicitLod | Op::ImageSampleProjImplicitLod | Op::ImageSampleProjExplicitLod => { - let mut base_wc = 5; - inst.expect_at_least(base_wc)?; - let result_type_id = self.next()?; - let result_id = self.next()?; - let sampled_image_id = self.next()?; - let coordinate_id = self.next()?; - - let mut level = crate::SampleLevel::Auto; - while base_wc < inst.wc { - let image_ops = self.next()?; - base_wc += 1; - match spirv::ImageOperands::from_bits_truncate(image_ops) { - spirv::ImageOperands::BIAS => { - let bias_expr = self.next()?; - let bias_handle = self.lookup_expression.lookup(bias_expr)?.handle; - level = crate::SampleLevel::Bias(bias_handle); - base_wc += 1; - } - spirv::ImageOperands::LOD => { - let lod_expr = self.next()?; - let lod_handle = self.lookup_expression.lookup(lod_expr)?.handle; - level = crate::SampleLevel::Exact(lod_handle); - base_wc += 1; - } - other => { - log::warn!("Skipping {:?}", other); - for _ in base_wc..inst.wc { - self.next()?; - } - break; - } - } - } - - 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 image_var_handle = expressions[si_lexp.image].as_global_var()?; - let sampler_var_handle = expressions[si_lexp.sampler].as_global_var()?; - log::debug!( - "\t\t\tImage {:?} sampled with {:?}", - image_var_handle, - sampler_var_handle - ); - if let Some(flags) = self.handle_sampling.get_mut(&image_var_handle) { - *flags |= SamplingFlags::REGULAR; - } - *self.handle_sampling.get_mut(&sampler_var_handle).unwrap() |= - SamplingFlags::REGULAR; - - let image_var = &global_arena[image_var_handle]; - let (coordinate, array_index) = match type_arena[image_var.ty].inner { - crate::TypeInner::Image { - dim, - arrayed, - class: _, - } => extract_image_coordinates( - dim, - arrayed, - coord_lexp.handle, - coord_type_handle, - type_arena, - expressions, - ), - _ => return Err(Error::InvalidSampleImage(image_var.ty)), - }; - - let expr = crate::Expression::ImageSample { - image: si_lexp.image, - sampler: si_lexp.sampler, - coordinate, - array_index, - offset: None, //TODO - level, - depth_ref: None, - }; - self.lookup_expression.insert( - result_id, - LookupExpression { - handle: expressions.append(expr), - type_id: result_type_id, - }, - ); + let extra = inst.expect_at_least(5)?; + self.parse_image_sample(extra, type_arena, global_arena, expressions)?; } Op::ImageSampleDrefImplicitLod | Op::ImageSampleDrefExplicitLod | Op::ImageSampleProjDrefImplicitLod | Op::ImageSampleProjDrefExplicitLod => { - let mut base_wc = 6; - inst.expect_at_least(base_wc)?; - 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 mut level = crate::SampleLevel::Auto; - while base_wc < inst.wc { - let image_ops = self.next()?; - base_wc += 1; - match spirv::ImageOperands::from_bits_truncate(image_ops) { - spirv::ImageOperands::BIAS => { - let bias_expr = self.next()?; - let bias_handle = self.lookup_expression.lookup(bias_expr)?.handle; - level = crate::SampleLevel::Bias(bias_handle); - base_wc += 1; - } - spirv::ImageOperands::LOD => { - let lod_expr = self.next()?; - let lod_handle = self.lookup_expression.lookup(lod_expr)?.handle; - level = crate::SampleLevel::Exact(lod_handle); - base_wc += 1; - } - other => { - log::warn!("Skipping {:?}", other); - for _ in base_wc..inst.wc { - self.next()?; - } - break; - } - } - } - - 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 image_var_handle = expressions[si_lexp.image].as_global_var()?; - let sampler_var_handle = expressions[si_lexp.sampler].as_global_var()?; - log::debug!( - "\t\t\tImage {:?} sampled with comparison {:?}", - image_var_handle, - sampler_var_handle - ); - if let Some(flags) = self.handle_sampling.get_mut(&image_var_handle) { - *flags |= SamplingFlags::COMPARISON; - } - *self.handle_sampling.get_mut(&sampler_var_handle).unwrap() |= - SamplingFlags::COMPARISON; - - 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 image_var = &global_arena[image_var_handle]; - let (coordinate, array_index) = match type_arena[image_var.ty].inner { - crate::TypeInner::Image { - dim, - arrayed, - class: _, - } => extract_image_coordinates( - dim, - arrayed, - coord_lexp.handle, - coord_type_handle, - type_arena, - expressions, - ), - _ => return Err(Error::InvalidSampleImage(image_var.ty)), - }; - - let expr = crate::Expression::ImageSample { - image: si_lexp.image, - sampler: si_lexp.sampler, - coordinate, - array_index, - offset: None, //TODO - level, - depth_ref: Some(dref_lexp.handle), - }; - self.lookup_expression.insert( - result_id, - LookupExpression { - handle: expressions.append(expr), - type_id: result_type_id, - }, - ); + let extra = inst.expect_at_least(6)?; + self.parse_image_sample_dref(extra, type_arena, global_arena, expressions)?; } Op::ImageQuerySize => { inst.expect(4)?; - let result_type_id = self.next()?; - let result_id = self.next()?; - let image_id = self.next()?; - - //TODO: handle arrays and cubes - let image_lexp = self.lookup_expression.lookup(image_id)?.clone(); - - let expr = crate::Expression::ImageQuery { - image: image_lexp.handle, - query: crate::ImageQuery::Size { level: None }, - }; - self.lookup_expression.insert( - result_id, - LookupExpression { - handle: expressions.append(expr), - type_id: result_type_id, - }, - ); + self.parse_image_query_size(false, expressions)?; } Op::ImageQuerySizeLod => { inst.expect(5)?; - let result_type_id = self.next()?; - let result_id = self.next()?; - let image_id = self.next()?; - let level_id = self.next()?; - - //TODO: handle arrays and cubes - let image_lexp = self.lookup_expression.lookup(image_id)?.clone(); - let level_lexp = self.lookup_expression.lookup(level_id)?.clone(); - - let expr = crate::Expression::ImageQuery { - image: image_lexp.handle, - query: crate::ImageQuery::Size { - level: Some(level_lexp.handle), - }, - }; - self.lookup_expression.insert( - result_id, - LookupExpression { - handle: expressions.append(expr), - type_id: result_type_id, - }, - ); + self.parse_image_query_size(true, expressions)?; } Op::ImageQueryLevels => { - let result_type_id = self.next()?; - let result_id = self.next()?; - let image_id = self.next()?; - - let image_lexp = self.lookup_expression.lookup(image_id)?.clone(); - - let expr = crate::Expression::ImageQuery { - image: image_lexp.handle, - query: crate::ImageQuery::NumLevels, - }; - self.lookup_expression.insert( - result_id, - LookupExpression { - handle: expressions.append(expr), - type_id: result_type_id, - }, - ); + inst.expect(4)?; + self.parse_image_query_other(crate::ImageQuery::NumLevels, expressions)?; } Op::ImageQuerySamples => { - let result_type_id = self.next()?; - let result_id = self.next()?; - let image_id = self.next()?; - - let image_lexp = self.lookup_expression.lookup(image_id)?.clone(); - - let expr = crate::Expression::ImageQuery { - image: image_lexp.handle, - query: crate::ImageQuery::NumSamples, - }; - self.lookup_expression.insert( - result_id, - LookupExpression { - handle: expressions.append(expr), - type_id: result_type_id, - }, - ); + inst.expect(4)?; + self.parse_image_query_other(crate::ImageQuery::NumSamples, expressions)?; } + // other ops Op::Select => { inst.expect(6)?; let result_type_id = self.next()?; @@ -1995,40 +1551,24 @@ impl> Parser { Op::ConstantComposite => self.parse_composite_constant(inst, &mut module), Op::ConstantNull | Op::Undef => self.parse_null_constant(inst, &mut module), Op::Variable => self.parse_global_variable(inst, &mut module), - Op::Function => self.parse_function(inst, &mut module), + Op::Function => { + self.switch(ModuleState::Function, inst.op)?; + inst.expect(5)?; + self.parse_function(&mut module) + } _ => Err(Error::UnsupportedInstruction(self.state, inst.op)), //TODO }?; } // 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() { + if !image::patch_comparison_type( + flags, + module.global_variables.get_mut(handle), + &mut module.types, + ) { return Err(Error::InconsistentComparisonSampling(handle)); } - log::debug!("Flipping comparison for {:?}", handle); - let var = module.global_variables.get_mut(handle); - let original_ty = &module.types[var.ty]; - let ty_inner = match original_ty.inner { - crate::TypeInner::Image { - class: _, - dim, - arrayed, - } => crate::TypeInner::Image { - class: crate::ImageClass::Depth, - dim, - arrayed, - }, - crate::TypeInner::Sampler { .. } => crate::TypeInner::Sampler { comparison: true }, - ref other => unreachable!("Unexpected type for comparison mutation: {:?}", other), - }; - let name = original_ty.name.clone(); - var.ty = module.types.append(crate::Type { - name, - inner: ty_inner, - }); } for (_, func) in module.functions.iter_mut() { @@ -2971,7 +2511,8 @@ impl> Parser { .can_comparison_sample() { log::debug!("\t\ttracking {:?} for sampling properties", handle); - self.handle_sampling.insert(handle, SamplingFlags::empty()); + self.handle_sampling + .insert(handle, image::SamplingFlags::empty()); } Ok(()) }