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 }