Merge pull request #80 from brenwill/master

MSL sort interface struct members by offset instead of location.
This commit is contained in:
Hans-Kristian Arntzen 2016-12-05 09:08:55 +01:00 committed by GitHub
commit cc207e32c8
3 changed files with 73 additions and 44 deletions

View File

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

View File

@ -39,20 +39,14 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
vtx_attrs_by_location.clear(); vtx_attrs_by_location.clear();
if (p_vtx_attrs) if (p_vtx_attrs)
for (auto &va : *p_vtx_attrs) for (auto &va : *p_vtx_attrs)
{
va.used_by_shader = false;
vtx_attrs_by_location[va.location] = &va; vtx_attrs_by_location[va.location] = &va;
}
resource_bindings.clear(); resource_bindings.clear();
if (p_res_bindings) if (p_res_bindings)
{ {
resource_bindings.reserve(p_res_bindings->size()); resource_bindings.reserve(p_res_bindings->size());
for (auto &rb : *p_res_bindings) for (auto &rb : *p_res_bindings)
{
rb.used_by_shader = false;
resource_bindings.push_back(&rb); resource_bindings.push_back(&rb);
}
} }
extract_builtins(); extract_builtins();
@ -382,12 +376,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) // Set the binding of the variable and mark if packed (used only with vertex inputs)
auto &var_dec = meta[ib_var_id].decoration; auto &var_dec = meta[ib_var_id].decoration;
var_dec.binding = vtx_binding; 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; string ib_var_ref;
if (storage == StorageClassInput) 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) if (storage == StorageClassOutput)
{ {
@ -413,10 +416,10 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
bool first_elem = true; bool first_elem = true;
for (auto p_var : vars) 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), // 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. // 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; auto &elem_dec = meta[p_var->self].decoration;
var_dec.binding = elem_dec.binding; var_dec.binding = elem_dec.binding;
@ -435,7 +438,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. // 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); 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. // Add a reference to the member to the interface struct.
auto &membertype = get<SPIRType>(member); auto &membertype = get<SPIRType>(member);
@ -471,7 +475,7 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
else else
{ {
// If needed, add a padding member to the struct to align to the next member's offset. // 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. // Add a reference to the variable type to the interface struct.
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size()); uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
@ -501,12 +505,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 by their offsets
{ MemberSorter memberSorter(ib_type, meta[ib_type.self], MemberSorter::Offset);
// Sort the members of the interface structure, unless this is packed input memberSorter.sort();
MemberSorterByLocation memberSorter(ib_type, meta[ib_type.self]);
memberSorter.sort();
}
return ib_var_id; return ib_var_id;
} }
@ -592,6 +593,12 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
switch (opcode) switch (opcode)
{ {
// ALU
case OpFMod:
BFOP(fmod);
break;
// Comparisons // Comparisons
case OpIEqual: case OpIEqual:
case OpLogicalEqual: case OpLogicalEqual:
@ -1167,9 +1174,8 @@ void CompilerMSL::emit_fixup()
// Returns a declaration for a structure member. // Returns a declaration for a structure member.
string CompilerMSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index) string CompilerMSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index)
{ {
bool should_pack = type.is_packed && is_vector(membertype); return join(type_to_glsl(membertype), " ", to_member_name(type, index), type_to_array_glsl(membertype),
return join((should_pack ? "packed_" : ""), type_to_glsl(membertype), " ", to_member_name(type, index), member_attribute_qualifier(type, index));
type_to_array_glsl(membertype), member_attribute_qualifier(type, index));
} }
// Return a MSL qualifier for the specified function attribute member // Return a MSL qualifier for the specified function attribute member
@ -1271,13 +1277,21 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
return ""; return "";
} }
// Returns the location decoration of the member with the specified index in the specified // Returns the location decoration of the member with the specified index in the specified type.
// type, or the value of the member index if the location has not been specified. // If the location of the member has been explicitly set, that location is used. If not, this
// This function assumes the members are ordered in their location order. // function assumes the members are ordered in their location order, and simply returns the
// This can be ensured using the MemberSorterByLocation class. // index as the location.
uint32_t CompilerMSL::get_ordered_member_location(uint32_t type_id, uint32_t index) 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) string CompilerMSL::constant_expression(const SPIRConstant &c)
@ -1526,13 +1540,14 @@ string CompilerMSL::get_vtx_idx_var_name(bool per_instance)
return "missing_vtx_idx_var"; return "missing_vtx_idx_var";
} }
// If the struct is packed, and the offset is greater than the current size of the struct, // If the struct contains indexed vertex input, and the offset is greater than the current
// appends a padding member to the struct, and returns the offset to use for the next member, // size of the struct, appends a padding member to the struct, and returns the offset to
// which is the offset provided. If the struct is not packed, or the offset is not greater // use for the next member, which is the offset provided. Otherwise, no padding is added,
// than the struct size, no padding is added, and the struct size is returned. // and the struct size is returned.
uint32_t CompilerMSL::pad_to_offset(SPIRType &struct_type, uint32_t offset, uint32_t struct_size) 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; return struct_size;
auto &pad_type = get_pad_type(offset - struct_size); auto &pad_type = get_pad_type(offset - struct_size);
@ -1962,7 +1977,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. // 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 // 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. // how the members should be reordered, based on builtin and location meta info.
@ -1984,12 +1999,20 @@ void MemberSorterByLocation::sort()
} }
// Sort first by builtin status (put builtins at end), then by location. // 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_meta1 = meta.members[mbr_idx1];
auto &mbr_meta2 = meta.members[mbr_idx2]; auto &mbr_meta2 = meta.members[mbr_idx2];
if (mbr_meta1.builtin != mbr_meta2.builtin) if (mbr_meta1.builtin != mbr_meta2.builtin)
return mbr_meta2.builtin; return mbr_meta2.builtin;
else 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); std::string get_vtx_idx_var_name(bool per_instance);
uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype); 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 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); 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) const;
size_t get_declared_type_size(const SPIRType &type, uint64_t dec_mask) 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"; std::string sampler_name_suffix = "Smplr";
}; };
// Sorts the members of a SPIRType and associated Meta info based on the location // Sorts the members of a SPIRType and associated Meta info based on a settable sorting
// and builtin decorations of the members. Members are rearranged by location, // aspect, which defines which aspect of the struct members will be used to sort them.
// with all builtin members appearing a the end. // Regardless of the sorting aspect, built-in members always appear at the end of the struct.
struct MemberSorterByLocation struct MemberSorter
{ {
enum SortAspect
{
Location,
Offset,
};
void sort(); void sort();
bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2); bool operator()(uint32_t mbr_idx1, uint32_t mbr_idx2);
MemberSorterByLocation(SPIRType &t, Meta &m) MemberSorter(SPIRType &t, Meta &m, SortAspect sa)
: type(t) : type(t)
, meta(m) , meta(m)
, sort_aspect(sa)
{ {
} }
SPIRType &type; SPIRType &type;
Meta &meta; Meta &meta;
SortAspect sort_aspect;
}; };
} }