[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 // 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(); 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(); let mut components = Vec::new();
for &v_id in ep.variable_ids.iter() { for &v_id in ep.variable_ids.iter() {
let lvar = self.lookup_variable.lookup(v_id)?; 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); members.push(sm);
components.push(function.expressions.append( 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 { members.push(crate::StructMember {
name: None, name: None,
ty: result.ty, ty: result.ty,
binding, 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 // populate just the globals first, then do `Load` in a
// separate step, so that we can get a range. // separate step, so that we can get a range.
components.push(expr_handle); components.push(expr_handle);
@ -545,7 +562,7 @@ impl<I: Iterator<Item = u32>> super::Frontend<I> {
name: None, name: None,
inner: crate::TypeInner::Struct { inner: crate::TypeInner::Struct {
members, members,
span: 0xFFFF, // shouldn't matter span: struct_alignment.round_up(next_member_offset),
}, },
}, },
span, span,

View File

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

View File

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

View File

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