1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-25 04:02:42 +01:00

RSX/Savestates: Replace GCM hack with a proper fix

This commit is contained in:
Eladash 2022-07-07 10:35:24 +03:00 committed by Ivan
parent f0c71ae2ae
commit 5f8f9e33f1
8 changed files with 61 additions and 79 deletions

View File

@ -1536,14 +1536,14 @@ bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noe
// If we fail due to being busy, wait a bit and try again.
while (static_cast<u32>(sending_error) == CELL_EBUSY)
{
thread_ctrl::wait_for(1000);
sending_error = sys_event_port_send(pf_port_id, data1, data2, data3);
if (cpu->is_stopped())
{
sending_error = {};
break;
}
thread_ctrl::wait_for(1000);
sending_error = sys_event_port_send(pf_port_id, data1, data2, data3);
}
if (sending_error)

View File

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Utilities/JIT.h"
#include "Utilities/date_time.h"
#include "Emu/Memory/vm.h"
@ -1704,7 +1704,7 @@ void spu_thread::serialize_common(utils::serial& ar)
, ch_out_mbox.data, ch_out_intr_mbox.data, snr_config, ch_snr1.data, ch_snr2.data, ch_events.raw().all, interrupts_enabled
, run_ctrl, exit_status.data, status_npc.raw().status);
if (GET_SERIALIZATION_VERSION(spu) != 1u)
if (GET_SERIALIZATION_VERSION(spu) != 1)
{
ar(ch_dec_start_timestamp, ch_dec_value, is_dec_frozen);
}

View File

