Special functions for core serialization (#14317)

This commit is contained in:
Cthulhu-throwaway 2022-08-12 21:24:28 -03:00 committed by GitHub
parent 74ef6a0f4a
commit 2d1c238c1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 142 additions and 125 deletions

3
core.h
View File

@ -41,12 +41,15 @@ bool core_run(void);
bool core_reset(void); bool core_reset(void);
bool core_serialize_size(retro_ctx_size_info_t *info); bool core_serialize_size(retro_ctx_size_info_t *info);
bool core_serialize_size_special(retro_ctx_size_info_t *info);
uint64_t core_serialization_quirks(void); uint64_t core_serialization_quirks(void);
bool core_serialize(retro_ctx_serialize_info_t *info); bool core_serialize(retro_ctx_serialize_info_t *info);
bool core_serialize_special(retro_ctx_serialize_info_t *info);
bool core_unserialize(retro_ctx_serialize_info_t *info); bool core_unserialize(retro_ctx_serialize_info_t *info);
bool core_unserialize_special(retro_ctx_serialize_info_t *info);
bool core_set_cheat(retro_ctx_cheat_info_t *info); bool core_set_cheat(retro_ctx_cheat_info_t *info);

View File

@ -3578,17 +3578,11 @@ static bool netplay_sync_pre_frame(netplay_t *netplay)
if (!(netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)) if (!(netplay->quirks & NETPLAY_QUIRK_INITIALIZATION))
{ {
retro_ctx_serialize_info_t serial_info = {0}; retro_ctx_serialize_info_t serial_info = {0};
bool okay = false;
runloop_state_t *runloop_st = runloop_state_get_ptr();
serial_info.data = netplay->buffer[netplay->run_ptr].state; serial_info.data = netplay->buffer[netplay->run_ptr].state;
serial_info.size = netplay->state_size; serial_info.size = netplay->state_size;
memset(serial_info.data, 0, serial_info.size); memset(serial_info.data, 0, serial_info.size);
if (core_serialize_special(&serial_info))
runloop_st->request_fast_savestate = true;
okay = core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
if (okay)
{ {
if (netplay->force_send_savestate && !netplay->stall && if (netplay->force_send_savestate && !netplay->stall &&
!netplay->remote_paused) !netplay->remote_paused)
@ -3604,7 +3598,7 @@ static bool netplay_sync_pre_frame(netplay_t *netplay)
netplay->run_frame_count = netplay->self_frame_count; netplay->run_frame_count = netplay->self_frame_count;
} }
/* Send this along to the other side */ /* Send this along to the other side. */
serial_info.data_const = serial_info.data_const =
netplay->buffer[netplay->run_ptr].state; netplay->buffer[netplay->run_ptr].state;
@ -3789,8 +3783,6 @@ static void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
netplay->replay_frame_count < netplay->run_frame_count) netplay->replay_frame_count < netplay->run_frame_count)
{ {
retro_ctx_serialize_info_t serial_info; retro_ctx_serialize_info_t serial_info;
bool okay = false;
runloop_state_t *runloop_st = runloop_state_get_ptr();
/* Replay frames. */ /* Replay frames. */
netplay->is_replay = true; netplay->is_replay = true;
@ -3820,31 +3812,24 @@ static void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
serial_info.data = NULL; serial_info.data = NULL;
serial_info.data_const = netplay->buffer[netplay->replay_ptr].state; serial_info.data_const = netplay->buffer[netplay->replay_ptr].state;
serial_info.size = netplay->state_size; serial_info.size = netplay->state_size;
if (!core_unserialize_special(&serial_info))
runloop_st->request_fast_savestate = true;
okay = core_unserialize(&serial_info);
runloop_st->request_fast_savestate = false;
if (!okay)
{
RARCH_ERR("[Netplay] Netplay savestate loading failed: Prepare for desync!\n"); RARCH_ERR("[Netplay] Netplay savestate loading failed: Prepare for desync!\n");
}
while (netplay->replay_frame_count < netplay->run_frame_count) while (netplay->replay_frame_count < netplay->run_frame_count)
{ {
retro_time_t start, tm; retro_time_t start, tm;
struct delta_frame *ptr = &netplay->buffer[netplay->replay_ptr]; struct delta_frame *ptr = &netplay->buffer[netplay->replay_ptr];
serial_info.data_const = NULL;
serial_info.data = ptr->state; serial_info.data = ptr->state;
serial_info.size = netplay->state_size; serial_info.size = netplay->state_size;
serial_info.data_const = NULL;
start = cpu_features_get_time_usec(); start = cpu_features_get_time_usec();
/* Remember the current state */ /* Remember the current state */
memset(serial_info.data, 0, serial_info.size); memset(serial_info.data, 0, serial_info.size);
runloop_st->request_fast_savestate = true; core_serialize_special(&serial_info);
core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
if (netplay->replay_frame_count < netplay->unread_frame_count) if (netplay->replay_frame_count < netplay->unread_frame_count)
netplay_handle_frame_hash(netplay, ptr); netplay_handle_frame_hash(netplay, ptr);
@ -3869,12 +3854,12 @@ static void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
RARCH_LOG("INP %X %X\n", ptr->real_input_state[0], ptr->self_state[0]); RARCH_LOG("INP %X %X\n", ptr->real_input_state[0], ptr->self_state[0]);
else else
RARCH_LOG("INP %X %X\n", ptr->self_state[0], ptr->real_input_state[0]); RARCH_LOG("INP %X %X\n", ptr->self_state[0], ptr->real_input_state[0]);
ptr = &netplay->buffer[netplay->replay_ptr]; ptr = &netplay->buffer[netplay->replay_ptr];
serial_info.data = ptr->state; serial_info.data = ptr->state;
memset(serial_info.data, 0, serial_info.size); memset(serial_info.data, 0, serial_info.size);
runloop_st->request_fast_savestate = true; core_serialize_special(&serial_info);
core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay->state_size ? netplay_delta_frame_crc(netplay, ptr) : 0); RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay->state_size ? netplay_delta_frame_crc(netplay, ptr) : 0);
} }
#endif #endif
@ -6780,17 +6765,13 @@ static bool netplay_init_serialization(netplay_t *netplay)
{ {
size_t i; size_t i;
retro_ctx_size_info_t info = {0}; retro_ctx_size_info_t info = {0};
runloop_state_t *runloop_st = runloop_state_get_ptr();
if (netplay->state_size) if (netplay->state_size)
return true; return true;
runloop_st->request_fast_savestate = true; core_serialize_size_special(&info);
core_serialize_size(&info);
runloop_st->request_fast_savestate = false;
if (!info.size) if (!info.size)
return false; return false;
netplay->state_size = info.size; netplay->state_size = info.size;
for (i = 0; i < netplay->buffer_size; i++) for (i = 0; i < netplay->buffer_size; i++)
@ -6822,8 +6803,6 @@ static bool netplay_init_serialization(netplay_t *netplay)
static bool netplay_try_init_serialization(netplay_t *netplay) static bool netplay_try_init_serialization(netplay_t *netplay)
{ {
retro_ctx_serialize_info_t serial_info; retro_ctx_serialize_info_t serial_info;
bool okay = false;
runloop_state_t *runloop_st = runloop_state_get_ptr();
if (netplay->state_size) if (netplay->state_size)
return true; return true;
@ -6831,19 +6810,15 @@ static bool netplay_try_init_serialization(netplay_t *netplay)
if (!netplay_init_serialization(netplay)) if (!netplay_init_serialization(netplay))
return false; return false;
/* Check if we can actually save */ /* Check if we can actually save. */
serial_info.data_const = NULL; serial_info.data_const = NULL;
serial_info.data = netplay->buffer[netplay->run_ptr].state; serial_info.data = netplay->buffer[netplay->run_ptr].state;
serial_info.size = netplay->state_size; serial_info.size = netplay->state_size;
if (!core_serialize_special(&serial_info))
runloop_st->request_fast_savestate = true;
okay = core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
if (!okay)
return false; return false;
/* Once initialized, we no longer exhibit this quirk */ /* Once initialized, we no longer exhibit this quirk. */
netplay->quirks &= ~((uint32_t)NETPLAY_QUIRK_INITIALIZATION); netplay->quirks &= ~NETPLAY_QUIRK_INITIALIZATION;
return netplay_init_socket_buffers(netplay); return netplay_init_socket_buffers(netplay);
} }
@ -7302,14 +7277,15 @@ static void netplay_core_reset(netplay_t *netplay)
void netplay_load_savestate(netplay_t *netplay, void netplay_load_savestate(netplay_t *netplay,
retro_ctx_serialize_info_t *serial_info, bool save) retro_ctx_serialize_info_t *serial_info, bool save)
{ {
retro_ctx_serialize_info_t tmp_serial_info; retro_ctx_serialize_info_t tmp_serial_info = {0};
bool okay = false;
runloop_state_t *runloop_st = runloop_state_get_ptr(); if (!serial_info)
save = true;
netplay_force_future(netplay); netplay_force_future(netplay);
/* Record it in our own buffer */ /* Record it in our own buffer. */
if (save || !serial_info) if (save)
{ {
/* TODO/FIXME: This is a critical failure! */ /* TODO/FIXME: This is a critical failure! */
if (!netplay_delta_frame_ready(netplay, if (!netplay_delta_frame_ready(netplay,
@ -7318,36 +7294,30 @@ void netplay_load_savestate(netplay_t *netplay,
if (!serial_info) if (!serial_info)
{ {
tmp_serial_info.size = netplay->state_size;
tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state; tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state;
tmp_serial_info.size = netplay->state_size;
runloop_st->request_fast_savestate = true; if (!core_serialize_special(&tmp_serial_info))
okay = core_serialize(&tmp_serial_info);
runloop_st->request_fast_savestate = false;
if (!okay)
return; return;
tmp_serial_info.data_const = tmp_serial_info.data; tmp_serial_info.data_const = tmp_serial_info.data;
serial_info = &tmp_serial_info; serial_info = &tmp_serial_info;
} }
else else if (serial_info->size <= netplay->state_size)
{
if (serial_info->size <= netplay->state_size)
memcpy(netplay->buffer[netplay->run_ptr].state, memcpy(netplay->buffer[netplay->run_ptr].state,
serial_info->data_const, serial_info->size); serial_info->data_const, serial_info->size);
} }
}
/* Don't send it if we're expected to be desynced */ /* Don't send it if we're expected to be desynced. */
if (netplay->desync) if (!netplay->desync)
return; {
/* Send this to every peer. */
/* Send this to every peer */
if (netplay->compress_nil.compression_backend) if (netplay->compress_nil.compression_backend)
netplay_send_savestate(netplay, serial_info, 0, &netplay->compress_nil); netplay_send_savestate(netplay, serial_info, 0,
&netplay->compress_nil);
if (netplay->compress_zlib.compression_backend) if (netplay->compress_zlib.compression_backend)
netplay_send_savestate(netplay, serial_info, NETPLAY_COMPRESSION_ZLIB, netplay_send_savestate(netplay, serial_info, NETPLAY_COMPRESSION_ZLIB,
&netplay->compress_zlib); &netplay->compress_zlib);
} }
}
/** /**
* netplay_toggle_play_spectate * netplay_toggle_play_spectate

146
runloop.c
View File

@ -3021,7 +3021,10 @@ bool runloop_environment_cb(unsigned cmd, void *data)
result &= ~(1|2); result &= ~(1|2);
#endif #endif
#if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING) #if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING)
if (runloop_st->request_fast_savestate) /* Deprecated.
Use RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT instead. */
/* TODO/FIXME: Get rid of this ugly hack. */
if (runloop_st->request_special_savestate)
result |= 4; result |= 4;
#endif #endif
if (data) if (data)
@ -3035,31 +3038,35 @@ bool runloop_environment_cb(unsigned cmd, void *data)
case RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT: case RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT:
{ {
int result = RETRO_SAVESTATE_CONTEXT_NORMAL; int result = RETRO_SAVESTATE_CONTEXT_NORMAL;
#if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING) #if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING)
if (runloop_st->request_fast_savestate) if (runloop_st->request_special_savestate)
{ {
#ifdef HAVE_RUNAHEAD
#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
settings_t
*settings = config_get_ptr();
result = (settings->bools.run_ahead_secondary_instance
&& runloop_st->runahead_secondary_core_available
&& secondary_core_ensure_exists(settings) ? RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY : RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE);
#else
result = RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE;
#endif
#endif
#ifdef HAVE_NETWORKING #ifdef HAVE_NETWORKING
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
result = RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY; result = RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY;
else
#endif #endif
}
#endif
if (data)
{ {
int* result_p = (int*)data; #ifdef HAVE_RUNAHEAD
*result_p = result; #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
settings_t *settings = config_get_ptr();
if (settings->bools.run_ahead_secondary_instance &&
runloop_st->runahead_secondary_core_available &&
secondary_core_ensure_exists(settings))
result = RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY;
else
#endif
result = RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE;
#endif
} }
}
#endif
if (data)
*(int*)data = result;
break; break;
} }
@ -4132,13 +4139,22 @@ bool secondary_core_ensure_exists(settings_t *settings)
#if defined(HAVE_RUNAHEAD) && defined(HAVE_DYNAMIC) #if defined(HAVE_RUNAHEAD) && defined(HAVE_DYNAMIC)
static bool secondary_core_deserialize(settings_t *settings, static bool secondary_core_deserialize(settings_t *settings,
const void *buffer, int size) const void *data, size_t size)
{
bool ret = false;
if (secondary_core_ensure_exists(settings))
{ {
runloop_state_t *runloop_st = &runloop_state; runloop_state_t *runloop_st = &runloop_state;
if (secondary_core_ensure_exists(settings))
return runloop_st->secondary_core.retro_unserialize(buffer, size); runloop_st->request_special_savestate = true;
ret = runloop_st->secondary_core.retro_unserialize(data, size);
runloop_st->request_special_savestate = false;
}
else
runloop_secondary_core_destroy(); runloop_secondary_core_destroy();
return false;
return ret;
} }
#endif #endif
@ -4614,9 +4630,7 @@ static bool runahead_create(runloop_state_t *runloop_st)
retro_ctx_size_info_t info; retro_ctx_size_info_t info;
video_driver_state_t *video_st = video_state_get_ptr(); video_driver_state_t *video_st = video_state_get_ptr();
runloop_st->request_fast_savestate = true; core_serialize_size_special(&info);
core_serialize_size(&info);
runloop_st->request_fast_savestate = false;
runahead_save_state_list_init(runloop_st, info.size); runahead_save_state_list_init(runloop_st, info.size);
video_st->runahead_is_active = video_st->active; video_st->runahead_is_active = video_st->active;
@ -4638,7 +4652,6 @@ static bool runahead_create(runloop_state_t *runloop_st)
static bool runahead_save_state(runloop_state_t *runloop_st) static bool runahead_save_state(runloop_state_t *runloop_st)
{ {
retro_ctx_serialize_info_t *serialize_info; retro_ctx_serialize_info_t *serialize_info;
bool okay = false;
if (!runloop_st->runahead_save_state_list) if (!runloop_st->runahead_save_state_list)
return false; return false;
@ -4646,11 +4659,7 @@ static bool runahead_save_state(runloop_state_t *runloop_st)
serialize_info = serialize_info =
(retro_ctx_serialize_info_t*)runloop_st->runahead_save_state_list->data[0]; (retro_ctx_serialize_info_t*)runloop_st->runahead_save_state_list->data[0];
runloop_st->request_fast_savestate = true; if (core_serialize_special(serialize_info))
okay = core_serialize(serialize_info);
runloop_st->request_fast_savestate = false;
if (okay)
return true; return true;
runahead_error(runloop_st); runahead_error(runloop_st);
@ -4659,47 +4668,35 @@ static bool runahead_save_state(runloop_state_t *runloop_st)
static bool runahead_load_state(runloop_state_t *runloop_st) static bool runahead_load_state(runloop_state_t *runloop_st)
{ {
bool okay = false;
retro_ctx_serialize_info_t *serialize_info = retro_ctx_serialize_info_t *serialize_info =
(retro_ctx_serialize_info_t*) (retro_ctx_serialize_info_t*)
runloop_st->runahead_save_state_list->data[0]; runloop_st->runahead_save_state_list->data[0];
bool last_dirty = runloop_st->input_is_dirty; bool last_dirty = runloop_st->input_is_dirty;
bool ret =
core_unserialize_special(serialize_info);
runloop_st->request_fast_savestate = true;
/* calling core_unserialize has side effects with
* netplay (it triggers transmitting your save state)
call retro_unserialize directly from the core instead */
okay = runloop_st->current_core.retro_unserialize(
serialize_info->data_const, serialize_info->size);
runloop_st->request_fast_savestate = false;
runloop_st->input_is_dirty = last_dirty; runloop_st->input_is_dirty = last_dirty;
if (!okay) if (!ret)
runahead_error(runloop_st); runahead_error(runloop_st);
return okay; return ret;
} }
#if HAVE_DYNAMIC #if HAVE_DYNAMIC
static bool runahead_load_state_secondary(void) static bool runahead_load_state_secondary(void)
{ {
bool okay = false;
runloop_state_t *runloop_st = &runloop_state; runloop_state_t *runloop_st = &runloop_state;
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
retro_ctx_serialize_info_t *serialize_info = retro_ctx_serialize_info_t *serialize_info =
(retro_ctx_serialize_info_t*)runloop_st->runahead_save_state_list->data[0]; (retro_ctx_serialize_info_t*)runloop_st->runahead_save_state_list->data[0];
runloop_st->request_fast_savestate = true; if (!secondary_core_deserialize(settings, serialize_info->data_const,
okay = serialize_info->size))
secondary_core_deserialize(settings,
serialize_info->data_const, (int)serialize_info->size);
runloop_st->request_fast_savestate = false;
if (!okay)
{ {
runloop_st->runahead_secondary_core_available = false; runloop_st->runahead_secondary_core_available = false;
runahead_error(runloop_st); runahead_error(runloop_st);
return false; return false;
} }
@ -8391,6 +8388,26 @@ bool core_unserialize(retro_ctx_serialize_info_t *info)
return true; return true;
} }
bool core_unserialize_special(retro_ctx_serialize_info_t *info)
{
bool ret;
runloop_state_t *runloop_st = &runloop_state;
if (!info)
return false;
runloop_st->request_special_savestate = true;
ret = runloop_st->current_core.retro_unserialize(info->data_const, info->size);
runloop_st->request_special_savestate = false;
#ifdef HAVE_NETWORKING
if (ret)
netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, info);
#endif
return ret;
}
bool core_serialize(retro_ctx_serialize_info_t *info) bool core_serialize(retro_ctx_serialize_info_t *info)
{ {
runloop_state_t *runloop_st = &runloop_state; runloop_state_t *runloop_st = &runloop_state;
@ -8399,6 +8416,21 @@ bool core_serialize(retro_ctx_serialize_info_t *info)
return true; return true;
} }
bool core_serialize_special(retro_ctx_serialize_info_t *info)
{
bool ret;
runloop_state_t *runloop_st = &runloop_state;
if (!info)
return false;
runloop_st->request_special_savestate = true;
ret = runloop_st->current_core.retro_serialize(info->data, info->size);
runloop_st->request_special_savestate = false;
return ret;
}
bool core_serialize_size(retro_ctx_size_info_t *info) bool core_serialize_size(retro_ctx_size_info_t *info)
{ {
runloop_state_t *runloop_st = &runloop_state; runloop_state_t *runloop_st = &runloop_state;
@ -8408,6 +8440,20 @@ bool core_serialize_size(retro_ctx_size_info_t *info)
return true; return true;
} }
bool core_serialize_size_special(retro_ctx_size_info_t *info)
{
runloop_state_t *runloop_st = &runloop_state;
if (!info)
return false;
runloop_st->request_special_savestate = true;
info->size = runloop_st->current_core.retro_serialize_size();
runloop_st->request_special_savestate = false;
return true;
}
uint64_t core_serialization_quirks(void) uint64_t core_serialization_quirks(void)
{ {
runloop_state_t *runloop_st = &runloop_state; runloop_state_t *runloop_st = &runloop_state;

View File

@ -292,9 +292,7 @@ struct runloop
bool runahead_secondary_core_available; bool runahead_secondary_core_available;
bool runahead_force_input_dirty; bool runahead_force_input_dirty;
#endif #endif
#if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING) bool request_special_savestate;
bool request_fast_savestate;
#endif
#ifdef HAVE_PATCH #ifdef HAVE_PATCH
bool patch_blocked; bool patch_blocked;
#endif #endif