mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[spv-in] Support texture/sampler function argument
This commit is contained in:
committed by
Dzmitry Malyshau
parent
e32f10f940
commit
f98b4e2f48
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user