@ -239,7 +239,7 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
const auto queue = idm::withdraw<lv2_obj, lv2_event_queue>(equeue_id, [&](lv2_event_queue& queue) -> CellError
{
qlock.lock(queue.mutex);
qlock = std::unique_lock{queue.mutex};
if (!mode && !queue.sq.empty())
{
@ -456,8 +456,14 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
if (is_stopped(state))
{
extern void signal_gcm_intr_thread_offline(lv2_event_queue&);
signal_gcm_intr_thread_offline(*queue);
std::lock_guard lock_rsx(queue->mutex);
if (std::find(queue->sq.begin(), queue->sq.end(), &ppu) == queue->sq.end())
{
break;
}
ppu.state += cpu_flag::again;
return {};
}
@ -686,7 +692,8 @@ error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
{
if (port.ret == CELL_EAGAIN)
{
return CELL_OK;
// Not really an error code exposed to games (thread has raised cpu_flag::again)
return not_an_error(CELL_EAGAIN);
}
if (port.ret == CELL_EBUSY)

View File

@ -37,7 +37,7 @@ u64 rsxTimeStamp()
return get_timebased_time();
}
void rsx::thread::send_event(u64 data1, u64 event_flags, u64 data3) const
bool rsx::thread::send_event(u64 data1, u64 event_flags, u64 data3)
{
// Filter event bits, send them only if they are masked by gcm
// Except the upper 32-bits, they are reserved for unmapped io events and execute unconditionally
@ -46,7 +46,7 @@ void rsx::thread::send_event(u64 data1, u64 event_flags, u64 data3) const
if (!event_flags)
{
// Nothing to do
return;
return true;
}
auto error = sys_event_port_send(rsx_event_port, data1, event_flags, data3);
@ -76,35 +76,19 @@ void rsx::thread::send_event(u64 data1, u64 event_flags, u64 data3) const
error = sys_event_port_send(rsx_event_port, data1, event_flags, data3);
}
if (!Emu.IsPaused() && error && error + 0u != CELL_ENOTCONN)
if (error + 0u == CELL_EAGAIN)
{
// Thread has aborted when sending event (VBLANK duplicates are allowed)
ensure((unsent_gcm_events.fetch_or(event_flags) & event_flags & ~(SYS_RSX_EVENT_VBLANK | SYS_RSX_EVENT_SECOND_VBLANK_BASE | SYS_RSX_EVENT_SECOND_VBLANK_BASE * 2)) == 0);
return false;
}
if (error && error + 0u != CELL_ENOTCONN)
{
fmt::throw_exception("rsx::thread::send_event() Failed to send event! (error=%x)", +error);
}
}
// Returns true on success of receiving the event
void signal_gcm_intr_thread_offline(lv2_event_queue& q)
{
const auto render = rsx::get_current_renderer();
const auto cpu = cpu_thread::get_current();
static shared_mutex s_dummy;
std::scoped_lock lock_rsx(render ? render->sys_rsx_mtx : s_dummy, q.mutex);
if (std::find(q.sq.begin(), q.sq.end(), cpu) == q.sq.end())
{
return;
}
cpu->state += cpu_flag::again;
if (!vm::check_addr(render->driver_info) || vm::_ref<RsxDriverInfo>(render->driver_info).handler_queue != q.id)
{
return;
}
render->gcm_intr_thread_offline = true;
return true;
}
error_code sys_rsx_device_open(cpu_thread& cpu)
@ -534,7 +518,10 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);
render->on_frame_end(static_cast<u32>(a4));
render->send_event(0, SYS_RSX_EVENT_QUEUE_BASE << a3, 0);
if (!render->send_event(0, SYS_RSX_EVENT_QUEUE_BASE << a3, 0))
{
break;
}
if (g_cfg.video.frame_limit == frame_limit_type::infinite)
{
@ -780,19 +767,6 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
case 0xFEC: // hack: flip event notification
{
reader_lock lock(render->sys_rsx_mtx);
if (render->gcm_intr_thread_offline)
{
if (auto cpu = get_current_cpu_thread())
{
cpu->state += cpu_flag::exit;
cpu->state += cpu_flag::again;
}
break;
}
// we only ever use head 1 for now
driverInfo.head[1].flipFlags |= 0x80000000;
driverInfo.head[1].lastFlipTime = rsxTimeStamp(); // should rsxthread set this?
@ -817,13 +791,6 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
// NOTE: There currently seem to only be 2 active heads on PS3
ensure(a3 < 2);
reader_lock lock(render->sys_rsx_mtx);
if (render->gcm_intr_thread_offline)
{
break;
}
// todo: this is wrong and should be 'second' vblank handler and freq, but since currently everything is reported as being 59.94, this should be fine
driverInfo.head[a3].lastSecondVTime.atomic_op([&](be_t<u64>& time)
{
@ -852,19 +819,6 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
case 0xFEF: // hack: user command
{
reader_lock lock(render->sys_rsx_mtx);
if (render->gcm_intr_thread_offline)
{
if (auto cpu = get_current_cpu_thread())
{
cpu->state += cpu_flag::exit;
cpu->state += cpu_flag::again;
}
break;
}
// 'custom' invalid package id for now
// as i think we need custom lv1 interrupts to handle this accurately
// this also should probly be set by rsxthread

View File

@ -453,6 +453,11 @@ namespace rsx
ar(device_addr, label_addr, main_mem_size, local_mem_size, rsx_event_port, driver_info);
ar(in_begin_end, zcull_stats_enabled, zcull_rendering_enabled, zcull_pixel_cnt_enabled);
ar(display_buffers, display_buffers_count, current_display_buffer);
if (ar.is_writing() || GET_SERIALIZATION_VERSION(rsx) != 1u)
{
ar(unsent_gcm_events);
}
}
thread::thread(utils::serial* _ar)
@ -756,6 +761,14 @@ namespace rsx
vblank_count = 0;
if (u64 event_flags = unsent_gcm_events.exchange(0))
{
if (!send_event(0, event_flags, 0))
{
return;
}
}
g_fxo->init<named_thread>("VBlank Thread", [this]()
{
// See sys_timer_usleep for details
@ -772,7 +785,7 @@ namespace rsx
u64 local_vblank_count = 0;
// TODO: exit condition
while (!is_stopped())
while (!is_stopped() && !unsent_gcm_events)
{
// Get current time
const u64 current = get_system_time();
@ -3407,6 +3420,13 @@ namespace rsx
if (!isHLE)
{
sys_rsx_context_attribute(0x55555555, 0xFEC, buffer, 0, 0, 0);
if (unsent_gcm_events)
{
// TODO: A proper fix
return;
}
continue;
}

View File

@ -584,9 +584,10 @@ namespace rsx
u32 local_mem_size{0};
u32 rsx_event_port{0};
u32 driver_info{0};
bool gcm_intr_thread_offline = false; // Hack for savestates
void send_event(u64, u64, u64) const;
atomic_t<u64> unsent_gcm_events = 0; // Unsent event bits when aborting RSX/VBLANK thread (will be sent on savestate load)
bool send_event(u64, u64, u64);
bool m_rtts_dirty = true;
std::array<bool, 16> m_textures_dirty;

View File

@ -67,8 +67,8 @@ u64 g_rtm_tx_limit2 = 0;
struct serial_ver_t
{
bool used = false;
u32 current_version = 0;
std::set<u32> compatible_versions;
s32 current_version = 0;
std::set<s32> compatible_versions;
};
static std::array<serial_ver_t, 23> s_serial_versions;
@ -83,7 +83,7 @@ static std::array<serial_ver_t, 23> s_serial_versions;
::s_serial_versions[identifier].used = true;\
}\
\
extern u32 get_##name##_serialization_version()\
extern s32 get_##name##_serialization_version()\
{\
return ::s_serial_versions[identifier].current_version;\
}
@ -101,7 +101,7 @@ SERIALIZATION_VER(lv2_config, 9, 1)
namespace rsx
{
SERIALIZATION_VER(rsx, 10, 1)
SERIALIZATION_VER(rsx, 10, 1, 2)
}
namespace np
@ -111,7 +111,7 @@ namespace np
#ifdef _MSC_VER
// Compiler bug, lambda function body does seem to inherit used namespace atleast for function decleration
SERIALIZATION_VER(rsx, 10, 1)
SERIALIZATION_VER(rsx, 10, 1, 2)
SERIALIZATION_VER(sceNp, 11, 1)
#endif

View File

@ -1118,7 +1118,7 @@ extern bool serialize(utils::serial& ar, T& obj);
#define GET_SERIALIZATION_VERSION(name) []()\
{\
extern u32 get_##name##_serialization_version();\
extern s32 get_##name##_serialization_version();\
return get_##name##_serialization_version();\
}()