Mercurial > repos > blastem
comparison render_sdl.c @ 1696:956c1cce05e2 mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 24 Jan 2019 19:15:59 -0800 |
parents | ba3fb7a3be6b |
children | 52a47611a273 |
comparison
equal
deleted
inserted
replaced
1648:b7ecd0d6a77b | 1696:956c1cce05e2 |
---|---|
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 |
21 #ifndef DISABLE_OPENGL | 22 #ifndef DISABLE_OPENGL |
23 #ifdef USE_GLES | |
24 #include <SDL_opengles2.h> | |
25 #else | |
22 #include <GL/glew.h> | 26 #include <GL/glew.h> |
27 #endif | |
23 #endif | 28 #endif |
24 | 29 |
25 #define MAX_EVENT_POLL_PER_FRAME 2 | 30 #define MAX_EVENT_POLL_PER_FRAME 2 |
26 | 31 |
27 static SDL_Window *main_window; | 32 static SDL_Window *main_window; |
28 static SDL_Window **extra_windows; | 33 static SDL_Window **extra_windows; |
29 static SDL_Renderer *main_renderer; | 34 static SDL_Renderer *main_renderer; |
30 static SDL_Renderer **extra_renderers; | 35 static SDL_Renderer **extra_renderers; |
31 static SDL_Texture **sdl_textures; | 36 static SDL_Texture **sdl_textures; |
37 static window_close_handler *close_handlers; | |
32 static uint8_t num_textures; | 38 static uint8_t num_textures; |
33 static SDL_Rect main_clip; | 39 static SDL_Rect main_clip; |
34 static SDL_GLContext *main_context; | 40 static SDL_GLContext *main_context; |
35 | 41 |
36 static int main_width, main_height, windowed_width, windowed_height, is_fullscreen; | 42 static int main_width, main_height, windowed_width, windowed_height, is_fullscreen; |
38 static uint8_t render_gl = 1; | 44 static uint8_t render_gl = 1; |
39 static uint8_t scanlines = 0; | 45 static uint8_t scanlines = 0; |
40 | 46 |
41 static uint32_t last_frame = 0; | 47 static uint32_t last_frame = 0; |
42 | 48 |
49 static uint8_t output_channels; | |
43 static uint32_t buffer_samples, sample_rate; | 50 static uint32_t buffer_samples, sample_rate; |
44 static uint32_t missing_count; | 51 static uint32_t missing_count; |
45 | 52 |
46 static SDL_mutex * audio_mutex; | 53 static SDL_mutex * audio_mutex; |
47 static SDL_cond * audio_ready; | 54 static SDL_cond * audio_ready; |
76 | 83 |
77 static int32_t mix_s16(audio_source *audio, void *vstream, int len) | 84 static int32_t mix_s16(audio_source *audio, void *vstream, int len) |
78 { | 85 { |
79 int samples = len/(sizeof(int16_t)*2); | 86 int samples = len/(sizeof(int16_t)*2); |
80 int16_t *stream = vstream; | 87 int16_t *stream = vstream; |
81 int16_t *end = stream + 2*samples; | 88 int16_t *end = stream + output_channels*samples; |
82 int16_t *src = audio->front; | 89 int16_t *src = audio->front; |
83 uint32_t i = audio->read_start; | 90 uint32_t i = audio->read_start; |
84 uint32_t i_end = audio->read_end; | 91 uint32_t i_end = audio->read_end; |
85 int16_t *cur = stream; | 92 int16_t *cur = stream; |
93 size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1; | |
86 if (audio->num_channels == 1) { | 94 if (audio->num_channels == 1) { |
87 while (cur < end && i != i_end) | 95 while (cur < end && i != i_end) |
88 { | 96 { |
89 *(cur++) += src[i]; | 97 *cur += src[i]; |
90 *(cur++) += src[i++]; | 98 cur += first_add; |
99 *cur += src[i++]; | |
100 cur += second_add; | |
91 i &= audio->mask; | 101 i &= audio->mask; |
92 } | 102 } |
93 } else { | 103 } else { |
94 while (cur < end && i != i_end) | 104 while (cur < end && i != i_end) |
95 { | 105 { |
96 *(cur++) += src[i++]; | 106 *cur += src[i++]; |
97 *(cur++) += src[i++]; | 107 cur += first_add; |
108 *cur += src[i++]; | |
109 cur += second_add; | |
98 i &= audio->mask; | 110 i &= audio->mask; |
99 } | 111 } |
100 } | 112 } |
101 | 113 |
102 if (cur != end) { | 114 if (cur != end) { |
120 float *end = stream + 2*samples; | 132 float *end = stream + 2*samples; |
121 int16_t *src = audio->front; | 133 int16_t *src = audio->front; |
122 uint32_t i = audio->read_start; | 134 uint32_t i = audio->read_start; |
123 uint32_t i_end = audio->read_end; | 135 uint32_t i_end = audio->read_end; |
124 float *cur = stream; | 136 float *cur = stream; |
137 size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1; | |
125 if (audio->num_channels == 1) { | 138 if (audio->num_channels == 1) { |
126 while (cur < end && i != i_end) | 139 while (cur < end && i != i_end) |
127 { | 140 { |
128 *(cur++) += ((float)src[i]) / 0x7FFF; | 141 *cur += ((float)src[i]) / 0x7FFF; |
129 *(cur++) += ((float)src[i++]) / 0x7FFF; | 142 cur += first_add; |
143 *cur += ((float)src[i++]) / 0x7FFF; | |
144 cur += second_add; | |
130 i &= audio->mask; | 145 i &= audio->mask; |
131 } | 146 } |
132 } else { | 147 } else { |
133 while(cur < end && i != i_end) | 148 while(cur < end && i != i_end) |
134 { | 149 { |
135 *(cur++) += ((float)src[i++]) / 0x7FFF; | 150 *cur += ((float)src[i++]) / 0x7FFF; |
136 *(cur++) += ((float)src[i++]) / 0x7FFF; | 151 cur += first_add; |
152 *cur += ((float)src[i++]) / 0x7FFF; | |
153 cur += second_add; | |
137 i &= audio->mask; | 154 i &= audio->mask; |
138 } | 155 } |
139 } | 156 } |
140 if (!sync_to_audio) { | 157 if (!sync_to_audio) { |
141 audio->read_start = i; | 158 audio->read_start = i; |
434 return is_fullscreen; | 451 return is_fullscreen; |
435 } | 452 } |
436 | 453 |
437 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) | 454 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) |
438 { | 455 { |
456 #ifdef USE_GLES | |
457 return 255 << 24 | b << 16 | g << 8 | r; | |
458 #else | |
439 return 255 << 24 | r << 16 | g << 8 | b; | 459 return 255 << 24 | r << 16 | g << 8 | b; |
460 #endif | |
440 } | 461 } |
441 | 462 |
442 #ifndef DISABLE_OPENGL | 463 #ifndef DISABLE_OPENGL |
443 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, at_pos; | 464 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, at_pos; |
444 | 465 |
451 | 472 |
452 static GLfloat vertex_data[8]; | 473 static GLfloat vertex_data[8]; |
453 | 474 |
454 static const GLushort element_data[] = {0, 1, 2, 3}; | 475 static const GLushort element_data[] = {0, 1, 2, 3}; |
455 | 476 |
477 static const GLchar shader_prefix[] = | |
478 #ifdef USE_GLES | |
479 "#version 100\n"; | |
480 #else | |
481 "#version 110\n" | |
482 "#define lowp\n" | |
483 "#define mediump\n" | |
484 "#define highp\n"; | |
485 #endif | |
486 | |
456 static GLuint load_shader(char * fname, GLenum shader_type) | 487 static GLuint load_shader(char * fname, GLenum shader_type) |
457 { | 488 { |
458 char const * parts[] = {get_home_dir(), "/.config/blastem/shaders/", fname}; | 489 char const * parts[] = {get_home_dir(), "/.config/blastem/shaders/", fname}; |
459 char * shader_path = alloc_concat_m(3, parts); | 490 char * shader_path = alloc_concat_m(3, parts); |
460 FILE * f = fopen(shader_path, "rb"); | 491 FILE * f = fopen(shader_path, "rb"); |
461 free(shader_path); | 492 free(shader_path); |
462 if (!f) { | 493 GLchar * text; |
463 parts[0] = get_exe_dir(); | 494 long fsize; |
464 parts[1] = "/shaders/"; | 495 if (f) { |
465 shader_path = alloc_concat_m(3, parts); | 496 fsize = file_size(f); |
466 f = fopen(shader_path, "rb"); | 497 text = malloc(fsize); |
498 if (fread(text, 1, fsize, f) != fsize) { | |
499 warning("Error reading from shader file %s\n", fname); | |
500 free(text); | |
501 return 0; | |
502 } | |
503 } else { | |
504 shader_path = path_append("shaders", fname); | |
505 uint32_t fsize32; | |
506 text = read_bundled_file(shader_path, &fsize32); | |
467 free(shader_path); | 507 free(shader_path); |
468 if (!f) { | 508 if (!text) { |
469 warning("Failed to open shader file %s for reading\n", fname); | 509 warning("Failed to open shader file %s for reading\n", fname); |
470 return 0; | 510 return 0; |
471 } | 511 } |
472 } | 512 fsize = fsize32; |
473 long fsize = file_size(f); | 513 } |
474 GLchar * text = malloc(fsize); | 514 |
475 if (fread(text, 1, fsize, f) != fsize) { | 515 if (strncmp(text, "#version", strlen("#version"))) { |
476 warning("Error reading from shader file %s\n", fname); | 516 GLchar *tmp = text; |
477 free(text); | 517 text = alloc_concat(shader_prefix, tmp); |
478 return 0; | 518 free(tmp); |
519 fsize += strlen(shader_prefix); | |
479 } | 520 } |
480 GLuint ret = glCreateShader(shader_type); | 521 GLuint ret = glCreateShader(shader_type); |
481 glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize); | 522 glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize); |
482 free(text); | 523 free(text); |
483 glCompileShader(ret); | 524 glCompileShader(ret); |
496 } | 537 } |
497 #endif | 538 #endif |
498 | 539 |
499 static uint32_t texture_buf[512 * 513]; | 540 static uint32_t texture_buf[512 * 513]; |
500 #ifndef DISABLE_OPENGL | 541 #ifndef DISABLE_OPENGL |
542 #ifdef USE_GLES | |
543 #define INTERNAL_FORMAT GL_RGBA | |
544 #define SRC_FORMAT GL_RGBA | |
545 #define RENDER_FORMAT SDL_PIXELFORMAT_ABGR8888 | |
546 #else | |
547 #define INTERNAL_FORMAT GL_RGBA8 | |
548 #define SRC_FORMAT GL_BGRA | |
549 #define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888 | |
550 #endif | |
501 static void gl_setup() | 551 static void gl_setup() |
502 { | 552 { |
503 tern_val def = {.ptrval = "linear"}; | 553 tern_val def = {.ptrval = "linear"}; |
504 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; | 554 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; |
505 GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR; | 555 GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR; |
511 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); | 561 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); |
512 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 562 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
513 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 563 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
514 if (i < 2) { | 564 if (i < 2) { |
515 //TODO: Fixme for PAL + invalid display mode | 565 //TODO: Fixme for PAL + invalid display mode |
516 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); | 566 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 512, 512, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf); |
517 } else { | 567 } else { |
518 uint32_t blank = 255 << 24; | 568 uint32_t blank = 255 << 24; |
519 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); | 569 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, &blank); |
520 } | 570 } |
521 } | 571 } |
522 glGenBuffers(2, buffers); | 572 glGenBuffers(2, buffers); |
523 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); | 573 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); |
524 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); | 574 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); |
572 #endif | 622 #endif |
573 tern_val def = {.ptrval = "linear"}; | 623 tern_val def = {.ptrval = "linear"}; |
574 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; | 624 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; |
575 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scaling); | 625 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scaling); |
576 //TODO: Fixme for invalid display mode | 626 //TODO: Fixme for invalid display mode |
577 sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, LINEBUF_SIZE, 588); | 627 sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, RENDER_FORMAT, SDL_TEXTUREACCESS_STREAMING, LINEBUF_SIZE, 588); |
578 #ifndef DISABLE_OPENGL | 628 #ifndef DISABLE_OPENGL |
579 } | 629 } |
580 #endif | 630 #endif |
581 } | 631 } |
582 | 632 |
919 on_context_created(); | 969 on_context_created(); |
920 } | 970 } |
921 } | 971 } |
922 #endif | 972 #endif |
923 break; | 973 break; |
974 case SDL_WINDOWEVENT_CLOSE: | |
975 if (SDL_GetWindowID(main_window) == event->window.windowID) { | |
976 exit(0); | |
977 } else { | |
978 for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++) | |
979 { | |
980 if (SDL_GetWindowID(extra_windows[i]) == event->window.windowID) { | |
981 if (close_handlers[i]) { | |
982 close_handlers[i](i + FRAMEBUFFER_USER_START); | |
983 } | |
984 break; | |
985 } | |
986 } | |
987 } | |
988 break; | |
924 } | 989 } |
925 break; | 990 break; |
926 case SDL_DROPFILE: | 991 case SDL_DROPFILE: |
927 if (drag_drop_handler) { | 992 if (drag_drop_handler) { |
928 drag_drop_handler(event->drop.file); | 993 drag_drop_handler(event->drop.file); |
976 if (SDL_OpenAudio(&desired, &actual) < 0) { | 1041 if (SDL_OpenAudio(&desired, &actual) < 0) { |
977 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); | 1042 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); |
978 } | 1043 } |
979 buffer_samples = actual.samples; | 1044 buffer_samples = actual.samples; |
980 sample_rate = actual.freq; | 1045 sample_rate = actual.freq; |
1046 output_channels = actual.channels; | |
981 printf("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples); | 1047 printf("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples); |
982 if (actual.format == AUDIO_S16SYS) { | 1048 if (actual.format == AUDIO_S16SYS) { |
983 puts("signed 16-bit int format"); | 1049 puts("signed 16-bit int format"); |
984 mix = mix_s16; | 1050 mix = mix_s16; |
985 } else if (actual.format == AUDIO_F32SYS) { | 1051 } else if (actual.format == AUDIO_F32SYS) { |
997 uint32_t flags = SDL_WINDOW_RESIZABLE; | 1063 uint32_t flags = SDL_WINDOW_RESIZABLE; |
998 if (is_fullscreen) { | 1064 if (is_fullscreen) { |
999 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; | 1065 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; |
1000 } | 1066 } |
1001 | 1067 |
1002 tern_val def = {.ptrval = "video"}; | 1068 tern_val def = {.ptrval = "audio"}; |
1003 char *sync_src = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval; | 1069 char *sync_src = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval; |
1004 sync_to_audio = !strcmp(sync_src, "audio"); | 1070 sync_to_audio = !strcmp(sync_src, "audio"); |
1005 | 1071 |
1006 const char *vsync; | 1072 const char *vsync; |
1007 if (sync_to_audio) { | 1073 if (sync_to_audio) { |
1048 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); | 1114 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); |
1049 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); | 1115 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); |
1050 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); | 1116 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); |
1051 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); | 1117 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); |
1052 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | 1118 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |
1119 #ifdef USE_GLES | |
1120 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); | |
1121 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); | |
1122 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); | |
1123 #endif | |
1053 } | 1124 } |
1054 #endif | 1125 #endif |
1055 main_window = SDL_CreateWindow(caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, main_width, main_height, flags); | 1126 main_window = SDL_CreateWindow(caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, main_width, main_height, flags); |
1056 if (!main_window) { | 1127 if (!main_window) { |
1057 fatal_error("Unable to create SDL window: %s\n", SDL_GetError()); | 1128 fatal_error("Unable to create SDL window: %s\n", SDL_GetError()); |
1058 } | 1129 } |
1059 #ifndef DISABLE_OPENGL | 1130 #ifndef DISABLE_OPENGL |
1060 if (gl_enabled) | 1131 if (gl_enabled) |
1061 { | 1132 { |
1062 main_context = SDL_GL_CreateContext(main_window); | 1133 main_context = SDL_GL_CreateContext(main_window); |
1134 #ifdef USE_GLES | |
1135 int major_version; | |
1136 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major_version) == 0 && major_version >= 2) { | |
1137 #else | |
1063 GLenum res = glewInit(); | 1138 GLenum res = glewInit(); |
1064 if (res != GLEW_OK) { | 1139 if (res != GLEW_OK) { |
1065 warning("Initialization of GLEW failed with code %d\n", res); | 1140 warning("Initialization of GLEW failed with code %d\n", res); |
1066 } | 1141 } |
1067 | 1142 |
1068 if (res == GLEW_OK && GLEW_VERSION_2_0) { | 1143 if (res == GLEW_OK && GLEW_VERSION_2_0) { |
1144 #endif | |
1069 render_gl = 1; | 1145 render_gl = 1; |
1146 SDL_GL_MakeCurrent(main_window, main_context); | |
1070 if (!strcmp("tear", vsync)) { | 1147 if (!strcmp("tear", vsync)) { |
1071 if (SDL_GL_SetSwapInterval(-1) < 0) { | 1148 if (SDL_GL_SetSwapInterval(-1) < 0) { |
1072 warning("late tear is not available (%s), using normal vsync\n", SDL_GetError()); | 1149 warning("late tear is not available (%s), using normal vsync\n", SDL_GetError()); |
1073 vsync = "on"; | 1150 vsync = "on"; |
1074 } else { | 1151 } else { |
1093 main_renderer = SDL_CreateRenderer(main_window, -1, flags); | 1170 main_renderer = SDL_CreateRenderer(main_window, -1, flags); |
1094 | 1171 |
1095 if (!main_renderer) { | 1172 if (!main_renderer) { |
1096 fatal_error("unable to create SDL renderer: %s\n", SDL_GetError()); | 1173 fatal_error("unable to create SDL renderer: %s\n", SDL_GetError()); |
1097 } | 1174 } |
1175 SDL_RendererInfo rinfo; | |
1176 SDL_GetRendererInfo(main_renderer, &rinfo); | |
1177 printf("SDL2 Render Driver: %s\n", rinfo.name); | |
1098 main_clip.x = main_clip.y = 0; | 1178 main_clip.x = main_clip.y = 0; |
1099 main_clip.w = main_width; | 1179 main_clip.w = main_width; |
1100 main_clip.h = main_height; | 1180 main_clip.h = main_height; |
1101 #ifndef DISABLE_OPENGL | 1181 #ifndef DISABLE_OPENGL |
1102 } | 1182 } |
1300 } | 1380 } |
1301 } | 1381 } |
1302 source_frame = 0; | 1382 source_frame = 0; |
1303 source_frame_count = frame_repeat[0]; | 1383 source_frame_count = frame_repeat[0]; |
1304 //sync samples with audio thread approximately every 8 lines | 1384 //sync samples with audio thread approximately every 8 lines |
1305 sync_samples = sync_to_audio ? buffer_samples : 8 * sample_rate / (source_hz * (VID_PAL ? 313 : 262)); | 1385 sync_samples = sync_to_audio ? buffer_samples : 8 * sample_rate / (source_hz * (std == VID_PAL ? 313 : 262)); |
1306 max_repeat++; | 1386 max_repeat++; |
1307 min_buffered = (((float)max_repeat * (float)sample_rate/(float)source_hz)/* / (float)buffer_samples*/);// + 0.9999; | 1387 min_buffered = (((float)max_repeat * (float)sample_rate/(float)source_hz)/* / (float)buffer_samples*/);// + 0.9999; |
1308 //min_buffered *= buffer_samples; | 1388 //min_buffered *= buffer_samples; |
1309 printf("Min samples buffered before audio start: %d\n", min_buffered); | 1389 printf("Min samples buffered before audio start: %d\n", min_buffered); |
1310 max_adjust = BASE_MAX_ADJUST / source_hz; | 1390 max_adjust = BASE_MAX_ADJUST / source_hz; |
1324 free(screenshot_path); | 1404 free(screenshot_path); |
1325 } | 1405 } |
1326 screenshot_path = path; | 1406 screenshot_path = path; |
1327 } | 1407 } |
1328 | 1408 |
1329 uint8_t render_create_window(char *caption, uint32_t width, uint32_t height) | 1409 uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler) |
1330 { | 1410 { |
1331 uint8_t win_idx = 0xFF; | 1411 uint8_t win_idx = 0xFF; |
1332 for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++) | 1412 for (int i = 0; i < num_textures - FRAMEBUFFER_USER_START; i++) |
1333 { | 1413 { |
1334 if (!extra_windows[i]) { | 1414 if (!extra_windows[i]) { |
1340 if (win_idx == 0xFF) { | 1420 if (win_idx == 0xFF) { |
1341 num_textures++; | 1421 num_textures++; |
1342 sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures)); | 1422 sdl_textures = realloc(sdl_textures, num_textures * sizeof(*sdl_textures)); |
1343 extra_windows = realloc(extra_windows, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_windows)); | 1423 extra_windows = realloc(extra_windows, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_windows)); |
1344 extra_renderers = realloc(extra_renderers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_renderers)); | 1424 extra_renderers = realloc(extra_renderers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*extra_renderers)); |
1425 close_handlers = realloc(close_handlers, (num_textures - FRAMEBUFFER_USER_START) * sizeof(*close_handlers)); | |
1345 win_idx = num_textures - FRAMEBUFFER_USER_START - 1; | 1426 win_idx = num_textures - FRAMEBUFFER_USER_START - 1; |
1346 } | 1427 } |
1347 extra_windows[win_idx] = SDL_CreateWindow(caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0); | 1428 extra_windows[win_idx] = SDL_CreateWindow(caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0); |
1348 if (!extra_windows[win_idx]) { | 1429 if (!extra_windows[win_idx]) { |
1349 goto fail_window; | 1430 goto fail_window; |
1355 uint8_t texture_idx = win_idx + FRAMEBUFFER_USER_START; | 1436 uint8_t texture_idx = win_idx + FRAMEBUFFER_USER_START; |
1356 sdl_textures[texture_idx] = SDL_CreateTexture(extra_renderers[win_idx], SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); | 1437 sdl_textures[texture_idx] = SDL_CreateTexture(extra_renderers[win_idx], SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); |
1357 if (!sdl_textures[texture_idx]) { | 1438 if (!sdl_textures[texture_idx]) { |
1358 goto fail_texture; | 1439 goto fail_texture; |
1359 } | 1440 } |
1441 close_handlers[win_idx] = close_handler; | |
1360 return texture_idx; | 1442 return texture_idx; |
1361 | 1443 |
1362 fail_texture: | 1444 fail_texture: |
1363 SDL_DestroyRenderer(extra_renderers[win_idx]); | 1445 SDL_DestroyRenderer(extra_renderers[win_idx]); |
1364 fail_renderer: | 1446 fail_renderer: |
1464 width -= overscan_left[video_standard] + overscan_right[video_standard]; | 1546 width -= overscan_left[video_standard] + overscan_right[video_standard]; |
1465 #ifndef DISABLE_OPENGL | 1547 #ifndef DISABLE_OPENGL |
1466 if (render_gl && which <= FRAMEBUFFER_EVEN) { | 1548 if (render_gl && which <= FRAMEBUFFER_EVEN) { |
1467 SDL_GL_MakeCurrent(main_window, main_context); | 1549 SDL_GL_MakeCurrent(main_window, main_context); |
1468 glBindTexture(GL_TEXTURE_2D, textures[which]); | 1550 glBindTexture(GL_TEXTURE_2D, textures[which]); |
1469 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]); | 1551 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]); |
1470 | 1552 |
1471 if (screenshot_file) { | 1553 if (screenshot_file) { |
1472 //properly supporting interlaced modes here is non-trivial, so only save the odd field for now | 1554 //properly supporting interlaced modes here is non-trivial, so only save the odd field for now |
1473 #ifndef DISABLE_ZLIB | 1555 #ifndef DISABLE_ZLIB |
1474 if (!strcasecmp(ext, "png")) { | 1556 if (!strcasecmp(ext, "png")) { |