comparison render_sdl.c @ 2685:da2e06c42d16

Add a compile-time flag to use RGB565 instead of ABGR/ARGB
author Michael Pavone <pavone@retrodev.com>
date Sun, 30 Mar 2025 00:06:53 -0700
parents 69c1093f8726
children 05915f01046d
comparison
equal deleted inserted replaced
2684:c649bcc18487 2685:da2e06c42d16
42 uint32_t width; 42 uint32_t width;
43 uint32_t height; 43 uint32_t height;
44 uint8_t num_static; 44 uint8_t num_static;
45 #ifndef DISABLE_OPENGL 45 #ifndef DISABLE_OPENGL
46 SDL_GLContext *gl_context; 46 SDL_GLContext *gl_context;
47 uint32_t *texture_buf; 47 pixel_t *texture_buf;
48 uint32_t tex_width; 48 uint32_t tex_width;
49 uint32_t tex_height; 49 uint32_t tex_height;
50 GLuint gl_texture[2]; 50 GLuint gl_texture[2];
51 GLuint *gl_static_images; 51 GLuint *gl_static_images;
52 GLuint vshader; 52 GLuint vshader;
92 }; 92 };
93 93
94 static uint8_t sync_src; 94 static uint8_t sync_src;
95 static uint32_t min_buffered; 95 static uint32_t min_buffered;
96 96
97 uint32_t **frame_buffers; 97 pixel_t **frame_buffers;
98 uint32_t num_buffers; 98 uint32_t num_buffers;
99 uint32_t buffer_storage; 99 uint32_t buffer_storage;
100 100
101 uint32_t render_min_buffered(void) 101 uint32_t render_min_buffered(void)
102 { 102 {
337 uint8_t render_fullscreen(void) 337 uint8_t render_fullscreen(void)
338 { 338 {
339 return is_fullscreen; 339 return is_fullscreen;
340 } 340 }
341 341
342 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) 342 pixel_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
343 { 343 {
344 #ifdef USE_RGB565
345 return r << 8 & 0xF800 | g << 3 & 0x07E0 | b >> 3;
346 #else
344 #ifdef USE_GLES 347 #ifdef USE_GLES
345 return 255UL << 24 | b << 16 | g << 8 | r; 348 return 255UL << 24 | b << 16 | g << 8 | r;
346 #else 349 #else
347 return 255UL << 24 | r << 16 | g << 8 | b; 350 return 255UL << 24 | r << 16 | g << 8 | b;
351 #endif
348 #endif 352 #endif
349 } 353 }
350 354
351 static uint8_t external_sync; 355 static uint8_t external_sync;
352 void render_set_external_sync(uint8_t ext_sync_on) 356 void render_set_external_sync(uint8_t ext_sync_on)
455 } 459 }
456 return ret; 460 return ret;
457 } 461 }
458 #endif 462 #endif
459 463
460 static uint32_t texture_buf[512 * 513]; 464 static pixel_t texture_buf[512 * 513];
461 #ifdef DISABLE_OPENGL 465 #ifdef DISABLE_OPENGL
466 #ifdef USE_RGB565
467 #define RENDER_FORMAT SDL_PIXELFORMAT_RGB565
468 #else
462 #define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888 469 #define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888
463 #else 470 #endif
471 #else //DISABLE_OPENGL
472 #ifdef USE_RGB565
473 #define INTERNAL_FORMAT GL_RGB
474 #define SRC_FORMAT GL_RGB
475 #define SRC_TYPE GL_UNSIGNED_SHORT_5_6_5
476 #define RENDER_FORMAT SDL_PIXELFORMAT_RGB565
477 #else //USE_RGB565
478 #define SRC_TYPE GL_UNSIGNED_BYTE
464 #ifdef USE_GLES 479 #ifdef USE_GLES
465 #define INTERNAL_FORMAT GL_RGBA 480 #define INTERNAL_FORMAT GL_RGBA
466 #define SRC_FORMAT GL_RGBA 481 #define SRC_FORMAT GL_RGBA
467 #define RENDER_FORMAT SDL_PIXELFORMAT_ABGR8888 482 #define RENDER_FORMAT SDL_PIXELFORMAT_ABGR8888
468 #else 483 #else //USE_GLES
469 #define INTERNAL_FORMAT GL_RGBA8 484 #define INTERNAL_FORMAT GL_RGBA8
470 #define SRC_FORMAT GL_BGRA 485 #define SRC_FORMAT GL_BGRA
471 #define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888 486 #define RENDER_FORMAT SDL_PIXELFORMAT_ARGB8888
472 #endif 487 #endif //USE_GLES
488 #endif //USE_RGB565
489
490 #ifdef USE_GLES
491 #define SRC_FORMAT32 GL_RGBA
492 #else
493 #define SRC_FORMAT32 GL_BGRA
494 #endif
495
473 static void gl_setup() 496 static void gl_setup()
474 { 497 {
475 tern_val def = {.ptrval = "linear"}; 498 tern_val def = {.ptrval = "linear"};
476 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval; 499 char *scaling = tern_find_path_default(config, "video\0scaling\0", def, TVAL_PTR).ptrval;
477 GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR; 500 GLint filter = strcmp(scaling, "linear") ? GL_NEAREST : GL_LINEAR;
492 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); 515 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
493 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 516 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
494 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 517 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
495 if (i < 2) { 518 if (i < 2) {
496 //TODO: Fixme for PAL + invalid display mode 519 //TODO: Fixme for PAL + invalid display mode
497 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, tex_width, tex_height, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, texture_buf); 520 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, tex_width, tex_height, 0, SRC_FORMAT, SRC_TYPE, texture_buf);
498 } else { 521 } else {
499 uint32_t blank = 255UL << 24; 522 pixel_t blank = render_map_color(0, 0, 0);
500 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, &blank); 523 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, SRC_TYPE, &blank);
501 } 524 }
502 } 525 }
503 glGenBuffers(2, buffers); 526 glGenBuffers(2, buffers);
504 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); 527 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
505 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); 528 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
536 glDeleteShader(vshader); 559 glDeleteShader(vshader);
537 glDeleteShader(fshader); 560 glDeleteShader(fshader);
538 glDeleteBuffers(2, buffers); 561 glDeleteBuffers(2, buffers);
539 glDeleteTextures(3, textures); 562 glDeleteTextures(3, textures);
540 } 563 }
541 #endif 564 #endif //DISABLE_OPENGL
542 565
543 static uint8_t texture_init; 566 static uint8_t texture_init;
544 static void render_alloc_surfaces() 567 static void render_alloc_surfaces()
545 { 568 {
546 if (texture_init) { 569 if (texture_init) {
1188 if (!num_buffers && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) { 1211 if (!num_buffers && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) {
1189 frame_mutex = SDL_CreateMutex(); 1212 frame_mutex = SDL_CreateMutex();
1190 free_buffer_mutex = SDL_CreateMutex(); 1213 free_buffer_mutex = SDL_CreateMutex();
1191 frame_ready = SDL_CreateCond(); 1214 frame_ready = SDL_CreateCond();
1192 buffer_storage = 4; 1215 buffer_storage = 4;
1193 frame_buffers = calloc(buffer_storage, sizeof(uint32_t*)); 1216 frame_buffers = calloc(buffer_storage, sizeof(pixel_t*));
1194 frame_buffers[0] = texture_buf; 1217 frame_buffers[0] = texture_buf;
1195 num_buffers = 1; 1218 num_buffers = 1;
1196 } 1219 }
1197 1220
1198 const char *vsync; 1221 const char *vsync;
1686 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1709 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1687 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1710 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1688 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1711 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1689 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1712 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1690 if (i) { 1713 if (i) {
1691 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, extras[win_idx].color); 1714 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, SRC_TYPE, extras[win_idx].color);
1692 } else { 1715 } else {
1693 extras[win_idx].tex_width = width; 1716 extras[win_idx].tex_width = width;
1694 extras[win_idx].tex_height = height; 1717 extras[win_idx].tex_height = height;
1695 char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", (tern_val){.ptrval = "off"}, TVAL_PTR).ptrval; 1718 char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", (tern_val){.ptrval = "off"}, TVAL_PTR).ptrval;
1696 if (strcmp(npot_textures, "on")) { 1719 if (strcmp(npot_textures, "on")) {
1697 extras[win_idx].tex_width = nearest_pow2(width); 1720 extras[win_idx].tex_width = nearest_pow2(width);
1698 extras[win_idx].tex_height = nearest_pow2(height); 1721 extras[win_idx].tex_height = nearest_pow2(height);
1699 } 1722 }
1700 extras[win_idx].texture_buf = calloc(extras[win_idx].tex_width * extras[win_idx].tex_height, sizeof(uint32_t)); 1723 extras[win_idx].texture_buf = calloc(PITCH_PIXEL_T(extras[win_idx].tex_width) * extras[win_idx].tex_height, sizeof(pixel_t));
1701 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, extras[win_idx].tex_width, extras[win_idx].tex_height, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, extras[win_idx].texture_buf); 1724 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, extras[win_idx].tex_width, extras[win_idx].tex_height, 0, SRC_FORMAT, SRC_TYPE, extras[win_idx].texture_buf);
1702 } 1725 }
1703 } 1726 }
1704 glGenBuffers(3, extras[win_idx].gl_buffers); 1727 glGenBuffers(3, extras[win_idx].gl_buffers);
1705 glBindBuffer(GL_ARRAY_BUFFER, extras[win_idx].gl_buffers[0]); 1728 glBindBuffer(GL_ARRAY_BUFFER, extras[win_idx].gl_buffers[0]);
1706 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data_default), vertex_data_default, GL_STATIC_DRAW); 1729 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data_default), vertex_data_default, GL_STATIC_DRAW);
1874 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1897 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1875 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1898 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1876 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1899 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1877 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1900 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1878 //TODO: maybe make this respect the npot texture setting? 1901 //TODO: maybe make this respect the npot texture setting?
1879 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, width, height, 0, SRC_FORMAT, GL_UNSIGNED_BYTE, pixels); 1902 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, width, height, 0, SRC_FORMAT32, GL_UNSIGNED_BYTE, pixels);
1880 } else 1903 } else
1881 #endif 1904 #endif
1882 { 1905 {
1883 extra->static_images[img_index] = SDL_CreateTexture(extra->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height); 1906 extra->static_images[img_index] = SDL_CreateTexture(extra->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height);
1884 SDL_UpdateTexture(extra->static_images[img_index], NULL, pixels, sizeof(uint32_t) * width); 1907 SDL_UpdateTexture(extra->static_images[img_index], NULL, pixels, sizeof(pixel_t) * width);
1885 } 1908 }
1886 free(pixels); 1909 free(pixels);
1887 return img_index; 1910 return img_index;
1888 } 1911 }
1889 1912
1961 extra_update_verts(extra, x, y, width, height); 1984 extra_update_verts(extra, x, y, width, height);
1962 extra->color[0] = b; 1985 extra->color[0] = b;
1963 extra->color[1] = g; 1986 extra->color[1] = g;
1964 extra->color[2] = r; 1987 extra->color[2] = r;
1965 glBindTexture(GL_TEXTURE_2D, extra->gl_texture[1]); 1988 glBindTexture(GL_TEXTURE_2D, extra->gl_texture[1]);
1966 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, SRC_FORMAT, GL_UNSIGNED_BYTE, extra->color); 1989 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, SRC_FORMAT, SRC_TYPE, extra->color);
1967 extra_draw_quad(extra, extra->gl_texture[1], 1.0f, 1.0f); 1990 extra_draw_quad(extra, extra->gl_texture[1], 1.0f, 1.0f);
1968 } 1991 }
1969 #endif 1992 #endif
1970 } 1993 }
1971 1994
1980 SDL_GL_SwapWindow(extras[win_idx].win); 2003 SDL_GL_SwapWindow(extras[win_idx].win);
1981 } 2004 }
1982 #endif 2005 #endif
1983 } 2006 }
1984 2007
1985 uint32_t *locked_pixels; 2008 pixel_t *locked_pixels;
1986 uint32_t locked_pitch; 2009 uint32_t locked_pitch;
1987 uint32_t *render_get_framebuffer(uint8_t which, int *pitch) 2010 pixel_t *render_get_framebuffer(uint8_t which, int *pitch)
1988 { 2011 {
1989 if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) { 2012 if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) {
1990 *pitch = LINEBUF_SIZE * sizeof(uint32_t); 2013 *pitch = PITCH_BYTES(LINEBUF_SIZE);
1991 uint32_t *buffer; 2014 pixel_t *buffer;
1992 SDL_LockMutex(free_buffer_mutex); 2015 SDL_LockMutex(free_buffer_mutex);
1993 if (num_buffers) { 2016 if (num_buffers) {
1994 buffer = frame_buffers[--num_buffers]; 2017 buffer = frame_buffers[--num_buffers];
1995 } else { 2018 } else {
1996 buffer = calloc(tex_width*(tex_height + 1), sizeof(uint32_t)); 2019 buffer = calloc(tex_width*(tex_height + 1), sizeof(pixel_t));
1997 } 2020 }
1998 SDL_UnlockMutex(free_buffer_mutex); 2021 SDL_UnlockMutex(free_buffer_mutex);
1999 locked_pixels = buffer; 2022 locked_pixels = buffer;
2000 return buffer; 2023 return buffer;
2001 } 2024 }
2002 #ifndef DISABLE_OPENGL 2025 #ifndef DISABLE_OPENGL
2003 if (render_gl && which <= FRAMEBUFFER_EVEN) { 2026 if (render_gl && which <= FRAMEBUFFER_EVEN) {
2004 *pitch = LINEBUF_SIZE * sizeof(uint32_t); 2027 *pitch = PITCH_BYTES(LINEBUF_SIZE);
2005 return texture_buf; 2028 return texture_buf;
2006 } else if (render_gl && which >= FRAMEBUFFER_USER_START) { 2029 } else if (render_gl && which >= FRAMEBUFFER_USER_START) {
2007 uint8_t win_idx = which - FRAMEBUFFER_USER_START; 2030 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
2008 *pitch = extras[win_idx].width * sizeof(uint32_t); 2031 *pitch = PITCH_BYTES(extras[win_idx].width);
2009 return extras[win_idx].texture_buf; 2032 return extras[win_idx].texture_buf;
2010 } else { 2033 } else {
2011 #endif 2034 #endif
2012 if (which == FRAMEBUFFER_UI && !sdl_textures[which]) { 2035 if (which == FRAMEBUFFER_UI && !sdl_textures[which]) {
2013 sdl_textures[which] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, main_width, main_height); 2036 sdl_textures[which] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, main_width, main_height);
2028 warning("Failed to lock texture: %s\n", SDL_GetError()); 2051 warning("Failed to lock texture: %s\n", SDL_GetError());
2029 return NULL; 2052 return NULL;
2030 } 2053 }
2031 static uint8_t last; 2054 static uint8_t last;
2032 if (which <= FRAMEBUFFER_EVEN) { 2055 if (which <= FRAMEBUFFER_EVEN) {
2033 locked_pixels = (uint32_t *)pixels; 2056 locked_pixels = (pixel_t *)pixels;
2034 if (which == FRAMEBUFFER_EVEN) { 2057 if (which == FRAMEBUFFER_EVEN) {
2035 pixels += *pitch; 2058 pixels += *pitch;
2036 } 2059 }
2037 locked_pitch = *pitch; 2060 locked_pitch = *pitch;
2038 if (which != last) { 2061 if (which != last) {
2039 *pitch *= 2; 2062 *pitch *= 2;
2040 } 2063 }
2041 last = which; 2064 last = which;
2042 } 2065 }
2043 return (uint32_t *)pixels; 2066 return (pixel_t *)pixels;
2044 #ifndef DISABLE_OPENGL 2067 #ifndef DISABLE_OPENGL
2045 } 2068 }
2046 #endif 2069 #endif
2047 } 2070 }
2048 2071
2049 static void release_buffer(uint32_t *buffer) 2072 static void release_buffer(pixel_t *buffer)
2050 { 2073 {
2051 SDL_LockMutex(free_buffer_mutex); 2074 SDL_LockMutex(free_buffer_mutex);
2052 if (num_buffers == buffer_storage) { 2075 if (num_buffers == buffer_storage) {
2053 buffer_storage *= 2; 2076 buffer_storage *= 2;
2054 frame_buffers = realloc(frame_buffers, sizeof(uint32_t*)*buffer_storage); 2077 frame_buffers = realloc(frame_buffers, sizeof(pixel_t*)*buffer_storage);
2055 } 2078 }
2056 frame_buffers[num_buffers++] = buffer; 2079 frame_buffers[num_buffers++] = buffer;
2057 SDL_UnlockMutex(free_buffer_mutex); 2080 SDL_UnlockMutex(free_buffer_mutex);
2058 } 2081 }
2059 2082
2064 #define FPS_INTERVAL 1000 2087 #define FPS_INTERVAL 1000
2065 #endif 2088 #endif
2066 2089
2067 static uint32_t last_width, last_height; 2090 static uint32_t last_width, last_height;
2068 static uint8_t interlaced, last_field; 2091 static uint8_t interlaced, last_field;
2069 static void process_framebuffer(uint32_t *buffer, uint8_t which, int width) 2092 static void process_framebuffer(pixel_t *buffer, uint8_t which, int width)
2070 { 2093 {
2071 if (sync_src == SYNC_VIDEO && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) { 2094 if (sync_src == SYNC_VIDEO && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) {
2072 source_frame++; 2095 source_frame++;
2073 if (source_frame >= source_hz) { 2096 if (source_frame >= source_hz) {
2074 source_frame = 0; 2097 source_frame = 0;
2098 } 2121 }
2099 free(screenshot_path); 2122 free(screenshot_path);
2100 screenshot_path = NULL; 2123 screenshot_path = NULL;
2101 } 2124 }
2102 interlaced = last_field != which; 2125 interlaced = last_field != which;
2103 buffer += overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard]; 2126 buffer += overscan_left[video_standard] + PITCH_PIXEL_T(LINEBUF_SIZE) * overscan_top[video_standard];
2104 } 2127 }
2105 #ifndef DISABLE_OPENGL 2128 #ifndef DISABLE_OPENGL
2106 if (render_gl && which <= FRAMEBUFFER_EVEN) { 2129 if (render_gl && which <= FRAMEBUFFER_EVEN) {
2107 SDL_GL_MakeCurrent(main_window, main_context); 2130 SDL_GL_MakeCurrent(main_window, main_context);
2108 glBindTexture(GL_TEXTURE_2D, textures[which]); 2131 glBindTexture(GL_TEXTURE_2D, textures[which]);
2109 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, SRC_FORMAT, GL_UNSIGNED_BYTE, buffer); 2132 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, LINEBUF_SIZE, height, SRC_FORMAT, SRC_TYPE, buffer);
2110 2133
2111 if (screenshot_file) { 2134 if (screenshot_file) {
2112 //properly supporting interlaced modes here is non-trivial, so only save the odd field for now 2135 //properly supporting interlaced modes here is non-trivial, so only save the odd field for now
2113 #ifndef DISABLE_ZLIB 2136 #ifndef DISABLE_ZLIB
2114 if (!strcasecmp(ext, "png")) { 2137 if (!strcasecmp(ext, "png")) {
2115 free(ext); 2138 free(ext);
2116 save_png(screenshot_file, buffer, width, height, LINEBUF_SIZE*sizeof(uint32_t)); 2139 save_png(screenshot_file, buffer, width, height, PITCH_BYTES(LINEBUF_SIZE));
2117 } else { 2140 } else {
2118 free(ext); 2141 free(ext);
2119 #endif 2142 #endif
2120 save_ppm(screenshot_file, buffer, width, height, LINEBUF_SIZE*sizeof(uint32_t)); 2143 save_ppm(screenshot_file, buffer, width, height, PITCH_BYTES(LINEBUF_SIZE));
2121 #ifndef DISABLE_ZLIB 2144 #ifndef DISABLE_ZLIB
2122 } 2145 }
2123 #endif 2146 #endif
2124 } 2147 }
2125 #ifndef DISABLE_ZLIB 2148 #ifndef DISABLE_ZLIB
2126 if (apng_file) { 2149 if (apng_file) {
2127 if (!apng) { 2150 if (!apng) {
2128 //TODO: more precise frame rate 2151 //TODO: more precise frame rate
2129 apng = start_apng(apng_file, width, height, video_standard == VID_PAL ? 50.0 : 60.0); 2152 apng = start_apng(apng_file, width, height, video_standard == VID_PAL ? 50.0 : 60.0);
2130 } 2153 }
2131 save_png24_frame(apng_file, buffer, apng, width, height, LINEBUF_SIZE*sizeof(uint32_t)); 2154 save_png24_frame(apng_file, buffer, apng, width, height, PITCH_BYTES(LINEBUF_SIZE));
2132 } 2155 }
2133 #endif 2156 #endif
2134 } else if (render_gl && which >= FRAMEBUFFER_USER_START) { 2157 } else if (render_gl && which >= FRAMEBUFFER_USER_START) {
2135 uint8_t win_idx = which - FRAMEBUFFER_USER_START; 2158 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
2136 SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context); 2159 SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
2137 glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture[0]); 2160 glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture[0]);
2138 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extras[win_idx].width, extras[win_idx].height, SRC_FORMAT, GL_UNSIGNED_BYTE, buffer); 2161 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extras[win_idx].width, extras[win_idx].height, SRC_FORMAT, SRC_TYPE, buffer);
2139 } else { 2162 } else {
2140 #endif 2163 #endif
2141 uint32_t shot_height = height; 2164 uint32_t shot_height = height;
2142 //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers 2165 //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers
2143 if (which <= FRAMEBUFFER_EVEN && last_field != which) { 2166 if (which <= FRAMEBUFFER_EVEN && last_field != which) {
2296 source_frame_count = frame_repeat[source_frame]; 2319 source_frame_count = frame_repeat[source_frame];
2297 } 2320 }
2298 } 2321 }
2299 2322
2300 typedef struct { 2323 typedef struct {
2301 uint32_t *buffer; 2324 pixel_t *buffer;
2302 int width; 2325 int width;
2303 uint8_t which; 2326 uint8_t which;
2304 } frame; 2327 } frame;
2305 frame frame_queue[4]; 2328 frame frame_queue[4];
2306 int frame_queue_len, frame_queue_read, frame_queue_write; 2329 int frame_queue_len, frame_queue_read, frame_queue_write;
2335 }; 2358 };
2336 frame_queue_write &= 0x3; 2359 frame_queue_write &= 0x3;
2337 frame_queue_len++; 2360 frame_queue_len++;
2338 SDL_CondSignal(frame_ready); 2361 SDL_CondSignal(frame_ready);
2339 SDL_UnlockMutex(frame_mutex); 2362 SDL_UnlockMutex(frame_mutex);
2363 #ifdef __ANDROID__
2364 if (which <= FRAMEBUFFER_EVEN) {
2365 static uint32_t frame_counter, start;
2366 frame_counter++;
2367 uint32_t last_frame= SDL_GetTicks();
2368 if ((last_frame - start) > FPS_INTERVAL) {
2369 if (start && (last_frame-start)) {
2370 debug_message("%s - %.1f fps (emulated)", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0));
2371 }
2372 start = last_frame;
2373 frame_counter = 0;
2374 }
2375 }
2376 #endif
2340 return; 2377 return;
2341 } 2378 }
2342 //TODO: Maybe fixme for render API 2379 //TODO: Maybe fixme for render API
2343 process_framebuffer(which < FRAMEBUFFER_USER_START ? texture_buf : extras[which - FRAMEBUFFER_USER_START].texture_buf, which, width); 2380 process_framebuffer(which < FRAMEBUFFER_USER_START ? texture_buf : extras[which - FRAMEBUFFER_USER_START].texture_buf, which, width);
2344 } 2381 }