mirror of
https://github.com/KhronosGroup/SPIRV-Cross.git
synced 2024-11-14 16:01:07 +00:00
Merge MSL with upstream.
This commit is contained in:
commit
cf476f36d1
15
main.cpp
15
main.cpp
@ -381,6 +381,7 @@ struct CLIArguments
|
||||
bool cpp = false;
|
||||
bool metal = false;
|
||||
bool vulkan_semantics = false;
|
||||
bool remove_unused = false;
|
||||
};
|
||||
|
||||
static void print_help()
|
||||
@ -389,7 +390,7 @@ static void print_help()
|
||||
"version>] [--dump-resources] [--help] [--force-temporary] [--cpp] [--cpp-interface-name <name>] "
|
||||
"[--metal] [--vulkan-semantics] [--flatten-ubo] [--fixup-clipspace] [--iterations iter] [--pls-in "
|
||||
"format input-name] [--pls-out format output-name] [--remap source_name target_name components] "
|
||||
"[--extension ext] [--entry name]\n");
|
||||
"[--extension ext] [--entry name] [--remove-unused-variables]\n");
|
||||
}
|
||||
|
||||
static bool remap_generic(Compiler &compiler, const vector<Resource> &resources, const Remap &remap)
|
||||
@ -527,6 +528,8 @@ int main(int argc, char *argv[])
|
||||
args.pls_out.push_back({ move(fmt), move(name) });
|
||||
});
|
||||
|
||||
cbs.add("--remove-unused-variables", [&args](CLIParser &) { args.remove_unused = true; });
|
||||
|
||||
cbs.default_handler = [&args](const char *value) { args.input = value; };
|
||||
cbs.error_handler = [] { print_help(); };
|
||||
|
||||
@ -580,7 +583,15 @@ int main(int argc, char *argv[])
|
||||
opts.vertex.fixup_clipspace = args.fixup;
|
||||
compiler->set_options(opts);
|
||||
|
||||
auto res = compiler->get_shader_resources();
|
||||
ShaderResources res;
|
||||
if (args.remove_unused)
|
||||
{
|
||||
auto active = compiler->get_active_interface_variables();
|
||||
res = compiler->get_shader_resources(active);
|
||||
compiler->set_enabled_interface_variables(move(active));
|
||||
}
|
||||
else
|
||||
res = compiler->get_shader_resources();
|
||||
|
||||
if (args.flatten_ubo)
|
||||
for (auto &ubo : res.uniform_buffers)
|
||||
|
@ -77,5 +77,8 @@ void main()
|
||||
k = lessThanEqual(a, a);
|
||||
k = greaterThan(a, a);
|
||||
k = greaterThanEqual(a, a);
|
||||
ssbo_1.b.x = (ssbo_1.b.x + 1.0lf);
|
||||
ssbo_2.b[0].x = (ssbo_2.b[0].x + 1.0lf);
|
||||
ssbo_3.b[0].x = (ssbo_3.b[0].x + 1.0lf);
|
||||
}
|
||||
|
||||
|
@ -46,5 +46,7 @@ void main()
|
||||
ssbo_1.b = (ssbo_1.b - u64vec4(i64vec4(1l)));
|
||||
ssbo_1.b = doubleBitsToUint64(int64BitsToDouble(ssbo_0.a));
|
||||
ssbo_0.a = doubleBitsToInt64(uint64BitsToDouble(ssbo_1.b));
|
||||
ssbo_2.a[0] = (ssbo_2.a[0] + 1l);
|
||||
ssbo_3.a[0] = (ssbo_3.a[0] + 2l);
|
||||
}
|
||||
|
||||
|
@ -84,4 +84,8 @@ void main()
|
||||
k = lessThanEqual(a, a);
|
||||
k = greaterThan(a, a);
|
||||
k = greaterThanEqual(a, a);
|
||||
|
||||
ssbo_1.b.x += 1.0lf;
|
||||
ssbo_2.b[0].x += 1.0lf;
|
||||
ssbo_3.b[0].x += 1.0lf;
|
||||
}
|
||||
|
@ -49,4 +49,7 @@ void main()
|
||||
|
||||
ssbo_1.b = doubleBitsToUint64(int64BitsToDouble(ssbo_0.a));
|
||||
ssbo_0.a = doubleBitsToInt64(uint64BitsToDouble(ssbo_1.b));
|
||||
|
||||
ssbo_2.a[0] += 1l;
|
||||
ssbo_3.a[0] += 2l;
|
||||
}
|
||||
|
@ -51,10 +51,15 @@ void CompilerCPP::emit_interface_block(const SPIRVariable &var)
|
||||
auto instance_name = to_name(var.self);
|
||||
uint32_t location = meta[var.self].decoration.location;
|
||||
|
||||
string buffer_name;
|
||||
auto flags = meta[type.self].decoration.decoration_flags;
|
||||
if (flags & (1ull << DecorationBlock))
|
||||
{
|
||||
emit_block_struct(type);
|
||||
auto buffer_name = to_name(type.self);
|
||||
buffer_name = to_name(type.self);
|
||||
}
|
||||
else
|
||||
buffer_name = type_to_glsl(type);
|
||||
|
||||
statement("internal::", qual, "<", buffer_name, type_to_array_glsl(type), "> ", instance_name, "__;");
|
||||
statement_no_indent("#define ", instance_name, " __res->", instance_name, "__.get()");
|
||||
@ -164,8 +169,8 @@ void CompilerCPP::emit_resources()
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
|
||||
!is_builtin_variable(var) && (meta[type.self].decoration.decoration_flags &
|
||||
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
|
||||
!is_hidden_variable(var) && (meta[type.self].decoration.decoration_flags &
|
||||
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
|
||||
{
|
||||
emit_buffer_block(var);
|
||||
}
|
||||
@ -179,8 +184,11 @@ void CompilerCPP::emit_resources()
|
||||
{
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant)
|
||||
if (!is_hidden_variable(var) && var.storage != StorageClassFunction && type.pointer &&
|
||||
type.storage == StorageClassPushConstant)
|
||||
{
|
||||
emit_push_constant_block(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,8 +200,8 @@ void CompilerCPP::emit_resources()
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (var.storage != StorageClassFunction && !is_builtin_variable(var) && !var.remapped_variable &&
|
||||
type.pointer && (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
||||
if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
|
||||
(var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
||||
interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
emit_interface_block(var);
|
||||
@ -209,8 +217,7 @@ void CompilerCPP::emit_resources()
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (var.storage != StorageClassFunction && !is_builtin_variable(var) && !var.remapped_variable &&
|
||||
type.pointer &&
|
||||
if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
|
||||
(type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
|
||||
{
|
||||
emit_uniform(var);
|
||||
|
134
spirv_cross.cpp
134
spirv_cross.cpp
@ -360,6 +360,34 @@ bool Compiler::is_immutable(uint32_t id) const
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool storage_class_is_interface(spv::StorageClass storage)
|
||||
{
|
||||
switch (storage)
|
||||
{
|
||||
case StorageClassInput:
|
||||
case StorageClassOutput:
|
||||
case StorageClassUniform:
|
||||
case StorageClassUniformConstant:
|
||||
case StorageClassAtomicCounter:
|
||||
case StorageClassPushConstant:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Compiler::is_hidden_variable(const SPIRVariable &var, bool include_builtins) const
|
||||
{
|
||||
if ((is_builtin_variable(var) && !include_builtins) || var.remapped_variable)
|
||||
return true;
|
||||
|
||||
bool hidden = false;
|
||||
if (check_active_interface_variables && storage_class_is_interface(var.storage))
|
||||
hidden = active_interface_variables.find(var.self) == end(active_interface_variables);
|
||||
return hidden;
|
||||
}
|
||||
|
||||
bool Compiler::is_builtin_variable(const SPIRVariable &var) const
|
||||
{
|
||||
if (var.compat_builtin || meta[var.self].decoration.builtin)
|
||||
@ -402,6 +430,99 @@ bool Compiler::is_matrix(const SPIRType &type) const
|
||||
}
|
||||
|
||||
ShaderResources Compiler::get_shader_resources() const
|
||||
{
|
||||
return get_shader_resources(nullptr);
|
||||
}
|
||||
|
||||
ShaderResources Compiler::get_shader_resources(const unordered_set<uint32_t> &active_variables) const
|
||||
{
|
||||
return get_shader_resources(&active_variables);
|
||||
}
|
||||
|
||||
bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t *args, uint32_t length)
|
||||
{
|
||||
uint32_t variable = 0;
|
||||
switch (opcode)
|
||||
{
|
||||
// Need this first, otherwise, GCC complains about unhandled switch statements.
|
||||
default:
|
||||
break;
|
||||
|
||||
case OpFunctionCall:
|
||||
{
|
||||
// Invalid SPIR-V.
|
||||
if (length < 3)
|
||||
return false;
|
||||
|
||||
uint32_t count = length - 3;
|
||||
args += 3;
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
auto *var = compiler.maybe_get<SPIRVariable>(args[i]);
|
||||
if (var && storage_class_is_interface(var->storage))
|
||||
variables.insert(args[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpAtomicStore:
|
||||
case OpStore:
|
||||
// Invalid SPIR-V.
|
||||
if (length < 1)
|
||||
return false;
|
||||
variable = args[0];
|
||||
break;
|
||||
|
||||
case OpAccessChain:
|
||||
case OpInBoundsAccessChain:
|
||||
case OpLoad:
|
||||
case OpImageTexelPointer:
|
||||
case OpAtomicLoad:
|
||||
case OpAtomicExchange:
|
||||
case OpAtomicCompareExchange:
|
||||
case OpAtomicIIncrement:
|
||||
case OpAtomicIDecrement:
|
||||
case OpAtomicIAdd:
|
||||
case OpAtomicISub:
|
||||
case OpAtomicSMin:
|
||||
case OpAtomicUMin:
|
||||
case OpAtomicSMax:
|
||||
case OpAtomicUMax:
|
||||
case OpAtomicAnd:
|
||||
case OpAtomicOr:
|
||||
case OpAtomicXor:
|
||||
// Invalid SPIR-V.
|
||||
if (length < 3)
|
||||
return false;
|
||||
variable = args[2];
|
||||
break;
|
||||
}
|
||||
|
||||
if (variable)
|
||||
{
|
||||
auto *var = compiler.maybe_get<SPIRVariable>(variable);
|
||||
if (var && storage_class_is_interface(var->storage))
|
||||
variables.insert(variable);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unordered_set<uint32_t> Compiler::get_active_interface_variables() const
|
||||
{
|
||||
// Traverse the call graph and find all interface variables which are in use.
|
||||
unordered_set<uint32_t> variables;
|
||||
InterfaceVariableAccessHandler handler(*this, variables);
|
||||
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
|
||||
return variables;
|
||||
}
|
||||
|
||||
void Compiler::set_enabled_interface_variables(std::unordered_set<uint32_t> active_variables)
|
||||
{
|
||||
active_interface_variables = move(active_variables);
|
||||
check_active_interface_variables = true;
|
||||
}
|
||||
|
||||
ShaderResources Compiler::get_shader_resources(const unordered_set<uint32_t> *active_variables) const
|
||||
{
|
||||
ShaderResources res;
|
||||
|
||||
@ -418,6 +539,9 @@ ShaderResources Compiler::get_shader_resources() const
|
||||
if (var.storage == StorageClassFunction || !type.pointer || is_builtin_variable(var))
|
||||
continue;
|
||||
|
||||
if (active_variables && active_variables->find(var.self) == end(*active_variables))
|
||||
continue;
|
||||
|
||||
// Input
|
||||
if (var.storage == StorageClassInput && interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
@ -701,7 +825,11 @@ void Compiler::set_member_qualified_name(uint32_t id, uint32_t index, const std:
|
||||
|
||||
uint32_t Compiler::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
|
||||
{
|
||||
auto &dec = meta.at(id).members.at(index);
|
||||
auto &m = meta.at(id);
|
||||
if (index >= m.members.size())
|
||||
return 0;
|
||||
|
||||
auto &dec = m.members[index];
|
||||
if (!(dec.decoration_flags & (1ull << decoration)))
|
||||
return 0;
|
||||
|
||||
@ -879,6 +1007,7 @@ void Compiler::parse(const Instruction &instruction)
|
||||
case OpMemoryModel:
|
||||
case OpSourceExtension:
|
||||
case OpNop:
|
||||
case OpLine:
|
||||
break;
|
||||
|
||||
case OpSource:
|
||||
@ -1778,8 +1907,7 @@ bool Compiler::traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHand
|
||||
if (!handler.handle(op, ops, i.length))
|
||||
return false;
|
||||
|
||||
uint32_t func = ops[2];
|
||||
if (op == OpFunctionCall && !traverse_all_reachable_opcodes(get<SPIRFunction>(func), handler))
|
||||
if (op == OpFunctionCall && !traverse_all_reachable_opcodes(get<SPIRFunction>(ops[2]), handler))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -179,9 +179,29 @@ public:
|
||||
// The name of the uniform will be the same as the interface block name.
|
||||
void flatten_interface_block(uint32_t id);
|
||||
|
||||
// Returns a set of all global variables which are statically accessed
|
||||
// by the control flow graph from the current entry point.
|
||||
// Only variables which change the interface for a shader are returned, that is,
|
||||
// variables with storage class of Input, Output, Uniform, UniformConstant, PushConstant and AtomicCounter
|
||||
// storage classes are returned.
|
||||
//
|
||||
// To use the returned set as the filter for which variables are used during compilation,
|
||||
// this set can be moved to set_enabled_interface_variables().
|
||||
std::unordered_set<uint32_t> get_active_interface_variables() const;
|
||||
|
||||
// Sets the interface variables which are used during compilation.
|
||||
// By default, all variables are used.
|
||||
// Once set, compile() will only consider the set in active_variables.
|
||||
void set_enabled_interface_variables(std::unordered_set<uint32_t> active_variables);
|
||||
|
||||
// Query shader resources, use ids with reflection interface to modify or query binding points, etc.
|
||||
ShaderResources get_shader_resources() const;
|
||||
|
||||
// Query shader resources, but only return the variables which are part of active_variables.
|
||||
// E.g.: get_shader_resources(get_active_variables()) to only return the variables which are statically
|
||||
// accessed.
|
||||
ShaderResources get_shader_resources(const std::unordered_set<uint32_t> &active_variables) const;
|
||||
|
||||
// Remapped variables are considered built-in variables and a backend will
|
||||
// not emit a declaration for this variable.
|
||||
// This is mostly useful for making use of builtins which are dependent on extensions.
|
||||
@ -240,6 +260,8 @@ protected:
|
||||
SPIRBlock *current_block = nullptr;
|
||||
std::vector<uint32_t> global_variables;
|
||||
std::vector<uint32_t> aliased_variables;
|
||||
std::unordered_set<uint32_t> active_interface_variables;
|
||||
bool check_active_interface_variables = false;
|
||||
|
||||
// If our IDs are out of range here as part of opcodes, throw instead of
|
||||
// undefined behavior.
|
||||
@ -305,6 +327,7 @@ protected:
|
||||
|
||||
virtual std::string to_name(uint32_t id, bool allow_alias = true);
|
||||
bool is_builtin_variable(const SPIRVariable &var) const;
|
||||
bool is_hidden_variable(const SPIRVariable &var, bool include_builtins = false) const;
|
||||
bool is_immutable(uint32_t id) const;
|
||||
bool is_member_builtin(const SPIRType &type, uint32_t index, spv::BuiltIn *builtin) const;
|
||||
bool is_scalar(const SPIRType &type) const;
|
||||
@ -402,10 +425,26 @@ private:
|
||||
std::unordered_set<uint32_t> seen;
|
||||
};
|
||||
|
||||
struct InterfaceVariableAccessHandler : OpcodeHandler
|
||||
{
|
||||
InterfaceVariableAccessHandler(const Compiler &compiler_, std::unordered_set<uint32_t> &variables_)
|
||||
: compiler(compiler_)
|
||||
, variables(variables_)
|
||||
{
|
||||
}
|
||||
|
||||
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
|
||||
|
||||
const Compiler &compiler;
|
||||
std::unordered_set<uint32_t> &variables;
|
||||
};
|
||||
|
||||
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
|
||||
bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
|
||||
// This must be an ordered data structure so we always pick the same type aliases.
|
||||
std::vector<uint32_t> global_struct_cache;
|
||||
|
||||
ShaderResources get_shader_resources(const std::unordered_set<uint32_t> *active_variables) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -449,7 +449,7 @@ string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
|
||||
|
||||
auto &memb = meta[type.self].members;
|
||||
if (index >= memb.size())
|
||||
return 0;
|
||||
return "";
|
||||
auto &dec = memb[index];
|
||||
|
||||
vector<string> attr;
|
||||
@ -1017,6 +1017,23 @@ void CompilerGLSL::emit_uniform(const SPIRVariable &var)
|
||||
statement(layout_for_variable(var), "uniform ", variable_decl(var), ";");
|
||||
}
|
||||
|
||||
void CompilerGLSL::replace_illegal_names()
|
||||
{
|
||||
for (auto &id : ids)
|
||||
{
|
||||
if (id.get_type() == TypeVariable)
|
||||
{
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
if (!is_hidden_variable(var))
|
||||
{
|
||||
auto &m = meta[var.self].decoration;
|
||||
if (m.alias.compare(0, 3, "gl_") == 0)
|
||||
m.alias = join("_", m.alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
|
||||
{
|
||||
auto &m = meta[var.self].decoration;
|
||||
@ -1024,7 +1041,28 @@ void CompilerGLSL::replace_fragment_output(SPIRVariable &var)
|
||||
if (m.decoration_flags & (1ull << DecorationLocation))
|
||||
location = m.location;
|
||||
|
||||
m.alias = join("gl_FragData[", location, "]");
|
||||
// If our variable is arrayed, we must not emit the array part of this as the SPIR-V will
|
||||
// do the access chain part of this for us.
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (type.array.empty())
|
||||
{
|
||||
// Redirect the write to a specific render target in legacy GLSL.
|
||||
m.alias = join("gl_FragData[", location, "]");
|
||||
}
|
||||
else if (type.array.size() == 1)
|
||||
{
|
||||
// If location is non-zero, we probably have to add an offset.
|
||||
// This gets really tricky since we'd have to inject an offset in the access chain.
|
||||
// FIXME: This seems like an extremely odd-ball case, so it's probably fine to leave it like this for now.
|
||||
m.alias = "gl_FragData";
|
||||
if (location != 0)
|
||||
throw CompilerError("Arrayed output variable used, but location is not 0. "
|
||||
"This is unimplemented in SPIRV-Cross.");
|
||||
}
|
||||
else
|
||||
throw CompilerError("Array-of-array output variable used. This cannot be implemented in legacy GLSL.");
|
||||
|
||||
var.compat_builtin = true; // We don't want to declare this variable, but use the name as-is.
|
||||
}
|
||||
|
||||
@ -1101,6 +1139,8 @@ void CompilerGLSL::emit_resources()
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
|
||||
replace_illegal_names();
|
||||
|
||||
// Legacy GL uses gl_FragData[], redeclare all fragment outputs
|
||||
// with builtins.
|
||||
if (execution.model == ExecutionModelFragment && is_legacy())
|
||||
@ -1135,8 +1175,8 @@ void CompilerGLSL::emit_resources()
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
|
||||
!is_builtin_variable(var) && (meta[type.self].decoration.decoration_flags &
|
||||
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
|
||||
!is_hidden_variable(var) && (meta[type.self].decoration.decoration_flags &
|
||||
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
|
||||
{
|
||||
emit_buffer_block(var);
|
||||
}
|
||||
@ -1150,8 +1190,11 @@ void CompilerGLSL::emit_resources()
|
||||
{
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant)
|
||||
if (!is_hidden_variable(var) && var.storage != StorageClassFunction && type.pointer &&
|
||||
type.storage == StorageClassPushConstant)
|
||||
{
|
||||
emit_push_constant_block(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1165,8 +1208,7 @@ void CompilerGLSL::emit_resources()
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (var.storage != StorageClassFunction && !is_builtin_variable(var) && !var.remapped_variable &&
|
||||
type.pointer &&
|
||||
if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
|
||||
(type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter))
|
||||
{
|
||||
emit_uniform(var);
|
||||
@ -1187,8 +1229,8 @@ void CompilerGLSL::emit_resources()
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (var.storage != StorageClassFunction && !is_builtin_variable(var) && !var.remapped_variable &&
|
||||
type.pointer && (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
||||
if (var.storage != StorageClassFunction && !is_hidden_variable(var) && type.pointer &&
|
||||
(var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
||||
interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
emit_interface_block(var);
|
||||
|
@ -310,6 +310,8 @@ protected:
|
||||
// and force recompile.
|
||||
bool check_atomic_image(uint32_t id);
|
||||
|
||||
void replace_illegal_names();
|
||||
|
||||
void replace_fragment_output(SPIRVariable &var);
|
||||
void replace_fragment_outputs();
|
||||
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype);
|
||||
|
@ -116,6 +116,7 @@ void CompilerMSL::extract_builtins()
|
||||
}
|
||||
}
|
||||
|
||||
auto &execution = get_entry_point();
|
||||
if (execution.model == ExecutionModelVertex) {
|
||||
if ( !(builtin_vars[BuiltInVertexIndex] || builtin_vars[BuiltInVertexId]) )
|
||||
add_builtin(BuiltInVertexIndex);
|
||||
@ -187,7 +188,7 @@ void CompilerMSL::extract_global_variables_from_functions()
|
||||
|
||||
std::set<uint32_t> added_arg_ids;
|
||||
std::set<uint32_t> processed_func_ids;
|
||||
extract_global_variables_from_function(execution.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.
|
||||
@ -238,7 +239,7 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id,
|
||||
}
|
||||
|
||||
// Add the global variables as arguments to the function
|
||||
if (func_id != execution.entry_point) {
|
||||
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;
|
||||
@ -297,7 +298,7 @@ void CompilerMSL::bind_vertex_attributes(std::set<uint32_t> &bindings)
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (var.storage == StorageClassInput && interface_variable_exists_in_entry_point(var.self) &&
|
||||
(!is_builtin_variable(var)) && !var.remapped_variable && type.pointer)
|
||||
!is_hidden_variable(var) && type.pointer)
|
||||
{
|
||||
auto &dec = meta[var.self].decoration;
|
||||
MSLVertexAttr *p_va = vtx_attrs_by_location[dec.location];
|
||||
@ -339,8 +340,8 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
|
||||
auto &dec = meta[var.self].decoration;
|
||||
|
||||
if (var.storage == storage && interface_variable_exists_in_entry_point(var.self) &&
|
||||
(!is_builtin_variable(var) || incl_builtins) && (!match_binding || (vtx_binding == dec.binding)) &&
|
||||
!var.remapped_variable && type.pointer)
|
||||
!is_hidden_variable(var, incl_builtins) && (!match_binding || (vtx_binding == dec.binding)) &&
|
||||
type.pointer)
|
||||
{
|
||||
vars.push_back(&var);
|
||||
}
|
||||
@ -537,13 +538,11 @@ void CompilerMSL::emit_resources()
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (type.pointer &&
|
||||
!is_builtin_variable(var) &&
|
||||
(var.storage == StorageClassUniform ||
|
||||
var.storage == StorageClassUniformConstant ||
|
||||
var.storage == StorageClassPushConstant) &&
|
||||
(meta[type.self].decoration.decoration_flags &
|
||||
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
|
||||
if (var.storage != StorageClassFunction && type.pointer &&
|
||||
(type.storage == StorageClassUniform || type.storage == StorageClassUniformConstant ||
|
||||
type.storage == StorageClassPushConstant) &&
|
||||
!is_hidden_variable(var) && (meta[type.self].decoration.decoration_flags &
|
||||
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))))
|
||||
{
|
||||
emit_struct(type);
|
||||
}
|
||||
@ -1241,6 +1240,9 @@ string CompilerMSL::entry_point_args(bool append_comma)
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (is_hidden_variable(var, true))
|
||||
continue;
|
||||
|
||||
if (var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
|
||||
var.storage == StorageClassPushConstant)
|
||||
{
|
||||
@ -1418,7 +1420,7 @@ 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 == execution.entry_point) ) {
|
||||
if (current_function && (current_function->self == entry_point) ) {
|
||||
string qual_name = meta.at(id).decoration.qualified_alias;
|
||||
if ( !qual_name.empty() )
|
||||
return qual_name;
|
||||
|
@ -66,7 +66,7 @@ def validate_shader(shader, vulkan):
|
||||
else:
|
||||
subprocess.check_call(['glslangValidator', shader])
|
||||
|
||||
def cross_compile(shader, vulkan, spirv):
|
||||
def cross_compile(shader, vulkan, spirv, eliminate):
|
||||
spirv_f, spirv_path = tempfile.mkstemp()
|
||||
glsl_f, glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
|
||||
os.close(spirv_f)
|
||||
@ -86,14 +86,20 @@ def cross_compile(shader, vulkan, spirv):
|
||||
# subprocess.check_call(['spirv-val', spirv_path])
|
||||
|
||||
spirv_cross_path = './spirv-cross'
|
||||
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', glsl_path, spirv_path])
|
||||
if eliminate:
|
||||
subprocess.check_call([spirv_cross_path, '--remove-unused-variables', '--entry', 'main', '--output', glsl_path, spirv_path])
|
||||
else:
|
||||
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', glsl_path, spirv_path])
|
||||
|
||||
# A shader might not be possible to make valid GLSL from, skip validation for this case.
|
||||
if (not ('nocompat' in glsl_path)) and (not spirv):
|
||||
validate_shader(glsl_path, False)
|
||||
|
||||
if vulkan or spirv:
|
||||
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path])
|
||||
if eliminate:
|
||||
subprocess.check_call([spirv_cross_path, '--remove-unused-variables', '--entry', 'main', '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path])
|
||||
else:
|
||||
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path])
|
||||
validate_shader(vulkan_glsl_path, vulkan)
|
||||
|
||||
return (spirv_path, glsl_path, vulkan_glsl_path if vulkan else None)
|
||||
@ -149,6 +155,9 @@ def shader_is_vulkan(shader):
|
||||
def shader_is_desktop(shader):
|
||||
return '.desktop.' in shader
|
||||
|
||||
def shader_is_eliminate_dead_variables(shader):
|
||||
return '.noeliminate.' not in shader
|
||||
|
||||
def shader_is_spirv(shader):
|
||||
return '.asm.' in shader
|
||||
|
||||
@ -156,10 +165,11 @@ def test_shader(stats, shader, update, keep):
|
||||
joined_path = os.path.join(shader[0], shader[1])
|
||||
vulkan = shader_is_vulkan(shader[1])
|
||||
desktop = shader_is_desktop(shader[1])
|
||||
eliminate = shader_is_eliminate_dead_variables(shader[1])
|
||||
spirv = shader_is_spirv(shader[1])
|
||||
|
||||
print('Testing shader:', joined_path)
|
||||
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, spirv)
|
||||
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, spirv, eliminate)
|
||||
|
||||
# Only test GLSL stats if we have a shader following GL semantics.
|
||||
if stats and (not vulkan) and (not spirv) and (not desktop):
|
||||
|
Loading…
Reference in New Issue
Block a user