comparison render_sdl.c @ 2053:3414a4423de1 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 15 Jan 2022 13:15:21 -0800
parents 0757da8ee702
children 46ee354f29bd
comparison
equal deleted inserted replaced
1692:5dacaef602a7 2053:3414a4423de1
11 #include "render_sdl.h" 11 #include "render_sdl.h"
12 #include "blastem.h" 12 #include "blastem.h"
13 #include "genesis.h" 13 #include "genesis.h"
14 #include "bindings.h" 14 #include "bindings.h"
15 #include "util.h" 15 #include "util.h"
16 #include "paths.h"
16 #include "ppm.h" 17 #include "ppm.h"
17 #include "png.h" 18 #include "png.h"
18 #include "config.h" 19 #include "config.h"
19 #include "controller_info.h" 20 #include "controller_info.h"
20 21
43 static uint8_t render_gl = 1; 44 static uint8_t render_gl = 1;
44 static uint8_t scanlines = 0; 45 static uint8_t scanlines = 0;
45 46
46 static uint32_t last_frame = 0; 47 static uint32_t last_frame = 0;
47 48
48 static uint32_t buffer_samples, sample_rate; 49 static SDL_mutex *audio_mutex, *frame_mutex, *free_buffer_mutex;
49 static uint32_t missing_count; 50 static SDL_cond *audio_ready, *frame_ready;
50
51 static SDL_mutex * audio_mutex;
52 static SDL_cond * audio_ready;
53 static uint8_t quitting = 0; 51 static uint8_t quitting = 0;
54 52
55 struct audio_source { 53 enum {
56 SDL_cond *cond; 54 SYNC_AUDIO,
57 int16_t *front; 55 SYNC_AUDIO_THREAD,
58 int16_t *back; 56 SYNC_VIDEO,
59 double dt; 57 SYNC_EXTERNAL
60 uint64_t buffer_fraction;
61 uint64_t buffer_inc;
62 uint32_t buffer_pos;
63 uint32_t read_start;
64 uint32_t read_end;
65 uint32_t lowpass_alpha;
66 uint32_t mask;
67 int16_t last_left;
68 int16_t last_right;
69 uint8_t num_channels;
70 uint8_t front_populated;
71 }; 58 };
72 59
73 static audio_source *audio_sources[8]; 60 static uint8_t sync_src;
74 static audio_source *inactive_audio_sources[8];
75 static uint8_t num_audio_sources;
76 static uint8_t num_inactive_audio_sources;
77 static uint8_t sync_to_audio;
78 static uint32_t min_buffered; 61 static uint32_t min_buffered;
79 62
80 typedef int32_t (*mix_func)(audio_source *audio, void *vstream, int len); 63 uint32_t **frame_buffers;
81 64 uint32_t num_buffers;
82 static int32_t mix_s16(audio_source *audio, void *vstream, int len) 65 uint32_t buffer_storage;
83 { 66
84 int samples = len/(sizeof(int16_t)*2); 67 uint32_t render_min_buffered(void)
85 int16_t *stream = vstream; 68 {
86 int16_t *end = stream + 2*samples; 69 return min_buffered;
87 int16_t *src = audio->front; 70 }
88 uint32_t i = audio->read_start; 71
89 uint32_t i_end = audio->read_end; 72 uint8_t render_is_audio_sync(void)
90 int16_t *cur = stream; 73 {
91 if (audio->num_channels == 1) { 74 return sync_src < SYNC_VIDEO;
92 while (cur < end && i != i_end) 75 }
93 { 76
94 *(cur++) += src[i]; 77 uint8_t render_should_release_on_exit(void)
95 *(cur++) += src[i++]; 78 {
96 i &= audio->mask; 79 return sync_src != SYNC_AUDIO_THREAD;
97 } 80 }
98 } else { 81
99 while (cur < end && i != i_end) 82 void render_buffer_consumed(audio_source *src)
100 { 83 {
101 *(cur++) += src[i++]; 84 SDL_CondSignal(src->opaque);
102 *(cur++) += src[i++]; 85 }
103 i &= audio->mask;
104 }
105 }
106
107 if (cur != end) {
108 printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
109 }
110 if (!sync_to_audio) {
111 audio->read_start = i;
112 }
113 if (cur != end) {
114 //printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
115 return (cur-end)/2;
116 } else {
117 return ((i_end - i) & audio->mask) / audio->num_channels;
118 }
119 }
120
121 static int32_t mix_f32(audio_source *audio, void *vstream, int len)
122 {
123 int samples = len/(sizeof(float)*2);
124 float *stream = vstream;
125 float *end = stream + 2*samples;
126 int16_t *src = audio->front;
127 uint32_t i = audio->read_start;
128 uint32_t i_end = audio->read_end;
129 float *cur = stream;
130 if (audio->num_channels == 1) {
131 while (cur < end && i != i_end)
132 {
133 *(cur++) += ((float)src[i]) / 0x7FFF;
134 *(cur++) += ((float)src[i++]) / 0x7FFF;
135 i &= audio->mask;
136 }
137 } else {
138 while(cur < end && i != i_end)
139 {
140 *(cur++) += ((float)src[i++]) / 0x7FFF;
141 *(cur++) += ((float)src[i++]) / 0x7FFF;
142 i &= audio->mask;
143 }
144 }
145 if (!sync_to_audio) {
146 audio->read_start = i;
147 }
148 if (cur != end) {
149 printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
150 return (cur-end)/2;
151 } else {
152 return ((i_end - i) & audio->mask) / audio->num_channels;
153 }
154 }
155
156 static int32_t mix_null(audio_source *audio, void *vstream, int len)
157 {
158 return 0;
159 }
160
161 static mix_func mix;
162 86
163 static void audio_callback(void * userdata, uint8_t *byte_stream, int len) 87 static void audio_callback(void * userdata, uint8_t *byte_stream, int len)
164 { 88 {
165 uint8_t num_populated;
166 memset(byte_stream, 0, len);
167 SDL_LockMutex(audio_mutex); 89 SDL_LockMutex(audio_mutex);
90 uint8_t all_ready;
168 do { 91 do {
169 num_populated = 0; 92 all_ready = all_sources_ready();
170 for (uint8_t i = 0; i < num_audio_sources; i++) 93 if (!quitting && !all_ready) {
171 {
172 if (audio_sources[i]->front_populated) {
173 num_populated++;
174 }
175 }
176 if (!quitting && num_populated < num_audio_sources) {
177 fflush(stdout);
178 SDL_CondWait(audio_ready, audio_mutex); 94 SDL_CondWait(audio_ready, audio_mutex);
179 } 95 }
180 } while(!quitting && num_populated < num_audio_sources); 96 } while(!quitting && !all_ready);
181 if (!quitting) { 97 if (!quitting) {
182 for (uint8_t i = 0; i < num_audio_sources; i++) 98 mix_and_convert(byte_stream, len, NULL);
183 {
184 mix(audio_sources[i], byte_stream, len);
185 audio_sources[i]->front_populated = 0;
186 SDL_CondSignal(audio_sources[i]->cond);
187 }
188 } 99 }
189 SDL_UnlockMutex(audio_mutex); 100 SDL_UnlockMutex(audio_mutex);
190 } 101 }
191 102
192 #define NO_LAST_BUFFERED -2000000000 103 #define NO_LAST_BUFFERED -2000000000
197 static float max_adjust; 108 static float max_adjust;
198 static int32_t cur_min_buffered; 109 static int32_t cur_min_buffered;
199 static uint32_t min_remaining_buffer; 110 static uint32_t min_remaining_buffer;
200 static void audio_callback_drc(void *userData, uint8_t *byte_stream, int len) 111 static void audio_callback_drc(void *userData, uint8_t *byte_stream, int len)
201 { 112 {
202 memset(byte_stream, 0, len);
203 if (cur_min_buffered < 0) { 113 if (cur_min_buffered < 0) {
204 //underflow last frame, but main thread hasn't gotten a chance to call SDL_PauseAudio yet 114 //underflow last frame, but main thread hasn't gotten a chance to call SDL_PauseAudio yet
205 return; 115 return;
206 } 116 }
207 cur_min_buffered = 0x7FFFFFFF; 117 cur_min_buffered = mix_and_convert(byte_stream, len, &min_remaining_buffer);
208 min_remaining_buffer = 0xFFFFFFFF; 118 }
209 for (uint8_t i = 0; i < num_audio_sources; i++) 119
210 { 120 static void audio_callback_run_on_audio(void *user_data, uint8_t *byte_stream, int len)
211 121 {
212 int32_t buffered = mix(audio_sources[i], byte_stream, len); 122 if (current_system) {
213 cur_min_buffered = buffered < cur_min_buffered ? buffered : cur_min_buffered; 123 current_system->resume_context(current_system);
214 uint32_t remaining = (audio_sources[i]->mask + 1)/audio_sources[i]->num_channels - buffered; 124 }
215 min_remaining_buffer = remaining < min_remaining_buffer ? remaining : min_remaining_buffer; 125 mix_and_convert(byte_stream, len, NULL);
216 } 126 }
217 } 127
218 128 void render_lock_audio()
219 static void lock_audio() 129 {
220 { 130 if (sync_src == SYNC_AUDIO) {
221 if (sync_to_audio) {
222 SDL_LockMutex(audio_mutex); 131 SDL_LockMutex(audio_mutex);
223 } else { 132 } else {
224 SDL_LockAudio(); 133 SDL_LockAudio();
225 } 134 }
226 } 135 }
227 136
228 static void unlock_audio() 137 void render_unlock_audio()
229 { 138 {
230 if (sync_to_audio) { 139 if (sync_src == SYNC_AUDIO) {
231 SDL_UnlockMutex(audio_mutex); 140 SDL_UnlockMutex(audio_mutex);
232 } else { 141 } else {
233 SDL_UnlockAudio(); 142 SDL_UnlockAudio();
234 } 143 }
235 } 144 }
239 SDL_LockMutex(audio_mutex); 148 SDL_LockMutex(audio_mutex);
240 quitting = 1; 149 quitting = 1;
241 SDL_CondSignal(audio_ready); 150 SDL_CondSignal(audio_ready);
242 SDL_UnlockMutex(audio_mutex); 151 SDL_UnlockMutex(audio_mutex);
243 SDL_CloseAudio(); 152 SDL_CloseAudio();
244 } 153 /*
245 154 FIXME: move this to render_audio.c
246 #define BUFFER_INC_RES 0x40000000UL 155 if (mix_buf) {
247 156 free(mix_buf);
248 void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider) 157 mix_buf = NULL;
249 { 158 }
250 src->buffer_inc = ((BUFFER_INC_RES * (uint64_t)sample_rate) / master_clock) * sample_divider; 159 */
251 } 160 }
252 161
253 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels) 162 void *render_new_audio_opaque(void)
254 { 163 {
255 audio_source *ret = NULL; 164 return SDL_CreateCond();
256 uint32_t alloc_size = sync_to_audio ? channels * buffer_samples : nearest_pow2(min_buffered * 4 * channels); 165 }
257 lock_audio(); 166
258 if (num_audio_sources < 8) { 167 void render_free_audio_opaque(void *opaque)
259 ret = malloc(sizeof(audio_source)); 168 {
260 ret->back = malloc(alloc_size * sizeof(int16_t)); 169 SDL_DestroyCond(opaque);
261 ret->front = sync_to_audio ? malloc(alloc_size * sizeof(int16_t)) : ret->back; 170 }
262 ret->front_populated = 0; 171
263 ret->cond = SDL_CreateCond(); 172 void render_audio_created(audio_source *source)
264 ret->num_channels = channels; 173 {
265 audio_sources[num_audio_sources++] = ret; 174 if (sync_src == SYNC_AUDIO) {
266 } 175 //SDL_PauseAudio acquires the audio device lock, which is held while the callback runs
267 unlock_audio(); 176 //since our callback can itself be stuck waiting on the audio_ready condition variable
268 if (!ret) { 177 //calling SDL_PauseAudio(0) again for audio sources after the first can deadlock
269 fatal_error("Too many audio sources!"); 178 //fortunately SDL_GetAudioStatus does not acquire the lock so is safe to call here
270 } else { 179 if (SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
271 render_audio_adjust_clock(ret, master_clock, sample_divider); 180 SDL_PauseAudio(0);
272 double lowpass_cutoff = get_lowpass_cutoff(config); 181 }
273 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI); 182 }
274 ret->dt = 1.0 / ((double)master_clock / (double)(sample_divider)); 183 if (current_system && sync_src == SYNC_AUDIO_THREAD) {
275 double alpha = ret->dt / (ret->dt + rc); 184 system_request_exit(current_system, 0);
276 ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha); 185 }
277 ret->buffer_pos = 0; 186 }
278 ret->buffer_fraction = 0; 187
279 ret->last_left = ret->last_right = 0; 188 void render_source_paused(audio_source *src, uint8_t remaining_sources)
280 ret->read_start = 0; 189 {
281 ret->read_end = sync_to_audio ? buffer_samples * channels : 0; 190 if (sync_src == SYNC_AUDIO) {
282 ret->mask = sync_to_audio ? 0xFFFFFFFF : alloc_size-1; 191 SDL_CondSignal(audio_ready);
283 } 192 }
284 if (sync_to_audio && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) { 193 if (!remaining_sources && render_is_audio_sync()) {
285 SDL_PauseAudio(0);
286 }
287 return ret;
288 }
289
290 void render_pause_source(audio_source *src)
291 {
292 uint8_t need_pause = 0;
293 lock_audio();
294 for (uint8_t i = 0; i < num_audio_sources; i++)
295 {
296 if (audio_sources[i] == src) {
297 audio_sources[i] = audio_sources[--num_audio_sources];
298 if (sync_to_audio) {
299 SDL_CondSignal(audio_ready);
300 }
301 break;
302 }
303 }
304 if (!num_audio_sources) {
305 need_pause = 1;
306 }
307 unlock_audio();
308 if (need_pause) {
309 SDL_PauseAudio(1); 194 SDL_PauseAudio(1);
310 } 195 if (sync_src == SYNC_AUDIO_THREAD) {
311 inactive_audio_sources[num_inactive_audio_sources++] = src; 196 SDL_CondSignal(frame_ready);
312 } 197 }
313 198 }
314 void render_resume_source(audio_source *src) 199 }
315 { 200
316 lock_audio(); 201 void render_source_resumed(audio_source *src)
317 if (num_audio_sources < 8) { 202 {
318 audio_sources[num_audio_sources++] = src; 203 if (sync_src == SYNC_AUDIO) {
319 } 204 //SDL_PauseAudio acquires the audio device lock, which is held while the callback runs
320 unlock_audio(); 205 //since our callback can itself be stuck waiting on the audio_ready condition variable
321 for (uint8_t i = 0; i < num_inactive_audio_sources; i++) 206 //calling SDL_PauseAudio(0) again for audio sources after the first can deadlock
322 { 207 //fortunately SDL_GetAudioStatus does not acquire the lock so is safe to call here
323 if (inactive_audio_sources[i] == src) { 208 if (SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
324 inactive_audio_sources[i] = inactive_audio_sources[--num_inactive_audio_sources]; 209 SDL_PauseAudio(0);
325 } 210 }
326 } 211 }
327 if (sync_to_audio) { 212 if (current_system && sync_src == SYNC_AUDIO_THREAD) {
328 SDL_PauseAudio(0); 213 system_request_exit(current_system, 0);
329 } 214 }
330 } 215 }
331 216
332 void render_free_source(audio_source *src) 217 void render_do_audio_ready(audio_source *src)
333 { 218 {
334 render_pause_source(src); 219 if (sync_src == SYNC_AUDIO_THREAD) {
335 220 int16_t *tmp = src->front;
336 free(src->front); 221 src->front = src->back;
337 if (sync_to_audio) { 222 src->back = tmp;
338 free(src->back); 223 src->front_populated = 1;
339 SDL_DestroyCond(src->cond); 224 src->buffer_pos = 0;
340 } 225 if (all_sources_ready()) {
341 free(src); 226 //we've emulated far enough to fill the current buffer
342 } 227 system_request_exit(current_system, 0);
343 static uint32_t sync_samples; 228 }
344 static void do_audio_ready(audio_source *src) 229 } else if (sync_src == SYNC_AUDIO) {
345 {
346 if (sync_to_audio) {
347 SDL_LockMutex(audio_mutex); 230 SDL_LockMutex(audio_mutex);
348 while (src->front_populated) { 231 while (src->front_populated) {
349 SDL_CondWait(src->cond, audio_mutex); 232 SDL_CondWait(src->opaque, audio_mutex);
350 } 233 }
351 int16_t *tmp = src->front; 234 int16_t *tmp = src->front;
352 src->front = src->back; 235 src->front = src->back;
353 src->back = tmp; 236 src->back = tmp;
354 src->front_populated = 1; 237 src->front_populated = 1;
365 SDL_PauseAudio(0); 248 SDL_PauseAudio(0);
366 } 249 }
367 } 250 }
368 } 251 }
369 252
370 static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
371 {
372 int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
373 current = tmp >> 16;
374 return current;
375 }
376
377 static void interp_sample(audio_source *src, int16_t last, int16_t current)
378 {
379 int64_t tmp = last * ((src->buffer_fraction << 16) / src->buffer_inc);
380 tmp += current * (0x10000 - ((src->buffer_fraction << 16) / src->buffer_inc));
381 src->back[src->buffer_pos++] = tmp >> 16;
382 }
383
384 void render_put_mono_sample(audio_source *src, int16_t value)
385 {
386 value = lowpass_sample(src, src->last_left, value);
387 src->buffer_fraction += src->buffer_inc;
388 uint32_t base = sync_to_audio ? 0 : src->read_end;
389 while (src->buffer_fraction > BUFFER_INC_RES)
390 {
391 src->buffer_fraction -= BUFFER_INC_RES;
392 interp_sample(src, src->last_left, value);
393
394 if (((src->buffer_pos - base) & src->mask) >= sync_samples) {
395 do_audio_ready(src);
396 }
397 src->buffer_pos &= src->mask;
398 }
399 src->last_left = value;
400 }
401
402 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
403 {
404 left = lowpass_sample(src, src->last_left, left);
405 right = lowpass_sample(src, src->last_right, right);
406 src->buffer_fraction += src->buffer_inc;
407 uint32_t base = sync_to_audio ? 0 : src->read_end;
408 while (src->buffer_fraction > BUFFER_INC_RES)
409 {
410 src->buffer_fraction -= BUFFER_INC_RES;
411
412 interp_sample(src, src->last_left, left);
413 interp_sample(src, src->last_right, right);
414
415 if (((src->buffer_pos - base) & src->mask)/2 >= sync_samples) {
416 do_audio_ready(src);
417 }
418 src->buffer_pos &= src->mask;
419 }
420 src->last_left = left;
421 src->last_right = right;
422 }
423
424 static SDL_Joystick * joysticks[MAX_JOYSTICKS]; 253 static SDL_Joystick * joysticks[MAX_JOYSTICKS];
425 static int joystick_sdl_index[MAX_JOYSTICKS]; 254 static int joystick_sdl_index[MAX_JOYSTICKS];
255 static uint8_t joystick_index_locked[MAX_JOYSTICKS];
426 256
427 int render_width() 257 int render_width()
428 { 258 {
429 return main_width; 259 return main_width;
430 } 260 }
446 #else 276 #else
447 return 255 << 24 | r << 16 | g << 8 | b; 277 return 255 << 24 | r << 16 | g << 8 | b;
448 #endif 278 #endif
449 } 279 }
450 280
281 static uint8_t external_sync;
282 void render_set_external_sync(uint8_t ext_sync_on)
283 {
284 if (ext_sync_on != external_sync) {
285 external_sync = ext_sync_on;
286 if (windowed_width) {
287 //only do this if render_init has already been called
288 render_config_updated();
289 }
290 }
291 }
292
451 #ifndef DISABLE_OPENGL 293 #ifndef DISABLE_OPENGL
452 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, at_pos; 294 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, un_texsize, at_pos;
295 static int tex_width, tex_height;
453 296
454 static GLfloat vertex_data_default[] = { 297 static GLfloat vertex_data_default[] = {
455 -1.0f, -1.0f, 298 -1.0f, -1.0f,
456 1.0f, -1.0f, 299 1.0f, -1.0f,
457 -1.0f, 1.0f, 300 -1.0f, 1.0f,
472 "#define highp\n"; 315 "#define highp\n";
473 #endif 316 #endif
474 317
475 static GLuint load_shader(char * fname, GLenum shader_type) 318 static GLuint load_shader(char * fname, GLenum shader_type)
476 { 319 {
320 char * shader_path;
321 FILE *f;
322 GLchar *text;
323 long fsize;
324 #ifndef __ANDROID__
477 char const * parts[] = {get_home_dir(), "/.config/blastem/shaders/", fname}; 325 char const * parts[] = {get_home_dir(), "/.config/blastem/shaders/", fname};
478 char * shader_path = alloc_concat_m(3, parts); 326 shader_path = alloc_concat_m(3, parts);
479 FILE * f = fopen(shader_path, "rb"); 327 f = fopen(shader_path, "rb");
480 free(shader_path); 328 free(shader_path);
481 if (!f) { 329 if (f) {
482 parts[0] = get_exe_dir(); 330 fsize = file_size(f);
483 parts[1] = "/shaders/"; 331 text = malloc(fsize);
484 shader_path = alloc_concat_m(3, parts); 332 if (fread(text, 1, fsize, f) != fsize) {
485 f = fopen(shader_path, "rb"); 333 warning("Error reading from shader file %s\n", fname);
334 free(text);
335 return 0;
336 }
337 } else {
338 #endif
339 shader_path = path_append("shaders", fname);
340 uint32_t fsize32;
341 text = read_bundled_file(shader_path, &fsize32);
486 free(shader_path); 342 free(shader_path);
487 if (!f) { 343 if (!text) {
488 warning("Failed to open shader file %s for reading\n", fname); 344 warning("Failed to open shader file %s for reading\n", fname);
489 return 0; 345 return 0;
490 } 346 }
491 } 347 fsize = fsize32;
492 long fsize = file_size(f); 348 #ifndef __ANDROID__
493 GLchar * text = malloc(fsize); 349 }
494 if (fread(text, 1, fsize, f) != fsize) { 350 #endif
495 warning("Error reading from shader file %s\n", fname); 351 text[fsize] = 0;
496 free(text); 352
497 return 0;
498 }
499 if (strncmp(text, "#version", strlen("#version"))) { 353 if (strncmp(text, "#version", strlen("#version"))) {
500 GLchar *tmp = text; 354 GLchar *tmp = text;
501 text = alloc_concat(shader_prefix, tmp); 355 text = alloc_concat(shader_prefix, tmp);
502 free(tmp); 356 free(tmp);
503 fsize += strlen(shader_prefix); 357 fsize += strlen(shader_prefix);
504 } 358 }
505 GLuint ret = glCreateShader(shader_type); 359 GLuint ret = glCreateShader(shader_type);
360 if (!ret) {
361 warning("glCreateShader failed with error %d\n", glGetError());
362 return 0;
363 }
506 glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize); 364 glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize);
507 free(text); 365 free(text);
508 glCompileShader(ret); 366 glCompileShader(ret);
509 GLint compile_status, loglen; 367 GLint compile_status, loglen;
510 glGetShaderiv(ret, GL_COMPILE_STATUS, &compile_status); 368 glGetShaderiv(ret, GL_COMPILE_STATUS, &compile_status);
520 return ret; 378 return ret;
521 } 379 }
522 #endif 380 #endif
523 381
524 static uint32_t texture_buf[512 * 513]; 382 static uint32_t texture_buf[512 * 513];
525 #ifndef DISABLE_OPENGL 383 #ifdef DISABLE_OPENGL
384 #define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888
385 #else
526 #ifdef USE_GLES 386 #ifdef USE_GLES
527 #define INTERNAL_FORMAT GL_RGBA 387 #define INTERNAL_FORMAT GL_RGBA
528 #define SRC_FORMAT GL_RGBA 388 #define SRC_FORMAT GL_RGBA
529 #define RENDER_FORMAT SDL_PIXELFORMAT_ABGR8888 389 #define RENDER_FORMAT SDL_PIXELFORMAT_ABGR8888
530 #else 390 #else
536 { 396 {
537 tern_val def = {.ptrval = "linear"}; 397 tern_val def = {.ptrval = "linear"};
538 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; 398 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval;
539 GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR; 399 GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR;
540 glGenTextures(3, textures); 400 glGenTextures(3, textures);
401 def.ptrval = "off";
402 char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", def, TVAL_PTR).ptrval;
403 if (!strcmp(npot_textures, "on")) {
404 tex_width = LINEBUF_SIZE;
405 tex_height = 294; //PAL height with full borders
406 } else {
407 tex_width = tex_height = 512;
408 }
409 debug_message("Using %dx%d textures\n", tex_width, tex_height);
541 for (int i = 0; i < 3; i++) 410 for (int i = 0; i < 3; i++)
542 { 411 {
543 glBindTexture(GL_TEXTURE_2D, textures[i]); 412 glBindTexture(GL_TEXTURE_2D, textures[i]);
544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); 413 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
545 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); 414 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
546 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
547 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
548 if (i < 2) { 417 if (i < 2) {
549 //TODO: Fixme for PAL + invalid display mode 418 //TODO: Fixme for PAL + invalid display mode
550 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 512, 512, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf); 419 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, tex_width, tex_height, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf);
551 } else { 420 } else {
552 uint32_t blank = 255 << 24; 421 uint32_t blank = 255 << 24;
553 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, &blank); 422 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, &blank);
554 } 423 }
555 } 424 }
574 } 443 }
575 un_textures[0] = glGetUniformLocation(program, "textures[0]"); 444 un_textures[0] = glGetUniformLocation(program, "textures[0]");
576 un_textures[1] = glGetUniformLocation(program, "textures[1]"); 445 un_textures[1] = glGetUniformLocation(program, "textures[1]");
577 un_width = glGetUniformLocation(program, "width"); 446 un_width = glGetUniformLocation(program, "width");
578 un_height = glGetUniformLocation(program, "height"); 447 un_height = glGetUniformLocation(program, "height");
448 un_texsize = glGetUniformLocation(program, "texsize");
579 at_pos = glGetAttribLocation(program, "pos"); 449 at_pos = glGetAttribLocation(program, "pos");
580 } 450 }
581 451
582 static void gl_teardown() 452 static void gl_teardown()
583 { 453 {
593 static void render_alloc_surfaces() 463 static void render_alloc_surfaces()
594 { 464 {
595 if (texture_init) { 465 if (texture_init) {
596 return; 466 return;
597 } 467 }
598 sdl_textures= malloc(sizeof(SDL_Texture *) * 2); 468 sdl_textures= calloc(sizeof(SDL_Texture *), 3);
599 num_textures = 2; 469 num_textures = 3;
600 texture_init = 1; 470 texture_init = 1;
601 #ifndef DISABLE_OPENGL 471 #ifndef DISABLE_OPENGL
602 if (render_gl) { 472 if (render_gl) {
603 sdl_textures[0] = sdl_textures[1] = NULL;
604 gl_setup(); 473 gl_setup();
605 } else { 474 } else {
606 #endif 475 #endif
607 tern_val def = {.ptrval = "linear"}; 476 tern_val def = {.ptrval = "linear"};
608 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; 477 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval;
665 } 534 }
666 535
667 static void update_aspect() 536 static void update_aspect()
668 { 537 {
669 //reset default values 538 //reset default values
539 #ifndef DISABLE_OPENGL
670 memcpy(vertex_data, vertex_data_default, sizeof(vertex_data)); 540 memcpy(vertex_data, vertex_data_default, sizeof(vertex_data));
541 #endif
671 main_clip.w = main_width; 542 main_clip.w = main_width;
672 main_clip.h = main_height; 543 main_clip.h = main_height;
673 main_clip.x = main_clip.y = 0; 544 main_clip.x = main_clip.y = 0;
674 if (config_aspect() > 0.0f) { 545 if (config_aspect() > 0.0f) {
675 float aspect = (float)main_width / main_height; 546 float aspect = (float)main_width / main_height;
697 } 568 }
698 #endif 569 #endif
699 } 570 }
700 } 571 }
701 572
702 static ui_render_fun on_context_destroyed, on_context_created; 573 static ui_render_fun on_context_destroyed, on_context_created, on_ui_fb_resized;
703 void render_set_gl_context_handlers(ui_render_fun destroy, ui_render_fun create) 574 void render_set_gl_context_handlers(ui_render_fun destroy, ui_render_fun create)
704 { 575 {
705 on_context_destroyed = destroy; 576 on_context_destroyed = destroy;
706 on_context_created = create; 577 on_context_created = create;
578 }
579
580 void render_set_ui_fb_resize_handler(ui_render_fun resize)
581 {
582 on_ui_fb_resized = resize;
707 } 583 }
708 584
709 static uint8_t scancode_map[SDL_NUM_SCANCODES] = { 585 static uint8_t scancode_map[SDL_NUM_SCANCODES] = {
710 [SDL_SCANCODE_A] = 0x1C, 586 [SDL_SCANCODE_A] = 0x1C,
711 [SDL_SCANCODE_B] = 0x32, 587 [SDL_SCANCODE_B] = 0x32,
840 } 716 }
841 } 717 }
842 return -1; 718 return -1;
843 } 719 }
844 720
721 static int lowest_unlocked_joystick_index(void)
722 {
723 for (int i = 0; i < MAX_JOYSTICKS; i++) {
724 if (!joystick_index_locked[i]) {
725 return i;
726 }
727 }
728 return -1;
729 }
730
845 SDL_Joystick *render_get_joystick(int index) 731 SDL_Joystick *render_get_joystick(int index)
846 { 732 {
847 if (index >= MAX_JOYSTICKS) { 733 if (index >= MAX_JOYSTICKS) {
848 return NULL; 734 return NULL;
849 } 735 }
861 return guid_string; 747 return guid_string;
862 } 748 }
863 749
864 SDL_GameController *render_get_controller(int index) 750 SDL_GameController *render_get_controller(int index)
865 { 751 {
866 if (index >= MAX_JOYSTICKS) { 752 if (index >= MAX_JOYSTICKS || !joysticks[index]) {
867 return NULL; 753 return NULL;
868 } 754 }
869 return SDL_GameControllerOpen(joystick_sdl_index[index]); 755 return SDL_GameControllerOpen(joystick_sdl_index[index]);
756 }
757
758 static uint8_t gc_events_enabled;
759 static SDL_GameController *controllers[MAX_JOYSTICKS];
760 void render_enable_gamepad_events(uint8_t enabled)
761 {
762 if (enabled != gc_events_enabled) {
763 gc_events_enabled = enabled;
764 for (int i = 0; i < MAX_JOYSTICKS; i++) {
765 if (enabled) {
766 controllers[i] = render_get_controller(i);
767 } else if (controllers[i]) {
768 SDL_GameControllerClose(controllers[i]);
769 controllers[i] = NULL;
770 }
771 }
772 }
870 } 773 }
871 774
872 static uint32_t overscan_top[NUM_VID_STD] = {2, 21}; 775 static uint32_t overscan_top[NUM_VID_STD] = {2, 21};
873 static uint32_t overscan_bot[NUM_VID_STD] = {1, 17}; 776 static uint32_t overscan_bot[NUM_VID_STD] = {1, 17};
874 static uint32_t overscan_left[NUM_VID_STD] = {13, 13}; 777 static uint32_t overscan_left[NUM_VID_STD] = {13, 13};
875 static uint32_t overscan_right[NUM_VID_STD] = {14, 14}; 778 static uint32_t overscan_right[NUM_VID_STD] = {14, 14};
876 static vid_std video_standard = VID_NTSC; 779 static vid_std video_standard = VID_NTSC;
780 static uint8_t need_ui_fb_resize;
781
782 int lock_joystick_index(int joystick, int desired_index)
783 {
784 if (desired_index < 0) {
785 desired_index = lowest_unlocked_joystick_index();
786 if (desired_index < 0 || desired_index >= joystick) {
787 return joystick;
788 }
789 }
790 SDL_Joystick *tmp_joy = joysticks[joystick];
791 int tmp_index = joystick_sdl_index[joystick];
792 joysticks[joystick] = joysticks[desired_index];
793 joystick_sdl_index[joystick] = joystick_sdl_index[desired_index];
794 joystick_index_locked[joystick] = joystick_sdl_index[desired_index];
795 joysticks[desired_index] = tmp_joy;
796 joystick_sdl_index[desired_index] = tmp_index;
797 joystick_index_locked[desired_index] = 1;
798 //update bindings as the controllers being swapped may have different mappings
799 handle_joy_added(desired_index);
800 if (joysticks[joystick]) {
801 handle_joy_added(joystick);
802 }
803 return desired_index;
804 }
877 805
878 static int32_t handle_event(SDL_Event *event) 806 static int32_t handle_event(SDL_Event *event)
879 { 807 {
880 if (custom_event_handler) { 808 if (custom_event_handler) {
881 custom_event_handler(event); 809 custom_event_handler(event);
889 break; 817 break;
890 case SDL_JOYBUTTONDOWN: 818 case SDL_JOYBUTTONDOWN:
891 handle_joydown(find_joystick_index(event->jbutton.which), event->jbutton.button); 819 handle_joydown(find_joystick_index(event->jbutton.which), event->jbutton.button);
892 break; 820 break;
893 case SDL_JOYBUTTONUP: 821 case SDL_JOYBUTTONUP:
894 handle_joyup(find_joystick_index(event->jbutton.which), event->jbutton.button); 822 handle_joyup(lock_joystick_index(find_joystick_index(event->jbutton.which), -1), event->jbutton.button);
895 break; 823 break;
896 case SDL_JOYHATMOTION: 824 case SDL_JOYHATMOTION:
897 handle_joy_dpad(find_joystick_index(event->jhat.which), event->jhat.hat, event->jhat.value); 825 handle_joy_dpad(lock_joystick_index(find_joystick_index(event->jhat.which), -1), event->jhat.hat, event->jhat.value);
898 break; 826 break;
899 case SDL_JOYAXISMOTION: 827 case SDL_JOYAXISMOTION:
900 handle_joy_axis(find_joystick_index(event->jaxis.which), event->jaxis.axis, event->jaxis.value); 828 handle_joy_axis(lock_joystick_index(find_joystick_index(event->jaxis.which), -1), event->jaxis.axis, event->jaxis.value);
901 break; 829 break;
902 case SDL_JOYDEVICEADDED: 830 case SDL_JOYDEVICEADDED:
903 if (event->jdevice.which < MAX_JOYSTICKS) { 831 if (event->jdevice.which < MAX_JOYSTICKS) {
904 int index = lowest_unused_joystick_index(); 832 int index = lowest_unused_joystick_index();
905 if (index >= 0) { 833 if (index >= 0) {
906 SDL_Joystick * joy = joysticks[index] = SDL_JoystickOpen(event->jdevice.which); 834 SDL_Joystick * joy = joysticks[index] = SDL_JoystickOpen(event->jdevice.which);
907 joystick_sdl_index[index] = event->jdevice.which; 835 joystick_sdl_index[index] = event->jdevice.which;
836 joystick_index_locked[index] = 0;
837 if (gc_events_enabled) {
838 controllers[index] = SDL_GameControllerOpen(event->jdevice.which);
839 }
908 if (joy) { 840 if (joy) {
909 printf("Joystick %d added: %s\n", index, SDL_JoystickName(joy)); 841 debug_message("Joystick %d added: %s\n", index, SDL_JoystickName(joy));
910 printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); 842 debug_message("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy));
911 handle_joy_added(index); 843 handle_joy_added(index);
912 } 844 }
913 } 845 }
914 } 846 }
915 break; 847 break;
916 case SDL_JOYDEVICEREMOVED: { 848 case SDL_JOYDEVICEREMOVED: {
917 int index = find_joystick_index(event->jdevice.which); 849 int index = find_joystick_index(event->jdevice.which);
918 if (index >= 0) { 850 if (index >= 0) {
919 SDL_JoystickClose(joysticks[index]); 851 SDL_JoystickClose(joysticks[index]);
920 joysticks[index] = NULL; 852 joysticks[index] = NULL;
921 printf("Joystick %d removed\n", index); 853 if (controllers[index]) {
854 SDL_GameControllerClose(controllers[index]);
855 controllers[index] = NULL;
856 }
857 debug_message("Joystick %d removed\n", index);
922 } else { 858 } else {
923 printf("Failed to find removed joystick with instance ID: %d\n", index); 859 debug_message("Failed to find removed joystick with instance ID: %d\n", index);
924 } 860 }
925 break; 861 break;
926 } 862 }
927 case SDL_MOUSEMOTION: 863 case SDL_MOUSEMOTION:
928 handle_mouse_moved(event->motion.which, event->motion.x, event->motion.y + overscan_top[video_standard], event->motion.xrel, event->motion.yrel); 864 handle_mouse_moved(event->motion.which, event->motion.x, event->motion.y + overscan_top[video_standard], event->motion.xrel, event->motion.yrel);
935 break; 871 break;
936 case SDL_WINDOWEVENT: 872 case SDL_WINDOWEVENT:
937 switch (event->window.event) 873 switch (event->window.event)
938 { 874 {
939 case SDL_WINDOWEVENT_SIZE_CHANGED: 875 case SDL_WINDOWEVENT_SIZE_CHANGED:
876 if (!main_window) {
877 break;
878 }
940 main_width = event->window.data1; 879 main_width = event->window.data1;
941 main_height = event->window.data2; 880 main_height = event->window.data2;
881 need_ui_fb_resize = 1;
942 update_aspect(); 882 update_aspect();
943 #ifndef DISABLE_OPENGL 883 #ifndef DISABLE_OPENGL
944 if (render_gl) { 884 if (render_gl) {
945 if (on_context_destroyed) { 885 if (on_context_destroyed) {
946 on_context_destroyed(); 886 on_context_destroyed();
954 } 894 }
955 } 895 }
956 #endif 896 #endif
957 break; 897 break;
958 case SDL_WINDOWEVENT_CLOSE: 898 case SDL_WINDOWEVENT_CLOSE:
959 if (SDL_GetWindowID(main_window) == event->window.windowID) { 899 if (main_window && SDL_GetWindowID(main_window) == event->window.windowID) {
960 exit(0); 900 exit(0);
961 } else { 901 } else {
962 for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++) 902 for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++)
963 { 903 {
964 if (SDL_GetWindowID(extra_windows[i]) == event->window.windowID) { 904 if (SDL_GetWindowID(extra_windows[i]) == event->window.windowID) {
999 static int source_hz; 939 static int source_hz;
1000 static int source_frame; 940 static int source_frame;
1001 static int source_frame_count; 941 static int source_frame_count;
1002 static int frame_repeat[60]; 942 static int frame_repeat[60];
1003 943
944 static uint32_t sample_rate;
1004 static void init_audio() 945 static void init_audio()
1005 { 946 {
1006 SDL_AudioSpec desired, actual; 947 SDL_AudioSpec desired, actual;
1007 char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval; 948 char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval;
1008 int rate = rate_str ? atoi(rate_str) : 0; 949 int rate = rate_str ? atoi(rate_str) : 0;
1009 if (!rate) { 950 if (!rate) {
1010 rate = 48000; 951 rate = 48000;
1011 } 952 }
1012 desired.freq = rate; 953 desired.freq = rate;
1013 desired.format = AUDIO_S16SYS; 954 char *config_format = tern_find_path_default(config, "audio\0format\0", (tern_val){.ptrval="f32"}, TVAL_PTR).ptrval;
955 desired.format = !strcmp(config_format, "s16") ? AUDIO_S16SYS : AUDIO_F32SYS;
1014 desired.channels = 2; 956 desired.channels = 2;
1015 char * samples_str = tern_find_path(config, "audio\0buffer\0", TVAL_PTR).ptrval; 957 char * samples_str = tern_find_path(config, "audio\0buffer\0", TVAL_PTR).ptrval;
1016 int samples = samples_str ? atoi(samples_str) : 0; 958 int samples = samples_str ? atoi(samples_str) : 0;
1017 if (!samples) { 959 if (!samples) {
1018 samples = 512; 960 samples = 512;
1019 } 961 }
1020 printf("config says: %d\n", samples); 962 debug_message("config says: %d\n", samples);
1021 desired.samples = samples*2; 963 desired.samples = samples*2;
1022 desired.callback = sync_to_audio ? audio_callback : audio_callback_drc; 964 switch (sync_src)
965 {
966 case SYNC_AUDIO:
967 desired.callback = audio_callback;
968 break;
969 case SYNC_AUDIO_THREAD:
970 desired.callback = audio_callback_run_on_audio;
971 break;
972 default:
973 desired.callback = audio_callback_drc;
974 }
1023 desired.userdata = NULL; 975 desired.userdata = NULL;
1024 976
1025 if (SDL_OpenAudio(&desired, &actual) < 0) { 977 if (SDL_OpenAudio(&desired, &actual) < 0) {
1026 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); 978 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError());
1027 } 979 }
1028 buffer_samples = actual.samples;
1029 sample_rate = actual.freq; 980 sample_rate = actual.freq;
1030 printf("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples); 981 debug_message("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples);
982 render_audio_format format = RENDER_AUDIO_UNKNOWN;
1031 if (actual.format == AUDIO_S16SYS) { 983 if (actual.format == AUDIO_S16SYS) {
1032 puts("signed 16-bit int format"); 984 debug_message("signed 16-bit int format\n");
1033 mix = mix_s16; 985 format = RENDER_AUDIO_S16;
1034 } else if (actual.format == AUDIO_F32SYS) { 986 } else if (actual.format == AUDIO_F32SYS) {
1035 puts("32-bit float format"); 987 debug_message("32-bit float format\n");
1036 mix = mix_f32; 988 format = RENDER_AUDIO_FLOAT;
1037 } else { 989 } else {
1038 printf("unsupported format %X\n", actual.format); 990 debug_message("unsupported format %X\n", actual.format);
1039 warning("Unsupported audio sample format: %X\n", actual.format); 991 warning("Unsupported audio sample format: %X\n", actual.format);
1040 mix = mix_null; 992 }
1041 } 993 render_audio_initialized(format, actual.freq, actual.channels, actual.samples, SDL_AUDIO_BITSIZE(actual.format) / 8);
1042 } 994 }
1043 995
1044 void window_setup(void) 996 void window_setup(void)
1045 { 997 {
1046 uint32_t flags = SDL_WINDOW_RESIZABLE; 998 uint32_t flags = SDL_WINDOW_RESIZABLE;
1047 if (is_fullscreen) { 999 if (is_fullscreen) {
1048 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; 1000 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
1049 } 1001 }
1050 1002
1051 tern_val def = {.ptrval = "audio"}; 1003 tern_val def = {.ptrval = "audio"};
1052 char *sync_src = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval; 1004 if (external_sync) {
1053 sync_to_audio = !strcmp(sync_src, "audio"); 1005 sync_src = SYNC_EXTERNAL;
1006 } else {
1007 char *sync_src_str = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval;
1008 if (!strcmp(sync_src_str, "audio")) {
1009 sync_src = SYNC_AUDIO;
1010 } else if (!strcmp(sync_src_str, "audio_thread")) {
1011 sync_src = SYNC_AUDIO_THREAD;
1012 } else {
1013 sync_src = SYNC_VIDEO;
1014 }
1015 }
1016
1017 if (!num_buffers && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) {
1018 frame_mutex = SDL_CreateMutex();
1019 free_buffer_mutex = SDL_CreateMutex();
1020 frame_ready = SDL_CreateCond();
1021 buffer_storage = 4;
1022 frame_buffers = calloc(buffer_storage, sizeof(uint32_t*));
1023 frame_buffers[0] = texture_buf;
1024 num_buffers = 1;
1025 }
1054 1026
1055 const char *vsync; 1027 const char *vsync;
1056 if (sync_to_audio) { 1028 if (sync_src == SYNC_AUDIO) {
1057 def.ptrval = "off"; 1029 def.ptrval = "off";
1058 vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval; 1030 vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval;
1059 } else { 1031 } else {
1060 vsync = "on"; 1032 vsync = "on";
1061 } 1033 }
1135 vsync = NULL; 1107 vsync = NULL;
1136 } 1108 }
1137 } 1109 }
1138 if (vsync) { 1110 if (vsync) {
1139 if (SDL_GL_SetSwapInterval(!strcmp("on", vsync)) < 0) { 1111 if (SDL_GL_SetSwapInterval(!strcmp("on", vsync)) < 0) {
1112 #ifdef __ANDROID__
1113 debug_message("Failed to set vsync to %s: %s\n", vsync, SDL_GetError());
1114 #else
1140 warning("Failed to set vsync to %s: %s\n", vsync, SDL_GetError()); 1115 warning("Failed to set vsync to %s: %s\n", vsync, SDL_GetError());
1116 #endif
1141 } 1117 }
1142 } 1118 }
1143 } else { 1119 } else {
1144 warning("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n"); 1120 warning("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n");
1145 } 1121 }
1155 if (!main_renderer) { 1131 if (!main_renderer) {
1156 fatal_error("unable to create SDL renderer: %s\n", SDL_GetError()); 1132 fatal_error("unable to create SDL renderer: %s\n", SDL_GetError());
1157 } 1133 }
1158 SDL_RendererInfo rinfo; 1134 SDL_RendererInfo rinfo;
1159 SDL_GetRendererInfo(main_renderer, &rinfo); 1135 SDL_GetRendererInfo(main_renderer, &rinfo);
1160 printf("SDL2 Render Driver: %s\n", rinfo.name); 1136 debug_message("SDL2 Render Driver: %s\n", rinfo.name);
1161 main_clip.x = main_clip.y = 0; 1137 main_clip.x = main_clip.y = 0;
1162 main_clip.w = main_width; 1138 main_clip.w = main_width;
1163 main_clip.h = main_height; 1139 main_clip.h = main_height;
1164 #ifndef DISABLE_OPENGL 1140 #ifndef DISABLE_OPENGL
1165 } 1141 }
1166 #endif 1142 #endif
1167 1143
1168 SDL_GetWindowSize(main_window, &main_width, &main_height); 1144 SDL_GetWindowSize(main_window, &main_width, &main_height);
1169 printf("Window created with size: %d x %d\n", main_width, main_height); 1145 debug_message("Window created with size: %d x %d\n", main_width, main_height);
1170 update_aspect(); 1146 update_aspect();
1171 render_alloc_surfaces(); 1147 render_alloc_surfaces();
1172 def.ptrval = "off"; 1148 def.ptrval = "off";
1173 scanlines = !strcmp(tern_find_path_default(config, "video\0scanlines\0", def, TVAL_PTR).ptrval, "on"); 1149 scanlines = !strcmp(tern_find_path_default(config, "video\0scanlines\0", def, TVAL_PTR).ptrval, "on");
1174 } 1150 }
1181 atexit(SDL_Quit); 1157 atexit(SDL_Quit);
1182 if (height <= 0) { 1158 if (height <= 0) {
1183 float aspect = config_aspect() > 0.0f ? config_aspect() : 4.0f/3.0f; 1159 float aspect = config_aspect() > 0.0f ? config_aspect() : 4.0f/3.0f;
1184 height = ((float)width / aspect) + 0.5f; 1160 height = ((float)width / aspect) + 0.5f;
1185 } 1161 }
1186 printf("width: %d, height: %d\n", width, height); 1162 debug_message("width: %d, height: %d\n", width, height);
1187 windowed_width = width; 1163 windowed_width = width;
1188 windowed_height = height; 1164 windowed_height = height;
1189 1165
1190 SDL_DisplayMode mode; 1166 SDL_DisplayMode mode;
1191 //TODO: Explicit multiple monitor support 1167 //TODO: Explicit multiple monitor support
1214 uint32_t db_size; 1190 uint32_t db_size;
1215 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size); 1191 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size);
1216 if (db_data) { 1192 if (db_data) {
1217 int added = SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(db_data, db_size), 1); 1193 int added = SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(db_data, db_size), 1);
1218 free(db_data); 1194 free(db_data);
1219 printf("Added %d game controller mappings from gamecontrollerdb.txt\n", added); 1195 debug_message("Added %d game controller mappings from gamecontrollerdb.txt\n", added);
1220 } 1196 }
1221 1197
1222 controller_add_mappings(); 1198 controller_add_mappings();
1223 1199
1224 SDL_JoystickEventState(SDL_ENABLE); 1200 SDL_JoystickEventState(SDL_ENABLE);
1225 1201
1226 render_set_video_standard(VID_NTSC); 1202 render_set_video_standard(VID_NTSC);
1227 1203
1228 atexit(render_quit); 1204 atexit(render_quit);
1229 } 1205 }
1230 #include<unistd.h> 1206
1207 void render_reset_mappings(void)
1208 {
1209 SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
1210 SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
1211 uint32_t db_size;
1212 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size);
1213 if (db_data) {
1214 int added = SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(db_data, db_size), 1);
1215 free(db_data);
1216 debug_message("Added %d game controller mappings from gamecontrollerdb.txt\n", added);
1217 }
1218 }
1231 static int in_toggle; 1219 static int in_toggle;
1232 static void update_source(audio_source *src, double rc, uint8_t sync_changed)
1233 {
1234 double alpha = src->dt / (src->dt + rc);
1235 int32_t lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
1236 src->lowpass_alpha = lowpass_alpha;
1237 if (sync_changed) {
1238 uint32_t alloc_size = sync_to_audio ? src->num_channels * buffer_samples : nearest_pow2(min_buffered * 4 * src->num_channels);
1239 src->back = realloc(src->back, alloc_size * sizeof(int16_t));
1240 if (sync_to_audio) {
1241 src->front = malloc(alloc_size * sizeof(int16_t));
1242 } else {
1243 free(src->front);
1244 src->front = src->back;
1245 }
1246 src->mask = sync_to_audio ? 0xFFFFFFFF : alloc_size-1;
1247 src->read_start = 0;
1248 src->read_end = sync_to_audio ? buffer_samples * src->num_channels : 0;
1249 src->buffer_pos = 0;
1250 }
1251 }
1252 1220
1253 void render_config_updated(void) 1221 void render_config_updated(void)
1254 { 1222 {
1255 uint8_t old_sync_to_audio = sync_to_audio;
1256
1257 free_surfaces(); 1223 free_surfaces();
1258 #ifndef DISABLE_OPENGL 1224 #ifndef DISABLE_OPENGL
1259 if (render_gl) { 1225 if (render_gl) {
1260 if (on_context_destroyed) { 1226 if (on_context_destroyed) {
1261 on_context_destroyed(); 1227 on_context_destroyed();
1268 #ifndef DISABLE_OPENGL 1234 #ifndef DISABLE_OPENGL
1269 } 1235 }
1270 #endif 1236 #endif
1271 in_toggle = 1; 1237 in_toggle = 1;
1272 SDL_DestroyWindow(main_window); 1238 SDL_DestroyWindow(main_window);
1239 main_window = NULL;
1273 drain_events(); 1240 drain_events();
1274 1241
1275 char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval; 1242 char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval;
1276 if (config_width) { 1243 if (config_width) {
1277 windowed_width = atoi(config_width); 1244 windowed_width = atoi(config_width);
1293 main_height = mode.h; 1260 main_height = mode.h;
1294 } else { 1261 } else {
1295 main_width = windowed_width; 1262 main_width = windowed_width;
1296 main_height = windowed_height; 1263 main_height = windowed_height;
1297 } 1264 }
1265 if (on_ui_fb_resized) {
1266 on_ui_fb_resized();
1267 }
1298 1268
1299 window_setup(); 1269 window_setup();
1300 update_aspect(); 1270 update_aspect();
1301 #ifndef DISABLE_OPENGL 1271 #ifndef DISABLE_OPENGL
1302 //need to check render_gl again after window_setup as render option could have changed 1272 //need to check render_gl again after window_setup as render option could have changed
1309 render_close_audio(); 1279 render_close_audio();
1310 quitting = 0; 1280 quitting = 0;
1311 init_audio(); 1281 init_audio();
1312 render_set_video_standard(video_standard); 1282 render_set_video_standard(video_standard);
1313 1283
1314 double lowpass_cutoff = get_lowpass_cutoff(config);
1315 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
1316 lock_audio();
1317 for (uint8_t i = 0; i < num_audio_sources; i++)
1318 {
1319 update_source(audio_sources[i], rc, old_sync_to_audio != sync_to_audio);
1320 }
1321 unlock_audio();
1322 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
1323 {
1324 update_source(inactive_audio_sources[i], rc, old_sync_to_audio != sync_to_audio);
1325 }
1326 drain_events(); 1284 drain_events();
1327 in_toggle = 0; 1285 in_toggle = 0;
1328 if (!was_paused) { 1286 if (!was_paused) {
1329 SDL_PauseAudio(0); 1287 SDL_PauseAudio(0);
1330 } 1288 }
1333 SDL_Window *render_get_window(void) 1291 SDL_Window *render_get_window(void)
1334 { 1292 {
1335 return main_window; 1293 return main_window;
1336 } 1294 }
1337 1295
1296 uint32_t render_audio_syncs_per_sec(void)
1297 {
1298 //sync samples with audio thread approximately every 8 lines when doing sync to video
1299 return render_is_audio_sync() ? 0 : source_hz * (video_standard == VID_PAL ? 313 : 262) / 8;
1300 }
1301
1338 void render_set_video_standard(vid_std std) 1302 void render_set_video_standard(vid_std std)
1339 { 1303 {
1340 video_standard = std; 1304 video_standard = std;
1305 if (render_is_audio_sync()) {
1306 return;
1307 }
1341 source_hz = std == VID_PAL ? 50 : 60; 1308 source_hz = std == VID_PAL ? 50 : 60;
1342 uint32_t max_repeat = 0; 1309 uint32_t max_repeat = 0;
1343 if (abs(source_hz - display_hz) < 2) { 1310 if (abs(source_hz - display_hz) < 2) {
1344 memset(frame_repeat, 0, sizeof(int)*display_hz); 1311 memset(frame_repeat, 0, sizeof(int)*display_hz);
1345 } else { 1312 } else {
1362 frame_repeat[source_hz-1] += display_hz - dst_frames; 1329 frame_repeat[source_hz-1] += display_hz - dst_frames;
1363 } 1330 }
1364 } 1331 }
1365 source_frame = 0; 1332 source_frame = 0;
1366 source_frame_count = frame_repeat[0]; 1333 source_frame_count = frame_repeat[0];
1367 //sync samples with audio thread approximately every 8 lines
1368 sync_samples = sync_to_audio ? buffer_samples : 8 * sample_rate / (source_hz * (VID_PAL ? 313 : 262));
1369 max_repeat++; 1334 max_repeat++;
1370 min_buffered = (((float)max_repeat * (float)sample_rate/(float)source_hz)/* / (float)buffer_samples*/);// + 0.9999; 1335 min_buffered = (((float)max_repeat * (float)sample_rate/(float)source_hz)/* / (float)buffer_samples*/);// + 0.9999;
1371 //min_buffered *= buffer_samples; 1336 //min_buffered *= buffer_samples;
1372 printf("Min samples buffered before audio start: %d\n", min_buffered); 1337 debug_message("Min samples buffered before audio start: %d\n", min_buffered);
1373 max_adjust = BASE_MAX_ADJUST / source_hz; 1338 max_adjust = BASE_MAX_ADJUST / source_hz;
1374 } 1339 }
1375 1340
1376 void render_update_caption(char *title) 1341 void render_update_caption(char *title)
1377 { 1342 {
1446 1411
1447 uint32_t *locked_pixels; 1412 uint32_t *locked_pixels;
1448 uint32_t locked_pitch; 1413 uint32_t locked_pitch;
1449 uint32_t *render_get_framebuffer(uint8_t which, int *pitch) 1414 uint32_t *render_get_framebuffer(uint8_t which, int *pitch)
1450 { 1415 {
1416 if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) {
1417 *pitch = LINEBUF_SIZE * sizeof(uint32_t);
1418 uint32_t *buffer;
1419 SDL_LockMutex(free_buffer_mutex);
1420 if (num_buffers) {
1421 buffer = frame_buffers[--num_buffers];
1422 } else {
1423 buffer = calloc(tex_width*(tex_height + 1), sizeof(uint32_t));
1424 }
1425 SDL_UnlockMutex(free_buffer_mutex);
1426 locked_pixels = buffer;
1427 return buffer;
1428 }
1451 #ifndef DISABLE_OPENGL 1429 #ifndef DISABLE_OPENGL
1452 if (render_gl && which <= FRAMEBUFFER_EVEN) { 1430 if (render_gl && which <= FRAMEBUFFER_EVEN) {
1453 *pitch = LINEBUF_SIZE * sizeof(uint32_t); 1431 *pitch = LINEBUF_SIZE * sizeof(uint32_t);
1454 return texture_buf; 1432 return texture_buf;
1455 } else { 1433 } else {
1456 #endif 1434 #endif
1435 if (which == FRAMEBUFFER_UI && !sdl_textures[which]) {
1436 sdl_textures[which] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, main_width, main_height);
1437 }
1457 if (which >= num_textures) { 1438 if (which >= num_textures) {
1458 warning("Request for invalid framebuffer number %d\n", which); 1439 warning("Request for invalid framebuffer number %d\n", which);
1459 return NULL; 1440 return NULL;
1460 } 1441 }
1461 void *pixels; 1442 uint8_t *pixels;
1462 if (SDL_LockTexture(sdl_textures[which], NULL, &pixels, pitch) < 0) { 1443 if (SDL_LockTexture(sdl_textures[which], NULL, (void **)&pixels, pitch) < 0) {
1463 warning("Failed to lock texture: %s\n", SDL_GetError()); 1444 warning("Failed to lock texture: %s\n", SDL_GetError());
1464 return NULL; 1445 return NULL;
1465 } 1446 }
1466 static uint8_t last; 1447 static uint8_t last;
1467 if (which <= FRAMEBUFFER_EVEN) { 1448 if (which <= FRAMEBUFFER_EVEN) {
1468 locked_pixels = pixels; 1449 locked_pixels = (uint32_t *)pixels;
1469 if (which == FRAMEBUFFER_EVEN) { 1450 if (which == FRAMEBUFFER_EVEN) {
1470 pixels += *pitch; 1451 pixels += *pitch;
1471 } 1452 }
1472 locked_pitch = *pitch; 1453 locked_pitch = *pitch;
1473 if (which != last) { 1454 if (which != last) {
1474 *pitch *= 2; 1455 *pitch *= 2;
1475 } 1456 }
1476 last = which; 1457 last = which;
1477 } 1458 }
1478 return pixels; 1459 return (uint32_t *)pixels;
1479 #ifndef DISABLE_OPENGL 1460 #ifndef DISABLE_OPENGL
1480 } 1461 }
1481 #endif 1462 #endif
1463 }
1464
1465 static void release_buffer(uint32_t *buffer)
1466 {
1467 SDL_LockMutex(free_buffer_mutex);
1468 if (num_buffers == buffer_storage) {
1469 buffer_storage *= 2;
1470 frame_buffers = realloc(frame_buffers, sizeof(uint32_t*)*buffer_storage);
1471 }
1472 frame_buffers[num_buffers++] = buffer;
1473 SDL_UnlockMutex(free_buffer_mutex);
1482 } 1474 }
1483 1475
1484 uint8_t events_processed; 1476 uint8_t events_processed;
1485 #ifdef __ANDROID__ 1477 #ifdef __ANDROID__
1486 #define FPS_INTERVAL 10000 1478 #define FPS_INTERVAL 10000
1488 #define FPS_INTERVAL 1000 1480 #define FPS_INTERVAL 1000
1489 #endif 1481 #endif
1490 1482
1491 static uint32_t last_width, last_height; 1483 static uint32_t last_width, last_height;
1492 static uint8_t interlaced; 1484 static uint8_t interlaced;
1493 void render_framebuffer_updated(uint8_t which, int width) 1485 static void process_framebuffer(uint32_t *buffer, uint8_t which, int width)
1494 { 1486 {
1495 static uint8_t last; 1487 static uint8_t last;
1496 if (!sync_to_audio && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) { 1488 if (sync_src == SYNC_VIDEO && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) {
1497 source_frame++; 1489 source_frame++;
1498 if (source_frame >= source_hz) { 1490 if (source_frame >= source_hz) {
1499 source_frame = 0; 1491 source_frame = 0;
1500 } 1492 }
1501 source_frame_count = frame_repeat[source_frame]; 1493 source_frame_count = frame_repeat[source_frame];
1514 screenshot_file = fopen(screenshot_path, "wb"); 1506 screenshot_file = fopen(screenshot_path, "wb");
1515 if (screenshot_file) { 1507 if (screenshot_file) {
1516 #ifndef DISABLE_ZLIB 1508 #ifndef DISABLE_ZLIB
1517 ext = path_extension(screenshot_path); 1509 ext = path_extension(screenshot_path);
1518 #endif 1510 #endif
1519 info_message("Saving screenshot to %s\n", screenshot_path); 1511 debug_message("Saving screenshot to %s\n", screenshot_path);
1520 } else { 1512 } else {
1521 warning("Failed to open screenshot file %s for writing\n", screenshot_path); 1513 warning("Failed to open screenshot file %s for writing\n", screenshot_path);
1522 } 1514 }
1523 free(screenshot_path); 1515 free(screenshot_path);
1524 screenshot_path = NULL; 1516 screenshot_path = NULL;
1529 width -= overscan_left[video_standard] + overscan_right[video_standard]; 1521 width -= overscan_left[video_standard] + overscan_right[video_standard];
1530 #ifndef DISABLE_OPENGL 1522 #ifndef DISABLE_OPENGL
1531 if (render_gl && which <= FRAMEBUFFER_EVEN) { 1523 if (render_gl && which <= FRAMEBUFFER_EVEN) {
1532 SDL_GL_MakeCurrent(main_window, main_context); 1524 SDL_GL_MakeCurrent(main_window, main_context);
1533 glBindTexture(GL_TEXTURE_2D, textures[which]); 1525 glBindTexture(GL_TEXTURE_2D, textures[which]);
1534 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]); 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]);
1535 1527
1536 if (screenshot_file) { 1528 if (screenshot_file) {
1537 //properly supporting interlaced modes here is non-trivial, so only save the odd field for now 1529 //properly supporting interlaced modes here is non-trivial, so only save the odd field for now
1538 #ifndef DISABLE_ZLIB 1530 #ifndef DISABLE_ZLIB
1539 if (!strcasecmp(ext, "png")) { 1531 if (!strcasecmp(ext, "png")) {
1540 free(ext); 1532 free(ext);
1541 save_png(screenshot_file, texture_buf, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); 1533 save_png(screenshot_file, buffer, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t));
1542 } else { 1534 } else {
1543 free(ext); 1535 free(ext);
1544 #endif 1536 #endif
1545 save_ppm(screenshot_file, texture_buf, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); 1537 save_ppm(screenshot_file, buffer, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t));
1546 #ifndef DISABLE_ZLIB 1538 #ifndef DISABLE_ZLIB
1547 } 1539 }
1548 #endif 1540 #endif
1549 } 1541 }
1550 } else { 1542 } else {
1551 #endif 1543 #endif
1544 //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers
1552 if (which <= FRAMEBUFFER_EVEN && last != which) { 1545 if (which <= FRAMEBUFFER_EVEN && last != which) {
1553 uint8_t *cur_dst = (uint8_t *)locked_pixels; 1546 uint8_t *cur_dst = (uint8_t *)locked_pixels;
1554 uint8_t *cur_saved = (uint8_t *)texture_buf; 1547 uint8_t *cur_saved = (uint8_t *)texture_buf;
1555 uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch; 1548 uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch;
1556 uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0; 1549 uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0;
1589 } 1582 }
1590 #endif 1583 #endif
1591 last_height = height; 1584 last_height = height;
1592 if (which <= FRAMEBUFFER_EVEN) { 1585 if (which <= FRAMEBUFFER_EVEN) {
1593 render_update_display(); 1586 render_update_display();
1587 } else if (which == FRAMEBUFFER_UI) {
1588 SDL_RenderCopy(main_renderer, sdl_textures[which], NULL, NULL);
1589 if (need_ui_fb_resize) {
1590 SDL_DestroyTexture(sdl_textures[which]);
1591 sdl_textures[which] = NULL;
1592 if (on_ui_fb_resized) {
1593 on_ui_fb_resized();
1594 }
1595 need_ui_fb_resize = 0;
1596 }
1594 } else { 1597 } else {
1595 SDL_RenderCopy(extra_renderers[which - FRAMEBUFFER_USER_START], sdl_textures[which], NULL, NULL); 1598 SDL_RenderCopy(extra_renderers[which - FRAMEBUFFER_USER_START], sdl_textures[which], NULL, NULL);
1596 SDL_RenderPresent(extra_renderers[which - FRAMEBUFFER_USER_START]); 1599 SDL_RenderPresent(extra_renderers[which - FRAMEBUFFER_USER_START]);
1597 } 1600 }
1598 if (screenshot_file) { 1601 if (screenshot_file) {
1604 frame_counter++; 1607 frame_counter++;
1605 last_frame= SDL_GetTicks(); 1608 last_frame= SDL_GetTicks();
1606 if ((last_frame - start) > FPS_INTERVAL) { 1609 if ((last_frame - start) > FPS_INTERVAL) {
1607 if (start && (last_frame-start)) { 1610 if (start && (last_frame-start)) {
1608 #ifdef __ANDROID__ 1611 #ifdef __ANDROID__
1609 info_message("%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); 1612 debug_message("%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0));
1610 #else 1613 #else
1611 if (!fps_caption) { 1614 if (!fps_caption) {
1612 fps_caption = malloc(strlen(caption) + strlen(" - 100000000.1 fps") + 1); 1615 fps_caption = malloc(strlen(caption) + strlen(" - 100000000.1 fps") + 1);
1613 } 1616 }
1614 sprintf(fps_caption, "%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); 1617 sprintf(fps_caption, "%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0));
1617 } 1620 }
1618 start = last_frame; 1621 start = last_frame;
1619 frame_counter = 0; 1622 frame_counter = 0;
1620 } 1623 }
1621 } 1624 }
1622 if (!sync_to_audio) { 1625 if (!render_is_audio_sync()) {
1623 int32_t local_cur_min, local_min_remaining; 1626 int32_t local_cur_min, local_min_remaining;
1624 SDL_LockAudio(); 1627 SDL_LockAudio();
1625 if (last_buffered > NO_LAST_BUFFERED) { 1628 if (last_buffered > NO_LAST_BUFFERED) {
1626 average_change *= 0.9f; 1629 average_change *= 0.9f;
1627 average_change += (cur_min_buffered - last_buffered) * 0.1f; 1630 average_change += (cur_min_buffered - last_buffered) * 0.1f;
1659 } else if (local_cur_min < min_buffered / 2) { 1662 } else if (local_cur_min < min_buffered / 2) {
1660 adjust_ratio = max_adjust; 1663 adjust_ratio = max_adjust;
1661 } 1664 }
1662 if (adjust_ratio != 0.0f) { 1665 if (adjust_ratio != 0.0f) {
1663 average_change = 0; 1666 average_change = 0;
1664 for (uint8_t i = 0; i < num_audio_sources; i++) 1667 render_audio_adjust_speed(adjust_ratio);
1665 { 1668
1666 audio_sources[i]->buffer_inc = ((double)audio_sources[i]->buffer_inc) + ((double)audio_sources[i]->buffer_inc) * adjust_ratio + 0.5;
1667 }
1668 } 1669 }
1669 while (source_frame_count > 0) 1670 while (source_frame_count > 0)
1670 { 1671 {
1671 render_update_display(); 1672 render_update_display();
1672 source_frame_count--; 1673 source_frame_count--;
1677 } 1678 }
1678 source_frame_count = frame_repeat[source_frame]; 1679 source_frame_count = frame_repeat[source_frame];
1679 } 1680 }
1680 } 1681 }
1681 1682
1683 typedef struct {
1684 uint32_t *buffer;
1685 int width;
1686 uint8_t which;
1687 } frame;
1688 frame frame_queue[4];
1689 int frame_queue_len, frame_queue_read, frame_queue_write;
1690
1691 void render_framebuffer_updated(uint8_t which, int width)
1692 {
1693 if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) {
1694 SDL_LockMutex(frame_mutex);
1695 while (frame_queue_len == 4) {
1696 SDL_CondSignal(frame_ready);
1697 SDL_UnlockMutex(frame_mutex);
1698 SDL_Delay(1);
1699 SDL_LockMutex(frame_mutex);
1700 }
1701 for (int cur = frame_queue_read, i = 0; i < frame_queue_len; i++) {
1702 if (frame_queue[cur].which == which) {
1703 int last = (frame_queue_write - 1) & 3;
1704 frame_queue_len--;
1705 release_buffer(frame_queue[cur].buffer);
1706 if (last != cur) {
1707 frame_queue[cur] = frame_queue[last];
1708 }
1709 frame_queue_write = last;
1710 break;
1711 }
1712 cur = (cur + 1) & 3;
1713 }
1714 frame_queue[frame_queue_write++] = (frame){
1715 .buffer = locked_pixels,
1716 .width = width,
1717 .which = which
1718 };
1719 frame_queue_write &= 0x3;
1720 frame_queue_len++;
1721 SDL_CondSignal(frame_ready);
1722 SDL_UnlockMutex(frame_mutex);
1723 return;
1724 }
1725 //TODO: Maybe fixme for render API
1726 process_framebuffer(texture_buf, which, width);
1727 }
1728
1729 void render_video_loop(void)
1730 {
1731 if (sync_src != SYNC_AUDIO_THREAD && sync_src != SYNC_EXTERNAL) {
1732 return;
1733 }
1734 SDL_PauseAudio(0);
1735 SDL_LockMutex(frame_mutex);
1736 for(;;)
1737 {
1738 while (!frame_queue_len && SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)
1739 {
1740 SDL_CondWait(frame_ready, frame_mutex);
1741 }
1742 while (frame_queue_len)
1743 {
1744 frame f = frame_queue[frame_queue_read++];
1745 frame_queue_read &= 0x3;
1746 frame_queue_len--;
1747 SDL_UnlockMutex(frame_mutex);
1748 process_framebuffer(f.buffer, f.which, f.width);
1749 release_buffer(f.buffer);
1750 SDL_LockMutex(frame_mutex);
1751 }
1752 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING) {
1753 break;
1754 }
1755 }
1756
1757 SDL_UnlockMutex(frame_mutex);
1758 }
1759
1682 static ui_render_fun render_ui; 1760 static ui_render_fun render_ui;
1683 void render_set_ui_render_fun(ui_render_fun fun) 1761 void render_set_ui_render_fun(ui_render_fun fun)
1684 { 1762 {
1685 render_ui = fun; 1763 render_ui = fun;
1686 } 1764 }
1701 glBindTexture(GL_TEXTURE_2D, textures[interlaced ? 1 : scanlines ? 2 : 0]); 1779 glBindTexture(GL_TEXTURE_2D, textures[interlaced ? 1 : scanlines ? 2 : 0]);
1702 glUniform1i(un_textures[1], 1); 1780 glUniform1i(un_textures[1], 1);
1703 1781
1704 glUniform1f(un_width, render_emulated_width()); 1782 glUniform1f(un_width, render_emulated_width());
1705 glUniform1f(un_height, last_height); 1783 glUniform1f(un_height, last_height);
1784 glUniform2f(un_texsize, tex_width, tex_height);
1706 1785
1707 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); 1786 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
1708 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); 1787 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0);
1709 glEnableVertexAttribArray(at_pos); 1788 glEnableVertexAttribArray(at_pos);
1710 1789
1760 uint32_t render_overscan_top() 1839 uint32_t render_overscan_top()
1761 { 1840 {
1762 return overscan_top[video_standard]; 1841 return overscan_top[video_standard];
1763 } 1842 }
1764 1843
1765 void render_wait_quit(vdp_context * context) 1844 uint32_t render_overscan_bot()
1845 {
1846 return overscan_bot[video_standard];
1847 }
1848
1849 void render_wait_quit(void)
1766 { 1850 {
1767 SDL_Event event; 1851 SDL_Event event;
1768 while(SDL_WaitEvent(&event)) { 1852 while(SDL_WaitEvent(&event)) {
1769 switch (event.type) { 1853 switch (event.type) {
1770 case SDL_QUIT: 1854 case SDL_QUIT:
1827 warning("Failed to open game controller %d: %s\n", controller, SDL_GetError()); 1911 warning("Failed to open game controller %d: %s\n", controller, SDL_GetError());
1828 return RENDER_NOT_PLUGGED_IN; 1912 return RENDER_NOT_PLUGGED_IN;
1829 } 1913 }
1830 1914
1831 SDL_GameControllerButtonBind cbind; 1915 SDL_GameControllerButtonBind cbind;
1916 int32_t is_positive = RENDER_AXIS_POS;
1832 if (is_axis) { 1917 if (is_axis) {
1833 1918
1834 int sdl_axis = render_lookup_axis(name); 1919 int sdl_axis = render_lookup_axis(name);
1835 if (sdl_axis == SDL_CONTROLLER_AXIS_INVALID) { 1920 if (sdl_axis == SDL_CONTROLLER_AXIS_INVALID) {
1836 SDL_GameControllerClose(control); 1921 SDL_GameControllerClose(control);
1841 int sdl_button = render_lookup_button(name); 1926 int sdl_button = render_lookup_button(name);
1842 if (sdl_button == SDL_CONTROLLER_BUTTON_INVALID) { 1927 if (sdl_button == SDL_CONTROLLER_BUTTON_INVALID) {
1843 SDL_GameControllerClose(control); 1928 SDL_GameControllerClose(control);
1844 return RENDER_INVALID_NAME; 1929 return RENDER_INVALID_NAME;
1845 } 1930 }
1931 if (sdl_button == SDL_CONTROLLER_BUTTON_DPAD_UP || sdl_button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
1932 //assume these will be negative if they are an axis
1933 is_positive = 0;
1934 }
1846 cbind = SDL_GameControllerGetBindForButton(control, sdl_button); 1935 cbind = SDL_GameControllerGetBindForButton(control, sdl_button);
1847 } 1936 }
1848 SDL_GameControllerClose(control); 1937 SDL_GameControllerClose(control);
1849 switch (cbind.bindType) 1938 switch (cbind.bindType)
1850 { 1939 {
1851 case SDL_CONTROLLER_BINDTYPE_BUTTON: 1940 case SDL_CONTROLLER_BINDTYPE_BUTTON:
1852 return cbind.value.button; 1941 return cbind.value.button;
1853 case SDL_CONTROLLER_BINDTYPE_AXIS: 1942 case SDL_CONTROLLER_BINDTYPE_AXIS:
1854 return RENDER_AXIS_BIT | cbind.value.axis; 1943 return RENDER_AXIS_BIT | cbind.value.axis | is_positive;
1855 case SDL_CONTROLLER_BINDTYPE_HAT: 1944 case SDL_CONTROLLER_BINDTYPE_HAT:
1856 return RENDER_DPAD_BIT | (cbind.value.hat.hat << 4) | cbind.value.hat.hat_mask; 1945 return RENDER_DPAD_BIT | (cbind.value.hat.hat << 4) | cbind.value.hat.hat_mask;
1857 } 1946 }
1858 return RENDER_NOT_MAPPED; 1947 return RENDER_NOT_MAPPED;
1859 } 1948 }
1920 //is the only thing that seems to work reliably 2009 //is the only thing that seems to work reliably
1921 //when we've just switched to fullscreen mode this should be harmless though 2010 //when we've just switched to fullscreen mode this should be harmless though
1922 SDL_SetWindowSize(main_window, windowed_width, windowed_height); 2011 SDL_SetWindowSize(main_window, windowed_width, windowed_height);
1923 drain_events(); 2012 drain_events();
1924 in_toggle = 0; 2013 in_toggle = 0;
1925 } 2014 need_ui_fb_resize = 1;
1926
1927 uint32_t render_audio_buffer()
1928 {
1929 return buffer_samples;
1930 }
1931
1932 uint32_t render_sample_rate()
1933 {
1934 return sample_rate;
1935 } 2015 }
1936 2016
1937 void render_errorbox(char *title, char *message) 2017 void render_errorbox(char *title, char *message)
1938 { 2018 {
1939 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, NULL); 2019 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, NULL);
1975 return FRAMEBUFFER_USER_START + i; 2055 return FRAMEBUFFER_USER_START + i;
1976 } 2056 }
1977 } 2057 }
1978 return 0xFF; 2058 return 0xFF;
1979 } 2059 }
2060
2061 uint8_t render_create_thread(render_thread *thread, const char *name, render_thread_fun fun, void *data)
2062 {
2063 *thread = SDL_CreateThread(fun, name, data);
2064 return *thread != 0;
2065 }