From 7e27e6476d69a83c77ea322da8981bafde16d715 Mon Sep 17 00:00:00 2001 From: echosys Date: Fri, 19 Jul 2024 19:14:19 +0000 Subject: [PATCH] Add option to only optimize SPIRV during load (#13) Adds a new option "On Load" to the "Optimize SPIRV output" option that turns on optimizations during the loading of the shader cache from disk, but turns it off after that. The previous checkbox states have been named "Never" for unchecked and "Always" for checked. The idea is that once the shader cache has most of the shaders in a game cached they can be optimized during initial game startup (where a performance hit matters less) and the few shaders that get compiled during runtime are not optimized to reduce performance hits. Most of the commit is adding the setting to the Android app, the main logic is in the `gl_shader_cache.cpp` and `vk_pipeline_cache.cpp` files. Reviewed-on: http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu/pulls/13 Co-authored-by: echosys Co-committed-by: echosys --- .../yuzu_emu/features/settings/model/IntSetting.kt | 1 + .../yuzu/yuzu_emu/features/settings/model/Settings.kt | 11 +++++++++++ .../features/settings/model/view/SettingsItem.kt | 9 +++++++++ .../features/settings/ui/SettingsFragmentPresenter.kt | 1 + src/android/app/src/main/res/values/arrays.xml | 11 +++++++++++ src/android/app/src/main/res/values/strings.xml | 6 ++++++ src/common/settings.cpp | 1 + src/common/settings.h | 9 +++++++-- src/common/settings_enums.h | 2 ++ src/video_core/renderer_opengl/gl_shader_cache.cpp | 10 +++++++--- src/video_core/renderer_opengl/gl_shader_cache.h | 1 + src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 11 +++++++---- src/video_core/renderer_vulkan/vk_pipeline_cache.h | 1 + src/yuzu/configuration/shared_translation.cpp | 6 ++++++ src/yuzu/uisettings.h | 1 + 15 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index 0165cb2d1d..c6d83c346f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -18,6 +18,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { RENDERER_ANTI_ALIASING("anti_aliasing"), RENDERER_SCREEN_LAYOUT("screen_layout"), RENDERER_ASPECT_RATIO("aspect_ratio"), + RENDERER_OPTIMIZE_SPIRV_OUTPUT("optimize_spirv_output"), AUDIO_OUTPUT_ENGINE("output_engine"), MAX_ANISOTROPY("max_anisotropy"), THEME("theme"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index 4f6b93bd2e..8a4cfd9827 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt @@ -117,4 +117,15 @@ object Settings { entries.firstOrNull { it.int == int } ?: Center } } + + enum class OptimizeSpirvOutput(val int: Int) { + Never(0), + OnLoad(1), + Always(2); + + companion object { + fun from(int: Int): OptimizeSpirvOutput = + entries.firstOrNull { it.int == int } ?: OnLoad + } + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 5fdf983185..3690e28a81 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -291,6 +291,15 @@ abstract class SettingsItem( descriptionId = R.string.renderer_force_max_clock_description ) ) + put( + SingleChoiceSetting( + IntSetting.RENDERER_OPTIMIZE_SPIRV_OUTPUT, + titleId = R.string.renderer_optimize_spirv_output, + descriptionId = 0, + choicesId = R.array.optimizeSpirvOutputEntries, + valuesId = R.array.optimizeSpirvOutputValues + ) + ) put( SwitchSetting( BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 3ea5f50081..e627e7f84f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -177,6 +177,7 @@ class SettingsFragmentPresenter( add(IntSetting.RENDERER_SCREEN_LAYOUT.key) add(IntSetting.RENDERER_ASPECT_RATIO.key) add(IntSetting.VERTICAL_ALIGNMENT.key) + add(IntSetting.RENDERER_OPTIMIZE_SPIRV_OUTPUT.key) add(BooleanSetting.PICTURE_IN_PICTURE.key) add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key) add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key) diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 1bd6455b4c..3da4a48c8b 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -303,4 +303,15 @@ 2 + + @string/never + @string/on_load + @string/always + + + 0 + 1 + 2 + + diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 4fbfa6d1d8..2ce5198eca 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -234,6 +234,7 @@ Anti-aliasing method Force maximum clocks (Adreno only) Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied). + Optimize SPIRV output Use asynchronous shaders Compiles shaders asynchronously, reducing stutter but may introduce glitches. Use reactive flushing @@ -662,6 +663,11 @@ Center Bottom + + Never + On Load + Always + Licenses FidelityFX-FSR diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 80d388fe88..245c432939 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -52,6 +52,7 @@ SWITCHABLE(NvdecEmulation, false); SWITCHABLE(Region, true); SWITCHABLE(RendererBackend, true); SWITCHABLE(ScalingFilter, false); +SWITCHABLE(SpirvOptimizeMode, true); SWITCHABLE(ShaderBackend, true); SWITCHABLE(TimeZone, true); SETTING(VSyncMode, true); diff --git a/src/common/settings.h b/src/common/settings.h index 21775c465a..1190a1bbfd 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -73,6 +73,7 @@ SWITCHABLE(NvdecEmulation, false); SWITCHABLE(Region, true); SWITCHABLE(RendererBackend, true); SWITCHABLE(ScalingFilter, false); +SWITCHABLE(SpirvOptimizeMode, true); SWITCHABLE(ShaderBackend, true); SWITCHABLE(TimeZone, true); SETTING(VSyncMode, true); @@ -278,8 +279,12 @@ struct Values { SwitchableSetting use_disk_shader_cache{linkage, true, "use_disk_shader_cache", Category::Renderer}; - SwitchableSetting optimize_spirv_output{linkage, false, "optimize_spirv_output", - Category::Renderer}; + SwitchableSetting optimize_spirv_output{linkage, + SpirvOptimizeMode::OnLoad, + SpirvOptimizeMode::Never, + SpirvOptimizeMode::Always, + "optimize_spirv_output", + Category::Renderer}; SwitchableSetting use_asynchronous_gpu_emulation{ linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer}; SwitchableSetting accelerate_astc{linkage, diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index 6e247e9306..a636154413 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -155,6 +155,8 @@ ENUM(ConsoleMode, Handheld, Docked); ENUM(AppletMode, HLE, LLE); +ENUM(SpirvOptimizeMode, Never, OnLoad, Always) + template inline std::string CanonicalizeEnum(Type id) { const auto group = EnumMetadata::Canonicalizations(); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 4801c803eb..81af54f216 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -178,6 +178,7 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, state_tracker{state_tracker_}, shader_notify{shader_notify_}, use_asynchronous_shaders{device.UseAsynchronousShaders()}, strict_context_required{device.StrictContextRequired()}, + optimize_spirv_output{Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Never}, profile{ .supported_spirv = 0x00010000, @@ -344,6 +345,10 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, if (!use_asynchronous_shaders) { workers.reset(); } + + if (Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Always) { + this->optimize_spirv_output = false; + } } GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { @@ -538,8 +543,7 @@ std::unique_ptr ShaderCache::CreateGraphicsPipeline( case Settings::ShaderBackend::SpirV: ConvertLegacyToGeneric(program, runtime_info); sources_spirv[stage_index] = - EmitSPIRV(profile, runtime_info, program, binding, - Settings::values.optimize_spirv_output.GetValue()); + EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output); break; } previous_program = &program; @@ -598,7 +602,7 @@ std::unique_ptr ShaderCache::CreateComputePipeline( code = EmitGLASM(profile, info, program); break; case Settings::ShaderBackend::SpirV: - code_spirv = EmitSPIRV(profile, program, Settings::values.optimize_spirv_output.GetValue()); + code_spirv = EmitSPIRV(profile, program, this->optimize_spirv_output); break; } diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 5ac4135295..2b46c22c70 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -73,6 +73,7 @@ private: VideoCore::ShaderNotify& shader_notify; const bool use_asynchronous_shaders; const bool strict_context_required; + bool optimize_spirv_output{}; GraphicsPipelineKey graphics_key{}; GraphicsPipeline* current_pipeline{}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 4fbd321c4b..4c95461c8a 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -310,6 +310,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, texture_cache{texture_cache_}, shader_notify{shader_notify_}, use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()}, + optimize_spirv_output{Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Never}, workers(device.HasBrokenParallelShaderCompiling() ? 1ULL : GetTotalPipelineWorkers(), "VkPipelineBuilder"), serialization_thread(1, "VkPipelineSerialization") { @@ -564,6 +565,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading if (state.statistics) { state.statistics->Report(); } + + if (Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Always) { + this->optimize_spirv_output = false; + } } GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() { @@ -673,8 +678,7 @@ 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, - Settings::values.optimize_spirv_output.GetValue())}; + const std::vector code{EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output)}; device.SaveShader(code); modules[stage_index] = BuildShader(device, code); if (device.HasDebuggingToolAttached()) { @@ -768,8 +772,7 @@ std::unique_ptr PipelineCache::CreateComputePipeline( } auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; - const std::vector code{ - EmitSPIRV(profile, program, Settings::values.optimize_spirv_output.GetValue())}; + const std::vector code{EmitSPIRV(profile, program, this->optimize_spirv_output)}; device.SaveShader(code); vk::ShaderModule spv_module{BuildShader(device, code)}; if (device.HasDebuggingToolAttached()) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 7977001280..7909bd8cf0 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -150,6 +150,7 @@ private: VideoCore::ShaderNotify& shader_notify; bool use_asynchronous_shaders{}; bool use_vulkan_pipeline_cache{}; + bool optimize_spirv_output{}; GraphicsPipelineCacheKey graphics_key{}; GraphicsPipeline* current_pipeline{}; diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 56ee9f0002..6c08c5a57d 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -319,6 +319,12 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { PAIR(AppletMode, LLE, tr("Real applet")), }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(SpirvOptimizeMode, Never, tr("Never")), + PAIR(SpirvOptimizeMode, OnLoad, tr("On Load")), + PAIR(SpirvOptimizeMode, Always, tr("Always")), + }}); translations->insert({Settings::EnumMetadata::Index(), { PAIR(AstcDecodeMode, Cpu, tr("CPU")), diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index e9059d50d1..fb5988b673 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -277,3 +277,4 @@ Q_DECLARE_METATYPE(Settings::RendererBackend); Q_DECLARE_METATYPE(Settings::ShaderBackend); Q_DECLARE_METATYPE(Settings::AstcRecompression); Q_DECLARE_METATYPE(Settings::AstcDecodeMode); +Q_DECLARE_METATYPE(Settings::SpirvOptimizeMode);