Implement dead variable elimination.
This commit is contained in:
parent
bd5eb1d2c6
commit
f61a5d1e5d
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;
|
||||
}
|
||||
|
@ -164,8 +164,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 +179,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 +195,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 +212,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);
|
||||
|
127
spirv_cross.cpp
127
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))
|
||||
{
|
||||
@ -1777,8 +1901,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;
|
||||
}
|
||||
|
||||
|
@ -176,9 +176,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.
|
||||
@ -237,6 +257,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.
|
||||
@ -302,6 +324,7 @@ protected:
|
||||
|
||||
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;
|
||||
@ -399,10 +422,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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1024,14 +1024,11 @@ void CompilerGLSL::replace_illegal_names()
|
||||
if (id.get_type() == TypeVariable)
|
||||
{
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
|
||||
if (!is_builtin_variable(var) && !var.remapped_variable)
|
||||
if (!is_hidden_variable(var))
|
||||
{
|
||||
auto &m = meta[var.self].decoration;
|
||||
if (m.alias.compare(0, 3, "gl_") == 0)
|
||||
{
|
||||
m.alias = join("_", m.alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1178,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);
|
||||
}
|
||||
@ -1193,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1208,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);
|
||||
@ -1230,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);
|
||||
|
@ -184,7 +184,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];
|
||||
@ -226,8 +226,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);
|
||||
}
|
||||
@ -427,8 +427,8 @@ void CompilerMSL::emit_resources()
|
||||
if (var.storage != StorageClassFunction && type.pointer &&
|
||||
(type.storage == StorageClassUniform || type.storage == StorageClassUniformConstant ||
|
||||
type.storage == StorageClassPushConstant) &&
|
||||
!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_struct(type);
|
||||
}
|
||||
@ -1095,6 +1095,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)
|
||||
{
|
||||
|
@ -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