From b5a3915d6cd810424c52df9e0805bc9a080b2e38 Mon Sep 17 00:00:00 2001 From: darktux Date: Wed, 10 Apr 2024 22:04:09 +0000 Subject: [PATCH] Optionally optimize generated SPIRV with spirv-opt Reviewed-on: http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/darktux/torzu/pulls/10 Co-authored-by: darktux Co-committed-by: darktux --- .gitmodules | 3 +++ CMakeLists.txt | 7 +++++ externals/CMakeLists.txt | 5 ++++ externals/SPIRV-Tools | 1 + src/shader_recompiler/CMakeLists.txt | 8 +++++- .../backend/spirv/emit_spirv.cpp | 26 +++++++++++++++++-- .../backend/spirv/emit_spirv.h | 7 ++--- .../renderer_opengl/gl_shader_cache.cpp | 6 +++-- .../renderer_vulkan/vk_pipeline_cache.cpp | 6 +++-- 9 files changed, 59 insertions(+), 10 deletions(-) create mode 160000 externals/SPIRV-Tools diff --git a/.gitmodules b/.gitmodules index af90bae67f..1a6e6574a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -64,3 +64,6 @@ [submodule "externals/sirit/externals/SPIRV-Headers"] path = externals/sirit/externals/SPIRV-Headers url = https://github.com/KhronosGroup/SPIRV-Headers.git +[submodule "externals/SPIRV-Tools"] + path = externals/SPIRV-Tools + url = https://github.com/KhronosGroup/SPIRV-Tools.git diff --git a/CMakeLists.txt b/CMakeLists.txt index c0c777bed6..3c3541aa78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,8 @@ option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON) option(YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES "Use Vulkan-Utility-Libraries from externals" ON) +option(YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS "Use SPIRV-Tools from externals" ON) + option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF) option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) @@ -329,6 +331,11 @@ if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES) find_package(VulkanUtilityLibraries REQUIRED) endif() +if (NOT YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS) + find_package(PkgConfig REQUIRED) + pkg_check_modules(SPIRV-Tools REQUIRED SPIRV-Tools) +endif() + if (ENABLE_LIBUSB) find_package(libusb 1.0.24 MODULE) endif() diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index fd3f54ae4f..2afe14a13a 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -160,6 +160,11 @@ if (YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES) add_subdirectory(Vulkan-Utility-Libraries) endif() +# SPIRV-Tools +if (YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS) + add_subdirectory(SPIRV-Tools) +endif() + # Boost headers add_subdirectory(boost-headers) diff --git a/externals/SPIRV-Tools b/externals/SPIRV-Tools new file mode 160000 index 0000000000..3983d15a1d --- /dev/null +++ b/externals/SPIRV-Tools @@ -0,0 +1 @@ +Subproject commit 3983d15a1d34fb95656818af0fc89c6260cbf316 diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 19db17c6d2..c809b220a4 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -242,7 +242,13 @@ add_library(shader_recompiler STATIC varying_state.h ) -target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit) +if (YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS) + set(SPIRV_TOOLS_LIBRARY SPIRV-Tools-opt) +else() + set(SPIRV_TOOLS_LIBRARY SPIRV-Tools SPIRV-Tools-opt) +endif() + +target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit ${SPIRV_TOOLS_LIBRARY}) if (MSVC) target_compile_options(shader_recompiler PRIVATE diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 3f9698d6bf..c3d33bb139 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "common/settings.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" @@ -481,7 +482,7 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) { } // Anonymous namespace std::vector EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, - IR::Program& program, Bindings& bindings) { + IR::Program& program, Bindings& bindings, bool optimize) { EmitContext ctx{profile, runtime_info, program, bindings}; const Id main{DefineMain(ctx, program)}; DefineEntryPoint(program, ctx, main); @@ -493,7 +494,28 @@ std::vector EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in SetupCapabilities(profile, program.info, ctx); SetupTransformFeedbackCapabilities(ctx, main); PatchPhiNodes(program, ctx); - return ctx.Assemble(); + + if (!optimize) { + return ctx.Assemble(); + } 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(); + + spvtools::OptimizerOptions opt_options; + opt_options.set_run_validator(false); + + std::vector result; + if (!spv_opt.Run(spirv.data(), spirv.size(), &result, opt_options)) { + LOG_ERROR(HW_GPU, + "Failed to optimize SPIRV shader output, continuing without optimization"); + result = std::move(spirv); + } + return result; + } } Id EmitPhi(EmitContext& ctx, IR::Inst* inst) { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 9378814840..47f88c3041 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h @@ -31,11 +31,12 @@ constexpr u32 RESCALING_LAYOUT_DOWN_FACTOR_OFFSET = offsetof(RescalingLayout, do constexpr u32 RENDERAREA_LAYOUT_OFFSET = offsetof(RenderAreaLayout, render_area); [[nodiscard]] std::vector EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, - IR::Program& program, Bindings& bindings); + IR::Program& program, Bindings& bindings, bool optimize); -[[nodiscard]] inline std::vector EmitSPIRV(const Profile& profile, IR::Program& program) { +[[nodiscard]] inline std::vector EmitSPIRV(const Profile& profile, IR::Program& program, + bool optimize) { Bindings binding; - return EmitSPIRV(profile, {}, program, binding); + return EmitSPIRV(profile, {}, program, binding, optimize); } } // namespace Shader::Backend::SPIRV diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index ba4e1ac210..1d546e3fff 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -537,7 +537,9 @@ std::unique_ptr ShaderCache::CreateGraphicsPipeline( break; case Settings::ShaderBackend::SpirV: ConvertLegacyToGeneric(program, runtime_info); - sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding); + sources_spirv[stage_index] = + EmitSPIRV(profile, runtime_info, program, binding, + Settings::values.optimize_spirv_output.GetValue()); break; } previous_program = &program; @@ -596,7 +598,7 @@ std::unique_ptr ShaderCache::CreateComputePipeline( code = EmitGLASM(profile, info, program); break; case Settings::ShaderBackend::SpirV: - code_spirv = EmitSPIRV(profile, program); + code_spirv = EmitSPIRV(profile, program, Settings::values.optimize_spirv_output.GetValue()); break; } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 51775f7f5c..e111eecdc4 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -688,7 +688,8 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)}; ConvertLegacyToGeneric(program, runtime_info); - const std::vector code{EmitSPIRV(profile, runtime_info, program, binding)}; + const std::vector code{EmitSPIRV(profile, runtime_info, program, binding, + Settings::values.optimize_spirv_output.GetValue())}; device.SaveShader(code); modules[stage_index] = BuildShader(device, code); if (device.HasDebuggingToolAttached()) { @@ -782,7 +783,8 @@ std::unique_ptr PipelineCache::CreateComputePipeline( } auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; - const std::vector code{EmitSPIRV(profile, program)}; + const std::vector code{ + EmitSPIRV(profile, program, Settings::values.optimize_spirv_output.GetValue())}; device.SaveShader(code); vk::ShaderModule spv_module{BuildShader(device, code)}; if (device.HasDebuggingToolAttached()) {