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")) {