[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:
João Capucho
2021-05-16 18:42:01 +01:00
committed by Dzmitry Malyshau
parent e4bc844ba0
commit 9ddca9cef5
5 changed files with 96 additions and 135 deletions

View File

@@ -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));

View File

@@ -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()
},
});

View File

@@ -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,

View File

@@ -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#"

View File

@@ -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!()
}
}
}