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:
Родитель
09c1e10d43
Коммит
32ae2eceed
|
@ -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();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче