mirror of https://github.com/bkaradzic/bgfx
Updated spirv-cross.
This commit is contained in:
parent
aaf0fdf7cf
commit
6cedc01d19
|
@ -820,6 +820,43 @@ spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *
|
|||
#endif
|
||||
}
|
||||
|
||||
size_t spvc_compiler_get_num_required_extensions(spvc_compiler compiler)
|
||||
{
|
||||
#if SPIRV_CROSS_C_API_GLSL
|
||||
if (compiler->backend != SPVC_BACKEND_GLSL)
|
||||
{
|
||||
compiler->context->report_error("Enabled extensions can only be queried on GLSL backend.");
|
||||
return SPVC_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return static_cast<CompilerGLSL *>(compiler->compiler.get())->get_required_extensions().size();
|
||||
#else
|
||||
compiler->context->report_error("Enabled extensions can only be queried on GLSL backend.");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *spvc_compiler_get_required_extension(spvc_compiler compiler, size_t index)
|
||||
{
|
||||
#if SPIRV_CROSS_C_API_GLSL
|
||||
if (compiler->backend != SPVC_BACKEND_GLSL)
|
||||
{
|
||||
compiler->context->report_error("Enabled extensions can only be queried on GLSL backend.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto &exts = static_cast<CompilerGLSL *>(compiler->compiler.get())->get_required_extensions();
|
||||
if (index < exts.size())
|
||||
return exts[index].c_str();
|
||||
else
|
||||
return nullptr;
|
||||
#else
|
||||
(void)index;
|
||||
compiler->context->report_error("Enabled extensions can only be queried on GLSL backend.");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id)
|
||||
{
|
||||
#if SPIRV_CROSS_C_API_GLSL
|
||||
|
|
|
@ -40,7 +40,7 @@ extern "C" {
|
|||
/* Bumped if ABI or API breaks backwards compatibility. */
|
||||
#define SPVC_C_API_VERSION_MAJOR 0
|
||||
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
|
||||
#define SPVC_C_API_VERSION_MINOR 56
|
||||
#define SPVC_C_API_VERSION_MINOR 57
|
||||
/* Bumped if internal implementation details change. */
|
||||
#define SPVC_C_API_VERSION_PATCH 0
|
||||
|
||||
|
@ -784,6 +784,8 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_compile(spvc_compiler compiler, const
|
|||
/* Maps to C++ API. */
|
||||
SPVC_PUBLIC_API spvc_result spvc_compiler_add_header_line(spvc_compiler compiler, const char *line);
|
||||
SPVC_PUBLIC_API spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *ext);
|
||||
SPVC_PUBLIC_API size_t spvc_compiler_get_num_required_extensions(spvc_compiler compiler);
|
||||
SPVC_PUBLIC_API const char *spvc_compiler_get_required_extension(spvc_compiler compiler, size_t index);
|
||||
SPVC_PUBLIC_API spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id);
|
||||
|
||||
SPVC_PUBLIC_API spvc_bool spvc_compiler_variable_is_depth_or_compare(spvc_compiler compiler, spvc_variable_id id);
|
||||
|
|
|
@ -5102,8 +5102,27 @@ string CompilerGLSL::to_extract_constant_composite_expression(uint32_t result_ty
|
|||
return constant_expression(tmp);
|
||||
}
|
||||
|
||||
string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type)
|
||||
string CompilerGLSL::to_rerolled_array_expression(const SPIRType &parent_type,
|
||||
const string &base_expr, const SPIRType &type)
|
||||
{
|
||||
bool remapped_boolean = parent_type.basetype == SPIRType::Struct &&
|
||||
type.basetype == SPIRType::Boolean &&
|
||||
backend.boolean_in_struct_remapped_type != SPIRType::Boolean;
|
||||
|
||||
SPIRType tmp_type;
|
||||
if (remapped_boolean)
|
||||
{
|
||||
tmp_type = get<SPIRType>(type.parent_type);
|
||||
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
|
||||
}
|
||||
else if (type.basetype == SPIRType::Boolean && backend.boolean_in_struct_remapped_type != SPIRType::Boolean)
|
||||
{
|
||||
// It's possible that we have an r-value expression that was OpLoaded from a struct.
|
||||
// We have to reroll this and explicitly cast the input to bool, because the r-value is short.
|
||||
tmp_type = get<SPIRType>(type.parent_type);
|
||||
remapped_boolean = true;
|
||||
}
|
||||
|
||||
uint32_t size = to_array_size_literal(type);
|
||||
auto &parent = get<SPIRType>(type.parent_type);
|
||||
string expr = "{ ";
|
||||
|
@ -5111,10 +5130,14 @@ string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const
|
|||
for (uint32_t i = 0; i < size; i++)
|
||||
{
|
||||
auto subexpr = join(base_expr, "[", convert_to_string(i), "]");
|
||||
if (parent.array.empty())
|
||||
if (!type_is_top_level_array(parent))
|
||||
{
|
||||
if (remapped_boolean)
|
||||
subexpr = join(type_to_glsl(tmp_type), "(", subexpr, ")");
|
||||
expr += subexpr;
|
||||
}
|
||||
else
|
||||
expr += to_rerolled_array_expression(subexpr, parent);
|
||||
expr += to_rerolled_array_expression(parent_type, subexpr, parent);
|
||||
|
||||
if (i + 1 < size)
|
||||
expr += ", ";
|
||||
|
@ -5124,13 +5147,26 @@ string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const
|
|||
return expr;
|
||||
}
|
||||
|
||||
string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool block_like_type)
|
||||
string CompilerGLSL::to_composite_constructor_expression(const SPIRType &parent_type, uint32_t id, bool block_like_type)
|
||||
{
|
||||
auto &type = expression_type(id);
|
||||
|
||||
bool reroll_array = !type.array.empty() &&
|
||||
(!backend.array_is_value_type ||
|
||||
(block_like_type && !backend.array_is_value_type_in_buffer_blocks));
|
||||
bool reroll_array = false;
|
||||
bool remapped_boolean = parent_type.basetype == SPIRType::Struct &&
|
||||
type.basetype == SPIRType::Boolean &&
|
||||
backend.boolean_in_struct_remapped_type != SPIRType::Boolean;
|
||||
|
||||
if (type_is_top_level_array(type))
|
||||
{
|
||||
reroll_array = !backend.array_is_value_type ||
|
||||
(block_like_type && !backend.array_is_value_type_in_buffer_blocks);
|
||||
|
||||
if (remapped_boolean)
|
||||
{
|
||||
// Forced to reroll if we have to change bool[] to short[].
|
||||
reroll_array = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (reroll_array)
|
||||
{
|
||||
|
@ -5144,10 +5180,20 @@ string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool block
|
|||
|
||||
// We're only triggering one read of the array expression, but this is fine since arrays have to be declared
|
||||
// as temporaries anyways.
|
||||
return to_rerolled_array_expression(to_enclosed_expression(id), type);
|
||||
return to_rerolled_array_expression(parent_type, to_enclosed_expression(id), type);
|
||||
}
|
||||
else
|
||||
return to_unpacked_expression(id);
|
||||
{
|
||||
auto expr = to_unpacked_expression(id);
|
||||
if (remapped_boolean)
|
||||
{
|
||||
auto tmp_type = type;
|
||||
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
|
||||
expr = join(type_to_glsl(tmp_type), "(", expr, ")");
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
|
||||
string CompilerGLSL::to_non_uniform_aware_expression(uint32_t id)
|
||||
|
@ -5657,11 +5703,13 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
|
|||
}
|
||||
}
|
||||
|
||||
string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_block_like_struct_scope)
|
||||
string CompilerGLSL::constant_expression(const SPIRConstant &c,
|
||||
bool inside_block_like_struct_scope,
|
||||
bool inside_struct_scope)
|
||||
{
|
||||
auto &type = get<SPIRType>(c.constant_type);
|
||||
|
||||
if (type.pointer)
|
||||
if (type_is_top_level_pointer(type))
|
||||
{
|
||||
return backend.null_pointer_literal;
|
||||
}
|
||||
|
@ -5676,19 +5724,32 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
|
|||
// with Offset = 0, using no ArrayStride on the enclosed array type.
|
||||
// A particular CTS test hits this scenario.
|
||||
bool array_type_decays = inside_block_like_struct_scope &&
|
||||
!type.array.empty() && !backend.array_is_value_type_in_buffer_blocks;
|
||||
type_is_top_level_array(type) &&
|
||||
!backend.array_is_value_type_in_buffer_blocks;
|
||||
|
||||
// Allow Metal to use the array<T> template to make arrays a value type
|
||||
bool needs_trailing_tracket = false;
|
||||
if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct &&
|
||||
type.array.empty())
|
||||
!type_is_top_level_array(type))
|
||||
{
|
||||
res = type_to_glsl_constructor(type) + "{ ";
|
||||
}
|
||||
else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type &&
|
||||
!type.array.empty() && !array_type_decays)
|
||||
type_is_top_level_array(type) && !array_type_decays)
|
||||
{
|
||||
res = type_to_glsl_constructor(type) + "({ ";
|
||||
const auto *p_type = &type;
|
||||
SPIRType tmp_type;
|
||||
|
||||
if (inside_struct_scope &&
|
||||
backend.boolean_in_struct_remapped_type != SPIRType::Boolean &&
|
||||
type.basetype == SPIRType::Boolean)
|
||||
{
|
||||
tmp_type = type;
|
||||
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
|
||||
p_type = &tmp_type;
|
||||
}
|
||||
|
||||
res = type_to_glsl_constructor(*p_type) + "({ ";
|
||||
needs_trailing_tracket = true;
|
||||
}
|
||||
else if (backend.use_initializer_list)
|
||||
|
@ -5718,7 +5779,7 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
|
|||
res += to_name(elem);
|
||||
else
|
||||
{
|
||||
if (type.array.empty() && type.basetype == SPIRType::Struct)
|
||||
if (!type_is_top_level_array(type) && type.basetype == SPIRType::Struct)
|
||||
{
|
||||
// When we get down to emitting struct members, override the block-like information.
|
||||
// For constants, we can freely mix and match block-like state.
|
||||
|
@ -5726,7 +5787,10 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
|
|||
has_member_decoration(type.self, subconstant_index, DecorationOffset);
|
||||
}
|
||||
|
||||
res += constant_expression(subc, inside_block_like_struct_scope);
|
||||
if (type.basetype == SPIRType::Struct)
|
||||
inside_struct_scope = true;
|
||||
|
||||
res += constant_expression(subc, inside_block_like_struct_scope, inside_struct_scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5748,19 +5812,30 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
|
|||
if (backend.supports_empty_struct)
|
||||
return "{ }";
|
||||
else if (backend.use_typed_initializer_list)
|
||||
return join(type_to_glsl(get<SPIRType>(c.constant_type)), "{ 0 }");
|
||||
return join(type_to_glsl(type), "{ 0 }");
|
||||
else if (backend.use_initializer_list)
|
||||
return "{ 0 }";
|
||||
else
|
||||
return join(type_to_glsl(get<SPIRType>(c.constant_type)), "(0)");
|
||||
return join(type_to_glsl(type), "(0)");
|
||||
}
|
||||
else if (c.columns() == 1)
|
||||
{
|
||||
return constant_expression_vector(c, 0);
|
||||
auto res = constant_expression_vector(c, 0);
|
||||
|
||||
if (inside_struct_scope &&
|
||||
backend.boolean_in_struct_remapped_type != SPIRType::Boolean &&
|
||||
type.basetype == SPIRType::Boolean)
|
||||
{
|
||||
SPIRType tmp_type = type;
|
||||
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
|
||||
res = join(type_to_glsl(tmp_type), "(", res, ")");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
string res = type_to_glsl(get<SPIRType>(c.constant_type)) + "(";
|
||||
string res = type_to_glsl(type) + "(";
|
||||
for (uint32_t col = 0; col < c.columns(); col++)
|
||||
{
|
||||
if (c.specialization_constant_id(col) != 0)
|
||||
|
@ -5772,6 +5847,16 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c, bool inside_bloc
|
|||
res += ", ";
|
||||
}
|
||||
res += ")";
|
||||
|
||||
if (inside_struct_scope &&
|
||||
backend.boolean_in_struct_remapped_type != SPIRType::Boolean &&
|
||||
type.basetype == SPIRType::Boolean)
|
||||
{
|
||||
SPIRType tmp_type = type;
|
||||
tmp_type.basetype = backend.boolean_in_struct_remapped_type;
|
||||
res = join(type_to_glsl(tmp_type), "(", res, ")");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -11107,7 +11192,7 @@ string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32
|
|||
|
||||
bool uses_buffer_offset =
|
||||
type.basetype == SPIRType::Struct && has_member_decoration(type.self, i, DecorationOffset);
|
||||
subop = to_composite_constructor_expression(elems[i], uses_buffer_offset);
|
||||
subop = to_composite_constructor_expression(type, elems[i], uses_buffer_offset);
|
||||
}
|
||||
|
||||
base = e ? e->base_expression : ID(0);
|
||||
|
@ -11197,8 +11282,15 @@ void CompilerGLSL::emit_block_instructions(SPIRBlock &block)
|
|||
if (backend.requires_relaxed_precision_analysis)
|
||||
{
|
||||
// If PHI variables are consumed in unexpected precision contexts, copy them here.
|
||||
for (auto &phi : block.phi_variables)
|
||||
for (size_t i = 0, n = block.phi_variables.size(); i < n; i++)
|
||||
{
|
||||
auto &phi = block.phi_variables[i];
|
||||
|
||||
// Ensure we only copy once. We know a-priori that this array will lay out
|
||||
// the same function variables together.
|
||||
if (i && block.phi_variables[i - 1].function_variable == phi.function_variable)
|
||||
continue;
|
||||
|
||||
auto itr = temporary_to_mirror_precision_alias.find(phi.function_variable);
|
||||
if (itr != temporary_to_mirror_precision_alias.end())
|
||||
{
|
||||
|
@ -11737,7 +11829,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||
// it is an array, and our backend does not support arrays as value types.
|
||||
// Emit the temporary, and copy it explicitly.
|
||||
e = &emit_uninitialized_temporary_expression(result_type, id);
|
||||
emit_array_copy(to_expression(id), id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr));
|
||||
emit_array_copy(nullptr, id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr));
|
||||
}
|
||||
else
|
||||
e = &emit_op(result_type, id, expr, forward, !usage_tracking);
|
||||
|
@ -15565,6 +15657,11 @@ void CompilerGLSL::require_extension(const std::string &ext)
|
|||
forced_extensions.push_back(ext);
|
||||
}
|
||||
|
||||
const SmallVector<std::string> &CompilerGLSL::get_required_extensions() const
|
||||
{
|
||||
return forced_extensions;
|
||||
}
|
||||
|
||||
void CompilerGLSL::require_extension_internal(const string &ext)
|
||||
{
|
||||
if (backend.supports_extensions && !has_extension(ext))
|
||||
|
@ -16329,6 +16426,17 @@ bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block)
|
|||
return true;
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_block_instructions_with_masked_debug(SPIRBlock &block)
|
||||
{
|
||||
// Have to block debug instructions such as OpLine here, since it will be treated as a statement otherwise,
|
||||
// which breaks loop optimizations.
|
||||
// Any line directive would be declared outside the loop body, which would just be confusing either way.
|
||||
bool old_block_debug_directives = block_debug_directives;
|
||||
block_debug_directives = true;
|
||||
emit_block_instructions(block);
|
||||
block_debug_directives = old_block_debug_directives;
|
||||
}
|
||||
|
||||
bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method)
|
||||
{
|
||||
SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
|
||||
|
@ -16339,7 +16447,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
|
|||
// If we're trying to create a true for loop,
|
||||
// we need to make sure that all opcodes before branch statement do not actually emit any code.
|
||||
// We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
|
||||
emit_block_instructions(block);
|
||||
emit_block_instructions_with_masked_debug(block);
|
||||
|
||||
bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries);
|
||||
|
||||
|
@ -16419,7 +16527,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
|
|||
// If we're trying to create a true for loop,
|
||||
// we need to make sure that all opcodes before branch statement do not actually emit any code.
|
||||
// We can then take the condition expression and create a for (; cond ; ) { body; } structure instead.
|
||||
emit_block_instructions(child);
|
||||
emit_block_instructions_with_masked_debug(child);
|
||||
|
||||
bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries);
|
||||
|
||||
|
@ -16557,6 +16665,24 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|||
if (block.merge == SPIRBlock::MergeLoop)
|
||||
add_loop_level();
|
||||
|
||||
// If we're emitting PHI variables with precision aliases, we have to emit them as hoisted temporaries.
|
||||
for (auto var_id : block.dominated_variables)
|
||||
{
|
||||
auto &var = get<SPIRVariable>(var_id);
|
||||
if (var.phi_variable)
|
||||
{
|
||||
auto mirrored_precision_itr = temporary_to_mirror_precision_alias.find(var_id);
|
||||
if (mirrored_precision_itr != temporary_to_mirror_precision_alias.end() &&
|
||||
find_if(block.declare_temporary.begin(), block.declare_temporary.end(),
|
||||
[mirrored_precision_itr](const std::pair<TypeID, VariableID> &p) {
|
||||
return p.second == mirrored_precision_itr->second;
|
||||
}) == block.declare_temporary.end())
|
||||
{
|
||||
block.declare_temporary.push_back({ var.basetype, mirrored_precision_itr->second });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit_hoisted_temporaries(block.declare_temporary);
|
||||
|
||||
SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;
|
||||
|
@ -17338,9 +17464,16 @@ uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics)
|
|||
MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask);
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t, uint32_t rhs_id, StorageClass, StorageClass)
|
||||
bool CompilerGLSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id, StorageClass, StorageClass)
|
||||
{
|
||||
string lhs;
|
||||
if (expr)
|
||||
lhs = expr;
|
||||
else
|
||||
lhs = to_expression(lhs_id);
|
||||
|
||||
statement(lhs, " = ", to_expression(rhs_id), ";");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompilerGLSL::unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id)
|
||||
|
@ -17773,6 +17906,11 @@ void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal)
|
|||
if (redirect_statement)
|
||||
return;
|
||||
|
||||
// If we're emitting code in a sensitive context such as condition blocks in for loops, don't emit
|
||||
// any line directives, because it's not possible.
|
||||
if (block_debug_directives)
|
||||
return;
|
||||
|
||||
if (options.emit_line_directives)
|
||||
{
|
||||
require_extension_internal("GL_GOOGLE_cpp_style_line_directive");
|
||||
|
|
|
@ -258,6 +258,10 @@ public:
|
|||
// require_extension("GL_KHR_my_extension");
|
||||
void require_extension(const std::string &ext);
|
||||
|
||||
// Returns the list of required extensions. After compilation this will contains any other
|
||||
// extensions that the compiler used automatically, in addition to the user specified ones.
|
||||
const SmallVector<std::string> &get_required_extensions() const;
|
||||
|
||||
// Legacy GLSL compatibility method.
|
||||
// Takes a uniform or push constant variable and flattens it into a (i|u)vec4 array[N]; array instead.
|
||||
// For this to work, all types in the block must be the same basic type, e.g. mixing vec2 and vec4 is fine, but
|
||||
|
@ -393,6 +397,7 @@ protected:
|
|||
};
|
||||
TemporaryCopy handle_instruction_precision(const Instruction &instr);
|
||||
void emit_block_instructions(SPIRBlock &block);
|
||||
void emit_block_instructions_with_masked_debug(SPIRBlock &block);
|
||||
|
||||
// For relax_nan_checks.
|
||||
GLSLstd450 get_remapped_glsl_op(GLSLstd450 std450_op) const;
|
||||
|
@ -426,7 +431,9 @@ protected:
|
|||
const std::string &qualifier = "", uint32_t base_offset = 0);
|
||||
virtual void emit_struct_padding_target(const SPIRType &type);
|
||||
virtual std::string image_type_glsl(const SPIRType &type, uint32_t id = 0);
|
||||
std::string constant_expression(const SPIRConstant &c, bool inside_block_like_struct_scope = false);
|
||||
std::string constant_expression(const SPIRConstant &c,
|
||||
bool inside_block_like_struct_scope = false,
|
||||
bool inside_struct_scope = false);
|
||||
virtual std::string constant_op_expression(const SPIRConstantOp &cop);
|
||||
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
|
||||
virtual void emit_fixup();
|
||||
|
@ -539,6 +546,7 @@ protected:
|
|||
SmallVector<std::string> *redirect_statement = nullptr;
|
||||
const SPIRBlock *current_continue_block = nullptr;
|
||||
bool block_temporary_hoisting = false;
|
||||
bool block_debug_directives = false;
|
||||
|
||||
void begin_scope();
|
||||
void end_scope();
|
||||
|
@ -604,6 +612,7 @@ protected:
|
|||
const char *uint16_t_literal_suffix = "us";
|
||||
const char *nonuniform_qualifier = "nonuniformEXT";
|
||||
const char *boolean_mix_function = "mix";
|
||||
SPIRType::BaseType boolean_in_struct_remapped_type = SPIRType::Boolean;
|
||||
bool swizzle_is_function = false;
|
||||
bool shared_is_implied = false;
|
||||
bool unsized_array_supported = true;
|
||||
|
@ -772,8 +781,8 @@ protected:
|
|||
void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist);
|
||||
std::string to_non_uniform_aware_expression(uint32_t id);
|
||||
std::string to_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_composite_constructor_expression(uint32_t id, bool block_like_type);
|
||||
std::string to_rerolled_array_expression(const std::string &expr, const SPIRType &type);
|
||||
std::string to_composite_constructor_expression(const SPIRType &parent_type, uint32_t id, bool block_like_type);
|
||||
std::string to_rerolled_array_expression(const SPIRType &parent_type, const std::string &expr, const SPIRType &type);
|
||||
std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_unpacked_expression(uint32_t id, bool register_expression_read = true);
|
||||
std::string to_unpacked_row_major_matrix_expression(uint32_t id);
|
||||
|
@ -806,7 +815,7 @@ protected:
|
|||
std::string layout_for_variable(const SPIRVariable &variable);
|
||||
std::string to_combined_image_sampler(VariableID image_id, VariableID samp_id);
|
||||
virtual bool skip_argument(uint32_t id) const;
|
||||
virtual void emit_array_copy(const std::string &lhs, uint32_t lhs_id, uint32_t rhs_id,
|
||||
virtual bool emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id,
|
||||
spv::StorageClass lhs_storage, spv::StorageClass rhs_storage);
|
||||
virtual void emit_block_hints(const SPIRBlock &block);
|
||||
virtual std::string to_initializer_expression(const SPIRVariable &var);
|
||||
|
|
|
@ -1467,6 +1467,7 @@ string CompilerMSL::compile()
|
|||
backend.support_small_type_sampling_result = true;
|
||||
backend.supports_empty_struct = true;
|
||||
backend.support_64bit_switch = true;
|
||||
backend.boolean_in_struct_remapped_type = SPIRType::Short;
|
||||
|
||||
// Allow Metal to use the array<T> template unless we force it off.
|
||||
backend.can_return_array = !msl_options.force_native_arrays;
|
||||
|
@ -7234,7 +7235,7 @@ void CompilerMSL::declare_constant_arrays()
|
|||
// FIXME: However, hoisting constants to main() means we need to pass down constant arrays to leaf functions if they are used there.
|
||||
// If there are multiple functions in the module, drop this case to avoid breaking use cases which do not need to
|
||||
// link into Metal libraries. This is hacky.
|
||||
if (!type.array.empty() && (!fully_inlined || is_scalar(type) || is_vector(type)))
|
||||
if (type_is_top_level_array(type) && (!fully_inlined || is_scalar(type) || is_vector(type)))
|
||||
{
|
||||
add_resource_name(c.self);
|
||||
auto name = to_name(c.self);
|
||||
|
@ -7266,7 +7267,7 @@ void CompilerMSL::declare_complex_constant_arrays()
|
|||
return;
|
||||
|
||||
auto &type = this->get<SPIRType>(c.constant_type);
|
||||
if (!type.array.empty() && !(is_scalar(type) || is_vector(type)))
|
||||
if (type_is_top_level_array(type) && !(is_scalar(type) || is_vector(type)))
|
||||
{
|
||||
add_resource_name(c.self);
|
||||
auto name = to_name(c.self);
|
||||
|
@ -7376,11 +7377,6 @@ void CompilerMSL::emit_specialization_constants_and_structs()
|
|||
string sc_type_name = type_to_glsl(type);
|
||||
add_resource_name(c.self);
|
||||
string sc_name = to_name(c.self);
|
||||
uint32_t constant_id = get_decoration(c.self, DecorationSpecId);
|
||||
if (!unique_func_constants.count(constant_id))
|
||||
unique_func_constants.insert(make_pair(constant_id, c.self));
|
||||
SPIRType::BaseType sc_tmp_type = expression_type(unique_func_constants[constant_id]).basetype;
|
||||
string sc_tmp_name = to_name(unique_func_constants[constant_id]) + "_tmp";
|
||||
|
||||
// Function constants are only supported in MSL 1.2 and later.
|
||||
// If we don't support it just declare the "default" directly.
|
||||
|
@ -7391,6 +7387,11 @@ void CompilerMSL::emit_specialization_constants_and_structs()
|
|||
!c.is_used_as_array_length)
|
||||
{
|
||||
// Only scalar, non-composite values can be function constants.
|
||||
uint32_t constant_id = get_decoration(c.self, DecorationSpecId);
|
||||
if (!unique_func_constants.count(constant_id))
|
||||
unique_func_constants.insert(make_pair(constant_id, c.self));
|
||||
SPIRType::BaseType sc_tmp_type = expression_type(unique_func_constants[constant_id]).basetype;
|
||||
string sc_tmp_name = to_name(unique_func_constants[constant_id]) + "_tmp";
|
||||
if (unique_func_constants[constant_id] == c.self)
|
||||
statement("constant ", sc_type_name, " ", sc_tmp_name, " [[function_constant(", constant_id,
|
||||
")]];");
|
||||
|
@ -9469,7 +9470,7 @@ static bool storage_class_array_is_thread(StorageClass storage)
|
|||
}
|
||||
}
|
||||
|
||||
void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t rhs_id,
|
||||
bool CompilerMSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id,
|
||||
StorageClass lhs_storage, StorageClass rhs_storage)
|
||||
{
|
||||
// Allow Metal to use the array<T> template to make arrays a value type.
|
||||
|
@ -9508,10 +9509,21 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r
|
|||
// Avoid spvCopy* wrapper functions; Otherwise, spvUnsafeArray<> template cannot be used with that storage qualifier.
|
||||
if (lhs_is_array_template && rhs_is_array_template && !using_builtin_array())
|
||||
{
|
||||
statement(lhs, " = ", to_expression(rhs_id), ";");
|
||||
// Fall back to normal copy path.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure the LHS variable has been declared
|
||||
if (lhs_var)
|
||||
flush_variable_declaration(lhs_var->self);
|
||||
|
||||
string lhs;
|
||||
if (expr)
|
||||
lhs = expr;
|
||||
else
|
||||
lhs = to_expression(lhs_id);
|
||||
|
||||
// Assignment from an array initializer is fine.
|
||||
auto &type = expression_type(rhs_id);
|
||||
auto *var = maybe_get_backing_variable(rhs_id);
|
||||
|
@ -9585,6 +9597,8 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r
|
|||
else
|
||||
statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ");");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t CompilerMSL::get_physical_tess_level_array_size(spv::BuiltIn builtin) const
|
||||
|
@ -9641,14 +9655,11 @@ bool CompilerMSL::maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs)
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure the LHS variable has been declared
|
||||
auto *p_v_lhs = maybe_get_backing_variable(id_lhs);
|
||||
if (p_v_lhs)
|
||||
flush_variable_declaration(p_v_lhs->self);
|
||||
|
||||
auto lhs_storage = get_expression_effective_storage_class(id_lhs);
|
||||
auto rhs_storage = get_expression_effective_storage_class(id_rhs);
|
||||
emit_array_copy(to_expression(id_lhs), id_lhs, id_rhs, lhs_storage, rhs_storage);
|
||||
if (!emit_array_copy(nullptr, id_lhs, id_rhs, lhs_storage, rhs_storage))
|
||||
return false;
|
||||
|
||||
register_write(id_lhs);
|
||||
|
||||
return true;
|
||||
|
@ -16784,20 +16795,31 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr,
|
|||
auto *source_expr = maybe_get<SPIRExpression>(source_id);
|
||||
auto *var = maybe_get_backing_variable(source_id);
|
||||
const SPIRType *var_type = nullptr, *phys_type = nullptr;
|
||||
|
||||
if (uint32_t phys_id = get_extended_decoration(source_id, SPIRVCrossDecorationPhysicalTypeID))
|
||||
phys_type = &get<SPIRType>(phys_id);
|
||||
else
|
||||
phys_type = &expr_type;
|
||||
|
||||
if (var)
|
||||
{
|
||||
source_id = var->self;
|
||||
var_type = &get_variable_data_type(*var);
|
||||
}
|
||||
|
||||
bool rewrite_boolean_load =
|
||||
expr_type.basetype == SPIRType::Boolean &&
|
||||
(var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct));
|
||||
|
||||
// Type fixups for workgroup variables if they are booleans.
|
||||
if (var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct) &&
|
||||
expr_type.basetype == SPIRType::Boolean)
|
||||
expr = join(type_to_glsl(expr_type), "(", expr, ")");
|
||||
if (rewrite_boolean_load)
|
||||
{
|
||||
if (type_is_top_level_array(expr_type))
|
||||
expr = to_rerolled_array_expression(expr_type, expr, expr_type);
|
||||
else
|
||||
expr = join(type_to_glsl(expr_type), "(", expr, ")");
|
||||
}
|
||||
|
||||
// Type fixups for workgroup variables if they are matrices.
|
||||
// Don't do fixup for packed types; those are handled specially.
|
||||
// FIXME: Maybe use a type like spvStorageMatrix for packed matrices?
|
||||
|
@ -16910,24 +16932,37 @@ void CompilerMSL::cast_to_variable_store(uint32_t target_id, std::string &expr,
|
|||
auto *target_expr = maybe_get<SPIRExpression>(target_id);
|
||||
auto *var = maybe_get_backing_variable(target_id);
|
||||
const SPIRType *var_type = nullptr, *phys_type = nullptr;
|
||||
|
||||
if (uint32_t phys_id = get_extended_decoration(target_id, SPIRVCrossDecorationPhysicalTypeID))
|
||||
phys_type = &get<SPIRType>(phys_id);
|
||||
else
|
||||
phys_type = &expr_type;
|
||||
|
||||
if (var)
|
||||
{
|
||||
target_id = var->self;
|
||||
var_type = &get_variable_data_type(*var);
|
||||
}
|
||||
|
||||
// Type fixups for workgroup variables if they are booleans.
|
||||
if (var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct) &&
|
||||
expr_type.basetype == SPIRType::Boolean)
|
||||
bool rewrite_boolean_store =
|
||||
expr_type.basetype == SPIRType::Boolean &&
|
||||
(var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct));
|
||||
|
||||
// Type fixups for workgroup variables or struct members if they are booleans.
|
||||
if (rewrite_boolean_store)
|
||||
{
|
||||
auto short_type = expr_type;
|
||||
short_type.basetype = SPIRType::Short;
|
||||
expr = join(type_to_glsl(short_type), "(", expr, ")");
|
||||
if (type_is_top_level_array(expr_type))
|
||||
{
|
||||
expr = to_rerolled_array_expression(*var_type, expr, expr_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto short_type = expr_type;
|
||||
short_type.basetype = SPIRType::Short;
|
||||
expr = join(type_to_glsl(short_type), "(", expr, ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Type fixups for workgroup variables if they are matrices.
|
||||
// Don't do fixup for packed types; those are handled specially.
|
||||
// FIXME: Maybe use a type like spvStorageMatrix for packed matrices?
|
||||
|
|
|
@ -1032,7 +1032,7 @@ protected:
|
|||
void add_pragma_line(const std::string &line);
|
||||
void add_typedef_line(const std::string &line);
|
||||
void emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem);
|
||||
void emit_array_copy(const std::string &lhs, uint32_t lhs_id, uint32_t rhs_id,
|
||||
bool emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id,
|
||||
spv::StorageClass lhs_storage, spv::StorageClass rhs_storage) override;
|
||||
void build_implicit_builtins();
|
||||
uint32_t build_constant_uint_array_pointer();
|
||||
|
|
Loading…
Reference in New Issue