Add traversal for active builtin variables.

Refactor some ugly type-copying for access chains.
This commit is contained in:
Hans-Kristian Arntzen 2017-03-06 15:21:00 +01:00
parent 829910280d
commit 099f307123
6 changed files with 155 additions and 19 deletions

View File

@ -297,6 +297,8 @@ string CompilerCPP::compile()
backend.explicit_struct_type = true;
backend.use_initializer_list = true;
update_active_builtins();
uint32_t pass_count = 0;
do
{

View File

@ -491,7 +491,7 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
case OpCopyMemory:
{
if (length < 3)
if (length < 2)
return false;
auto *var = compiler.maybe_get<SPIRVariable>(args[0]);
@ -2865,7 +2865,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
case OpCopyMemory:
{
if (length < 3)
if (length < 2)
return false;
uint32_t lhs = args[0];
@ -3116,3 +3116,117 @@ bool Compiler::get_common_basic_type(const SPIRType &type, SPIRType::BaseType &b
return true;
}
}
bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
{
const auto add_if_builtin = [&](uint32_t id) {
// Only handles variables here.
// Builtins which are part of a block are handled in AccessChain.
auto *var = compiler.maybe_get<SPIRVariable>(id);
if (var && compiler.meta[id].decoration.builtin)
compiler.active_builtins |= 1ull << compiler.meta[id].decoration.builtin_type;
};
switch (opcode)
{
case OpStore:
if (length < 1)
return false;
add_if_builtin(args[0]);
break;
case OpCopyMemory:
if (length < 2)
return false;
add_if_builtin(args[0]);
add_if_builtin(args[1]);
break;
case OpCopyObject:
case OpLoad:
if (length < 3)
return false;
add_if_builtin(args[2]);
break;
case OpFunctionCall:
{
if (length < 3)
return false;
uint32_t count = length - 3;
args += 3;
for (uint32_t i = 0; i < count; i++)
add_if_builtin(args[i]);
break;
}
case OpAccessChain:
case OpInBoundsAccessChain:
{
if (length < 4)
return false;
// Only consider global variables, cannot consider variables in functions yet, or other
// access chains as they have not been created yet.
auto *var = compiler.maybe_get<SPIRVariable>(args[2]);
if (!var)
break;
auto *type = &compiler.get<SPIRType>(var->basetype);
// Start traversing type hierarchy at the proper non-pointer types.
while (type->pointer)
{
assert(type->parent_type);
type = &compiler.get<SPIRType>(type->parent_type);
}
uint32_t count = length - 3;
args += 3;
for (uint32_t i = 0; i < count; i++)
{
// Arrays
if (!type->array.empty())
{
type = &compiler.get<SPIRType>(type->parent_type);
}
// Structs
else if (type->basetype == SPIRType::Struct)
{
uint32_t index = compiler.get<SPIRConstant>(args[i]).scalar();
if (index < uint32_t(compiler.meta[type->self].members.size()))
{
auto &decorations = compiler.meta[type->self].members[index];
if (decorations.builtin)
compiler.active_builtins |= 1ull << decorations.builtin_type;
}
type = &compiler.get<SPIRType>(type->member_types[index]);
}
else
{
// No point in traversing further. We won't find any extra builtins.
break;
}
}
break;
}
default:
break;
}
return true;
}
void Compiler::update_active_builtins()
{
active_builtins = 0;
ActiveBuiltinHandler handler(*this);
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
}

View File

@ -577,6 +577,17 @@ protected:
void register_combined_image_sampler(SPIRFunction &caller, uint32_t texture_id, uint32_t sampler_id);
};
struct ActiveBuiltinHandler : OpcodeHandler
{
ActiveBuiltinHandler(Compiler &compiler_)
: compiler(compiler_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
};
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.
@ -591,6 +602,10 @@ protected:
std::unordered_set<uint32_t> forced_temporaries;
std::unordered_set<uint32_t> forwarded_temporaries;
uint64_t active_builtins = 0;
// Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader.
void update_active_builtins();
};
}

View File

@ -310,6 +310,7 @@ string CompilerGLSL::compile()
// Scan the SPIR-V to find trivial uses of extensions.
find_static_extensions();
fixup_image_load_store_access();
update_active_builtins();
uint32_t pass_count = 0;
do
@ -3331,8 +3332,12 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
const auto *type = &expression_type(base);
// For resolving array accesses, etc, keep a local copy for poking.
SPIRType temp;
// Start traversing type hierarchy at the proper non-pointer types.
while (type->pointer)
{
assert(type->parent_type);
type = &get<SPIRType>(type->parent_type);
}
bool access_chain_is_arrayed = false;
bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
@ -3351,11 +3356,8 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
expr += to_expression(index);
expr += "]";
// We have to modify the type, so keep a local copy.
if (&temp != type)
temp = *type;
type = &temp;
temp.array.pop_back();
assert(type->parent_type);
type = &get<SPIRType>(type->parent_type);
access_chain_is_arrayed = true;
}
@ -3414,11 +3416,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
expr += to_expression(index);
expr += "]";
// We have to modify the type, so keep a local copy.
if (&temp != type)
temp = *type;
type = &temp;
temp.columns = 1;
type = &get<SPIRType>(type->parent_type);
}
// Vector -> Scalar
else if (type->vecsize > 1)
@ -3441,11 +3439,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
expr += "]";
}
// We have to modify the type, so keep a local copy.
if (&temp != type)
temp = *type;
type = &temp;
temp.vecsize = 1;
type = &get<SPIRType>(type->parent_type);
}
else
SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
@ -3686,6 +3680,13 @@ std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(uin
{
const auto *type = &expression_type(base);
// Start traversing type hierarchy at the proper non-pointer types.
while (type->pointer)
{
assert(type->parent_type);
type = &get<SPIRType>(type->parent_type);
}
// This holds the type of the current pointer which we are traversing through.
// We always start out from a struct type which is the block.
// This is primarily used to reflect the array strides and matrix strides later.

View File

@ -1006,6 +1006,8 @@ string CompilerHLSL::compile()
backend.use_initializer_list = true;
backend.use_constructor_splatting = false;
update_active_builtins();
uint32_t pass_count = 0;
do
{

View File

@ -68,6 +68,8 @@ string CompilerMSL::compile()
non_stage_in_input_var_ids.clear();
struct_member_padding.clear();
update_active_builtins();
// Preprocess OpCodes to extract the need to output additional header content
set_enabled_interface_variables(get_active_interface_variables());
preprocess_op_codes();