mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-11 06:40:39 +00:00
Savestates: Save PPU running order
This commit is contained in:
parent
4dff8b16f1
commit
68349e48cd
@ -2390,6 +2390,12 @@ void ppu_thread::serialize_common(utils::serial& ar)
|
||||
}
|
||||
}
|
||||
|
||||
struct save_lv2_tag
|
||||
{
|
||||
atomic_t<bool> saved = false;
|
||||
atomic_t<bool> loaded = false;
|
||||
};
|
||||
|
||||
ppu_thread::ppu_thread(utils::serial& ar)
|
||||
: cpu_thread(idm::last_id()) // last_id() is showed to constructor on serialization
|
||||
, stack_size(ar)
|
||||
@ -2398,6 +2404,8 @@ ppu_thread::ppu_thread(utils::serial& ar)
|
||||
, entry_func(std::bit_cast<ppu_func_opd_t, u64>(ar))
|
||||
, is_interrupt_thread(ar)
|
||||
{
|
||||
[[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(ppu);
|
||||
|
||||
struct init_pushed
|
||||
{
|
||||
bool pushed = false;
|
||||
@ -2408,6 +2416,11 @@ ppu_thread::ppu_thread(utils::serial& ar)
|
||||
syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1);
|
||||
syscall_history.count_debug_arguments = static_cast<u32>(g_cfg.core.ppu_call_history ? std::size(syscall_history.data[0].args) : 0);
|
||||
|
||||
if (version >= 2 && !g_fxo->get<save_lv2_tag>().loaded.exchange(true))
|
||||
{
|
||||
ar(lv2_obj::g_priority_order_tag);
|
||||
}
|
||||
|
||||
serialize_common(ar);
|
||||
|
||||
// Restore jm_mask
|
||||
@ -2437,7 +2450,41 @@ ppu_thread::ppu_thread(utils::serial& ar)
|
||||
case PPU_THREAD_STATUS_RUNNABLE:
|
||||
case PPU_THREAD_STATUS_ONPROC:
|
||||
{
|
||||
lv2_obj::awake(this);
|
||||
if (version >= 2)
|
||||
{
|
||||
const u32 order = ar.pop<u32>();
|
||||
|
||||
struct awake_pushed
|
||||
{
|
||||
bool pushed = false;
|
||||
shared_mutex dummy;
|
||||
std::map<u32, ppu_thread*> awake_ppus;
|
||||
};
|
||||
|
||||
g_fxo->get<awake_pushed>().awake_ppus[order] = this;
|
||||
|
||||
if (!std::exchange(g_fxo->get<awake_pushed>().pushed, true))
|
||||
{
|
||||
Emu.PostponeInitCode([this]()
|
||||
{
|
||||
u32 prev = umax;
|
||||
|
||||
for (auto ppu : g_fxo->get<awake_pushed>().awake_ppus)
|
||||
{
|
||||
ensure(prev + 1 == ppu.first);
|
||||
prev = ppu.first;
|
||||
lv2_obj::awake(ppu.second);
|
||||
}
|
||||
|
||||
g_fxo->get<awake_pushed>().awake_ppus.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lv2_obj::awake(this);
|
||||
}
|
||||
|
||||
[[fallthrough]];
|
||||
}
|
||||
case PPU_THREAD_STATUS_SLEEP:
|
||||
@ -2485,6 +2532,7 @@ ppu_thread::ppu_thread(utils::serial& ar)
|
||||
const u32 op = vm::read32(ppu.cia);
|
||||
const auto& table = g_fxo->get<ppu_interpreter_rt>();
|
||||
ppu.loaded_from_savestate = true;
|
||||
ppu.prio.raw().preserve_bit = 1;
|
||||
table.decode(op)(ppu, {op}, vm::_ptr<u32>(ppu.cia), &ppu_ret);
|
||||
|
||||
ppu.optional_savestate_state->clear(); // Reset to writing state
|
||||
@ -2539,9 +2587,17 @@ void ppu_thread::save(utils::serial& ar)
|
||||
}
|
||||
|
||||
ar(stack_size, stack_addr, _joiner, entry, is_interrupt_thread);
|
||||
|
||||
const bool is_null = ar.m_file_handler && ar.m_file_handler->is_null();
|
||||
|
||||
if (!is_null && !g_fxo->get<save_lv2_tag>().saved.exchange(true))
|
||||
{
|
||||
ar(lv2_obj::g_priority_order_tag);
|
||||
}
|
||||
|
||||
serialize_common(ar);
|
||||
|
||||
ppu_thread_status status = lv2_obj::ppu_state(this, false);
|
||||
auto [status, order] = lv2_obj::ppu_state(this, false);
|
||||
|
||||
if (status == PPU_THREAD_STATUS_SLEEP && cpu_flag::again - state)
|
||||
{
|
||||
@ -2551,6 +2607,11 @@ void ppu_thread::save(utils::serial& ar)
|
||||
|
||||
ar(status);
|
||||
|
||||
if (status == PPU_THREAD_STATUS_RUNNABLE || status == PPU_THREAD_STATUS_ONPROC)
|
||||
{
|
||||
ar(order);
|
||||
}
|
||||
|
||||
ar(*ppu_tname.load());
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,8 @@ public:
|
||||
{
|
||||
u64 all;
|
||||
bf_t<s64, 0, 13> prio; // Thread priority (0..3071) (firs 12-bits)
|
||||
bf_t<s64, 13, 51> order; // Thread enqueue order (last 52-bits)
|
||||
bf_t<s64, 13, 50> order; // Thread enqueue order (last 52-bits)
|
||||
bf_t<u64, 63, 1> preserve_bit; // Preserve value for savestates
|
||||
};
|
||||
|
||||
atomic_t<ppu_prio_t> prio{};
|
||||
|
@ -1946,7 +1946,7 @@ void lv2_obj::make_scheduler_ready()
|
||||
lv2_obj::awake_all();
|
||||
}
|
||||
|
||||
ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_lv2)
|
||||
std::pair<ppu_thread_status, u32> lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_lv2)
|
||||
{
|
||||
std::optional<reader_lock> opt_lock[2];
|
||||
|
||||
@ -1957,13 +1957,13 @@ ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_l
|
||||
|
||||
if (!Emu.IsReady() ? ppu->state.all_of(cpu_flag::stop) : ppu->stop_flag_removal_protection)
|
||||
{
|
||||
return PPU_THREAD_STATUS_IDLE;
|
||||
return { PPU_THREAD_STATUS_IDLE, 0};
|
||||
}
|
||||
|
||||
switch (ppu->joiner)
|
||||
{
|
||||
case ppu_join_status::zombie: return PPU_THREAD_STATUS_ZOMBIE;
|
||||
case ppu_join_status::exited: return PPU_THREAD_STATUS_DELETED;
|
||||
case ppu_join_status::zombie: return { PPU_THREAD_STATUS_ZOMBIE, 0};
|
||||
case ppu_join_status::exited: return { PPU_THREAD_STATUS_DELETED, 0};
|
||||
default: break;
|
||||
}
|
||||
|
||||
@ -1988,18 +1988,18 @@ ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_l
|
||||
{
|
||||
if (!ppu->interrupt_thread_executing)
|
||||
{
|
||||
return PPU_THREAD_STATUS_STOP;
|
||||
return { PPU_THREAD_STATUS_STOP, 0};
|
||||
}
|
||||
|
||||
return PPU_THREAD_STATUS_SLEEP;
|
||||
return { PPU_THREAD_STATUS_SLEEP, 0 };
|
||||
}
|
||||
|
||||
if (pos >= g_cfg.core.ppu_threads + 0u)
|
||||
{
|
||||
return PPU_THREAD_STATUS_RUNNABLE;
|
||||
return { PPU_THREAD_STATUS_RUNNABLE, pos };
|
||||
}
|
||||
|
||||
return PPU_THREAD_STATUS_ONPROC;
|
||||
return { PPU_THREAD_STATUS_ONPROC, pos};
|
||||
}
|
||||
|
||||
void lv2_obj::set_future_sleep(cpu_thread* cpu)
|
||||
|
@ -239,6 +239,16 @@ public:
|
||||
|
||||
object->prio.atomic_op([order = ++g_priority_order_tag](std::common_type_t<decltype(std::declval<T>()->prio.load())>& prio)
|
||||
{
|
||||
if constexpr (requires { +std::declval<decltype(prio)>().preserve_bit; } )
|
||||
{
|
||||
if (prio.preserve_bit)
|
||||
{
|
||||
// Restoring state on load
|
||||
prio.preserve_bit = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
prio.order = order;
|
||||
});
|
||||
}
|
||||
@ -274,7 +284,7 @@ public:
|
||||
|
||||
static void make_scheduler_ready();
|
||||
|
||||
static ppu_thread_status ppu_state(ppu_thread* ppu, bool lock_idm = true, bool lock_lv2 = true);
|
||||
static std::pair<ppu_thread_status, u32> ppu_state(ppu_thread* ppu, bool lock_idm = true, bool lock_lv2 = true);
|
||||
|
||||
static inline void append(cpu_thread* const thread)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ static std::array<serial_ver_t, 26> s_serial_versions;
|
||||
}
|
||||
|
||||
SERIALIZATION_VER(global_version, 0, 16) // For stuff not listed here
|
||||
SERIALIZATION_VER(ppu, 1, 1)
|
||||
SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep order*/)
|
||||
SERIALIZATION_VER(spu, 2, 1)
|
||||
SERIALIZATION_VER(lv2_sync, 3, 1)
|
||||
SERIALIZATION_VER(lv2_vm, 4, 1)
|
||||
|
@ -655,7 +655,7 @@ void kernel_explorer::update()
|
||||
idm::select<named_thread<ppu_thread>>([&](u32 id, ppu_thread& ppu)
|
||||
{
|
||||
const auto func = ppu.last_function;
|
||||
const ppu_thread_status status = lv2_obj::ppu_state(&ppu, false, false);
|
||||
const ppu_thread_status status = lv2_obj::ppu_state(&ppu, false, false).first;
|
||||
|
||||
add_leaf(find_node(root, additional_nodes::ppu_threads), qstr(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, Status: %s, State: %s, %s func: “%s”%s", id, *ppu.ppu_tname.load(), ppu.prio.load().prio, ppu.joiner.load(), status, ppu.state.load()
|
||||
, ppu.ack_suspend ? "After" : (ppu.current_function ? "In" : "Last"), func ? func : "", get_wait_time_str(ppu.start_time))));
|
||||
|
Loading…
x
Reference in New Issue
Block a user