diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 9fdc8d92bd..806bd7e54c 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1023,6 +1023,44 @@ cpu_thread& cpu_thread::operator=(thread_state) return *this; } +void cpu_thread::add_remove_flags(bs_t to_add, bs_t to_remove) +{ + bs_t result{}; + + if (!to_remove) + { + state.add_fetch(to_add); + return; + } + else if (!to_add) + { + result = state.sub_fetch(to_remove); + } + else + { + result = state.atomic_op([&](bs_t& v) + { + v += to_add; + v -= to_remove; + return v; + }); + } + + if (!::is_paused(to_remove) && !::is_stopped(to_remove)) + { + // No notable change requiring notification + return; + } + + if (::is_paused(result) || ::is_stopped(result)) + { + // Flags that stop thread execution + return; + } + + state.notify_one(); +} + std::string cpu_thread::get_name() const { // Downcast to correct type diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index cfdee6db4b..a11e4cd869 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -149,7 +149,9 @@ public: void notify(); cpu_thread& operator=(thread_state); -public: + // Add/remove CPU state flags in an atomic operations, notifying if required + void add_remove_flags(bs_t to_add, bs_t to_remove); + // Thread stats for external observation static atomic_t g_threads_created, g_threads_deleted, g_suspend_counter; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 244ad670b1..892ce75a34 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -652,13 +652,14 @@ namespace rsx m_overlay_manager = g_fxo->init(0); } - state -= cpu_flag::stop + cpu_flag::wait; // TODO: Remove workaround - if (!_ar) { + add_remove_flags({}, cpu_flag::stop); // TODO: Remove workaround return; } + add_remove_flags(cpu_flag::suspend, cpu_flag::stop); + serialized = true; save(*_ar); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index d3bb9aa9c2..0969cf5a5c 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -2230,7 +2230,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, } } - const bool autostart = (std::exchange(m_force_boot, false) || g_cfg.misc.autostart); + const bool autostart = m_ar || (std::exchange(m_force_boot, false) || g_cfg.misc.autostart); if (IsReady()) { @@ -2333,8 +2333,6 @@ void Emulator::FixGuestTime() } } - m_ar.reset(); - g_tls_log_prefix = []() { return std::string(); @@ -2349,33 +2347,60 @@ void Emulator::FixGuestTime() void Emulator::FinalizeRunRequest() { - auto on_select = [](u32, spu_thread& spu) + const bool autostart = !m_ar || !!g_cfg.misc.autostart; + + bs_t add_flags = cpu_flag::dbg_global_pause; + + if (autostart) { + add_flags -= cpu_flag::dbg_global_pause; + } + + auto spu_select = [&](u32, spu_thread& spu) + { + bs_t sub_flags = cpu_flag::stop; + if (spu.group && spu.index == spu.group->waiter_spu_index) { - return; + sub_flags -= cpu_flag::stop; } - - if (std::exchange(spu.stop_flag_removal_protection, false)) + else if (std::exchange(spu.stop_flag_removal_protection, false)) { - return; + sub_flags -= cpu_flag::stop; } - ensure(spu.state.test_and_reset(cpu_flag::stop)); - spu.state.notify_one(); + spu.add_remove_flags(add_flags, sub_flags); }; + auto ppu_select = [&](u32, ppu_thread& ppu) + { + ppu.state += add_flags; + }; + + if (auto rsx = g_fxo->try_get()) + { + static_cast(rsx)->add_remove_flags(add_flags, cpu_flag::suspend); + } + if (m_savestate_extension_flags1 & SaveStateExtentionFlags1::ShouldCloseMenu) { g_fxo->get().active = true; } - idm::select>(on_select); + idm::select>(spu_select); + idm::select>(ppu_select); lv2_obj::make_scheduler_ready(); m_state.compare_and_swap_test(system_state::starting, system_state::running); + m_ar.reset(); + + if (!autostart) + { + Pause(); + } + if (m_savestate_extension_flags1 & SaveStateExtentionFlags1::ShouldCloseMenu) { std::thread([this, info = GetEmulationIdentifier()]()