mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-28 13:28:01 +03:00
RSX/Savestates: Replace GCM hack with a proper fix
This commit is contained in:
parent
f0c71ae2ae
commit
5f8f9e33f1
8 changed files with 61 additions and 79 deletions
|
@ -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.
|
// If we fail due to being busy, wait a bit and try again.
|
||||||
while (static_cast<u32>(sending_error) == CELL_EBUSY)
|
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())
|
if (cpu->is_stopped())
|
||||||
{
|
{
|
||||||
sending_error = {};
|
sending_error = {};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_ctrl::wait_for(1000);
|
|
||||||
sending_error = sys_event_port_send(pf_port_id, data1, data2, data3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sending_error)
|
if (sending_error)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Utilities/JIT.h"
|
#include "Utilities/JIT.h"
|
||||||
#include "Utilities/date_time.h"
|
#include "Utilities/date_time.h"
|
||||||
#include "Emu/Memory/vm.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
|
, 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);
|
, 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);
|
ar(ch_dec_start_timestamp, ch_dec_value, is_dec_frozen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
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())
|
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))
|
if (is_stopped(state))
|
||||||
{
|
{
|
||||||
extern void signal_gcm_intr_thread_offline(lv2_event_queue&);
|
std::lock_guard lock_rsx(queue->mutex);
|
||||||
signal_gcm_intr_thread_offline(*queue);
|
|
||||||
|
if (std::find(queue->sq.begin(), queue->sq.end(), &ppu) == queue->sq.end())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppu.state += cpu_flag::again;
|
||||||
return {};
|
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)
|
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)
|
if (port.ret == CELL_EBUSY)
|
||||||
|
|
|
@ -37,7 +37,7 @@ u64 rsxTimeStamp()
|
||||||
return get_timebased_time();
|
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
|
// 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
|
// 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)
|
if (!event_flags)
|
||||||
{
|
{
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto error = sys_event_port_send(rsx_event_port, data1, event_flags, data3);
|
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);
|
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);
|
fmt::throw_exception("rsx::thread::send_event() Failed to send event! (error=%x)", +error);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true on success of receiving the event
|
return true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_code sys_rsx_device_open(cpu_thread& cpu)
|
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);
|
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);
|
||||||
|
|
||||||
render->on_frame_end(static_cast<u32>(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)
|
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
|
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
|
// we only ever use head 1 for now
|
||||||
driverInfo.head[1].flipFlags |= 0x80000000;
|
driverInfo.head[1].flipFlags |= 0x80000000;
|
||||||
driverInfo.head[1].lastFlipTime = rsxTimeStamp(); // should rsxthread set this?
|
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
|
// NOTE: There currently seem to only be 2 active heads on PS3
|
||||||
ensure(a3 < 2);
|
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
|
// 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)
|
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
|
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
|
// 'custom' invalid package id for now
|
||||||
// as i think we need custom lv1 interrupts to handle this accurately
|
// as i think we need custom lv1 interrupts to handle this accurately
|
||||||
// this also should probly be set by rsxthread
|
// this also should probly be set by rsxthread
|
||||||
|
|
|
@ -453,6 +453,11 @@ namespace rsx
|
||||||
ar(device_addr, label_addr, main_mem_size, local_mem_size, rsx_event_port, driver_info);
|
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(in_begin_end, zcull_stats_enabled, zcull_rendering_enabled, zcull_pixel_cnt_enabled);
|
||||||
ar(display_buffers, display_buffers_count, current_display_buffer);
|
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)
|
thread::thread(utils::serial* _ar)
|
||||||
|
@ -756,6 +761,14 @@ namespace rsx
|
||||||
|
|
||||||
vblank_count = 0;
|
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]()
|
g_fxo->init<named_thread>("VBlank Thread", [this]()
|
||||||
{
|
{
|
||||||
// See sys_timer_usleep for details
|
// See sys_timer_usleep for details
|
||||||
|
@ -772,7 +785,7 @@ namespace rsx
|
||||||
u64 local_vblank_count = 0;
|
u64 local_vblank_count = 0;
|
||||||
|
|
||||||
// TODO: exit condition
|
// TODO: exit condition
|
||||||
while (!is_stopped())
|
while (!is_stopped() && !unsent_gcm_events)
|
||||||
{
|
{
|
||||||
// Get current time
|
// Get current time
|
||||||
const u64 current = get_system_time();
|
const u64 current = get_system_time();
|
||||||
|
@ -3407,6 +3420,13 @@ namespace rsx
|
||||||
if (!isHLE)
|
if (!isHLE)
|
||||||
{
|
{
|
||||||
sys_rsx_context_attribute(0x55555555, 0xFEC, buffer, 0, 0, 0);
|
sys_rsx_context_attribute(0x55555555, 0xFEC, buffer, 0, 0, 0);
|
||||||
|
|
||||||
|
if (unsent_gcm_events)
|
||||||
|
{
|
||||||
|
// TODO: A proper fix
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -584,9 +584,10 @@ namespace rsx
|
||||||
u32 local_mem_size{0};
|
u32 local_mem_size{0};
|
||||||
u32 rsx_event_port{0};
|
u32 rsx_event_port{0};
|
||||||
u32 driver_info{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;
|
bool m_rtts_dirty = true;
|
||||||
std::array<bool, 16> m_textures_dirty;
|
std::array<bool, 16> m_textures_dirty;
|
||||||
|
|
|
@ -67,8 +67,8 @@ u64 g_rtm_tx_limit2 = 0;
|
||||||
struct serial_ver_t
|
struct serial_ver_t
|
||||||
{
|
{
|
||||||
bool used = false;
|
bool used = false;
|
||||||
u32 current_version = 0;
|
s32 current_version = 0;
|
||||||
std::set<u32> compatible_versions;
|
std::set<s32> compatible_versions;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::array<serial_ver_t, 23> s_serial_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;\
|
::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;\
|
return ::s_serial_versions[identifier].current_version;\
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ SERIALIZATION_VER(lv2_config, 9, 1)
|
||||||
|
|
||||||
namespace rsx
|
namespace rsx
|
||||||
{
|
{
|
||||||
SERIALIZATION_VER(rsx, 10, 1)
|
SERIALIZATION_VER(rsx, 10, 1, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace np
|
namespace np
|
||||||
|
@ -111,7 +111,7 @@ namespace np
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// Compiler bug, lambda function body does seem to inherit used namespace atleast for function decleration
|
// 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)
|
SERIALIZATION_VER(sceNp, 11, 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1118,7 +1118,7 @@ extern bool serialize(utils::serial& ar, T& obj);
|
||||||
|
|
||||||
#define GET_SERIALIZATION_VERSION(name) []()\
|
#define GET_SERIALIZATION_VERSION(name) []()\
|
||||||
{\
|
{\
|
||||||
extern u32 get_##name##_serialization_version();\
|
extern s32 get_##name##_serialization_version();\
|
||||||
return get_##name##_serialization_version();\
|
return get_##name##_serialization_version();\
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue