diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 4248fb84f1..faf78babb3 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -4615,15 +4615,15 @@ bool spu_thread::process_mfc_cmd() if (getllar_busy_waiting_switch == umax && getllar_spin_count == 4) { - const u32 percent = g_cfg.core.spu_getllar_busy_waiting_percentage; - // Hidden value to force busy waiting (100 to 1 are dynamically adjusted, 0 is not) - if (percent != 101) + if (!g_cfg.core.spu_getllar_spin_optimization_disabled) { + const u32 percent = g_cfg.core.spu_getllar_busy_waiting_percentage; + // Predict whether or not to use operating system sleep based on history auto& stats = getllar_wait_time[(addr % SPU_LS_SIZE) / 128]; - const auto old_stats = stats; + const std::array old_stats = stats; std::array new_stats{}; // Rotate history (prepare newest entry) @@ -4640,7 +4640,7 @@ bool spu_thread::process_mfc_cmd() for (u8 val : old_stats) { total_wait += val; - zero_count += (val == 0 ? 1 : 0); + if (val == 0) ++zero_count; } // Add to chance if previous wait was long enough @@ -4675,10 +4675,8 @@ bool spu_thread::process_mfc_cmd() // Don't be stubborn, force operating sleep if too much time has passed else if (getllar_busy_waiting_switch == 1 && perf0.get() > getllar_evaluate_time && perf0.get() - getllar_evaluate_time >= 400'000) { - const u32 percent = g_cfg.core.spu_getllar_busy_waiting_percentage; - // Hidden value to force busy waiting - if (percent != 101) + if (!g_cfg.core.spu_getllar_spin_optimization_disabled) { spu_log.trace("SPU wait for 0x%x", addr); getllar_wait_time[(addr % SPU_LS_SIZE) / 128].front() = 1; diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index eeebd7d132..4049a8aa14 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -32,7 +32,8 @@ struct cfg_root : cfg::node cfg::_bool set_daz_and_ftz{ this, "Set DAZ and FTZ", false }; cfg::_enum spu_decoder{ this, "SPU Decoder", spu_decoder_type::llvm }; cfg::uint<0, 100> spu_reservation_busy_waiting_percentage{ this, "SPU Reservation Busy Waiting Percentage", 0, true }; - cfg::uint<0, 101> spu_getllar_busy_waiting_percentage{ this, "SPU GETLLAR Busy Waiting Percentage", 100, true }; + cfg::uint<0, 100> spu_getllar_busy_waiting_percentage{ this, "SPU GETLLAR Busy Waiting Percentage", 100, true }; + cfg::_bool spu_getllar_spin_optimization_disabled{ this, "Disable SPU GETLLAR Spin Optimization", false, true }; cfg::_bool spu_debug{ this, "SPU Debug" }; cfg::_bool mfc_debug{ this, "MFC Debug" }; cfg::_int<0, 6> preferred_spu_threads{ this, "Preferred SPU Threads", 0, true }; // Number of hardware threads dedicated to heavy simultaneous spu tasks diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index 1bc86e307f..845e21a8d8 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -51,6 +51,7 @@ enum class emu_settings_type AccuratePPUFPCC, MaxPreemptCount, SPUProfiler, + DisableSpinOptimization, // Graphics Renderer, @@ -248,6 +249,7 @@ inline static const std::map settings_location { emu_settings_type::AccuratePPUFPCC, { "Core", "PPU Set FPCC Bits"}}, { emu_settings_type::MaxPreemptCount, { "Core", "Max CPU Preempt Count"}}, { emu_settings_type::SPUProfiler, { "Core", "SPU Profiler"}}, + { emu_settings_type::DisableSpinOptimization, { "Core", "Disable SPU GETLLAR Spin Optimization"}}, // Graphics Tab { emu_settings_type::Renderer, { "Video", "Renderer"}}, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 3297bc2dc9..1d275bb498 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -1585,6 +1585,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->disableAsyncHostMM, emu_settings_type::DisableAsyncHostMM); SubscribeTooltip(ui->disableAsyncHostMM, tooltips.settings.disable_async_host_mm); + m_emu_settings->EnhanceCheckBox(ui->disableSpinOptimization, emu_settings_type::DisableSpinOptimization); + SubscribeTooltip(ui->disableSpinOptimization, tooltips.settings.disable_spin_optimization); + // Comboboxes m_emu_settings->EnhanceComboBox(ui->maxSPURSThreads, emu_settings_type::MaxSPURSThreads, true); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index bdc51566d9..08a453d1f6 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -265,7 +265,7 @@ - + @@ -2422,6 +2422,13 @@ + + + + Disable SPU GETLLAR Spin Optimization + + + @@ -4242,16 +4249,16 @@ - - Disable Asynchronous Memory Manager - + + Disable Asynchronous Memory Manager + - - Disable On-Disk Shader Cache - + + Disable On-Disk Shader Cache + @@ -4365,16 +4372,16 @@ - - PPU Vector NaN Fixup - + + PPU Vector NaN Fixup + - - SPU Profiler - + + SPU Profiler + @@ -4398,7 +4405,7 @@ - + 0 @@ -4459,23 +4466,23 @@ - - - - 0 - 0 - - - - Vulkan Queue Scheduler - - - - - - - - + + + + 0 + 0 + + + + Vulkan Queue Scheduler + + + + + + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 4e5de9d619..83eb96ddf6 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -41,6 +41,7 @@ public: const QString force_hw_MSAA = tr("Forces MSAA to use the host GPU's resolve capabilities for all sampling operations.\nThis option incurs a performance penalty as well as the risk of visual artifacts but can yield crisper visuals when MSAA is enabled."); const QString disable_vertex_cache = tr("Disables the vertex cache.\nMight resolve missing or flickering graphics output.\nMay degrade performance."); const QString disable_async_host_mm = tr("Force host memory management calls to be inlined instead of handled asynchronously.\nThis can cause severe performance degradation and stuttering in some games.\nThis option is only needed by developers to debug problems with texture cache memory protection."); + const QString disable_spin_optimization = tr("Disable SPU GETLLAR spin optimization.\nThis can cause severe performance degradation and stuttering in many games.\nThis option is only needed for a select number of games."); const QString zcull_operation_mode = tr("Changes ZCULL report synchronization behaviour. Experiment to find the best option for your game. Approximate mode is recommended for most games.\n· Precise is the most accurate to PS3 behaviour. Required for accurate visuals in some titles such as Demon's Souls and The Darkness.\n· Approximate is a much faster way to generate occlusion data which may not always match what the PS3 would generate. Works well with most PS3 games.\n· Relaxed changes the synchronization method completely and can greatly improve performance in some games or completely break others."); const QString max_spurs_threads = tr("Limits the maximum number of SPURS threads in each thread group.\nMay improve performance in some cases, especially on systems with limited number of hardware threads.\nLimiting the number of threads is likely to cause crashes; it's recommended to keep this at the default value."); const QString sleep_timers_accuracy = tr("Changes the sleep period accuracy.\n'As Host' uses default accuracy of the underlying operating system, while 'All Timers' attempts to improve it.\n'Usleep Only' limits the adjustments to usleep syscall only.\nCan affect performance in unexpected ways.");