Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Savestates: Don't actually delete savestates #12702

Merged
merged 4 commits into from Sep 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 11 additions & 1 deletion rpcs3/Emu/Cell/PPUThread.cpp
Expand Up @@ -1277,6 +1277,16 @@ std::string ppu_thread::dump_misc() const
{
std::string ret = cpu_thread::dump_misc();

if (ack_suspend)
{
if (ret.ends_with("\n"))
{
ret.pop_back();
}

fmt::append(ret, " (LV2 suspended)\n");
}

fmt::append(ret, "Priority: %d\n", +prio);
fmt::append(ret, "Stack: 0x%x..0x%x\n", stack_addr, stack_addr + stack_size - 1);
fmt::append(ret, "Joiner: %s\n", joiner.load());
Expand All @@ -1296,7 +1306,7 @@ std::string ppu_thread::dump_misc() const
if (u64 v = gpr[i]; v != syscall_args[i - 3])
fmt::append(ret, " ** r%d: 0x%llx\n", i, v);
}
else if (is_paused())
else if (is_paused() || is_stopped())
{
if (const auto last_func = last_function)
{
Expand Down
87 changes: 63 additions & 24 deletions rpcs3/Emu/Cell/SPUThread.cpp
Expand Up @@ -1694,6 +1694,7 @@ spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u
if (g_cfg.core.mfc_debug)
{
utils::memory_commit(vm::g_stat_addr + vm_offset(), SPU_LS_SIZE);
mfc_history.resize(max_mfc_dump_idx);
}

if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit || g_cfg.core.spu_decoder == spu_decoder_type::llvm)
Expand All @@ -1710,11 +1711,6 @@ spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u
cpu_init();
}

if (g_cfg.core.mfc_debug)
{
mfc_history.resize(max_mfc_dump_idx);
}

range_lock = vm::alloc_range_lock();
}

Expand All @@ -1726,6 +1722,20 @@ void spu_thread::serialize_common(utils::serial& ar)
, run_ctrl, exit_status.data, status_npc.raw().status, ch_dec_start_timestamp, ch_dec_value, is_dec_frozen);

ar(std::span(mfc_queue, mfc_size));

u32 vals[4]{};

if (ar.is_writing())
{
const u8 count = ch_in_mbox.try_read(vals);
ar(count, std::span(vals, count));
}
else
{
const u8 count = ar;
ar(std::span(vals, count));
ch_in_mbox.set_values(count, vals[0], vals[1], vals[2], vals[3]);
}
}

spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group)
Expand Down Expand Up @@ -1757,6 +1767,7 @@ spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group)
if (g_cfg.core.mfc_debug)
{
utils::memory_commit(vm::g_stat_addr + vm_offset(), SPU_LS_SIZE);
mfc_history.resize(max_mfc_dump_idx);
}

if (g_cfg.core.spu_decoder != spu_decoder_type::_static && g_cfg.core.spu_decoder != spu_decoder_type::dynamic)
Expand All @@ -1768,22 +1779,10 @@ spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group)
}
}

if (get_type() >= spu_type::raw)
{
cpu_init();
}

range_lock = vm::alloc_range_lock();

serialize_common(ar);

{
u32 vals[4]{};
const u8 count = ar;
ar(std::span(vals, count));
ch_in_mbox.set_values(count, vals[0], vals[1], vals[2], vals[3]);
}

status_npc.raw().npc = pc | u8{interrupts_enabled};

if (get_type() == spu_type::threaded)
Expand Down Expand Up @@ -1835,12 +1834,6 @@ void spu_thread::save(utils::serial& ar)

serialize_common(ar);

{
u32 vals[4]{};
const u8 count = ch_in_mbox.try_read(vals);
ar(count, std::span(vals, count));
}

if (get_type() == spu_type::threaded)
{
for (const auto& [key, q] : spuq)
Expand Down Expand Up @@ -5347,8 +5340,10 @@ void spu_thread::fast_call(u32 ls_addr)
gpr[1]._u32[3] = old_stack;
}

bool spu_thread::capture_local_storage() const
bool spu_thread::capture_state()
{
ensure(state & cpu_flag::wait);

spu_exec_object spu_exec;

// Save data as an executable segment, even the SPU stack
Expand Down Expand Up @@ -5432,6 +5427,50 @@ bool spu_thread::capture_local_storage() const
}

spu_log.success("SPU Local Storage image saved to '%s'", elf_path);

if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit || g_cfg.core.spu_decoder == spu_decoder_type::llvm)
{
return true;
}

auto& rewind = rewind_captures[current_rewind_capture_idx++ % rewind_captures.size()];

