From f294ee6858d4091b65ab61afdef4b52ac66d416b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Sat, 21 May 2022 18:47:14 -0700 Subject: [PATCH] Updated spirv-cross. --- 3rdparty/spirv-cross/main.cpp | 12 +++ 3rdparty/spirv-cross/spirv_glsl.cpp | 112 +++++++++++++++++++++++++--- 3rdparty/spirv-cross/spirv_glsl.hpp | 2 + 3rdparty/spirv-cross/spirv_msl.cpp | 12 ++- 4 files changed, 128 insertions(+), 10 deletions(-) diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index c4ff4c4e1..521e98f96 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -1070,6 +1070,18 @@ static ExecutionModel stage_to_execution_model(const std::string &stage) return ExecutionModelTessellationEvaluation; else if (stage == "geom") return ExecutionModelGeometry; + else if (stage == "rgen") + return ExecutionModelRayGenerationKHR; + else if (stage == "rint") + return ExecutionModelIntersectionKHR; + else if (stage == "rahit") + return ExecutionModelAnyHitKHR; + else if (stage == "rchit") + return ExecutionModelClosestHitKHR; + else if (stage == "rmiss") + return ExecutionModelMissKHR; + else if (stage == "rcall") + return ExecutionModelCallableKHR; else SPIRV_CROSS_THROW("Invalid stage."); } diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 9779c3941..34020b931 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -316,6 +316,7 @@ void CompilerGLSL::reset(uint32_t iteration_count) // Clear invalid expression tracking. invalid_expressions.clear(); + composite_insert_overwritten.clear(); current_function = nullptr; // Clear temporary usage tracking. @@ -4311,7 +4312,8 @@ void CompilerGLSL::force_temporary_and_recompile(uint32_t id) uint32_t CompilerGLSL::consume_temporary_in_precision_context(uint32_t type_id, uint32_t id, Options::Precision precision) { // Constants do not have innate precision. - if (ir.ids[id].get_type() == TypeConstant || ir.ids[id].get_type() == TypeConstantOp) + auto handle_type = ir.ids[id].get_type(); + if (handle_type == TypeConstant || handle_type == TypeConstantOp || handle_type == TypeUndef) return id; // Ignore anything that isn't 32-bit values. @@ -4381,6 +4383,11 @@ void CompilerGLSL::handle_invalid_expression(uint32_t id) // This means we need another pass at compilation, but next time, // force temporary variables so that they cannot be invalidated. force_temporary_and_recompile(id); + + // If the invalid expression happened as a result of a CompositeInsert + // overwrite, we must block this from happening next iteration. + if (composite_insert_overwritten.count(id)) + block_composite_insert_overwrite.insert(id); } // Converts the format of the current expression from packed to unpacked, @@ -7100,7 +7107,7 @@ string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args) // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube. bool workaround_lod_array_shadow_as_grad = false; if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) && - is_depth_image(imgtype, tex) && args.lod) + is_depth_image(imgtype, tex) && args.lod && !args.base.is_fetch) { if (!expression_is_constant_null(args.lod)) { @@ -7244,7 +7251,7 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube. bool workaround_lod_array_shadow_as_grad = ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) && - is_depth_image(imgtype, img) && args.lod != 0; + is_depth_image(imgtype, img) && args.lod != 0 && !args.base.is_fetch; if (args.dref) { @@ -10309,7 +10316,9 @@ CompilerGLSL::Options::Precision CompilerGLSL::analyze_expression_precision(cons for (uint32_t i = 0; i < length; i++) { uint32_t arg = args[i]; - if (ir.ids[arg].get_type() == TypeConstant) + + auto handle_type = ir.ids[arg].get_type(); + if (handle_type == TypeConstant || handle_type == TypeConstantOp || handle_type == TypeUndef) continue; if (has_decoration(arg, DecorationRelaxedPrecision)) @@ -11105,11 +11114,61 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) flush_variable_declaration(composite); - // Make a copy, then use access chain to store the variable. - statement(declare_temporary(result_type, id), to_expression(composite), ";"); - set(id, to_name(id), result_type, true); - auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr); - statement(chain, " = ", to_unpacked_expression(obj), ";"); + // CompositeInsert requires a copy + modification, but this is very awkward code in HLL. + // Speculate that the input composite is no longer used, and we can modify it in-place. + // There are various scenarios where this is not possible to satisfy. + bool can_modify_in_place = true; + forced_temporaries.insert(id); + + // Cannot safely RMW PHI variables since they have no way to be invalidated, + // forcing temporaries is not going to help. + // This is similar for Constant and Undef inputs. + // The only safe thing to RMW is SPIRExpression. + if (invalid_expressions.count(composite) || + block_composite_insert_overwrite.count(composite) || + maybe_get(composite) == nullptr) + { + can_modify_in_place = false; + } + else if (backend.requires_relaxed_precision_analysis && + has_decoration(composite, DecorationRelaxedPrecision) != + has_decoration(id, DecorationRelaxedPrecision) && + get(result_type).basetype != SPIRType::Struct) + { + // Similarly, if precision does not match for input and output, + // we cannot alias them. If we write a composite into a relaxed precision + // ID, we might get a false truncation. + can_modify_in_place = false; + } + + if (can_modify_in_place) + { + // Have to make sure the modified SSA value is bound to a temporary so we can modify it in-place. + if (!forced_temporaries.count(composite)) + force_temporary_and_recompile(composite); + + auto chain = access_chain_internal(composite, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr); + statement(chain, " = ", to_unpacked_expression(obj), ";"); + set(id, to_expression(composite), result_type, true); + invalid_expressions.insert(composite); + composite_insert_overwritten.insert(composite); + } + else + { + if (maybe_get(composite) != nullptr) + { + emit_uninitialized_temporary_expression(result_type, id); + } + else + { + // Make a copy, then use access chain to store the variable. + statement(declare_temporary(result_type, id), to_expression(composite), ";"); + set(id, to_name(id), result_type, true); + } + + auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr); + statement(chain, " = ", to_unpacked_expression(obj), ";"); + } break; } @@ -15704,8 +15763,43 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) break; case SPIRBlock::Unreachable: + { + // Avoid emitting false fallthrough, which can happen for + // if (cond) break; else discard; inside a case label. + // Discard is not always implementable as a terminator. + + auto &cfg = get_cfg_for_current_function(); + bool inner_dominator_is_switch = false; + ID id = block.self; + + while (id) + { + auto &iter_block = get(id); + if (iter_block.terminator == SPIRBlock::MultiSelect || + iter_block.merge == SPIRBlock::MergeLoop) + { + ID next_block = iter_block.merge == SPIRBlock::MergeLoop ? + iter_block.merge_block : iter_block.next_block; + bool outside_construct = next_block && cfg.find_common_dominator(next_block, block.self) == next_block; + if (!outside_construct) + { + inner_dominator_is_switch = iter_block.terminator == SPIRBlock::MultiSelect; + break; + } + } + + if (cfg.get_preceding_edges(id).empty()) + break; + + id = cfg.get_immediate_dominator(id); + } + + if (inner_dominator_is_switch) + statement("break; // unreachable workaround"); + emit_next_block = false; break; + } case SPIRBlock::IgnoreIntersection: statement("ignoreIntersectionEXT;"); diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index 8d1c71318..c4396991e 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -915,6 +915,8 @@ protected: uint32_t consume_temporary_in_precision_context(uint32_t type_id, uint32_t id, Options::Precision precision); std::unordered_map temporary_to_mirror_precision_alias; + std::unordered_set composite_insert_overwritten; + std::unordered_set block_composite_insert_overwrite; std::string emit_for_loop_initializers(const SPIRBlock &block); void emit_while_loop_initializers(const SPIRBlock &block); diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index cb6eac92f..22ab19006 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -15685,9 +15685,19 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr, if (var && var->storage == StorageClassWorkgroup && expr_type.basetype == SPIRType::Boolean) expr = join(type_to_glsl(expr_type), "(", expr, ")"); - // Only interested in standalone builtin variables. + // Only interested in standalone builtin variables in the switch below. if (!has_decoration(source_id, DecorationBuiltIn)) + { + // If the backing variable does not match our expected sign, we can fix it up here. + // See ensure_correct_input_type(). + if (var && var->storage == StorageClassInput) + { + auto &base_type = get(var->basetype); + if (base_type.basetype != SPIRType::Struct && expr_type.basetype != base_type.basetype) + expr = join(type_to_glsl(expr_type), "(", expr, ")"); + } return; + } auto builtin = static_cast(get_decoration(source_id, DecorationBuiltIn)); auto expected_type = expr_type.basetype;