Bugfixes to bring Netplay Nouveau from "kinda working" to "stably

working":

(1) Fixups to the stall logic to make sure it always receives frames
while stalling :)

(2) Disused the used_real field. It was misconfigured and would
frequently claim to be using real data when real data hadn't been
used... this means more replays for now, but used_real will be readded.
(TODO)

(3) Stall duration is now related to sync frames, and thus configurable.

(4) Delta frames were having the good ol' initialization problem, as
frame==0 was indistinguishable from unused. Quickfixed by adding a
"used" field, but maybe there's a better way.

(5) If serialization fails, switch immediately to blocking mode
(stall_frames = 0). Blocking mode barely works, but if serialization
fails, no mode will work!

(6) I'm not sure which bug my replaying-from-previous-frame was trying
to fix, but the correct behavior is to replay from the last frame we had
vital information, not the frame prior. Notionally this should just be
an efficiency thing, but unsigned arithmetic at 0 made this a "just
ignore all input from now on" thing.
This commit is contained in:
Gregor Richards 2016-09-12 17:50:38 -04:00
parent 07e869ccae
commit c7d0bf90f6
4 changed files with 56 additions and 28 deletions

View File

@ -143,7 +143,7 @@ static bool send_chunk(netplay_t *netplay)
**/
static bool get_self_input_state(netplay_t *netplay)
{
uint32_t state[WORDS_PER_FRAME - 1] = {0};
uint32_t state[WORDS_PER_FRAME - 1] = {0, 0, 0};
struct delta_frame *ptr = &netplay->buffer[netplay->self_ptr];
if (!netplay_delta_frame_ready(netplay, ptr, netplay->self_frame_count))
@ -261,9 +261,9 @@ static bool netplay_get_cmd(netplay_t *netplay)
uint32_t flip_frame;
uint32_t cmd_size;
/* If we're not ready for input, wait until we are. Could fill the TCP buffer, stalling the other side. */
if (!netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->read_ptr], netplay->read_frame_count))
return false;
/* FIXME: This depends on delta_frame_ready */
netplay->timeout_cnt = 0;
if (!socket_receive_all_blocking(netplay->fd, &cmd, sizeof(cmd)))
return false;
@ -314,7 +314,6 @@ static bool netplay_get_cmd(netplay_t *netplay)
memcpy(netplay->buffer[netplay->read_ptr].real_input_state, buffer + 1, sizeof(buffer) - sizeof(uint32_t));
netplay->read_ptr = NEXT_PTR(netplay->read_ptr);
netplay->read_frame_count++;
netplay->timeout_cnt = 0;
return true;
}
@ -409,9 +408,13 @@ static int poll_input(netplay_t *netplay, bool block)
* but we aren't using the TCP connection for anything useful atm. */
if (FD_ISSET(netplay->fd, &fds))
{
had_input = true;
if (!netplay_get_cmd(netplay))
return -1;
/* If we're not ready for input, wait until we are. Could fill the TCP buffer, stalling the other side. */
if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->read_ptr], netplay->read_frame_count))
{
had_input = true;
if (!netplay_get_cmd(netplay))
return -1;
}
}
#if 0
@ -431,9 +434,9 @@ static int poll_input(netplay_t *netplay, bool block)
}
#endif
RARCH_LOG("Network is stalling, resending packet... Count %u of %d ...\n",
netplay->timeout_cnt, MAX_RETRIES);
} while (had_input);
RARCH_LOG("Network is stalling at frame %u, count %u of %d ...\n",
netplay->self_frame_count, netplay->timeout_cnt, MAX_RETRIES);
} while (had_input || (block && (netplay->read_frame_count <= netplay->self_frame_count)));
/*if (block)
return -1;*/
@ -521,9 +524,13 @@ static bool netplay_poll(netplay_t *netplay)
netplay->can_poll = false;
#if 0
if (!get_self_input_state(netplay))
return false;
#endif
get_self_input_state(netplay);
#if 0
/* We skip reading the first frame so the host has a chance to grab
* our host info so we don't block forever :') */
if (netplay->self_frame_count == 0)
@ -538,9 +545,11 @@ static bool netplay_poll(netplay_t *netplay)
netplay->read_frame_count++;
return true;
}
#endif
/* Read Netplay input */
res = poll_input(netplay, 0); /* FIXME: configure stalling intervals */
/* Read Netplay input, block if we're configured to stall for input every
* frame */
res = poll_input(netplay, netplay->stall_frames == 0);
if (res == -1)
{
netplay->has_connection = false;
@ -580,8 +589,8 @@ static bool netplay_poll(netplay_t *netplay)
if (netplay->read_frame_count < netplay->self_frame_count)
simulate_input(netplay);
else
netplay->buffer[PREV_PTR(netplay->self_ptr)].used_real = true;
/*else
netplay->buffer[PREV_PTR(netplay->self_ptr)].used_real = true;*/
/* Consider stalling */
switch (netplay->stall) {
@ -591,7 +600,7 @@ static bool netplay_poll(netplay_t *netplay)
break;
default: /* not stalling */
if (netplay->read_frame_count < netplay->self_frame_count - 10)
if (netplay->read_frame_count + netplay->stall_frames <= netplay->self_frame_count)
netplay->stall = RARCH_NETPLAY_STALL_RUNNING_FAST;
}
@ -774,6 +783,9 @@ static int init_tcp_connection(const struct addrinfo *res,
{
bool ret = true;
int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
int flag = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
if (fd < 0)
{
@ -937,11 +949,9 @@ netplay_t *netplay_new(const char *server, uint16_t port,
bool spectate,
const char *nick)
{
uint32_t buffer_frames;
netplay_t *netplay = NULL;
/*if (frames > UDP_FRAME_PACKETS)
frames = UDP_FRAME_PACKETS;*/
netplay = (netplay_t*)calloc(1, sizeof(*netplay));
if (!netplay)
return NULL;
@ -953,6 +963,7 @@ netplay_t *netplay_new(const char *server, uint16_t port,
netplay->spectate.enabled = spectate;
netplay->is_server = server == NULL;
strlcpy(netplay->nick, nick, sizeof(netplay->nick));
netplay->stall_frames = frames;
if(spectate)
netplay->net_cbs = netplay_get_cbs_spectate();

View File

@ -348,14 +348,18 @@ bool netplay_is_spectate(netplay_t* netplay)
bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, uint32_t frame)
{
void *remember_state;
if (delta->frame == frame) return true;
if (netplay->other_frame_count <= delta->frame)
if (delta->used)
{
/* We haven't even replayed this frame yet, so we can't overwrite it! */
return false;
if (delta->frame == frame) return true;
if (netplay->other_frame_count <= delta->frame)
{
/* We haven't even replayed this frame yet, so we can't overwrite it! */
return false;
}
}
remember_state = delta->state;
memset(delta, 0, sizeof(struct delta_frame));
delta->used = true;
delta->frame = frame;
delta->state = remember_state;
return true;

View File

@ -36,7 +36,12 @@ static void netplay_net_pre_frame(netplay_t *netplay)
serial_info.data = netplay->buffer[netplay->self_ptr].state;
serial_info.size = netplay->state_size;
core_serialize(&serial_info);
if (!core_serialize(&serial_info))
{
/* If the core can't serialize properly, we must stall for the
* remote input on EVERY frame, because we can't recover */
netplay->stall_frames = 0;
}
}
netplay->can_poll = true;
@ -55,9 +60,11 @@ static void netplay_net_post_frame(netplay_t *netplay)
{
netplay->self_frame_count++;
#if 0
/* Nothing to do... */
if (netplay->other_frame_count == netplay->read_frame_count)
return;
#endif
/* Skip ahead if we predicted correctly.
* Skip until our simulation failed. */
@ -80,8 +87,8 @@ static void netplay_net_post_frame(netplay_t *netplay)
/* Replay frames. */
netplay->is_replay = true;
netplay->replay_ptr = PREV_PTR(netplay->other_ptr);
netplay->replay_frame_count = netplay->other_frame_count - 1;
netplay->replay_ptr = netplay->other_ptr;
netplay->replay_frame_count = netplay->other_frame_count;
if (netplay->replay_frame_count < netplay->self_frame_count)
{
@ -114,7 +121,7 @@ static void netplay_net_post_frame(netplay_t *netplay)
/* For the remainder of the frames up to the read count, we can use the real data */
while (netplay->replay_frame_count < netplay->read_frame_count)
{
netplay->buffer[netplay->replay_ptr].used_real = true;
/*netplay->buffer[netplay->replay_ptr].used_real = true;*/
netplay->replay_ptr = NEXT_PTR(netplay->replay_ptr);
netplay->replay_frame_count++;
}
@ -222,7 +229,11 @@ static bool netplay_net_info_cb(netplay_t* netplay, unsigned frames)
return false;
}
netplay->buffer_size = frames + 1;
/* * 2 + 1 because:
* Self sits in the middle,
* Other is allowed to drift as much as 'frames' frames behind
* Read is allowed to drift as much as 'frames' frames ahead */
netplay->buffer_size = frames * 2 + 1;
if (!netplay_net_init_buffers(netplay))
return false;

View File

@ -41,6 +41,7 @@
struct delta_frame
{
bool used; /* a bit derpy, but this is how we know if the delta's been used at all */
uint32_t frame;
void *state;
@ -143,6 +144,7 @@ struct netplay
uint32_t pause_frame;
/* And stalling */
uint32_t stall_frames;
int stall;
struct netplay_callbacks* net_cbs;