mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[glsl-in] Fix input/output handling
Previously we passed a struct with the input bindings and just ignored the outputs. Now we handle them the same way we do with builtins, by creating function local globals that are read and written in a wrapper entry point.
This commit is contained in:
committed by
Dzmitry Malyshau
parent
e4bc844ba0
commit
9ddca9cef5
@@ -1,6 +1,6 @@
|
||||
use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind, SourceMetadata};
|
||||
use crate::{
|
||||
proc::ResolveContext, Arena, BinaryOperator, Block, BuiltIn, Constant, Expression, FastHashMap,
|
||||
proc::ResolveContext, Arena, BinaryOperator, Binding, Block, Constant, Expression, FastHashMap,
|
||||
Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, Module,
|
||||
RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, Type,
|
||||
TypeInner, UnaryOperator,
|
||||
@@ -9,7 +9,6 @@ use crate::{
|
||||
#[derive(Debug)]
|
||||
pub enum GlobalLookup {
|
||||
Variable(Handle<GlobalVariable>),
|
||||
InOutSelect(u32),
|
||||
BlockSelect(Handle<GlobalVariable>, u32),
|
||||
}
|
||||
|
||||
@@ -38,19 +37,14 @@ pub struct Program<'a> {
|
||||
pub lookup_global_variables: FastHashMap<String, GlobalLookup>,
|
||||
pub lookup_constants: FastHashMap<String, Handle<Constant>>,
|
||||
|
||||
pub built_ins: Vec<(BuiltIn, Handle<GlobalVariable>)>,
|
||||
pub entry_args: Vec<(Binding, bool, Handle<GlobalVariable>)>,
|
||||
pub entries: Vec<(String, ShaderStage, Handle<Function>)>,
|
||||
|
||||
pub input_struct: Handle<Type>,
|
||||
pub output_struct: Handle<Type>,
|
||||
|
||||
pub module: Module,
|
||||
}
|
||||
|
||||
impl<'a> Program<'a> {
|
||||
pub fn new(entry_points: &'a FastHashMap<String, ShaderStage>) -> Program<'a> {
|
||||
let mut module = Module::default();
|
||||
|
||||
Program {
|
||||
version: 0,
|
||||
profile: Profile::Core,
|
||||
@@ -61,27 +55,10 @@ impl<'a> Program<'a> {
|
||||
lookup_global_variables: FastHashMap::default(),
|
||||
lookup_constants: FastHashMap::default(),
|
||||
|
||||
built_ins: Vec::new(),
|
||||
entry_args: Vec::new(),
|
||||
entries: Vec::new(),
|
||||
|
||||
input_struct: module.types.append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Struct {
|
||||
level: crate::StructLevel::Root,
|
||||
members: Vec::new(),
|
||||
span: 0,
|
||||
},
|
||||
}),
|
||||
output_struct: module.types.append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Struct {
|
||||
level: crate::StructLevel::Root,
|
||||
members: Vec::new(),
|
||||
span: 0,
|
||||
},
|
||||
}),
|
||||
|
||||
module,
|
||||
module: Module::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,17 +132,6 @@ impl<'a> Program<'a> {
|
||||
|
||||
solver.solve(root).map_err(|e| (meta, e).into())
|
||||
}
|
||||
|
||||
pub fn function_args_prelude(&self) -> (Vec<FunctionArgument>, Vec<ParameterQualifier>) {
|
||||
(
|
||||
vec![FunctionArgument {
|
||||
name: None,
|
||||
ty: self.input_struct,
|
||||
binding: None,
|
||||
}],
|
||||
vec![ParameterQualifier::In],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -223,11 +189,6 @@ impl<'function> Context<'function> {
|
||||
self.lookup_global_var_exps.get(name).cloned().or_else(|| {
|
||||
let expr = match *program.lookup_global_variables.get(name)? {
|
||||
GlobalLookup::Variable(v) => Expression::GlobalVariable(v),
|
||||
GlobalLookup::InOutSelect(index) => {
|
||||
let base = self.expressions.append(Expression::FunctionArgument(0));
|
||||
|
||||
Expression::AccessIndex { base, index }
|
||||
}
|
||||
GlobalLookup::BlockSelect(handle, index) => {
|
||||
let base = self.expressions.append(Expression::GlobalVariable(handle));
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
proc::ensure_block_returns, Arena, BinaryOperator, Binding, Block, BuiltIn, EntryPoint,
|
||||
Expression, Function, FunctionArgument, FunctionResult, Handle, MathFunction,
|
||||
RelationalFunction, SampleLevel, ScalarKind, ShaderStage, Statement, StorageClass, Type,
|
||||
TypeInner,
|
||||
RelationalFunction, SampleLevel, ScalarKind, ShaderStage, Statement, StorageClass,
|
||||
StructMember, Type, TypeInner,
|
||||
};
|
||||
|
||||
use super::{ast::*, error::ErrorKind, SourceMetadata};
|
||||
@@ -223,14 +223,15 @@ impl Program<'_> {
|
||||
self.parse_relational_fun(ctx, name, &args, RelationalFunction::Any, meta)
|
||||
}
|
||||
_ => {
|
||||
let sig = FunctionSignature {
|
||||
name,
|
||||
parameters: args
|
||||
.iter()
|
||||
.zip(raw_args.iter().map(|e| e.meta.clone()))
|
||||
.map(|(e, meta)| self.resolve_handle(ctx, *e, meta))
|
||||
.collect::<Result<_, _>>()?,
|
||||
};
|
||||
let mut parameters = Vec::new();
|
||||
|
||||
for (e, meta) in args.iter().zip(raw_args.iter().map(|e| e.meta.clone())) {
|
||||
let handle = self.resolve_handle(ctx, *e, meta)?;
|
||||
|
||||
parameters.push(handle)
|
||||
}
|
||||
|
||||
let sig = FunctionSignature { name, parameters };
|
||||
|
||||
let function = self
|
||||
.lookup_function
|
||||
@@ -390,20 +391,19 @@ impl Program<'_> {
|
||||
let mut expressions = Arena::new();
|
||||
let mut body = Vec::new();
|
||||
|
||||
arguments.push(FunctionArgument {
|
||||
name: None,
|
||||
ty: self.input_struct,
|
||||
binding: None,
|
||||
});
|
||||
for (binding, input, handle) in self.entry_args.iter().cloned() {
|
||||
match binding {
|
||||
Binding::Location { .. } if !input => continue,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
for (built_in, handle) in self.built_ins.iter().copied() {
|
||||
let ty = self.module.global_variables[handle].ty;
|
||||
let arg = arguments.len() as u32;
|
||||
|
||||
arguments.push(FunctionArgument {
|
||||
name: None,
|
||||
ty,
|
||||
binding: Some(Binding::BuiltIn(built_in)),
|
||||
binding: Some(binding),
|
||||
});
|
||||
|
||||
let pointer = expressions.append(Expression::GlobalVariable(handle));
|
||||
@@ -412,25 +412,49 @@ impl Program<'_> {
|
||||
body.push(Statement::Store { pointer, value });
|
||||
}
|
||||
|
||||
let res = expressions.append(Expression::Call(function));
|
||||
|
||||
body.push(Statement::Call {
|
||||
function,
|
||||
arguments: vec![expressions.append(Expression::FunctionArgument(0))],
|
||||
result: Some(res),
|
||||
arguments: Vec::new(),
|
||||
result: None,
|
||||
});
|
||||
|
||||
for (i, (built_in, handle)) in self.built_ins.iter().copied().enumerate() {
|
||||
if !should_write(built_in, stage) {
|
||||
continue;
|
||||
let mut span = 0;
|
||||
let mut members = Vec::new();
|
||||
let mut components = Vec::new();
|
||||
|
||||
for (binding, input, handle) in self.entry_args.iter().cloned() {
|
||||
match binding {
|
||||
Binding::Location { .. } if input => continue,
|
||||
Binding::BuiltIn(builtin) if !should_write(builtin, stage) => continue,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let value = expressions.append(Expression::GlobalVariable(handle));
|
||||
let pointer = expressions.append(Expression::FunctionArgument(i as u32 + 1));
|
||||
let ty = self.module.global_variables[handle].ty;
|
||||
|
||||
body.push(Statement::Store { pointer, value });
|
||||
members.push(StructMember {
|
||||
name: None,
|
||||
ty,
|
||||
binding: Some(binding),
|
||||
offset: span,
|
||||
});
|
||||
|
||||
span += self.module.types[ty].inner.span(&self.module.constants);
|
||||
|
||||
let pointer = expressions.append(Expression::GlobalVariable(handle));
|
||||
let load = expressions.append(Expression::Load { pointer });
|
||||
components.push(load)
|
||||
}
|
||||
|
||||
let ty = self.module.types.append(Type {
|
||||
name: None,
|
||||
inner: TypeInner::Struct {
|
||||
top_level: true,
|
||||
members,
|
||||
span,
|
||||
},
|
||||
});
|
||||
|
||||
let res = expressions.append(Expression::Compose { ty, components });
|
||||
body.push(Statement::Return { value: Some(res) });
|
||||
|
||||
self.module.entry_points.push(EntryPoint {
|
||||
@@ -443,10 +467,7 @@ impl Program<'_> {
|
||||
arguments,
|
||||
expressions,
|
||||
body,
|
||||
result: Some(FunctionResult {
|
||||
ty: self.output_struct,
|
||||
binding: None,
|
||||
}),
|
||||
result: Some(FunctionResult { ty, binding: None }),
|
||||
..Default::default()
|
||||
},
|
||||
});
|
||||
|
||||
@@ -569,8 +569,8 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> {
|
||||
let result = ty.map(|ty| FunctionResult { ty, binding: None });
|
||||
let mut expressions = Arena::new();
|
||||
let mut local_variables = Arena::new();
|
||||
let (mut arguments, mut parameters) =
|
||||
self.program.function_args_prelude();
|
||||
let mut arguments = Vec::new();
|
||||
let mut parameters = Vec::new();
|
||||
|
||||
let mut context = Context::new(
|
||||
&mut expressions,
|
||||
|
||||
@@ -337,6 +337,21 @@ fn functions() {
|
||||
|
||||
println!();
|
||||
|
||||
let _program = parse_program(
|
||||
r#"
|
||||
# version 450
|
||||
float callee(uint q) {
|
||||
return float(q);
|
||||
}
|
||||
|
||||
float caller() {
|
||||
callee(1u);
|
||||
}
|
||||
"#,
|
||||
&entry_points,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Nested function call
|
||||
let _program = parse_program(
|
||||
r#"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Binding, BuiltIn, Constant, Expression, GlobalVariable, Handle, LocalVariable, ScalarKind,
|
||||
StorageAccess, StorageClass, StructMember, Type, TypeInner, VectorSize,
|
||||
StorageAccess, StorageClass, Type, TypeInner, VectorSize,
|
||||
};
|
||||
|
||||
use super::ast::*;
|
||||
@@ -50,7 +50,8 @@ impl Program<'_> {
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.built_ins.push((BuiltIn::Position, handle));
|
||||
self.entry_args
|
||||
.push((Binding::BuiltIn(BuiltIn::Position), true, handle));
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name.into(), GlobalLookup::Variable(handle));
|
||||
@@ -75,7 +76,8 @@ impl Program<'_> {
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.built_ins.push((BuiltIn::VertexIndex, handle));
|
||||
self.entry_args
|
||||
.push((Binding::BuiltIn(BuiltIn::VertexIndex), true, handle));
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name.into(), GlobalLookup::Variable(handle));
|
||||
@@ -100,7 +102,8 @@ impl Program<'_> {
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.built_ins.push((BuiltIn::InstanceIndex, handle));
|
||||
self.entry_args
|
||||
.push((Binding::BuiltIn(BuiltIn::InstanceIndex), true, handle));
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name.into(), GlobalLookup::Variable(handle));
|
||||
@@ -312,24 +315,29 @@ impl Program<'_> {
|
||||
if let Some(location) = location {
|
||||
let input = StorageQualifier::Input == storage;
|
||||
|
||||
let index = self.add_member(
|
||||
input,
|
||||
Some(name.clone()),
|
||||
let handle = self.module.global_variables.append(GlobalVariable {
|
||||
name: Some(name.clone()),
|
||||
class: StorageClass::Function,
|
||||
binding: None,
|
||||
ty,
|
||||
Some(Binding::Location {
|
||||
init,
|
||||
storage_access: StorageAccess::all(),
|
||||
});
|
||||
|
||||
self.entry_args.push((
|
||||
Binding::Location {
|
||||
location,
|
||||
interpolation,
|
||||
sampling,
|
||||
}),
|
||||
);
|
||||
},
|
||||
input,
|
||||
handle,
|
||||
));
|
||||
|
||||
self.lookup_global_variables
|
||||
.insert(name, GlobalLookup::InOutSelect(index));
|
||||
.insert(name, GlobalLookup::Variable(handle));
|
||||
|
||||
let base = ctx.expressions.append(Expression::FunctionArgument(0));
|
||||
return Ok(ctx
|
||||
.expressions
|
||||
.append(Expression::AccessIndex { base, index }));
|
||||
return Ok(ctx.expressions.append(Expression::GlobalVariable(handle)));
|
||||
} else if let StorageQualifier::Const = storage {
|
||||
let handle = init.ok_or_else(|| {
|
||||
ErrorKind::SemanticError(meta, "Constant must have a initializer".into())
|
||||
@@ -405,48 +413,4 @@ impl Program<'_> {
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn add_member(
|
||||
&mut self,
|
||||
input: bool,
|
||||
name: Option<String>,
|
||||
ty: Handle<Type>,
|
||||
binding: Option<Binding>,
|
||||
) -> u32 {
|
||||
let handle = match input {
|
||||
true => self.input_struct,
|
||||
false => self.output_struct,
|
||||
};
|
||||
|
||||
let offset = if let TypeInner::Struct { ref members, .. } = self.module.types[handle].inner
|
||||
{
|
||||
members
|
||||
.last()
|
||||
.map(|member| {
|
||||
member.offset
|
||||
+ self.module.types[member.ty]
|
||||
.inner
|
||||
.span(&self.module.constants)
|
||||
})
|
||||
.unwrap_or(0)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if let TypeInner::Struct {
|
||||
ref mut members, ..
|
||||
} = self.module.types.get_mut(handle).inner
|
||||
{
|
||||
members.push(StructMember {
|
||||
name,
|
||||
ty,
|
||||
binding,
|
||||
offset,
|
||||
});
|
||||
|
||||
members.len() as u32 - 1
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user