CompilerMSL enhancements to handling of in/out variables.

CompilerMSL sort in/out attributes by attribute number (location). Sort inputs in reverse order.
CompilerMSL propagate incoming vertex attribute offset values.
CompilerMSL elide unused in/out variables.
CompilerMSL replace use of sets with unordered_sets.
This commit is contained in:
Bill Hollings 2016-12-18 18:48:15 -05:00
Родитель 09c1e10d43
Коммит 32ae2eceed
2 изменённых файлов: 51 добавлений и 29 удалений

Просмотреть файл

@ -49,6 +49,8 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
resource_bindings.push_back(&rb); resource_bindings.push_back(&rb);
} }
set_enabled_interface_variables(get_active_interface_variables());
extract_builtins(); extract_builtins();
localize_global_variables(); localize_global_variables();
add_interface_structs(); add_interface_structs();
@ -171,7 +173,7 @@ void CompilerMSL::extract_global_variables_from_functions()
{ {
// Uniforms // Uniforms
std::set<uint32_t> global_var_ids; std::unordered_set<uint32_t> global_var_ids;
for (auto &id : ids) for (auto &id : ids)
{ {
if (id.get_type() == TypeVariable) if (id.get_type() == TypeVariable)
@ -183,17 +185,17 @@ void CompilerMSL::extract_global_variables_from_functions()
} }
} }
std::set<uint32_t> added_arg_ids; std::unordered_set<uint32_t> added_arg_ids;
std::set<uint32_t> processed_func_ids; std::unordered_set<uint32_t> processed_func_ids;
extract_global_variables_from_function(entry_point, added_arg_ids, global_var_ids, processed_func_ids); extract_global_variables_from_function(entry_point, added_arg_ids, global_var_ids, processed_func_ids);
} }
// MSL does not support the use of global variables for shader input content. // MSL does not support the use of global variables for shader input content.
// For any global variable accessed directly by the specified function, extract that variable, // For any global variable accessed directly by the specified function, extract that variable,
// add it as an argument to that function, and the arg to the added_arg_ids collection. // add it as an argument to that function, and the arg to the added_arg_ids collection.
void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids, void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::unordered_set<uint32_t> &added_arg_ids,
std::set<uint32_t> &global_var_ids, std::unordered_set<uint32_t> &global_var_ids,
std::set<uint32_t> &processed_func_ids) std::unordered_set<uint32_t> &processed_func_ids)
{ {
// Avoid processing a function more than once // Avoid processing a function more than once
if (processed_func_ids.find(func_id) != processed_func_ids.end()) if (processed_func_ids.find(func_id) != processed_func_ids.end())
@ -225,7 +227,7 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
case OpFunctionCall: case OpFunctionCall:
{ {
uint32_t inner_func_id = ops[2]; uint32_t inner_func_id = ops[2];
std::set<uint32_t> inner_func_args; std::unordered_set<uint32_t> inner_func_args;
extract_global_variables_from_function(inner_func_id, inner_func_args, global_var_ids, extract_global_variables_from_function(inner_func_id, inner_func_args, global_var_ids,
processed_func_ids); processed_func_ids);
added_arg_ids.insert(inner_func_args.begin(), inner_func_args.end()); added_arg_ids.insert(inner_func_args.begin(), inner_func_args.end());
@ -270,7 +272,7 @@ void CompilerMSL::add_interface_structs()
uint32_t var_id; uint32_t var_id;
if (execution.model == ExecutionModelVertex && !vtx_attrs_by_location.empty()) if (execution.model == ExecutionModelVertex && !vtx_attrs_by_location.empty())
{ {
std::set<uint32_t> vtx_bindings; std::unordered_set<uint32_t> vtx_bindings;
bind_vertex_attributes(vtx_bindings); bind_vertex_attributes(vtx_bindings);
for (uint32_t vb : vtx_bindings) for (uint32_t vb : vtx_bindings)
{ {
@ -291,7 +293,7 @@ void CompilerMSL::add_interface_structs()
// Iterate through the variables and populates each input vertex attribute variable // Iterate through the variables and populates each input vertex attribute variable
// from the binding info provided during compiler construction, matching by location. // from the binding info provided during compiler construction, matching by location.
void CompilerMSL::bind_vertex_attributes(std::set<uint32_t> &bindings) void CompilerMSL::bind_vertex_attributes(std::unordered_set<uint32_t> &bindings)
{ {
auto &execution = get_entry_point(); auto &execution = get_entry_point();
@ -326,7 +328,7 @@ void CompilerMSL::bind_vertex_attributes(std::set<uint32_t> &bindings)
} }
} }
// Add an the interface structure for the type of storage. For vertex inputs, each // Add an interface structure for the type of storage. For vertex inputs, each
// binding must have its own structure, and a structure is created for vtx_binding. // binding must have its own structure, and a structure is created for vtx_binding.
// For non-vertex input, and all outputs, the vtx_binding argument is ignored. // For non-vertex input, and all outputs, the vtx_binding argument is ignored.
// Returns the ID of the newly added variable, or zero if no variable was added. // Returns the ID of the newly added variable, or zero if no variable was added.
@ -367,7 +369,7 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
auto &ib_type = set<SPIRType>(ib_type_id); auto &ib_type = set<SPIRType>(ib_type_id);
ib_type.basetype = SPIRType::Struct; ib_type.basetype = SPIRType::Struct;
ib_type.storage = storage; ib_type.storage = storage;
set_decoration(ib_type.self, DecorationBlock); set_decoration(ib_type_id, DecorationBlock);
uint32_t ib_var_id = next_id++; uint32_t ib_var_id = next_id++;
auto &var = set<SPIRVariable>(ib_var_id, ib_type_id, storage, 0); auto &var = set<SPIRVariable>(ib_var_id, ib_type_id, storage, 0);
@ -443,7 +445,6 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
pad_to_offset(ib_type, is_indxd_vtx_input, (var_dec.offset + mbr_offset), uint32_t(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);
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size()); uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
ib_type.member_types.push_back(member); // membertype.self is different for array types ib_type.member_types.push_back(member); // membertype.self is different for array types
@ -461,6 +462,13 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
uint32_t locn = get_member_decoration(type_id, i, DecorationLocation); uint32_t locn = get_member_decoration(type_id, i, DecorationLocation);
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, locn); set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, locn);
// Set vertex binding offsets
if (execution.model == ExecutionModelVertex && storage == StorageClassInput)
{
uint32_t offset = get_member_decoration(type_id, i, DecorationOffset);
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationOffset, offset);
}
// Mark the member as builtin if needed // Mark the member as builtin if needed
BuiltIn builtin; BuiltIn builtin;
if (is_member_builtin(type, i, &builtin)) if (is_member_builtin(type, i, &builtin))
@ -496,6 +504,10 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
auto &dec = meta[p_var->self].decoration; auto &dec = meta[p_var->self].decoration;
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, dec.location); set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, dec.location);
// Set vertex binding offsets
if (execution.model == ExecutionModelVertex && storage == StorageClassInput)
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationOffset, dec.offset);
// Mark the member as builtin if needed // Mark the member as builtin if needed
if (is_builtin_variable(*p_var)) if (is_builtin_variable(*p_var))
{ {
@ -506,8 +518,12 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
} }
} }
// Sort the members of the interface structure by their offsets // Sort the members of the interface structure by their attribute numbers.
MemberSorter memberSorter(ib_type, meta[ib_type_id], MemberSorter::Offset); // Oddly, Metal handles inputs better if they are sorted in reverse order,
// particularly if the offsets are all equal.
MemberSorter::SortAspect sort_aspect =
(storage == StorageClassInput) ? MemberSorter::LocationReverse : MemberSorter::Location;
MemberSorter memberSorter(ib_type, meta[ib_type_id], sort_aspect);
memberSorter.sort(); memberSorter.sort();
return ib_var_id; return ib_var_id;
@ -1410,11 +1426,9 @@ string CompilerMSL::entry_point_args(bool append_comma)
auto &var = id.get<SPIRVariable>(); auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype); auto &type = get<SPIRType>(var.basetype);
if (is_hidden_variable(var, true)) if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
continue; var.storage == StorageClassPushConstant) &&
!is_hidden_variable(var))
if (var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
var.storage == StorageClassPushConstant)
{ {
switch (type.basetype) switch (type.basetype)
{ {
@ -1950,15 +1964,16 @@ size_t CompilerMSL::get_declared_type_size(uint32_t type_id, uint64_t dec_mask)
} }
} }
// 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 the required sorting aspect.
void MemberSorter::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
// how the members should be reordered, based on builtin and location meta info. // the members should be reordered, based on builtin and sorting aspect meta info.
size_t mbr_cnt = type.member_types.size(); size_t mbr_cnt = type.member_types.size();
vector<uint32_t> mbr_idxs(mbr_cnt); vector<uint32_t> mbr_idxs(mbr_cnt);
iota(mbr_idxs.begin(), mbr_idxs.end(), 0); // Fill with consecutive indices iota(mbr_idxs.begin(), mbr_idxs.end(), 0); // Fill with consecutive indices
std::sort(mbr_idxs.begin(), mbr_idxs.end(), *this); // Sort member indices based on member locations std::sort(mbr_idxs.begin(), mbr_idxs.end(), *this); // Sort member indices based on sorting aspect
// Move type and meta member info to the order defined by the sorted member indices. // Move type and meta member info to the order defined by the sorted member indices.
// This is done by creating temporary copies of both member types and meta, and then // This is done by creating temporary copies of both member types and meta, and then
@ -1972,7 +1987,7 @@ void MemberSorter::sort()
} }
} }
// Sort first by builtin status (put builtins at end), then by location. // Sort first by builtin status (put builtins at end), then by the sorting aspect.
bool MemberSorter::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];
@ -1984,8 +1999,13 @@ bool MemberSorter::operator()(uint32_t mbr_idx1, uint32_t mbr_idx2)
{ {
case Location: case Location:
return mbr_meta1.location < mbr_meta2.location; return mbr_meta1.location < mbr_meta2.location;
case LocationReverse:
return mbr_meta1.location > mbr_meta2.location;
case Offset: case Offset:
return mbr_meta1.offset < mbr_meta2.offset; return mbr_meta1.offset < mbr_meta2.offset;
case OffsetThenLocationReverse:
return (mbr_meta1.offset < mbr_meta2.offset) ||
((mbr_meta1.offset == mbr_meta2.offset) && (mbr_meta1.location > mbr_meta2.location));
default: default:
return false; return false;
} }

