[spv-in] Support texture/sampler function argument

This commit is contained in:
João Capucho
2021-06-24 22:00:52 +01:00
committed by Dzmitry Malyshau
parent e32f10f940
commit f98b4e2f48
3 changed files with 167 additions and 52 deletions

View File

@@ -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<I: Iterator<Item = u32>> super::Parser<I> {
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<I: Iterator<Item = u32>> super::Parser<I> {
&mut module.constants,
&module.types,
&module.global_variables,
&fun.arguments,
&mut function_info,
)?;
flow_graph.add_node(node);
@@ -187,6 +193,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
// 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 {

View File

@@ -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<crate::Expression> {
fn get_global_var(
fn get_image_expr_ty(
&self,
handle: Handle<crate::Expression>,
) -> Result<Handle<crate::GlobalVariable>, Error> {
global_vars: &Arena<crate::GlobalVariable>,
arguments: &[FunctionArgument],
) -> Result<Handle<crate::Type>, 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<I: Iterator<Item = u32>> super::Parser<I> {
words_left: u16,
type_arena: &Arena<crate::Type>,
global_arena: &Arena<crate::GlobalVariable>,
arguments: &[FunctionArgument],
expressions: &mut Arena<crate::Expression>,
) -> Result<crate::Statement, Error> {
let image_id = self.next()?;
@@ -246,12 +253,11 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
}
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<I: Iterator<Item = u32>> super::Parser<I> {
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<I: Iterator<Item = u32>> super::Parser<I> {
mut words_left: u16,
type_arena: &Arena<crate::Type>,
global_arena: &Arena<crate::GlobalVariable>,
arguments: &[FunctionArgument],
expressions: &mut Arena<crate::Expression>,
) -> Result<(), Error> {
let result_type_id = self.next()?;
@@ -328,12 +335,11 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
}
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<I: Iterator<Item = u32>> super::Parser<I> {
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<I: Iterator<Item = u32>> super::Parser<I> {
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub(super) fn parse_image_sample(
&mut self,
mut words_left: u16,
options: SamplingOptions,
type_arena: &Arena<crate::Type>,
global_arena: &Arena<crate::GlobalVariable>,
arguments: &[FunctionArgument],
expressions: &mut Arena<crate::Expression>,
function_info: &mut FunctionInfo,
) -> Result<(), Error> {
let result_type_id = self.next()?;
let result_id = self.next()?;
@@ -432,26 +441,42 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
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<I: Iterator<Item = u32>> super::Parser<I> {
type_arena,
expressions,
),
_ => return Err(Error::InvalidImage(image_var.ty)),
_ => return Err(Error::InvalidImage(image_ty)),
};
let expr = crate::Expression::ImageSample {

View File

@@ -371,6 +371,10 @@ impl Default for Options {
}
}
struct FunctionInfo {
parameters_sampling: Vec<Option<image::SamplingFlags>>,
}
pub struct Parser<I> {
data: I,
state: ModuleState,
@@ -405,6 +409,7 @@ pub struct Parser<I> {
options: Options,
index_constants: Vec<Handle<crate::Constant>>,
index_constant_expressions: Vec<Handle<crate::Expression>>,
function_info: FastHashMap<Handle<crate::Function>, FunctionInfo>,
}
impl<I: Iterator<Item = u32>> Parser<I> {
@@ -436,6 +441,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
options: options.clone(),
index_constants: Vec::new(),
index_constant_expressions: Vec::new(),
function_info: FastHashMap::default(),
}
}
@@ -783,6 +789,8 @@ impl<I: Iterator<Item = u32>> Parser<I> {
const_arena: &mut Arena<crate::Constant>,
type_arena: &Arena<crate::Type>,
global_arena: &Arena<crate::GlobalVariable>,
arguments: &[crate::FunctionArgument],
function_info: &mut FunctionInfo,
) -> Result<ControlFlowNode, Error> {
let mut block = Vec::new();
let mut phis = Vec::new();
@@ -1479,14 +1487,19 @@ impl<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
/// 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<crate::Expression>,
function: Option<Handle<crate::Function>>,
) -> 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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
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<I: Iterator<Item = u32>> Parser<I> {
| 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<I: Iterator<Item = u32>> Parser<I> {
Ok(())
}
fn patch_function(&self, fun: &mut crate::Function) -> Result<(), Error> {
fn patch_function(
&mut self,
handle: Option<Handle<crate::Function>>,
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<I: Iterator<Item = u32>> Parser<I> {
}
}
// 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.