Merge MSL with upstream.

This commit is contained in:
Bill Hollings 2016-08-31 21:00:56 -04:00
commit cf476f36d1
14 changed files with 292 additions and 39 deletions

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
};
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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):