sdl, improve handling of window resizing
authorkub <derkub@gmail.com>
Sun, 9 Feb 2025 18:49:45 +0000 (19:49 +0100)
committerkub <derkub@gmail.com>
Wed, 12 Feb 2025 19:06:28 +0000 (20:06 +0100)
Makefile
platform/common/plat_sdl.c
platform/libpicofe

index 76d0117..5cd200b 100644 (file)
--- 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
index 405da64..8490212 100644 (file)
@@ -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;
index 81d2580..92bd9c3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 81d2580006b56ede8e559b7a7f608ebb5ebbe6ae
+Subproject commit 92bd9c36dac9b5b560ba8f45055f0265a10d979a