# HG changeset patch # User Michael Pavone # Date 1644218723 28800 # Node ID 46ee354f29bd15208c8f24f8f92183951b1f77ab # Parent 8665d8da0e1c26d1b21a77341487767f9efe82ec Hack fix for audio deadlock issue diff -r 8665d8da0e1c -r 46ee354f29bd render_audio.c --- a/render_audio.c Sun Feb 06 22:52:24 2022 -0800 +++ b/render_audio.c Sun Feb 06 23:25:23 2022 -0800 @@ -135,6 +135,40 @@ return num_populated == num_audio_sources; } +uint8_t audio_deadlock_hack(void) +{ + uint32_t min_buffer_pos = 0xFFFFFFFFU; + for (uint8_t i = 0; i < num_audio_sources; i++) + { + if (audio_sources[i]->front_populated) { + uint32_t buffer_pos = audio_sources[i]->buffer_pos; + if (audio_sources[i]->num_channels == 1) { + buffer_pos *= 2; + } + if (buffer_pos < min_buffer_pos) { + min_buffer_pos = buffer_pos; + } + } + } + uint8_t do_signal = 0; + for (uint8_t i = 0; i < num_audio_sources; i++) + { + if (!audio_sources[i]->front_populated) { + audio_sources[i]->front_populated = 1; + int16_t *tmp = audio_sources[i]->front; + audio_sources[i]->front = audio_sources[i]->back; + audio_sources[i]->back = tmp; + if (audio_sources[i]->num_channels == 2) { + audio_sources[i]->buffer_pos = min_buffer_pos; + } else { + audio_sources[i]->buffer_pos = min_buffer_pos / 2; + } + do_signal = 1; + } + } + return do_signal; +} + #define BUFFER_INC_RES 0x40000000UL void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider) diff -r 8665d8da0e1c -r 46ee354f29bd render_sdl.c --- a/render_sdl.c Sun Feb 06 22:52:24 2022 -0800 +++ b/render_sdl.c Sun Feb 06 23:25:23 2022 -0800 @@ -214,6 +214,8 @@ } } +uint8_t audio_deadlock_hack(void); + void render_do_audio_ready(audio_source *src) { if (sync_src == SYNC_AUDIO_THREAD) { @@ -228,6 +230,11 @@ } } else if (sync_src == SYNC_AUDIO) { SDL_LockMutex(audio_mutex); + if (src->front_populated) { + if (audio_deadlock_hack()) { + SDL_CondSignal(audio_ready); + } + } while (src->front_populated) { SDL_CondWait(src->opaque, audio_mutex); } @@ -349,7 +356,7 @@ } #endif text[fsize] = 0; - + if (strncmp(text, "#version", strlen("#version"))) { GLchar *tmp = text; text = alloc_concat(shader_prefix, tmp); @@ -999,7 +1006,7 @@ if (is_fullscreen) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } - + tern_val def = {.ptrval = "audio"}; if (external_sync) { sync_src = SYNC_EXTERNAL; @@ -1013,7 +1020,7 @@ 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(); @@ -1023,7 +1030,7 @@ frame_buffers[0] = texture_buf; num_buffers = 1; } - + const char *vsync; if (sync_src == SYNC_AUDIO) { def.ptrval = "off"; @@ -1031,7 +1038,7 @@ } else { vsync = "on"; } - + tern_node *video = tern_find_node(config, "video"); if (video) { @@ -1059,7 +1066,7 @@ } } render_gl = 0; - + #ifndef DISABLE_OPENGL char *gl_enabled_str = tern_find_path_default(config, "video\0gl\0", def, TVAL_PTR).ptrval; uint8_t gl_enabled = strcmp(gl_enabled_str, "off") != 0; @@ -1162,7 +1169,7 @@ debug_message("width: %d, height: %d\n", width, height); windowed_width = width; windowed_height = height; - + SDL_DisplayMode mode; //TODO: Explicit multiple monitor support SDL_GetCurrentDisplayMode(0, &mode); @@ -1177,16 +1184,16 @@ main_width = width; main_height = height; is_fullscreen = fullscreen; - + caption = title; - + window_setup(); audio_mutex = SDL_CreateMutex(); audio_ready = SDL_CreateCond(); - + init_audio(); - + uint32_t db_size; char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size); if (db_data) { @@ -1194,11 +1201,11 @@ free(db_data); debug_message("Added %d game controller mappings from gamecontrollerdb.txt\n", added); } - + controller_add_mappings(); - + SDL_JoystickEventState(SDL_ENABLE); - + render_set_video_standard(VID_NTSC); atexit(render_quit); @@ -1238,7 +1245,7 @@ SDL_DestroyWindow(main_window); main_window = NULL; drain_events(); - + char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval; if (config_width) { windowed_width = atoi(config_width); @@ -1265,7 +1272,7 @@ if (on_ui_fb_resized) { on_ui_fb_resized(); } - + window_setup(); update_aspect(); #ifndef DISABLE_OPENGL @@ -1280,7 +1287,7 @@ quitting = 0; init_audio(); render_set_video_standard(video_standard); - + drain_events(); in_toggle = 0; if (!was_paused) { @@ -1364,7 +1371,7 @@ break; } } - + if (win_idx == 0xFF) { num_textures++; sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures)); @@ -1388,7 +1395,7 @@ } close_handlers[win_idx] = close_handler; return texture_idx; - + fail_texture: SDL_DestroyRenderer(extra_renderers[win_idx]); fail_renderer: @@ -1404,7 +1411,7 @@ //Destroying the renderers also frees the textures SDL_DestroyRenderer(extra_renderers[win_idx]); SDL_DestroyWindow(extra_windows[win_idx]); - + extra_renderers[win_idx] = NULL; extra_windows[win_idx] = NULL; } @@ -1494,9 +1501,9 @@ //TODO: Figure out what to do about SDL Render API texture locking return; } - + last_width = width; - uint32_t height = which <= FRAMEBUFFER_EVEN + uint32_t height = which <= FRAMEBUFFER_EVEN ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard]) : 240; FILE *screenshot_file = NULL; @@ -1524,7 +1531,7 @@ 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, 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 @@ -1646,7 +1653,7 @@ || (average_change >0 && local_cur_min > 5 * min_buffered / 4) || cur_min_buffered < 0 ) { - + if (cur_min_buffered < 0) { adjust_ratio = max_adjust; SDL_PauseAudio(1); @@ -1665,7 +1672,7 @@ if (adjust_ratio != 0.0f) { average_change = 0; render_audio_adjust_speed(adjust_ratio); - + } while (source_frame_count > 0) { @@ -1753,7 +1760,7 @@ break; } } - + SDL_UnlockMutex(frame_mutex); } @@ -1791,7 +1798,7 @@ glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); glDisableVertexAttribArray(at_pos); - + if (render_ui) { render_ui(); } @@ -1902,7 +1909,7 @@ if (controller > MAX_JOYSTICKS || !joysticks[controller]) { return RENDER_NOT_PLUGGED_IN; } - + if (!SDL_IsGameController(joystick_sdl_index[controller])) { return RENDER_NOT_MAPPED; } @@ -1911,11 +1918,11 @@ warning("Failed to open game controller %d: %s\n", controller, SDL_GetError()); return RENDER_NOT_PLUGGED_IN; } - + SDL_GameControllerButtonBind cbind; int32_t is_positive = RENDER_AXIS_POS; if (is_axis) { - + int sdl_axis = render_lookup_axis(name); if (sdl_axis == SDL_CONTROLLER_AXIS_INVALID) { SDL_GameControllerClose(control); @@ -1979,7 +1986,7 @@ return; } in_toggle = 1; - + //toggling too fast seems to cause a deadlock static uint32_t last_toggle; uint32_t cur = SDL_GetTicks(); @@ -1988,7 +1995,7 @@ return; } last_toggle = cur; - + drain_events(); is_fullscreen = !is_fullscreen; if (is_fullscreen) { @@ -2052,7 +2059,7 @@ for (int i = 0; i < num_textures - 2; i++) { if (extra_windows[i] && (SDL_GetWindowFlags(extra_windows[i]) & SDL_WINDOW_INPUT_FOCUS)) { - return FRAMEBUFFER_USER_START + i; + return FRAMEBUFFER_USER_START + i; } } return 0xFF;