comparison render_sdl.c @ 2093:46ee354f29bd

Hack fix for audio deadlock issue
author Michael Pavone <pavone@retrodev.com>
date Sun, 06 Feb 2022 23:25:23 -0800
parents 0757da8ee702
children f11f4399d64b
comparison
equal deleted inserted replaced
2092:8665d8da0e1c 2093:46ee354f29bd
212 if (current_system && sync_src == SYNC_AUDIO_THREAD) { 212 if (current_system && sync_src == SYNC_AUDIO_THREAD) {
213 system_request_exit(current_system, 0); 213 system_request_exit(current_system, 0);
214 } 214 }
215 } 215 }
216 216
217 uint8_t audio_deadlock_hack(void);
218
217 void render_do_audio_ready(audio_source *src) 219 void render_do_audio_ready(audio_source *src)
218 { 220 {
219 if (sync_src == SYNC_AUDIO_THREAD) { 221 if (sync_src == SYNC_AUDIO_THREAD) {
220 int16_t *tmp = src->front; 222 int16_t *tmp = src->front;
221 src->front = src->back; 223 src->front = src->back;
226 //we've emulated far enough to fill the current buffer 228 //we've emulated far enough to fill the current buffer
227 system_request_exit(current_system, 0); 229 system_request_exit(current_system, 0);
228 } 230 }
229 } else if (sync_src == SYNC_AUDIO) { 231 } else if (sync_src == SYNC_AUDIO) {
230 SDL_LockMutex(audio_mutex); 232 SDL_LockMutex(audio_mutex);
233 if (src->front_populated) {
234 if (audio_deadlock_hack()) {
235 SDL_CondSignal(audio_ready);
236 }
237 }
231 while (src->front_populated) { 238 while (src->front_populated) {
232 SDL_CondWait(src->opaque, audio_mutex); 239 SDL_CondWait(src->opaque, audio_mutex);
233 } 240 }
234 int16_t *tmp = src->front; 241 int16_t *tmp = src->front;
235 src->front = src->back; 242 src->front = src->back;
347 fsize = fsize32; 354 fsize = fsize32;
348 #ifndef __ANDROID__ 355 #ifndef __ANDROID__
349 } 356 }
350 #endif 357 #endif
351 text[fsize] = 0; 358 text[fsize] = 0;
352 359
353 if (strncmp(text, "#version", strlen("#version"))) { 360 if (strncmp(text, "#version", strlen("#version"))) {
354 GLchar *tmp = text; 361 GLchar *tmp = text;
355 text = alloc_concat(shader_prefix, tmp); 362 text = alloc_concat(shader_prefix, tmp);
356 free(tmp); 363 free(tmp);
357 fsize += strlen(shader_prefix); 364 fsize += strlen(shader_prefix);
997 { 1004 {
998 uint32_t flags = SDL_WINDOW_RESIZABLE; 1005 uint32_t flags = SDL_WINDOW_RESIZABLE;
999 if (is_fullscreen) { 1006 if (is_fullscreen) {
1000 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; 1007 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
1001 } 1008 }
1002 1009
1003 tern_val def = {.ptrval = "audio"}; 1010 tern_val def = {.ptrval = "audio"};
1004 if (external_sync) { 1011 if (external_sync) {
1005 sync_src = SYNC_EXTERNAL; 1012 sync_src = SYNC_EXTERNAL;
1006 } else { 1013 } else {
1007 char *sync_src_str = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval; 1014 char *sync_src_str = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval;
1011 sync_src = SYNC_AUDIO_THREAD; 1018 sync_src = SYNC_AUDIO_THREAD;
1012 } else { 1019 } else {
1013 sync_src = SYNC_VIDEO; 1020 sync_src = SYNC_VIDEO;
1014 } 1021 }
1015 } 1022 }
1016 1023
1017 if (!num_buffers && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) { 1024 if (!num_buffers && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) {
1018 frame_mutex = SDL_CreateMutex(); 1025 frame_mutex = SDL_CreateMutex();
1019 free_buffer_mutex = SDL_CreateMutex(); 1026 free_buffer_mutex = SDL_CreateMutex();
1020 frame_ready = SDL_CreateCond(); 1027 frame_ready = SDL_CreateCond();
1021 buffer_storage = 4; 1028 buffer_storage = 4;
1022 frame_buffers = calloc(buffer_storage, sizeof(uint32_t*)); 1029 frame_buffers = calloc(buffer_storage, sizeof(uint32_t*));
1023 frame_buffers[0] = texture_buf; 1030 frame_buffers[0] = texture_buf;
1024 num_buffers = 1; 1031 num_buffers = 1;
1025 } 1032 }
1026 1033
1027 const char *vsync; 1034 const char *vsync;
1028 if (sync_src == SYNC_AUDIO) { 1035 if (sync_src == SYNC_AUDIO) {
1029 def.ptrval = "off"; 1036 def.ptrval = "off";
1030 vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval; 1037 vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval;
1031 } else { 1038 } else {
1032 vsync = "on"; 1039 vsync = "on";
1033 } 1040 }
1034 1041
1035 tern_node *video = tern_find_node(config, "video"); 1042 tern_node *video = tern_find_node(config, "video");
1036 if (video) 1043 if (video)
1037 { 1044 {
1038 for (int i = 0; i < NUM_VID_STD; i++) 1045 for (int i = 0; i < NUM_VID_STD; i++)
1039 { 1046 {
1057 } 1064 }
1058 } 1065 }
1059 } 1066 }
1060 } 1067 }
1061 render_gl = 0; 1068 render_gl = 0;
1062 1069
1063 #ifndef DISABLE_OPENGL 1070 #ifndef DISABLE_OPENGL
1064 char *gl_enabled_str = tern_find_path_default(config, "video\0gl\0", def, TVAL_PTR).ptrval; 1071 char *gl_enabled_str = tern_find_path_default(config, "video\0gl\0", def, TVAL_PTR).ptrval;
1065 uint8_t gl_enabled = strcmp(gl_enabled_str, "off") != 0; 1072 uint8_t gl_enabled = strcmp(gl_enabled_str, "off") != 0;
1066 if (gl_enabled) 1073 if (gl_enabled)
1067 { 1074 {
1160 height = ((float)width / aspect) + 0.5f; 1167 height = ((float)width / aspect) + 0.5f;
1161 } 1168 }
1162 debug_message("width: %d, height: %d\n", width, height); 1169 debug_message("width: %d, height: %d\n", width, height);
1163 windowed_width = width; 1170 windowed_width = width;
1164 windowed_height = height; 1171 windowed_height = height;
1165 1172
1166 SDL_DisplayMode mode; 1173 SDL_DisplayMode mode;
1167 //TODO: Explicit multiple monitor support 1174 //TODO: Explicit multiple monitor support
1168 SDL_GetCurrentDisplayMode(0, &mode); 1175 SDL_GetCurrentDisplayMode(0, &mode);
1169 display_hz = mode.refresh_rate; 1176 display_hz = mode.refresh_rate;
1170 1177
1175 height = mode.h; 1182 height = mode.h;
1176 } 1183 }
1177 main_width = width; 1184 main_width = width;
1178 main_height = height; 1185 main_height = height;
1179 is_fullscreen = fullscreen; 1186 is_fullscreen = fullscreen;
1180 1187
1181 caption = title; 1188 caption = title;
1182 1189
1183 window_setup(); 1190 window_setup();
1184 1191
1185 audio_mutex = SDL_CreateMutex(); 1192 audio_mutex = SDL_CreateMutex();
1186 audio_ready = SDL_CreateCond(); 1193 audio_ready = SDL_CreateCond();
1187 1194
1188 init_audio(); 1195 init_audio();
1189 1196
1190 uint32_t db_size; 1197 uint32_t db_size;
1191 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size); 1198 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size);
1192 if (db_data) { 1199 if (db_data) {
1193 int added = SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(db_data, db_size), 1); 1200 int added = SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(db_data, db_size), 1);
1194 free(db_data); 1201 free(db_data);
1195 debug_message("Added %d game controller mappings from gamecontrollerdb.txt\n", added); 1202 debug_message("Added %d game controller mappings from gamecontrollerdb.txt\n", added);
1196 } 1203 }
1197 1204
1198 controller_add_mappings(); 1205 controller_add_mappings();
1199 1206
1200 SDL_JoystickEventState(SDL_ENABLE); 1207 SDL_JoystickEventState(SDL_ENABLE);
1201 1208
1202 render_set_video_standard(VID_NTSC); 1209 render_set_video_standard(VID_NTSC);
1203 1210
1204 atexit(render_quit); 1211 atexit(render_quit);
1205 } 1212 }
1206 1213
1236 #endif 1243 #endif
1237 in_toggle = 1; 1244 in_toggle = 1;
1238 SDL_DestroyWindow(main_window); 1245 SDL_DestroyWindow(main_window);
1239 main_window = NULL; 1246 main_window = NULL;
1240 drain_events(); 1247 drain_events();
1241 1248
1242 char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval; 1249 char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval;
1243 if (config_width) { 1250 if (config_width) {
1244 windowed_width = atoi(config_width); 1251 windowed_width = atoi(config_width);
1245 } 1252 }
1246 char *config_height = tern_find_path(config, "video\0height\0", TVAL_PTR).ptrval; 1253 char *config_height = tern_find_path(config, "video\0height\0", TVAL_PTR).ptrval;
1263 main_height = windowed_height; 1270 main_height = windowed_height;
1264 } 1271 }
1265 if (on_ui_fb_resized) { 1272 if (on_ui_fb_resized) {
1266 on_ui_fb_resized(); 1273 on_ui_fb_resized();
1267 } 1274 }
1268 1275
1269 window_setup(); 1276 window_setup();
1270 update_aspect(); 1277 update_aspect();
1271 #ifndef DISABLE_OPENGL 1278 #ifndef DISABLE_OPENGL
1272 //need to check render_gl again after window_setup as render option could have changed 1279 //need to check render_gl again after window_setup as render option could have changed
1273 if (render_gl && on_context_created) { 1280 if (render_gl && on_context_created) {
1278 uint8_t was_paused = SDL_GetAudioStatus() == SDL_AUDIO_PAUSED; 1285 uint8_t was_paused = SDL_GetAudioStatus() == SDL_AUDIO_PAUSED;
1279 render_close_audio(); 1286 render_close_audio();
1280 quitting = 0; 1287 quitting = 0;
1281 init_audio(); 1288 init_audio();
1282 render_set_video_standard(video_standard); 1289 render_set_video_standard(video_standard);
1283 1290
1284 drain_events(); 1291 drain_events();
1285 in_toggle = 0; 1292 in_toggle = 0;
1286 if (!was_paused) { 1293 if (!was_paused) {
1287 SDL_PauseAudio(0); 1294 SDL_PauseAudio(0);
1288 } 1295 }
1362 if (!extra_windows[i]) { 1369 if (!extra_windows[i]) {
1363 win_idx = i; 1370 win_idx = i;
1364 break; 1371 break;
1365 } 1372 }
1366 } 1373 }
1367 1374
1368 if (win_idx == 0xFF) { 1375 if (win_idx == 0xFF) {
1369 num_textures++; 1376 num_textures++;
1370 sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures)); 1377 sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures));
1371 extra_windows = realloc(extra_windows, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_windows)); 1378 extra_windows = realloc(extra_windows, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_windows));
1372 extra_renderers = realloc(extra_renderers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_renderers)); 1379 extra_renderers = realloc(extra_renderers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_renderers));
1386 if (!sdl_textures[texture_idx]) { 1393 if (!sdl_textures[texture_idx]) {
1387 goto fail_texture; 1394 goto fail_texture;
1388 } 1395 }
1389 close_handlers[win_idx] = close_handler; 1396 close_handlers[win_idx] = close_handler;
1390 return texture_idx; 1397 return texture_idx;
1391 1398
1392 fail_texture: 1399 fail_texture:
1393 SDL_DestroyRenderer(extra_renderers[win_idx]); 1400 SDL_DestroyRenderer(extra_renderers[win_idx]);
1394 fail_renderer: 1401 fail_renderer:
1395 SDL_DestroyWindow(extra_windows[win_idx]); 1402 SDL_DestroyWindow(extra_windows[win_idx]);
1396 fail_window: 1403 fail_window:
1402 { 1409 {
1403 uint8_t win_idx = which - FRAMEBUFFER_USER_START; 1410 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
1404 //Destroying the renderers also frees the textures 1411 //Destroying the renderers also frees the textures
1405 SDL_DestroyRenderer(extra_renderers[win_idx]); 1412 SDL_DestroyRenderer(extra_renderers[win_idx]);
1406 SDL_DestroyWindow(extra_windows[win_idx]); 1413 SDL_DestroyWindow(extra_windows[win_idx]);
1407 1414
1408 extra_renderers[win_idx] = NULL; 1415 extra_renderers[win_idx] = NULL;
1409 extra_windows[win_idx] = NULL; 1416 extra_windows[win_idx] = NULL;
1410 } 1417 }
1411 1418
1412 uint32_t *locked_pixels; 1419 uint32_t *locked_pixels;
1492 } 1499 }
1493 source_frame_count = frame_repeat[source_frame]; 1500 source_frame_count = frame_repeat[source_frame];
1494 //TODO: Figure out what to do about SDL Render API texture locking 1501 //TODO: Figure out what to do about SDL Render API texture locking
1495 return; 1502 return;
1496 } 1503 }
1497 1504
1498 last_width = width; 1505 last_width = width;
1499 uint32_t height = which <= FRAMEBUFFER_EVEN 1506 uint32_t height = which <= FRAMEBUFFER_EVEN
1500 ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard]) 1507 ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard])
1501 : 240; 1508 : 240;
1502 FILE *screenshot_file = NULL; 1509 FILE *screenshot_file = NULL;
1503 uint32_t shot_height, shot_width; 1510 uint32_t shot_height, shot_width;
1504 char *ext; 1511 char *ext;
1522 #ifndef DISABLE_OPENGL 1529 #ifndef DISABLE_OPENGL
1523 if (render_gl && which <= FRAMEBUFFER_EVEN) { 1530 if (render_gl && which <= FRAMEBUFFER_EVEN) {
1524 SDL_GL_MakeCurrent(main_window, main_context); 1531 SDL_GL_MakeCurrent(main_window, main_context);
1525 glBindTexture(GL_TEXTURE_2D, textures[which]); 1532 glBindTexture(GL_TEXTURE_2D, textures[which]);
1526 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]); 1533 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]);
1527 1534
1528 if (screenshot_file) { 1535 if (screenshot_file) {
1529 //properly supporting interlaced modes here is non-trivial, so only save the odd field for now 1536 //properly supporting interlaced modes here is non-trivial, so only save the odd field for now
1530 #ifndef DISABLE_ZLIB 1537 #ifndef DISABLE_ZLIB
1531 if (!strcasecmp(ext, "png")) { 1538 if (!strcasecmp(ext, "png")) {
1532 free(ext); 1539 free(ext);
1644 frames_to_problem < BUFFER_FRAMES_THRESHOLD 1651 frames_to_problem < BUFFER_FRAMES_THRESHOLD
1645 || (average_change < 0 && local_cur_min < 3*min_buffered / 4) 1652 || (average_change < 0 && local_cur_min < 3*min_buffered / 4)
1646 || (average_change >0 && local_cur_min > 5 * min_buffered / 4) 1653 || (average_change >0 && local_cur_min > 5 * min_buffered / 4)
1647 || cur_min_buffered < 0 1654 || cur_min_buffered < 0
1648 ) { 1655 ) {
1649 1656
1650 if (cur_min_buffered < 0) { 1657 if (cur_min_buffered < 0) {
1651 adjust_ratio = max_adjust; 1658 adjust_ratio = max_adjust;
1652 SDL_PauseAudio(1); 1659 SDL_PauseAudio(1);
1653 last_buffered = NO_LAST_BUFFERED; 1660 last_buffered = NO_LAST_BUFFERED;
1654 cur_min_buffered = 0; 1661 cur_min_buffered = 0;
1663 adjust_ratio = max_adjust; 1670 adjust_ratio = max_adjust;
1664 } 1671 }
1665 if (adjust_ratio != 0.0f) { 1672 if (adjust_ratio != 0.0f) {
1666 average_change = 0; 1673 average_change = 0;
1667 render_audio_adjust_speed(adjust_ratio); 1674 render_audio_adjust_speed(adjust_ratio);
1668 1675
1669 } 1676 }
1670 while (source_frame_count > 0) 1677 while (source_frame_count > 0)
1671 { 1678 {
1672 render_update_display(); 1679 render_update_display();
1673 source_frame_count--; 1680 source_frame_count--;
1751 } 1758 }
1752 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING) { 1759 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING) {
1753 break; 1760 break;
1754 } 1761 }
1755 } 1762 }
1756 1763
1757 SDL_UnlockMutex(frame_mutex); 1764 SDL_UnlockMutex(frame_mutex);
1758 } 1765 }
1759 1766
1760 static ui_render_fun render_ui; 1767 static ui_render_fun render_ui;
1761 void render_set_ui_render_fun(ui_render_fun fun) 1768 void render_set_ui_render_fun(ui_render_fun fun)
1789 1796
1790 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); 1797 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
1791 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); 1798 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0);
1792 1799
1793 glDisableVertexAttribArray(at_pos); 1800 glDisableVertexAttribArray(at_pos);
1794 1801
1795 if (render_ui) { 1802 if (render_ui) {
1796 render_ui(); 1803 render_ui();
1797 } 1804 }
1798 1805
1799 SDL_GL_SwapWindow(main_window); 1806 SDL_GL_SwapWindow(main_window);
1900 { 1907 {
1901 tern_node *button_lookup, *axis_lookup; 1908 tern_node *button_lookup, *axis_lookup;
1902 if (controller > MAX_JOYSTICKS || !joysticks[controller]) { 1909 if (controller > MAX_JOYSTICKS || !joysticks[controller]) {
1903 return RENDER_NOT_PLUGGED_IN; 1910 return RENDER_NOT_PLUGGED_IN;
1904 } 1911 }
1905 1912
1906 if (!SDL_IsGameController(joystick_sdl_index[controller])) { 1913 if (!SDL_IsGameController(joystick_sdl_index[controller])) {
1907 return RENDER_NOT_MAPPED; 1914 return RENDER_NOT_MAPPED;
1908 } 1915 }
1909 SDL_GameController *control = SDL_GameControllerOpen(joystick_sdl_index[controller]); 1916 SDL_GameController *control = SDL_GameControllerOpen(joystick_sdl_index[controller]);
1910 if (!control) { 1917 if (!control) {
1911 warning("Failed to open game controller %d: %s\n", controller, SDL_GetError()); 1918 warning("Failed to open game controller %d: %s\n", controller, SDL_GetError());
1912 return RENDER_NOT_PLUGGED_IN; 1919 return RENDER_NOT_PLUGGED_IN;
1913 } 1920 }
1914 1921
1915 SDL_GameControllerButtonBind cbind; 1922 SDL_GameControllerButtonBind cbind;
1916 int32_t is_positive = RENDER_AXIS_POS; 1923 int32_t is_positive = RENDER_AXIS_POS;
1917 if (is_axis) { 1924 if (is_axis) {
1918 1925
1919 int sdl_axis = render_lookup_axis(name); 1926 int sdl_axis = render_lookup_axis(name);
1920 if (sdl_axis == SDL_CONTROLLER_AXIS_INVALID) { 1927 if (sdl_axis == SDL_CONTROLLER_AXIS_INVALID) {
1921 SDL_GameControllerClose(control); 1928 SDL_GameControllerClose(control);
1922 return RENDER_INVALID_NAME; 1929 return RENDER_INVALID_NAME;
1923 } 1930 }
1977 //protect against event processing causing us to attempt to toggle while still toggling 1984 //protect against event processing causing us to attempt to toggle while still toggling
1978 if (in_toggle) { 1985 if (in_toggle) {
1979 return; 1986 return;
1980 } 1987 }
1981 in_toggle = 1; 1988 in_toggle = 1;
1982 1989
1983 //toggling too fast seems to cause a deadlock 1990 //toggling too fast seems to cause a deadlock
1984 static uint32_t last_toggle; 1991 static uint32_t last_toggle;
1985 uint32_t cur = SDL_GetTicks(); 1992 uint32_t cur = SDL_GetTicks();
1986 if (last_toggle && cur - last_toggle < TOGGLE_MIN_DELAY) { 1993 if (last_toggle && cur - last_toggle < TOGGLE_MIN_DELAY) {
1987 in_toggle = 0; 1994 in_toggle = 0;
1988 return; 1995 return;
1989 } 1996 }
1990 last_toggle = cur; 1997 last_toggle = cur;
1991 1998
1992 drain_events(); 1999 drain_events();
1993 is_fullscreen = !is_fullscreen; 2000 is_fullscreen = !is_fullscreen;
1994 if (is_fullscreen) { 2001 if (is_fullscreen) {
1995 SDL_DisplayMode mode; 2002 SDL_DisplayMode mode;
1996 //TODO: Multiple monitor support 2003 //TODO: Multiple monitor support
2050 return FRAMEBUFFER_ODD; 2057 return FRAMEBUFFER_ODD;
2051 } 2058 }
2052 for (int i = 0; i < num_textures - 2; i++) 2059 for (int i = 0; i < num_textures - 2; i++)
2053 { 2060 {
2054 if (extra_windows[i] && (SDL_GetWindowFlags(extra_windows[i]) & SDL_WINDOW_INPUT_FOCUS)) { 2061 if (extra_windows[i] && (SDL_GetWindowFlags(extra_windows[i]) & SDL_WINDOW_INPUT_FOCUS)) {
2055 return FRAMEBUFFER_USER_START + i; 2062 return FRAMEBUFFER_USER_START + i;
2056 } 2063 }
2057 } 2064 }
2058 return 0xFF; 2065 return 0xFF;
2059 } 2066 }
2060 2067