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);