mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-24 00:20:01 +00:00
New sync system
The idea: * Use a fixed number of delay_frames (eventually to be fixed at 120, currently still uses the config variable, 0 will still be an option) * Determine how long it takes to simulate a frame. * Stall only if resimulating the intervening frames would be sufficiently annoying (currently fixed at three frames worth of time) Because clients always try to catch up, the actual frame delay works out automatically to be minimally zero and maximally the latency. If one client is underpowered but the other is fine, the powerful one will automatically take up the slack. Seems like the most reasonable system.
This commit is contained in:
parent
6890456ac0
commit
45d732a014
@ -43,7 +43,6 @@ enum rarch_netplay_ctl_state
|
||||
RARCH_NETPLAY_CTL_IS_DATA_INITED,
|
||||
RARCH_NETPLAY_CTL_PAUSE,
|
||||
RARCH_NETPLAY_CTL_UNPAUSE,
|
||||
RARCH_NETPLAY_CTL_CATCH_UP,
|
||||
RARCH_NETPLAY_CTL_LOAD_SAVESTATE,
|
||||
RARCH_NETPLAY_CTL_DISCONNECT
|
||||
};
|
||||
|
@ -216,8 +216,23 @@ static bool netplay_poll(void)
|
||||
break;
|
||||
|
||||
default: /* not stalling */
|
||||
{
|
||||
retro_time_t max_ahead;
|
||||
|
||||
/* Figure out how many frames we're allowed to be ahead: Ideally we need to be
|
||||
* able to run our entire stall worth of frames in one real frame. In
|
||||
* practice, we'll allow a couple jitter frames. (FIXME: hard coded
|
||||
* as three 60FPS frame) */
|
||||
if (netplay_data->frame_run_time_avg)
|
||||
max_ahead = 50000 / netplay_data->frame_run_time_avg;
|
||||
else
|
||||
max_ahead = netplay_data->delay_frames;
|
||||
if (max_ahead > netplay_data->delay_frames)
|
||||
max_ahead = netplay_data->delay_frames;
|
||||
|
||||
/* Are we too far ahead? */
|
||||
netplay_update_unread_ptr(netplay_data);
|
||||
if (netplay_data->unread_frame_count + netplay_data->delay_frames
|
||||
if (netplay_data->unread_frame_count + max_ahead
|
||||
<= netplay_data->self_frame_count)
|
||||
{
|
||||
netplay_data->stall = NETPLAY_STALL_RUNNING_FAST;
|
||||
@ -246,6 +261,7 @@ static bool netplay_poll(void)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're stalling, consider disconnection */
|
||||
@ -922,9 +938,6 @@ bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data)
|
||||
case RARCH_NETPLAY_CTL_UNPAUSE:
|
||||
netplay_frontend_paused(netplay_data, false);
|
||||
break;
|
||||
case RARCH_NETPLAY_CTL_CATCH_UP:
|
||||
ret = netplay_data->catch_up;
|
||||
break;
|
||||
case RARCH_NETPLAY_CTL_LOAD_SAVESTATE:
|
||||
netplay_load_savestate(netplay_data, (retro_ctx_serialize_info_t*)data, true);
|
||||
break;
|
||||
|
@ -45,6 +45,8 @@
|
||||
#define MAX_RETRIES 16
|
||||
#define RETRY_MS 500
|
||||
|
||||
#define NETPLAY_FRAME_RUN_TIME_WINDOW 128
|
||||
|
||||
#define PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1)
|
||||
#define NEXT_PTR(x) ((x + 1) % netplay->buffer_size)
|
||||
|
||||
@ -415,14 +417,25 @@ struct netplay
|
||||
bool flip;
|
||||
uint32_t flip_frame;
|
||||
|
||||
/* Netplay pausing
|
||||
*/
|
||||
/* Netplay pausing */
|
||||
bool local_paused;
|
||||
bool remote_paused;
|
||||
|
||||
/* And stalling */
|
||||
/* Old-style stalling (to be removed) */
|
||||
uint32_t delay_frames;
|
||||
|
||||
/* We stall if we're far enough ahead that we couldn't transparently rewind.
|
||||
* To know if we could transparently rewind, we need to know how long
|
||||
* running a frame takes. We record that every frame and get a running
|
||||
* (window) average */
|
||||
retro_time_t frame_run_time[NETPLAY_FRAME_RUN_TIME_WINDOW];
|
||||
int frame_run_time_ptr;
|
||||
retro_time_t frame_run_time_sum, frame_run_time_avg;
|
||||
|
||||
/* Are we stalled? */
|
||||
enum rarch_netplay_stall_reason stall;
|
||||
|
||||
/* How long have we been stalled? */
|
||||
retro_time_t stall_time;
|
||||
|
||||
/* Opposite of stalling, should we be catching up? */
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "netplay_private.h"
|
||||
|
||||
#include "../../autosave.h"
|
||||
#include "../../driver.h"
|
||||
#include "../../input/input_driver.h"
|
||||
|
||||
#if 0
|
||||
#define DEBUG_NONDETERMINISTIC_CORES
|
||||
@ -341,6 +343,8 @@ process:
|
||||
*/
|
||||
void netplay_sync_post_frame(netplay_t *netplay)
|
||||
{
|
||||
int catch_up_ct;
|
||||
|
||||
netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
|
||||
netplay->self_frame_count++;
|
||||
|
||||
@ -407,11 +411,15 @@ void netplay_sync_post_frame(netplay_t *netplay)
|
||||
|
||||
while (netplay->replay_frame_count < netplay->self_frame_count)
|
||||
{
|
||||
retro_time_t start, tm;
|
||||
|
||||
struct delta_frame *ptr = &netplay->buffer[netplay->replay_ptr];
|
||||
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);
|
||||
core_serialize(&serial_info);
|
||||
@ -442,8 +450,20 @@ void netplay_sync_post_frame(netplay_t *netplay)
|
||||
RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get our time window */
|
||||
tm = cpu_features_get_time_usec() - start;
|
||||
netplay->frame_run_time_sum -= netplay->frame_run_time[netplay->frame_run_time_ptr];
|
||||
netplay->frame_run_time[netplay->frame_run_time_ptr] = tm;
|
||||
netplay->frame_run_time_sum += tm;
|
||||
netplay->frame_run_time_ptr++;
|
||||
if (netplay->frame_run_time_ptr >= NETPLAY_FRAME_RUN_TIME_WINDOW)
|
||||
netplay->frame_run_time_ptr = 0;
|
||||
}
|
||||
|
||||
/* Average our time */
|
||||
netplay->frame_run_time_avg = netplay->frame_run_time_sum / NETPLAY_FRAME_RUN_TIME_WINDOW;
|
||||
|
||||
if (netplay->unread_frame_count < netplay->self_frame_count)
|
||||
{
|
||||
netplay->other_ptr = netplay->unread_ptr;
|
||||
@ -459,10 +479,22 @@ void netplay_sync_post_frame(netplay_t *netplay)
|
||||
}
|
||||
|
||||
/* If we're behind, try to catch up */
|
||||
if (netplay->self_frame_count < netplay->unread_frame_count - 2)
|
||||
netplay->catch_up = true;
|
||||
/* FIXME: Any use in interacting with the real fast forwarding? */
|
||||
if (netplay->catch_up)
|
||||
catch_up_ct = 0;
|
||||
else
|
||||
catch_up_ct = 2;
|
||||
if (netplay->self_frame_count < netplay->unread_frame_count - catch_up_ct)
|
||||
{
|
||||
netplay->catch_up = true;
|
||||
input_driver_set_nonblock_state();
|
||||
}
|
||||
else
|
||||
{
|
||||
netplay->catch_up = false;
|
||||
input_driver_unset_nonblock_state();
|
||||
}
|
||||
driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL);
|
||||
|
||||
/* If we're supposed to stall, rewind (we shouldn't get this far if we're
|
||||
* stalled, so this is a last resort) */
|
||||
|
Loading…
Reference in New Issue
Block a user