mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 12:32:52 +00:00
New approach to input latency
This commit is contained in:
parent
2b3343a687
commit
c4cb94db19
@ -106,10 +106,10 @@ static bool netplay_can_poll(netplay_t *netplay)
|
||||
static bool get_self_input_state(netplay_t *netplay)
|
||||
{
|
||||
uint32_t state[WORDS_PER_INPUT] = {0, 0, 0};
|
||||
struct delta_frame *ptr = &netplay->buffer[netplay->self_ptr];
|
||||
struct delta_frame *ptr = &netplay->buffer[netplay->input_ptr];
|
||||
size_t i;
|
||||
|
||||
if (!netplay_delta_frame_ready(netplay, ptr, netplay->self_frame_count))
|
||||
if (!netplay_delta_frame_ready(netplay, ptr, netplay->input_frame_count))
|
||||
return false;
|
||||
|
||||
if (ptr->have_local)
|
||||
@ -118,7 +118,7 @@ static bool get_self_input_state(netplay_t *netplay)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!input_driver_is_libretro_input_blocked() && netplay->self_frame_count > 0)
|
||||
if (!input_driver_is_libretro_input_blocked() && netplay->input_frame_count > 0)
|
||||
{
|
||||
/* First frame we always give zero input since relying on
|
||||
* input from first frame screws up when we use -F 0. */
|
||||
@ -205,7 +205,7 @@ static bool netplay_poll(void)
|
||||
netplay_update_unread_ptr(netplay_data);
|
||||
if (netplay_data->stateless_mode &&
|
||||
netplay_data->connected_players &&
|
||||
netplay_data->unread_frame_count <= netplay_data->self_frame_count)
|
||||
netplay_data->unread_frame_count <= netplay_data->run_frame_count)
|
||||
res = netplay_poll_net_input(netplay_data, true);
|
||||
else
|
||||
res = netplay_poll_net_input(netplay_data, false);
|
||||
@ -218,16 +218,16 @@ static bool netplay_poll(void)
|
||||
}
|
||||
|
||||
/* Simulate the input if we don't have real input */
|
||||
netplay_simulate_input(netplay_data, netplay_data->self_ptr, false);
|
||||
netplay_simulate_input(netplay_data, netplay_data->run_ptr, false);
|
||||
|
||||
/* Consider stalling */
|
||||
/* If we're stalled, consider unstalling */
|
||||
switch (netplay_data->stall)
|
||||
{
|
||||
case NETPLAY_STALL_RUNNING_FAST:
|
||||
{
|
||||
netplay_update_unread_ptr(netplay_data);
|
||||
if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES - 2
|
||||
> netplay_data->self_frame_count)
|
||||
> netplay_data->input_frame_count)
|
||||
{
|
||||
netplay_data->stall = NETPLAY_STALL_NONE;
|
||||
for (i = 0; i < netplay_data->connections_size; i++)
|
||||
@ -240,6 +240,11 @@ static bool netplay_poll(void)
|
||||
break;
|
||||
}
|
||||
|
||||
case NETPLAY_STALL_INPUT_LATENCY:
|
||||
/* Just let it recalculate momentarily */
|
||||
netplay_data->stall = NETPLAY_STALL_NONE;
|
||||
break;
|
||||
|
||||
case NETPLAY_STALL_SERVER_REQUESTED:
|
||||
{
|
||||
/* See if the stall is done */
|
||||
@ -261,38 +266,50 @@ static bool netplay_poll(void)
|
||||
break;
|
||||
|
||||
default: /* not stalling */
|
||||
{
|
||||
/* Are we too far ahead? */
|
||||
netplay_update_unread_ptr(netplay_data);
|
||||
if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES
|
||||
<= netplay_data->self_frame_count)
|
||||
{
|
||||
netplay_data->stall = NETPLAY_STALL_RUNNING_FAST;
|
||||
netplay_data->stall_time = cpu_features_get_time_usec();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Figure out who to blame */
|
||||
if (netplay_data->is_server)
|
||||
/* If we're not stalled, consider stalling */
|
||||
if (!netplay_data->stall)
|
||||
{
|
||||
netplay_update_unread_ptr(netplay_data);
|
||||
|
||||
/* Have we not reat enough latency frames? */
|
||||
if (netplay_data->run_frame_count + NETPLAY_INPUT_LATENCY_FRAMES > netplay_data->input_frame_count)
|
||||
{
|
||||
netplay_data->stall = NETPLAY_STALL_INPUT_LATENCY;
|
||||
netplay_data->stall_time = 0;
|
||||
}
|
||||
|
||||
/* Are we too far ahead? */
|
||||
if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES
|
||||
<= netplay_data->input_frame_count)
|
||||
{
|
||||
netplay_data->stall = NETPLAY_STALL_RUNNING_FAST;
|
||||
netplay_data->stall_time = cpu_features_get_time_usec();
|
||||
|
||||
/* Figure out who to blame */
|
||||
if (netplay_data->is_server)
|
||||
{
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
{
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
if (!(netplay_data->connected_players & (1<<player))) continue;
|
||||
if (netplay_data->read_frame_count[player] > netplay_data->unread_frame_count) continue;
|
||||
for (i = 0; i < netplay_data->connections_size; i++)
|
||||
{
|
||||
if (!(netplay_data->connected_players & (1<<player))) continue;
|
||||
if (netplay_data->read_frame_count[player] > netplay_data->unread_frame_count) continue;
|
||||
for (i = 0; i < netplay_data->connections_size; i++)
|
||||
struct netplay_connection *connection = &netplay_data->connections[i];
|
||||
if (connection->active &&
|
||||
connection->mode == NETPLAY_CONNECTION_PLAYING &&
|
||||
connection->player == player)
|
||||
{
|
||||
struct netplay_connection *connection = &netplay_data->connections[i];
|
||||
if (connection->active &&
|
||||
connection->mode == NETPLAY_CONNECTION_PLAYING &&
|
||||
connection->player == player)
|
||||
{
|
||||
connection->stall = NETPLAY_STALL_RUNNING_FAST;
|
||||
connection->stall_time = netplay_data->stall_time;
|
||||
break;
|
||||
}
|
||||
connection->stall = NETPLAY_STALL_RUNNING_FAST;
|
||||
connection->stall_time = netplay_data->stall_time;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,7 +388,7 @@ static int16_t netplay_input_state(netplay_t *netplay,
|
||||
unsigned idx, unsigned id)
|
||||
{
|
||||
size_t ptr = netplay->is_replay ?
|
||||
netplay->replay_ptr : netplay->self_ptr;
|
||||
netplay->replay_ptr : netplay->run_ptr;
|
||||
|
||||
const uint32_t *curr_input_state = NULL;
|
||||
|
||||
@ -492,7 +509,7 @@ static void netplay_flip_users(netplay_t *netplay)
|
||||
{
|
||||
/* Must be in the future because we may have
|
||||
* already sent this frame's data */
|
||||
uint32_t flip_frame = netplay->self_frame_count + 1;
|
||||
uint32_t flip_frame = netplay->input_frame_count + 1;
|
||||
uint32_t flip_frame_net = htonl(flip_frame);
|
||||
size_t i;
|
||||
|
||||
@ -688,7 +705,7 @@ void netplay_send_savestate(netplay_t *netplay,
|
||||
/* Send it to relevant peers */
|
||||
header[0] = htonl(NETPLAY_CMD_LOAD_SAVESTATE);
|
||||
header[1] = htonl(wn + 2*sizeof(uint32_t));
|
||||
header[2] = htonl(netplay->self_frame_count);
|
||||
header[2] = htonl(netplay->run_frame_count);
|
||||
header[3] = htonl(serial_info->size);
|
||||
|
||||
for (i = 0; i < netplay->connections_size; i++)
|
||||
@ -721,16 +738,21 @@ void netplay_load_savestate(netplay_t *netplay,
|
||||
{
|
||||
retro_ctx_serialize_info_t tmp_serial_info;
|
||||
|
||||
/* Wherever we're inputting, that's where we consider our state to be loaded
|
||||
* (FIXME: Need to be more careful about saving it?) */
|
||||
netplay->run_ptr = netplay->input_ptr;
|
||||
netplay->run_frame_count = netplay->input_frame_count;
|
||||
|
||||
/* Record it in our own buffer */
|
||||
if (save || !serial_info)
|
||||
{
|
||||
if (netplay_delta_frame_ready(netplay,
|
||||
&netplay->buffer[netplay->self_ptr], netplay->self_frame_count))
|
||||
&netplay->buffer[netplay->run_ptr], netplay->run_frame_count))
|
||||
{
|
||||
if (!serial_info)
|
||||
{
|
||||
tmp_serial_info.size = netplay->state_size;
|
||||
tmp_serial_info.data = netplay->buffer[netplay->self_ptr].state;
|
||||
tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state;
|
||||
if (!core_serialize(&tmp_serial_info))
|
||||
return;
|
||||
tmp_serial_info.data_const = tmp_serial_info.data;
|
||||
@ -740,7 +762,7 @@ void netplay_load_savestate(netplay_t *netplay,
|
||||
{
|
||||
if (serial_info->size <= netplay->state_size)
|
||||
{
|
||||
memcpy(netplay->buffer[netplay->self_ptr].state,
|
||||
memcpy(netplay->buffer[netplay->run_ptr].state,
|
||||
serial_info->data_const, serial_info->size);
|
||||
}
|
||||
}
|
||||
@ -755,29 +777,29 @@ void netplay_load_savestate(netplay_t *netplay,
|
||||
/* We need to ignore any intervening data from the other side,
|
||||
* and never rewind past this */
|
||||
netplay_update_unread_ptr(netplay);
|
||||
if (netplay->unread_frame_count < netplay->self_frame_count)
|
||||
if (netplay->unread_frame_count < netplay->run_frame_count)
|
||||
{
|
||||
uint32_t player;
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
{
|
||||
if (!(netplay->connected_players & (1<<player))) continue;
|
||||
if (netplay->read_frame_count[player] < netplay->self_frame_count)
|
||||
if (netplay->read_frame_count[player] < netplay->run_frame_count)
|
||||
{
|
||||
netplay->read_ptr[player] = netplay->self_ptr;
|
||||
netplay->read_frame_count[player] = netplay->self_frame_count;
|
||||
netplay->read_ptr[player] = netplay->run_ptr;
|
||||
netplay->read_frame_count[player] = netplay->run_frame_count;
|
||||
}
|
||||
}
|
||||
if (netplay->server_frame_count < netplay->self_frame_count)
|
||||
if (netplay->server_frame_count < netplay->run_frame_count)
|
||||
{
|
||||
netplay->server_ptr = netplay->self_ptr;
|
||||
netplay->server_frame_count = netplay->self_frame_count;
|
||||
netplay->server_ptr = netplay->run_ptr;
|
||||
netplay->server_frame_count = netplay->run_frame_count;
|
||||
}
|
||||
netplay_update_unread_ptr(netplay);
|
||||
}
|
||||
if (netplay->other_frame_count < netplay->self_frame_count)
|
||||
if (netplay->other_frame_count < netplay->run_frame_count)
|
||||
{
|
||||
netplay->other_ptr = netplay->self_ptr;
|
||||
netplay->other_frame_count = netplay->self_frame_count;
|
||||
netplay->other_ptr = netplay->run_ptr;
|
||||
netplay->other_frame_count = netplay->run_frame_count;
|
||||
}
|
||||
|
||||
/* If we can't send it to the peer, loading a state was a bad idea */
|
||||
@ -807,7 +829,7 @@ static void netplay_toggle_play_spectate(netplay_t *netplay)
|
||||
uint32_t payload[2];
|
||||
char msg[512];
|
||||
const char *dmsg = NULL;
|
||||
payload[0] = htonl(netplay->self_frame_count);
|
||||
payload[0] = htonl(netplay->input_frame_count);
|
||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
||||
{
|
||||
/* Mark us as no longer playing */
|
||||
|
@ -518,7 +518,7 @@ bool netplay_handshake_sync(netplay_t *netplay, struct netplay_connection *conne
|
||||
cmd[0] = htonl(NETPLAY_CMD_SYNC);
|
||||
cmd[1] = htonl(3*sizeof(uint32_t) + MAX_USERS*sizeof(uint32_t) +
|
||||
NETPLAY_NICK_LEN + mem_info.size);
|
||||
cmd[2] = htonl(netplay->self_frame_count);
|
||||
cmd[2] = htonl(netplay->input_frame_count);
|
||||
connected_players = netplay->connected_players;
|
||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
||||
connected_players |= 1<<netplay->self_player;
|
||||
@ -904,22 +904,23 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
netplay->flip_frame = flip_frame;
|
||||
|
||||
/* Set our frame counters as requested */
|
||||
netplay->self_frame_count = netplay->other_frame_count =
|
||||
netplay->unread_frame_count = netplay->server_frame_count =
|
||||
new_frame_count;
|
||||
netplay->input_frame_count = netplay->run_frame_count =
|
||||
netplay->other_frame_count = netplay->unread_frame_count =
|
||||
netplay->server_frame_count = new_frame_count;
|
||||
for (i = 0; i < netplay->buffer_size; i++)
|
||||
{
|
||||
struct delta_frame *ptr = &netplay->buffer[i];
|
||||
ptr->used = false;
|
||||
|
||||
if (i == netplay->self_ptr)
|
||||
if (i == netplay->input_ptr)
|
||||
{
|
||||
/* Clear out any current data but still use this frame */
|
||||
if (!netplay_delta_frame_ready(netplay, ptr, 0))
|
||||
return false;
|
||||
ptr->frame = new_frame_count;
|
||||
ptr->have_local = true;
|
||||
netplay->other_ptr = netplay->unread_ptr = netplay->server_ptr = i;
|
||||
netplay->run_ptr = netplay->other_ptr = netplay->unread_ptr =
|
||||
netplay->server_ptr = i;
|
||||
|
||||
}
|
||||
}
|
||||
@ -927,8 +928,8 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
{
|
||||
if (connected_players & (1<<i))
|
||||
{
|
||||
netplay->read_ptr[i] = netplay->self_ptr;
|
||||
netplay->read_frame_count[i] = netplay->self_frame_count;
|
||||
netplay->read_ptr[i] = netplay->input_ptr;
|
||||
netplay->read_frame_count[i] = netplay->input_frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,7 +321,7 @@ bool netplay_try_init_serialization(netplay_t *netplay)
|
||||
|
||||
/* Check if we can actually save */
|
||||
serial_info.data_const = NULL;
|
||||
serial_info.data = netplay->buffer[netplay->self_ptr].state;
|
||||
serial_info.data = netplay->buffer[netplay->run_ptr].state;
|
||||
serial_info.size = netplay->state_size;
|
||||
|
||||
if (!core_serialize(&serial_info))
|
||||
|
@ -38,7 +38,7 @@ static void print_state(netplay_t *netplay)
|
||||
#define APPEND(out) cur += snprintf out
|
||||
#define M msg + cur, sizeof(msg) - cur
|
||||
|
||||
APPEND((M, "NETPLAY: S:%u U:%u O:%u", netplay->self_frame_count, netplay->unread_frame_count, netplay->other_frame_count));
|
||||
APPEND((M, "NETPLAY: S:%u U:%u O:%u", netplay->input_frame_count, netplay->unread_frame_count, netplay->other_frame_count));
|
||||
if (!netplay->is_server)
|
||||
APPEND((M, " H:%u", netplay->server_frame_count));
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
@ -204,7 +204,7 @@ static bool send_input_frame(netplay_t *netplay,
|
||||
bool netplay_send_cur_input(netplay_t *netplay,
|
||||
struct netplay_connection *connection)
|
||||
{
|
||||
struct delta_frame *dframe = &netplay->buffer[netplay->self_ptr];
|
||||
struct delta_frame *dframe = &netplay->buffer[netplay->input_ptr];
|
||||
uint32_t player;
|
||||
|
||||
if (netplay->is_server)
|
||||
@ -220,7 +220,7 @@ bool netplay_send_cur_input(netplay_t *netplay,
|
||||
if (dframe->have_real[player])
|
||||
{
|
||||
if (!send_input_frame(netplay, connection, NULL,
|
||||
netplay->self_frame_count, player,
|
||||
netplay->input_frame_count, player,
|
||||
dframe->real_input_state[player]))
|
||||
return false;
|
||||
}
|
||||
@ -230,7 +230,7 @@ bool netplay_send_cur_input(netplay_t *netplay,
|
||||
/* If we're not playing, send a NOINPUT */
|
||||
if (netplay->self_mode != NETPLAY_CONNECTION_PLAYING)
|
||||
{
|
||||
uint32_t payload = htonl(netplay->self_frame_count);
|
||||
uint32_t payload = htonl(netplay->input_frame_count);
|
||||
if (!netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_NOINPUT,
|
||||
&payload, sizeof(payload)))
|
||||
return false;
|
||||
@ -242,7 +242,7 @@ bool netplay_send_cur_input(netplay_t *netplay,
|
||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
||||
{
|
||||
if (!send_input_frame(netplay, connection, NULL,
|
||||
netplay->self_frame_count,
|
||||
netplay->input_frame_count,
|
||||
(netplay->is_server ? NETPLAY_CMD_INPUT_BIT_SERVER : 0) | netplay->self_player,
|
||||
dframe->self_state))
|
||||
return false;
|
||||
@ -505,7 +505,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
if (netplay->is_server)
|
||||
{
|
||||
/* Forward it on if it's past data*/
|
||||
if (dframe->frame <= netplay->self_frame_count)
|
||||
if (dframe->frame <= netplay->input_frame_count)
|
||||
send_input_frame(netplay, NULL, connection, buffer[0],
|
||||
player, dframe->real_input_state[player]);
|
||||
}
|
||||
@ -585,7 +585,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
/* Force a rewind to assure the flip happens: This just prevents us
|
||||
* from skipping other past the flip because our prediction was
|
||||
* correct */
|
||||
if (flip_frame < netplay->self_frame_count)
|
||||
if (flip_frame < netplay->input_frame_count)
|
||||
netplay->force_rewind = true;
|
||||
|
||||
RARCH_LOG("%s.\n", msg_hash_to_str(MSG_NETPLAY_USERS_HAS_FLIPPED));
|
||||
@ -638,7 +638,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
{
|
||||
uint32_t payload[2];
|
||||
uint32_t player = 0;
|
||||
payload[0] = htonl(netplay->self_frame_count + 1);
|
||||
payload[0] = htonl(netplay->input_frame_count + 1);
|
||||
|
||||
if (!netplay->is_server)
|
||||
{
|
||||
@ -695,8 +695,8 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||
|
||||
/* And expect their data */
|
||||
netplay->read_ptr[player] = NEXT_PTR(netplay->self_ptr);
|
||||
netplay->read_frame_count[player] = netplay->self_frame_count + 1;
|
||||
netplay->read_ptr[player] = NEXT_PTR(netplay->input_ptr);
|
||||
netplay->read_frame_count[player] = netplay->input_frame_count + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -734,7 +734,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
frame = ntohl(payload[0]);
|
||||
|
||||
/* We're changing past input, so must replay it */
|
||||
if (frame < netplay->self_frame_count)
|
||||
if (frame < netplay->input_frame_count)
|
||||
netplay->force_rewind = true;
|
||||
|
||||
mode = ntohl(payload[1]);
|
||||
@ -767,16 +767,16 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
netplay->self_player = player;
|
||||
|
||||
/* Fix up current frame info */
|
||||
if (frame <= netplay->self_frame_count)
|
||||
if (frame <= netplay->input_frame_count)
|
||||
{
|
||||
/* It wanted past frames, better send 'em! */
|
||||
START(netplay->server_ptr);
|
||||
while (dframe->used && dframe->frame <= netplay->self_frame_count)
|
||||
while (dframe->used && dframe->frame <= netplay->input_frame_count)
|
||||
{
|
||||
memcpy(dframe->real_input_state[player], dframe->self_state, sizeof(dframe->self_state));
|
||||
dframe->have_real[player] = true;
|
||||
send_input_frame(netplay, connection, NULL, dframe->frame, player, dframe->self_state);
|
||||
if (dframe->frame == netplay->self_frame_count) break;
|
||||
if (dframe->frame == netplay->input_frame_count) break;
|
||||
NEXT();
|
||||
}
|
||||
|
||||
@ -786,8 +786,8 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
uint32_t frame_count;
|
||||
|
||||
/* It wants future frames, make sure we don't capture or send intermediate ones */
|
||||
START(netplay->self_ptr);
|
||||
frame_count = netplay->self_frame_count;
|
||||
START(netplay->input_ptr);
|
||||
frame_count = netplay->input_frame_count;
|
||||
while (true)
|
||||
{
|
||||
if (!dframe->used)
|
||||
@ -954,7 +954,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
case NETPLAY_CMD_CRC:
|
||||
{
|
||||
uint32_t buffer[2];
|
||||
size_t tmp_ptr = netplay->self_ptr;
|
||||
size_t tmp_ptr = netplay->input_ptr;
|
||||
bool found = false;
|
||||
|
||||
if (cmd_size != sizeof(buffer))
|
||||
@ -985,7 +985,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
}
|
||||
|
||||
tmp_ptr = PREV_PTR(tmp_ptr);
|
||||
} while (tmp_ptr != netplay->self_ptr);
|
||||
} while (tmp_ptr != netplay->input_ptr);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
@ -1035,8 +1035,8 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
if (!netplay->is_replay)
|
||||
{
|
||||
netplay->is_replay = true;
|
||||
netplay->replay_ptr = netplay->self_ptr;
|
||||
netplay->replay_frame_count = netplay->self_frame_count;
|
||||
netplay->replay_ptr = netplay->run_ptr;
|
||||
netplay->replay_frame_count = netplay->run_frame_count;
|
||||
netplay_wait_and_init_serialization(netplay);
|
||||
netplay->is_replay = false;
|
||||
}
|
||||
@ -1134,15 +1134,20 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
true, &rd, &wn, NULL);
|
||||
|
||||
/* Skip ahead if it's past where we are */
|
||||
if (frame > netplay->self_frame_count)
|
||||
if (frame > netplay->run_frame_count)
|
||||
{
|
||||
/* This is squirrely: We need to assure that when we advance the
|
||||
* frame in post_frame, THEN we're referring to the frame to
|
||||
* load into. If we refer directly to read_ptr, then we'll end
|
||||
* up never reading the input for read_frame_count itself, which
|
||||
* will make the other side unhappy. */
|
||||
netplay->self_ptr = PREV_PTR(netplay->read_ptr[connection->player]);
|
||||
netplay->self_frame_count = frame - 1;
|
||||
netplay->run_ptr = PREV_PTR(netplay->read_ptr[connection->player]);
|
||||
netplay->run_frame_count = frame - 1;
|
||||
if (frame > netplay->input_frame_count)
|
||||
{
|
||||
netplay->input_ptr = netplay->run_ptr;
|
||||
netplay->input_frame_count = netplay->run_frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't expect earlier data from other clients */
|
||||
@ -1308,7 +1313,7 @@ int netplay_poll_net_input(netplay_t *netplay, bool block)
|
||||
netplay_update_unread_ptr(netplay);
|
||||
|
||||
/* If we were blocked for input, pass if we have this frame's input */
|
||||
if (netplay->unread_frame_count > netplay->self_frame_count)
|
||||
if (netplay->unread_frame_count > netplay->run_frame_count)
|
||||
break;
|
||||
|
||||
/* If we're supposed to block but we didn't have enough input, wait for it */
|
||||
@ -1330,7 +1335,7 @@ int netplay_poll_net_input(netplay_t *netplay, bool block)
|
||||
return -1;
|
||||
|
||||
RARCH_LOG("Network is stalling at frame %u, count %u of %d ...\n",
|
||||
netplay->self_frame_count, netplay->timeout_cnt, MAX_RETRIES);
|
||||
netplay->run_frame_count, netplay->timeout_cnt, MAX_RETRIES);
|
||||
|
||||
if (netplay->timeout_cnt >= MAX_RETRIES && !netplay->remote_paused)
|
||||
return -1;
|
||||
@ -1348,7 +1353,7 @@ int netplay_poll_net_input(netplay_t *netplay, bool block)
|
||||
*/
|
||||
bool netplay_flip_port(netplay_t *netplay)
|
||||
{
|
||||
size_t frame = netplay->self_frame_count;
|
||||
size_t frame = netplay->input_frame_count;
|
||||
|
||||
if (netplay->flip_frame == 0)
|
||||
return false;
|
||||
|
@ -50,6 +50,9 @@
|
||||
#define NETPLAY_MAX_REQ_STALL_TIME 60
|
||||
#define NETPLAY_MAX_REQ_STALL_FREQUENCY 120
|
||||
|
||||
/* TEMPORARY */
|
||||
#define NETPLAY_INPUT_LATENCY_FRAMES 5
|
||||
|
||||
#define PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1)
|
||||
#define NEXT_PTR(x) ((x + 1) % netplay->buffer_size)
|
||||
|
||||
@ -210,6 +213,7 @@ enum rarch_netplay_stall_reason
|
||||
{
|
||||
NETPLAY_STALL_NONE = 0,
|
||||
NETPLAY_STALL_RUNNING_FAST,
|
||||
NETPLAY_STALL_INPUT_LATENCY,
|
||||
NETPLAY_STALL_SERVER_REQUESTED,
|
||||
NETPLAY_STALL_NO_CONNECTION
|
||||
};
|
||||
@ -357,9 +361,13 @@ struct netplay
|
||||
/* The size of our packet buffers */
|
||||
size_t packet_buffer_size;
|
||||
|
||||
/* The current frame seen by the frontend */
|
||||
size_t self_ptr;
|
||||
uint32_t self_frame_count;
|
||||
/* The frame we're currently inputting */
|
||||
size_t input_ptr;
|
||||
uint32_t input_frame_count;
|
||||
|
||||
/* The frame we're currently running */
|
||||
size_t run_ptr;
|
||||
uint32_t run_frame_count;
|
||||
|
||||
/* The first frame at which some data might be unreliable */
|
||||
size_t other_ptr;
|
||||
|
@ -42,8 +42,8 @@ void netplay_update_unread_ptr(netplay_t *netplay)
|
||||
if (netplay->is_server && !netplay->connected_players)
|
||||
{
|
||||
/* Nothing at all to read! */
|
||||
netplay->unread_ptr = netplay->self_ptr;
|
||||
netplay->unread_frame_count = netplay->self_frame_count;
|
||||
netplay->unread_ptr = netplay->input_ptr;
|
||||
netplay->unread_frame_count = netplay->input_frame_count;
|
||||
|
||||
}
|
||||
else
|
||||
@ -186,14 +186,14 @@ bool netplay_sync_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))
|
||||
if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->run_ptr], netplay->run_frame_count))
|
||||
{
|
||||
serial_info.data_const = NULL;
|
||||
serial_info.data = netplay->buffer[netplay->self_ptr].state;
|
||||
serial_info.data = netplay->buffer[netplay->run_ptr].state;
|
||||
serial_info.size = netplay->state_size;
|
||||
|
||||
memset(serial_info.data, 0, serial_info.size);
|
||||
if ((netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) || netplay->self_frame_count == 0)
|
||||
if ((netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) || netplay->run_frame_count == 0)
|
||||
{
|
||||
/* Don't serialize until it's safe */
|
||||
}
|
||||
@ -201,8 +201,19 @@ bool netplay_sync_pre_frame(netplay_t *netplay)
|
||||
{
|
||||
if (netplay->force_send_savestate && !netplay->stall && !netplay->remote_paused)
|
||||
{
|
||||
/* Bring our running frame and input frames into parity so we don't
|
||||
* send old info */
|
||||
if (netplay->run_ptr != netplay->input_ptr)
|
||||
{
|
||||
memcpy(netplay->buffer[netplay->input_ptr].state,
|
||||
netplay->buffer[netplay->run_ptr].state,
|
||||
netplay->state_size);
|
||||
netplay->run_ptr = netplay->input_ptr;
|
||||
netplay->run_frame_count = netplay->input_frame_count;
|
||||
}
|
||||
|
||||
/* Send this along to the other side */
|
||||
serial_info.data_const = netplay->buffer[netplay->self_ptr].state;
|
||||
serial_info.data_const = netplay->buffer[netplay->run_ptr].state;
|
||||
netplay_load_savestate(netplay, &serial_info, false);
|
||||
netplay->force_send_savestate = false;
|
||||
}
|
||||
@ -216,7 +227,7 @@ bool netplay_sync_pre_frame(netplay_t *netplay)
|
||||
}
|
||||
|
||||
/* If we can't transmit savestates, we must stall until the client is ready */
|
||||
if (netplay->self_frame_count > 0 &&
|
||||
if (netplay->run_frame_count > 0 &&
|
||||
(netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION)) &&
|
||||
(netplay->connections_size == 0 || !netplay->connections[0].active ||
|
||||
netplay->connections[0].mode < NETPLAY_CONNECTION_CONNECTED))
|
||||
@ -357,16 +368,24 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
/* Unless we're stalling, we've just finished running a frame */
|
||||
if (!stalled)
|
||||
{
|
||||
netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
|
||||
netplay->self_frame_count++;
|
||||
netplay->run_ptr = NEXT_PTR(netplay->run_ptr);
|
||||
netplay->run_frame_count++;
|
||||
}
|
||||
|
||||
/* We've finished an input frame even if we're stalling, unless we're too
|
||||
* far ahead of ourselves */
|
||||
if (netplay->input_frame_count < netplay->run_frame_count + NETPLAY_INPUT_LATENCY_FRAMES)
|
||||
{
|
||||
netplay->input_ptr = NEXT_PTR(netplay->input_ptr);
|
||||
netplay->input_frame_count++;
|
||||
}
|
||||
|
||||
/* Only relevant if we're connected */
|
||||
if ((netplay->is_server && !netplay->connected_players) ||
|
||||
(netplay->self_mode < NETPLAY_CONNECTION_CONNECTED))
|
||||
{
|
||||
netplay->other_frame_count = netplay->self_frame_count;
|
||||
netplay->other_ptr = netplay->self_ptr;
|
||||
netplay->other_frame_count = netplay->input_frame_count;
|
||||
netplay->other_ptr = netplay->input_ptr;
|
||||
/* FIXME: Duplication */
|
||||
if (netplay->catch_up)
|
||||
{
|
||||
@ -383,7 +402,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
/* Skip ahead if we predicted correctly.
|
||||
* Skip until our simulation failed. */
|
||||
while (netplay->other_frame_count < netplay->unread_frame_count &&
|
||||
netplay->other_frame_count < netplay->self_frame_count)
|
||||
netplay->other_frame_count < netplay->run_frame_count)
|
||||
{
|
||||
struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr];
|
||||
size_t i;
|
||||
@ -406,7 +425,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
/* Now replay the real input if we've gotten ahead of it */
|
||||
if (netplay->force_rewind ||
|
||||
(netplay->other_frame_count < netplay->unread_frame_count &&
|
||||
netplay->other_frame_count < netplay->self_frame_count))
|
||||
netplay->other_frame_count < netplay->run_frame_count))
|
||||
{
|
||||
retro_ctx_serialize_info_t serial_info;
|
||||
|
||||
@ -428,7 +447,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
RARCH_ERR("Netplay savestate loading failed: Prepare for desync!\n");
|
||||
}
|
||||
|
||||
while (netplay->replay_frame_count < netplay->self_frame_count)
|
||||
while (netplay->replay_frame_count < netplay->run_frame_count)
|
||||
{
|
||||
retro_time_t start, tm;
|
||||
|
||||
@ -483,15 +502,15 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
/* 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)
|
||||
if (netplay->unread_frame_count < netplay->run_frame_count)
|
||||
{
|
||||
netplay->other_ptr = netplay->unread_ptr;
|
||||
netplay->other_frame_count = netplay->unread_frame_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
netplay->other_ptr = netplay->self_ptr;
|
||||
netplay->other_frame_count = netplay->self_frame_count;
|
||||
netplay->other_ptr = netplay->run_ptr;
|
||||
netplay->other_frame_count = netplay->run_frame_count;
|
||||
}
|
||||
netplay->is_replay = false;
|
||||
netplay->force_rewind = false;
|
||||
@ -520,7 +539,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
if (netplay->catch_up)
|
||||
{
|
||||
/* Are we caught up? */
|
||||
if (netplay->self_frame_count >= lo_frame_count)
|
||||
if (netplay->input_frame_count >= lo_frame_count)
|
||||
{
|
||||
netplay->catch_up = false;
|
||||
input_driver_unset_nonblock_state();
|
||||
@ -530,7 +549,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
}
|
||||
else if (!stalled)
|
||||
{
|
||||
if (netplay->self_frame_count + 2 < lo_frame_count)
|
||||
if (netplay->input_frame_count + 2 < lo_frame_count)
|
||||
{
|
||||
/* Are we falling behind? */
|
||||
netplay->catch_up = true;
|
||||
@ -538,7 +557,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
driver_set_nonblock_state();
|
||||
|
||||
}
|
||||
else if (netplay->self_frame_count + 2 < hi_frame_count)
|
||||
else if (netplay->input_frame_count + 2 < hi_frame_count)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@ -554,16 +573,16 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
player = connection->player;
|
||||
|
||||
/* Are they ahead? */
|
||||
if (netplay->self_frame_count + 2 < netplay->read_frame_count[player])
|
||||
if (netplay->input_frame_count + 2 < netplay->read_frame_count[player])
|
||||
{
|
||||
/* Tell them to stall */
|
||||
if (connection->stall_frame + NETPLAY_MAX_REQ_STALL_FREQUENCY <
|
||||
netplay->self_frame_count)
|
||||
netplay->input_frame_count)
|
||||
{
|
||||
connection->stall_frame = netplay->self_frame_count;
|
||||
connection->stall_frame = netplay->input_frame_count;
|
||||
netplay_cmd_stall(netplay, connection,
|
||||
netplay->read_frame_count[player] -
|
||||
netplay->self_frame_count + 1);
|
||||
netplay->input_frame_count + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user