Deal with scalar layout of entire structs.
Mark all candidate struct types.
This commit is contained in:
parent
12c5020854
commit
e90d816cdd
@ -1,5 +1,3 @@
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
@ -9,7 +7,7 @@ struct UBO
|
||||
{
|
||||
float4x4 uMVPR;
|
||||
float4x4 uMVPC;
|
||||
float2x4 uMVP;
|
||||
float4x4 uMVP;
|
||||
};
|
||||
|
||||
struct main0_out
|
||||
@ -22,16 +20,10 @@ struct main0_in
|
||||
float4 aVertex [[attribute(0)]];
|
||||
};
|
||||
|
||||
// Implementation of a conversion of matrix content from RowMajor to ColumnMajor organization.
|
||||
float2x4 spvConvertFromRowMajor2x4(float2x4 m)
|
||||
{
|
||||
return float2x4(float4(m[0][0], m[0][2], m[1][0], m[1][2]), float4(m[0][1], m[0][3], m[1][1], m[1][3]));
|
||||
}
|
||||
|
||||
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _18 [[buffer(0)]])
|
||||
{
|
||||
main0_out out = {};
|
||||
float2 v = in.aVertex * spvConvertFromRowMajor2x4(_18.uMVP);
|
||||
float2 v = in.aVertex * transpose(float2x4(_18.uMVP[0].xy, _18.uMVP[1].xy, _18.uMVP[2].xy, _18.uMVP[3].xy));
|
||||
out.gl_Position = (_18.uMVPR * in.aVertex) + (in.aVertex * _18.uMVPC);
|
||||
return out;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _18 [[buffer(0)]]
|
||||
main0_out out = {};
|
||||
out.gl_Position = _18.uMVP * in.aVertex;
|
||||
out.vColor = float4(0.0);
|
||||
float3 L = in.aVertex.xyz - float3(_18.light.Position);
|
||||
float3 L = in.aVertex.xyz - _18.light.Position;
|
||||
out.vColor += ((_18.light.Color * fast::clamp(1.0 - (length(L) / _18.light.Radius), 0.0, 1.0)) * dot(in.aNormal, normalize(L)));
|
||||
return out;
|
||||
}
|
||||
|
@ -1416,6 +1416,7 @@ enum ExtendedDecorations
|
||||
// Marks if the physical type is to be declared with tight packing rules, i.e. packed_floatN on MSL and friends.
|
||||
// If this is set, PhysicalTypeID might also be set. It can be set to same as logical type if all we're doing
|
||||
// is converting float3 to packed_float3 for example.
|
||||
// If this is marked on a struct, it means the struct itself must use only Packed types for all its members.
|
||||
SPIRVCrossDecorationPhysicalTypePacked,
|
||||
|
||||
// The padding in bytes before declaring this struct member.
|
||||
|
@ -2392,6 +2392,48 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l
|
||||
return type_id;
|
||||
}
|
||||
|
||||
void CompilerMSL::mark_scalar_layout_structs(const SPIRType &type)
|
||||
{
|
||||
uint32_t mbr_cnt = type.member_types.size();
|
||||
for (uint32_t i = 0; i < mbr_cnt; i++)
|
||||
{
|
||||
auto &mbr_type = get<SPIRType>(type.member_types[i]);
|
||||
if (mbr_type.basetype == SPIRType::Struct)
|
||||
{
|
||||
if (has_extended_decoration(mbr_type.self, SPIRVCrossDecorationPhysicalTypePacked))
|
||||
continue;
|
||||
|
||||
uint32_t msl_alignment = get_declared_struct_member_alignment_msl(type, i);
|
||||
uint32_t msl_size = get_declared_struct_member_size_msl(type, i);
|
||||
uint32_t spirv_offset = type_struct_member_offset(type, i);
|
||||
uint32_t spirv_offset_next;
|
||||
if (i + 1 < mbr_cnt)
|
||||
spirv_offset_next = type_struct_member_offset(type, i + 1);
|
||||
else
|
||||
spirv_offset_next = spirv_offset + msl_size;
|
||||
|
||||
// Both are complicated cases. In scalar layout, a struct of float3 might just consume 12 bytes,
|
||||
// and the next member will be placed at offset 12.
|
||||
bool struct_is_misaligned = (spirv_offset % msl_alignment) != 0;
|
||||
bool struct_is_too_large = spirv_offset + msl_size > spirv_offset_next;
|
||||
|
||||
if (struct_is_misaligned || struct_is_too_large)
|
||||
{
|
||||
set_extended_decoration(mbr_type.self, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
|
||||
// Problem case! Struct needs to be placed at an awkward alignment.
|
||||
// Mark every member of the child struct as packed.
|
||||
uint32_t child_mbr_cnt = mbr_type.member_types.size();
|
||||
for (uint32_t j = 0; j < child_mbr_cnt; j++)
|
||||
set_extended_member_decoration(mbr_type.self, j, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
}
|
||||
|
||||
// Traverse ...
|
||||
mark_scalar_layout_structs(mbr_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the members of the struct type by offset, and pack and then pad members where needed
|
||||
// to align MSL members with SPIR-V offsets. The struct members are iterated twice. Packing
|
||||
// occurs first, followed by padding, because packing a member reduces both its size and its
|
||||
@ -2550,7 +2592,9 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
||||
|
||||
uint32_t elems_per_stride = array_stride / (mbr_type.width / 8);
|
||||
|
||||
if (elems_per_stride > 4)
|
||||
if (elems_per_stride == 3)
|
||||
SPIRV_CROSS_THROW("Cannot use ArrayStride of 3 elements in remapping scenarios.");
|
||||
else if (elems_per_stride > 4)
|
||||
SPIRV_CROSS_THROW("Cannot represent vectors with more than 4 elements in MSL.");
|
||||
|
||||
auto physical_type = mbr_type;
|
||||
@ -2562,7 +2606,9 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
||||
set_decoration(type_id, DecorationArrayStride, array_stride);
|
||||
|
||||
// Remove packed_ for vectors of size 1, 2 and 4.
|
||||
if (elems_per_stride != 3)
|
||||
if (has_extended_decoration(ib_type.self, SPIRVCrossDecorationPhysicalTypePacked))
|
||||
SPIRV_CROSS_THROW("Unable to remove packed decoration as entire struct must be fully packed. Do not mix scalar and std140 layout rules.");
|
||||
else
|
||||
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
}
|
||||
else if (is_matrix(mbr_type))
|
||||
@ -2572,7 +2618,9 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
||||
|
||||
uint32_t elems_per_stride = matrix_stride / (mbr_type.width / 8);
|
||||
|
||||
if (elems_per_stride > 4)
|
||||
if (elems_per_stride == 3)
|
||||
SPIRV_CROSS_THROW("Cannot use ArrayStride of 3 elements in remapping scenarios.");
|
||||
else if (elems_per_stride > 4)
|
||||
SPIRV_CROSS_THROW("Cannot represent vectors with more than 4 elements in MSL.");
|
||||
|
||||
bool row_major = has_member_decoration(ib_type.self, index, DecorationRowMajor);
|
||||
@ -2588,7 +2636,9 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
||||
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypeID, type_id);
|
||||
|
||||
// Remove packed_ for vectors of size 1, 2 and 4.
|
||||
if (elems_per_stride != 3)
|
||||
if (has_extended_decoration(ib_type.self, SPIRVCrossDecorationPhysicalTypePacked))
|
||||
SPIRV_CROSS_THROW("Unable to remove packed decoration as entire struct must be fully packed. Do not mix scalar and std140 layout rules.");
|
||||
else
|
||||
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
}
|
||||
|
||||
@ -3566,6 +3616,16 @@ void CompilerMSL::emit_specialization_constants_and_structs()
|
||||
unordered_set<uint32_t> declared_structs;
|
||||
unordered_set<uint32_t> aligned_structs;
|
||||
|
||||
// First, we need to deal with scalar block layout.
|
||||
// It is possible that a struct may have to be placed at an alignment which does not match the innate alignment of the struct itself.
|
||||
// In that case, if such a case exists for a struct, we must force that all elements of the struct become packed_ types.
|
||||
// This makes the struct alignment as small as physically possible.
|
||||
// When we actually align the struct later, we can insert padding as necessary to make the packed members behave like normally aligned types.
|
||||
ir.for_each_typed_id<SPIRType>([&](uint32_t type_id, const SPIRType &type) {
|
||||
if (type.basetype == SPIRType::Struct && has_extended_decoration(type_id, SPIRVCrossDecorationBufferBlockRepacked))
|
||||
mark_scalar_layout_structs(type);
|
||||
});
|
||||
|
||||
// Very particular use of the soft loop lock.
|
||||
// align_struct may need to create custom types on the fly, but we don't care about
|
||||
// these types for purpose of iterating over them in ir.ids_for_type and friends.
|
||||
|
@ -535,6 +535,7 @@ protected:
|
||||
|
||||
std::string to_component_argument(uint32_t id);
|
||||
void align_struct(SPIRType &ib_type, std::unordered_set<uint32_t> &aligned_structs);
|
||||
void mark_scalar_layout_structs(const SPIRType &ib_type);
|
||||
void ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t index);
|
||||
bool validate_member_packing_rules_msl(const SPIRType &type, uint32_t index) const;
|
||||
std::string get_argument_address_space(const SPIRVariable &argument);
|
||||
|
Loading…
Reference in New Issue
Block a user