# HG changeset patch # User Michael Pavone # Date 1587283149 25200 # Node ID 2c1c88cd1a3f694971fcf64a91cf5d6cbff7b642 # Parent 374a5ae694e815b87900db6fccaa0db7b634b667# Parent f23e70fb6607b457fcd75ab8b2a7b1dc4c2e8abe Merge from default diff -r 374a5ae694e8 -r 2c1c88cd1a3f Makefile --- a/Makefile Sat Apr 18 11:42:53 2020 -0700 +++ b/Makefile Sun Apr 19 00:59:09 2020 -0700 @@ -100,16 +100,17 @@ endif ifeq ($(OS),Darwin) -CFLAGS+= -IFrameworks/SDL2.framework/Headers +SDL_INCLUDE_PATH:=Frameworks/SDL2.framework/Headers LDFLAGS+= -FFrameworks -framework SDL2 -framework OpenGL -framework AppKit FIXUP:=install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 @executable_path/Frameworks/SDL2.framework/Versions/A/SDL2 else -CFLAGS+= -Isdl/include +SDL_INCLUDE_PATH:=sdl/include LDFLAGS+= -Wl,-rpath='$$ORIGIN/lib' -Llib -lSDL2 ifndef USE_GLES LDFLAGS+= $(shell pkg-config --libs gl) endif endif #Darwin +CFLAGS+= -I$(SDL_INCLUDE_PATH) else ifeq ($(MAKECMDGOALS),libblastem.$(SO)) @@ -260,6 +261,10 @@ CFLAGS+= -DDATA_PATH='"'$(DATA_PATH)'"' endif +ifdef FONT_PATH +CFLAGS+= -DFONT_PATH='"'$(FONT_PATH)'"' +endif + ALL=dis$(EXE) zdis$(EXE) stateview$(EXE) vgmplay$(EXE) blastem$(EXE) ifneq ($(OS),Windows) ALL+= termhelper diff -r 374a5ae694e8 -r 2c1c88cd1a3f blastem.c --- a/blastem.c Sat Apr 18 11:42:53 2020 -0700 +++ b/blastem.c Sun Apr 19 00:59:09 2020 -0700 @@ -682,6 +682,7 @@ current_system->debugger_type = dtype; current_system->enter_debugger = start_in_debugger && menu == debug_target; current_system->start_context(current_system, menu ? NULL : statefile); + render_video_loop(); for(;;) { if (current_system->should_exit) { diff -r 374a5ae694e8 -r 2c1c88cd1a3f default.cfg --- a/default.cfg Sat Apr 18 11:42:53 2020 -0700 +++ b/default.cfg Sun Apr 19 00:59:09 2020 -0700 @@ -335,6 +335,8 @@ rate 48000 buffer 512 lowpass_cutoff 3390 + #Use f32 for 32-bit floating point, s16 for signed 16-bit integer + format f32 } clocks { diff -r 374a5ae694e8 -r 2c1c88cd1a3f genesis.c --- a/genesis.c Sat Apr 18 11:42:53 2020 -0700 +++ b/genesis.c Sun Apr 19 00:59:09 2020 -0700 @@ -1265,12 +1265,12 @@ resume_68k(gen->m68k); } } -#ifndef IS_LIB - bindings_release_capture(); - vdp_release_framebuffer(gen->vdp); - render_pause_source(gen->ym->audio); - render_pause_source(gen->psg->audio); -#endif + if (render_should_release_on_exit()) { + bindings_release_capture(); + vdp_release_framebuffer(gen->vdp); + render_pause_source(gen->ym->audio); + render_pause_source(gen->psg->audio); + } } static void start_genesis(system_header *system, char *statefile) @@ -1321,13 +1321,13 @@ static void resume_genesis(system_header *system) { genesis_context *gen = (genesis_context *)system; -#ifndef IS_LIB - render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); - bindings_reacquire_capture(); - vdp_reacquire_framebuffer(gen->vdp); - render_resume_source(gen->ym->audio); - render_resume_source(gen->psg->audio); -#endif + if (render_should_release_on_exit()) { + render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); + bindings_reacquire_capture(); + vdp_reacquire_framebuffer(gen->vdp); + render_resume_source(gen->ym->audio); + render_resume_source(gen->psg->audio); + } resume_68k(gen->m68k); handle_reset_requests(gen); } diff -r 374a5ae694e8 -r 2c1c88cd1a3f libblastem.c --- a/libblastem.c Sat Apr 18 11:42:53 2020 -0700 +++ b/libblastem.c Sun Apr 19 00:59:09 2020 -0700 @@ -453,6 +453,11 @@ return 1; } +uint8_t render_should_release_on_exit(void) +{ + return 0; +} + void render_buffer_consumed(audio_source *src) { } diff -r 374a5ae694e8 -r 2c1c88cd1a3f nuklear_ui/font.c --- a/nuklear_ui/font.c Sat Apr 18 11:42:53 2020 -0700 +++ b/nuklear_ui/font.c Sun Apr 19 00:59:09 2020 -0700 @@ -1,11 +1,19 @@ #include #include #include +#include #include "../util.h" #include "sfnt.h" char *default_font_path(void) { +#ifdef FONT_PATH + FILE *f = fopen(FONT_PATH, "rb"); + if (f) { + fclose(f); + return strdup(FONT_PATH); + } +#endif FILE *fc_pipe = popen("fc-match -f '%{file}'", "r"); if (!fc_pipe) { return NULL; diff -r 374a5ae694e8 -r 2c1c88cd1a3f render.h --- a/render.h Sat Apr 18 11:42:53 2020 -0700 +++ b/render.h Sun Apr 19 00:59:09 2020 -0700 @@ -135,6 +135,8 @@ void render_set_gl_context_handlers(ui_render_fun destroy, ui_render_fun create); 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); #endif //RENDER_H_ diff -r 374a5ae694e8 -r 2c1c88cd1a3f render_sdl.c --- a/render_sdl.c Sat Apr 18 11:42:53 2020 -0700 +++ b/render_sdl.c Sun Apr 19 00:59:09 2020 -0700 @@ -46,13 +46,17 @@ static uint32_t last_frame = 0; -static SDL_mutex * audio_mutex; -static SDL_cond * audio_ready; +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; +static uint8_t sync_to_audio, run_on_audio_thread; static uint32_t min_buffered; +uint32_t **frame_buffers; +uint32_t num_buffers; +uint32_t buffer_storage; + uint32_t render_min_buffered(void) { return min_buffered; @@ -60,7 +64,12 @@ uint8_t render_is_audio_sync(void) { - return sync_to_audio; + return sync_to_audio || run_on_audio_thread; +} + +uint8_t render_should_release_on_exit(void) +{ + return !run_on_audio_thread; } void render_buffer_consumed(audio_source *src) @@ -101,6 +110,14 @@ cur_min_buffered = mix_and_convert(byte_stream, len, &min_remaining_buffer); } +static void audio_callback_run_on_audio(void *user_data, uint8_t *byte_stream, int len) +{ + if (current_system) { + current_system->resume_context(current_system); + } + mix_and_convert(byte_stream, len, NULL); +} + void render_lock_audio() { if (sync_to_audio) { @@ -150,6 +167,9 @@ if (sync_to_audio && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) { SDL_PauseAudio(0); } + if (current_system) { + current_system->request_exit(current_system); + } } void render_source_paused(audio_source *src, uint8_t remaining_sources) @@ -171,7 +191,17 @@ void render_do_audio_ready(audio_source *src) { - if (sync_to_audio) { + if (run_on_audio_thread) { + int16_t *tmp = src->front; + src->front = src->back; + src->back = tmp; + src->front_populated = 1; + src->buffer_pos = 0; + if (all_sources_ready()) { + //we've emulated far enough to fill the current buffer + current_system->request_exit(current_system); + } + } else if (sync_to_audio) { SDL_LockMutex(audio_mutex); while (src->front_populated) { SDL_CondWait(src->opaque, audio_mutex); @@ -873,7 +903,8 @@ rate = 48000; } desired.freq = rate; - desired.format = AUDIO_F32SYS; + char *config_format = tern_find_path_default(config, "audio\0format\0", (tern_val){.ptrval="f32"}, TVAL_PTR).ptrval; + desired.format = !strcmp(config_format, "s16") ? AUDIO_S16SYS : AUDIO_F32SYS; desired.channels = 2; char * samples_str = tern_find_path(config, "audio\0buffer\0", TVAL_PTR).ptrval; int samples = samples_str ? atoi(samples_str) : 0; @@ -882,7 +913,7 @@ } debug_message("config says: %d\n", samples); desired.samples = samples*2; - desired.callback = sync_to_audio ? audio_callback : audio_callback_drc; + desired.callback = sync_to_audio ? audio_callback : run_on_audio_thread ? audio_callback_run_on_audio : audio_callback_drc; desired.userdata = NULL; if (SDL_OpenAudio(&desired, &actual) < 0) { @@ -914,6 +945,7 @@ 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"); const char *vsync; if (sync_to_audio) { @@ -1076,6 +1108,16 @@ 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; @@ -1177,12 +1219,15 @@ uint32_t render_audio_syncs_per_sec(void) { //sync samples with audio thread approximately every 8 lines when doing sync to video - return sync_to_audio ? 0 : source_hz * (video_standard == VID_PAL ? 313 : 262) / 8; + return render_is_audio_sync() ? 0 : source_hz * (video_standard == VID_PAL ? 313 : 262) / 8; } void render_set_video_standard(vid_std std) { video_standard = std; + if (render_is_audio_sync()) { + return; + } source_hz = std == VID_PAL ? 50 : 60; uint32_t max_repeat = 0; if (abs(source_hz - display_hz) < 2) { @@ -1291,6 +1336,19 @@ uint32_t locked_pitch; uint32_t *render_get_framebuffer(uint8_t which, int *pitch) { + if (run_on_audio_thread) { + *pitch = LINEBUF_SIZE * sizeof(uint32_t); + uint32_t *buffer; + SDL_LockMutex(free_buffer_mutex); + if (num_buffers) { + buffer = frame_buffers[--num_buffers]; + } else { + buffer = calloc(512*512, sizeof(uint32_t)); + } + SDL_UnlockMutex(free_buffer_mutex); + locked_pixels = buffer; + return buffer; + } #ifndef DISABLE_OPENGL if (render_gl && which <= FRAMEBUFFER_EVEN) { *pitch = LINEBUF_SIZE * sizeof(uint32_t); @@ -1327,6 +1385,17 @@ #endif } +static void release_buffer(uint32_t *buffer) +{ + SDL_LockMutex(free_buffer_mutex); + if (num_buffers == buffer_storage) { + buffer_storage *= 2; + frame_buffers = realloc(frame_buffers, sizeof(uint32_t*)*buffer_storage); + } + frame_buffers[num_buffers++] = buffer; + SDL_UnlockMutex(free_buffer_mutex); +} + uint8_t events_processed; #ifdef __ANDROID__ #define FPS_INTERVAL 10000 @@ -1336,10 +1405,10 @@ static uint32_t last_width, last_height; static uint8_t interlaced; -void render_framebuffer_updated(uint8_t which, int width) +static void process_framebuffer(uint32_t *buffer, uint8_t which, int width) { static uint8_t last; - if (!sync_to_audio && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) { + if (!render_is_audio_sync() && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) { source_frame++; if (source_frame >= source_hz) { source_frame = 0; @@ -1377,24 +1446,25 @@ if (render_gl && which <= FRAMEBUFFER_EVEN) { SDL_GL_MakeCurrent(main_window, main_context); glBindTexture(GL_TEXTURE_2D, textures[which]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, SRC_FORMAT, GL_UNSIGNED_BYTE, buffer + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]); if (screenshot_file) { //properly supporting interlaced modes here is non-trivial, so only save the odd field for now #ifndef DISABLE_ZLIB if (!strcasecmp(ext, "png")) { free(ext); - save_png(screenshot_file, texture_buf, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); + save_png(screenshot_file, buffer, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); } else { free(ext); #endif - save_ppm(screenshot_file, texture_buf, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); + save_ppm(screenshot_file, buffer, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); #ifndef DISABLE_ZLIB } #endif } } else { #endif + //TODO: Support run_on_audio_thread 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; @@ -1475,7 +1545,7 @@ frame_counter = 0; } } - if (!sync_to_audio) { + if (!render_is_audio_sync()) { int32_t local_cur_min, local_min_remaining; SDL_LockAudio(); if (last_buffered > NO_LAST_BUFFERED) { @@ -1533,6 +1603,78 @@ } } +typedef struct { + uint32_t *buffer; + int width; + uint8_t which; +} frame; +frame frame_queue[4]; +int frame_queue_len, frame_queue_read, frame_queue_write; + +void render_framebuffer_updated(uint8_t which, int width) +{ + if (run_on_audio_thread) { + SDL_LockMutex(frame_mutex); + while (frame_queue_len == 4) { + SDL_CondSignal(frame_ready); + SDL_UnlockMutex(frame_mutex); + SDL_Delay(1); + SDL_LockMutex(frame_mutex); + } + for (int cur = frame_queue_read, i = 0; i < frame_queue_len; i++) { + if (frame_queue[cur].which == which) { + int last = (frame_queue_write - 1) & 3; + frame_queue_len--; + release_buffer(frame_queue[cur].buffer); + if (last != cur) { + frame_queue[cur] = frame_queue[last]; + } + frame_queue_write = last; + break; + } + cur = (cur + 1) & 3; + } + frame_queue[frame_queue_write++] = (frame){ + .buffer = locked_pixels, + .width = width, + .which = which + }; + frame_queue_write &= 0x3; + frame_queue_len++; + SDL_CondSignal(frame_ready); + SDL_UnlockMutex(frame_mutex); + return; + } + //TODO: Maybe fixme for render API + process_framebuffer(texture_buf, which, width); +} + +void render_video_loop(void) +{ + if (!run_on_audio_thread) { + return; + } + SDL_PauseAudio(0); + SDL_LockMutex(frame_mutex); + for(;;) + { + while (!frame_queue_len) + { + SDL_CondWait(frame_ready, frame_mutex); + } + for (int i = 0; i < frame_queue_len; i++) + { + frame f = frame_queue[frame_queue_read++]; + frame_queue_read &= 0x3; + process_framebuffer(f.buffer, f.which, f.width); + release_buffer(f.buffer); + } + frame_queue_len = 0; + } + + SDL_UnlockMutex(frame_mutex); +} + static ui_render_fun render_ui; void render_set_ui_render_fun(ui_render_fun fun) { diff -r 374a5ae694e8 -r 2c1c88cd1a3f sms.c --- a/sms.c Sat Apr 18 11:42:53 2020 -0700 +++ b/sms.c Sun Apr 19 00:59:09 2020 -0700 @@ -430,22 +430,22 @@ target_cycle -= adjust; } } -#ifndef IS_LIB - bindings_release_capture(); - vdp_release_framebuffer(sms->vdp); - render_pause_source(sms->psg->audio); -#endif + if (render_should_release_on_exit()) { + bindings_release_capture(); + vdp_release_framebuffer(sms->vdp); + render_pause_source(sms->psg->audio); + } sms->should_return = 0; } static void resume_sms(system_header *system) { sms_context *sms = (sms_context *)system; -#ifndef IS_LIB - bindings_reacquire_capture(); - vdp_reacquire_framebuffer(sms->vdp); - render_resume_source(sms->psg->audio); -#endif + if (render_should_release_on_exit()) { + bindings_reacquire_capture(); + vdp_reacquire_framebuffer(sms->vdp); + render_resume_source(sms->psg->audio); + } run_sms(system); }