From d80cb20bd0a91e97f6e7757911cf607f7b06832c Mon Sep 17 00:00:00 2001 From: kub Date: Sun, 9 Feb 2025 19:49:45 +0100 Subject: [PATCH] sdl, improve handling of window resizing --- Makefile | 2 +- platform/common/plat_sdl.c | 214 ++++++++++++++++++++++--------------- platform/libpicofe | 2 +- 3 files changed, 130 insertions(+), 88 deletions(-) diff --git a/Makefile b/Makefile index 76d01178..5cd200ba 100644 --- a/Makefile +++ b/Makefile @@ -183,7 +183,7 @@ else LDFLAGS += -lEGL -lGLESv2 # on raspi GLESv1_CM is included in GLESv2 endif OBJS += platform/linux/emu.o platform/linux/blit.o # FIXME -OBJS += platform/common/plat_sdl.o platform/common/input_sdlkbd.o +OBJS += platform/common/plat_sdl.o platform/common/inputmap_kbd.o OBJS += platform/libpicofe/plat_sdl.o platform/libpicofe/in_sdl.o OBJS += platform/libpicofe/linux/plat.o USE_FRONTEND = 1 diff --git a/platform/common/plat_sdl.c b/platform/common/plat_sdl.c index 405da643..84902128 100644 --- a/platform/common/plat_sdl.c +++ b/platform/common/plat_sdl.c @@ -87,91 +87,91 @@ static struct uyvy { uint32_t y:8; uint32_t vyu:24; } yuv_uyvy[65536]; void bgr_to_uyvy_init(void) { - int i, v; - - /* init yuv converter: - y0 = (int)((0.299f * r0) + (0.587f * g0) + (0.114f * b0)); - y1 = (int)((0.299f * r1) + (0.587f * g1) + (0.114f * b1)); - u = (int)(8 * 0.565f * (b0 - y0)) + 128; - v = (int)(8 * 0.713f * (r0 - y0)) + 128; - */ - for (i = 0; i < 32; i++) { - yuv_ry[i] = (int)(0.299f * i * 65536.0f + 0.5f); - yuv_gy[i] = (int)(0.587f * i * 65536.0f + 0.5f); - yuv_by[i] = (int)(0.114f * i * 65536.0f + 0.5f); - } - for (i = -32; i < 32; i++) { - v = (int)(8 * 0.565f * i) + 128; - if (v < 0) - v = 0; - if (v > 255) - v = 255; - yuv_u[i + 32] = v; - v = (int)(8 * 0.713f * i) + 128; - if (v < 0) - v = 0; - if (v > 255) - v = 255; - yuv_v[i + 32] = v; - } - // valid Y range seems to be 16..235 - for (i = 0; i < 256; i++) { - yuv_y[i] = 16 + 219 * i / 32; - } - // everything combined into one large array for speed - for (i = 0; i < 65536; i++) { - int r = (i >> 11) & 0x1f, g = (i >> 6) & 0x1f, b = (i >> 0) & 0x1f; - int y = (yuv_ry[r] + yuv_gy[g] + yuv_by[b]) >> 16; - yuv_uyvy[i].y = yuv_y[y]; + int i, v; + + /* init yuv converter: + y0 = (int)((0.299f * r0) + (0.587f * g0) + (0.114f * b0)); + y1 = (int)((0.299f * r1) + (0.587f * g1) + (0.114f * b1)); + u = (int)(8 * 0.565f * (b0 - y0)) + 128; + v = (int)(8 * 0.713f * (r0 - y0)) + 128; + */ + for (i = 0; i < 32; i++) { + yuv_ry[i] = (int)(0.299f * i * 65536.0f + 0.5f); + yuv_gy[i] = (int)(0.587f * i * 65536.0f + 0.5f); + yuv_by[i] = (int)(0.114f * i * 65536.0f + 0.5f); + } + for (i = -32; i < 32; i++) { + v = (int)(8 * 0.565f * i) + 128; + if (v < 0) + v = 0; + if (v > 255) + v = 255; + yuv_u[i + 32] = v; + v = (int)(8 * 0.713f * i) + 128; + if (v < 0) + v = 0; + if (v > 255) + v = 255; + yuv_v[i + 32] = v; + } + // valid Y range seems to be 16..235 + for (i = 0; i < 256; i++) { + yuv_y[i] = 16 + 219 * i / 32; + } + // everything combined into one large array for speed + for (i = 0; i < 65536; i++) { + int r = (i >> 11) & 0x1f, g = (i >> 6) & 0x1f, b = (i >> 0) & 0x1f; + int y = (yuv_ry[r] + yuv_gy[g] + yuv_by[b]) >> 16; + yuv_uyvy[i].y = yuv_y[y]; #if CPU_IS_LE - yuv_uyvy[i].vyu = (yuv_v[r-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[b-y + 32]; + yuv_uyvy[i].vyu = (yuv_v[r-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[b-y + 32]; #else - yuv_uyvy[i].vyu = (yuv_v[b-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[r-y + 32]; + yuv_uyvy[i].vyu = (yuv_v[b-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[r-y + 32]; #endif - } + } } void rgb565_to_uyvy(void *d, const void *s, int w, int h, int pitch, int dpitch, int x2) { - uint32_t *dst = d; - const uint16_t *src = s; - int i; - - if (x2) while (h--) { - for (i = w; i >= 4; src += 4, dst += 4, i -= 4) - { - struct uyvy *uyvy0 = yuv_uyvy + src[0], *uyvy1 = yuv_uyvy + src[1]; - struct uyvy *uyvy2 = yuv_uyvy + src[2], *uyvy3 = yuv_uyvy + src[3]; + uint32_t *dst = d; + const uint16_t *src = s; + int i; + + if (x2) while (h--) { + for (i = w; i >= 4; src += 4, dst += 4, i -= 4) + { + struct uyvy *uyvy0 = yuv_uyvy + src[0], *uyvy1 = yuv_uyvy + src[1]; + struct uyvy *uyvy2 = yuv_uyvy + src[2], *uyvy3 = yuv_uyvy + src[3]; #if CPU_IS_LE - dst[0] = (uyvy0->y << 24) | uyvy0->vyu; - dst[1] = (uyvy1->y << 24) | uyvy1->vyu; - dst[2] = (uyvy2->y << 24) | uyvy2->vyu; - dst[3] = (uyvy3->y << 24) | uyvy3->vyu; + dst[0] = (uyvy0->y << 24) | uyvy0->vyu; + dst[1] = (uyvy1->y << 24) | uyvy1->vyu; + dst[2] = (uyvy2->y << 24) | uyvy2->vyu; + dst[3] = (uyvy3->y << 24) | uyvy3->vyu; #else - dst[0] = uyvy0->y | (uyvy0->vyu << 8); - dst[1] = uyvy1->y | (uyvy1->vyu << 8); - dst[2] = uyvy2->y | (uyvy2->vyu << 8); - dst[3] = uyvy3->y | (uyvy3->vyu << 8); + dst[0] = uyvy0->y | (uyvy0->vyu << 8); + dst[1] = uyvy1->y | (uyvy1->vyu << 8); + dst[2] = uyvy2->y | (uyvy2->vyu << 8); + dst[3] = uyvy3->y | (uyvy3->vyu << 8); #endif - } - src += pitch - (w-i); - dst += (dpitch - 2*(w-i))/2; - } else while (h--) { - for (i = w; i >= 4; src += 4, dst += 2, i -= 4) - { - struct uyvy *uyvy0 = yuv_uyvy + src[0], *uyvy1 = yuv_uyvy + src[1]; - struct uyvy *uyvy2 = yuv_uyvy + src[2], *uyvy3 = yuv_uyvy + src[3]; + } + src += pitch - (w-i); + dst += (dpitch - 2*(w-i))/2; + } else while (h--) { + for (i = w; i >= 4; src += 4, dst += 2, i -= 4) + { + struct uyvy *uyvy0 = yuv_uyvy + src[0], *uyvy1 = yuv_uyvy + src[1]; + struct uyvy *uyvy2 = yuv_uyvy + src[2], *uyvy3 = yuv_uyvy + src[3]; #if CPU_IS_LE - dst[0] = (uyvy1->y << 24) | uyvy0->vyu; - dst[1] = (uyvy3->y << 24) | uyvy2->vyu; + dst[0] = (uyvy1->y << 24) | uyvy0->vyu; + dst[1] = (uyvy3->y << 24) | uyvy2->vyu; #else - dst[0] = uyvy1->y | (uyvy0->vyu << 8); - dst[1] = uyvy3->y | (uyvy2->vyu << 8); + dst[0] = uyvy1->y | (uyvy0->vyu << 8); + dst[1] = uyvy3->y | (uyvy2->vyu << 8); #endif - } - src += pitch - (w-i); - dst += (dpitch - (w-i))/2; - } + } + src += pitch - (w-i); + dst += (dpitch - (w-i))/2; + } } void copy_intscale(void *dst, int w, int h, int pp, void *src, int sw, int sh, int spp) @@ -213,9 +213,9 @@ 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)) { + (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) + if (g_menuscreen_w * 3/4 >= g_menuscreen_h) w = (w * 3 * g_menuscreen_w/g_menuscreen_h)/4 & ~1; else h = (h * 4 * g_menuscreen_h/g_menuscreen_w)/3 & ~1; @@ -233,7 +233,8 @@ void plat_video_set_size(int w, int h) } } if (plat_sdl_overlay || plat_sdl_gl_active || - plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2) { + (plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2 || + plat_sdl_screen->w < 320 || plat_sdl_screen->h < 240)) { // use shadow buffer for overlays and sw integer scaling g_screen_width = area.w; g_screen_height = area.h; @@ -286,15 +287,28 @@ void plat_video_flip(void) if (SDL_MUSTLOCK(plat_sdl_screen)) SDL_UnlockSurface(plat_sdl_screen); SDL_Flip(plat_sdl_screen); - if (SDL_MUSTLOCK(plat_sdl_screen)) - SDL_LockSurface(plat_sdl_screen); - if (!copy) { + // take over resized settings for the physical SDL surface + if ((plat_sdl_screen->w != g_menuscreen_w || + plat_sdl_screen->h != g_menuscreen_h) && plat_sdl_is_windowed() && + SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) { + plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, 1); + SDL_WM_GrabInput(SDL_GRAB_OFF); + g_menuscreen_pp = plat_sdl_screen->pitch/2; + + // force upper layer to use new dimensions + plat_video_set_shadow(g_screen_width, g_screen_height); + plat_video_set_buffer(g_screen_ptr); + rendstatus_old = -1; + } else 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 (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_LockSurface(plat_sdl_screen); + if (clear_buf_cnt) { memset(g_screen_ptr, 0, plat_sdl_screen->pitch*plat_sdl_screen->h); clear_buf_cnt--; @@ -329,7 +343,7 @@ void plat_video_clear_buffers(void) { 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_pp * g_menuscreen_h * 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); clear_buf_cnt = 3; // do it thrice in case of triple buffering @@ -338,9 +352,17 @@ void plat_video_clear_buffers(void) void plat_video_menu_update(void) { - // w/h might have changed due to resizing - plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, 1); - resize_buffers(); + // WM may grab input while resizing the window; our own window resizing + // is only safe if the WM isn't active anymore, so try to grab input. + if (plat_sdl_is_windowed() && SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) { + // w/h might change in resize callback + int w, h; + do { + w = g_menuscreen_w, h = g_menuscreen_h; + plat_sdl_change_video_mode(w, h, 1); + } while (w != g_menuscreen_w || h != g_menuscreen_h); + SDL_WM_GrabInput(SDL_GRAB_OFF); + } // update pitch as it is needed by the menu bg scaler if (plat_sdl_overlay || plat_sdl_gl_active) @@ -402,8 +424,8 @@ void plat_video_menu_leave(void) void plat_video_loop_prepare(void) { // take over any new vout settings + area = (struct area) { 0, 0 }; plat_sdl_change_video_mode(0, 0, 0); - area.w = g_menuscreen_w, area.h = g_menuscreen_h; resize_buffers(); // switch over to scaled output if available, but keep the aspect ratio @@ -420,8 +442,10 @@ void plat_video_loop_prepare(void) g_screen_ptr = shadow_fb; } else { + plat_video_set_size(g_menuscreen_w, g_menuscreen_h); if (plat_sdl_is_windowed() && - (plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2)) { + (plat_sdl_screen->w >= 320*2 || plat_sdl_screen->h >= 240*2 || + plat_sdl_screen->w < 320 || plat_sdl_screen->h < 240)) { // shadow buffer for integer scaling g_screen_width = 320; g_screen_height = 240; @@ -434,7 +458,6 @@ void plat_video_loop_prepare(void) 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); @@ -456,7 +479,23 @@ static void plat_sdl_resize(int w, int h) { g_menuscreen_h = plat_sdl_screen->h; g_menuscreen_w = plat_sdl_screen->w; + + if (!plat_sdl_overlay && !plat_sdl_gl_active && + plat_sdl_is_windowed() && !plat_sdl_is_fullscreen()) { + // in SDL window mode, adapt window to integer scaling + if (g_menuscreen_w * 3/4 >= g_menuscreen_h) + g_menuscreen_w = g_menuscreen_h * 4/3; + else + g_menuscreen_h = g_menuscreen_w * 3/4; + g_menuscreen_w = g_menuscreen_w/320*320; + g_menuscreen_h = g_menuscreen_h/240*240; + if (g_menuscreen_w == 0) { + g_menuscreen_w = 320; + g_menuscreen_h = 240; + } + } } + resize_buffers(); rendstatus_old = -1; } @@ -474,15 +513,18 @@ void plat_init(void) ret = plat_sdl_init(); if (ret != 0) exit(1); + #if defined(__OPENDINGUX__) // opendingux on JZ47x0 may falsely report a HW overlay, fix to window plat_target.vout_method = 0; +#elif !defined(__MIYOO__) && !defined(__RETROFW__) && !defined(__DINGUX__) + if (! plat_sdl_is_windowed()) #endif + SDL_ShowCursor(0); plat_sdl_quit_cb = plat_sdl_quit; plat_sdl_resize_cb = plat_sdl_resize; - SDL_ShowCursor(0); SDL_WM_SetCaption("PicoDrive " VERSION, NULL); g_menuscreen_pp = g_menuscreen_w; diff --git a/platform/libpicofe b/platform/libpicofe index 81d25800..92bd9c36 160000 --- a/platform/libpicofe +++ b/platform/libpicofe @@ -1 +1 @@ -Subproject commit 81d2580006b56ede8e559b7a7f608ebb5ebbe6ae +Subproject commit 92bd9c36dac9b5b560ba8f45055f0265a10d979a -- 2.39.5