savestates: implement an api call for context awareness (#14101)

This commit is contained in:
barbudreadmon 2022-06-30 10:45:59 +02:00 committed by GitHub
parent a5ebfc442a
commit e9d67f2bbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 9 deletions

View File

@ -1759,6 +1759,12 @@ enum retro_mod
* the frontend is attempting to call retro_run().
*/
#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* int * --
* Tells the core about the context the frontend is asking for savestate.
* (see enum retro_savestate_context)
*/
/* VFS functionality */
/* File paths:
@ -2996,6 +3002,35 @@ enum retro_pixel_format
RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX
};
enum retro_savestate_context
{
/* Standard savestate written to disk. */
RETRO_SAVESTATE_CONTEXT_NORMAL = 0,
/* Savestate where you are guaranteed that the same instance will load the save state.
* You can store internal pointers to code or data.
* It's still a full serialization and deserialization, and could be loaded or saved at any time.
* It won't be written to disk or sent over the network.
*/
RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,
/* Savestate where you are guaranteed that the same emulator binary will load that savestate.
* You can skip anything that would slow down saving or loading state but you can not store internal pointers.
* It won't be written to disk or sent over the network.
* Example: "Second Instance" runahead
*/
RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY = 2,
/* Savestate used within a rollback netplay feature.
* You should skip anything that would unnecessarily increase bandwidth usage.
* It won't be written to disk but it will be sent over the network.
*/
RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY = 3,
/* Ensure sizeof() == sizeof(int). */
RETRO_SAVESTATE_CONTEXT_UNKNOWN = INT_MAX
};
struct retro_message
{
const char *msg; /* Message to be displayed. */

View File

@ -3422,12 +3422,17 @@ static bool netplay_sync_pre_frame(netplay_t *netplay, bool *disconnect)
(NETPLAY_QUIRK_INITIALIZATION | NETPLAY_QUIRK_NO_SAVESTATES)))
{
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);
if (core_serialize(&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 &&
!netplay->remote_paused)
@ -3638,6 +3643,8 @@ 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;
@ -3668,7 +3675,10 @@ static void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
serial_info.data_const = netplay->buffer[netplay->replay_ptr].state;
serial_info.size = netplay->state_size;
if (!core_unserialize(&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");
}
@ -3686,7 +3696,9 @@ static void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
/* 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;
if (netplay->replay_frame_count < netplay->unread_frame_count)
netplay_handle_frame_hash(netplay, ptr);
@ -3714,7 +3726,9 @@ static void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
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;
RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay->state_size ? netplay_delta_frame_crc(netplay, ptr) : 0);
}
#endif
@ -6688,12 +6702,15 @@ 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};
retro_ctx_size_info_t info = {0};
runloop_state_t *runloop_st = runloop_state_get_ptr();
if (netplay->state_size)
return true;
runloop_st->request_fast_savestate = true;
core_serialize_size(&info);
runloop_st->request_fast_savestate = false;
if (!info.size)
return false;
@ -6734,6 +6751,8 @@ 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;
@ -6746,7 +6765,10 @@ static bool netplay_try_init_serialization(netplay_t *netplay)
serial_info.data = netplay->buffer[netplay->run_ptr].state;
serial_info.size = netplay->state_size;
if (!core_serialize(&serial_info))
runloop_st->request_fast_savestate = true;
okay = core_serialize(&serial_info);
runloop_st->request_fast_savestate = false;
if (!okay)
return false;
/* Once initialized, we no longer exhibit this quirk */
@ -7210,6 +7232,8 @@ 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();
netplay_force_future(netplay);
@ -7225,7 +7249,11 @@ void netplay_load_savestate(netplay_t *netplay,
{
tmp_serial_info.size = netplay->state_size;
tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state;
if (!core_serialize(&tmp_serial_info))
runloop_st->request_fast_savestate = true;
okay = core_serialize(&tmp_serial_info);
runloop_st->request_fast_savestate = false;
if (!okay)
return;
tmp_serial_info.data_const = tmp_serial_info.data;
serial_info = &tmp_serial_info;

View File

@ -3017,15 +3017,15 @@ bool runloop_environment_cb(unsigned cmd, void *data)
&& !(video_st->current_video->frame == video_null.frame))
result |= 1;
#ifdef HAVE_RUNAHEAD
if (runloop_st->request_fast_savestate)
result |= 4;
if (audio_st->hard_disable)
result |= 8;
#endif
#ifdef HAVE_NETWORKING
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_REPLAYING, NULL))
result &= ~(1|2);
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
#endif
#if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING)
if (runloop_st->request_fast_savestate)
result |= 4;
#endif
if (data)
@ -3036,6 +3036,37 @@ bool runloop_environment_cb(unsigned cmd, void *data)
break;
}
case RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT:
{
int result = RETRO_SAVESTATE_CONTEXT_NORMAL;
settings_t
*settings = config_get_ptr();
#if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING)
if (runloop_st->request_fast_savestate)
{
#ifdef HAVE_RUNAHEAD
#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
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;
#endif
}
#endif
if (data)
{
int* result_p = (int*)data;
*result_p = result;
}
break;
}
case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE:
{
struct retro_midi_interface *midi_interface =

View File

@ -288,11 +288,13 @@ struct runloop
bool has_variable_update;
bool input_is_dirty;
bool runahead_save_state_size_known;
bool request_fast_savestate;
bool runahead_available;
bool runahead_secondary_core_available;
bool runahead_force_input_dirty;
#endif
#if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING)
bool request_fast_savestate;
#endif
#ifdef HAVE_PATCH
bool patch_blocked;
#endif