Mercurial > repos > blastem
comparison render_sdl.c @ 1983:a7b753e260a2 mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 09 May 2020 23:39:44 -0700 |
parents | 81df9aa2de9b |
children | 3537514ea206 |
comparison
equal
deleted
inserted
replaced
1937:cafde1255ad3 | 1983:a7b753e260a2 |
---|---|
48 | 48 |
49 static SDL_mutex *audio_mutex, *frame_mutex, *free_buffer_mutex; | 49 static SDL_mutex *audio_mutex, *frame_mutex, *free_buffer_mutex; |
50 static SDL_cond *audio_ready, *frame_ready; | 50 static SDL_cond *audio_ready, *frame_ready; |
51 static uint8_t quitting = 0; | 51 static uint8_t quitting = 0; |
52 | 52 |
53 static uint8_t sync_to_audio, run_on_audio_thread; | 53 enum { |
54 SYNC_AUDIO, | |
55 SYNC_AUDIO_THREAD, | |
56 SYNC_VIDEO, | |
57 SYNC_EXTERNAL | |
58 }; | |
59 | |
60 static uint8_t sync_src; | |
54 static uint32_t min_buffered; | 61 static uint32_t min_buffered; |
55 | 62 |
56 uint32_t **frame_buffers; | 63 uint32_t **frame_buffers; |
57 uint32_t num_buffers; | 64 uint32_t num_buffers; |
58 uint32_t buffer_storage; | 65 uint32_t buffer_storage; |
62 return min_buffered; | 69 return min_buffered; |
63 } | 70 } |
64 | 71 |
65 uint8_t render_is_audio_sync(void) | 72 uint8_t render_is_audio_sync(void) |
66 { | 73 { |
67 return sync_to_audio || run_on_audio_thread; | 74 return sync_src < SYNC_VIDEO; |
68 } | 75 } |
69 | 76 |
70 uint8_t render_should_release_on_exit(void) | 77 uint8_t render_should_release_on_exit(void) |
71 { | 78 { |
72 return !run_on_audio_thread; | 79 return sync_src != SYNC_AUDIO_THREAD; |
73 } | 80 } |
74 | 81 |
75 void render_buffer_consumed(audio_source *src) | 82 void render_buffer_consumed(audio_source *src) |
76 { | 83 { |
77 SDL_CondSignal(src->opaque); | 84 SDL_CondSignal(src->opaque); |
118 mix_and_convert(byte_stream, len, NULL); | 125 mix_and_convert(byte_stream, len, NULL); |
119 } | 126 } |
120 | 127 |
121 void render_lock_audio() | 128 void render_lock_audio() |
122 { | 129 { |
123 if (sync_to_audio) { | 130 if (sync_src == SYNC_AUDIO) { |
124 SDL_LockMutex(audio_mutex); | 131 SDL_LockMutex(audio_mutex); |
125 } else { | 132 } else { |
126 SDL_LockAudio(); | 133 SDL_LockAudio(); |
127 } | 134 } |
128 } | 135 } |
129 | 136 |
130 void render_unlock_audio() | 137 void render_unlock_audio() |
131 { | 138 { |
132 if (sync_to_audio) { | 139 if (sync_src == SYNC_AUDIO) { |
133 SDL_UnlockMutex(audio_mutex); | 140 SDL_UnlockMutex(audio_mutex); |
134 } else { | 141 } else { |
135 SDL_UnlockAudio(); | 142 SDL_UnlockAudio(); |
136 } | 143 } |
137 } | 144 } |
162 SDL_DestroyCond(opaque); | 169 SDL_DestroyCond(opaque); |
163 } | 170 } |
164 | 171 |
165 void render_audio_created(audio_source *source) | 172 void render_audio_created(audio_source *source) |
166 { | 173 { |
167 if (sync_to_audio && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) { | 174 if (render_is_audio_sync()) { |
168 SDL_PauseAudio(0); | 175 SDL_PauseAudio(0); |
169 } | 176 } |
170 if (current_system) { | 177 if (current_system && sync_src == SYNC_AUDIO_THREAD) { |
171 current_system->request_exit(current_system); | 178 system_request_exit(current_system, 0); |
172 } | 179 } |
173 } | 180 } |
174 | 181 |
175 void render_source_paused(audio_source *src, uint8_t remaining_sources) | 182 void render_source_paused(audio_source *src, uint8_t remaining_sources) |
176 { | 183 { |
177 if (sync_to_audio) { | 184 if (sync_src == SYNC_AUDIO) { |
178 SDL_CondSignal(audio_ready); | 185 SDL_CondSignal(audio_ready); |
179 } | 186 } |
180 if (!remaining_sources) { | 187 if (!remaining_sources && render_is_audio_sync()) { |
188 SDL_PauseAudio(1); | |
189 if (sync_src == SYNC_AUDIO_THREAD) { | |
190 SDL_CondSignal(frame_ready); | |
191 } | |
192 } | |
193 } | |
194 | |
195 void render_source_resumed(audio_source *src) | |
196 { | |
197 if (render_is_audio_sync()) { | |
181 SDL_PauseAudio(0); | 198 SDL_PauseAudio(0); |
182 } | 199 } |
183 } | 200 if (current_system && sync_src == SYNC_AUDIO_THREAD) { |
184 | 201 system_request_exit(current_system, 0); |
185 void render_source_resumed(audio_source *src) | |
186 { | |
187 if (sync_to_audio) { | |
188 SDL_PauseAudio(0); | |
189 } | 202 } |
190 } | 203 } |
191 | 204 |
192 void render_do_audio_ready(audio_source *src) | 205 void render_do_audio_ready(audio_source *src) |
193 { | 206 { |
194 if (run_on_audio_thread) { | 207 if (sync_src == SYNC_AUDIO_THREAD) { |
195 int16_t *tmp = src->front; | 208 int16_t *tmp = src->front; |
196 src->front = src->back; | 209 src->front = src->back; |
197 src->back = tmp; | 210 src->back = tmp; |
198 src->front_populated = 1; | 211 src->front_populated = 1; |
199 src->buffer_pos = 0; | 212 src->buffer_pos = 0; |
200 if (all_sources_ready()) { | 213 if (all_sources_ready()) { |
201 //we've emulated far enough to fill the current buffer | 214 //we've emulated far enough to fill the current buffer |
202 current_system->request_exit(current_system); | 215 system_request_exit(current_system, 0); |
203 } | 216 } |
204 } else if (sync_to_audio) { | 217 } else if (sync_src == SYNC_AUDIO) { |
205 SDL_LockMutex(audio_mutex); | 218 SDL_LockMutex(audio_mutex); |
206 while (src->front_populated) { | 219 while (src->front_populated) { |
207 SDL_CondWait(src->opaque, audio_mutex); | 220 SDL_CondWait(src->opaque, audio_mutex); |
208 } | 221 } |
209 int16_t *tmp = src->front; | 222 int16_t *tmp = src->front; |
251 #else | 264 #else |
252 return 255 << 24 | r << 16 | g << 8 | b; | 265 return 255 << 24 | r << 16 | g << 8 | b; |
253 #endif | 266 #endif |
254 } | 267 } |
255 | 268 |
269 static uint8_t external_sync; | |
270 void render_set_external_sync(uint8_t ext_sync_on) | |
271 { | |
272 if (ext_sync_on != external_sync) { | |
273 external_sync = ext_sync_on; | |
274 if (windowed_width) { | |
275 //only do this if render_init has already been called | |
276 render_config_updated(); | |
277 } | |
278 } | |
279 } | |
280 | |
256 #ifndef DISABLE_OPENGL | 281 #ifndef DISABLE_OPENGL |
257 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, at_pos; | 282 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, un_texsize, at_pos; |
283 static int tex_width, tex_height; | |
258 | 284 |
259 static GLfloat vertex_data_default[] = { | 285 static GLfloat vertex_data_default[] = { |
260 -1.0f, -1.0f, | 286 -1.0f, -1.0f, |
261 1.0f, -1.0f, | 287 1.0f, -1.0f, |
262 -1.0f, 1.0f, | 288 -1.0f, 1.0f, |
358 { | 384 { |
359 tern_val def = {.ptrval = "linear"}; | 385 tern_val def = {.ptrval = "linear"}; |
360 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; | 386 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; |
361 GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR; | 387 GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR; |
362 glGenTextures(3, textures); | 388 glGenTextures(3, textures); |
389 def.ptrval = "off"; | |
390 char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", def, TVAL_PTR).ptrval; | |
391 if (!strcmp(npot_textures, "on")) { | |
392 tex_width = LINEBUF_SIZE; | |
393 tex_height = 294; //PAL height with full borders | |
394 } else { | |
395 tex_width = tex_height = 512; | |
396 } | |
397 printf("Using %dx%d textures\n", tex_width, tex_height); | |
363 for (int i = 0; i < 3; i++) | 398 for (int i = 0; i < 3; i++) |
364 { | 399 { |
365 glBindTexture(GL_TEXTURE_2D, textures[i]); | 400 glBindTexture(GL_TEXTURE_2D, textures[i]); |
366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); | 401 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); |
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); | 402 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); |
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 403 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 404 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
370 if (i < 2) { | 405 if (i < 2) { |
371 //TODO: Fixme for PAL + invalid display mode | 406 //TODO: Fixme for PAL + invalid display mode |
372 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 512, 512, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf); | 407 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, tex_width, tex_height, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf); |
373 } else { | 408 } else { |
374 uint32_t blank = 255 << 24; | 409 uint32_t blank = 255 << 24; |
375 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, &blank); | 410 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, &blank); |
376 } | 411 } |
377 } | 412 } |
396 } | 431 } |
397 un_textures[0] = glGetUniformLocation(program, "textures[0]"); | 432 un_textures[0] = glGetUniformLocation(program, "textures[0]"); |
398 un_textures[1] = glGetUniformLocation(program, "textures[1]"); | 433 un_textures[1] = glGetUniformLocation(program, "textures[1]"); |
399 un_width = glGetUniformLocation(program, "width"); | 434 un_width = glGetUniformLocation(program, "width"); |
400 un_height = glGetUniformLocation(program, "height"); | 435 un_height = glGetUniformLocation(program, "height"); |
436 un_texsize = glGetUniformLocation(program, "texsize"); | |
401 at_pos = glGetAttribLocation(program, "pos"); | 437 at_pos = glGetAttribLocation(program, "pos"); |
402 } | 438 } |
403 | 439 |
404 static void gl_teardown() | 440 static void gl_teardown() |
405 { | 441 { |
911 if (!samples) { | 947 if (!samples) { |
912 samples = 512; | 948 samples = 512; |
913 } | 949 } |
914 debug_message("config says: %d\n", samples); | 950 debug_message("config says: %d\n", samples); |
915 desired.samples = samples*2; | 951 desired.samples = samples*2; |
916 desired.callback = sync_to_audio ? audio_callback : run_on_audio_thread ? audio_callback_run_on_audio : audio_callback_drc; | 952 switch (sync_src) |
953 { | |
954 case SYNC_AUDIO: | |
955 desired.callback = audio_callback; | |
956 break; | |
957 case SYNC_AUDIO_THREAD: | |
958 desired.callback = audio_callback_run_on_audio; | |
959 break; | |
960 default: | |
961 desired.callback = audio_callback_drc; | |
962 } | |
917 desired.userdata = NULL; | 963 desired.userdata = NULL; |
918 | 964 |
919 if (SDL_OpenAudio(&desired, &actual) < 0) { | 965 if (SDL_OpenAudio(&desired, &actual) < 0) { |
920 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); | 966 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); |
921 } | 967 } |
941 if (is_fullscreen) { | 987 if (is_fullscreen) { |
942 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; | 988 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; |
943 } | 989 } |
944 | 990 |
945 tern_val def = {.ptrval = "audio"}; | 991 tern_val def = {.ptrval = "audio"}; |
946 char *sync_src = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval; | 992 if (external_sync) { |
947 sync_to_audio = !strcmp(sync_src, "audio"); | 993 sync_src = SYNC_EXTERNAL; |
948 run_on_audio_thread = !strcmp(sync_src, "audio_thread"); | 994 } else { |
995 char *sync_src_str = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval; | |
996 if (!strcmp(sync_src_str, "audio")) { | |
997 sync_src = SYNC_AUDIO; | |
998 } else if (!strcmp(sync_src_str, "audio_thread")) { | |
999 sync_src = SYNC_AUDIO_THREAD; | |
1000 } else { | |
1001 sync_src = SYNC_VIDEO; | |
1002 } | |
1003 } | |
1004 | |
1005 if (!num_buffers && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) { | |
1006 frame_mutex = SDL_CreateMutex(); | |
1007 free_buffer_mutex = SDL_CreateMutex(); | |
1008 frame_ready = SDL_CreateCond(); | |
1009 buffer_storage = 4; | |
1010 frame_buffers = calloc(buffer_storage, sizeof(uint32_t*)); | |
1011 frame_buffers[0] = texture_buf; | |
1012 num_buffers = 1; | |
1013 } | |
949 | 1014 |
950 const char *vsync; | 1015 const char *vsync; |
951 if (sync_to_audio) { | 1016 if (sync_src == SYNC_AUDIO) { |
952 def.ptrval = "off"; | 1017 def.ptrval = "off"; |
953 vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval; | 1018 vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval; |
954 } else { | 1019 } else { |
955 vsync = "on"; | 1020 vsync = "on"; |
956 } | 1021 } |
1106 window_setup(); | 1171 window_setup(); |
1107 | 1172 |
1108 audio_mutex = SDL_CreateMutex(); | 1173 audio_mutex = SDL_CreateMutex(); |
1109 audio_ready = SDL_CreateCond(); | 1174 audio_ready = SDL_CreateCond(); |
1110 | 1175 |
1111 if (run_on_audio_thread) { | |
1112 frame_mutex = SDL_CreateMutex(); | |
1113 free_buffer_mutex = SDL_CreateMutex(); | |
1114 frame_ready = SDL_CreateCond(); | |
1115 buffer_storage = 4; | |
1116 frame_buffers = calloc(buffer_storage, sizeof(uint32_t*)); | |
1117 frame_buffers[0] = texture_buf; | |
1118 num_buffers = 1; | |
1119 } | |
1120 | |
1121 init_audio(); | 1176 init_audio(); |
1122 | 1177 |
1123 uint32_t db_size; | 1178 uint32_t db_size; |
1124 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size); | 1179 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size); |
1125 if (db_data) { | 1180 if (db_data) { |
1134 | 1189 |
1135 render_set_video_standard(VID_NTSC); | 1190 render_set_video_standard(VID_NTSC); |
1136 | 1191 |
1137 atexit(render_quit); | 1192 atexit(render_quit); |
1138 } | 1193 } |
1139 #include<unistd.h> | |
1140 static int in_toggle; | 1194 static int in_toggle; |
1141 | 1195 |
1142 void render_config_updated(void) | 1196 void render_config_updated(void) |
1143 { | 1197 { |
1144 uint8_t old_sync_to_audio = sync_to_audio; | |
1145 | |
1146 free_surfaces(); | 1198 free_surfaces(); |
1147 #ifndef DISABLE_OPENGL | 1199 #ifndef DISABLE_OPENGL |
1148 if (render_gl) { | 1200 if (render_gl) { |
1149 if (on_context_destroyed) { | 1201 if (on_context_destroyed) { |
1150 on_context_destroyed(); | 1202 on_context_destroyed(); |
1334 | 1386 |
1335 uint32_t *locked_pixels; | 1387 uint32_t *locked_pixels; |
1336 uint32_t locked_pitch; | 1388 uint32_t locked_pitch; |
1337 uint32_t *render_get_framebuffer(uint8_t which, int *pitch) | 1389 uint32_t *render_get_framebuffer(uint8_t which, int *pitch) |
1338 { | 1390 { |
1339 if (run_on_audio_thread) { | 1391 if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) { |
1340 *pitch = LINEBUF_SIZE * sizeof(uint32_t); | 1392 *pitch = LINEBUF_SIZE * sizeof(uint32_t); |
1341 uint32_t *buffer; | 1393 uint32_t *buffer; |
1342 SDL_LockMutex(free_buffer_mutex); | 1394 SDL_LockMutex(free_buffer_mutex); |
1343 if (num_buffers) { | 1395 if (num_buffers) { |
1344 buffer = frame_buffers[--num_buffers]; | 1396 buffer = frame_buffers[--num_buffers]; |
1345 } else { | 1397 } else { |
1346 buffer = calloc(512*512, sizeof(uint32_t)); | 1398 buffer = calloc(tex_width*(tex_height + 1), sizeof(uint32_t)); |
1347 } | 1399 } |
1348 SDL_UnlockMutex(free_buffer_mutex); | 1400 SDL_UnlockMutex(free_buffer_mutex); |
1349 locked_pixels = buffer; | 1401 locked_pixels = buffer; |
1350 return buffer; | 1402 return buffer; |
1351 } | 1403 } |
1360 } | 1412 } |
1361 if (which >= num_textures) { | 1413 if (which >= num_textures) { |
1362 warning("Request for invalid framebuffer number %d\n", which); | 1414 warning("Request for invalid framebuffer number %d\n", which); |
1363 return NULL; | 1415 return NULL; |
1364 } | 1416 } |
1365 void *pixels; | 1417 uint8_t *pixels; |
1366 if (SDL_LockTexture(sdl_textures[which], NULL, &pixels, pitch) < 0) { | 1418 if (SDL_LockTexture(sdl_textures[which], NULL, (void **)&pixels, pitch) < 0) { |
1367 warning("Failed to lock texture: %s\n", SDL_GetError()); | 1419 warning("Failed to lock texture: %s\n", SDL_GetError()); |
1368 return NULL; | 1420 return NULL; |
1369 } | 1421 } |
1370 static uint8_t last; | 1422 static uint8_t last; |
1371 if (which <= FRAMEBUFFER_EVEN) { | 1423 if (which <= FRAMEBUFFER_EVEN) { |
1372 locked_pixels = pixels; | 1424 locked_pixels = (uint32_t *)pixels; |
1373 if (which == FRAMEBUFFER_EVEN) { | 1425 if (which == FRAMEBUFFER_EVEN) { |
1374 pixels += *pitch; | 1426 pixels += *pitch; |
1375 } | 1427 } |
1376 locked_pitch = *pitch; | 1428 locked_pitch = *pitch; |
1377 if (which != last) { | 1429 if (which != last) { |
1378 *pitch *= 2; | 1430 *pitch *= 2; |
1379 } | 1431 } |
1380 last = which; | 1432 last = which; |
1381 } | 1433 } |
1382 return pixels; | 1434 return (uint32_t *)pixels; |
1383 #ifndef DISABLE_OPENGL | 1435 #ifndef DISABLE_OPENGL |
1384 } | 1436 } |
1385 #endif | 1437 #endif |
1386 } | 1438 } |
1387 | 1439 |
1406 static uint32_t last_width, last_height; | 1458 static uint32_t last_width, last_height; |
1407 static uint8_t interlaced; | 1459 static uint8_t interlaced; |
1408 static void process_framebuffer(uint32_t *buffer, uint8_t which, int width) | 1460 static void process_framebuffer(uint32_t *buffer, uint8_t which, int width) |
1409 { | 1461 { |
1410 static uint8_t last; | 1462 static uint8_t last; |
1411 if (!render_is_audio_sync() && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) { | 1463 if (sync_src == SYNC_VIDEO && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) { |
1412 source_frame++; | 1464 source_frame++; |
1413 if (source_frame >= source_hz) { | 1465 if (source_frame >= source_hz) { |
1414 source_frame = 0; | 1466 source_frame = 0; |
1415 } | 1467 } |
1416 source_frame_count = frame_repeat[source_frame]; | 1468 source_frame_count = frame_repeat[source_frame]; |
1462 } | 1514 } |
1463 #endif | 1515 #endif |
1464 } | 1516 } |
1465 } else { | 1517 } else { |
1466 #endif | 1518 #endif |
1467 //TODO: Support run_on_audio_thread for render API framebuffers | 1519 //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers |
1468 if (which <= FRAMEBUFFER_EVEN && last != which) { | 1520 if (which <= FRAMEBUFFER_EVEN && last != which) { |
1469 uint8_t *cur_dst = (uint8_t *)locked_pixels; | 1521 uint8_t *cur_dst = (uint8_t *)locked_pixels; |
1470 uint8_t *cur_saved = (uint8_t *)texture_buf; | 1522 uint8_t *cur_saved = (uint8_t *)texture_buf; |
1471 uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch; | 1523 uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch; |
1472 uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0; | 1524 uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0; |
1611 frame frame_queue[4]; | 1663 frame frame_queue[4]; |
1612 int frame_queue_len, frame_queue_read, frame_queue_write; | 1664 int frame_queue_len, frame_queue_read, frame_queue_write; |
1613 | 1665 |
1614 void render_framebuffer_updated(uint8_t which, int width) | 1666 void render_framebuffer_updated(uint8_t which, int width) |
1615 { | 1667 { |
1616 if (run_on_audio_thread) { | 1668 if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) { |
1617 SDL_LockMutex(frame_mutex); | 1669 SDL_LockMutex(frame_mutex); |
1618 while (frame_queue_len == 4) { | 1670 while (frame_queue_len == 4) { |
1619 SDL_CondSignal(frame_ready); | 1671 SDL_CondSignal(frame_ready); |
1620 SDL_UnlockMutex(frame_mutex); | 1672 SDL_UnlockMutex(frame_mutex); |
1621 SDL_Delay(1); | 1673 SDL_Delay(1); |
1649 process_framebuffer(texture_buf, which, width); | 1701 process_framebuffer(texture_buf, which, width); |
1650 } | 1702 } |
1651 | 1703 |
1652 void render_video_loop(void) | 1704 void render_video_loop(void) |
1653 { | 1705 { |
1654 if (!run_on_audio_thread) { | 1706 if (sync_src != SYNC_AUDIO_THREAD && sync_src != SYNC_EXTERNAL) { |
1655 return; | 1707 return; |
1656 } | 1708 } |
1657 SDL_PauseAudio(0); | |
1658 SDL_LockMutex(frame_mutex); | 1709 SDL_LockMutex(frame_mutex); |
1659 for(;;) | 1710 for(;;) |
1660 { | 1711 { |
1661 while (!frame_queue_len) | 1712 while (!frame_queue_len && SDL_GetAudioStatus() == SDL_AUDIO_PLAYING) |
1662 { | 1713 { |
1663 SDL_CondWait(frame_ready, frame_mutex); | 1714 SDL_CondWait(frame_ready, frame_mutex); |
1664 } | 1715 } |
1665 for (int i = 0; i < frame_queue_len; i++) | 1716 while (frame_queue_len) |
1666 { | 1717 { |
1667 frame f = frame_queue[frame_queue_read++]; | 1718 frame f = frame_queue[frame_queue_read++]; |
1668 frame_queue_read &= 0x3; | 1719 frame_queue_read &= 0x3; |
1720 frame_queue_len--; | |
1721 SDL_UnlockMutex(frame_mutex); | |
1669 process_framebuffer(f.buffer, f.which, f.width); | 1722 process_framebuffer(f.buffer, f.which, f.width); |
1670 release_buffer(f.buffer); | 1723 release_buffer(f.buffer); |
1671 } | 1724 SDL_LockMutex(frame_mutex); |
1672 frame_queue_len = 0; | 1725 } |
1726 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING) { | |
1727 break; | |
1728 } | |
1673 } | 1729 } |
1674 | 1730 |
1675 SDL_UnlockMutex(frame_mutex); | 1731 SDL_UnlockMutex(frame_mutex); |
1676 } | 1732 } |
1677 | 1733 |
1697 glBindTexture(GL_TEXTURE_2D, textures[interlaced ? 1 : scanlines ? 2 : 0]); | 1753 glBindTexture(GL_TEXTURE_2D, textures[interlaced ? 1 : scanlines ? 2 : 0]); |
1698 glUniform1i(un_textures[1], 1); | 1754 glUniform1i(un_textures[1], 1); |
1699 | 1755 |
1700 glUniform1f(un_width, render_emulated_width()); | 1756 glUniform1f(un_width, render_emulated_width()); |
1701 glUniform1f(un_height, last_height); | 1757 glUniform1f(un_height, last_height); |
1758 glUniform2f(un_texsize, tex_width, tex_height); | |
1702 | 1759 |
1703 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); | 1760 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); |
1704 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); | 1761 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); |
1705 glEnableVertexAttribArray(at_pos); | 1762 glEnableVertexAttribArray(at_pos); |
1706 | 1763 |
1972 return FRAMEBUFFER_USER_START + i; | 2029 return FRAMEBUFFER_USER_START + i; |
1973 } | 2030 } |
1974 } | 2031 } |
1975 return 0xFF; | 2032 return 0xFF; |
1976 } | 2033 } |
2034 | |
2035 uint8_t render_create_thread(render_thread *thread, const char *name, render_thread_fun fun, void *data) | |
2036 { | |
2037 *thread = SDL_CreateThread(fun, name, data); | |
2038 return *thread != 0; | |
2039 } |