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