mirror of
https://github.com/libretro/RetroArch
synced 2025-04-09 21:45:45 +00:00
Workarounds for cores that can't be saved early
Netplay now never serializes/unserializes cores before 60 frames have been emulated. This is a workaround for buggy cores and documented as such.
This commit is contained in:
parent
731f2c8f2b
commit
f665881d6d
@ -596,13 +596,18 @@ static bool netplay_poll(netplay_t *netplay)
|
|||||||
if (netplay_is_server(netplay) && netplay->spectate.enabled)
|
if (netplay_is_server(netplay) && netplay->spectate.enabled)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Read Netplay input, block if we're configured to stall for input every
|
/* WORKAROUND: The only reason poll_input is ignored in the first frame is
|
||||||
* frame */
|
* that some cores can't report state size until after the first frame. */
|
||||||
res = poll_input(netplay, (netplay->stall_frames == 0) && (netplay->read_frame_count <= netplay->self_frame_count));
|
if (netplay->self_frame_count > 0)
|
||||||
if (res == -1)
|
|
||||||
{
|
{
|
||||||
hangup(netplay);
|
/* Read Netplay input, block if we're configured to stall for input every
|
||||||
return false;
|
* frame */
|
||||||
|
res = poll_input(netplay, (netplay->stall_frames == 0) && (netplay->read_frame_count <= netplay->self_frame_count));
|
||||||
|
if (res == -1)
|
||||||
|
{
|
||||||
|
hangup(netplay);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simulate the input if we don't have real input */
|
/* Simulate the input if we don't have real input */
|
||||||
@ -940,7 +945,6 @@ static bool init_socket(netplay_t *netplay, const char *server, uint16_t port)
|
|||||||
static bool netplay_init_buffers(netplay_t *netplay, unsigned frames)
|
static bool netplay_init_buffers(netplay_t *netplay, unsigned frames)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
retro_ctx_size_info_t info;
|
|
||||||
|
|
||||||
if (!netplay)
|
if (!netplay)
|
||||||
return false;
|
return false;
|
||||||
@ -957,17 +961,9 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames)
|
|||||||
if (!netplay->buffer)
|
if (!netplay->buffer)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
core_serialize_size(&info);
|
/* WORKAROUND: The code to initialize state buffers really should be here.
|
||||||
|
* It's been moved to work around cores that can't core_serialize_size
|
||||||
netplay->state_size = info.size;
|
* early. */
|
||||||
|
|
||||||
for (i = 0; i < netplay->buffer_size; i++)
|
|
||||||
{
|
|
||||||
netplay->buffer[i].state = calloc(netplay->state_size, 1);
|
|
||||||
|
|
||||||
if (!netplay->buffer[i].state)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1136,7 +1132,8 @@ void netplay_free(netplay_t *netplay)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < netplay->buffer_size; i++)
|
for (i = 0; i < netplay->buffer_size; i++)
|
||||||
free(netplay->buffer[i].state);
|
if (netplay->buffer[i].state)
|
||||||
|
free(netplay->buffer[i].state);
|
||||||
|
|
||||||
free(netplay->buffer);
|
free(netplay->buffer);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "../../autosave.h"
|
#include "../../autosave.h"
|
||||||
|
|
||||||
|
#define TOO_EARLY_TO_SAVE 60
|
||||||
|
|
||||||
static void netplay_handle_frame_hash(netplay_t *netplay, struct delta_frame *delta)
|
static void netplay_handle_frame_hash(netplay_t *netplay, struct delta_frame *delta)
|
||||||
{
|
{
|
||||||
if (netplay_is_server(netplay))
|
if (netplay_is_server(netplay))
|
||||||
@ -66,7 +68,12 @@ static bool netplay_net_pre_frame(netplay_t *netplay)
|
|||||||
serial_info.data = netplay->buffer[netplay->self_ptr].state;
|
serial_info.data = netplay->buffer[netplay->self_ptr].state;
|
||||||
serial_info.size = netplay->state_size;
|
serial_info.size = netplay->state_size;
|
||||||
|
|
||||||
if (core_serialize(&serial_info))
|
if (!netplay->has_connection && netplay->self_frame_count < TOO_EARLY_TO_SAVE)
|
||||||
|
{
|
||||||
|
/* WORKAROUND: Some cores don't like being save/loadstated too early.
|
||||||
|
* If we're not even connected yet, just don't bother. */
|
||||||
|
}
|
||||||
|
else if (netplay->savestates_work && core_serialize(&serial_info))
|
||||||
{
|
{
|
||||||
if (netplay->force_send_savestate)
|
if (netplay->force_send_savestate)
|
||||||
{
|
{
|
||||||
@ -173,6 +180,30 @@ static void netplay_net_post_frame(netplay_t *netplay)
|
|||||||
netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
|
netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
|
||||||
netplay->self_frame_count++;
|
netplay->self_frame_count++;
|
||||||
|
|
||||||
|
/* WORKAROUND: We initialize the buffer states late to work around cores
|
||||||
|
* that can't even core_serialize_size early. */
|
||||||
|
if (netplay->self_frame_count == 1 && netplay->state_size == 0)
|
||||||
|
{
|
||||||
|
int 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->savestates_work = false;
|
||||||
|
netplay->stall_frames = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Only relevant if we're connected */
|
/* Only relevant if we're connected */
|
||||||
if (!netplay->has_connection)
|
if (!netplay->has_connection)
|
||||||
return;
|
return;
|
||||||
@ -208,6 +239,24 @@ static void netplay_net_post_frame(netplay_t *netplay)
|
|||||||
netplay->replay_ptr = netplay->other_ptr;
|
netplay->replay_ptr = netplay->other_ptr;
|
||||||
netplay->replay_frame_count = netplay->other_frame_count;
|
netplay->replay_frame_count = netplay->other_frame_count;
|
||||||
|
|
||||||
|
/* WORKAROUND: Some cores cannot serialize or unserialize too early in
|
||||||
|
* execution. We avoid the problem by forcing some phantom frames to
|
||||||
|
* pass. */
|
||||||
|
if (netplay->self_frame_count < TOO_EARLY_TO_SAVE)
|
||||||
|
{
|
||||||
|
int frameskip;
|
||||||
|
for (frameskip = 0; frameskip < TOO_EARLY_TO_SAVE; frameskip++)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_THREADS)
|
||||||
|
autosave_lock();
|
||||||
|
#endif
|
||||||
|
core_run();
|
||||||
|
#if defined(HAVE_THREADS)
|
||||||
|
autosave_unlock();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serial_info.data = NULL;
|
serial_info.data = NULL;
|
||||||
serial_info.data_const = netplay->buffer[netplay->replay_ptr].state;
|
serial_info.data_const = netplay->buffer[netplay->replay_ptr].state;
|
||||||
serial_info.size = netplay->state_size;
|
serial_info.size = netplay->state_size;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user