1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-03 00:38:44 +00:00

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_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);
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_special(retro_ctx_serialize_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))
{
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.size = netplay->state_size;
memset(serial_info.data, 0, serial_info.size);
runloop_st->request_fast_savestate = true;
okay = core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
if (okay)
if (core_serialize_special(&serial_info))
{
if (netplay->force_send_savestate && !netplay->stall &&
!netplay->remote_paused)
@ -3604,7 +3598,7 @@ static bool netplay_sync_pre_frame(netplay_t *netplay)
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 =
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)
{
retro_ctx_serialize_info_t serial_info;
bool okay = false;
runloop_state_t *runloop_st = runloop_state_get_ptr();
/* Replay frames. */
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_const = netplay->buffer[netplay->replay_ptr].state;
serial_info.size = netplay->state_size;
runloop_st->request_fast_savestate = true;
okay = core_unserialize(&serial_info);
runloop_st->request_fast_savestate = false;
if (!okay)
{
if (!core_unserialize_special(&serial_info))
RARCH_ERR("[Netplay] Netplay savestate loading failed: Prepare for desync!\n");
}
while (netplay->replay_frame_count < netplay->run_frame_count)
{
retro_time_t start, tm;
struct delta_frame *ptr = &netplay->buffer[netplay->replay_ptr];
serial_info.data_const = NULL;
serial_info.data = ptr->state;
serial_info.size = netplay->state_size;
serial_info.data_const = NULL;
start = cpu_features_get_time_usec();
/* Remember the current state */
memset(serial_info.data, 0, serial_info.size);
runloop_st->request_fast_savestate = true;
core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
core_serialize_special(&serial_info);
if (netplay->replay_frame_count < netplay->unread_frame_count)
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]);
else
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;
memset(serial_info.data, 0, serial_info.size);
runloop_st->request_fast_savestate = true;
core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
core_serialize_special(&serial_info);
RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay->state_size ? netplay_delta_frame_crc(netplay, ptr) : 0);
}
#endif
@ -6779,18 +6764,14 @@ static bool netplay_init_socket_buffers(netplay_t *netplay)
static bool netplay_init_serialization(netplay_t *netplay)
{
size_t i;
retro_ctx_size_info_t info = {0};
runloop_state_t *runloop_st = runloop_state_get_ptr();
retro_ctx_size_info_t info = {0};
if (netplay->state_size)
return true;
runloop_st->request_fast_savestate = true;
core_serialize_size(&info);
runloop_st->request_fast_savestate = false;
core_serialize_size_special(&info);
if (!info.size)
return false;
netplay->state_size = info.size;
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)
{
retro_ctx_serialize_info_t serial_info;
bool okay = false;
runloop_state_t *runloop_st = runloop_state_get_ptr();
if (netplay->state_size)
return true;
@ -6831,19 +6810,15 @@ static bool netplay_try_init_serialization(netplay_t *netplay)
if (!netplay_init_serialization(netplay))
return false;
/* Check if we can actually save */
/* Check if we can actually save. */
serial_info.data_const = NULL;
serial_info.data = netplay->buffer[netplay->run_ptr].state;
serial_info.size = netplay->state_size;
runloop_st->request_fast_savestate = true;
okay = core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
if (!okay)
if (!core_serialize_special(&serial_info))
return false;
/* Once initialized, we no longer exhibit this quirk */
netplay->quirks &= ~((uint32_t)NETPLAY_QUIRK_INITIALIZATION);
/* Once initialized, we no longer exhibit this quirk. */
netplay->quirks &= ~NETPLAY_QUIRK_INITIALIZATION;
return netplay_init_socket_buffers(netplay);
}
@ -7302,51 +7277,46 @@ static void netplay_core_reset(netplay_t *netplay)
void netplay_load_savestate(netplay_t *netplay,
retro_ctx_serialize_info_t *serial_info, bool save)
{
retro_ctx_serialize_info_t tmp_serial_info;
bool okay = false;
runloop_state_t *runloop_st = runloop_state_get_ptr();
retro_ctx_serialize_info_t tmp_serial_info = {0};
if (!serial_info)
save = true;
netplay_force_future(netplay);
/* Record it in our own buffer */
if (save || !serial_info)
/* Record it in our own buffer. */
if (save)
{
/* TODO/FIXME: This is a critical failure! */
if (!netplay_delta_frame_ready(netplay,
&netplay->buffer[netplay->run_ptr], netplay->run_frame_count))
&netplay->buffer[netplay->run_ptr], netplay->run_frame_count))
return;
if (!serial_info)
{
tmp_serial_info.size = netplay->state_size;
tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state;
runloop_st->request_fast_savestate = true;
okay = core_serialize(&tmp_serial_info);
runloop_st->request_fast_savestate = false;
if (!okay)
tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state;
tmp_serial_info.size = netplay->state_size;
if (!core_serialize_special(&tmp_serial_info))
return;
tmp_serial_info.data_const = tmp_serial_info.data;
serial_info = &tmp_serial_info;
}
else
{
if (serial_info->size <= netplay->state_size)
memcpy(netplay->buffer[netplay->run_ptr].state,
serial_info->data_const, serial_info->size);
serial_info = &tmp_serial_info;
}
else if (serial_info->size <= netplay->state_size)
memcpy(netplay->buffer[netplay->run_ptr].state,
serial_info->data_const, serial_info->size);
}
/* Don't send it if we're expected to be desynced */
if (netplay->desync)
return;
/* Send this to every peer */
if (netplay->compress_nil.compression_backend)
netplay_send_savestate(netplay, serial_info, 0, &netplay->compress_nil);
if (netplay->compress_zlib.compression_backend)
netplay_send_savestate(netplay, serial_info, NETPLAY_COMPRESSION_ZLIB,
&netplay->compress_zlib);
/* Don't send it if we're expected to be desynced. */
if (!netplay->desync)
{
/* Send this to every peer. */
if (netplay->compress_nil.compression_backend)
netplay_send_savestate(netplay, serial_info, 0,
&netplay->compress_nil);
if (netplay->compress_zlib.compression_backend)
netplay_send_savestate(netplay, serial_info, NETPLAY_COMPRESSION_ZLIB,
&netplay->compress_zlib);
}
}
/**

148
runloop.c
View File

@ -3021,7 +3021,10 @@ bool runloop_environment_cb(unsigned cmd, void *data)
result &= ~(1|2);
#endif
#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;
#endif
if (data)
@ -3034,32 +3037,36 @@ bool runloop_environment_cb(unsigned cmd, void *data)
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 (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
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
result = RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY;
else
#endif
{
#ifdef HAVE_RUNAHEAD
#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* result_p = (int*)data;
*result_p = result;
}
*(int*)data = result;
break;
}
@ -4132,13 +4139,22 @@ bool secondary_core_ensure_exists(settings_t *settings)
#if defined(HAVE_RUNAHEAD) && defined(HAVE_DYNAMIC)
static bool secondary_core_deserialize(settings_t *settings,
const void *buffer, int size)
const void *data, size_t size)
{
runloop_state_t *runloop_st = &runloop_state;
bool ret = false;
if (secondary_core_ensure_exists(settings))
return runloop_st->secondary_core.retro_unserialize(buffer, size);
runloop_secondary_core_destroy();
return false;
{
runloop_state_t *runloop_st = &runloop_state;
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();
return ret;
}
#endif
@ -4614,9 +4630,7 @@ static bool runahead_create(runloop_state_t *runloop_st)
retro_ctx_size_info_t info;
video_driver_state_t *video_st = video_state_get_ptr();
runloop_st->request_fast_savestate = true;
core_serialize_size(&info);
runloop_st->request_fast_savestate = false;
core_serialize_size_special(&info);
runahead_save_state_list_init(runloop_st, info.size);
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)
{
retro_ctx_serialize_info_t *serialize_info;
bool okay = false;
if (!runloop_st->runahead_save_state_list)
return false;
@ -4646,11 +4659,7 @@ static bool runahead_save_state(runloop_state_t *runloop_st)
serialize_info =
(retro_ctx_serialize_info_t*)runloop_st->runahead_save_state_list->data[0];
runloop_st->request_fast_savestate = true;
okay = core_serialize(serialize_info);
runloop_st->request_fast_savestate = false;
if (okay)
if (core_serialize_special(serialize_info))
return true;
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)
{
bool okay = false;
retro_ctx_serialize_info_t *serialize_info =
(retro_ctx_serialize_info_t*)
runloop_st->runahead_save_state_list->data[0];
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;
if (!okay)
if (!ret)
runahead_error(runloop_st);
return okay;
return ret;
}
#if HAVE_DYNAMIC
static bool runahead_load_state_secondary(void)
{
bool okay = false;
runloop_state_t *runloop_st = &runloop_state;
settings_t *settings = config_get_ptr();
retro_ctx_serialize_info_t *serialize_info =
(retro_ctx_serialize_info_t*)runloop_st->runahead_save_state_list->data[0];
runloop_st->request_fast_savestate = true;
okay =
secondary_core_deserialize(settings,
serialize_info->data_const, (int)serialize_info->size);
runloop_st->request_fast_savestate = false;
if (!okay)
if (!secondary_core_deserialize(settings, serialize_info->data_const,
serialize_info->size))
{
runloop_st->runahead_secondary_core_available = false;
runahead_error(runloop_st);
return false;
}
@ -8391,6 +8388,26 @@ bool core_unserialize(retro_ctx_serialize_info_t *info)
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)
{
runloop_state_t *runloop_st = &runloop_state;
@ -8399,6 +8416,21 @@ bool core_serialize(retro_ctx_serialize_info_t *info)
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)
{
runloop_state_t *runloop_st = &runloop_state;
@ -8408,6 +8440,20 @@ bool core_serialize_size(retro_ctx_size_info_t *info)
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)
{
runloop_state_t *runloop_st = &runloop_state;

View File

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