mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 08:11:51 +00:00
Savestates: Add save stage names
This commit is contained in:
parent
26746ac9ee
commit
d1837b54b4
@ -3022,11 +3022,14 @@ 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
|
||||
{
|
||||
fs::pending_file file;
|
||||
std::shared_ptr<stx::init_mutex> init_mtx = std::make_shared<stx::init_mutex>();
|
||||
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, init_mtx, join_ended, this]()
|
||||
auto verbose_message = std::make_shared<atomic_ptr<std::string>>();
|
||||
auto init_mtx = std::make_shared<stx::init_mutex>();
|
||||
auto join_ended = std::make_shared<bool>(false);
|
||||
auto to_ar = std::make_shared<atomic_ptr<utils::serial>>();
|
||||
|
||||
auto stop_watchdog = make_ptr(new named_thread("Stop Watchdog"sv,
|
||||
[to_ar, init_mtx, join_ended, verbose_message, this]()
|
||||
{
|
||||
const auto closed_sucessfully = std::make_shared<atomic_t<bool>>(false);
|
||||
|
||||
@ -3058,10 +3061,10 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
if (auto ar_ptr = to_ar.load())
|
||||
if (auto ar_ptr = to_ar->load())
|
||||
{
|
||||
// Total amount of waiting: about 10s
|
||||
GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr, init_mtx);
|
||||
GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr, verbose_message.get(), init_mtx);
|
||||
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
@ -3076,7 +3079,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
|
||||
|
||||
*closed_sucessfully = true;
|
||||
});
|
||||
}));
|
||||
|
||||
// Join threads
|
||||
for (const auto& [type, data] : *g_fxo)
|
||||
@ -3097,8 +3100,15 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
|
||||
static_cast<void>(init_mtx->init());
|
||||
|
||||
auto set_progress_message = [&](std::string_view text)
|
||||
{
|
||||
*verbose_message = stx::make_single<std::string>(text);
|
||||
};
|
||||
|
||||
while (savestate)
|
||||
{
|
||||
set_progress_message("Creating File");
|
||||
|
||||
path = get_savestate_file(m_title_id, m_path, 0, 0);
|
||||
|
||||
// The function is meant for reading files, so if there is no GZ file it would not return compressed file path
|
||||
@ -3124,7 +3134,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
|
||||
auto serial_ptr = stx::make_single<utils::serial>();
|
||||
serial_ptr->m_file_handler = make_compressed_serialization_file_handler(file.file);
|
||||
to_ar = std::move(serial_ptr);
|
||||
*to_ar = std::move(serial_ptr);
|
||||
|
||||
signal_system_cache_can_stay();
|
||||
break;
|
||||
@ -3142,7 +3152,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);
|
||||
};
|
||||
|
||||
auto& ar = *to_ar.load();
|
||||
auto& ar = *to_ar->load();
|
||||
|
||||
read_used_savestate_versions(); // Reset version data
|
||||
USING_SERIALIZATION_VERSION(global_version);
|
||||
@ -3217,6 +3227,8 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
ar(std::string{});
|
||||
};
|
||||
|
||||
set_progress_message("Creating Header");
|
||||
|
||||
ar("RPCS3SAV"_u64);
|
||||
ar(std::endian::native == std::endian::little);
|
||||
ar(g_cfg.savestate.state_inspection_mode.get());
|
||||
@ -3256,12 +3268,22 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
|
||||
ar(klic.empty() ? std::array<u8, 16>{} : std::bit_cast<std::array<u8, 16>>(klic[0]));
|
||||
ar(m_game_dir);
|
||||
|
||||
set_progress_message("Saving HDD1");
|
||||
save_hdd1();
|
||||
set_progress_message("Saving HDD0");
|
||||
save_hdd0();
|
||||
|
||||
ar(std::array<u8, 32>{}); // Reserved for future use
|
||||
|
||||
set_progress_message("Saving VMemory");
|
||||
vm::save(ar);
|
||||
|
||||
set_progress_message("Saving FXO");
|
||||
g_fxo->save(ar);
|
||||
|
||||
set_progress_message("Finalizing File");
|
||||
|
||||
bs_t<SaveStateExtentionFlags1> extension_flags{SaveStateExtentionFlags1::SupportsMenuOpenResume};
|
||||
|
||||
if (g_fxo->get<SysutilMenuOpenStatus>().active)
|
||||
@ -3285,18 +3307,17 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
if (emu_state_cap_thread == thread_state::errored)
|
||||
{
|
||||
sys_log.error("Saving savestate failed due to fatal error!");
|
||||
to_ar.reset();
|
||||
to_ar->reset();
|
||||
savestate = false;
|
||||
}
|
||||
}
|
||||
|
||||
stop_watchdog = thread_state::finished;
|
||||
static_cast<void>(init_mtx->reset());
|
||||
|
||||
if (savestate)
|
||||
{
|
||||
fs::stat_t file_stat{};
|
||||
|
||||
set_progress_message("Commiting File");
|
||||
|
||||
if (!file.commit() || !fs::get_stat(path, file_stat))
|
||||
{
|
||||
sys_log.error("Failed to write savestate to file! (path='%s', %s)", path, fs::g_tls_error);
|
||||
@ -3394,8 +3415,10 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
}
|
||||
}
|
||||
|
||||
set_progress_message("Resetting Objects");
|
||||
|
||||
// Final termination from main thread (move the last ownership of join thread in order to destroy it)
|
||||
CallFromMainThread([join_thread = std::move(join_thread), allow_autoexit, this]() mutable
|
||||
CallFromMainThread([join_thread = std::move(join_thread), verbose_message, stop_watchdog, init_mtx, allow_autoexit, this]()
|
||||
{
|
||||
cpu_thread::cleanup();
|
||||
|
||||
@ -3407,6 +3430,9 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
|
||||
|
||||
vm::close();
|
||||
|
||||
*stop_watchdog = thread_state::finished;
|
||||
static_cast<void>(init_mtx->reset());
|
||||
|
||||
jit_runtime::finalize();
|
||||
|
||||
perf_stat_base::report();
|
||||
|
@ -64,7 +64,7 @@ struct EmuCallbacks
|
||||
std::function<void()> on_ready;
|
||||
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>>, stx::shared_ptr<utils::serial>, std::shared_ptr<void>)> on_save_state_progress;
|
||||
std::function<void(std::shared_ptr<atomic_t<bool>>, stx::shared_ptr<utils::serial>, stx::atomic_ptr<std::string>*, std::shared_ptr<void>)> on_save_state_progress;
|
||||
std::function<void(bool enabled)> enable_disc_eject;
|
||||
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
|
||||
|
@ -148,7 +148,7 @@ void headless_application::InitializeCallbacks()
|
||||
}
|
||||
};
|
||||
|
||||
callbacks.on_save_state_progress = [](std::shared_ptr<atomic_t<bool>>, stx::shared_ptr<utils::serial>, std::shared_ptr<void>)
|
||||
callbacks.on_save_state_progress = [](std::shared_ptr<atomic_t<bool>>, stx::shared_ptr<utils::serial>, stx::atomic_ptr<std::string>*, std::shared_ptr<void>)
|
||||
{
|
||||
};
|
||||
|
||||
|
@ -685,9 +685,9 @@ 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, std::shared_ptr<void> init_mtx)
|
||||
callbacks.on_save_state_progress = [this](std::shared_ptr<atomic_t<bool>> closed_successfully, stx::shared_ptr<utils::serial> ar_ptr, stx::atomic_ptr<std::string>* code_location, std::shared_ptr<void> init_mtx)
|
||||
{
|
||||
Emu.CallFromMainThread([this, closed_successfully, ar_ptr, init_mtx]
|
||||
Emu.CallFromMainThread([this, closed_successfully, ar_ptr, code_location, init_mtx]
|
||||
{
|
||||
const auto half_seconds = std::make_shared<int>(1);
|
||||
|
||||
@ -696,30 +696,72 @@ void gui_application::InitializeCallbacks()
|
||||
pdlg->setAutoClose(true);
|
||||
pdlg->show();
|
||||
|
||||
QString text_base = tr("Waiting for %0 second(s), %1 written");
|
||||
QString text_base = tr("%0 written, %1 second(s) passed%2");
|
||||
|
||||
pdlg->setLabelText(text_base.arg(0).arg("0B"));
|
||||
pdlg->setLabelText(text_base.arg("0B").arg(1).arg(""));
|
||||
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, init_mtx]()
|
||||
connect(update_timer, &QTimer::timeout, [pdlg, ar_ptr, half_seconds, text_base, closed_successfully
|
||||
, code_location, init_mtx, old_written = usz{0}, repeat_count = u32{0}]() mutable
|
||||
{
|
||||
auto init = static_cast<stx::init_mutex*>(init_mtx.get())->access();
|
||||
std::string verbose_message;
|
||||
usz bytes_written = 0;
|
||||
|
||||
if (!init)
|
||||
{
|
||||
pdlg->reject();
|
||||
return;
|
||||
auto init = static_cast<stx::init_mutex*>(init_mtx.get())->access();
|
||||
|
||||
if (!init)
|
||||
{
|
||||
pdlg->reject();
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto str_ptr = code_location->load())
|
||||
{
|
||||
verbose_message = "\n" + *str_ptr;
|
||||
}
|
||||
|
||||
*half_seconds += 1;
|
||||
|
||||
bytes_written = ar_ptr->get_size();
|
||||
}
|
||||
|
||||
*half_seconds += 1;
|
||||
if (old_written == bytes_written)
|
||||
{
|
||||
if (repeat_count == 60)
|
||||
{
|
||||
if (verbose_message.empty())
|
||||
{
|
||||
verbose_message += "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
verbose_message += ". ";
|
||||
}
|
||||
|
||||
const usz bytes_written = ar_ptr->get_size();
|
||||
pdlg->setLabelText(text_base.arg(*half_seconds / 2).arg(gui::utils::format_byte_size(bytes_written)));
|
||||
verbose_message += "If Stuck, Report To Developers";
|
||||
}
|
||||
else
|
||||
{
|
||||
repeat_count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
repeat_count = 0;
|
||||
}
|
||||
|
||||
old_written = bytes_written;
|
||||
|
||||
pdlg->setLabelText(text_base.arg(gui::utils::format_byte_size(bytes_written)).arg(*half_seconds / 2).arg(qstr(verbose_message)));
|
||||
|
||||
// 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));
|
||||
const int percent = std::clamp(static_cast<int>(100. - 100. / std::pow(2., std::fmax(0.01, bytes_written * 1. / (300 * 1024 * 1024)))), 2, 100);
|
||||
|
||||
// Add a third of the remaining progress when the keyword is found
|
||||
pdlg->setValue(verbose_message.find("Finalizing") != umax ? 100 - ((100 - percent) * 2 / 3) : percent);
|
||||
|
||||
if (*closed_successfully)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user