mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-12 17:58:37 +12:00
Savestates/SPU: Complete fix for saving sys_spu_thread_receive_event
This commit is contained in:
parent
ab27ee4cf4
commit
cdd6840826
5 changed files with 84 additions and 33 deletions
|
@ -4790,6 +4790,12 @@ bool spu_thread::stop_and_signal(u32 code)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Emu.IsStarting())
|
||||||
|
{
|
||||||
|
// Deregister lv2_obj::g_to_sleep entry (savestates related)
|
||||||
|
lv2_obj::sleep(*this);
|
||||||
|
}
|
||||||
|
|
||||||
if (group->run_state >= SPU_THREAD_GROUP_STATUS_WAITING && group->run_state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED)
|
if (group->run_state >= SPU_THREAD_GROUP_STATUS_WAITING && group->run_state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED)
|
||||||
{
|
{
|
||||||
// Try again
|
// Try again
|
||||||
|
|
|
@ -1233,6 +1233,30 @@ void lv2_obj::sleep_unlocked(cpu_thread& thread, u64 timeout)
|
||||||
{
|
{
|
||||||
const u64 start_time = get_guest_system_time();
|
const u64 start_time = get_guest_system_time();
|
||||||
|
|
||||||
|
auto on_to_sleep_update = [&]()
|
||||||
|
{
|
||||||
|
std::string out = fmt::format("Threads (%d):", g_to_sleep.size());
|
||||||
|
for (auto thread : g_to_sleep)
|
||||||
|
{
|
||||||
|
fmt::append(out, " 0x%x,", thread->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ppu_log.warning("%s", out);
|
||||||
|
|
||||||
|
if (g_to_sleep.empty())
|
||||||
|
{
|
||||||
|
// All threads are ready, wake threads
|
||||||
|
Emu.CallFromMainThread([]
|
||||||
|
{
|
||||||
|
if (Emu.IsStarting())
|
||||||
|
{
|
||||||
|
// It uses lv2_obj::g_mutex, run it on main thread
|
||||||
|
Emu.FinalizeRunRequest();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (auto ppu = thread.try_get<ppu_thread>())
|
if (auto ppu = thread.try_get<ppu_thread>())
|
||||||
{
|
{
|
||||||
ppu_log.trace("sleep() - waiting (%zu)", g_pending.size());
|
ppu_log.trace("sleep() - waiting (%zu)", g_pending.size());
|
||||||
|
@ -1260,27 +1284,7 @@ void lv2_obj::sleep_unlocked(cpu_thread& thread, u64 timeout)
|
||||||
if (unqueue(g_to_sleep, ppu))
|
if (unqueue(g_to_sleep, ppu))
|
||||||
{
|
{
|
||||||
ppu->start_time = start_time;
|
ppu->start_time = start_time;
|
||||||
|
on_to_sleep_update();
|
||||||
std::string out = fmt::format("Threads (%d):", g_to_sleep.size());
|
|
||||||
for (auto thread : g_to_sleep)
|
|
||||||
{
|
|
||||||
fmt::append(out, " 0x%x,", thread->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
ppu_log.warning("%s", out);
|
|
||||||
|
|
||||||
if (g_to_sleep.empty())
|
|
||||||
{
|
|
||||||
// All threads are ready, wake threads
|
|
||||||
Emu.CallFromMainThread([]
|
|
||||||
{
|
|
||||||
if (Emu.IsStarting())
|
|
||||||
{
|
|
||||||
// It uses lv2_obj::g_mutex, run it on main thread
|
|
||||||
Emu.FinalizeRunRequest();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Already sleeping
|
// Already sleeping
|
||||||
|
@ -1293,6 +1297,13 @@ void lv2_obj::sleep_unlocked(cpu_thread& thread, u64 timeout)
|
||||||
ppu->raddr = 0; // Clear reservation
|
ppu->raddr = 0; // Clear reservation
|
||||||
ppu->start_time = start_time;
|
ppu->start_time = start_time;
|
||||||
}
|
}
|
||||||
|
else if (auto spu = thread.try_get<spu_thread>())
|
||||||
|
{
|
||||||
|
if (unqueue(g_to_sleep, spu))
|
||||||
|
{
|
||||||
|
on_to_sleep_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (timeout)
|
if (timeout)
|
||||||
{
|
{
|
||||||
|
@ -1551,9 +1562,9 @@ ppu_thread_status lv2_obj::ppu_state(ppu_thread* ppu, bool lock_idm, bool lock_l
|
||||||
return PPU_THREAD_STATUS_ONPROC;
|
return PPU_THREAD_STATUS_ONPROC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lv2_obj::set_future_sleep(ppu_thread* ppu)
|
void lv2_obj::set_future_sleep(cpu_thread* cpu)
|
||||||
{
|
{
|
||||||
g_to_sleep.emplace_back(ppu);
|
g_to_sleep.emplace_back(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lv2_obj::is_scheduler_ready()
|
bool lv2_obj::is_scheduler_ready()
|
||||||
|
|
|
@ -228,7 +228,7 @@ lv2_spu_group::lv2_spu_group(utils::serial& ar) noexcept
|
||||||
*ep = idm::get_unlocked<lv2_obj, lv2_event_queue>(ar.operator u32());
|
*ep = idm::get_unlocked<lv2_obj, lv2_event_queue>(ar.operator u32());
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 waiter_spu_index = -1;
|
waiter_spu_index = -1;
|
||||||
|
|
||||||
switch (run_state)
|
switch (run_state)
|
||||||
{
|
{
|
||||||
|
@ -256,15 +256,20 @@ lv2_spu_group::lv2_spu_group(utils::serial& ar) noexcept
|
||||||
// Suspend all SPU threads except a thread that waits on sys_spu_thread_receive_event
|
// Suspend all SPU threads except a thread that waits on sys_spu_thread_receive_event
|
||||||
for (const auto& thread : threads)
|
for (const auto& thread : threads)
|
||||||
{
|
{
|
||||||
if (thread && thread->index != waiter_spu_index)
|
if (thread)
|
||||||
{
|
{
|
||||||
|
if (thread->index == waiter_spu_index)
|
||||||
|
{
|
||||||
|
lv2_obj::set_future_sleep(thread.get());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
thread->state += cpu_flag::suspend;
|
thread->state += cpu_flag::suspend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//case SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED:
|
|
||||||
//case SPU_THREAD_GROUP_STATUS_RUNNING:
|
//case SPU_THREAD_GROUP_STATUS_RUNNING:
|
||||||
//case SPU_THREAD_GROUP_STATUS_STOPPED:
|
//case SPU_THREAD_GROUP_STATUS_STOPPED:
|
||||||
//case SPU_THREAD_GROUP_STATUS_UNKNOWN:
|
//case SPU_THREAD_GROUP_STATUS_UNKNOWN:
|
||||||
|
|
|
@ -200,7 +200,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialization related
|
// Serialization related
|
||||||
static void set_future_sleep(ppu_thread* ppu);
|
static void set_future_sleep(cpu_thread* cpu);
|
||||||
static bool is_scheduler_ready();
|
static bool is_scheduler_ready();
|
||||||
|
|
||||||
static void cleanup();
|
static void cleanup();
|
||||||
|
@ -450,7 +450,7 @@ private:
|
||||||
static std::deque<std::pair<u64, class cpu_thread*>> g_waiting;
|
static std::deque<std::pair<u64, class cpu_thread*>> g_waiting;
|
||||||
|
|
||||||
// Threads which must call lv2_obj::sleep before the scheduler starts
|
// Threads which must call lv2_obj::sleep before the scheduler starts
|
||||||
static std::deque<class ppu_thread*> g_to_sleep;
|
static std::deque<class cpu_thread*> g_to_sleep;
|
||||||
|
|
||||||
static void schedule_all();
|
static void schedule_all();
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "Emu/Cell/lv2/sys_sync.h"
|
#include "Emu/Cell/lv2/sys_sync.h"
|
||||||
#include "Emu/Cell/lv2/sys_prx.h"
|
#include "Emu/Cell/lv2/sys_prx.h"
|
||||||
#include "Emu/Cell/lv2/sys_overlay.h"
|
#include "Emu/Cell/lv2/sys_overlay.h"
|
||||||
|
#include "Emu/Cell/lv2/sys_spu.h"
|
||||||
#include "Emu/Cell/Modules/cellGame.h"
|
#include "Emu/Cell/Modules/cellGame.h"
|
||||||
|
|
||||||
#include "Emu/title.h"
|
#include "Emu/title.h"
|
||||||
|
@ -1955,11 +1956,30 @@ void Emulator::RunPPU()
|
||||||
// Run main thread
|
// Run main thread
|
||||||
idm::select<named_thread<ppu_thread>>([](u32, named_thread<ppu_thread>& cpu)
|
idm::select<named_thread<ppu_thread>>([](u32, named_thread<ppu_thread>& cpu)
|
||||||
{
|
{
|
||||||
if (cpu.stop_flag_removal_protection) return;
|
if (std::exchange(cpu.stop_flag_removal_protection, false))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ensure(cpu.state.test_and_reset(cpu_flag::stop));
|
ensure(cpu.state.test_and_reset(cpu_flag::stop));
|
||||||
cpu.state.notify_one(cpu_flag::stop);
|
cpu.state.notify_one(cpu_flag::stop);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Run SPUs waiting on a syscall (savestates related)
|
||||||
|
idm::select<named_thread<spu_thread>>([](u32, named_thread<spu_thread>& spu)
|
||||||
|
{
|
||||||
|
if (spu.group && spu.index == spu.group->waiter_spu_index)
|
||||||
|
{
|
||||||
|
if (std::exchange(spu.stop_flag_removal_protection, false))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure(spu.state.test_and_reset(cpu_flag::stop));
|
||||||
|
spu.state.notify_one(cpu_flag::stop);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (auto thr = g_fxo->try_get<named_thread<rsx::rsx_replay_thread>>())
|
if (auto thr = g_fxo->try_get<named_thread<rsx::rsx_replay_thread>>())
|
||||||
{
|
{
|
||||||
thr->state -= cpu_flag::stop;
|
thr->state -= cpu_flag::stop;
|
||||||
|
@ -1992,11 +2012,20 @@ void Emulator::FixGuestTime()
|
||||||
}
|
}
|
||||||
void Emulator::FinalizeRunRequest()
|
void Emulator::FinalizeRunRequest()
|
||||||
{
|
{
|
||||||
auto on_select = [] (u32, spu_thread& cpu)
|
auto on_select = [](u32, spu_thread& spu)
|
||||||
{
|
{
|
||||||
if (cpu.stop_flag_removal_protection) return;
|
if (spu.group && spu.index == spu.group->waiter_spu_index)
|
||||||
ensure(cpu.state.test_and_reset(cpu_flag::stop));
|
{
|
||||||
cpu.state.notify_one(cpu_flag::stop);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::exchange(spu.stop_flag_removal_protection, false))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure(spu.state.test_and_reset(cpu_flag::stop));
|
||||||
|
spu.state.notify_one(cpu_flag::stop);
|
||||||
};
|
};
|
||||||
|
|
||||||
idm::select<named_thread<spu_thread>>(on_select);
|
idm::select<named_thread<spu_thread>>(on_select);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue