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 <echosys@noreply.localhost> Co-committed-by: echosys <echosys@noreply.localhost>
This commit is contained in:
parent
224ec03070
commit
7e27e6476d
15 changed files with 72 additions and 9 deletions
|
@ -18,6 +18,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||||
RENDERER_ANTI_ALIASING("anti_aliasing"),
|
RENDERER_ANTI_ALIASING("anti_aliasing"),
|
||||||
RENDERER_SCREEN_LAYOUT("screen_layout"),
|
RENDERER_SCREEN_LAYOUT("screen_layout"),
|
||||||
RENDERER_ASPECT_RATIO("aspect_ratio"),
|
RENDERER_ASPECT_RATIO("aspect_ratio"),
|
||||||
|
RENDERER_OPTIMIZE_SPIRV_OUTPUT("optimize_spirv_output"),
|
||||||
AUDIO_OUTPUT_ENGINE("output_engine"),
|
AUDIO_OUTPUT_ENGINE("output_engine"),
|
||||||
MAX_ANISOTROPY("max_anisotropy"),
|
MAX_ANISOTROPY("max_anisotropy"),
|
||||||
THEME("theme"),
|
THEME("theme"),
|
||||||
|
|
|
@ -117,4 +117,15 @@ object Settings {
|
||||||
entries.firstOrNull { it.int == int } ?: Center
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,6 +291,15 @@ abstract class SettingsItem(
|
||||||
descriptionId = R.string.renderer_force_max_clock_description
|
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(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS,
|
BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS,
|
||||||
|
|
|
@ -177,6 +177,7 @@ class SettingsFragmentPresenter(
|
||||||
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
||||||
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
||||||
add(IntSetting.VERTICAL_ALIGNMENT.key)
|
add(IntSetting.VERTICAL_ALIGNMENT.key)
|
||||||
|
add(IntSetting.RENDERER_OPTIMIZE_SPIRV_OUTPUT.key)
|
||||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||||
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
||||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||||
|
|
|
@ -303,4 +303,15 @@
|
||||||
<item>2</item>
|
<item>2</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
|
<string-array name="optimizeSpirvOutputEntries">
|
||||||
|
<item>@string/never</item>
|
||||||
|
<item>@string/on_load</item>
|
||||||
|
<item>@string/always</item>
|
||||||
|
</string-array>
|
||||||
|
<integer-array name="optimizeSpirvOutputValues">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
</integer-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -234,6 +234,7 @@
|
||||||
<string name="renderer_anti_aliasing">Anti-aliasing method</string>
|
<string name="renderer_anti_aliasing">Anti-aliasing method</string>
|
||||||
<string name="renderer_force_max_clock">Force maximum clocks (Adreno only)</string>
|
<string name="renderer_force_max_clock">Force maximum clocks (Adreno only)</string>
|
||||||
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
|
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
|
||||||
|
<string name="renderer_optimize_spirv_output">Optimize SPIRV output</string>
|
||||||
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
||||||
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, reducing stutter but may introduce glitches.</string>
|
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, reducing stutter but may introduce glitches.</string>
|
||||||
<string name="renderer_reactive_flushing">Use reactive flushing</string>
|
<string name="renderer_reactive_flushing">Use reactive flushing</string>
|
||||||
|
@ -662,6 +663,11 @@
|
||||||
<string name="center">Center</string>
|
<string name="center">Center</string>
|
||||||
<string name="bottom">Bottom</string>
|
<string name="bottom">Bottom</string>
|
||||||
|
|
||||||
|
<!-- Optimize SPIRV output -->
|
||||||
|
<string name="never">Never</string>
|
||||||
|
<string name="on_load">On Load</string>
|
||||||
|
<string name="always">Always</string>
|
||||||
|
|
||||||
<!-- Licenses screen strings -->
|
<!-- Licenses screen strings -->
|
||||||
<string name="licenses">Licenses</string>
|
<string name="licenses">Licenses</string>
|
||||||
<string name="license_fidelityfx_fsr" translatable="false">FidelityFX-FSR</string>
|
<string name="license_fidelityfx_fsr" translatable="false">FidelityFX-FSR</string>
|
||||||
|
|
|
@ -52,6 +52,7 @@ SWITCHABLE(NvdecEmulation, false);
|
||||||
SWITCHABLE(Region, true);
|
SWITCHABLE(Region, true);
|
||||||
SWITCHABLE(RendererBackend, true);
|
SWITCHABLE(RendererBackend, true);
|
||||||
SWITCHABLE(ScalingFilter, false);
|
SWITCHABLE(ScalingFilter, false);
|
||||||
|
SWITCHABLE(SpirvOptimizeMode, true);
|
||||||
SWITCHABLE(ShaderBackend, true);
|
SWITCHABLE(ShaderBackend, true);
|
||||||
SWITCHABLE(TimeZone, true);
|
SWITCHABLE(TimeZone, true);
|
||||||
SETTING(VSyncMode, true);
|
SETTING(VSyncMode, true);
|
||||||
|
|
|
@ -73,6 +73,7 @@ SWITCHABLE(NvdecEmulation, false);
|
||||||
SWITCHABLE(Region, true);
|
SWITCHABLE(Region, true);
|
||||||
SWITCHABLE(RendererBackend, true);
|
SWITCHABLE(RendererBackend, true);
|
||||||
SWITCHABLE(ScalingFilter, false);
|
SWITCHABLE(ScalingFilter, false);
|
||||||
|
SWITCHABLE(SpirvOptimizeMode, true);
|
||||||
SWITCHABLE(ShaderBackend, true);
|
SWITCHABLE(ShaderBackend, true);
|
||||||
SWITCHABLE(TimeZone, true);
|
SWITCHABLE(TimeZone, true);
|
||||||
SETTING(VSyncMode, true);
|
SETTING(VSyncMode, true);
|
||||||
|
@ -278,7 +279,11 @@ struct Values {
|
||||||
|
|
||||||
SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
|
SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
|
||||||
Category::Renderer};
|
Category::Renderer};
|
||||||
SwitchableSetting<bool> optimize_spirv_output{linkage, false, "optimize_spirv_output",
|
SwitchableSetting<SpirvOptimizeMode, true> optimize_spirv_output{linkage,
|
||||||
|
SpirvOptimizeMode::OnLoad,
|
||||||
|
SpirvOptimizeMode::Never,
|
||||||
|
SpirvOptimizeMode::Always,
|
||||||
|
"optimize_spirv_output",
|
||||||
Category::Renderer};
|
Category::Renderer};
|
||||||
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
|
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
|
||||||
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
|
linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
|
||||||
|
|
|
@ -155,6 +155,8 @@ ENUM(ConsoleMode, Handheld, Docked);
|
||||||
|
|
||||||
ENUM(AppletMode, HLE, LLE);
|
ENUM(AppletMode, HLE, LLE);
|
||||||
|
|
||||||
|
ENUM(SpirvOptimizeMode, Never, OnLoad, Always)
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
inline std::string CanonicalizeEnum(Type id) {
|
inline std::string CanonicalizeEnum(Type id) {
|
||||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||||
|
|
|
@ -178,6 +178,7 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||||
state_tracker{state_tracker_}, shader_notify{shader_notify_},
|
state_tracker{state_tracker_}, shader_notify{shader_notify_},
|
||||||
use_asynchronous_shaders{device.UseAsynchronousShaders()},
|
use_asynchronous_shaders{device.UseAsynchronousShaders()},
|
||||||
strict_context_required{device.StrictContextRequired()},
|
strict_context_required{device.StrictContextRequired()},
|
||||||
|
optimize_spirv_output{Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Never},
|
||||||
profile{
|
profile{
|
||||||
.supported_spirv = 0x00010000,
|
.supported_spirv = 0x00010000,
|
||||||
|
|
||||||
|
@ -344,6 +345,10 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
|
||||||
if (!use_asynchronous_shaders) {
|
if (!use_asynchronous_shaders) {
|
||||||
workers.reset();
|
workers.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Always) {
|
||||||
|
this->optimize_spirv_output = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() {
|
GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() {
|
||||||
|
@ -538,8 +543,7 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||||
case Settings::ShaderBackend::SpirV:
|
case Settings::ShaderBackend::SpirV:
|
||||||
ConvertLegacyToGeneric(program, runtime_info);
|
ConvertLegacyToGeneric(program, runtime_info);
|
||||||
sources_spirv[stage_index] =
|
sources_spirv[stage_index] =
|
||||||
EmitSPIRV(profile, runtime_info, program, binding,
|
EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output);
|
||||||
Settings::values.optimize_spirv_output.GetValue());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
previous_program = &program;
|
previous_program = &program;
|
||||||
|
@ -598,7 +602,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||||
code = EmitGLASM(profile, info, program);
|
code = EmitGLASM(profile, info, program);
|
||||||
break;
|
break;
|
||||||
case Settings::ShaderBackend::SpirV:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ private:
|
||||||
VideoCore::ShaderNotify& shader_notify;
|
VideoCore::ShaderNotify& shader_notify;
|
||||||
const bool use_asynchronous_shaders;
|
const bool use_asynchronous_shaders;
|
||||||
const bool strict_context_required;
|
const bool strict_context_required;
|
||||||
|
bool optimize_spirv_output{};
|
||||||
|
|
||||||
GraphicsPipelineKey graphics_key{};
|
GraphicsPipelineKey graphics_key{};
|
||||||
GraphicsPipeline* current_pipeline{};
|
GraphicsPipeline* current_pipeline{};
|
||||||
|
|
|
@ -310,6 +310,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||||
texture_cache{texture_cache_}, shader_notify{shader_notify_},
|
texture_cache{texture_cache_}, shader_notify{shader_notify_},
|
||||||
use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
|
use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
|
||||||
use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.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(),
|
workers(device.HasBrokenParallelShaderCompiling() ? 1ULL : GetTotalPipelineWorkers(),
|
||||||
"VkPipelineBuilder"),
|
"VkPipelineBuilder"),
|
||||||
serialization_thread(1, "VkPipelineSerialization") {
|
serialization_thread(1, "VkPipelineSerialization") {
|
||||||
|
@ -564,6 +565,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
|
||||||
if (state.statistics) {
|
if (state.statistics) {
|
||||||
state.statistics->Report();
|
state.statistics->Report();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings::values.optimize_spirv_output.GetValue() != Settings::SpirvOptimizeMode::Always) {
|
||||||
|
this->optimize_spirv_output = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() {
|
GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() {
|
||||||
|
@ -673,8 +678,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||||
|
|
||||||
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
|
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
|
||||||
ConvertLegacyToGeneric(program, runtime_info);
|
ConvertLegacyToGeneric(program, runtime_info);
|
||||||
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding,
|
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding, this->optimize_spirv_output)};
|
||||||
Settings::values.optimize_spirv_output.GetValue())};
|
|
||||||
device.SaveShader(code);
|
device.SaveShader(code);
|
||||||
modules[stage_index] = BuildShader(device, code);
|
modules[stage_index] = BuildShader(device, code);
|
||||||
if (device.HasDebuggingToolAttached()) {
|
if (device.HasDebuggingToolAttached()) {
|
||||||
|
@ -768,8 +772,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
||||||
const std::vector<u32> code{
|
const std::vector<u32> code{EmitSPIRV(profile, program, this->optimize_spirv_output)};
|
||||||
EmitSPIRV(profile, program, Settings::values.optimize_spirv_output.GetValue())};
|
|
||||||
device.SaveShader(code);
|
device.SaveShader(code);
|
||||||
vk::ShaderModule spv_module{BuildShader(device, code)};
|
vk::ShaderModule spv_module{BuildShader(device, code)};
|
||||||
if (device.HasDebuggingToolAttached()) {
|
if (device.HasDebuggingToolAttached()) {
|
||||||
|
|
|
@ -150,6 +150,7 @@ private:
|
||||||
VideoCore::ShaderNotify& shader_notify;
|
VideoCore::ShaderNotify& shader_notify;
|
||||||
bool use_asynchronous_shaders{};
|
bool use_asynchronous_shaders{};
|
||||||
bool use_vulkan_pipeline_cache{};
|
bool use_vulkan_pipeline_cache{};
|
||||||
|
bool optimize_spirv_output{};
|
||||||
|
|
||||||
GraphicsPipelineCacheKey graphics_key{};
|
GraphicsPipelineCacheKey graphics_key{};
|
||||||
GraphicsPipeline* current_pipeline{};
|
GraphicsPipeline* current_pipeline{};
|
||||||
|
|
|
@ -319,6 +319,12 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
||||||
PAIR(AppletMode, LLE, tr("Real applet")),
|
PAIR(AppletMode, LLE, tr("Real applet")),
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
translations->insert({Settings::EnumMetadata<Settings::SpirvOptimizeMode>::Index(),
|
||||||
|
{
|
||||||
|
PAIR(SpirvOptimizeMode, Never, tr("Never")),
|
||||||
|
PAIR(SpirvOptimizeMode, OnLoad, tr("On Load")),
|
||||||
|
PAIR(SpirvOptimizeMode, Always, tr("Always")),
|
||||||
|
}});
|
||||||
translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),
|
||||||
{
|
{
|
||||||
PAIR(AstcDecodeMode, Cpu, tr("CPU")),
|
PAIR(AstcDecodeMode, Cpu, tr("CPU")),
|
||||||
|
|
|
@ -277,3 +277,4 @@ Q_DECLARE_METATYPE(Settings::RendererBackend);
|
||||||
Q_DECLARE_METATYPE(Settings::ShaderBackend);
|
Q_DECLARE_METATYPE(Settings::ShaderBackend);
|
||||||
Q_DECLARE_METATYPE(Settings::AstcRecompression);
|
Q_DECLARE_METATYPE(Settings::AstcRecompression);
|
||||||
Q_DECLARE_METATYPE(Settings::AstcDecodeMode);
|
Q_DECLARE_METATYPE(Settings::AstcDecodeMode);
|
||||||
|
Q_DECLARE_METATYPE(Settings::SpirvOptimizeMode);
|
||||||
|
|
Loading…
Reference in a new issue