Handle padding for struct members in buffers.

Fixes earlier issues with struct-packing test.
This commit is contained in:
Hans-Kristian Arntzen 2016-05-05 16:32:15 +02:00
parent 2d38c6e192
commit 44ef367141
3 changed files with 36 additions and 13 deletions

View File

@ -32,12 +32,16 @@ struct Content
S2 m2s[1];
S0 m0;
S1 m1;
float m4;
S2 m2;
S3 m3;
float m4;
};
layout(binding = 1, std430) buffer SSBO1
{
Content content;
Content content1[2];
Content content2;
mat2 m0;
mat2 m1;
mat2x3 m2[4];
@ -46,10 +50,7 @@ layout(binding = 1, std430) buffer SSBO1
layout(row_major) mat2 m5[9];
layout(row_major) mat2x3 m6[2][4];
layout(row_major) mat3x2 m7;
float array[1024];
Content content;
Content content1[2];
Content content2;
float array[];
} ssbo_430;
layout(binding = 0, std140) buffer SSBO0

View File

@ -32,12 +32,17 @@ struct Content
S2 m2s[1];
S0 m0;
S1 m1;
float m4;
S2 m2;
S3 m3;
float m4;
};
layout(binding = 1, std430) buffer SSBO1
{
Content content;
Content content1[2];
Content content2;
layout(column_major) mat2 m0;
layout(column_major) mat2 m1;
layout(column_major) mat2x3 m2[4];
@ -46,11 +51,7 @@ layout(binding = 1, std430) buffer SSBO1
layout(row_major) mat2 m5[9];
layout(row_major) mat2x3 m6[4][2];
layout(row_major) mat3x2 m7;
float array[1024];
Content content;
Content content1[2];
Content content2;
float array[];
} ssbo_430;
layout(binding = 0, std140) buffer SSBO0

View File

@ -584,11 +584,23 @@ uint32_t CompilerGLSL::type_to_std430_size(const SPIRType &type, uint64_t flags)
if (type.basetype == SPIRType::Struct)
{
uint32_t pad_alignment = 1;
for (uint32_t i = 0; i < type.member_types.size(); i++)
{
auto member_flags = meta[type.self].members.at(i).decoration_flags;
auto &member_type = get<SPIRType>(type.member_types[i]);
uint32_t alignment = type_to_std430_alignment(member_type, member_flags);
uint32_t std430_alignment = type_to_std430_alignment(member_type, member_flags);
uint32_t alignment = max(std430_alignment, pad_alignment);
// The next member following a struct member is aligned to the base alignment of the struct that came before.
// GL 4.5 spec, 7.6.2.2.
if (member_type.basetype == SPIRType::Struct)
pad_alignment = std430_alignment;
else
pad_alignment = 1;
size = (size + alignment - 1) & ~(alignment - 1);
size += type_to_std430_size(member_type, member_flags);
}
@ -634,6 +646,7 @@ bool CompilerGLSL::ssbo_is_std430_packing(const SPIRType &type)
// std430 only removes the vec4 requirement.
uint32_t offset = 0;
uint32_t pad_alignment = 1;
for (uint32_t i = 0; i < type.member_types.size(); i++)
{
@ -642,7 +655,15 @@ bool CompilerGLSL::ssbo_is_std430_packing(const SPIRType &type)
// Verify alignment rules.
uint32_t std430_alignment = type_to_std430_alignment(memb_type, member_flags);
offset = (offset + std430_alignment - 1) & ~(std430_alignment - 1);
uint32_t alignment = max(std430_alignment, pad_alignment);
offset = (offset + alignment - 1) & ~(alignment - 1);
// The next member following a struct member is aligned to the base alignment of the struct that came before.
// GL 4.5 spec, 7.6.2.2.
if (memb_type.basetype == SPIRType::Struct)
pad_alignment = std430_alignment;
else
pad_alignment = 1;
uint32_t actual_offset = type_struct_member_offset(type, i);
if (actual_offset != offset) // This cannot be std430.