diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 7bdebca275..2105e0c748 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1602,6 +1602,18 @@ void Emulator::Stop(bool restart) sys_log.notice("Stopping emulator..."); + if (!restart) + { + // Show visual feedback to the user in case that stopping takes a while. + // This needs to be done before actually stopping, because otherwise the necessary threads will be terminated before we can show an image. + if (auto progress_dialog = g_fxo->try_get>(); progress_dialog && +g_progr) + { + // We are currently showing a progress dialog. Notify it that we are going to stop emulation. + g_system_progress_stopping = true; + std::this_thread::sleep_for(20ms); // Enough for one frame to be rendered + } + } + named_thread stop_watchdog("Stop Watchdog", [&]() { for (uint i = 0; thread_ctrl::state() != thread_state::aborting;) diff --git a/rpcs3/Emu/system_progress.cpp b/rpcs3/Emu/system_progress.cpp index b9a3f29897..f499819306 100644 --- a/rpcs3/Emu/system_progress.cpp +++ b/rpcs3/Emu/system_progress.cpp @@ -15,6 +15,9 @@ atomic_t g_progr_pdone{0}; // For Batch PPU Compilation atomic_t g_system_progress_canceled{false}; +// For showing feedback while stopping emulation +atomic_t g_system_progress_stopping{false}; + namespace rsx::overlays { class progress_dialog : public message_dialog @@ -26,14 +29,17 @@ namespace rsx::overlays void progress_dialog_server::operator()() { - while (thread_ctrl::state() != thread_state::aborting) + std::shared_ptr native_dlg; + g_system_progress_stopping = false; + + while (!g_system_progress_stopping && thread_ctrl::state() != thread_state::aborting) { // Wait for the start condition auto text0 = +g_progr; while (!text0) { - if (thread_ctrl::state() == thread_state::aborting) + if (g_system_progress_stopping || thread_ctrl::state() == thread_state::aborting) { break; } @@ -42,7 +48,7 @@ void progress_dialog_server::operator()() text0 = +g_progr; } - if (thread_ctrl::state() == thread_state::aborting) + if (g_system_progress_stopping || thread_ctrl::state() == thread_state::aborting) { break; } @@ -52,7 +58,6 @@ void progress_dialog_server::operator()() // Initialize message dialog bool skip_this_one = false; // Workaround: do not open a progress dialog if there is already a cell message dialog open. std::shared_ptr dlg; - std::shared_ptr native_dlg; if (const auto renderer = rsx::get_current_renderer(); renderer && renderer->is_inited) @@ -104,7 +109,7 @@ void progress_dialog_server::operator()() auto text1 = text0; // Update progress - while (thread_ctrl::state() != thread_state::aborting) + while (!g_system_progress_stopping && thread_ctrl::state() != thread_state::aborting) { const auto text_new = g_progr.load(); @@ -168,7 +173,7 @@ void progress_dialog_server::operator()() std::this_thread::sleep_for(10ms); } - if (thread_ctrl::state() == thread_state::aborting) + if (g_system_progress_stopping || thread_ctrl::state() == thread_state::aborting) { break; } @@ -196,6 +201,12 @@ void progress_dialog_server::operator()() g_progr_ptotal -= ptotal; g_progr_ptotal.notify_all(); } + + if (native_dlg && g_system_progress_stopping) + { + native_dlg->set_text("Stopping. Please wait..."); + native_dlg->refresh(); + } } progress_dialog_server::~progress_dialog_server() diff --git a/rpcs3/Emu/system_progress.hpp b/rpcs3/Emu/system_progress.hpp index 118447aae5..9082ec4d8c 100644 --- a/rpcs3/Emu/system_progress.hpp +++ b/rpcs3/Emu/system_progress.hpp @@ -9,6 +9,7 @@ extern atomic_t g_progr_fdone; extern atomic_t g_progr_ptotal; extern atomic_t g_progr_pdone; extern atomic_t g_system_progress_canceled; +extern atomic_t g_system_progress_stopping; // Initialize progress dialog (can be recursive) class scoped_progress_dialog final diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index fe116c5831..a6f1b39dde 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -7,6 +7,7 @@ #include "Utilities/File.h" #include "Emu/System.h" #include "Emu/system_config.h" +#include "Emu/system_progress.hpp" #include "Emu/IdManager.h" #include "Emu/Cell/Modules/cellScreenshot.h" #include "Emu/RSX/rsx_utils.h" @@ -348,7 +349,12 @@ void gs_frame::close() { Emu.CallAfter([this]() { - QWindow::hide(); // Workaround + if (!(+g_progr)) + { + // Hide the dialog before stopping if no progress bar is being shown. + // Otherwise users might think that the game softlocked if stopping takes too long. + QWindow::hide(); + } if (!Emu.IsStopped()) {