This commit is contained in:
Bill Hollings 2017-01-27 16:12:37 -08:00
commit 804d5313fa
4 changed files with 92 additions and 17 deletions

View File

@ -26,7 +26,6 @@ vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _16 [[buffer(0)]]
main0_out out = {};
out.gl_Position = _16.uMVP * in.aVertex;
out.vNormal = in.aNormal;
out.gl_Position.y = -(out.gl_Position.y); // Invert Y-axis for Metal
return out;
}

View File

@ -2397,8 +2397,10 @@ SPIREntryPoint &Compiler::get_entry_point()
bool Compiler::interface_variable_exists_in_entry_point(uint32_t id) const
{
auto &var = get<SPIRVariable>(id);
if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
SPIRV_CROSS_THROW("Only Input and Output variables are part of a shader linking interface.");
if (var.storage != StorageClassInput && var.storage != StorageClassOutput &&
var.storage != StorageClassUniformConstant)
throw CompilerError(
"Only Input, Output variables and Uniform constants are part of a shader linking interface.");
// This is to avoid potential problems with very old glslang versions which did
// not emit input/output interfaces properly.

View File

@ -29,6 +29,7 @@ CompilerMSL::CompilerMSL(vector<uint32_t> spirv_)
options.vertex.fixup_clipspace = false;
populate_func_name_overrides();
populate_var_name_overrides();
}
// Populate the collection of function names that need to be overridden
@ -38,6 +39,12 @@ void CompilerMSL::populate_func_name_overrides()
func_name_overrides["saturate"] = "saturate0";
}
void CompilerMSL::populate_var_name_overrides()
{
var_name_overrides["kernel"] = "kernel0";
var_name_overrides["bias"] = "bias0";
}
string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_vtx_attrs,
std::vector<MSLResourceBinding> *p_res_bindings)
{
@ -47,6 +54,10 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
// Remember the input parameters
msl_config = msl_cfg;
// Set main function name if it was explicitly set
if (!msl_config.entry_point_name.empty())
set_name(entry_point, msl_config.entry_point_name);
vtx_attrs_by_location.clear();
if (p_vtx_attrs)
for (auto &va : *p_vtx_attrs)
@ -61,10 +72,11 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
set_enabled_interface_variables(get_active_interface_variables());
preprocess_op_codes();
// Create structs to hold input and output variables
// Create structs to hold input, output and uniform variables
qual_pos_var_name = "";
stage_in_var_id = add_interface_block(StorageClassInput);
stage_out_var_id = add_interface_block(StorageClassOutput);
stage_uniforms_var_id = add_interface_block(StorageClassUniformConstant);
// Convert the use of global variables to recursively-passed function parameters
localize_global_variables();
@ -158,10 +170,17 @@ void CompilerMSL::extract_global_variables_from_functions()
auto &var = id.get<SPIRVariable>();
if (var.storage == StorageClassInput || var.storage == StorageClassUniform ||
var.storage == StorageClassUniformConstant || var.storage == StorageClassPushConstant)
{
global_var_ids.insert(var.self);
}
}
}
// Local vars that are declared in the main function and accessed directy by a function
auto &entry_func = get<SPIRFunction>(entry_point);
for (auto &var : entry_func.local_variables)
global_var_ids.insert(var);
std::unordered_set<uint32_t> added_arg_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);
@ -176,7 +195,11 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
{
// Avoid processing a function more than once
if (processed_func_ids.find(func_id) != processed_func_ids.end())
{
// Return function global variables
added_arg_ids = function_global_vars[func_id];
return;
}
processed_func_ids.insert(func_id);
@ -199,6 +222,7 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
uint32_t base_id = ops[2];
if (global_var_ids.find(base_id) != global_var_ids.end())
added_arg_ids.insert(base_id);
break;
}
case OpFunctionCall:
@ -217,6 +241,8 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
}
}
function_global_vars[func_id] = added_arg_ids;
// Add the global variables as arguments to the function
if (func_id != entry_point)
{
@ -312,6 +338,12 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
break;
}
case StorageClassUniformConstant:
{
ib_var_ref = stage_uniform_var_name;
break;
}
default:
break;
}
@ -358,7 +390,11 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
mbr_idx++;
}
}
else
else if (type.basetype == SPIRType::Boolean || type.basetype == SPIRType::Char ||
type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt ||
type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64 ||
type.basetype == SPIRType::Float || type.basetype == SPIRType::Double ||
type.basetype == SPIRType::Boolean)
{
// Add a reference to the variable type to the interface struct.
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
@ -375,7 +411,10 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
// Copy the variable location from the original variable to the member
auto &dec = meta[p_var->self].decoration;
uint32_t locn = dec.location;
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, locn);
if (get_decoration_mask(p_var->self) & (1ull << DecorationLocation))
{
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, locn);
}
mark_location_as_used_by_shader(locn, storage);
// Mark the member as builtin if needed
@ -396,6 +435,15 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
MemberSorter memberSorter(ib_type, meta[ib_type_id], sort_aspect);
memberSorter.sort();
// Sort input or output variables alphabetical
auto &execution = get_entry_point();
if ((execution.model == ExecutionModelFragment && storage == StorageClassInput) ||
(execution.model == ExecutionModelVertex && storage == StorageClassOutput))
{
MemberSorter memberSorter(ib_type, meta[ib_type.self], MemberSorter::Alphabetical);
memberSorter.sort();
}
return ib_var_id;
}
@ -481,6 +529,7 @@ void CompilerMSL::emit_resources()
// Output interface blocks.
emit_interface_block(stage_in_var_id);
emit_interface_block(stage_out_var_id);
emit_interface_block(stage_uniforms_var_id);
}
// Override for MSL-specific syntax instructions
@ -627,7 +676,9 @@ void CompilerMSL::emit_interface_block(uint32_t ib_var_id)
{
auto &ib_var = get<SPIRVariable>(ib_var_id);
auto &ib_type = get<SPIRType>(ib_var.basetype);
emit_struct(ib_type);
auto &m = meta.at(ib_type.self);
if (m.members.size() > 0)
emit_struct(ib_type);
}
}
@ -1069,9 +1120,8 @@ void CompilerMSL::emit_fixup()
{
if (options.vertex.fixup_clipspace)
{
const char *suffix = backend.float_literal_suffix ? "f" : "";
statement(qual_pos_var_name, ".z = 2.0", suffix, " * ", qual_pos_var_name, ".z - ", qual_pos_var_name,
".w;", " // Adjust clip-space for Metal");
statement(qual_pos_var_name, ".z = (", qual_pos_var_name, ".z + ", qual_pos_var_name,
".w) * 0.5; // Adjust clip-space for Metal");
}
if (msl_config.flip_vert_y)
@ -1310,12 +1360,15 @@ string CompilerMSL::entry_point_args(bool append_comma)
auto &type = get<SPIRType>(var.basetype);
if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
var.storage == StorageClassPushConstant) &&
!is_hidden_variable(var))
var.storage == StorageClassPushConstant))
{
switch (type.basetype)
{
case SPIRType::Struct:
{
auto &m = meta.at(type.self);
if (m.members.size() == 0)
break;
if (!ep_args.empty())
ep_args += ", ";
if ((meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock)) != 0 &&
@ -1330,6 +1383,7 @@ string CompilerMSL::entry_point_args(bool append_comma)
ep_args += type_to_glsl(type) + "& " + to_name(var.self);
ep_args += " [[buffer(" + convert_to_string(get_metal_resource_index(var, type.basetype)) + ")]]";
break;
}
case SPIRType::Sampler:
if (!ep_args.empty())
ep_args += ", ";
@ -1431,8 +1485,12 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
auto &type = expression_type(arg.id);
bool constref = !type.pointer || arg.write_count == 0;
// TODO: Check if this arg is an uniform pointer
bool pointer = type.storage == StorageClassUniformConstant;
auto &var = get<SPIRVariable>(arg.id);
return join(constref ? "const " : "", type_to_glsl(type), "& ", to_name(var.self), type_to_array_glsl(type));
return join(constref ? "const " : "", type_to_glsl(type), pointer ? " " : "& ", to_name(var.self),
type_to_array_glsl(type));
}
// If we're currently in the entry point function, and the object
@ -1468,9 +1526,14 @@ string CompilerMSL::to_qualified_member_name(const SPIRType &type, uint32_t inde
string CompilerMSL::ensure_valid_name(string name, string pfx)
{
if (name.size() >= 2 && name[0] == '_' && isdigit(name[1]))
{
return join(pfx, name);
}
else
return name;
{
auto iter = var_name_overrides.find(name);
return (iter != var_name_overrides.end()) ? iter->second : name;
}
}
// Returns an MSL string describing the SPIR-V type
@ -1861,6 +1924,8 @@ bool CompilerMSL::MemberSorter::operator()(uint32_t mbr_idx1, uint32_t mbr_idx2)
case OffsetThenLocationReverse:
return (mbr_meta1.offset < mbr_meta2.offset) ||
((mbr_meta1.offset == mbr_meta2.offset) && (mbr_meta1.location > mbr_meta2.location));
case Alphabetical:
return mbr_meta1.alias > mbr_meta2.alias;
default:
return false;
}

View File

@ -29,9 +29,10 @@ namespace spirv_cross
// Options for compiling to Metal Shading Language
struct MSLConfiguration
{
bool flip_vert_y = true;
bool flip_frag_y = true;
bool flip_vert_y = false;
bool flip_frag_y = false;
bool is_rendering_points = false;
std::string entry_point_name;
};
// Defines MSL characteristics of a vertex attribute at a particular location.
@ -115,22 +116,26 @@ protected:
uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x,
uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias,
uint32_t comp, uint32_t sample, bool *p_forward) override;
std::string clean_func_name(std::string func_name) override;
void preprocess_op_codes();
void emit_custom_functions();
void localize_global_variables();
void extract_global_variables_from_functions();
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> function_global_vars;
void extract_global_variables_from_function(uint32_t func_id, std::unordered_set<uint32_t> &added_arg_ids,
std::unordered_set<uint32_t> &global_var_ids,
std::unordered_set<uint32_t> &processed_func_ids);
uint32_t add_interface_block(spv::StorageClass storage);
void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage);
void emit_resources();
void emit_interface_block(uint32_t ib_var_id);
void populate_func_name_overrides();
void populate_var_name_overrides();
std::string func_type_decl(SPIRType &type);
std::string clean_func_name(std::string func_name) override;
std::string entry_point_args(bool append_comma);
std::string get_entry_point_name();
std::string to_qualified_member_name(const SPIRType &type, uint32_t index);
@ -148,15 +153,18 @@ protected:
MSLConfiguration msl_config;
std::unordered_map<std::string, std::string> func_name_overrides;
std::unordered_map<std::string, std::string> var_name_overrides;
std::set<uint32_t> custom_function_ops;
std::unordered_map<uint32_t, MSLVertexAttr *> vtx_attrs_by_location;
std::vector<MSLResourceBinding *> resource_bindings;
MSLResourceBinding next_metal_resource_index;
uint32_t stage_in_var_id = 0;
uint32_t stage_out_var_id = 0;
uint32_t stage_uniforms_var_id = 0;
std::string qual_pos_var_name;
std::string stage_in_var_name = "in";
std::string stage_out_var_name = "out";
std::string stage_uniform_var_name = "uniforms";
std::string sampler_name_suffix = "Smplr";
// OpcodeHandler that handles several MSL preprocessing operations.
@ -184,6 +192,7 @@ protected:
LocationReverse,
Offset,
OffsetThenLocationReverse,
Alphabetical
};
void sort();