mirror of
https://github.com/libretro/RetroArch
synced 2025-01-29 00:32:49 +00:00
savestates: implement an api call for context awareness (#14101)
This commit is contained in:
parent
a5ebfc442a
commit
e9d67f2bbe
@ -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. */
|
||||
|
@ -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;
|
||||
|
37
runloop.c
37
runloop.c
@ -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 =
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user