diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index 5bf67b7f6..0900bf8c5 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -88,7 +88,6 @@ static void make_bg(int no_scale, int from_screen) int h = g_menubg_src_h ? g_menubg_src_h : g_screen_height; int pp = g_menubg_src_pp ? g_menubg_src_pp : g_screen_ppitch; short *dst; - int x, y; if (from_screen) { src = g_screen_ptr; @@ -104,24 +103,24 @@ static void make_bg(int no_scale, int from_screen) if (!no_scale && g_menuscreen_w / w >= 2 && g_menuscreen_h / h >= 2) { int xf = g_menuscreen_w / w, yf = g_menuscreen_h / h; - int f = no_scale ? 1 : xf < yf ? xf : yf; - int xs = f * w, ys = f * h; - unsigned short t; - int i, j, k, l; + int f = no_scale ? 1 : xf < yf ? xf : yf, xs = f * w, ys = f * h; + int x = (g_menuscreen_w - xs)/2, y = (g_menuscreen_h - ys)/2; + uint16_t *p = (uint16_t *)g_menubg_ptr; + uint16_t *q = (uint16_t *)src; - x = (g_menuscreen_w - xs)/2, y = (g_menuscreen_h - ys)/2; - dst = (short *)g_menubg_ptr + y * g_menuscreen_w + x; + int i, j, k, l; + p += y * g_menuscreen_pp + x; for (i = 0; i < h; i++) { - for (j = 0; j < w; j++, src++) { - t = (PXMASKH(*src,1)>>1) - (PXMASKH(*src,3)>>3); + for (j = 0; j < w; j++, q++) { + uint16_t t = (PXMASKH(*q,1)>>1) - (PXMASKH(*q,3)>>3); for (l = 0; l < f; l++) - *dst++ = t; + *p++ = t; } - src += pp - w; - dst += g_menuscreen_w - xs; + p += g_menuscreen_pp - xs; + q += pp - w; for (k = 1; k < f; k++) { - memcpy(dst, dst-g_menuscreen_w, g_menuscreen_w*2); - dst += g_menuscreen_w; + memcpy(p, p-g_menuscreen_pp, g_menuscreen_w*2); + p += g_menuscreen_pp; } } return; diff --git a/platform/common/plat_sdl.c b/platform/common/plat_sdl.c index cdcaee7a8..8ba3a8c9b 100644 --- a/platform/common/plat_sdl.c +++ b/platform/common/plat_sdl.c @@ -174,6 +174,30 @@ void rgb565_to_uyvy(void *d, const void *s, int w, int h, int pitch, int dpitch, } } +void copy_intscale(void *dst, int w, int h, int pp, void *src, int sw, int sh, int spp) +{ + int xf = w / sw, yf = h / sh; + int f = xf < yf ? xf : yf, xs = f * sw, ys = f * sh; + int x = (w - xs)/2, y = (h - ys)/2; + uint16_t *p = (uint16_t *)dst; + uint16_t *q = (uint16_t *)src; + + // copy 16bit image with scaling by an integer factor + int i, j, k, l; + p += y * pp + x; + for (i = 0; i < sh; i++) { + for (j = 0; j < sw; j++, q++) + for (l = 0; l < f; l++) + *p++ = *q; + p += pp - xs; + q += spp - sw; + for (k = 1; k < f; k++) { + memcpy(p, p-pp, w*2); + p += pp; + } + } +} + static int clear_buf_cnt, clear_stat_cnt; static void resize_buffers(void) @@ -188,22 +212,39 @@ static void resize_buffers(void) void plat_video_set_size(int w, int h) { + if ((plat_sdl_overlay || plat_sdl_gl_active) && + (w != g_screen_width || h != g_screen_height)) { + // scale to the window, but mind aspect ratio (scaled to 4:3) + if (g_menuscreen_w * /*h*/w*3/4 >= g_menuscreen_h * w) + w = (w * 3 * g_menuscreen_w/g_menuscreen_h)/4 & ~1; + else + h = (h * 4 * g_menuscreen_h/g_menuscreen_w)/3 & ~1; + } + if (area.w != w || area.h != h) { area = (struct area) { w, h }; - if (plat_sdl_change_video_mode(w, h, 0) < 0) { - // failed, revert to original resolution - area = (struct area) { g_screen_width,g_screen_height }; - plat_sdl_change_video_mode(g_screen_width, g_screen_height, 0); + + if (plat_sdl_overlay || plat_sdl_gl_active || !plat_sdl_is_windowed()) { + // create surface for overlays, or try using a hw scaler + if (plat_sdl_change_video_mode(w, h, 0) < 0) { + // failed, revert to original resolution + area = (struct area) { g_screen_width,g_screen_height }; + plat_sdl_change_video_mode(g_screen_width, g_screen_height, 0); + } } - if (!plat_sdl_overlay && !plat_sdl_gl_active) { + if (plat_sdl_overlay || plat_sdl_gl_active || + plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2) { + // use shadow buffer for overlays and sw integer scaling + g_screen_width = area.w; + g_screen_height = area.h; + g_screen_ppitch = area.w; + g_screen_ptr = shadow_fb; + } else { + // unscaled SDL window buffer can be used directly g_screen_width = plat_sdl_screen->w; g_screen_height = plat_sdl_screen->h; g_screen_ppitch = plat_sdl_screen->pitch/2; g_screen_ptr = plat_sdl_screen->pixels; - } else { - g_screen_width = w; - g_screen_height = h; - g_screen_ppitch = w; } } } @@ -236,15 +277,24 @@ void plat_video_flip(void) gl_flip(shadow_fb, g_screen_ppitch, g_screen_height); } else { - if (SDL_MUSTLOCK(plat_sdl_screen)) { + int copy = g_screen_ptr != plat_sdl_screen->pixels; + if (copy) + copy_intscale(plat_sdl_screen->pixels, plat_sdl_screen->w, + plat_sdl_screen->h, plat_sdl_screen->pitch/2, + shadow_fb, area.w, area.h, area.w); + + if (SDL_MUSTLOCK(plat_sdl_screen)) SDL_UnlockSurface(plat_sdl_screen); - SDL_Flip(plat_sdl_screen); + SDL_Flip(plat_sdl_screen); + if (SDL_MUSTLOCK(plat_sdl_screen)) SDL_LockSurface(plat_sdl_screen); - } else - SDL_Flip(plat_sdl_screen); - g_screen_ppitch = plat_sdl_screen->pitch/2; - g_screen_ptr = plat_sdl_screen->pixels; - plat_video_set_buffer(g_screen_ptr); + + if (!copy) { + g_screen_ppitch = plat_sdl_screen->pitch/2; + g_screen_ptr = plat_sdl_screen->pixels; + plat_video_set_buffer(g_screen_ptr); + } + if (clear_buf_cnt) { memset(g_screen_ptr, 0, plat_sdl_screen->pitch*plat_sdl_screen->h); clear_buf_cnt--; @@ -277,7 +327,8 @@ void plat_video_clear_status(void) void plat_video_clear_buffers(void) { - if (plat_sdl_overlay || plat_sdl_gl_active) + if (plat_sdl_overlay || plat_sdl_gl_active || + plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2) memset(shadow_fb, 0, g_menuscreen_w * g_menuscreen_h * 2); else { memset(g_screen_ptr, 0, plat_sdl_screen->pitch*plat_sdl_screen->h); @@ -366,40 +417,48 @@ void plat_video_loop_prepare(void) } g_screen_ppitch = g_screen_width; g_screen_ptr = shadow_fb; + plat_video_set_size(g_screen_width, g_screen_height); } else { - g_screen_width = plat_sdl_screen->w; - g_screen_height = plat_sdl_screen->h; - g_screen_ppitch = plat_sdl_screen->pitch/2; + if (plat_sdl_is_windowed() && + (plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2)) { + // shadow buffer for integer scaling + g_screen_width = 320; + g_screen_height = 240; + g_screen_ppitch = 320; + g_screen_ptr = shadow_fb; + } else { + // no scaling needed, use screen buffer directly + g_screen_width = plat_sdl_screen->w; + g_screen_height = plat_sdl_screen->h; + g_screen_ppitch = plat_sdl_screen->pitch/2; + g_screen_ptr = plat_sdl_screen->pixels; + } + plat_video_set_size(g_screen_width, g_screen_height); + if (SDL_MUSTLOCK(plat_sdl_screen)) SDL_LockSurface(plat_sdl_screen); - g_screen_ptr = plat_sdl_screen->pixels; } - plat_video_set_size(g_screen_width, g_screen_height); plat_video_set_buffer(g_screen_ptr); } static void plat_sdl_resize(int w, int h) { // take over new settings - if (plat_sdl_screen->w != area.w || plat_sdl_screen->h != area.h) { #if defined(__OPENDINGUX__) - if (currentConfig.vscaling != EOPT_SCALE_HW && - plat_sdl_screen->w == 320 && - plat_sdl_screen->h == 480) { - g_menuscreen_h = 240; - g_menuscreen_w = 320; - - } else + if (currentConfig.vscaling != EOPT_SCALE_HW && + plat_sdl_screen->w == 320 && plat_sdl_screen->h == 480) { + g_menuscreen_h = 240; + g_menuscreen_w = 320; + } else #endif - { - g_menuscreen_h = plat_sdl_screen->h; - g_menuscreen_w = plat_sdl_screen->w; - } - resize_buffers(); - rendstatus_old = -1; + { + g_menuscreen_h = plat_sdl_screen->h; + g_menuscreen_w = plat_sdl_screen->w; } + resize_buffers(); + rendstatus_old = -1; } static void plat_sdl_quit(void)