Просмотреть файл

@ -18,7 +18,7 @@
#define SPIRV_CROSS_MSL_HPP #define SPIRV_CROSS_MSL_HPP
#include "spirv_glsl.hpp" #include "spirv_glsl.hpp"
#include <set> #include <unordered_set>
#include <vector> #include <vector>
namespace spirv_cross namespace spirv_cross
@ -117,11 +117,11 @@ protected:
void add_builtin(spv::BuiltIn builtin_type); void add_builtin(spv::BuiltIn builtin_type);
void localize_global_variables(); void localize_global_variables();
void extract_global_variables_from_functions(); void extract_global_variables_from_functions();
void extract_global_variables_from_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids, void extract_global_variables_from_function(uint32_t func_id, std::unordered_set<uint32_t> &added_arg_ids,
std::set<uint32_t> &global_var_ids, std::unordered_set<uint32_t> &global_var_ids,
std::set<uint32_t> &processed_func_ids); std::unordered_set<uint32_t> &processed_func_ids);
void add_interface_structs(); void add_interface_structs();
void bind_vertex_attributes(std::set<uint32_t> &bindings); void bind_vertex_attributes(std::unordered_set<uint32_t> &bindings);
uint32_t add_interface_struct(spv::StorageClass storage, uint32_t vtx_binding = 0); uint32_t add_interface_struct(spv::StorageClass storage, uint32_t vtx_binding = 0);
void emit_resources(); void emit_resources();
void emit_interface_block(uint32_t ib_var_id); void emit_interface_block(uint32_t ib_var_id);
@ -169,7 +169,9 @@ struct MemberSorter
enum SortAspect enum SortAspect
{ {
Location, Location,
LocationReverse,
Offset, Offset,
OffsetThenLocationReverse,
}; };
void sort(); void sort();