if (rewind)
{
spu_log.error("Due to resource limits the 16th SPU rewind capture is being overwritten with a new one. (free the most recent by loading it)");
rewind.reset();
}

rewind = std::make_shared<utils::serial>();
(*rewind)(std::span(prog.bin.data(), prog.bin.size())); // span serialization doesn't remember size which is what we need
serialize_common(*rewind);

// TODO: Save and restore decrementer state properly

spu_log.success("SPU rewind image has been saved in memory. (%d free slots left)", std::count_if(rewind_captures.begin(), rewind_captures.end(), FN(!x.operator bool())));
return true;
}

bool spu_thread::try_load_debug_capture()
{
if (cpu_flag::wait - state)
{
return false;
}

auto rewind = std::move(rewind_captures[(current_rewind_capture_idx - 1) % rewind_captures.size()]);

if (!rewind)
{
return false;
}

rewind->set_reading_state();
(*rewind)(std::span(ls, SPU_LS_SIZE)); // span serialization doesn't remember size which is what we need
serialize_common(*rewind);
current_rewind_capture_idx--;

spu_log.success("Last SPU rewind image has been loaded.");
return true;
}

Expand Down
6 changes: 5 additions & 1 deletion rpcs3/Emu/Cell/SPUThread.h
Expand Up @@ -813,7 +813,11 @@ class spu_thread : public cpu_thread

void fast_call(u32 ls_addr);

bool capture_local_storage() const;
std::array<std::shared_ptr<utils::serial>, 32> rewind_captures; // shared_ptr to avoid header inclusion
u8 current_rewind_capture_idx = 0;

bool capture_state();
bool try_load_debug_capture();
void wakeup_delay(u32 div = 1) const;

// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type
Expand Down
16 changes: 15 additions & 1 deletion rpcs3/Emu/System.cpp
Expand Up @@ -678,7 +678,13 @@ game_boot_result Emulator::BootGame(const std::string& path, const std::string&

if (g_cfg.savestate.suspend_emu && m_ar)
{
fs::remove_file(path);
std::string old_path = path.substr(0, path.find_last_not_of(fs::delim));
old_path.insert(old_path.find_last_of(fs::delim) + 1, "old-"sv);

if (fs::rename(path, old_path, true))
{
sys_log.notice("Savestate has been moved to path='%s'", old_path);
}
}

return error;
Expand Down Expand Up @@ -2532,6 +2538,14 @@ std::shared_ptr<utils::serial> Emulator::Kill(bool allow_autoexit, bool savestat
}
else
{
std::string old_path = path.substr(0, path.find_last_not_of(fs::delim));
old_path.insert(old_path.find_last_of(fs::delim) + 1, "old-"sv);

if (fs::remove_file(old_path))
{
sys_log.success("Old savestate has been removed: path='%s'", old_path);
}

sys_log.success("Saved savestate! path='%s'", path);
}

Expand Down
16 changes: 15 additions & 1 deletion rpcs3/rpcs3qt/debugger_frame.cpp
Expand Up @@ -30,6 +30,7 @@
#include <QVBoxLayout>
#include <QTimer>
#include <QCheckBox>
#include <QMessageBox>
#include <charconv>

#include "util/asm.hpp"
Expand Down Expand Up @@ -324,6 +325,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
"\nKeys Ctrl+B: Open breakpoints settings."
"\nKeys Ctrl+S: Search memory string utility."
"\nKeys Alt+S: Capture SPU images of selected SPU."
"\nKeys Alt+R: Load last saved SPU state capture."
"\nKey D: SPU MFC commands logger, MFC debug setting must be enabled."
"\nKey D: Also PPU calling history logger, interpreter and non-zero call history size must be used."
"\nKey E: Instruction Editor: click on the instruction you want to modify, then press E."
Expand Down Expand Up @@ -594,6 +596,12 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)

if (cpu->id_type() == 1 || cpu->id_type() == 2)
{
if (cpu->id_type() == 2 && modifiers & Qt::AltModifier)
{
static_cast<spu_thread*>(cpu)->try_load_debug_capture();
return;
}

if (!m_reg_editor)
{
m_reg_editor = new register_editor_dialog(this, m_disasm.get(), make_check_cpu(cpu));
Expand All @@ -615,7 +623,13 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
return;
}

static_cast<spu_thread*>(cpu)->capture_local_storage();
if (!cpu->state.all_of(cpu_flag::wait + cpu_flag::dbg_pause))
{
QMessageBox::warning(this, QObject::tr("Pause the SPU Thread!"), QObject::tr("Cannot perform SPU capture due to the thread need manual pausing!"));
return;
}

static_cast<spu_thread*>(cpu)->capture_state();
}
return;
}
Expand Down