From b974fa5718444f8a7347e3ee880d66ce5939ba8e Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 13:29:27 -0400 Subject: [PATCH 01/15] Add a libretro environment for serialization quirks The new environment RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS allows cores to communicate any quirks their implementation of serialization may exhibit. This is useful for distinguishing between serialization implementations that are sufficient for netplay, rewind, regular use, etc, as each of these have different requirements and it should be possible to support a "good enough" serialization without breaking frontend features. --- core.h | 2 ++ core_impl.c | 7 +++++++ libretro-common/include/libretro.h | 25 +++++++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/core.h b/core.h index 0b80d39737..c760727b7a 100644 --- a/core.h +++ b/core.h @@ -178,6 +178,8 @@ bool core_set_environment(retro_ctx_environ_info_t *info); bool core_serialize_size(retro_ctx_size_info_t *info); +uint32_t core_serialize_quirks(void); + bool core_serialize(retro_ctx_serialize_info_t *info); bool core_unserialize(retro_ctx_serialize_info_t *info); diff --git a/core_impl.c b/core_impl.c index 683a821c57..3bae3c6bee 100644 --- a/core_impl.c +++ b/core_impl.c @@ -291,6 +291,13 @@ bool core_unserialize(retro_ctx_serialize_info_t *info) return true; } +uint32_t core_serialize_quirks(void) +{ + uint32_t ret = 0; + rarch_environment_cb(RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS, &ret); + return ret; +} + bool core_serialize(retro_ctx_serialize_info_t *info) { if (!info) diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index a4df6be470..2ba7c6a50f 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -976,6 +976,31 @@ struct retro_hw_render_context_negotiation_interface * so it will be used after SET_HW_RENDER, but before the context_reset callback. */ +#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0) + /* Serialized state is incomplete in some way. Set if serialization is + * usable in typical end-user cases but should not be relied upon to + * implement frame-sensitive frontend features such as netplay or + * rerecording. */ +#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1) + /* The core must spend some time initializing before serialization is + * safe. */ +#define RETRO_SERIALIZATION_QUIRK_INITIALIZING (1 << 2) + /* If MUST_INITIALIZE is set, this should also be set if initialization is + * in progress. */ +#define RETRO_SERIALIZATION_QUIRK_VARIABLE_SIZE (1 << 3) + /* Serialization size may change within a session. */ +#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4) + /* Serialized state can only be loaded during the same session. */ +#define RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT (1 << 5) + /* Serialized state cannot be loaded on a different architecture from the + * one it was saved on. */ + +#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 + /* uint32_t * -- + * Sets quirk flags associated with serialization. + */ + + #define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */ #define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */ #define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */ From 44931586b71f07cacb536b6d42e260b23311e9c1 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 13:31:58 -0400 Subject: [PATCH 02/15] Removing Netplay workarounds which will soon be replaced by quirks --- network/netplay/netplay.c | 33 ++++++++++++++++++++++++------- network/netplay/netplay.h | 3 ++- network/netplay/netplay_net.c | 6 +++--- network/netplay/netplay_private.h | 25 +++++++++++++++++++++-- 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index e4f5c90f86..6675aa22d7 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -729,9 +729,11 @@ static bool netplay_poll(void) /* Read Netplay input, block if we're configured to stall for input every * frame */ - res = poll_input(netplay_data, - (netplay_data->stall_frames == 0) - && (netplay_data->read_frame_count <= netplay_data->self_frame_count)); + if (netplay_data->stall_frames == 0 && + netplay_data->read_frame_count <= netplay_data->self_frame_count) + res = poll_input(netplay_data, true); + else + res = poll_input(netplay_data, false); if (res == -1) { hangup(netplay_data); @@ -981,7 +983,7 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) if (!netplay->buffer[i].state) { - netplay->savestates_work = false; + netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; netplay->stall_frames = 0; } } @@ -999,6 +1001,7 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) * @cb : Libretro callbacks. * @spectate : If true, enable spectator mode. * @nick : Nickname of user. + * @quirks : Netplay quirks required for this session. * * Creates a new netplay handle. A NULL host means we're * hosting (user 1). @@ -1007,7 +1010,7 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) **/ netplay_t *netplay_new(const char *server, uint16_t port, unsigned frames, unsigned check_frames, const struct retro_callbacks *cb, - bool spectate, const char *nick) + bool spectate, const char *nick, uint32_t quirks) { netplay_t *netplay = (netplay_t*)calloc(1, sizeof(*netplay)); if (!netplay) @@ -1019,10 +1022,10 @@ netplay_t *netplay_new(const char *server, uint16_t port, netplay->port = server ? 0 : 1; netplay->spectate.enabled = spectate; netplay->is_server = server == NULL; - netplay->savestates_work = true; strlcpy(netplay->nick, nick, sizeof(netplay->nick)); netplay->stall_frames = frames; netplay->check_frames = check_frames; + netplay->quirks = quirks; if (!netplay_init_buffers(netplay, frames)) { @@ -1332,6 +1335,8 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port) { struct retro_callbacks cbs = {0}; settings_t *settings = config_get_ptr(); + uint32_t serialization_quirks = 0; + uint32_t quirks = 0; if (!netplay_enabled) return false; @@ -1345,6 +1350,20 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port) core_set_default_callbacks(&cbs); + /* Map the core's quirks to our quirks */ + serialization_quirks = core_serialize_quirks(); + if ((serialization_quirks & ~((uint32_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))) + { + /* Quirks we don't support! Just disable everything. */ + quirks |= NETPLAY_QUIRK_NO_SAVESTATES; + } + if ((serialization_quirks & NETPLAY_QUIRK_MAP_NO_SAVESTATES)) + quirks |= NETPLAY_QUIRK_NO_SAVESTATES; + if ((serialization_quirks & NETPLAY_QUIRK_MAP_NO_TRANSMISSION)) + quirks |= NETPLAY_QUIRK_NO_TRANSMISSION; + if ((serialization_quirks & NETPLAY_QUIRK_MAP_INITIALIZATION)) + quirks |= NETPLAY_QUIRK_INITIALIZATION; + if (netplay_is_client) { RARCH_LOG("Connecting to netplay host...\n"); @@ -1361,7 +1380,7 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port) netplay_is_client ? server : NULL, port ? port : RARCH_DEFAULT_PORT, settings->netplay.sync_frames, settings->netplay.check_frames, &cbs, - is_spectate, settings->username); + is_spectate, settings->username, quirks); if (netplay_data) return true; diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index 6fb459b662..703437e0fc 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -139,6 +139,7 @@ size_t audio_sample_batch_net(const int16_t *data, size_t frames); * @cb : Libretro callbacks. * @spectate : If true, enable spectator mode. * @nick : Nickname of user. + * @quirks : Netplay quirks. * * Creates a new netplay handle. A NULL host means we're * hosting (user 1). @@ -148,7 +149,7 @@ size_t audio_sample_batch_net(const int16_t *data, size_t frames); netplay_t *netplay_new(const char *server, uint16_t port, unsigned frames, unsigned check_frames, const struct retro_callbacks *cb, bool spectate, - const char *nick); + const char *nick, uint32_t quirks); /** * netplay_free: diff --git a/network/netplay/netplay_net.c b/network/netplay/netplay_net.c index 2562f48231..e1a2ab7fbd 100644 --- a/network/netplay/netplay_net.c +++ b/network/netplay/netplay_net.c @@ -69,7 +69,7 @@ static bool netplay_net_pre_frame(netplay_t *netplay) serial_info.size = netplay->state_size; memset(serial_info.data, 0, serial_info.size); - if (netplay->savestates_work && core_serialize(&serial_info)) + if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && core_serialize(&serial_info)) { if (netplay->force_send_savestate && !netplay->stall) { @@ -83,7 +83,7 @@ static bool netplay_net_pre_frame(netplay_t *netplay) { /* If the core can't serialize properly, we must stall for the * remote input on EVERY frame, because we can't recover */ - netplay->savestates_work = false; + netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; netplay->stall_frames = 0; if (!netplay->has_connection) netplay->stall = RARCH_NETPLAY_STALL_NO_CONNECTION; @@ -135,7 +135,7 @@ static bool netplay_net_pre_frame(netplay_t *netplay) netplay->has_connection = true; /* Send them the savestate */ - if (netplay->savestates_work) + if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && !(netplay->quirks & NETPLAY_QUIRK_NO_TRANSMISSION)) { netplay_load_savestate(netplay, NULL, true); } diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index e792d94788..e2159e10e6 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -40,6 +40,27 @@ #define PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1) #define NEXT_PTR(x) ((x + 1) % netplay->buffer_size) +/* Quirks mandated by how particular cores save states. This is distilled from + * the larger set of quirks that the quirks environment can communicate. */ +#define NETPLAY_QUIRK_NO_SAVESTATES (1<<0) +#define NETPLAY_QUIRK_NO_TRANSMISSION (1<<1) +#define NETPLAY_QUIRK_INITIALIZATION (1<<2) + +/* Mapping of serialization quirks to netplay quirks. */ +#define NETPLAY_QUIRK_MAP_UNDERSTOOD \ + (RETRO_SERIALIZATION_QUIRK_INCOMPLETE \ + |RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE \ + |RETRO_SERIALIZATION_QUIRK_INITIALIZING \ + |RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION \ + |RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT) +#define NETPLAY_QUIRK_MAP_NO_SAVESTATES \ + (RETRO_SERIALIZATION_QUIRK_INCOMPLETE) +#define NETPLAY_QUIRK_MAP_NO_TRANSMISSION \ + (RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION \ + |RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT) +#define NETPLAY_QUIRK_MAP_INITIALIZATION \ + (RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE) + struct delta_frame { bool used; /* a bit derpy, but this is how we know if the delta's been used at all */ @@ -118,8 +139,8 @@ struct netplay * events, such as player flipping or savestate loading. */ bool force_rewind; - /* Does the core support savestates? */ - bool savestates_work; + /* Quirks in the savestate implementation */ + unsigned quirks; /* Force our state to be sent to the other side. Used when they request a * savestate, to send at the next pre-frame. */ From 5676d0b848f08a3a94aaef4727d90d20bf027c9a Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 13:39:00 -0400 Subject: [PATCH 03/15] Adding Netplay quirk for untransmittable savestates --- network/netplay/netplay.c | 4 ++++ network/netplay/netplay_net.c | 11 ++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index 6675aa22d7..0c306b3a4c 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -1280,6 +1280,10 @@ void netplay_load_savestate(netplay_t *netplay, retro_ctx_serialize_info_t *seri netplay->other_frame_count = netplay->self_frame_count; } + /* If we can't send it to the peer, loading a state was a bad idea */ + if (netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION)) + return; + /* And send it to the peer (FIXME: this is an ugly way to do this) */ header[0] = htonl(NETPLAY_CMD_LOAD_SAVESTATE); header[1] = htonl(serial_info->size + sizeof(uint32_t)); diff --git a/network/netplay/netplay_net.c b/network/netplay/netplay_net.c index e1a2ab7fbd..a4fffb0a70 100644 --- a/network/netplay/netplay_net.c +++ b/network/netplay/netplay_net.c @@ -85,9 +85,12 @@ static bool netplay_net_pre_frame(netplay_t *netplay) * remote input on EVERY frame, because we can't recover */ netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; netplay->stall_frames = 0; - if (!netplay->has_connection) - netplay->stall = RARCH_NETPLAY_STALL_NO_CONNECTION; } + + /* If we can't transmit savestates, we must stall until the client is ready */ + if (!netplay->has_connection && + (netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION))) + netplay->stall = RARCH_NETPLAY_STALL_NO_CONNECTION; } if (netplay->is_server && !netplay->has_connection) @@ -135,10 +138,8 @@ static bool netplay_net_pre_frame(netplay_t *netplay) netplay->has_connection = true; /* Send them the savestate */ - if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && !(netplay->quirks & NETPLAY_QUIRK_NO_TRANSMISSION)) - { + if (!(netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION))) netplay_load_savestate(netplay, NULL, true); - } /* And expect the current frame from the other side */ netplay->read_frame_count = netplay->other_frame_count = netplay->self_frame_count; From 07a4ad791dfcd9674ca88cea910c1e7658dcfc9d Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 14:03:18 -0400 Subject: [PATCH 04/15] Implemented Netplay initialization quirk --- network/netplay/netplay.c | 73 ++++++++++++++++++++++-------- network/netplay/netplay_net.c | 10 +++- network/netplay/netplay_private.h | 6 +++ network/netplay/netplay_spectate.c | 14 ++++++ 4 files changed, 83 insertions(+), 20 deletions(-) diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index 0c306b3a4c..90fe92303b 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -31,6 +31,7 @@ #include "netplay_private.h" +#include "../../autosave.h" #include "../../configuration.h" #include "../../command.h" #include "../../movie.h" @@ -951,6 +952,57 @@ void netplay_log_connection(const struct sockaddr_storage *their_addr, +bool netplay_wait_and_init_serialization(netplay_t *netplay) +{ + int frames; + + if (netplay->state_size) + return true; + + /* Wait maximally 60 frames, or until the core reports it's initialized */ + for (frames = 0; (core_serialize_quirks() & RETRO_SERIALIZATION_QUIRK_INITIALIZING) && frames < 60; frames++) + { +#if defined(HAVE_THREADS) + autosave_lock(); +#endif + core_run(); +#if defined(HAVE_THREADS) + autosave_unlock(); +#endif + } + + return netplay_init_serialization(netplay); + +} + +bool netplay_init_serialization(netplay_t *netplay) +{ + unsigned i; + retro_ctx_size_info_t info; + + if (netplay->state_size) + return true; + + core_serialize_size(&info); + + netplay->state_size = info.size; + + for (i = 0; i < netplay->buffer_size; i++) + { + netplay->buffer[i].state = calloc(netplay->state_size, 1); + + if (!netplay->buffer[i].state) + { + netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; + return false; + } + } + + /* Once initialized, we no longer exhibit this quirk */ + netplay->quirks &= ~((uint32_t) NETPLAY_QUIRK_INITIALIZATION); + + return true; +} static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) { @@ -969,25 +1021,8 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) if (!netplay->buffer) return false; - { - unsigned i; - retro_ctx_size_info_t info; - - core_serialize_size(&info); - - netplay->state_size = info.size; - - for (i = 0; i < netplay->buffer_size; i++) - { - netplay->buffer[i].state = calloc(netplay->state_size, 1); - - if (!netplay->buffer[i].state) - { - netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; - netplay->stall_frames = 0; - } - } - } + if (!(netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)) + return netplay_init_serialization(netplay); return true; } diff --git a/network/netplay/netplay_net.c b/network/netplay/netplay_net.c index a4fffb0a70..ce3e79d2e8 100644 --- a/network/netplay/netplay_net.c +++ b/network/netplay/netplay_net.c @@ -69,7 +69,11 @@ static bool netplay_net_pre_frame(netplay_t *netplay) serial_info.size = netplay->state_size; memset(serial_info.data, 0, serial_info.size); - if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && core_serialize(&serial_info)) + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + { + /* Don't serialize until it's safe */ + } + else if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && core_serialize(&serial_info)) { if (netplay->force_send_savestate && !netplay->stall) { @@ -216,6 +220,10 @@ static void netplay_net_post_frame(netplay_t *netplay) netplay->replay_ptr = netplay->other_ptr; netplay->replay_frame_count = netplay->other_frame_count; + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + /* Make sure we're initialized before we start loading things */ + netplay_wait_and_init_serialization(netplay); + serial_info.data = NULL; serial_info.data_const = netplay->buffer[netplay->replay_ptr].state; serial_info.size = netplay->state_size; diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index e2159e10e6..35cb47c530 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -198,6 +198,12 @@ struct netplay_callbacks* netplay_get_cbs_net(void); struct netplay_callbacks* netplay_get_cbs_spectate(void); +/* Normally called at init time, unless the INITIALIZATION quirk is set */ +bool netplay_init_serialization(netplay_t *netplay); + +/* Force serialization to be ready by fast-forwarding the core */ +bool netplay_wait_and_init_serialization(netplay_t *netplay); + void netplay_simulate_input(netplay_t *netplay, uint32_t sim_ptr); void netplay_log_connection(const struct sockaddr_storage *their_addr, diff --git a/network/netplay/netplay_spectate.c b/network/netplay/netplay_spectate.c index 53ad18b85a..fa05546268 100644 --- a/network/netplay/netplay_spectate.c +++ b/network/netplay/netplay_spectate.c @@ -111,6 +111,16 @@ static bool netplay_spectate_pre_frame(netplay_t *netplay) return true; } + /* Wait until it's safe to serialize */ + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + { + netplay->is_replay = true; + netplay->replay_ptr = netplay->self_ptr; + netplay->replay_frame_count = netplay->self_frame_count; + netplay_wait_and_init_serialization(netplay); + netplay->is_replay = false; + } + /* Start them at the current frame */ netplay->spectate.frames[idx] = netplay->self_frame_count; serial_info.data_const = NULL; @@ -197,6 +207,10 @@ static void netplay_spectate_post_frame(netplay_t *netplay) netplay->replay_ptr = netplay->other_ptr; netplay->replay_frame_count = netplay->other_frame_count; + /* Wait until it's safe to serialize */ + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + netplay_wait_and_init_serialization(netplay); + serial_info.data = NULL; serial_info.data_const = netplay->buffer[netplay->replay_ptr].state; serial_info.size = netplay->state_size; From 0d661ef6a2af06cf83b6ff5edb5e412e3bcd0666 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 14:16:48 -0400 Subject: [PATCH 05/15] Fix some backwards implementation in reporting serialization quirks --- core.h | 4 +++- core_impl.c | 12 ++++++++---- dynamic.c | 4 ++++ network/netplay/netplay.c | 4 ++-- network/netplay/netplay_net.c | 3 +-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/core.h b/core.h index c760727b7a..258588c4ab 100644 --- a/core.h +++ b/core.h @@ -178,7 +178,9 @@ bool core_set_environment(retro_ctx_environ_info_t *info); bool core_serialize_size(retro_ctx_size_info_t *info); -uint32_t core_serialize_quirks(void); +uint32_t core_serialization_quirks(void); + +void core_set_serialization_quirks(uint32_t quirks); bool core_serialize(retro_ctx_serialize_info_t *info); diff --git a/core_impl.c b/core_impl.c index 3bae3c6bee..e0197842f5 100644 --- a/core_impl.c +++ b/core_impl.c @@ -52,6 +52,7 @@ static bool core_game_loaded = false; static bool core_input_polled = false; static bool core_has_set_input_descriptors = false; static struct retro_callbacks retro_ctx; +static uint32_t core_serialization_quirks_v = 0; static void core_input_state_poll_maybe(void) { @@ -291,11 +292,14 @@ bool core_unserialize(retro_ctx_serialize_info_t *info) return true; } -uint32_t core_serialize_quirks(void) +uint32_t core_serialization_quirks(void) { - uint32_t ret = 0; - rarch_environment_cb(RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS, &ret); - return ret; + return core_serialization_quirks_v; +} + +void core_set_serialization_quirks(uint32_t quirks) +{ + core_serialization_quirks_v = quirks; } bool core_serialize(retro_ctx_serialize_info_t *info) diff --git a/dynamic.c b/dynamic.c index 933f11f171..c74bb92c04 100644 --- a/dynamic.c +++ b/dynamic.c @@ -1608,6 +1608,10 @@ bool rarch_environment_cb(unsigned cmd, void *data) break; } + case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS: + core_set_serialization_quirks(*((uint32_t *) data)); + break; + /* Default */ default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index 90fe92303b..c75b0df87a 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -960,7 +960,7 @@ bool netplay_wait_and_init_serialization(netplay_t *netplay) return true; /* Wait maximally 60 frames, or until the core reports it's initialized */ - for (frames = 0; (core_serialize_quirks() & RETRO_SERIALIZATION_QUIRK_INITIALIZING) && frames < 60; frames++) + for (frames = 0; (core_serialization_quirks() & RETRO_SERIALIZATION_QUIRK_INITIALIZING) && frames < 60; frames++) { #if defined(HAVE_THREADS) autosave_lock(); @@ -1390,7 +1390,7 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port) core_set_default_callbacks(&cbs); /* Map the core's quirks to our quirks */ - serialization_quirks = core_serialize_quirks(); + serialization_quirks = core_serialization_quirks(); if ((serialization_quirks & ~((uint32_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))) { /* Quirks we don't support! Just disable everything. */ diff --git a/network/netplay/netplay_net.c b/network/netplay/netplay_net.c index ce3e79d2e8..cc8319e1ab 100644 --- a/network/netplay/netplay_net.c +++ b/network/netplay/netplay_net.c @@ -61,8 +61,7 @@ static bool netplay_net_pre_frame(netplay_t *netplay) { retro_ctx_serialize_info_t serial_info; - if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->self_ptr], netplay->self_frame_count) && - netplay->self_frame_count > 0) + if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->self_ptr], netplay->self_frame_count)) { serial_info.data_const = NULL; serial_info.data = netplay->buffer[netplay->self_ptr].state; From 3fa3fe0fcd95acb2710b7d2816be9e0df4d7c420 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 14:36:23 -0400 Subject: [PATCH 06/15] Fixes for the other few Netplay initialization points --- network/netplay/netplay.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index c75b0df87a..db582fe2bd 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -557,6 +557,23 @@ static bool netplay_get_cmd(netplay_t *netplay) { uint32_t frame; + /* Make sure we're ready for it */ + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + { + if (!netplay->is_replay) + { + netplay->is_replay = true; + netplay->replay_ptr = netplay->self_ptr; + netplay->replay_frame_count = netplay->self_frame_count; + netplay_wait_and_init_serialization(netplay); + netplay->is_replay = false; + } + else + { + netplay_wait_and_init_serialization(netplay); + } + } + /* There is a subtlty in whether the load comes before or after the * current frame: * @@ -1222,6 +1239,13 @@ bool netplay_pre_frame(netplay_t *netplay) if (netplay->local_paused) netplay_frontend_paused(netplay, false); + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + { + /* Are we ready now? */ + if (!(core_serialization_quirks() & RETRO_SERIALIZATION_QUIRK_INITIALIZING) || netplay->self_frame_count > 60) + netplay_init_serialization(netplay); + } + if (!netplay->net_cbs->pre_frame(netplay)) return false; From 2c0eb777569962842f86ded6e1024ee0b2b3b30b Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 14:51:05 -0400 Subject: [PATCH 07/15] core_[un]serialize waits for initialization quirk. --- core_impl.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/core_impl.c b/core_impl.c index e0197842f5..0f58f60633 100644 --- a/core_impl.c +++ b/core_impl.c @@ -282,6 +282,8 @@ bool core_unserialize(retro_ctx_serialize_info_t *info) { if (!info) return false; + if (core_serialization_quirks_v & RETRO_SERIALIZATION_QUIRK_INITIALIZING) + return false; if (!core.retro_unserialize(info->data_const, info->size)) return false; @@ -292,20 +294,12 @@ bool core_unserialize(retro_ctx_serialize_info_t *info) return true; } -uint32_t core_serialization_quirks(void) -{ - return core_serialization_quirks_v; -} - -void core_set_serialization_quirks(uint32_t quirks) -{ - core_serialization_quirks_v = quirks; -} - bool core_serialize(retro_ctx_serialize_info_t *info) { if (!info) return false; + if (core_serialization_quirks_v & RETRO_SERIALIZATION_QUIRK_INITIALIZING) + return false; if (!core.retro_serialize(info->data, info->size)) return false; return true; @@ -319,6 +313,16 @@ bool core_serialize_size(retro_ctx_size_info_t *info) return true; } +uint32_t core_serialization_quirks(void) +{ + return core_serialization_quirks_v; +} + +void core_set_serialization_quirks(uint32_t quirks) +{ + core_serialization_quirks_v = quirks; +} + bool core_frame(retro_ctx_frame_info_t *info) { if (!info || !retro_ctx.frame_cb) From 90bd741786ea2cae3432b585f93bf8001fe77f9a Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 15:37:02 -0400 Subject: [PATCH 08/15] Switching serialization quirks to uint64_t for consistency with other bitfields --- core.h | 4 ++-- core_impl.c | 6 +++--- libretro-common/include/libretro.h | 2 +- network/netplay/netplay.c | 10 +++++----- network/netplay/netplay.h | 2 +- network/netplay/netplay_private.h | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core.h b/core.h index 258588c4ab..b7bf4657a8 100644 --- a/core.h +++ b/core.h @@ -178,9 +178,9 @@ bool core_set_environment(retro_ctx_environ_info_t *info); bool core_serialize_size(retro_ctx_size_info_t *info); -uint32_t core_serialization_quirks(void); +uint64_t core_serialization_quirks(void); -void core_set_serialization_quirks(uint32_t quirks); +void core_set_serialization_quirks(uint64_t quirks); bool core_serialize(retro_ctx_serialize_info_t *info); diff --git a/core_impl.c b/core_impl.c index 0f58f60633..cd86d1b058 100644 --- a/core_impl.c +++ b/core_impl.c @@ -52,7 +52,7 @@ static bool core_game_loaded = false; static bool core_input_polled = false; static bool core_has_set_input_descriptors = false; static struct retro_callbacks retro_ctx; -static uint32_t core_serialization_quirks_v = 0; +static uint64_t core_serialization_quirks_v = 0; static void core_input_state_poll_maybe(void) { @@ -313,12 +313,12 @@ bool core_serialize_size(retro_ctx_size_info_t *info) return true; } -uint32_t core_serialization_quirks(void) +uint64_t core_serialization_quirks(void) { return core_serialization_quirks_v; } -void core_set_serialization_quirks(uint32_t quirks) +void core_set_serialization_quirks(uint64_t quirks) { core_serialization_quirks_v = quirks; } diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 2ba7c6a50f..e1a3c46e71 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -996,7 +996,7 @@ struct retro_hw_render_context_negotiation_interface * one it was saved on. */ #define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 - /* uint32_t * -- + /* uint64_t * -- * Sets quirk flags associated with serialization. */ diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index db582fe2bd..472e69a691 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -1016,7 +1016,7 @@ bool netplay_init_serialization(netplay_t *netplay) } /* Once initialized, we no longer exhibit this quirk */ - netplay->quirks &= ~((uint32_t) NETPLAY_QUIRK_INITIALIZATION); + netplay->quirks &= ~((uint64_t) NETPLAY_QUIRK_INITIALIZATION); return true; } @@ -1062,7 +1062,7 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) **/ netplay_t *netplay_new(const char *server, uint16_t port, unsigned frames, unsigned check_frames, const struct retro_callbacks *cb, - bool spectate, const char *nick, uint32_t quirks) + bool spectate, const char *nick, uint64_t quirks) { netplay_t *netplay = (netplay_t*)calloc(1, sizeof(*netplay)); if (!netplay) @@ -1398,8 +1398,8 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port) { struct retro_callbacks cbs = {0}; settings_t *settings = config_get_ptr(); - uint32_t serialization_quirks = 0; - uint32_t quirks = 0; + uint64_t serialization_quirks = 0; + uint64_t quirks = 0; if (!netplay_enabled) return false; @@ -1415,7 +1415,7 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port) /* Map the core's quirks to our quirks */ serialization_quirks = core_serialization_quirks(); - if ((serialization_quirks & ~((uint32_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))) + if ((serialization_quirks & ~((uint64_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))) { /* Quirks we don't support! Just disable everything. */ quirks |= NETPLAY_QUIRK_NO_SAVESTATES; diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index 703437e0fc..4900a85530 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -149,7 +149,7 @@ size_t audio_sample_batch_net(const int16_t *data, size_t frames); netplay_t *netplay_new(const char *server, uint16_t port, unsigned frames, unsigned check_frames, const struct retro_callbacks *cb, bool spectate, - const char *nick, uint32_t quirks); + const char *nick, uint64_t quirks); /** * netplay_free: diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index 35cb47c530..a5041667b6 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -140,7 +140,7 @@ struct netplay bool force_rewind; /* Quirks in the savestate implementation */ - unsigned quirks; + uint64_t quirks; /* Force our state to be sent to the other side. Used when they request a * savestate, to send at the next pre-frame. */ From fad6e2e87e84d3c67e5977b0c7a2f47f0a0fd224 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 15:51:15 -0400 Subject: [PATCH 09/15] Make quirks a bidirectional interface, so the frontend can refuse quirks it doesn't support, in particular variable sized states. --- dynamic.c | 11 ++++++++++- libretro-common/include/libretro.h | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dynamic.c b/dynamic.c index c74bb92c04..b2ad6bb394 100644 --- a/dynamic.c +++ b/dynamic.c @@ -1609,7 +1609,16 @@ bool rarch_environment_cb(unsigned cmd, void *data) } case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS: - core_set_serialization_quirks(*((uint32_t *) data)); + core_set_serialization_quirks(*((uint64_t *) data)); + + /* Zero any unrecognized quirks */ + *((uint64_t *) data) &= ~((uint64_t) + ((RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT-1) | + RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT)); + + /* And zero variable-sized serialization, which we don't support */ + *((uint64_t *) data) &= ~((uint64_t) RETRO_SERIALIZATION_QUIRK_VARIABLE_SIZE); + break; /* Default */ diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index e1a3c46e71..7f8e340aa5 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -997,7 +997,8 @@ struct retro_hw_render_context_negotiation_interface #define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 /* uint64_t * -- - * Sets quirk flags associated with serialization. + * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't + * recognize or support. */ From 919897c46410e2d9789827656c0c047c4dca42de Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 18:36:02 -0400 Subject: [PATCH 10/15] Some style/clarity nits. --- dynamic.c | 17 ++++++++++------- libretro-common/include/libretro.h | 26 +++++++++++++------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/dynamic.c b/dynamic.c index b2ad6bb394..03345d02ca 100644 --- a/dynamic.c +++ b/dynamic.c @@ -1609,17 +1609,20 @@ bool rarch_environment_cb(unsigned cmd, void *data) } case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS: - core_set_serialization_quirks(*((uint64_t *) data)); + { + uint64_t *quirks = (uint64_t *) data; - /* Zero any unrecognized quirks */ - *((uint64_t *) data) &= ~((uint64_t) - ((RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT-1) | - RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT)); + core_set_serialization_quirks(*quirks); - /* And zero variable-sized serialization, which we don't support */ - *((uint64_t *) data) &= ~((uint64_t) RETRO_SERIALIZATION_QUIRK_VARIABLE_SIZE); + /* Zero any unrecognized quirks, and zero unsupported VARIABLE_SIZE */ + *quirks &= (RETRO_SERIALIZATION_QUIRK_INCOMPLETE + |RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE + |RETRO_SERIALIZATION_QUIRK_INITIALIZING + |RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION + |RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT); break; + } /* Default */ default: diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 7f8e340aa5..59914d2c59 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -976,29 +976,29 @@ struct retro_hw_render_context_negotiation_interface * so it will be used after SET_HW_RENDER, but before the context_reset callback. */ +/* Serialized state is incomplete in some way. Set if serialization is + * usable in typical end-user cases but should not be relied upon to + * implement frame-sensitive frontend features such as netplay or + * rerecording. */ #define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0) - /* Serialized state is incomplete in some way. Set if serialization is - * usable in typical end-user cases but should not be relied upon to - * implement frame-sensitive frontend features such as netplay or - * rerecording. */ +/* The core must spend some time initializing before serialization is + * safe. */ #define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1) - /* The core must spend some time initializing before serialization is - * safe. */ +/* If MUST_INITIALIZE is set, this should also be set if initialization is + * in progress. */ #define RETRO_SERIALIZATION_QUIRK_INITIALIZING (1 << 2) - /* If MUST_INITIALIZE is set, this should also be set if initialization is - * in progress. */ +/* Serialization size may change within a session. */ #define RETRO_SERIALIZATION_QUIRK_VARIABLE_SIZE (1 << 3) - /* Serialization size may change within a session. */ +/* Serialized state can only be loaded during the same session. */ #define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4) - /* Serialized state can only be loaded during the same session. */ +/* Serialized state cannot be loaded on a different architecture from the + * one it was saved on. */ #define RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT (1 << 5) - /* Serialized state cannot be loaded on a different architecture from the - * one it was saved on. */ #define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 /* uint64_t * -- * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't - * recognize or support. + * recognize or support. Should be set during retro_init or retro_load_game. */ From 1483aa710fc490fac985c2cd4a0bec55e7c4dd39 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 19:02:54 -0400 Subject: [PATCH 11/15] Changing the initialization quirk to communicate by retro_serialize and the variable size quirk to use a core and front flag. --- core_impl.c | 4 ---- dynamic.c | 9 --------- libretro-common/include/libretro.h | 10 ++++++---- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/core_impl.c b/core_impl.c index cd86d1b058..9f1cb1ebbf 100644 --- a/core_impl.c +++ b/core_impl.c @@ -282,8 +282,6 @@ bool core_unserialize(retro_ctx_serialize_info_t *info) { if (!info) return false; - if (core_serialization_quirks_v & RETRO_SERIALIZATION_QUIRK_INITIALIZING) - return false; if (!core.retro_unserialize(info->data_const, info->size)) return false; @@ -298,8 +296,6 @@ bool core_serialize(retro_ctx_serialize_info_t *info) { if (!info) return false; - if (core_serialization_quirks_v & RETRO_SERIALIZATION_QUIRK_INITIALIZING) - return false; if (!core.retro_serialize(info->data, info->size)) return false; return true; diff --git a/dynamic.c b/dynamic.c index 03345d02ca..e6d1c45d2e 100644 --- a/dynamic.c +++ b/dynamic.c @@ -1611,16 +1611,7 @@ bool rarch_environment_cb(unsigned cmd, void *data) case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS: { uint64_t *quirks = (uint64_t *) data; - core_set_serialization_quirks(*quirks); - - /* Zero any unrecognized quirks, and zero unsupported VARIABLE_SIZE */ - *quirks &= (RETRO_SERIALIZATION_QUIRK_INCOMPLETE - |RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE - |RETRO_SERIALIZATION_QUIRK_INITIALIZING - |RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION - |RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT); - break; } diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 59914d2c59..241f1006d6 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -982,13 +982,15 @@ struct retro_hw_render_context_negotiation_interface * rerecording. */ #define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0) /* The core must spend some time initializing before serialization is - * safe. */ + * supported. */ #define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1) /* If MUST_INITIALIZE is set, this should also be set if initialization is * in progress. */ -#define RETRO_SERIALIZATION_QUIRK_INITIALIZING (1 << 2) /* Serialization size may change within a session. */ -#define RETRO_SERIALIZATION_QUIRK_VARIABLE_SIZE (1 << 3) +#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2) +/* Set by the frontend to acknowledge that it supports variable-sized + * states. */ +#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3) /* Serialized state can only be loaded during the same session. */ #define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4) /* Serialized state cannot be loaded on a different architecture from the @@ -998,7 +1000,7 @@ struct retro_hw_render_context_negotiation_interface #define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 /* uint64_t * -- * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't - * recognize or support. Should be set during retro_init or retro_load_game. + * recognize or support. Should be set in either retro_init or retro_load_game, but not both. */ From 51683661e569bae3e857f59db8105d2f80e5f1a0 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Fri, 30 Sep 2016 19:04:58 -0400 Subject: [PATCH 12/15] Changes to Netplay for the recent changes to quirks. --- network/netplay/netplay.c | 56 ++++++++++++++++++++++--------- network/netplay/netplay_private.h | 1 - 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index 472e69a691..e5aa7402fa 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -969,27 +969,52 @@ void netplay_log_connection(const struct sockaddr_storage *their_addr, -bool netplay_wait_and_init_serialization(netplay_t *netplay) +bool netplay_try_init_serialization(netplay_t *netplay) { - int frames; + retro_ctx_serialize_info_t serial_info; if (netplay->state_size) return true; - /* Wait maximally 60 frames, or until the core reports it's initialized */ - for (frames = 0; (core_serialization_quirks() & RETRO_SERIALIZATION_QUIRK_INITIALIZING) && frames < 60; frames++) - { + if (!netplay_init_serialization(netplay)) + return false; + + /* Check if we can actually save */ + serial_info.data_const = NULL; + serial_info.data = netplay->buffer[netplay->self_ptr].state; + serial_info.size = netplay->state_size; + + if (!core_serialize(&serial_info)) + return false; + + /* Once initialized, we no longer exhibit this quirk */ + netplay->quirks &= ~((uint64_t) NETPLAY_QUIRK_INITIALIZATION); + + return true; +} + +bool netplay_wait_and_init_serialization(netplay_t *netplay) +{ + int frame; + + if (netplay->state_size) + return true; + + /* Wait a maximum of 60 frames */ + for (frame = 0; frame < 60; frame++) { + if (netplay_try_init_serialization(netplay)) + return true; + #if defined(HAVE_THREADS) - autosave_lock(); + autosave_lock(); #endif - core_run(); + core_run(); #if defined(HAVE_THREADS) - autosave_unlock(); + autosave_unlock(); #endif } - return netplay_init_serialization(netplay); - + return false; } bool netplay_init_serialization(netplay_t *netplay) @@ -1002,6 +1027,9 @@ bool netplay_init_serialization(netplay_t *netplay) core_serialize_size(&info); + if (!info.size) + return false; + netplay->state_size = info.size; for (i = 0; i < netplay->buffer_size; i++) @@ -1015,9 +1043,6 @@ bool netplay_init_serialization(netplay_t *netplay) } } - /* Once initialized, we no longer exhibit this quirk */ - netplay->quirks &= ~((uint64_t) NETPLAY_QUIRK_INITIALIZATION); - return true; } @@ -1039,7 +1064,7 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) return false; if (!(netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)) - return netplay_init_serialization(netplay); + netplay_init_serialization(netplay); return true; } @@ -1242,8 +1267,7 @@ bool netplay_pre_frame(netplay_t *netplay) if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) { /* Are we ready now? */ - if (!(core_serialization_quirks() & RETRO_SERIALIZATION_QUIRK_INITIALIZING) || netplay->self_frame_count > 60) - netplay_init_serialization(netplay); + netplay_try_init_serialization(netplay); } if (!netplay->net_cbs->pre_frame(netplay)) diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index a5041667b6..9bb566f9e3 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -50,7 +50,6 @@ #define NETPLAY_QUIRK_MAP_UNDERSTOOD \ (RETRO_SERIALIZATION_QUIRK_INCOMPLETE \ |RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE \ - |RETRO_SERIALIZATION_QUIRK_INITIALIZING \ |RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION \ |RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT) #define NETPLAY_QUIRK_MAP_NO_SAVESTATES \ From a636bac4281ded9ad4d07ede7f12f2b3b811ecbd Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Sat, 1 Oct 2016 07:44:09 -0400 Subject: [PATCH 13/15] Style and clarity nits. --- libretro-common/include/libretro.h | 6 ++---- network/netplay/netplay.c | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 241f1006d6..60c0c86f94 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -984,8 +984,6 @@ struct retro_hw_render_context_negotiation_interface /* The core must spend some time initializing before serialization is * supported. */ #define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1) -/* If MUST_INITIALIZE is set, this should also be set if initialization is - * in progress. */ /* Serialization size may change within a session. */ #define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2) /* Set by the frontend to acknowledge that it supports variable-sized @@ -993,8 +991,8 @@ struct retro_hw_render_context_negotiation_interface #define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3) /* Serialized state can only be loaded during the same session. */ #define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4) -/* Serialized state cannot be loaded on a different architecture from the - * one it was saved on. */ +/* Serialized state cannot be loaded on a different architecture from the one + * it was saved on, typically due to endianness or word length issues. */ #define RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT (1 << 5) #define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index e5aa7402fa..5dede24636 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -1439,16 +1439,16 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port) /* Map the core's quirks to our quirks */ serialization_quirks = core_serialization_quirks(); - if ((serialization_quirks & ~((uint64_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))) + if (serialization_quirks & ~((uint64_t) NETPLAY_QUIRK_MAP_UNDERSTOOD)) { /* Quirks we don't support! Just disable everything. */ quirks |= NETPLAY_QUIRK_NO_SAVESTATES; } - if ((serialization_quirks & NETPLAY_QUIRK_MAP_NO_SAVESTATES)) + if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_SAVESTATES) quirks |= NETPLAY_QUIRK_NO_SAVESTATES; - if ((serialization_quirks & NETPLAY_QUIRK_MAP_NO_TRANSMISSION)) + if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_TRANSMISSION) quirks |= NETPLAY_QUIRK_NO_TRANSMISSION; - if ((serialization_quirks & NETPLAY_QUIRK_MAP_INITIALIZATION)) + if (serialization_quirks & NETPLAY_QUIRK_MAP_INITIALIZATION) quirks |= NETPLAY_QUIRK_INITIALIZATION; if (netplay_is_client) From 701cc5a18cfa2579ce0d947395f0dd31c4dd9770 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Mon, 3 Oct 2016 16:38:38 -0400 Subject: [PATCH 14/15] Splitting endian and other platform savestate quirks. --- libretro-common/include/libretro.h | 10 +++++++--- network/netplay/netplay_private.h | 6 ++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 60c0c86f94..8c621f980f 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -991,9 +991,13 @@ struct retro_hw_render_context_negotiation_interface #define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3) /* Serialized state can only be loaded during the same session. */ #define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4) -/* Serialized state cannot be loaded on a different architecture from the one - * it was saved on, typically due to endianness or word length issues. */ -#define RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT (1 << 5) +/* Serialized state cannot be loaded on an architecture with a different + * endianness from the one it was saved on. */ +#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5) +/* Serialized state cannot be loaded on a different platform from the one it + * was saved on for reasons other than endianness, such as word or C type size + * dependence */ +#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6) #define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 /* uint64_t * -- diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index 9bb566f9e3..ae80b5eb53 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -51,12 +51,14 @@ (RETRO_SERIALIZATION_QUIRK_INCOMPLETE \ |RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE \ |RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION \ - |RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT) + |RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT \ + |RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT) #define NETPLAY_QUIRK_MAP_NO_SAVESTATES \ (RETRO_SERIALIZATION_QUIRK_INCOMPLETE) #define NETPLAY_QUIRK_MAP_NO_TRANSMISSION \ (RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION \ - |RETRO_SERIALIZATION_QUIRK_ARCHITECTURE_DEPENDENT) + |RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT \ + |RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT) #define NETPLAY_QUIRK_MAP_INITIALIZATION \ (RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE) From 8cfb4b573ba7c1a50f05573142a62e0f730d9700 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Mon, 3 Oct 2016 16:58:27 -0400 Subject: [PATCH 15/15] Removing confusing "or C type" verbage --- libretro-common/include/libretro.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 8c621f980f..d8662e5ebd 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -995,7 +995,7 @@ struct retro_hw_render_context_negotiation_interface * endianness from the one it was saved on. */ #define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5) /* Serialized state cannot be loaded on a different platform from the one it - * was saved on for reasons other than endianness, such as word or C type size + * was saved on for reasons other than endianness, such as word size * dependence */ #define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)