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 0165cb2d1..c6d83c346 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 4f6b93bd2..8a4cfd982 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 5fdf98318..3690e28a8 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 3ea5f5008..e627e7f84 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 1bd6455b4..3da4a48c8 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 4fbfa6d1d..2ce5198ec 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 80d388fe8..245c43293 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 21775c465..1190a1bbf 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 6e247e930..a63615441 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 4801c803e..81af54f21 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 5ac413529..2b46c22c7 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 4fbd321c4..4c95461c8 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 797700128..7909bd8cf 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 56ee9f000..6c08c5a57 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 e9059d50d..fb5988b67 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);