[spirv] improved spir-v shader opt (#239)

increases speed ~tenfold for Spir-V output optimization when using it on load.

Co-authored-by: wildcard <nubieluv@gmail.com>
Signed-off-by: crueter <crueter@eden-emu.dev>

Co-authored-by: wildcard <nubieluv@gmail.com>
Reviewed-on: #239
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
This commit is contained in:
crueter 2025-08-15 21:40:41 +02:00
parent 72fb15cacc
commit 09a8fab2a2
Signed by: crueter
GPG key ID: 425ACD2D4830EBC6

View file

@ -22,7 +22,15 @@ namespace Shader::Backend::SPIRV {
namespace { namespace {
template <class Func> template <class Func>
struct FuncTraits {}; struct FuncTraits {};
thread_local std::unique_ptr<spvtools::Optimizer> thread_optimizer;
spvtools::Optimizer& GetThreadOptimizer() {
if (!thread_optimizer) {
thread_optimizer = std::make_unique<spvtools::Optimizer>(SPV_ENV_VULKAN_1_3);
thread_optimizer->RegisterPerformancePasses();
}
return *thread_optimizer;
}
template <class ReturnType_, class... Args> template <class ReturnType_, class... Args>
struct FuncTraits<ReturnType_ (*)(Args...)> { struct FuncTraits<ReturnType_ (*)(Args...)> {
using ReturnType = ReturnType_; using ReturnType = ReturnType_;
@ -466,22 +474,31 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
} }
void PatchPhiNodes(IR::Program& program, EmitContext& ctx) { void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
auto inst{program.blocks.front()->begin()}; // Flatten all leading PHIs from each block into a vector
size_t block_index{0}; std::vector<IR::Inst*> phi_instructions;
ctx.PatchDeferredPhi([&](size_t phi_arg, Id parent) -> std::pair<Id, Id> { for (IR::Block* block : program.blocks) {
if (phi_arg == 0) { for (auto it = block->begin(); it != block->end(); ++it) {
++inst; if (it->GetOpcode() != IR::Opcode::Phi)
if (inst == program.blocks[block_index]->end() || break;
inst->GetOpcode() != IR::Opcode::Phi) { phi_instructions.push_back(&*it);
do { }
++block_index;
inst = program.blocks[block_index]->begin();
} while (inst->GetOpcode() != IR::Opcode::Phi);
} }
if (phi_instructions.empty()) {
return; // nothing to patch
}
// Start "before" first PHI; advance on phi_arg == 0
size_t phi_index = static_cast<size_t>(-1);
ctx.PatchDeferredPhi([&](size_t phi_arg, Id parent) -> std::pair<Id, Id> {
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 } // Anonymous namespace
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
@ -503,10 +520,11 @@ std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in
} else { } else {
std::vector<u32> spirv = ctx.Assemble(); std::vector<u32> spirv = ctx.Assemble();
spvtools::Optimizer spv_opt(SPV_ENV_VULKAN_1_3); // Use thread-local optimizer instead of creating a new one
spv_opt.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, auto& spv_opt = GetThreadOptimizer();
const char* m) { LOG_ERROR(HW_GPU, "spirv-opt: {}", m); }); spv_opt.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
spv_opt.RegisterPerformancePasses(); LOG_ERROR(HW_GPU, "spirv-opt: {}", m);
});
spvtools::OptimizerOptions opt_options; spvtools::OptimizerOptions opt_options;
opt_options.set_run_validator(false); opt_options.set_run_validator(false);