Merge branch 'master' of git://github.com/brenwill/SPIRV-Cross
This commit is contained in:
Коммит
75c2285f6e
12
README.md
12
README.md
|
@ -21,7 +21,7 @@ However, most missing features are expected to be "trivial" improvements at this
|
||||||
|
|
||||||
SPIRV-Cross has been tested on Linux, OSX and Windows.
|
SPIRV-Cross has been tested on Linux, OSX and Windows.
|
||||||
|
|
||||||
### Linux and OSX
|
### Linux and macOS
|
||||||
|
|
||||||
Just run `make` on the command line. A recent GCC (4.8+) or Clang (3.x+) compiler is required as SPIRV-Cross uses C++11 extensively.
|
Just run `make` on the command line. A recent GCC (4.8+) or Clang (3.x+) compiler is required as SPIRV-Cross uses C++11 extensively.
|
||||||
|
|
||||||
|
@ -142,8 +142,14 @@ along with the Apache 2.0 licensing stub.
|
||||||
|
|
||||||
### Formatting
|
### Formatting
|
||||||
|
|
||||||
SPIRV-Cross uses clang-format to automatically format code.
|
SPIRV-Cross uses `clang-format` to automatically format code.
|
||||||
Please use clang-format with the style sheet found in `.clang-format` to automatically format code before submitting a pull request.
|
Please use `clang-format` with the style sheet found in `.clang-format` to automatically format code before submitting a pull request.
|
||||||
|
|
||||||
|
To make things easy, the `format_all.sh` script can be used to format all
|
||||||
|
source files in the library. In this directory, run the following from the
|
||||||
|
command line:
|
||||||
|
|
||||||
|
./format_all.sh
|
||||||
|
|
||||||
## ABI concerns
|
## ABI concerns
|
||||||
|
|
||||||
|
|
|
@ -845,6 +845,7 @@ struct Meta
|
||||||
struct Decoration
|
struct Decoration
|
||||||
{
|
{
|
||||||
std::string alias;
|
std::string alias;
|
||||||
|
std::string qualified_alias;
|
||||||
uint64_t decoration_flags = 0;
|
uint64_t decoration_flags = 0;
|
||||||
spv::BuiltIn builtin_type;
|
spv::BuiltIn builtin_type;
|
||||||
uint32_t location = 0;
|
uint32_t location = 0;
|
||||||
|
|
|
@ -845,6 +845,12 @@ const std::string &Compiler::get_member_name(uint32_t id, uint32_t index) const
|
||||||
return m.members[index].alias;
|
return m.members[index].alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Compiler::set_member_qualified_name(uint32_t id, uint32_t index, const std::string &name)
|
||||||
|
{
|
||||||
|
meta.at(id).members.resize(max(meta[id].members.size(), size_t(index) + 1));
|
||||||
|
meta.at(id).members[index].qualified_alias = name;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t Compiler::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
|
uint32_t Compiler::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
|
||||||
{
|
{
|
||||||
auto &m = meta.at(id);
|
auto &m = meta.at(id);
|
||||||
|
@ -1115,6 +1121,9 @@ void Compiler::parse(const Instruction &instruction)
|
||||||
uint32_t strlen_words = (e.name.size() + 1 + 3) >> 2;
|
uint32_t strlen_words = (e.name.size() + 1 + 3) >> 2;
|
||||||
e.interface_variables.insert(end(e.interface_variables), ops + strlen_words + 2, ops + instruction.length);
|
e.interface_variables.insert(end(e.interface_variables), ops + strlen_words + 2, ops + instruction.length);
|
||||||
|
|
||||||
|
// Set the name of the entry point in case OpName is not provided later
|
||||||
|
set_name(ops[1], e.name);
|
||||||
|
|
||||||
// If we don't have an entry, make the first one our "default".
|
// If we don't have an entry, make the first one our "default".
|
||||||
if (!entry_point)
|
if (!entry_point)
|
||||||
entry_point = ops[1];
|
entry_point = ops[1];
|
||||||
|
@ -1173,6 +1182,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||||
set_decoration(id, decoration, ops[2]);
|
set_decoration(id, decoration, ops[2]);
|
||||||
else
|
else
|
||||||
set_decoration(id, decoration);
|
set_decoration(id, decoration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,6 +166,9 @@ public:
|
||||||
// Sets the member identifier for OpTypeStruct ID, member number "index".
|
// Sets the member identifier for OpTypeStruct ID, member number "index".
|
||||||
void set_member_name(uint32_t id, uint32_t index, const std::string &name);
|
void set_member_name(uint32_t id, uint32_t index, const std::string &name);
|
||||||
|
|
||||||
|
// Sets the qualified member identifier for OpTypeStruct ID, member number "index".
|
||||||
|
void set_member_qualified_name(uint32_t id, uint32_t index, const std::string &name);
|
||||||
|
|
||||||
// Gets the decoration mask for a member of a struct, similar to get_decoration_mask.
|
// Gets the decoration mask for a member of a struct, similar to get_decoration_mask.
|
||||||
uint64_t get_member_decoration_mask(uint32_t id, uint32_t index) const;
|
uint64_t get_member_decoration_mask(uint32_t id, uint32_t index) const;
|
||||||
|
|
||||||
|
@ -394,7 +397,7 @@ protected:
|
||||||
std::unordered_set<uint32_t> selection_merge_targets;
|
std::unordered_set<uint32_t> selection_merge_targets;
|
||||||
std::unordered_set<uint32_t> multiselect_merge_targets;
|
std::unordered_set<uint32_t> multiselect_merge_targets;
|
||||||
|
|
||||||
std::string to_name(uint32_t id, bool allow_alias = true);
|
virtual std::string to_name(uint32_t id, bool allow_alias = true);
|
||||||
bool is_builtin_variable(const SPIRVariable &var) const;
|
bool is_builtin_variable(const SPIRVariable &var) const;
|
||||||
bool is_hidden_variable(const SPIRVariable &var, bool include_builtins = false) const;
|
bool is_hidden_variable(const SPIRVariable &var, bool include_builtins = false) const;
|
||||||
bool is_immutable(uint32_t id) const;
|
bool is_immutable(uint32_t id) const;
|
||||||
|
|
|
@ -1426,6 +1426,14 @@ void CompilerGLSL::emit_resources()
|
||||||
statement("");
|
statement("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a string representation of the ID, usable as a function arg.
|
||||||
|
// Default is to simply return the expression representation fo the arg ID.
|
||||||
|
// Subclasses may override to modify the return value.
|
||||||
|
string CompilerGLSL::to_func_call_arg(uint32_t id)
|
||||||
|
{
|
||||||
|
return to_expression(id);
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerGLSL::handle_invalid_expression(uint32_t id)
|
void CompilerGLSL::handle_invalid_expression(uint32_t id)
|
||||||
{
|
{
|
||||||
auto &expr = get<SPIRExpression>(id);
|
auto &expr = get<SPIRExpression>(id);
|
||||||
|
@ -3456,7 +3464,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||||
if (skip_argument(arg[i]))
|
if (skip_argument(arg[i]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
arglist.push_back(to_expression(arg[i]));
|
arglist.push_back(to_func_call_arg(arg[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &combined : callee.combined_parameters)
|
for (auto &combined : callee.combined_parameters)
|
||||||
|
@ -3474,6 +3482,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||||
|
|
||||||
arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
|
arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
append_global_func_args(callee, length, arglist);
|
||||||
|
|
||||||
funexpr += merge(arglist);
|
funexpr += merge(arglist);
|
||||||
funexpr += ")";
|
funexpr += ")";
|
||||||
|
|
||||||
|
@ -4581,6 +4592,22 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Appends function arguments, mapped from global variables, beyond the specified arg index.
|
||||||
|
// This is used when a function call uses fewer arguments than the function defines.
|
||||||
|
// This situation may occur if the function signature has been dynamically modified to
|
||||||
|
// extract global variables referenced from within the function, and convert them to
|
||||||
|
// function arguments. This is necessary for shader languages that do not support global
|
||||||
|
// access to shader input content from within a function (eg. Metal). Each additional
|
||||||
|
// function args uses the name of the global variable. Function nesting will modify the
|
||||||
|
// functions and calls all the way up the nesting chain.
|
||||||
|
void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, vector<string> &arglist)
|
||||||
|
{
|
||||||
|
auto &args = func.arguments;
|
||||||
|
uint32_t arg_cnt = uint32_t(args.size());
|
||||||
|
for (uint32_t arg_idx = index; arg_idx < arg_cnt; arg_idx++)
|
||||||
|
arglist.push_back(to_func_call_arg(args[arg_idx].id));
|
||||||
|
}
|
||||||
|
|
||||||
string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
|
string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index)
|
||||||
{
|
{
|
||||||
auto &memb = meta[type.self].members;
|
auto &memb = meta[type.self].members;
|
||||||
|
@ -5677,7 +5704,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPIRBlock::Kill:
|
case SPIRBlock::Kill:
|
||||||
statement("discard;");
|
statement(backend.discard_literal, ";");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -148,6 +148,7 @@ protected:
|
||||||
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
|
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
|
||||||
virtual void emit_fixup();
|
virtual void emit_fixup();
|
||||||
virtual std::string variable_decl(const SPIRType &type, const std::string &name);
|
virtual std::string variable_decl(const SPIRType &type, const std::string &name);
|
||||||
|
virtual std::string to_func_call_arg(uint32_t id);
|
||||||
|
|
||||||
std::unique_ptr<std::ostringstream> buffer;
|
std::unique_ptr<std::ostringstream> buffer;
|
||||||
|
|
||||||
|
@ -220,6 +221,7 @@ protected:
|
||||||
// shouldn't need polymorphism.
|
// shouldn't need polymorphism.
|
||||||
struct BackendVariations
|
struct BackendVariations
|
||||||
{
|
{
|
||||||
|
std::string discard_literal = "discard";
|
||||||
bool float_literal_suffix = false;
|
bool float_literal_suffix = false;
|
||||||
bool double_literal_suffix = true;
|
bool double_literal_suffix = true;
|
||||||
bool uint32_t_literal_suffix = true;
|
bool uint32_t_literal_suffix = true;
|
||||||
|
@ -285,6 +287,7 @@ protected:
|
||||||
const char *index_to_swizzle(uint32_t index);
|
const char *index_to_swizzle(uint32_t index);
|
||||||
std::string remap_swizzle(uint32_t result_type, uint32_t input_components, uint32_t expr);
|
std::string remap_swizzle(uint32_t result_type, uint32_t input_components, uint32_t expr);
|
||||||
std::string declare_temporary(uint32_t type, uint32_t id);
|
std::string declare_temporary(uint32_t type, uint32_t id);
|
||||||
|
void append_global_func_args(const SPIRFunction &func, uint32_t index, std::vector<std::string> &arglist);
|
||||||
std::string to_expression(uint32_t id);
|
std::string to_expression(uint32_t id);
|
||||||
std::string to_member_name(const SPIRType &type, uint32_t index);
|
std::string to_member_name(const SPIRType &type, uint32_t index);
|
||||||
std::string type_to_glsl_constructor(const SPIRType &type);
|
std::string type_to_glsl_constructor(const SPIRType &type);
|
||||||
|
|
263
spirv_msl.cpp
263
spirv_msl.cpp
|
@ -57,6 +57,7 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
|
||||||
extract_builtins();
|
extract_builtins();
|
||||||
localize_global_variables();
|
localize_global_variables();
|
||||||
add_interface_structs();
|
add_interface_structs();
|
||||||
|
extract_global_variables_from_functions();
|
||||||
|
|
||||||
// Do not deal with ES-isms like precision, older extensions and such.
|
// Do not deal with ES-isms like precision, older extensions and such.
|
||||||
options.es = false;
|
options.es = false;
|
||||||
|
@ -65,6 +66,7 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
|
||||||
backend.uint32_t_literal_suffix = true;
|
backend.uint32_t_literal_suffix = true;
|
||||||
backend.basic_int_type = "int";
|
backend.basic_int_type = "int";
|
||||||
backend.basic_uint_type = "uint";
|
backend.basic_uint_type = "uint";
|
||||||
|
backend.discard_literal = "discard_fragment()";
|
||||||
backend.swizzle_is_function = false;
|
backend.swizzle_is_function = false;
|
||||||
backend.shared_is_implied = false;
|
backend.shared_is_implied = false;
|
||||||
|
|
||||||
|
@ -114,6 +116,35 @@ void CompilerMSL::extract_builtins()
|
||||||
builtin_vars[dec.builtin_type] = var.self;
|
builtin_vars[dec.builtin_type] = var.self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &execution = get_entry_point();
|
||||||
|
if (execution.model == ExecutionModelVertex)
|
||||||
|
{
|
||||||
|
if (!(builtin_vars[BuiltInVertexIndex] || builtin_vars[BuiltInVertexId]))
|
||||||
|
add_builtin(BuiltInVertexIndex);
|
||||||
|
|
||||||
|
if (!(builtin_vars[BuiltInInstanceIndex] || builtin_vars[BuiltInInstanceId]))
|
||||||
|
add_builtin(BuiltInInstanceIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an appropriate built-in variable for the specified builtin type.
|
||||||
|
void CompilerMSL::add_builtin(BuiltIn builtin_type)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Add a new typed variable for this interface structure.
|
||||||
|
uint32_t next_id = increase_bound_by(2);
|
||||||
|
uint32_t ib_type_id = next_id++;
|
||||||
|
auto &ib_type = set<SPIRType>(ib_type_id);
|
||||||
|
ib_type.basetype = SPIRType::UInt;
|
||||||
|
ib_type.storage = StorageClassInput;
|
||||||
|
|
||||||
|
uint32_t ib_var_id = next_id++;
|
||||||
|
set<SPIRVariable>(ib_var_id, ib_type_id, StorageClassInput, 0);
|
||||||
|
set_decoration(ib_var_id, DecorationBuiltIn, builtin_type);
|
||||||
|
set_name(ib_var_id, builtin_to_glsl(builtin_type));
|
||||||
|
|
||||||
|
builtin_vars[builtin_type] = ib_var_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the Private global variables to the entry function.
|
// Move the Private global variables to the entry function.
|
||||||
|
@ -138,6 +169,95 @@ void CompilerMSL::localize_global_variables()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For any global variable accessed directly by a function,
|
||||||
|
// extract that variable and add it as an argument to that function.
|
||||||
|
void CompilerMSL::extract_global_variables_from_functions()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Uniforms
|
||||||
|
std::set<uint32_t> global_var_ids;
|
||||||
|
for (auto &id : ids)
|
||||||
|
{
|
||||||
|
if (id.get_type() == TypeVariable)
|
||||||
|
{
|
||||||
|
auto &var = id.get<SPIRVariable>();
|
||||||
|
if (var.storage == StorageClassInput || var.storage == StorageClassUniform ||
|
||||||
|
var.storage == StorageClassUniformConstant || var.storage == StorageClassPushConstant)
|
||||||
|
global_var_ids.insert(var.self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<uint32_t> added_arg_ids;
|
||||||
|
std::set<uint32_t> 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.
|
||||||
|
// 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.
|
||||||
|
void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids,
|
||||||
|
std::set<uint32_t> &global_var_ids,
|
||||||
|
std::set<uint32_t> &processed_func_ids)
|
||||||
|
{
|
||||||
|
// Avoid processing a function more than once
|
||||||
|
if (processed_func_ids.find(func_id) != processed_func_ids.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
processed_func_ids.insert(func_id);
|
||||||
|
|
||||||
|
auto &func = get<SPIRFunction>(func_id);
|
||||||
|
|
||||||
|
// Recursively establish global args added to functions on which we depend.
|
||||||
|
for (auto block : func.blocks)
|
||||||
|
{
|
||||||
|
auto &b = get<SPIRBlock>(block);
|
||||||
|
for (auto &i : b.ops)
|
||||||
|
{
|
||||||
|
auto ops = stream(i);
|
||||||
|
auto op = static_cast<Op>(i.op);
|
||||||
|
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case OpLoad:
|
||||||
|
case OpAccessChain:
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
uint32_t inner_func_id = ops[2];
|
||||||
|
std::set<uint32_t> inner_func_args;
|
||||||
|
extract_global_variables_from_function(inner_func_id, inner_func_args, global_var_ids,
|
||||||
|
processed_func_ids);
|
||||||
|
added_arg_ids.insert(inner_func_args.begin(), inner_func_args.end());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the global variables as arguments to the function
|
||||||
|
if (func_id != entry_point)
|
||||||
|
{
|
||||||
|
uint32_t next_id = increase_bound_by(uint32_t(added_arg_ids.size()));
|
||||||
|
for (uint32_t arg_id : added_arg_ids)
|
||||||
|
{
|
||||||
|
uint32_t type_id = get<SPIRVariable>(arg_id).basetype;
|
||||||
|
func.add_parameter(type_id, next_id);
|
||||||
|
set<SPIRVariable>(next_id, type_id, StorageClassFunction);
|
||||||
|
set_name(next_id, get_name(arg_id));
|
||||||
|
meta[next_id].decoration.qualified_alias = meta[arg_id].decoration.qualified_alias;
|
||||||
|
next_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Adds any interface structure variables needed by this shader
|
// Adds any interface structure variables needed by this shader
|
||||||
void CompilerMSL::add_interface_structs()
|
void CompilerMSL::add_interface_structs()
|
||||||
{
|
{
|
||||||
|
@ -301,9 +421,7 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &type = get<SPIRType>(p_var->basetype);
|
auto &type = get<SPIRType>(p_var->basetype);
|
||||||
auto &type_dec = meta[type.self].decoration;
|
if (type.basetype == SPIRType::Struct)
|
||||||
|
|
||||||
if (type_dec.decoration_flags & (1ull << DecorationBlock))
|
|
||||||
{
|
{
|
||||||
// Flatten the struct members into the interface struct
|
// Flatten the struct members into the interface struct
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
@ -311,22 +429,22 @@ 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, (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);
|
||||||
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(membertype.self);
|
ib_type.member_types.push_back(membertype.self);
|
||||||
|
|
||||||
// Give the member a name, and assign it an offset within the struct.
|
// Give the member a name, and assign it an offset within the struct.
|
||||||
string mbr_name = to_member_name(type, i);
|
string mbr_name = ensure_member_name(to_qualified_member_name(type, i));
|
||||||
set_member_name(ib_type.self, ib_mbr_idx, mbr_name);
|
set_member_name(ib_type.self, ib_mbr_idx, mbr_name);
|
||||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationOffset, (uint32_t)struct_size);
|
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationOffset, uint32_t(struct_size));
|
||||||
struct_size = get_declared_struct_size(ib_type);
|
struct_size = get_declared_struct_size(ib_type);
|
||||||
|
|
||||||
// Update the original variable reference to include the structure reference
|
// Update the original variable reference to include the structure reference
|
||||||
string qual_var_name = ib_var_ref + "." + mbr_name;
|
string qual_var_name = ib_var_ref + "." + mbr_name;
|
||||||
set_member_name(type.self, i, qual_var_name);
|
set_member_qualified_name(type.self, i, qual_var_name);
|
||||||
|
|
||||||
// Copy the variable location from the original variable to the member
|
// Copy the variable location from the original variable to the member
|
||||||
uint32_t locn = get_member_decoration(type.self, i, DecorationLocation);
|
uint32_t locn = get_member_decoration(type.self, i, DecorationLocation);
|
||||||
|
@ -347,21 +465,21 @@ 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, 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());
|
||||||
ib_type.member_types.push_back(type.self);
|
ib_type.member_types.push_back(type.self);
|
||||||
|
|
||||||
// Give the member a name, and assign it an offset within the struct.
|
// Give the member a name, and assign it an offset within the struct.
|
||||||
string mbr_name = to_name(p_var->self);
|
string mbr_name = ensure_member_name(to_name(p_var->self));
|
||||||
set_member_name(ib_type.self, ib_mbr_idx, mbr_name);
|
set_member_name(ib_type.self, ib_mbr_idx, mbr_name);
|
||||||
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationOffset, (uint32_t)struct_size);
|
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationOffset, uint32_t(struct_size));
|
||||||
struct_size = get_declared_struct_size(ib_type);
|
struct_size = get_declared_struct_size(ib_type);
|
||||||
|
|
||||||
// Update the original variable reference to include the structure reference
|
// Update the original variable reference to include the structure reference
|
||||||
string qual_var_name = ib_var_ref + "." + mbr_name;
|
string qual_var_name = ib_var_ref + "." + mbr_name;
|
||||||
meta[p_var->self].decoration.alias = qual_var_name;
|
meta[p_var->self].decoration.qualified_alias = qual_var_name;
|
||||||
|
|
||||||
// Copy the variable location from the original variable to the member
|
// Copy the variable location from the original variable to the member
|
||||||
auto &dec = meta[p_var->self].decoration;
|
auto &dec = meta[p_var->self].decoration;
|
||||||
|
@ -398,6 +516,18 @@ void CompilerMSL::emit_header()
|
||||||
statement("");
|
statement("");
|
||||||
statement("using namespace metal;");
|
statement("using namespace metal;");
|
||||||
statement("");
|
statement("");
|
||||||
|
emit_msl_defines();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerMSL::emit_msl_defines()
|
||||||
|
{
|
||||||
|
statement("// Standard GLSL->MSL redefinitions");
|
||||||
|
statement("#define dFdy dfdy");
|
||||||
|
statement("#define dFdx dfdy");
|
||||||
|
statement("#define atan(y,x) atan2((y),(x))");
|
||||||
|
statement("#define greaterThan(a,b) ((a)>(b))");
|
||||||
|
statement("inline uint2 imageSize(thread const texture2d<float>& tex) { return uint2(tex.get_width(), tex.get_height()); }");
|
||||||
|
statement("");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerMSL::emit_resources()
|
void CompilerMSL::emit_resources()
|
||||||
|
@ -512,14 +642,31 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, bool is_decl)
|
||||||
{
|
{
|
||||||
add_local_variable_name(arg.id);
|
add_local_variable_name(arg.id);
|
||||||
|
|
||||||
decl += "thread " + argument_decl(arg);
|
bool is_uniform_struct = false;
|
||||||
if (&arg != &func.arguments.back())
|
|
||||||
decl += ", ";
|
|
||||||
|
|
||||||
// Hold a pointer to the parameter so we can invalidate the readonly field if needed.
|
|
||||||
auto *var = maybe_get<SPIRVariable>(arg.id);
|
auto *var = maybe_get<SPIRVariable>(arg.id);
|
||||||
if (var)
|
if (var)
|
||||||
var->parameter = &arg;
|
{
|
||||||
|
var->parameter = &arg; // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
|
||||||
|
|
||||||
|
// Check if this arg is one of the synthetic uniform args
|
||||||
|
// created to handle uniform access inside the function
|
||||||
|
auto &var_type = get<SPIRType>(var->basetype);
|
||||||
|
is_uniform_struct =
|
||||||
|
((var_type.basetype == SPIRType::Struct) &&
|
||||||
|
(var_type.storage == StorageClassUniform || var_type.storage == StorageClassUniformConstant ||
|
||||||
|
var_type.storage == StorageClassPushConstant));
|
||||||
|
}
|
||||||
|
|
||||||
|
decl += (is_uniform_struct ? "constant " : "thread ");
|
||||||
|
decl += argument_decl(arg);
|
||||||
|
|
||||||
|
// Manufacture automatic sampler arg for SampledImage texture
|
||||||
|
auto &arg_type = get<SPIRType>(arg.type);
|
||||||
|
if (arg_type.basetype == SPIRType::SampledImage)
|
||||||
|
decl += ", thread const sampler& " + to_sampler_expression(arg.id);
|
||||||
|
|
||||||
|
if (&arg != &func.arguments.back())
|
||||||
|
decl += ", ";
|
||||||
}
|
}
|
||||||
|
|
||||||
decl += ")";
|
decl += ")";
|
||||||
|
@ -840,6 +987,21 @@ void CompilerMSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id
|
||||||
meta[result_id].sampler = samp_id;
|
meta[result_id].sampler = samp_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a string representation of the ID, usable as a function arg.
|
||||||
|
// Manufacture automatic sampler arg for SampledImage texture.
|
||||||
|
string CompilerMSL::to_func_call_arg(uint32_t id)
|
||||||
|
{
|
||||||
|
string arg_str = CompilerGLSL::to_func_call_arg(id);
|
||||||
|
|
||||||
|
// Manufacture automatic sampler arg for SampledImage texture.
|
||||||
|
auto &var = get<SPIRVariable>(id);
|
||||||
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
if (type.basetype == SPIRType::SampledImage)
|
||||||
|
arg_str += ", " + to_sampler_expression(id);
|
||||||
|
|
||||||
|
return arg_str;
|
||||||
|
}
|
||||||
|
|
||||||
// If the ID represents a sampled image that has been assigned a sampler already,
|
// If the ID represents a sampled image that has been assigned a sampler already,
|
||||||
// generate an expression for the sampler, otherwise generate a fake sampler name
|
// generate an expression for the sampler, otherwise generate a fake sampler name
|
||||||
// by appending a suffix to the expression constructed from the ID.
|
// by appending a suffix to the expression constructed from the ID.
|
||||||
|
@ -860,7 +1022,7 @@ void CompilerMSL::emit_fixup()
|
||||||
{
|
{
|
||||||
const char *suffix = backend.float_literal_suffix ? "f" : "";
|
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,
|
statement(qual_pos_var_name, ".z = 2.0", suffix, " * ", qual_pos_var_name, ".z - ", qual_pos_var_name,
|
||||||
".w;");
|
".w;", " // Adjust clip-space for Metal");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msl_config.flip_vert_y)
|
if (msl_config.flip_vert_y)
|
||||||
|
@ -939,7 +1101,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
|
||||||
{
|
{
|
||||||
case BuiltInFrontFacing:
|
case BuiltInFrontFacing:
|
||||||
case BuiltInPointCoord:
|
case BuiltInPointCoord:
|
||||||
case BuiltInSamplePosition:
|
case BuiltInFragCoord:
|
||||||
case BuiltInSampleId:
|
case BuiltInSampleId:
|
||||||
case BuiltInSampleMask:
|
case BuiltInSampleMask:
|
||||||
case BuiltInLayer:
|
case BuiltInLayer:
|
||||||
|
@ -1240,7 +1402,7 @@ uint32_t CompilerMSL::pad_to_offset(SPIRType &struct_type, uint32_t offset, uint
|
||||||
return struct_size;
|
return struct_size;
|
||||||
|
|
||||||
auto &pad_type = get_pad_type(offset - struct_size);
|
auto &pad_type = get_pad_type(offset - struct_size);
|
||||||
uint32_t mbr_idx = (uint32_t)struct_type.member_types.size();
|
uint32_t mbr_idx = uint32_t(struct_type.member_types.size());
|
||||||
struct_type.member_types.push_back(pad_type.self);
|
struct_type.member_types.push_back(pad_type.self);
|
||||||
set_member_name(struct_type.self, mbr_idx, ("pad" + convert_to_string(mbr_idx)));
|
set_member_name(struct_type.self, mbr_idx, ("pad" + convert_to_string(mbr_idx)));
|
||||||
set_member_decoration(struct_type.self, mbr_idx, DecorationOffset, struct_size);
|
set_member_decoration(struct_type.self, mbr_idx, DecorationOffset, struct_size);
|
||||||
|
@ -1276,6 +1438,39 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
||||||
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), "& ", to_name(var.self), type_to_array_glsl(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're currently in the entry point function, and the object
|
||||||
|
// has a qualified name, use it, otherwise use the standard name.
|
||||||
|
string CompilerMSL::to_name(uint32_t id, bool allow_alias)
|
||||||
|
{
|
||||||
|
if (current_function && (current_function->self == entry_point))
|
||||||
|
{
|
||||||
|
string qual_name = meta.at(id).decoration.qualified_alias;
|
||||||
|
if (!qual_name.empty())
|
||||||
|
return qual_name;
|
||||||
|
}
|
||||||
|
return Compiler::to_name(id, allow_alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a name that combines the name of the struct with the name of the member
|
||||||
|
string CompilerMSL::to_qualified_member_name(const SPIRType &type, uint32_t index)
|
||||||
|
{
|
||||||
|
// Get name and strip any underscore prefix
|
||||||
|
string mbr_name = to_member_name(type, index);
|
||||||
|
size_t startPos = mbr_name.find_first_not_of("_");
|
||||||
|
mbr_name = (startPos != std::string::npos) ? mbr_name.substr(startPos) : "";
|
||||||
|
return join(to_name(type.self), "_", mbr_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensures that the specified struct member name is permanently usable by prepending
|
||||||
|
// an alpha char if the first chars are _ and a digit, which indicate a transient name.
|
||||||
|
string CompilerMSL::ensure_member_name(string mbr_name)
|
||||||
|
{
|
||||||
|
if (mbr_name.size() >= 2 && mbr_name[0] == '_' && isdigit(mbr_name[1]))
|
||||||
|
return join("m", mbr_name);
|
||||||
|
else
|
||||||
|
return mbr_name;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns an MSL string describing the SPIR-V type
|
// Returns an MSL string describing the SPIR-V type
|
||||||
string CompilerMSL::type_to_glsl(const SPIRType &type)
|
string CompilerMSL::type_to_glsl(const SPIRType &type)
|
||||||
{
|
{
|
||||||
|
@ -1413,7 +1608,7 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin)
|
||||||
switch (builtin)
|
switch (builtin)
|
||||||
{
|
{
|
||||||
case BuiltInPosition:
|
case BuiltInPosition:
|
||||||
return (stage_out_var_name + ".gl_Position");
|
return qual_pos_var_name.empty() ? (stage_out_var_name + ".gl_Position") : qual_pos_var_name;
|
||||||
case BuiltInPointSize:
|
case BuiltInPointSize:
|
||||||
return (stage_out_var_name + ".gl_PointSize");
|
return (stage_out_var_name + ".gl_PointSize");
|
||||||
case BuiltInVertexId:
|
case BuiltInVertexId:
|
||||||
|
@ -1493,7 +1688,7 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin)
|
||||||
return "front_facing";
|
return "front_facing";
|
||||||
case BuiltInPointCoord:
|
case BuiltInPointCoord:
|
||||||
return "point_coord";
|
return "point_coord";
|
||||||
case BuiltInSamplePosition:
|
case BuiltInFragCoord:
|
||||||
return "position";
|
return "position";
|
||||||
case BuiltInSampleId:
|
case BuiltInSampleId:
|
||||||
return "sample_id";
|
return "sample_id";
|
||||||
|
@ -1546,7 +1741,7 @@ string CompilerMSL::builtin_type_decl(BuiltIn builtin)
|
||||||
return "bool";
|
return "bool";
|
||||||
case BuiltInPointCoord:
|
case BuiltInPointCoord:
|
||||||
return "float2";
|
return "float2";
|
||||||
case BuiltInSamplePosition:
|
case BuiltInFragCoord:
|
||||||
return "float4";
|
return "float4";
|
||||||
case BuiltInSampleId:
|
case BuiltInSampleId:
|
||||||
return "uint";
|
return "uint";
|
||||||
|
@ -1576,8 +1771,9 @@ size_t CompilerMSL::get_declared_type_size(const SPIRType &type) const
|
||||||
// taking into consideration the specified mask of decorations.
|
// taking into consideration the specified mask of decorations.
|
||||||
size_t CompilerMSL::get_declared_type_size(const SPIRType &type, uint64_t dec_mask) const
|
size_t CompilerMSL::get_declared_type_size(const SPIRType &type, uint64_t dec_mask) const
|
||||||
{
|
{
|
||||||
if (type.basetype != SPIRType::Struct)
|
if (type.basetype == SPIRType::Struct)
|
||||||
{
|
return get_declared_struct_size(type);
|
||||||
|
|
||||||
switch (type.basetype)
|
switch (type.basetype)
|
||||||
{
|
{
|
||||||
case SPIRType::Unknown:
|
case SPIRType::Unknown:
|
||||||
|
@ -1617,18 +1813,11 @@ size_t CompilerMSL::get_declared_type_size(const SPIRType &type, uint64_t dec_ma
|
||||||
// ArrayStride is part of the array type not OpMemberDecorate.
|
// ArrayStride is part of the array type not OpMemberDecorate.
|
||||||
auto &dec = meta[type.self].decoration;
|
auto &dec = meta[type.self].decoration;
|
||||||
if (dec.decoration_flags & (1ull << DecorationArrayStride))
|
if (dec.decoration_flags & (1ull << DecorationArrayStride))
|
||||||
return dec.array_stride * to_array_size_literal(type, type.array.size() - 1);
|
return dec.array_stride * to_array_size_literal(type, uint32_t(type.array.size()) - 1);
|
||||||
else
|
|
||||||
throw CompilerError("Type does not have ArrayStride set.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Recurse.
|
throw CompilerError("Type does not have ArrayStride set.");
|
||||||
uint32_t last = uint32_t(type.member_types.size() - 1);
|
}
|
||||||
uint32_t offset = type_struct_member_offset(type, last);
|
|
||||||
size_t size = get_declared_struct_size(get<SPIRType>(type.member_types.back()));
|
|
||||||
return offset + size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,9 +107,16 @@ protected:
|
||||||
std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member) override;
|
std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member) override;
|
||||||
std::string constant_expression(const SPIRConstant &c) override;
|
std::string constant_expression(const SPIRConstant &c) override;
|
||||||
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
|
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
|
||||||
|
std::string to_func_call_arg(uint32_t id) override;
|
||||||
|
std::string to_name(uint32_t id, bool allow_alias = true) override;
|
||||||
|
|
||||||
void extract_builtins();
|
void extract_builtins();
|
||||||
|
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_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids,
|
||||||
|
std::set<uint32_t> &global_var_ids,
|
||||||
|
std::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::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);
|
||||||
|
@ -117,11 +124,14 @@ protected:
|
||||||
void emit_interface_block(uint32_t ib_var_id);
|
void emit_interface_block(uint32_t ib_var_id);
|
||||||
void emit_function_prototype(SPIRFunction &func, bool is_decl);
|
void emit_function_prototype(SPIRFunction &func, bool is_decl);
|
||||||
void emit_function_declarations();
|
void emit_function_declarations();
|
||||||
|
void emit_msl_defines();
|
||||||
|
|
||||||
std::string func_type_decl(SPIRType &type);
|
std::string func_type_decl(SPIRType &type);
|
||||||
std::string clean_func_name(std::string func_name);
|
std::string clean_func_name(std::string func_name);
|
||||||
std::string entry_point_args(bool append_comma);
|
std::string entry_point_args(bool append_comma);
|
||||||
std::string get_entry_point_name();
|
std::string get_entry_point_name();
|
||||||
|
std::string to_qualified_member_name(const SPIRType &type, uint32_t index);
|
||||||
|
std::string ensure_member_name(std::string mbr_name);
|
||||||
std::string to_sampler_expression(uint32_t id);
|
std::string to_sampler_expression(uint32_t id);
|
||||||
std::string builtin_qualifier(spv::BuiltIn builtin);
|
std::string builtin_qualifier(spv::BuiltIn builtin);
|
||||||
std::string builtin_type_decl(spv::BuiltIn builtin);
|
std::string builtin_type_decl(spv::BuiltIn builtin);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче