mirror of
https://github.com/libretro/RetroArch
synced 2025-03-30 16:20:27 +00:00
Special functions for core serialization (#14317)
This commit is contained in:
parent
74ef6a0f4a
commit
2d1c238c1d
3
core.h
3
core.h
@ -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);
|
||||
|
||||
|
@ -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
148
runloop.c
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user