[naga spv-in] Lay out entry point output structs correctly.

In the SPIR-V front end, when generating Naga IR `Struct` types to
represent a SPIR-V entry point's `Output` variables, instead of saying
"0xFFFF, // shouldn't matter", follow the usual rules in assigning
struct member offsets and computing an overall
size (`TypeInner::Struct::span`) for the resulting struct type.
This commit is contained in:
Jim Blandy 2025-06-14 11:28:42 -07:00
parent 0aa1baface
commit 48eae68156
4 changed files with 25 additions and 7 deletions

View File

@ -374,7 +374,15 @@ impl<I: Iterator<Item = u32>> super::Frontend<I> {
);
// 3. copy the outputs from privates to the result
//
// It would be nice to share struct layout code here with `parse_type_struct`,
// but that case needs to take into account offset decorations, which makes an
// abstraction harder to follow than just writing out what we mean. `Layouter`
// and `Alignment` cover the worst parts already.
let mut members = Vec::new();
self.layouter.update(module.to_ctx()).unwrap();
let mut next_member_offset = 0;
let mut struct_alignment = crate::proc::Alignment::ONE;
let mut components = Vec::new();
for &v_id in ep.variable_ids.iter() {
let lvar = self.lookup_variable.lookup(v_id)?;
@ -435,6 +443,11 @@ impl<I: Iterator<Item = u32>> super::Frontend<I> {
}
}
let member_alignment = self.layouter[sm.ty].alignment;
next_member_offset = member_alignment.round_up(next_member_offset);
sm.offset = next_member_offset;
struct_alignment = struct_alignment.max(member_alignment);
next_member_offset += self.layouter[sm.ty].size;
members.push(sm);
components.push(function.expressions.append(
@ -454,12 +467,16 @@ impl<I: Iterator<Item = u32>> super::Frontend<I> {
}
}
let member_alignment = self.layouter[result.ty].alignment;
next_member_offset = member_alignment.round_up(next_member_offset);
members.push(crate::StructMember {
name: None,
ty: result.ty,
binding,
offset: 0,
offset: next_member_offset,
});
struct_alignment = struct_alignment.max(member_alignment);
next_member_offset += self.layouter[result.ty].size;
// populate just the globals first, then do `Load` in a
// separate step, so that we can get a range.
components.push(expr_handle);
@ -545,7 +562,7 @@ impl<I: Iterator<Item = u32>> super::Frontend<I> {
name: None,
inner: crate::TypeInner::Struct {
members,
span: 0xFFFF, // shouldn't matter
span: struct_alignment.round_up(next_member_offset),
},
},
span,

View File

@ -160,10 +160,10 @@
binding: Some(BuiltIn(Position(
invariant: false,
))),
offset: 0,
offset: 16,
),
],
span: 65535,
span: 32,
),
),
],

View File

@ -251,10 +251,10 @@
binding: Some(BuiltIn(Position(
invariant: false,
))),
offset: 0,
offset: 16,
),
],
span: 65535,
span: 32,
),
),
],

View File

@ -15,6 +15,7 @@ struct gl_PerVertex {
};
struct VertexOutput {
metal::float2 member;
char _pad1[8];
metal::float4 gl_Position;
};
@ -53,6 +54,6 @@ vertex main_Output main_(
main_1(v_uv, a_uv_1, unnamed, a_pos_1);
metal::float2 _e7 = v_uv;
metal::float4 _e8 = unnamed.gl_Position;
const auto _tmp = VertexOutput {_e7, _e8};
const auto _tmp = VertexOutput {_e7, {}, _e8};
return main_Output { _tmp.member, _tmp.gl_Position };
}