From f98b4e2f48f6373cd05854a04e4de04f8928707c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Capucho?= Date: Thu, 24 Jun 2021 22:00:52 +0100 Subject: [PATCH] [spv-in] Support texture/sampler function argument --- src/front/spv/function.rs | 9 ++- src/front/spv/image.rs | 81 +++++++++++++++--------- src/front/spv/mod.rs | 129 +++++++++++++++++++++++++++++++------- 3 files changed, 167 insertions(+), 52 deletions(-) diff --git a/src/front/spv/function.rs b/src/front/spv/function.rs index 7c05546543..f124bd1f78 100644 --- a/src/front/spv/function.rs +++ b/src/front/spv/function.rs @@ -1,6 +1,6 @@ use crate::arena::{Arena, Handle}; -use super::{flow::*, Error, Instruction, LookupExpression, LookupHelper as _}; +use super::{flow::*, Error, FunctionInfo, Instruction, LookupExpression, LookupHelper as _}; pub type BlockId = u32; @@ -135,6 +135,10 @@ impl> super::Parser { self.function_call_graph.add_node(fun_id); let mut flow_graph = FlowGraph::new(); + let mut function_info = FunctionInfo { + parameters_sampling: vec![None; fun.arguments.len()], + }; + // Scan the blocks and add them as nodes loop { let fun_inst = self.next_inst()?; @@ -153,6 +157,8 @@ impl> super::Parser { &mut module.constants, &module.types, &module.global_variables, + &fun.arguments, + &mut function_info, )?; flow_graph.add_node(node); @@ -187,6 +193,7 @@ impl> super::Parser { // done let fun_handle = module.functions.append(fun); self.lookup_function.insert(fun_id, fun_handle); + self.function_info.insert(fun_handle, function_info); if let Some(ep) = self.lookup_entry_point.remove(&fun_id) { // create a wrapping function let mut function = crate::Function { diff --git a/src/front/spv/image.rs b/src/front/spv/image.rs index 1fa9e938f4..75736771a1 100644 --- a/src/front/spv/image.rs +++ b/src/front/spv/image.rs @@ -1,6 +1,9 @@ -use crate::arena::{Arena, Handle}; +use crate::{ + arena::{Arena, Handle}, + FunctionArgument, +}; -use super::{Error, LookupExpression, LookupHelper as _}; +use super::{Error, FunctionInfo, LookupExpression, LookupHelper as _}; #[derive(Clone, Debug)] pub(super) struct LookupSampledImage { @@ -19,12 +22,15 @@ bitflags::bitflags! { } impl Arena { - fn get_global_var( + fn get_image_expr_ty( &self, handle: Handle, - ) -> Result, Error> { + global_vars: &Arena, + arguments: &[FunctionArgument], + ) -> Result, Error> { match self[handle] { - crate::Expression::GlobalVariable(handle) => Ok(handle), + crate::Expression::GlobalVariable(handle) => Ok(global_vars[handle].ty), + crate::Expression::FunctionArgument(i) => Ok(arguments[i as usize].ty), ref other => Err(Error::InvalidGlobalVar(other.clone())), } } @@ -229,6 +235,7 @@ impl> super::Parser { words_left: u16, type_arena: &Arena, global_arena: &Arena, + arguments: &[FunctionArgument], expressions: &mut Arena, ) -> Result { let image_id = self.next()?; @@ -246,12 +253,11 @@ impl> super::Parser { } let image_lexp = self.lookup_expression.lookup(image_id)?; - let image_var_handle = expressions.get_global_var(image_lexp.handle)?; - let image_var = &global_arena[image_var_handle]; + let image_ty = expressions.get_image_expr_ty(image_lexp.handle, global_arena, arguments)?; 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 { + let (coordinate, array_index) = match type_arena[image_ty].inner { crate::TypeInner::Image { dim, arrayed, @@ -268,7 +274,7 @@ impl> super::Parser { type_arena, expressions, ), - _ => return Err(Error::InvalidImage(image_var.ty)), + _ => return Err(Error::InvalidImage(image_ty)), }; let value_lexp = self.lookup_expression.lookup(value_id)?; @@ -286,6 +292,7 @@ impl> super::Parser { mut words_left: u16, type_arena: &Arena, global_arena: &Arena, + arguments: &[FunctionArgument], expressions: &mut Arena, ) -> Result<(), Error> { let result_type_id = self.next()?; @@ -328,12 +335,11 @@ impl> super::Parser { } let image_lexp = self.lookup_expression.lookup(image_id)?; - let image_var_handle = expressions.get_global_var(image_lexp.handle)?; - let image_var = &global_arena[image_var_handle]; + let image_ty = expressions.get_image_expr_ty(image_lexp.handle, global_arena, arguments)?; 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 { + let (coordinate, array_index) = match type_arena[image_ty].inner { crate::TypeInner::Image { dim, arrayed, @@ -350,7 +356,7 @@ impl> super::Parser { type_arena, expressions, ), - _ => return Err(Error::InvalidImage(image_var.ty)), + _ => return Err(Error::InvalidImage(image_ty)), }; let expr = crate::Expression::ImageLoad { @@ -369,13 +375,16 @@ impl> super::Parser { Ok(()) } + #[allow(clippy::too_many_arguments)] pub(super) fn parse_image_sample( &mut self, mut words_left: u16, options: SamplingOptions, type_arena: &Arena, global_arena: &Arena, + arguments: &[FunctionArgument], expressions: &mut Arena, + function_info: &mut FunctionInfo, ) -> Result<(), Error> { let result_type_id = self.next()?; let result_id = self.next()?; @@ -432,26 +441,42 @@ impl> super::Parser { 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.get_global_var(si_lexp.image)?; - let sampler_var_handle = expressions.get_global_var(si_lexp.sampler)?; - log::debug!( - "\t\t\tImage {:?} sampled with {:?} under {:?}", - image_var_handle, - sampler_var_handle, - options, - ); let sampling_bit = if options.compare { SamplingFlags::COMPARISON } else { SamplingFlags::REGULAR }; - if let Some(flags) = self.handle_sampling.get_mut(&image_var_handle) { - *flags |= sampling_bit; - } - *self.handle_sampling.get_mut(&sampler_var_handle).unwrap() |= sampling_bit; - let image_var = &global_arena[image_var_handle]; - let (coordinate, array_index) = match type_arena[image_var.ty].inner { + let image_ty = match expressions[si_lexp.image] { + crate::Expression::GlobalVariable(handle) => { + if let Some(flags) = self.handle_sampling.get_mut(&handle) { + *flags |= sampling_bit; + } + + global_arena[handle].ty + } + crate::Expression::FunctionArgument(i) => { + let flags = function_info.parameters_sampling[i as usize] + .get_or_insert(SamplingFlags::empty()); + *flags |= sampling_bit; + + arguments[i as usize].ty + } + ref other => return Err(Error::InvalidGlobalVar(other.clone())), + }; + match expressions[si_lexp.sampler] { + crate::Expression::GlobalVariable(handle) => { + *self.handle_sampling.get_mut(&handle).unwrap() |= sampling_bit + } + crate::Expression::FunctionArgument(i) => { + let flags = function_info.parameters_sampling[i as usize] + .get_or_insert(SamplingFlags::empty()); + *flags |= sampling_bit; + } + ref other => return Err(Error::InvalidGlobalVar(other.clone())), + } + + let (coordinate, array_index) = match type_arena[image_ty].inner { crate::TypeInner::Image { dim, arrayed, @@ -470,7 +495,7 @@ impl> super::Parser { type_arena, expressions, ), - _ => return Err(Error::InvalidImage(image_var.ty)), + _ => return Err(Error::InvalidImage(image_ty)), }; let expr = crate::Expression::ImageSample { diff --git a/src/front/spv/mod.rs b/src/front/spv/mod.rs index 0ad9a002e3..361be0aa4c 100644 --- a/src/front/spv/mod.rs +++ b/src/front/spv/mod.rs @@ -371,6 +371,10 @@ impl Default for Options { } } +struct FunctionInfo { + parameters_sampling: Vec>, +} + pub struct Parser { data: I, state: ModuleState, @@ -405,6 +409,7 @@ pub struct Parser { options: Options, index_constants: Vec>, index_constant_expressions: Vec>, + function_info: FastHashMap, FunctionInfo>, } impl> Parser { @@ -436,6 +441,7 @@ impl> Parser { options: options.clone(), index_constants: Vec::new(), index_constant_expressions: Vec::new(), + function_info: FastHashMap::default(), } } @@ -783,6 +789,8 @@ impl> Parser { const_arena: &mut Arena, type_arena: &Arena, global_arena: &Arena, + arguments: &[crate::FunctionArgument], + function_info: &mut FunctionInfo, ) -> Result { let mut block = Vec::new(); let mut phis = Vec::new(); @@ -1479,14 +1487,19 @@ impl> Parser { Op::ImageWrite => { let extra = inst.expect_at_least(4)?; block.extend(emitter.finish(expressions)); - let stmt = - self.parse_image_write(extra, type_arena, global_arena, expressions)?; + let stmt = self.parse_image_write( + extra, + type_arena, + global_arena, + arguments, + expressions, + )?; block.push(stmt); emitter.start(expressions); } Op::ImageFetch | Op::ImageRead => { let extra = inst.expect_at_least(5)?; - self.parse_image_load(extra, type_arena, global_arena, expressions)?; + self.parse_image_load(extra, type_arena, global_arena, arguments, expressions)?; } Op::ImageSampleImplicitLod | Op::ImageSampleExplicitLod => { let extra = inst.expect_at_least(5)?; @@ -1494,7 +1507,15 @@ impl> Parser { compare: false, project: false, }; - self.parse_image_sample(extra, options, type_arena, global_arena, expressions)?; + self.parse_image_sample( + extra, + options, + type_arena, + global_arena, + arguments, + expressions, + function_info, + )?; } Op::ImageSampleProjImplicitLod | Op::ImageSampleProjExplicitLod => { let extra = inst.expect_at_least(5)?; @@ -1502,7 +1523,15 @@ impl> Parser { compare: false, project: true, }; - self.parse_image_sample(extra, options, type_arena, global_arena, expressions)?; + self.parse_image_sample( + extra, + options, + type_arena, + global_arena, + arguments, + expressions, + function_info, + )?; } Op::ImageSampleDrefImplicitLod | Op::ImageSampleDrefExplicitLod => { let extra = inst.expect_at_least(6)?; @@ -1510,7 +1539,15 @@ impl> Parser { compare: true, project: false, }; - self.parse_image_sample(extra, options, type_arena, global_arena, expressions)?; + self.parse_image_sample( + extra, + options, + type_arena, + global_arena, + arguments, + expressions, + function_info, + )?; } Op::ImageSampleProjDrefImplicitLod | Op::ImageSampleProjDrefExplicitLod => { let extra = inst.expect_at_least(6)?; @@ -1518,7 +1555,15 @@ impl> Parser { compare: true, project: true, }; - self.parse_image_sample(extra, options, type_arena, global_arena, expressions)?; + self.parse_image_sample( + extra, + options, + type_arena, + global_arena, + arguments, + expressions, + function_info, + )?; } Op::ImageQuerySize => { inst.expect(4)?; @@ -2199,14 +2244,19 @@ impl> Parser { /// 1. Function call targets are replaced by `deferred_function_calls` map /// 2. Lift the contents of "If" that only breaks on rejection, onto the parent after it. /// 3. Lift the contents of "Switch" that only has a default, onto the parent after it. - fn patch_statements(&self, statements: &mut crate::Block) -> Result<(), Error> { + fn patch_statements( + &mut self, + statements: &mut crate::Block, + expressions: &mut Arena, + function: Option>, + ) -> Result<(), Error> { use crate::Statement as S; let mut i = 0usize; while i < statements.len() { match statements[i] { S::Emit(_) => {} S::Block(ref mut block) => { - self.patch_statements(block)?; + self.patch_statements(block, expressions, function)?; } S::If { condition: _, @@ -2218,8 +2268,8 @@ impl> Parser { let extracted = mem::take(accept); statements.splice(i + 1..i + 1, extracted.into_iter()); } else { - self.patch_statements(reject)?; - self.patch_statements(accept)?; + self.patch_statements(reject, expressions, function)?; + self.patch_statements(accept, expressions, function)?; } } S::Switch { @@ -2233,17 +2283,17 @@ impl> Parser { statements.splice(i + 1..i + 1, extracted.into_iter()); } else { for case in cases.iter_mut() { - self.patch_statements(&mut case.body)?; + self.patch_statements(&mut case.body, expressions, function)?; } - self.patch_statements(default)?; + self.patch_statements(default, expressions, function)?; } } S::Loop { ref mut body, ref mut continuing, } => { - self.patch_statements(body)?; - self.patch_statements(continuing)?; + self.patch_statements(body, expressions, function)?; + self.patch_statements(continuing, expressions, function)?; } S::Break | S::Continue @@ -2253,10 +2303,39 @@ impl> Parser { | S::Store { .. } | S::ImageStore { .. } => {} S::Call { - ref mut function, .. + function: ref mut callee, + ref arguments, + .. } => { - let fun_id = self.deferred_function_calls[function.index()]; - *function = *self.lookup_function.lookup(fun_id)?; + let fun_id = self.deferred_function_calls[callee.index()]; + let handle = *self.lookup_function.lookup(fun_id)?; + + // Patch sampling flags + for (i, arg) in arguments.iter().enumerate() { + let callee_info = &self.function_info[&handle]; + + if let Some(flags) = callee_info.parameters_sampling.get(i).and_then(|e| *e) + { + match expressions[*arg] { + crate::Expression::GlobalVariable(handle) => { + *self.handle_sampling.get_mut(&handle).unwrap() |= flags + } + crate::Expression::FunctionArgument(i) => { + if let Some(handle) = function { + let function_info = + self.function_info.get_mut(&handle).unwrap(); + let caller_flags = function_info.parameters_sampling + [i as usize] + .get_or_insert(image::SamplingFlags::empty()); + *caller_flags |= flags; + } + } + ref other => return Err(Error::InvalidGlobalVar(other.clone())), + } + } + } + + *callee = handle; } } i += 1; @@ -2264,14 +2343,18 @@ impl> Parser { Ok(()) } - fn patch_function(&self, fun: &mut crate::Function) -> Result<(), Error> { + fn patch_function( + &mut self, + handle: Option>, + fun: &mut crate::Function, + ) -> Result<(), Error> { for (_, expr) in fun.expressions.iter_mut() { if let crate::Expression::Call(ref mut function) = *expr { let fun_id = self.deferred_function_calls[function.index()]; *function = *self.lookup_function.lookup(fun_id)?; } } - self.patch_statements(&mut fun.body)?; + self.patch_statements(&mut fun.body, &mut fun.expressions, handle)?; Ok(()) } @@ -2380,11 +2463,11 @@ impl> Parser { } } // patch all the functions - for (_, fun) in module.functions.iter_mut() { - self.patch_function(fun)?; + for (handle, fun) in module.functions.iter_mut() { + self.patch_function(Some(handle), fun)?; } for ep in module.entry_points.iter_mut() { - self.patch_function(&mut ep.function)?; + self.patch_function(None, &mut ep.function)?; } // Check all the images and samplers to have consistent comparison property.