summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2020-05-08 00:22:54 -0700
committerMichael Pavone <pavone@retrodev.com>2020-05-08 00:22:54 -0700
commit6a8bc413fbfb25ed90aa83c6854835a759d41c35 (patch)
tree4ed0079facdaebe2f6155705cb3ce40278c55b1a
parent50eed62a8b67f10b6f1001368fbc3fae3b3d39fd (diff)
Make netplay remote sync to network rather than audio or video so it doesn't drift out of sync with the host
-rw-r--r--event_log.c8
-rw-r--r--gen_player.c21
-rw-r--r--gen_player.h2
-rw-r--r--render.h4
-rwxr-xr-xrender_sdl.c102
5 files changed, 95 insertions, 42 deletions
diff --git a/event_log.c b/event_log.c
index 99bf536..dd6eaa7 100644
--- a/event_log.c
+++ b/event_log.c
@@ -551,7 +551,6 @@ void init_event_reader_tcp(event_reader *reader, char *address, char *port)
if (Z_OK != res && Z_BUF_ERROR != res) {
fatal_error("inflate returned %d in init_event_reader_tcp\n", res);
}
- socket_blocking(reader->socket, 0);
int flag = 1;
setsockopt(reader->socket, IPPROTO_TCP, TCP_NODELAY, (const char *)&flag, sizeof(flag));
}
@@ -608,19 +607,14 @@ static void inflate_flush(event_reader *reader)
void reader_ensure_data(event_reader *reader, size_t bytes)
{
if (reader->buffer.size - reader->buffer.cur_pos < bytes) {
- if (reader->socket) {
- read_from_socket(reader);
- }
if (reader->input_stream.avail_in) {
inflate_flush(reader);
}
- if (reader->socket && reader->buffer.size - reader->buffer.cur_pos < bytes) {
- socket_blocking(reader->socket, 1);
+ if (reader->socket) {
while (reader->buffer.size - reader->buffer.cur_pos < bytes) {
read_from_socket(reader);
inflate_flush(reader);
}
- socket_blocking(reader->socket, 0);
}
}
}
diff --git a/gen_player.c b/gen_player.c
index 74eab4b..24c4d31 100644
--- a/gen_player.c
+++ b/gen_player.c
@@ -24,9 +24,8 @@ static void sync_sound(gen_player *gen, uint32_t target)
//printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2);
}
-void start_context(system_header *sys, char *statefile)
+static void run(gen_player *player)
{
- gen_player *player = (gen_player *)sys;
while(player->reader.socket || player->reader.buffer.cur_pos < player->reader.buffer.size)
{
uint32_t cycle;
@@ -92,7 +91,22 @@ void start_context(system_header *sys, char *statefile)
reader_ensure_data(&player->reader, 1);
}
}
-
+}
+
+static int thread_main(void *player)
+{
+ run(player);
+ return 0;
+}
+
+void start_context(system_header *sys, char *statefile)
+{
+ gen_player *player = (gen_player *)sys;
+ if (player->reader.socket) {
+ render_create_thread(&player->thread, "player", thread_main, player);
+ } else {
+ run(player);
+ }
}
static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button)
@@ -151,6 +165,7 @@ gen_player *alloc_config_gen_player_reader(event_reader *reader)
gen_player *player = calloc(1, sizeof(gen_player));
player->reader = *reader;
inflateCopy(&player->reader.input_stream, &reader->input_stream);
+ render_set_external_sync(1);
config_common(player);
return player;
}
diff --git a/gen_player.h b/gen_player.h
index 0b451da..643ee93 100644
--- a/gen_player.h
+++ b/gen_player.h
@@ -1,6 +1,7 @@
#ifndef GEN_PLAYER_H_
#define GEN_PLAYER_H_
+#include "render.h"
#include "system.h"
#include "vdp.h"
#include "psg.h"
@@ -13,6 +14,7 @@ typedef struct {
vdp_context *vdp;
ym2612_context *ym;
psg_context *psg;
+ render_thread thread;
event_reader reader;
} gen_player;
diff --git a/render.h b/render.h
index 2bd7724..ece0613 100644
--- a/render.h
+++ b/render.h
@@ -65,6 +65,7 @@
#define RENDER_DPAD_LEFT SDL_HAT_LEFT
#define RENDER_DPAD_RIGHT SDL_HAT_RIGHT
#define render_relative_mouse SDL_SetRelativeMouseMode
+typedef SDL_Thread* render_thread;
#endif
#endif
@@ -93,6 +94,7 @@ typedef enum {
typedef void (*drop_handler)(const char *filename);
typedef void (*window_close_handler)(uint8_t which);
typedef void (*ui_render_fun)(void);
+typedef int (*render_thread_fun)(void*);
uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b);
void render_save_screenshot(char *path);
@@ -135,6 +137,8 @@ void render_set_ui_render_fun(ui_render_fun);
void render_set_ui_fb_resize_handler(ui_render_fun resize);
void render_video_loop(void);
uint8_t render_should_release_on_exit(void);
+void render_set_external_sync(uint8_t ext_sync_on);
+uint8_t render_create_thread(render_thread *thread, const char *name, render_thread_fun fun, void *data);
#endif //RENDER_H_
diff --git a/render_sdl.c b/render_sdl.c
index 1077109..79e9b37 100755
--- a/render_sdl.c
+++ b/render_sdl.c
@@ -50,7 +50,14 @@ static SDL_mutex *audio_mutex, *frame_mutex, *free_buffer_mutex;
static SDL_cond *audio_ready, *frame_ready;
static uint8_t quitting = 0;
-static uint8_t sync_to_audio, run_on_audio_thread;
+enum {
+ SYNC_AUDIO,
+ SYNC_AUDIO_THREAD,
+ SYNC_VIDEO,
+ SYNC_EXTERNAL
+};
+
+static uint8_t sync_src;
static uint32_t min_buffered;
uint32_t **frame_buffers;
@@ -64,12 +71,12 @@ uint32_t render_min_buffered(void)
uint8_t render_is_audio_sync(void)
{
- return sync_to_audio || run_on_audio_thread;
+ return sync_src < SYNC_VIDEO;
}
uint8_t render_should_release_on_exit(void)
{
- return !run_on_audio_thread;
+ return sync_src != SYNC_AUDIO_THREAD;
}
void render_buffer_consumed(audio_source *src)
@@ -120,7 +127,7 @@ static void audio_callback_run_on_audio(void *user_data, uint8_t *byte_stream, i
void render_lock_audio()
{
- if (sync_to_audio) {
+ if (sync_src == SYNC_AUDIO) {
SDL_LockMutex(audio_mutex);
} else {
SDL_LockAudio();
@@ -129,7 +136,7 @@ void render_lock_audio()
void render_unlock_audio()
{
- if (sync_to_audio) {
+ if (sync_src == SYNC_AUDIO) {
SDL_UnlockMutex(audio_mutex);
} else {
SDL_UnlockAudio();
@@ -164,7 +171,7 @@ void render_free_audio_opaque(void *opaque)
void render_audio_created(audio_source *source)
{
- if (sync_to_audio && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
+ if (sync_src == SYNC_AUDIO && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
SDL_PauseAudio(0);
}
if (current_system) {
@@ -174,7 +181,7 @@ void render_audio_created(audio_source *source)
void render_source_paused(audio_source *src, uint8_t remaining_sources)
{
- if (sync_to_audio) {
+ if (sync_src == SYNC_AUDIO) {
SDL_CondSignal(audio_ready);
}
if (!remaining_sources) {
@@ -184,14 +191,14 @@ void render_source_paused(audio_source *src, uint8_t remaining_sources)
void render_source_resumed(audio_source *src)
{
- if (sync_to_audio) {
+ if (sync_src == SYNC_AUDIO) {
SDL_PauseAudio(0);
}
}
void render_do_audio_ready(audio_source *src)
{
- if (run_on_audio_thread) {
+ if (sync_src == SYNC_AUDIO_THREAD) {
int16_t *tmp = src->front;
src->front = src->back;
src->back = tmp;
@@ -201,7 +208,7 @@ void render_do_audio_ready(audio_source *src)
//we've emulated far enough to fill the current buffer
current_system->request_exit(current_system);
}
- } else if (sync_to_audio) {
+ } else if (sync_src == SYNC_AUDIO) {
SDL_LockMutex(audio_mutex);
while (src->front_populated) {
SDL_CondWait(src->opaque, audio_mutex);
@@ -253,6 +260,15 @@ uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
#endif
}
+static uint8_t external_sync;
+void render_set_external_sync(uint8_t ext_sync_on)
+{
+ if (ext_sync_on != external_sync) {
+ external_sync = ext_sync_on;
+ render_config_updated();
+ }
+}
+
#ifndef DISABLE_OPENGL
static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, at_pos;
@@ -913,7 +929,16 @@ static void init_audio()
}
debug_message("config says: %d\n", samples);
desired.samples = samples*2;
- desired.callback = sync_to_audio ? audio_callback : run_on_audio_thread ? audio_callback_run_on_audio : audio_callback_drc;
+ switch (sync_src)
+ {
+ case SYNC_AUDIO:
+ desired.callback = audio_callback;
+ break;
+ case SYNC_AUDIO_THREAD:
+ desired.callback = audio_callback_run_on_audio;
+ default:
+ desired.callback = audio_callback_drc;
+ }
desired.userdata = NULL;
if (SDL_OpenAudio(&desired, &actual) < 0) {
@@ -943,12 +968,31 @@ void window_setup(void)
}
tern_val def = {.ptrval = "audio"};
- char *sync_src = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval;
- sync_to_audio = !strcmp(sync_src, "audio");
- run_on_audio_thread = !strcmp(sync_src, "audio_thread");
+ if (external_sync) {
+ sync_src = SYNC_EXTERNAL;
+ } else {
+ char *sync_src_str = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval;
+ if (!strcmp(sync_src_str, "audio")) {
+ sync_src = SYNC_AUDIO;
+ } else if (!strcmp(sync_src_str, "audio_thread")) {
+ sync_src = SYNC_AUDIO_THREAD;
+ } else {
+ sync_src = SYNC_VIDEO;
+ }
+ }
+
+ if (!num_buffers && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) {
+ frame_mutex = SDL_CreateMutex();
+ free_buffer_mutex = SDL_CreateMutex();
+ frame_ready = SDL_CreateCond();
+ buffer_storage = 4;
+ frame_buffers = calloc(buffer_storage, sizeof(uint32_t*));
+ frame_buffers[0] = texture_buf;
+ num_buffers = 1;
+ }
const char *vsync;
- if (sync_to_audio) {
+ if (sync_src == SYNC_AUDIO) {
def.ptrval = "off";
vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval;
} else {
@@ -1108,16 +1152,6 @@ void render_init(int width, int height, char * title, uint8_t fullscreen)
audio_mutex = SDL_CreateMutex();
audio_ready = SDL_CreateCond();
- if (run_on_audio_thread) {
- frame_mutex = SDL_CreateMutex();
- free_buffer_mutex = SDL_CreateMutex();
- frame_ready = SDL_CreateCond();
- buffer_storage = 4;
- frame_buffers = calloc(buffer_storage, sizeof(uint32_t*));
- frame_buffers[0] = texture_buf;
- num_buffers = 1;
- }
-
init_audio();
uint32_t db_size;
@@ -1140,8 +1174,6 @@ static int in_toggle;
void render_config_updated(void)
{
- uint8_t old_sync_to_audio = sync_to_audio;
-
free_surfaces();
#ifndef DISABLE_OPENGL
if (render_gl) {
@@ -1335,7 +1367,7 @@ uint32_t *locked_pixels;
uint32_t locked_pitch;
uint32_t *render_get_framebuffer(uint8_t which, int *pitch)
{
- if (run_on_audio_thread) {
+ if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) {
*pitch = LINEBUF_SIZE * sizeof(uint32_t);
uint32_t *buffer;
SDL_LockMutex(free_buffer_mutex);
@@ -1407,7 +1439,7 @@ static uint8_t interlaced;
static void process_framebuffer(uint32_t *buffer, uint8_t which, int width)
{
static uint8_t last;
- if (!render_is_audio_sync() && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) {
+ if (sync_src == SYNC_VIDEO && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) {
source_frame++;
if (source_frame >= source_hz) {
source_frame = 0;
@@ -1463,7 +1495,7 @@ static void process_framebuffer(uint32_t *buffer, uint8_t which, int width)
}
} else {
#endif
- //TODO: Support run_on_audio_thread for render API framebuffers
+ //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers
if (which <= FRAMEBUFFER_EVEN && last != which) {
uint8_t *cur_dst = (uint8_t *)locked_pixels;
uint8_t *cur_saved = (uint8_t *)texture_buf;
@@ -1612,7 +1644,7 @@ int frame_queue_len, frame_queue_read, frame_queue_write;
void render_framebuffer_updated(uint8_t which, int width)
{
- if (run_on_audio_thread) {
+ if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) {
SDL_LockMutex(frame_mutex);
while (frame_queue_len == 4) {
SDL_CondSignal(frame_ready);
@@ -1650,7 +1682,7 @@ void render_framebuffer_updated(uint8_t which, int width)
void render_video_loop(void)
{
- if (!run_on_audio_thread) {
+ if (sync_src != SYNC_AUDIO_THREAD && sync_src != SYNC_EXTERNAL) {
return;
}
SDL_PauseAudio(0);
@@ -1973,3 +2005,9 @@ uint8_t render_get_active_framebuffer(void)
}
return 0xFF;
}
+
+uint8_t render_create_thread(render_thread *thread, const char *name, render_thread_fun fun, void *data)
+{
+ *thread = SDL_CreateThread(fun, name, data);
+ return *thread != 0;
+}