glsl-in: Flatten entry point arguments

The IR doesn't allow having structs has bindings for entry point
input/output, so the glsl frontend must flatten them.

Glsl defines that the locations are sequential from the block base location.
This commit is contained in:
João Capucho 2021-12-15 21:11:48 +00:00 committed by Dzmitry Malyshau
parent 049b48b319
commit 9c75f3cdce
3 changed files with 166 additions and 29 deletions

View File

@ -1058,6 +1058,82 @@ impl Parser {
});
}
/// Helper function for building the input/output interface of the entry point
///
/// Calls `f` with the data of the entry point argument, flattening composite types
/// recursively
///
/// The passed arguments to the callback are:
/// - The name
/// - The pointer expression to the global storage
/// - The handle to the type of the entry point argument
/// - The binding of the entry point argument
/// - The expression arena
fn arg_type_walker(
&self,
name: Option<String>,
binding: crate::Binding,
pointer: Handle<Expression>,
ty: Handle<Type>,
expressions: &mut Arena<Expression>,
f: &mut impl FnMut(
Option<String>,
Handle<Expression>,
Handle<Type>,
crate::Binding,
&mut Arena<Expression>,
),
) {
match self.module.types[ty].inner {
TypeInner::Struct { ref members, .. } => {
let mut location = match binding {
crate::Binding::Location { location, .. } => location,
_ => return,
};
for (i, member) in members.iter().enumerate() {
let member_pointer = expressions.append(
Expression::AccessIndex {
base: pointer,
index: i as u32,
},
crate::Span::default(),
);
let binding = match member.binding.clone() {
Some(binding) => binding,
None => {
let interpolation = self.module.types[member.ty]
.inner
.scalar_kind()
.map(|kind| match kind {
ScalarKind::Float => crate::Interpolation::Perspective,
_ => crate::Interpolation::Flat,
});
let binding = crate::Binding::Location {
location,
interpolation,
sampling: None,
};
location += 1;
binding
}
};
self.arg_type_walker(
member.name.clone(),
binding,
member_pointer,
member.ty,
expressions,
f,
)
}
}
_ => f(name, pointer, ty, binding, expressions),
}
}
pub(crate) fn add_entry_point(
&mut self,
function: Handle<Function>,
@ -1079,20 +1155,29 @@ impl Parser {
continue;
}
let ty = self.module.global_variables[arg.handle].ty;
let idx = arguments.len() as u32;
arguments.push(FunctionArgument {
name: arg.name.clone(),
ty,
binding: Some(arg.binding.clone()),
});
let pointer =
expressions.append(Expression::GlobalVariable(arg.handle), Default::default());
let value = expressions.append(Expression::FunctionArgument(idx), Default::default());
body.push(Statement::Store { pointer, value }, Default::default());
self.arg_type_walker(
arg.name.clone(),
arg.binding.clone(),
pointer,
self.module.global_variables[arg.handle].ty,
&mut expressions,
&mut |name, pointer, ty, binding, expressions| {
let idx = arguments.len() as u32;
arguments.push(FunctionArgument {
name,
ty,
binding: Some(binding),
});
let value =
expressions.append(Expression::FunctionArgument(idx), Default::default());
body.push(Statement::Store { pointer, value }, Default::default());
},
)
}
body.extend_block(global_init_body);
@ -1115,26 +1200,34 @@ impl Parser {
continue;
}
let ty = self.module.global_variables[arg.handle].ty;
members.push(StructMember {
name: arg.name.clone(),
ty,
binding: Some(arg.binding.clone()),
offset: span,
});
span += self.module.types[ty].inner.span(&self.module.constants);
let pointer =
expressions.append(Expression::GlobalVariable(arg.handle), Default::default());
let len = expressions.len();
let load = expressions.append(Expression::Load { pointer }, Default::default());
body.push(
Statement::Emit(expressions.range_from(len)),
Default::default(),
);
components.push(load)
self.arg_type_walker(
arg.name.clone(),
arg.binding.clone(),
pointer,
self.module.global_variables[arg.handle].ty,
&mut expressions,
&mut |name, pointer, ty, binding, expressions| {
members.push(StructMember {
name,
ty,
binding: Some(binding),
offset: span,
});
span += self.module.types[ty].inner.span(&self.module.constants);
let len = expressions.len();
let load = expressions.append(Expression::Load { pointer }, Default::default());
body.push(
Statement::Emit(expressions.range_from(len)),
Default::default(),
);
components.push(load)
},
)
}
let (ty, value) = if !components.is_empty() {

View File

@ -0,0 +1,14 @@
#version 450
layout(location = 0) in VertexData {
vec2 position;
vec2 a;
} vert;
layout(location = 0) out FragmentData {
vec2 position;
vec2 a;
} frag;
void main() {
}

View File

@ -0,0 +1,30 @@
struct VertexData {
position: vec2<f32>;
a: vec2<f32>;
};
struct FragmentData {
position: vec2<f32>;
a: vec2<f32>;
};
struct VertexOutput {
[[location(0)]] position: vec2<f32>;
[[location(1)]] a: vec2<f32>;
};
var<private> vert: VertexData;
var<private> frag: FragmentData;
fn main_1() {
}
[[stage(vertex)]]
fn main([[location(0)]] position: vec2<f32>, [[location(1)]] a: vec2<f32>) -> VertexOutput {
vert.position = position;
vert.a = a;
main_1();
let _e17 = frag.position;
let _e19 = frag.a;
return VertexOutput(_e17, _e19);
}