MSL sort interface struct members by offset instead of location.

MSL support OpFMod as fmod() function.
Remove SPIRType::is_packed member.
This commit is contained in:
Bill Hollings 2016-12-04 12:32:58 -05:00
parent b9600aa8d3
commit aca1b55449
3 changed files with 73 additions and 38 deletions

View File

@ -218,8 +218,6 @@ struct SPIRType : IVariant
std::vector<uint32_t> member_types;
bool is_packed = false; // Tightly packed in memory (no alignment padding)
struct Image
{
uint32_t type;

View File

@ -382,12 +382,21 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
// Set the binding of the variable and mark if packed (used only with vertex inputs)
auto &var_dec = meta[ib_var_id].decoration;
var_dec.binding = vtx_binding;
ib_type.is_packed = (execution.model == ExecutionModelVertex && storage == StorageClassInput &&
var_dec.binding != msl_config.vtx_attr_stage_in_binding);
// Track whether this is vertex input that is indexed, as opposed to stage_in
bool is_indxd_vtx_input = (execution.model == ExecutionModelVertex && storage == StorageClassInput &&
var_dec.binding != msl_config.vtx_attr_stage_in_binding);
string ib_var_ref;
if (storage == StorageClassInput)
ib_var_ref = ib_type.is_packed ? stage_in_var_name + convert_to_string(vtx_binding) : stage_in_var_name;
{
ib_var_ref = stage_in_var_name;
// Multiple vertex input bindings are available, so qualify each with the Metal buffer index
if (execution.model == ExecutionModelVertex)
ib_var_ref += convert_to_string(vtx_binding);
}
if (storage == StorageClassOutput)
{
@ -413,10 +422,10 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
bool first_elem = true;
for (auto p_var : vars)
{
// For packed vertex attributes, copy the attribute characteristics to the parent
// For index-accessed vertex attributes, copy the attribute characteristics to the parent
// structure (all components have same vertex attribute characteristics except offset),
// and add a reference to the vertex index builtin to the parent struct variable name.
if (ib_type.is_packed && first_elem)
if (is_indxd_vtx_input && first_elem)
{
auto &elem_dec = meta[p_var->self].decoration;
var_dec.binding = elem_dec.binding;
@ -435,7 +444,8 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
{
// If needed, add a padding member to the struct to align to the next member's offset.
uint32_t mbr_offset = get_member_decoration(type.self, i, DecorationOffset);
struct_size = pad_to_offset(ib_type, (var_dec.offset + mbr_offset), uint32_t(struct_size));
struct_size =
pad_to_offset(ib_type, is_indxd_vtx_input, (var_dec.offset + mbr_offset), uint32_t(struct_size));
// Add a reference to the member to the interface struct.
auto &membertype = get<SPIRType>(member);
@ -471,7 +481,7 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
else
{
// If needed, add a padding member to the struct to align to the next member's offset.
struct_size = pad_to_offset(ib_type, var_dec.offset, uint32_t(struct_size));
struct_size = pad_to_offset(ib_type, is_indxd_vtx_input, var_dec.offset, uint32_t(struct_size));
// Add a reference to the variable type to the interface struct.
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
@ -501,12 +511,9 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
}
}
if (!ib_type.is_packed)
{
// Sort the members of the interface structure, unless this is packed input
MemberSorterByLocation memberSorter(ib_type, meta[ib_type.self]);
memberSorter.sort();
}
// Sort the members of the interface structure by their offsets
MemberSorter memberSorter(ib_type, meta[ib_type.self], MemberSorter::Offset);
memberSorter.sort();
return ib_var_id;
}
@ -592,6 +599,12 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
switch (opcode)
{
// ALU
case OpFMod:
BFOP(fmod);
break;
// Comparisons
case OpIEqual:
case OpLogicalEqual:
@ -1167,9 +1180,8 @@ void CompilerMSL::emit_fixup()
// Returns a declaration for a structure member.
string CompilerMSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index)
{
bool should_pack = type.is_packed && is_vector(membertype);
return join((should_pack ? "packed_" : ""), type_to_glsl(membertype), " ", to_member_name(type, index),
type_to_array_glsl(membertype), member_attribute_qualifier(type, index));
return join(type_to_glsl(membertype), " ", to_member_name(type, index), type_to_array_glsl(membertype),
member_attribute_qualifier(type, index));
}
// Return a MSL qualifier for the specified function attribute member
@ -1271,13 +1283,21 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
return "";
}
// Returns the location decoration of the member with the specified index in the specified
// type, or the value of the member index if the location has not been specified.
// This function assumes the members are ordered in their location order.
// This can be ensured using the MemberSorterByLocation class.
// Returns the location decoration of the member with the specified index in the specified type.
// If the location of the member has been explicitly set, that location is used. If not, this
// function assumes the members are ordered in their location order, and simply returns the
// index as the location.
uint32_t CompilerMSL::get_ordered_member_location(uint32_t type_id, uint32_t index)
{
return max(get_member_decoration(type_id, index, DecorationLocation), index);
auto &m = meta.at(type_id);
if (index < m.members.size())
{
auto &dec = m.members[index];
if (dec.decoration_flags & (1ull << DecorationLocation))
return dec.location;
}
return index;
}
string CompilerMSL::constant_expression(const SPIRConstant &c)
@ -1526,13 +1546,14 @@ string CompilerMSL::get_vtx_idx_var_name(bool per_instance)
return "missing_vtx_idx_var";
}
// If the struct is packed, and the offset is greater than the current size of the struct,
// appends a padding member to the struct, and returns the offset to use for the next member,
// which is the offset provided. If the struct is not packed, or the offset is not greater
// than the struct size, no padding is added, and the struct size is returned.
uint32_t CompilerMSL::pad_to_offset(SPIRType &struct_type, uint32_t offset, uint32_t struct_size)
// If the struct contains indexed vertex input, and the offset is greater than the current
// size of the struct, appends a padding member to the struct, and returns the offset to
// use for the next member, which is the offset provided. Otherwise, no padding is added,
// and the struct size is returned.
uint32_t CompilerMSL::pad_to_offset(SPIRType &struct_type, bool is_indxd_vtx_input, uint32_t offset,
uint32_t struct_size)
{
if (!(struct_type.is_packed && offset > struct_size))
if (!(is_indxd_vtx_input && offset > struct_size))
return struct_size;
auto &pad_type = get_pad_type(offset - struct_size);
@ -1962,7 +1983,7 @@ size_t CompilerMSL::get_declared_type_size(const SPIRType &type, uint64_t dec_ma
}
// Sort both type and meta member content based on builtin status (put builtins at end), then by location.
void MemberSorterByLocation::sort()
void MemberSorter::sort()
{
// Create a temporary array of consecutive member indices and sort it base on
// how the members should be reordered, based on builtin and location meta info.
@ -1984,12 +2005,20 @@ void MemberSorterByLocation::sort()
}
// Sort first by builtin status (put builtins at end), then by location.
bool MemberSorterByLocation::operator()(uint32_t mbr_idx1, uint32_t mbr_idx2)
bool MemberSorter::operator()(uint32_t mbr_idx1, uint32_t mbr_idx2)
{
auto &mbr_meta1 = meta.members[mbr_idx1];
auto &mbr_meta2 = meta.members[mbr_idx2];
if (mbr_meta1.builtin != mbr_meta2.builtin)
return mbr_meta2.builtin;
else
return mbr_meta1.location < mbr_meta2.location;
switch (sort_aspect)
{
case Location:
return mbr_meta1.location < mbr_meta2.location;
case Offset:
return mbr_meta1.offset < mbr_meta2.offset;
default:
return false;
}
}

View File

@ -142,7 +142,7 @@ protected:
std::string get_vtx_idx_var_name(bool per_instance);
uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype);
uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index);
uint32_t pad_to_offset(SPIRType &struct_type, uint32_t offset, uint32_t struct_size);
uint32_t pad_to_offset(SPIRType &struct_type, bool is_indxd_vtx_input, uint32_t offset, uint32_t struct_size);
SPIRType &get_pad_type(uint32_t pad_len);
size_t get_declared_type_size(const SPIRType &type) const;
size_t get_declared_type_size(const SPIRType &type, uint64_t dec_mask) const;
@ -161,20 +161,28 @@ protected:
std::string sampler_name_suffix = "Smplr";
};
// Sorts the members of a SPIRType and associated Meta info based on the location
// and builtin decorations of the members. Members are rearranged by location,
// with all builtin members appearing a the end.
struct MemberSorterByLocation
// Sorts the members of a SPIRType and associated Meta info based on a settable sorting
// aspect, which defines which aspect of the struct members will be used to sort them.
// Regardless of the sorting aspect, built-in members always appear at the end of the struct.
struct MemberSorter
{
enum SortAspect
{
Location,
Offset,
};
void sort();
bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2);
MemberSorterByLocation(SPIRType &t, Meta &m)
MemberSorter(SPIRType &t, Meta &m, SortAspect sa)
: type(t)
, meta(m)
, sort_aspect(sa)
{
}
SPIRType &type;
Meta &meta;
SortAspect sort_aspect;
};
}