diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 704319d0a8..d792e7caea 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -3200,15 +3200,15 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s sys_log.notice("Stopping emulator..."); + const bool continuous_savestate_mode = savestate && !g_cfg.savestate.suspend_emu; + + // 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 (g_fxo->try_get>() && (continuous_savestate_mode || g_progr_text.operator bool())) { - // 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_text.operator bool()) - { - // 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 - } + // Notify progress dialog that we are going to stop emulation + g_system_progress_stopping = continuous_savestate_mode ? system_progress_stop_state::stop_state_continuous_savestate : system_progress_stop_state::stop_state_stopping; + std::this_thread::sleep_for(30ms); // Enough for one frame to be rendered } // Signal threads @@ -3280,7 +3280,10 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s if (auto ar_ptr = to_ar->load()) { // Total amount of waiting: about 10s - GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr, verbose_message.get(), init_mtx); + if (g_cfg.savestate.suspend_emu) + { + GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr, verbose_message.get(), init_mtx); + } while (thread_ctrl::state() != thread_state::aborting) { diff --git a/rpcs3/Emu/localized_string_id.h b/rpcs3/Emu/localized_string_id.h index 21437762bb..d1f576051d 100644 --- a/rpcs3/Emu/localized_string_id.h +++ b/rpcs3/Emu/localized_string_id.h @@ -295,6 +295,7 @@ enum class localized_string_id PROGRESS_DIALOG_OF, PROGRESS_DIALOG_PLEASE_WAIT, PROGRESS_DIALOG_STOPPING_PLEASE_WAIT, + PROGRESS_DIALOG_SAVESTATE_PLEASE_WAIT, PROGRESS_DIALOG_SCANNING_PPU_EXECUTABLE, PROGRESS_DIALOG_ANALYZING_PPU_EXECUTABLE, PROGRESS_DIALOG_SCANNING_PPU_MODULES, diff --git a/rpcs3/Emu/system_progress.cpp b/rpcs3/Emu/system_progress.cpp index 66d59af65b..52e49516fb 100644 --- a/rpcs3/Emu/system_progress.cpp +++ b/rpcs3/Emu/system_progress.cpp @@ -26,7 +26,7 @@ atomic_t g_progr_pdone{0}; atomic_t g_system_progress_canceled{false}; // For showing feedback while stopping emulation -atomic_t g_system_progress_stopping{false}; +atomic_t g_system_progress_stopping{system_progress_stop_state::stop_state_disabled}; namespace rsx::overlays { @@ -40,7 +40,7 @@ namespace rsx::overlays void progress_dialog_server::operator()() { std::shared_ptr native_dlg; - g_system_progress_stopping = false; + g_system_progress_stopping = system_progress_stop_state::stop_state_disabled; g_system_progress_canceled = false; const auto get_state = []() @@ -63,6 +63,41 @@ void progress_dialog_server::operator()() return whole_state; }; + const auto create_native_dialog = [&native_dlg](const std::string& text, bool* show_overlay_message) + { + if (const auto renderer = rsx::get_current_renderer()) + { + // Some backends like OpenGL actually initialize a lot of driver objects in the "on_init" method. + // Wait for init to complete within reasonable time. Abort just in case we have hardware/driver issues. + renderer->is_initialized.wait(0, atomic_wait_timeout(5 * 1000000000ull)); + + auto manager = g_fxo->try_get(); + + if (show_overlay_message) + { + *show_overlay_message = g_fxo->get().show_overlay_message_only; + if (*show_overlay_message) + { + return; + } + } + + if (manager) + { + MsgDialogType type{}; + type.se_mute_on = true; + type.se_normal = true; + type.bg_invisible = true; + type.disable_cancel = true; + type.progress_bar_count = 1; + + native_dlg = manager->create(true); + native_dlg->show(false, text, type, msg_dialog_source::sys_progress, nullptr); + native_dlg->progress_bar_set_message(0, get_localized_string(localized_string_id::PROGRESS_DIALOG_PLEASE_WAIT)); + } + } + }; + while (!g_system_progress_stopping && thread_ctrl::state() != thread_state::aborting) { // Wait for the start condition @@ -113,29 +148,7 @@ void progress_dialog_server::operator()() bool show_overlay_message = false; // Only show an overlay message after initial loading is done. std::shared_ptr dlg; - if (const auto renderer = rsx::get_current_renderer()) - { - // Some backends like OpenGL actually initialize a lot of driver objects in the "on_init" method. - // Wait for init to complete within reasonable time. Abort just in case we have hardware/driver issues. - renderer->is_initialized.wait(0, atomic_wait_timeout(5 * 1000000000ull)); - - auto manager = g_fxo->try_get(); - show_overlay_message = g_fxo->get().show_overlay_message_only; - - if (manager && !show_overlay_message) - { - MsgDialogType type{}; - type.se_mute_on = true; - type.se_normal = true; - type.bg_invisible = true; - type.disable_cancel = true; - type.progress_bar_count = 1; - - native_dlg = manager->create(true); - native_dlg->show(false, text0, type, msg_dialog_source::sys_progress, nullptr); - native_dlg->progress_bar_set_message(0, get_localized_string(localized_string_id::PROGRESS_DIALOG_PLEASE_WAIT)); - } - } + create_native_dialog(text0, &show_overlay_message); if (!show_overlay_message && !native_dlg && (dlg = Emu.GetCallbacks().get_msg_dialog())) { @@ -392,6 +405,7 @@ void progress_dialog_server::operator()() else if (native_dlg) { native_dlg->close(false, false); + native_dlg.reset(); } else if (dlg) { @@ -411,10 +425,25 @@ void progress_dialog_server::operator()() g_progr_ptotal.notify_all(); } - if (native_dlg && g_system_progress_stopping) + if (g_system_progress_stopping) { - native_dlg->set_text(get_localized_string(localized_string_id::PROGRESS_DIALOG_STOPPING_PLEASE_WAIT)); - native_dlg->refresh(); + const std::string text = get_localized_string( + g_system_progress_stopping == system_progress_stop_state::stop_state_continuous_savestate + ? localized_string_id::PROGRESS_DIALOG_SAVESTATE_PLEASE_WAIT + : localized_string_id::PROGRESS_DIALOG_STOPPING_PLEASE_WAIT + ); + if (native_dlg) + { + native_dlg->set_text(text); + } + else + { + create_native_dialog(text, nullptr); + } + if (native_dlg) + { + native_dlg->refresh(); + } } if (g_progr_ptotal.exchange(0)) diff --git a/rpcs3/Emu/system_progress.hpp b/rpcs3/Emu/system_progress.hpp index 13ae8d13eb..67e4e68df1 100644 --- a/rpcs3/Emu/system_progress.hpp +++ b/rpcs3/Emu/system_progress.hpp @@ -36,6 +36,13 @@ struct alignas(16) progress_dialog_string_t } }; +enum system_progress_stop_state : u32 +{ + stop_state_disabled = 0, + stop_state_stopping, + stop_state_continuous_savestate +}; + extern progress_dialog_string_t g_progr_text; extern atomic_t g_progr_ftotal; extern atomic_t g_progr_fdone; @@ -44,7 +51,7 @@ extern atomic_t g_progr_fknown_bits; 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; +extern atomic_t g_system_progress_stopping; // Initialize progress dialog (can be recursive) class scoped_progress_dialog final diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 08af646b50..e16f97aff0 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -795,7 +795,7 @@ void gui_application::InitializeCallbacks() verbose_message += ". "; } - verbose_message += "If Stuck, Report To Developers"; + verbose_message += tr("If Stuck, Report To Developers").toStdString(); } else { diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index 8ea21f6d03..7e8ae3f803 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -314,6 +314,7 @@ private: case localized_string_id::PROGRESS_DIALOG_OF: return tr("of"); case localized_string_id::PROGRESS_DIALOG_PLEASE_WAIT: return tr("Please wait"); case localized_string_id::PROGRESS_DIALOG_STOPPING_PLEASE_WAIT: return tr("Stopping. Please wait..."); + case localized_string_id::PROGRESS_DIALOG_SAVESTATE_PLEASE_WAIT: return tr("Creating savestate. Please wait..."); case localized_string_id::PROGRESS_DIALOG_SCANNING_PPU_EXECUTABLE: return tr("Scanning PPU Executable..."); case localized_string_id::PROGRESS_DIALOG_ANALYZING_PPU_EXECUTABLE: return tr("Analyzing PPU Executable..."); case localized_string_id::PROGRESS_DIALOG_SCANNING_PPU_MODULES: return tr("Scanning PPU Modules...");