diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index b430ec810..81db89ce0 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -1348,6 +1348,10 @@ static string compile_iteration(const CLIArguments &args, std::vector build_dummy_sampler = true; } + // If we're explicitly renaming, we probably want that name to be output. + if (!args.entry_point_rename.empty()) + hlsl_opts.use_entry_point_name = true; + hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base; hlsl_opts.force_storage_buffer_as_uav = args.hlsl_force_storage_buffer_as_uav; hlsl_opts.nonwritable_uav_texture_as_srv = args.hlsl_nonwritable_uav_texture_as_srv; diff --git a/3rdparty/spirv-cross/spirv_cfg.hpp b/3rdparty/spirv-cross/spirv_cfg.hpp index 90973b567..1d85fe0a9 100644 --- a/3rdparty/spirv-cross/spirv_cfg.hpp +++ b/3rdparty/spirv-cross/spirv_cfg.hpp @@ -59,6 +59,11 @@ public: return 0; } + bool is_reachable(uint32_t block) const + { + return visit_order.count(block) != 0; + } + uint32_t get_visit_order(uint32_t block) const { auto itr = visit_order.find(block); diff --git a/3rdparty/spirv-cross/spirv_cross.cpp b/3rdparty/spirv-cross/spirv_cross.cpp index 5463e9cda..050c875e8 100644 --- a/3rdparty/spirv-cross/spirv_cross.cpp +++ b/3rdparty/spirv-cross/spirv_cross.cpp @@ -3744,6 +3744,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA DominatorBuilder builder(cfg); auto &blocks = var.second; auto &type = expression_type(var.first); + BlockID potential_continue_block = 0; // Figure out which block is dominating all accesses of those variables. for (auto &block : blocks) @@ -3765,14 +3766,13 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA { // The variable is used in multiple continue blocks, this is not a loop // candidate, signal that by setting block to -1u. - auto &potential = potential_loop_variables[var.first]; - - if (potential == 0) - potential = block; + if (potential_continue_block == 0) + potential_continue_block = block; else - potential = ~(0u); + potential_continue_block = ~(0u); } } + builder.add_block(block); } @@ -3781,6 +3781,34 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA // Add it to a per-block list of variables. BlockID dominating_block = builder.get_dominator(); + if (dominating_block && potential_continue_block != 0 && potential_continue_block != ~0u) + { + auto &inner_block = get(dominating_block); + + BlockID merge_candidate = 0; + + // Analyze the dominator. If it lives in a different loop scope than the candidate continue + // block, reject the loop variable candidate. + if (inner_block.merge == SPIRBlock::MergeLoop) + merge_candidate = inner_block.merge_block; + else if (inner_block.loop_dominator != SPIRBlock::NoDominator) + merge_candidate = get(inner_block.loop_dominator).merge_block; + + if (merge_candidate != 0 && cfg.is_reachable(merge_candidate)) + { + // If the merge block has a higher post-visit order, we know that continue candidate + // cannot reach the merge block, and we have two separate scopes. + if (!cfg.is_reachable(potential_continue_block) || + cfg.get_visit_order(merge_candidate) > cfg.get_visit_order(potential_continue_block)) + { + potential_continue_block = 0; + } + } + } + + if (potential_continue_block != 0 && potential_continue_block != ~0u) + potential_loop_variables[var.first] = potential_continue_block; + // For variables whose dominating block is inside a loop, there is a risk that these variables // actually need to be preserved across loop iterations. We can express this by adding // a "read" access to the loop header. diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 9936c404d..f47ac62a7 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -327,6 +327,8 @@ void CompilerGLSL::reset(uint32_t iteration_count) // Ensure that we declare phi-variable copies even if the original declaration isn't deferred flushed_phi_variables.clear(); + current_emitting_switch_stack.clear(); + reset_name_caches(); ir.for_each_typed_id([&](uint32_t, SPIRFunction &func) { @@ -14895,21 +14897,32 @@ void CompilerGLSL::branch(BlockID from, BlockID to) // - Break merge target all at once ... // Very dirty workaround. - // Switch constructs are able to break, but they cannot break out of a loop at the same time. + // Switch constructs are able to break, but they cannot break out of a loop at the same time, + // yet SPIR-V allows it. // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block, // write to the ladder here, and defer the break. // The loop we're breaking out of must dominate the switch block, or there is no ladder breaking case. - if (current_emitting_switch && is_loop_break(to) && - current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) && - get(current_emitting_switch->loop_dominator).merge_block == to) + if (is_loop_break(to)) { - if (!current_emitting_switch->need_ladder_break) + for (size_t n = current_emitting_switch_stack.size(); n; n--) { - force_recompile(); - current_emitting_switch->need_ladder_break = true; - } + auto *current_emitting_switch = current_emitting_switch_stack[n - 1]; - statement("_", current_emitting_switch->self, "_ladder_break = true;"); + if (current_emitting_switch && + current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) && + get(current_emitting_switch->loop_dominator).merge_block == to) + { + if (!current_emitting_switch->need_ladder_break) + { + force_recompile(); + current_emitting_switch->need_ladder_break = true; + } + + statement("_", current_emitting_switch->self, "_ladder_break = true;"); + } + else + break; + } } statement("break;"); } @@ -15594,8 +15607,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) else if (type.basetype == SPIRType::Short) label_suffix = backend.int16_t_literal_suffix; - SPIRBlock *old_emitting_switch = current_emitting_switch; - current_emitting_switch = █ + current_emitting_switch_stack.push_back(&block); if (block.need_ladder_break) statement("bool _", block.self, "_ladder_break = false;"); @@ -15880,7 +15892,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) end_scope(); } - current_emitting_switch = old_emitting_switch; + current_emitting_switch_stack.pop_back(); break; } diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index dc693787c..a798737cf 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -364,7 +364,7 @@ protected: virtual void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags); SPIRBlock *current_emitting_block = nullptr; - SPIRBlock *current_emitting_switch = nullptr; + SmallVector current_emitting_switch_stack; bool current_emitting_switch_fallthrough = false; virtual void emit_instruction(const Instruction &instr); diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index c5a37d2c1..919727d7a 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -2404,12 +2404,32 @@ string CompilerHLSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32 return arg_str; } +string CompilerHLSL::get_inner_entry_point_name() const +{ + auto &execution = get_entry_point(); + + if (hlsl_options.use_entry_point_name) + { + auto name = join(execution.name, "_inner"); + ParsedIR::sanitize_underscores(name); + return name; + } + + if (execution.model == ExecutionModelVertex) + return "vert_main"; + else if (execution.model == ExecutionModelFragment) + return "frag_main"; + else if (execution.model == ExecutionModelGLCompute) + return "comp_main"; + else + SPIRV_CROSS_THROW("Unsupported execution model."); +} + void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) { if (func.self != ir.default_entry_point) add_function_overload(func); - auto &execution = get_entry_point(); // Avoid shadow declarations. local_variable_names = resource_names; @@ -2430,14 +2450,7 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret if (func.self == ir.default_entry_point) { - if (execution.model == ExecutionModelVertex) - decl += "vert_main"; - else if (execution.model == ExecutionModelFragment) - decl += "frag_main"; - else if (execution.model == ExecutionModelGLCompute) - decl += "comp_main"; - else - SPIRV_CROSS_THROW("Unsupported execution model."); + decl += get_inner_entry_point_name(); processing_entry_point = true; } else @@ -2555,7 +2568,13 @@ void CompilerHLSL::emit_hlsl_entry_point() break; } - statement(require_output ? "SPIRV_Cross_Output " : "void ", "main(", merge(arguments), ")"); + const char *entry_point_name; + if (hlsl_options.use_entry_point_name) + entry_point_name = get_entry_point().name.c_str(); + else + entry_point_name = "main"; + + statement(require_output ? "SPIRV_Cross_Output " : "void ", entry_point_name, "(", merge(arguments), ")"); begin_scope(); bool legacy = hlsl_options.shader_model <= 30; @@ -2728,12 +2747,12 @@ void CompilerHLSL::emit_hlsl_entry_point() }); // Run the shader. - if (execution.model == ExecutionModelVertex) - statement("vert_main();"); - else if (execution.model == ExecutionModelFragment) - statement("frag_main();"); - else if (execution.model == ExecutionModelGLCompute) - statement("comp_main();"); + if (execution.model == ExecutionModelVertex || + execution.model == ExecutionModelFragment || + execution.model == ExecutionModelGLCompute) + { + statement(get_inner_entry_point_name(), "();"); + } else SPIRV_CROSS_THROW("Unsupported shader stage."); @@ -4728,9 +4747,9 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i) case OpGroupNonUniformBallotBitCount: { auto operation = static_cast(ops[3]); + bool forward = should_forward(ops[4]); if (operation == GroupOperationReduce) { - bool forward = should_forward(ops[4]); auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x) + countbits(", to_enclosed_expression(ops[4]), ".y)"); auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z) + countbits(", @@ -4739,9 +4758,31 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i) inherit_expression_dependencies(id, ops[4]); } else if (operation == GroupOperationInclusiveScan) - SPIRV_CROSS_THROW("Cannot trivially implement BallotBitCount Inclusive Scan in HLSL."); + { + auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x & gl_SubgroupLeMask.x) + countbits(", + to_enclosed_expression(ops[4]), ".y & gl_SubgroupLeMask.y)"); + auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z & gl_SubgroupLeMask.z) + countbits(", + to_enclosed_expression(ops[4]), ".w & gl_SubgroupLeMask.w)"); + emit_op(result_type, id, join(left, " + ", right), forward); + if (!active_input_builtins.get(BuiltInSubgroupLeMask)) + { + active_input_builtins.set(BuiltInSubgroupLeMask); + force_recompile_guarantee_forward_progress(); + } + } else if (operation == GroupOperationExclusiveScan) - SPIRV_CROSS_THROW("Cannot trivially implement BallotBitCount Exclusive Scan in HLSL."); + { + auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x & gl_SubgroupLtMask.x) + countbits(", + to_enclosed_expression(ops[4]), ".y & gl_SubgroupLtMask.y)"); + auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z & gl_SubgroupLtMask.z) + countbits(", + to_enclosed_expression(ops[4]), ".w & gl_SubgroupLtMask.w)"); + emit_op(result_type, id, join(left, " + ", right), forward); + if (!active_input_builtins.get(BuiltInSubgroupLtMask)) + { + active_input_builtins.set(BuiltInSubgroupLtMask); + force_recompile_guarantee_forward_progress(); + } + } else SPIRV_CROSS_THROW("Invalid BitCount operation."); break; diff --git a/3rdparty/spirv-cross/spirv_hlsl.hpp b/3rdparty/spirv-cross/spirv_hlsl.hpp index 23b97f112..f01bcf96f 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.hpp +++ b/3rdparty/spirv-cross/spirv_hlsl.hpp @@ -137,6 +137,9 @@ public: // If add_vertex_attribute_remap is used and this feature is used, // the semantic name will be queried once per active location. bool flatten_matrix_vertex_input_semantics = false; + + // Rather than emitting main() for the entry point, use the name in SPIR-V. + bool use_entry_point_name = false; }; explicit CompilerHLSL(std::vector spirv_) @@ -374,6 +377,8 @@ private: bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override; std::vector composite_selection_workaround_types; + + std::string get_inner_entry_point_name() const; }; } // namespace SPIRV_CROSS_NAMESPACE diff --git a/3rdparty/spirv-cross/spirv_parser.cpp b/3rdparty/spirv-cross/spirv_parser.cpp index 262aa70ff..c290a5ebb 100644 --- a/3rdparty/spirv-cross/spirv_parser.cpp +++ b/3rdparty/spirv-cross/spirv_parser.cpp @@ -1020,7 +1020,16 @@ void Parser::parse(const Instruction &instruction) } else { - ir.block_meta[current_block->next_block] &= ~ParsedIR::BLOCK_META_SELECTION_MERGE_BIT; + // Collapse loops if we have to. + bool collapsed_loop = current_block->true_block == current_block->merge_block && + current_block->merge == SPIRBlock::MergeLoop; + + if (collapsed_loop) + { + ir.block_meta[current_block->merge_block] &= ~ParsedIR::BLOCK_META_LOOP_MERGE_BIT; + ir.block_meta[current_block->continue_block] &= ~ParsedIR::BLOCK_META_CONTINUE_BIT; + } + current_block->next_block = current_block->true_block; current_block->condition = 0; current_block->true_block = 0;