From d3e3467b86b2424649f7164595dc2746a1e3e836 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 10 Aug 2025 12:54:56 -0400 Subject: [PATCH] [spirv] improved spir-v shader opt increases speed ~tenfold for Spir-V output optimization Co-authored-by: wildcard Signed-off-by: crueter --- .../backend/spirv/emit_spirv.cpp | 57 +++++++++++++------ 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 2ea31b29f4..170acff5d7 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -22,7 +22,15 @@ namespace Shader::Backend::SPIRV { namespace { template struct FuncTraits {}; + thread_local std::unique_ptr thread_optimizer; + spvtools::Optimizer& GetThreadOptimizer() { + if (!thread_optimizer) { + thread_optimizer = std::make_unique(SPV_ENV_VULKAN_1_3); + thread_optimizer->RegisterPerformancePasses(); + } + return *thread_optimizer; + } template struct FuncTraits { using ReturnType = ReturnType_; @@ -466,27 +474,39 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct } void PatchPhiNodes(IR::Program& program, EmitContext& ctx) { - auto inst{program.blocks.front()->begin()}; - size_t block_index{0}; - ctx.PatchDeferredPhi([&](size_t phi_arg, Id parent) -> std::pair { - if (phi_arg == 0) { - ++inst; - if (inst == program.blocks[block_index]->end() || - inst->GetOpcode() != IR::Opcode::Phi) { - do { - ++block_index; - inst = program.blocks[block_index]->begin(); - } while (inst->GetOpcode() != IR::Opcode::Phi); + // Flatten all leading PHIs from each block into a vector + std::vector phi_instructions; + phi_instructions.reserve(64); // guess; adjust/remove if unneeded + for (IR::Block* block : program.blocks) { + for (auto it = block->begin(); it != block->end(); ++it) { + if (it->GetOpcode() != IR::Opcode::Phi) + break; + phi_instructions.push_back(&*it); + } } + + if (phi_instructions.empty()) { + return; // nothing to patch + } + + // Start "before" first PHI; advance on phi_arg == 0 + size_t phi_index = static_cast(-1); + + ctx.PatchDeferredPhi([&](size_t phi_arg, Id parent) -> std::pair { + if (phi_arg == 0) { + ++phi_index; + } + IR::Inst* phi = phi_instructions[phi_index]; + return { ctx.Def(phi->Arg(phi_arg)), parent }; + }); } - return {ctx.Def(inst->Arg(phi_arg)), parent}; - }); -} } // Anonymous namespace std::vector EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, Bindings& bindings, bool optimize) { EmitContext ctx{profile, runtime_info, program, bindings}; + // Reserve capacity for interfaces to reduce allocations + ctx.interfaces.reserve(16); const Id main{DefineMain(ctx, program)}; DefineEntryPoint(program, ctx, main); if (profile.support_float_controls) { @@ -503,10 +523,11 @@ std::vector EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in } else { std::vector spirv = ctx.Assemble(); - spvtools::Optimizer spv_opt(SPV_ENV_VULKAN_1_3); - spv_opt.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, - const char* m) { LOG_ERROR(HW_GPU, "spirv-opt: {}", m); }); - spv_opt.RegisterPerformancePasses(); + // Use thread-local optimizer instead of creating a new one + auto& spv_opt = GetThreadOptimizer(); + spv_opt.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, const char* m) { + LOG_ERROR(HW_GPU, "spirv-opt: {}", m); + }); spvtools::OptimizerOptions opt_options; opt_options.set_run_validator(false);