mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-16 16:21:02 +00:00
GUI: Progress Dialog On Save State Creation
This commit is contained in:
parent
707a648a4c
commit
580f9bf03a
@ -139,7 +139,8 @@ bool zip(const void* src, usz size, fs::file& out, bool multi_thread_it)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::serial compressor(!multi_thread_it || size < 0x40'0000);
|
utils::serial compressor;
|
||||||
|
compressor.set_expect_little_data(!multi_thread_it || size < 0x40'0000);
|
||||||
compressor.m_file_handler = make_compressed_serialization_file_handler(out);
|
compressor.m_file_handler = make_compressed_serialization_file_handler(out);
|
||||||
|
|
||||||
std::string_view buffer_view{static_cast<const char*>(src), size};
|
std::string_view buffer_view{static_cast<const char*>(src), size};
|
||||||
|
@ -2970,13 +2970,16 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||||||
|
|
||||||
*join_thread = make_ptr(new named_thread("Emulation Join Thread"sv, [join_thread, savestate, allow_autoexit, this]() mutable
|
*join_thread = make_ptr(new named_thread("Emulation Join Thread"sv, [join_thread, savestate, allow_autoexit, this]() mutable
|
||||||
{
|
{
|
||||||
named_thread stop_watchdog("Stop Watchdog"sv, [this]()
|
std::shared_ptr<bool> join_ended = std::make_shared<bool>(false);
|
||||||
|
atomic_ptr<utils::serial> to_ar;
|
||||||
|
|
||||||
|
named_thread stop_watchdog("Stop Watchdog"sv, [&to_ar, join_ended, this]()
|
||||||
{
|
{
|
||||||
const auto closed_sucessfully = std::make_shared<atomic_t<bool>>(false);
|
const auto closed_sucessfully = std::make_shared<atomic_t<bool>>(false);
|
||||||
|
|
||||||
bool is_being_held_longer = false;
|
bool is_being_held_longer = false;
|
||||||
|
|
||||||
for (int i = 0; thread_ctrl::state() != thread_state::aborting;)
|
for (int i = 0; !*join_ended && thread_ctrl::state() != thread_state::aborting;)
|
||||||
{
|
{
|
||||||
if (g_watchdog_hold_ctr)
|
if (g_watchdog_hold_ctr)
|
||||||
{
|
{
|
||||||
@ -3000,6 +3003,25 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||||||
thread_ctrl::wait_for(5'000);
|
thread_ctrl::wait_for(5'000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; thread_ctrl::state() != thread_state::aborting;)
|
||||||
|
{
|
||||||
|
if (auto ar_ptr = to_ar.load())
|
||||||
|
{
|
||||||
|
// Total amount of waiting: about 10s
|
||||||
|
GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr);
|
||||||
|
|
||||||
|
while (thread_ctrl::state() != thread_state::aborting)
|
||||||
|
{
|
||||||
|
thread_ctrl::wait_for(5'000);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_ctrl::wait_for(5'000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
*closed_sucessfully = true;
|
*closed_sucessfully = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3018,8 +3040,6 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||||||
|
|
||||||
sys_log.notice("All threads have been stopped.");
|
sys_log.notice("All threads have been stopped.");
|
||||||
|
|
||||||
std::unique_ptr<utils::serial> to_ar;
|
|
||||||
|
|
||||||
fs::pending_file file;
|
fs::pending_file file;
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
@ -3048,13 +3068,15 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
to_ar = std::make_unique<utils::serial>();
|
to_ar = stx::make_single<utils::serial>();
|
||||||
to_ar->m_file_handler = make_compressed_serialization_file_handler(file.file);
|
to_ar.load()->m_file_handler = make_compressed_serialization_file_handler(file.file);
|
||||||
|
|
||||||
signal_system_cache_can_stay();
|
signal_system_cache_can_stay();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*join_ended = true;
|
||||||
|
|
||||||
if (savestate)
|
if (savestate)
|
||||||
{
|
{
|
||||||
// Savestate thread
|
// Savestate thread
|
||||||
@ -3065,7 +3087,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||||||
return fmt::format("Emu State Capture Thread: '%s'", g_tls_serialize_name);
|
return fmt::format("Emu State Capture Thread: '%s'", g_tls_serialize_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto& ar = *to_ar;
|
auto& ar = *to_ar.load();
|
||||||
|
|
||||||
read_used_savestate_versions(); // Reset version data
|
read_used_savestate_versions(); // Reset version data
|
||||||
USING_SERIALIZATION_VERSION(global_version);
|
USING_SERIALIZATION_VERSION(global_version);
|
||||||
@ -3196,6 +3218,10 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||||||
|
|
||||||
ar(std::array<u8, 32>{}); // Reserved for future use
|
ar(std::array<u8, 32>{}); // Reserved for future use
|
||||||
ar(timestamp);
|
ar(timestamp);
|
||||||
|
|
||||||
|
// Final file write, the file is ready to be committed
|
||||||
|
ar.seek_end();
|
||||||
|
ar.m_file_handler->finalize(ar);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Join it
|
// Join it
|
||||||
@ -3209,15 +3235,9 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_watchdog = thread_state::aborting;
|
|
||||||
|
|
||||||
if (savestate)
|
if (savestate)
|
||||||
{
|
{
|
||||||
auto& ar = *to_ar;
|
auto& ar = *to_ar.load();
|
||||||
|
|
||||||
// Final file write, the file is ready to be committed
|
|
||||||
ar.seek_end();
|
|
||||||
ar.m_file_handler->finalize(ar);
|
|
||||||
|
|
||||||
fs::stat_t file_stat{};
|
fs::stat_t file_stat{};
|
||||||
|
|
||||||
@ -3257,6 +3277,8 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
|||||||
ar.set_reading_state();
|
ar.set_reading_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop_watchdog = thread_state::aborting;
|
||||||
|
|
||||||
// Log additional debug information - do not do it on the main thread due to the concern of halting UI events
|
// Log additional debug information - do not do it on the main thread due to the concern of halting UI events
|
||||||
|
|
||||||
if (g_tty && sys_log.notice)
|
if (g_tty && sys_log.notice)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "util/types.hpp"
|
#include "util/types.hpp"
|
||||||
#include "util/atomic.hpp"
|
#include "util/atomic.hpp"
|
||||||
|
#include "util/shared_ptr.hpp"
|
||||||
#include "Utilities/bit_set.h"
|
#include "Utilities/bit_set.h"
|
||||||
#include "config_mode.h"
|
#include "config_mode.h"
|
||||||
#include "games_config.h"
|
#include "games_config.h"
|
||||||
@ -63,6 +64,7 @@ struct EmuCallbacks
|
|||||||
std::function<void()> on_ready;
|
std::function<void()> on_ready;
|
||||||
std::function<bool()> on_missing_fw;
|
std::function<bool()> on_missing_fw;
|
||||||
std::function<void(std::shared_ptr<atomic_t<bool>>, int)> on_emulation_stop_no_response;
|
std::function<void(std::shared_ptr<atomic_t<bool>>, int)> on_emulation_stop_no_response;
|
||||||
|
std::function<void(std::shared_ptr<atomic_t<bool>>, stx::shared_ptr<utils::serial>)> on_save_state_progress;
|
||||||
std::function<void(bool enabled)> enable_disc_eject;
|
std::function<void(bool enabled)> enable_disc_eject;
|
||||||
std::function<void(bool enabled)> enable_disc_insert;
|
std::function<void(bool enabled)> enable_disc_insert;
|
||||||
std::function<bool(bool, std::function<void()>)> try_to_quit; // (force_quit, on_exit) Try to close RPCS3
|
std::function<bool(bool, std::function<void()>)> try_to_quit; // (force_quit, on_exit) Try to close RPCS3
|
||||||
|
@ -148,6 +148,10 @@ void headless_application::InitializeCallbacks()
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
callbacks.on_save_state_progress = [](std::shared_ptr<atomic_t<bool>>, stx::shared_ptr<utils::serial>)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
callbacks.enable_disc_eject = [](bool) {};
|
callbacks.enable_disc_eject = [](bool) {};
|
||||||
callbacks.enable_disc_insert = [](bool) {};
|
callbacks.enable_disc_insert = [](bool) {};
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "recvmessage_dialog_frame.h"
|
#include "recvmessage_dialog_frame.h"
|
||||||
#include "sendmessage_dialog_frame.h"
|
#include "sendmessage_dialog_frame.h"
|
||||||
#include "stylesheets.h"
|
#include "stylesheets.h"
|
||||||
|
#include "progress_dialog.h"
|
||||||
|
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
@ -665,6 +666,45 @@ void gui_application::InitializeCallbacks()
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
callbacks.on_save_state_progress = [this](std::shared_ptr<atomic_t<bool>> closed_successfully, stx::shared_ptr<utils::serial> ar_ptr)
|
||||||
|
{
|
||||||
|
Emu.CallFromMainThread([this, closed_successfully, ar_ptr]
|
||||||
|
{
|
||||||
|
const auto half_seconds = std::make_shared<int>(1);
|
||||||
|
|
||||||
|
progress_dialog* pdlg = new progress_dialog(tr("Creating Save-State / Do Not Close RPCS3"), tr("Please wait..."), tr("Hide Progress"), 0, 100, true, m_main_window);
|
||||||
|
pdlg->setAutoReset(false);
|
||||||
|
pdlg->setAutoClose(true);
|
||||||
|
pdlg->show();
|
||||||
|
|
||||||
|
QString text_base = tr("Waiting for %0 second(s), %1 written");
|
||||||
|
|
||||||
|
pdlg->setLabelText(text_base.arg(0).arg("0B"));
|
||||||
|
pdlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
QTimer* update_timer = new QTimer(pdlg);
|
||||||
|
|
||||||
|
connect(update_timer, &QTimer::timeout, [pdlg, ar_ptr, half_seconds, text_base, closed_successfully]()
|
||||||
|
{
|
||||||
|
*half_seconds += 1;
|
||||||
|
|
||||||
|
const usz bytes_written = atomic_storage<usz>::load(ar_ptr->pos);
|
||||||
|
pdlg->setLabelText(text_base.arg(*half_seconds / 2).arg(gui::utils::format_byte_size(bytes_written)));
|
||||||
|
|
||||||
|
// 300MB -> 50%, 600MB -> 75%, 1200MB -> 87.5% etc
|
||||||
|
pdlg->setValue(std::clamp(static_cast<int>(100. - 100. / std::pow(2., std::fmax(0.01, bytes_written * 1. / (300 * 1024 * 1024)))), 2, 100));
|
||||||
|
|
||||||
|
if (*closed_successfully)
|
||||||
|
{
|
||||||
|
pdlg->reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pdlg->open();
|
||||||
|
update_timer->start(500);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
callbacks.add_breakpoint = [this](u32 addr)
|
callbacks.add_breakpoint = [this](u32 addr)
|
||||||
{
|
{
|
||||||
Emu.BlockingCallFromMainThread([this, addr]()
|
Emu.BlockingCallFromMainThread([this, addr]()
|
||||||
|
@ -83,11 +83,7 @@ public:
|
|||||||
usz m_max_data = umax;
|
usz m_max_data = umax;
|
||||||
std::unique_ptr<serialization_file_handler> m_file_handler;
|
std::unique_ptr<serialization_file_handler> m_file_handler;
|
||||||
|
|
||||||
serial(bool expect_little_data = false) noexcept
|
serial() noexcept = default;
|
||||||
: m_expect_little_data(expect_little_data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
serial(const serial&) = delete;
|
serial(const serial&) = delete;
|
||||||
serial& operator=(const serial&) = delete;
|
serial& operator=(const serial&) = delete;
|
||||||
explicit serial(serial&&) noexcept = default;
|
explicit serial(serial&&) noexcept = default;
|
||||||
@ -100,6 +96,11 @@ public:
|
|||||||
return m_is_writing;
|
return m_is_writing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_expect_little_data(bool value)
|
||||||
|
{
|
||||||
|
m_expect_little_data = value;
|
||||||
|
}
|
||||||
|
|
||||||
// Return true if small amounts of both input and output memory are expected (performance hint)
|
// Return true if small amounts of both input and output memory are expected (performance hint)
|
||||||
bool expect_little_data() const
|
bool expect_little_data() const
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user