This commit is contained in:
Bill Hollings 2016-10-24 09:24:24 -04:00
Родитель 0943d9fece
Коммит ac00c6032f
8 изменённых файлов: 255 добавлений и 240 удалений

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

@ -142,8 +142,14 @@ along with the Apache 2.0 licensing stub.
### Formatting
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.
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.
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

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

@ -845,7 +845,7 @@ struct Meta
struct Decoration
{
std::string alias;
std::string qualified_alias;
std::string qualified_alias;
uint64_t decoration_flags = 0;
spv::BuiltIn builtin_type;
uint32_t location = 0;

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

@ -847,8 +847,8 @@ const std::string &Compiler::get_member_name(uint32_t id, uint32_t index) const
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;
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
@ -1112,16 +1112,17 @@ void Compiler::parse(const Instruction &instruction)
case OpEntryPoint:
{
auto itr = entry_points.insert(make_pair(ops[1], SPIREntryPoint(ops[1], static_cast<ExecutionModel>(ops[0]),
extract_string(spirv, instruction.offset + 2))));
auto itr =
entry_points.insert(make_pair(ops[1], SPIREntryPoint(ops[1], static_cast<ExecutionModel>(ops[0]),
extract_string(spirv, instruction.offset + 2))));
auto &e = itr.first->second;
// Strings need nul-terminator and consume the whole word.
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);
// Set the name of the entry point in case OpName is not provided later
set_name(ops[1], e.name);
// 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 (!entry_point)
@ -1182,7 +1183,7 @@ void Compiler::parse(const Instruction &instruction)
else
set_decoration(id, decoration);
break;
break;
}
case OpMemberDecorate:

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

@ -166,8 +166,8 @@ public:
// Sets the member identifier for OpTypeStruct ID, member number "index".
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);
// 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.
uint64_t get_member_decoration_mask(uint32_t id, uint32_t index) const;

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

@ -1404,7 +1404,7 @@ void CompilerGLSL::emit_resources()
// Subclasses may override to modify the return value.
string CompilerGLSL::to_func_call_arg(uint32_t id)
{
return to_expression(id);
return to_expression(id);
}
void CompilerGLSL::handle_invalid_expression(uint32_t id)
@ -3437,7 +3437,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
if (skip_argument(arg[i]))
continue;
arglist.push_back(to_func_call_arg(arg[i]));
arglist.push_back(to_func_call_arg(arg[i]));
}
for (auto &combined : callee.combined_parameters)
@ -3456,9 +3456,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
arglist.push_back(to_combined_image_sampler(image_id, sampler_id));
}
append_global_func_args(callee, length, arglist);
append_global_func_args(callee, length, arglist);
funexpr += merge(arglist);
funexpr += merge(arglist);
funexpr += ")";
// Check for function call constraints.
@ -4575,10 +4575,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
// 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));
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)

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

@ -148,7 +148,7 @@ protected:
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
virtual void emit_fixup();
virtual std::string variable_decl(const SPIRType &type, const std::string &name);
virtual std::string to_func_call_arg(uint32_t id);
virtual std::string to_func_call_arg(uint32_t id);
std::unique_ptr<std::ostringstream> buffer;
@ -286,7 +286,7 @@ protected:
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 declare_temporary(uint32_t type, uint32_t id);
void append_global_func_args(const SPIRFunction &func, uint32_t index, std::vector<std::string> &arglist);
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_member_name(const SPIRType &type, uint32_t index);
std::string type_to_glsl_constructor(const SPIRType &type);

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

@ -56,8 +56,8 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
extract_builtins();
localize_global_variables();
add_interface_structs();
extract_global_variables_from_functions();
add_interface_structs();
extract_global_variables_from_functions();
// Do not deal with ES-isms like precision, older extensions and such.
options.es = false;
@ -102,46 +102,48 @@ string CompilerMSL::compile()
// Adds any builtins used by this shader to the builtin_vars collection
void CompilerMSL::extract_builtins()
{
builtin_vars.clear();
builtin_vars.clear();
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &dec = meta[var.self].decoration;
for (auto &id : ids)
{
if (id.get_type() == TypeVariable)
{
auto &var = id.get<SPIRVariable>();
auto &dec = meta[var.self].decoration;
if (dec.builtin)
builtin_vars[dec.builtin_type] = var.self;
}
}
if (dec.builtin)
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);
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);
}
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) {
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;
// 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));
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;
builtin_vars[builtin_type] = ib_var_id;
}
// Move the Private global variables to the entry function.
@ -171,85 +173,88 @@ void CompilerMSL::localize_global_variables()
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);
}
}
// 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);
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)
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;
// 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);
processed_func_ids.insert(func_id);
auto& func = get<SPIRFunction>(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);
// 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;
}
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;
}
}
}
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++;
}
}
// 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
@ -415,7 +420,7 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
}
auto &type = get<SPIRType>(p_var->basetype);
if (type.basetype == SPIRType::Struct)
if (type.basetype == SPIRType::Struct)
{
// Flatten the struct members into the interface struct
uint32_t i = 0;
@ -510,19 +515,20 @@ void CompilerMSL::emit_header()
statement("");
statement("using namespace metal;");
statement("");
emit_msl_defines();
emit_msl_defines();
}
void CompilerMSL::emit_msl_defines()
{
statement("// Standard GLSL->MSL redefinitions");
statement("#define discard discard_fragment()");
statement("#define dFdy dfdy");
statement("#define dFdx dfdy");
statement("#define atan(x,y) atan2((y),(x))");
statement("inline bool greaterThan(float2 a,float2 b) { return all(a>b) ? true : false; }");
statement("inline uint2 imageSize(thread const texture2d<float>& tex) { return uint2(tex.get_width(), tex.get_height()); }");
statement("");
statement("// Standard GLSL->MSL redefinitions");
statement("#define discard discard_fragment()");
statement("#define dFdy dfdy");
statement("#define dFdx dfdy");
statement("#define atan(x,y) atan2((y),(x))");
statement("inline bool greaterThan(float2 a,float2 b) { return all(a>b) ? true : false; }");
statement("inline uint2 imageSize(thread const texture2d<float>& tex) { return uint2(tex.get_width(), "
"tex.get_height()); }");
statement("");
}
void CompilerMSL::emit_resources()
@ -639,29 +645,30 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, bool is_decl)
bool is_uniform_struct = false;
auto *var = maybe_get<SPIRVariable>(arg.id);
if (var) {
var->parameter = &arg; // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
if (var)
{
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));
}
// 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);
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);
// 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 += ", ";
}
if (&arg != &func.arguments.back())
decl += ", ";
}
decl += ")";
statement(decl, (is_decl ? ";" : ""));
@ -985,15 +992,15 @@ void CompilerMSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id
// 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);
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);
// 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;
return arg_str;
}
// If the ID represents a sampled image that has been assigned a sampler already,
@ -1193,24 +1200,24 @@ string CompilerMSL::func_type_decl(SPIRType &type)
// Prepend a entry type, based on the execution model
string entry_type;
switch (execution.model)
{
case ExecutionModelVertex:
entry_type = "vertex";
break;
case ExecutionModelFragment:
entry_type = (execution.flags & (1ull << ExecutionModeEarlyFragmentTests)) ?
"fragment [[ early_fragment_tests ]]" :
"fragment";
break;
case ExecutionModelGLCompute:
case ExecutionModelKernel:
entry_type = "kernel";
break;
default:
entry_type = "unknown";
break;
}
switch (execution.model)
{
case ExecutionModelVertex:
entry_type = "vertex";
break;
case ExecutionModelFragment:
entry_type = (execution.flags & (1ull << ExecutionModeEarlyFragmentTests)) ?
"fragment [[ early_fragment_tests ]]" :
"fragment";
break;
case ExecutionModelGLCompute:
case ExecutionModelKernel:
entry_type = "kernel";
break;
default:
entry_type = "unknown";
break;
}
return entry_type + " " + return_type;
}
@ -1436,32 +1443,33 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
// 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);
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);
// 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;
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
@ -1765,52 +1773,53 @@ size_t CompilerMSL::get_declared_type_size(const SPIRType &type) const
size_t CompilerMSL::get_declared_type_size(const SPIRType &type, uint64_t dec_mask) const
{
if (type.basetype == SPIRType::Struct)
return get_declared_struct_size(type);
return get_declared_struct_size(type);
switch (type.basetype)
{
case SPIRType::Unknown:
case SPIRType::Void:
case SPIRType::AtomicCounter:
case SPIRType::Image:
case SPIRType::SampledImage:
case SPIRType::Sampler:
throw CompilerError("Querying size of object with opaque size.");
default:
break;
}
switch (type.basetype)
{
case SPIRType::Unknown:
case SPIRType::Void:
case SPIRType::AtomicCounter:
case SPIRType::Image:
case SPIRType::SampledImage:
case SPIRType::Sampler:
throw CompilerError("Querying size of object with opaque size.");
default:
break;
}
size_t component_size = type.width / 8;
unsigned vecsize = type.vecsize;
unsigned columns = type.columns;
size_t component_size = type.width / 8;
unsigned vecsize = type.vecsize;
unsigned columns = type.columns;
if (type.array.empty())
{
// Vectors.
if (columns == 1)
return vecsize * component_size;
else
{
// Per SPIR-V spec, matrices must be tightly packed and aligned up for vec3 accesses.
if ((dec_mask & (1ull << DecorationRowMajor)) && columns == 3)
columns = 4;
else if ((dec_mask & (1ull << DecorationColMajor)) && vecsize == 3)
vecsize = 4;
if (type.array.empty())
{
// Vectors.
if (columns == 1)
return vecsize * component_size;
else
{
// Per SPIR-V spec, matrices must be tightly packed and aligned up for vec3 accesses.
if ((dec_mask & (1ull << DecorationRowMajor)) && columns == 3)
columns = 4;
else if ((dec_mask & (1ull << DecorationColMajor)) && vecsize == 3)
vecsize = 4;
return vecsize * columns * component_size;
}
}
else
{
// For arrays, we can use ArrayStride to get an easy check.
// ArrayStride is part of the array type not OpMemberDecorate.
auto &dec = meta[type.self].decoration;
if (dec.decoration_flags & (1ull << DecorationArrayStride))
return dec.array_stride * to_array_size_literal(type, (uint32_t)type.array.size() - 1);
else {
throw CompilerError("Type does not have ArrayStride set.");
}
}
return vecsize * columns * component_size;
}
}
else
{
// For arrays, we can use ArrayStride to get an easy check.
// ArrayStride is part of the array type not OpMemberDecorate.
auto &dec = meta[type.self].decoration;
if (dec.decoration_flags & (1ull << DecorationArrayStride))
return dec.array_stride * to_array_size_literal(type, (uint32_t)type.array.size() - 1);
else
{
throw CompilerError("Type does not have ArrayStride set.");
}
}
}
// Sort both type and meta member content based on builtin status (put builtins at end), then by location.

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

@ -107,17 +107,16 @@ protected:
std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member) 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;
std::string to_func_call_arg(uint32_t id) override;
std::string to_name(uint32_t id, bool allow_alias = true) 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 add_builtin(spv::BuiltIn builtin_type);
void add_builtin(spv::BuiltIn builtin_type);
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 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 bind_vertex_attributes(std::set<uint32_t> &bindings);
uint32_t add_interface_struct(spv::StorageClass storage, uint32_t vtx_binding = 0);
@ -125,14 +124,14 @@ protected:
void emit_interface_block(uint32_t ib_var_id);
void emit_function_prototype(SPIRFunction &func, bool is_decl);
void emit_function_declarations();
void emit_msl_defines();
void emit_msl_defines();
std::string func_type_decl(SPIRType &type);
std::string clean_func_name(std::string func_name);
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);
std::string ensure_member_name(std::string mbr_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 builtin_qualifier(spv::BuiltIn builtin);
std::string builtin_type_decl(spv::BuiltIn builtin);