From 810239393ddf80252d03ff6220e945a684c744e3 Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 11 May 2025 01:21:51 +0300 Subject: [PATCH] sdandalone: rework sdl output - 2x overlay mode from PicoDrive - somewhat proper fullscreen mode - overlay scaling options - gles mode probably broken (no longer works on more modern distros anyway - it's some very old code) - new bugs --- Makefile | 5 +- frontend/cspace.c | 198 +++++++++++------- frontend/cspace.h | 4 +- frontend/libpicofe | 2 +- frontend/menu.c | 25 ++- frontend/pandora/ui_feat.h | 1 + frontend/plat_sdl.c | 415 +++++++++++++++++++++++++++++-------- frontend/plugin_lib.c | 54 +++-- frontend/plugin_lib.h | 1 + 9 files changed, 510 insertions(+), 195 deletions(-) diff --git a/Makefile b/Makefile index 7d76d217..f56ca1a5 100644 --- a/Makefile +++ b/Makefile @@ -363,9 +363,11 @@ endif ifeq "$(PLATFORM)" "generic" OBJS += frontend/libpicofe/in_sdl.o -OBJS += frontend/libpicofe/plat_sdl.o +#OBJS += frontend/libpicofe/plat_sdl.o OBJS += frontend/libpicofe/plat_dummy.o OBJS += frontend/plat_sdl.o +frontend/plat_sdl.o frontend/libpicofe/plat_sdl.o: CFLAGS += -DSDL_OVERLAY_2X +frontend/menu.o: CFLAGS += -DSDL_OVERLAY_2X -DMENU_SHOW_VARSCALER=1 ifeq "$(HAVE_EVDEV)" "1" OBJS += frontend/libpicofe/linux/in_evdev.o endif @@ -387,6 +389,7 @@ OBJS += frontend/libpicofe/linux/in_evdev.o OBJS += frontend/plat_pandora.o frontend/plat_omap.o frontend/main.o frontend/menu.o: CFLAGS += -include frontend/pandora/ui_feat.h frontend/libpicofe/linux/plat.o: CFLAGS += -DPANDORA +frontend/plugin_lib.o: CFLAGS += -DPANDORA USE_PLUGIN_LIB = 1 USE_FRONTEND = 1 CFLAGS += -gdwarf-3 diff --git a/frontend/cspace.c b/frontend/cspace.c index 3a09792c..8249f80f 100644 --- a/frontend/cspace.c +++ b/frontend/cspace.c @@ -168,36 +168,53 @@ void bgr888_to_xrgb8888(void * __restrict__ dst_, const void * __restrict__ src_ /* YUV stuff */ static int yuv_ry[32], yuv_gy[32], yuv_by[32]; static unsigned char yuv_u[32 * 2], yuv_v[32 * 2]; +static struct uyvy { uint32_t y:8; uint32_t vyu:24; } yuv_uyvy[32768]; 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; - } + unsigned char yuv_y[256]; + 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 < 32768; i++) { + int r = (i >> 0) & 0x1f, g = (i >> 5) & 0x1f, b = (i >> 10) & 0x1f; + int y = (yuv_ry[r] + yuv_gy[g] + yuv_by[b]) >> 16; + yuv_uyvy[i].y = yuv_y[y]; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + yuv_uyvy[i].vyu = (yuv_v[b-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[r-y + 32]; +#else + yuv_uyvy[i].vyu = (yuv_v[r-y + 32] << 16) | (yuv_y[y] << 8) | yuv_u[b-y + 32]; +#endif + } } void rgb565_to_uyvy(void *d, const void *s, int pixels) @@ -229,54 +246,89 @@ void rgb565_to_uyvy(void *d, const void *s, int pixels) } } -void bgr555_to_uyvy(void *d, const void *s, int pixels) +void bgr555_to_uyvy(void *d, const void *s, int pixels, int x2) { - unsigned int *dst = d; - const unsigned short *src = s; - const unsigned char *yu = yuv_u + 32; - const unsigned char *yv = yuv_v + 32; - int r0, g0, b0, r1, g1, b1; - int y0, y1, u, v; - - for (; pixels > 1; src += 2, dst++, pixels -= 2) - { - b0 = (src[0] >> 10) & 0x1f; - g0 = (src[0] >> 5) & 0x1f; - r0 = src[0] & 0x1f; - b1 = (src[1] >> 10) & 0x1f; - g1 = (src[1] >> 5) & 0x1f; - r1 = src[1] & 0x1f; - y0 = (yuv_ry[r0] + yuv_gy[g0] + yuv_by[b0]) >> 16; - y1 = (yuv_ry[r1] + yuv_gy[g1] + yuv_by[b1]) >> 16; - u = yu[b0 - y0]; - v = yv[r0 - y0]; - y0 = 16 + 219 * y0 / 31; - y1 = 16 + 219 * y1 / 31; - - *dst = (y1 << 24) | (v << 16) | (y0 << 8) | u; - } + uint32_t *dst = d; + const uint16_t *src = s; + int i; + + if (x2) { + for (i = pixels; i >= 4; src += 4, dst += 4, i -= 4) + { + const struct uyvy *uyvy0 = yuv_uyvy + (src[0] & 0x7fff); + const struct uyvy *uyvy1 = yuv_uyvy + (src[1] & 0x7fff); + const struct uyvy *uyvy2 = yuv_uyvy + (src[2] & 0x7fff); + const struct uyvy *uyvy3 = yuv_uyvy + (src[3] & 0x7fff); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + 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); +#else + 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; +#endif + } + } else { + for (i = pixels; i >= 4; src += 4, dst += 2, i -= 4) + { + const struct uyvy *uyvy0 = yuv_uyvy + (src[0] & 0x7fff); + const struct uyvy *uyvy1 = yuv_uyvy + (src[1] & 0x7fff); + const struct uyvy *uyvy2 = yuv_uyvy + (src[2] & 0x7fff); + const struct uyvy *uyvy3 = yuv_uyvy + (src[3] & 0x7fff); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + dst[0] = uyvy1->y | (uyvy0->vyu << 8); + dst[1] = uyvy3->y | (uyvy2->vyu << 8); +#else + dst[0] = (uyvy1->y << 24) | uyvy0->vyu; + dst[1] = (uyvy3->y << 24) | uyvy2->vyu; +#endif + } + } } -void bgr888_to_uyvy(void *d, const void *s, int pixels) +void bgr888_to_uyvy(void *d, const void *s, int pixels, int x2) { - unsigned int *dst = d; - const unsigned char *src8 = s; - const unsigned char *yu = yuv_u + 32; - const unsigned char *yv = yuv_v + 32; - int r0, g0, b0, r1, g1, b1; - int y0, y1, u, v; - - for (; pixels > 0; src8 += 3*2, dst++, pixels -= 2) - { - r0 = src8[0], g0 = src8[1], b0 = src8[2]; - r1 = src8[3], g1 = src8[4], b1 = src8[5]; - y0 = (r0 * 19595 + g0 * 38470 + b0 * 7471) >> 16; - y1 = (r1 * 19595 + g1 * 38470 + b1 * 7471) >> 16; - u = yu[(b0 - y0) / 8]; - v = yv[(r0 - y0) / 8]; - y0 = 16 + 219 * y0 / 255; - y1 = 16 + 219 * y1 / 255; - - *dst = (y1 << 24) | (v << 16) | (y0 << 8) | u; - } + unsigned int *dst = d; + const unsigned char *src8 = s; + const unsigned char *yu = yuv_u + 32; + const unsigned char *yv = yuv_v + 32; + int r0, g0, b0, r1, g1, b1; + int y0, y1, u0, u1, v0, v1; + + if (x2) { + for (; pixels >= 2; src8 += 3*2, pixels -= 2) + { + r0 = src8[0], g0 = src8[1], b0 = src8[2]; + r1 = src8[3], g1 = src8[4], b1 = src8[5]; + y0 = (r0 * 19595 + g0 * 38470 + b0 * 7471) >> 16; + y1 = (r1 * 19595 + g1 * 38470 + b1 * 7471) >> 16; + u0 = yu[(b0 - y0) / 8]; + u1 = yu[(b1 - y1) / 8]; + v0 = yv[(r0 - y0) / 8]; + v1 = yv[(r1 - y1) / 8]; + y0 = 16 + 219 * y0 / 255; + y1 = 16 + 219 * y1 / 255; + + *dst++ = (y0 << 24) | (v0 << 16) | (y0 << 8) | u0; + *dst++ = (y1 << 24) | (v1 << 16) | (y1 << 8) | u1; + } + } + else { + for (; pixels >= 2; src8 += 3*2, dst++, pixels -= 2) + { + r0 = src8[0], g0 = src8[1], b0 = src8[2]; + r1 = src8[3], g1 = src8[4], b1 = src8[5]; + y0 = (r0 * 19595 + g0 * 38470 + b0 * 7471) >> 16; + y1 = (r1 * 19595 + g1 * 38470 + b1 * 7471) >> 16; + u0 = yu[(b0 - y0) / 8]; + v0 = yv[(r0 - y0) / 8]; + y0 = 16 + 219 * y0 / 255; + y1 = 16 + 219 * y1 / 255; + + *dst = (y1 << 24) | (v0 << 16) | (y0 << 8) | u0; + } + } } diff --git a/frontend/cspace.h b/frontend/cspace.h index 61bddf90..e5931960 100644 --- a/frontend/cspace.h +++ b/frontend/cspace.h @@ -19,8 +19,8 @@ void bgr888_to_xrgb8888(void *dst, const void *src, int bytes); void bgr_to_uyvy_init(void); void rgb565_to_uyvy(void *d, const void *s, int pixels); -void bgr555_to_uyvy(void *d, const void *s, int pixels); -void bgr888_to_uyvy(void *d, const void *s, int pixels); +void bgr555_to_uyvy(void *d, const void *s, int pixels, int x2); +void bgr888_to_uyvy(void *d, const void *s, int pixels, int x2); #ifdef __cplusplus } diff --git a/frontend/libpicofe b/frontend/libpicofe index a8ded55f..80612f5f 160000 --- a/frontend/libpicofe +++ b/frontend/libpicofe @@ -1 +1 @@ -Subproject commit a8ded55fc9df952b5582a6da72e1de887e65a34b +Subproject commit 80612f5f31a3201e6c7f710109a9c8b48f6bb757 diff --git a/frontend/menu.c b/frontend/menu.c index 99ca5925..a5ffb7b4 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -94,6 +94,7 @@ typedef enum MA_OPT_SWFILTER, MA_OPT_GAMMA, MA_OPT_VOUT_MODE, + MA_OPT_VOUT_FULL, MA_OPT_SCANLINES, MA_OPT_SCANLINE_LEVEL, MA_OPT_CENTERING, @@ -132,7 +133,6 @@ static int bios_sel, gpu_plugsel, spu_plugsel; #ifndef UI_FEATURES_H #define MENU_BIOS_PATH "bios/" -#define MENU_SHOW_VARSCALER 0 #define MENU_SHOW_VOUTMODE 1 #define MENU_SHOW_SCALER2 0 #define MENU_SHOW_NUBS_BTNS 0 @@ -142,6 +142,12 @@ static int bios_sel, gpu_plugsel, spu_plugsel; #define MENU_SHOW_FULLSCREEN 1 #define MENU_SHOW_VOLUME 0 #endif +#ifndef MENU_SHOW_VARSCALER +#define MENU_SHOW_VARSCALER 0 +#endif +#ifndef MENU_SHOW_VARSCALER_C +#define MENU_SHOW_VARSCALER_C 0 +#endif static int min(int x, int y) { return x < y ? x : y; } static int max(int x, int y) { return x > y ? x : y; } @@ -1280,7 +1286,11 @@ static int menu_loop_keyconfig(int id, int keys) // ------------ gfx options menu ------------ static const char *men_scaler[] = { - "1x1", "integer scaled 2x", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL + "1x1", "integer scaled 2x", "scaled 4:3", "integer scaled 4:3", "fullscreen", +#if MENU_SHOW_VARSCALER_C + "custom", +#endif + NULL }; static const char *men_soft_filter[] = { "None", #ifdef HAVE_NEON32 @@ -1385,10 +1395,11 @@ static int menu_loop_cscaler(int id, int keys) static menu_entry e_menu_gfx_options[] = { - mee_enum ("Screen centering", MA_OPT_CENTERING, pl_rearmed_cbs.screen_centering_type, men_centering), + mee_enum ("PSX Screen centering", MA_OPT_CENTERING, pl_rearmed_cbs.screen_centering_type, men_centering), mee_enum ("Show overscan", MA_OPT_OVERSCAN, pl_rearmed_cbs.show_overscan, men_overscan), mee_enum_h ("Scaler", MA_OPT_VARSCALER, g_scaler, men_scaler, h_scaler), mee_enum ("Video output mode", MA_OPT_VOUT_MODE, plat_target.vout_method, men_dummy), + mee_onoff ("Fullscreen mode", MA_OPT_VOUT_FULL, plat_target.vout_fullscreen, 1), mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1), mee_enum ("Hardware Filter", MA_OPT_HWFILTER, plat_target.hwfilter, men_dummy), mee_enum_h ("Software Filter", MA_OPT_SWFILTER, soft_filter, men_soft_filter, h_soft_filter), @@ -2672,6 +2683,12 @@ void menu_init(void) me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, plat_target.vout_methods != NULL); +#ifndef SDL_OVERLAY_2X + i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_FULL); + e_menu_gfx_options[i].data = plat_target.vout_methods; + me_enable(e_menu_gfx_options, MA_OPT_VOUT_FULL, 0); +#endif + i = me_id2offset(e_menu_gfx_options, MA_OPT_HWFILTER); e_menu_gfx_options[i].data = plat_target.hwfilters; me_enable(e_menu_gfx_options, MA_OPT_HWFILTER, @@ -2685,7 +2702,7 @@ void menu_init(void) #endif me_enable(e_menu_gfx_options, MA_OPT_VARSCALER, MENU_SHOW_VARSCALER); me_enable(e_menu_gfx_options, MA_OPT_VOUT_MODE, MENU_SHOW_VOUTMODE); - me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER); + me_enable(e_menu_gfx_options, MA_OPT_VARSCALER_C, MENU_SHOW_VARSCALER_C); me_enable(e_menu_gfx_options, MA_OPT_SCALER2, MENU_SHOW_SCALER2); me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, MENU_SHOW_NUBS_BTNS); me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, MENU_SHOW_VIBRATION); diff --git a/frontend/pandora/ui_feat.h b/frontend/pandora/ui_feat.h index 3bb808af..5eb3dc2f 100644 --- a/frontend/pandora/ui_feat.h +++ b/frontend/pandora/ui_feat.h @@ -4,6 +4,7 @@ #define MENU_BIOS_PATH "/pandora/appdata/pcsx_rearmed/bios/" #define BOOT_MSG "Booting up... (press SPACE for menu)" #define MENU_SHOW_VARSCALER 1 +#define MENU_SHOW_VARSCALER_C 1 #define MENU_SHOW_VOUTMODE 0 #define MENU_SHOW_SCALER2 0 #define MENU_SHOW_NUBS_BTNS 1 diff --git a/frontend/plat_sdl.c b/frontend/plat_sdl.c index 64cac7ce..3529d979 100644 --- a/frontend/plat_sdl.c +++ b/frontend/plat_sdl.c @@ -9,6 +9,7 @@ */ #include +#include #include #include "libpicofe/input.h" @@ -16,14 +17,18 @@ #include "libpicofe/menu.h" #include "libpicofe/fonts.h" #include "libpicofe/plat_sdl.h" +#include "libpicofe/plat.h" #include "libpicofe/gl.h" #include "cspace.h" #include "plugin_lib.h" #include "plugin.h" +#include "menu.h" #include "main.h" #include "plat.h" #include "revision.h" +#include "libpicofe/plat_sdl.c" + static const struct in_default_bind in_sdl_defbinds[] = { { SDLK_UP, IN_BINDTYPE_PLAYER12, DKEY_UP }, { SDLK_DOWN, IN_BINDTYPE_PLAYER12, DKEY_DOWN }, @@ -90,39 +95,45 @@ static const struct in_pdata in_sdl_platform_data = { static int psx_w = 256, psx_h = 240; static void *shadow_fb, *menubg_img; +static int resized, window_w, window_h; +static int vout_fullscreen_old; +static int forced_clears; +static int forced_flips; +static int sdl12_compat; static int in_menu; +static void handle_scaler_resize(int w, int h); static void centered_clear(void); -static void *setup_blit_callbacks(int w); - -static int change_video_mode(int force) -{ - int w, h, ret; - - if (in_menu) { - w = g_menuscreen_w; - h = g_menuscreen_h; - } - else { - w = psx_w; - h = psx_h; - } - - ret = plat_sdl_change_video_mode(w, h, force); - if (ret == 0 && plat_sdl_overlay == NULL && !plat_sdl_gl_active) - centered_clear(); - return ret; -} static void resize_cb(int w, int h) { - // used by some plugins.. + // used by some plugins... pl_rearmed_cbs.screen_w = w; pl_rearmed_cbs.screen_h = h; pl_rearmed_cbs.gles_display = gl_es_display; pl_rearmed_cbs.gles_surface = gl_es_surface; plugin_call_rearmed_cbs(); - setup_blit_callbacks(psx_w); +} + +static void sdl_event_handler(void *event_) +{ + SDL_Event *event = event_; + + switch (event->type) { + case SDL_VIDEORESIZE: + if (window_w != (event->resize.w & ~3) || window_h != (event->resize.h & ~1)) { + window_w = event->resize.w & ~3; + window_h = event->resize.h & ~1; + resized = 1; + } + return; + case SDL_ACTIVEEVENT: + // no need to redraw? + return; + default: + break; + } + plat_sdl_event_handler(event_); } static void quit_cb(void) @@ -140,6 +151,7 @@ static void get_layer_pos(int *x, int *y, int *w, int *h) void plat_init(void) { + const SDL_version *ver; int shadow_size; int ret; @@ -150,6 +162,10 @@ void plat_init(void) if (ret != 0) exit(1); + ver = SDL_Linked_Version(); + sdl12_compat = ver->patch >= 50; + printf("SDL %u.%u.%u compat=%d\n", ver->major, ver->minor, ver->patch, sdl12_compat); + in_menu = 1; SDL_WM_SetCaption("PCSX-ReARMed " REV, NULL); @@ -165,12 +181,19 @@ void plat_init(void) exit(1); } - in_sdl_init(&in_sdl_platform_data, plat_sdl_event_handler); + in_sdl_init(&in_sdl_platform_data, sdl_event_handler); in_probe(); pl_rearmed_cbs.only_16bpp = 1; pl_rearmed_cbs.pl_get_layer_pos = get_layer_pos; bgr_to_uyvy_init(); + + // to "finish" init and set SDL_RESIZABLE + plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, -1); + if (plat_sdl_overlay) { + printf("overlay: %08x hw=%d\n", plat_sdl_overlay->format, + plat_sdl_overlay->hw_overlay); + } } void plat_finish(void) @@ -186,22 +209,70 @@ void plat_gvideo_open(int is_pal) { } -static void uyvy_to_rgb565(void *d, const void *s, int pixels) +static void uyvy_to_rgb565(void *d, int pixels) { + const unsigned int *src = (const void *)plat_sdl_overlay->pixels[0]; + int x2 = plat_sdl_overlay->w >= psx_w * 2; unsigned short *dst = d; - const unsigned int *src = s; int v; // no colors, for now - for (; pixels > 0; src++, dst += 2, pixels -= 2) { - v = (*src >> 8) & 0xff; - v = (v - 16) * 255 / 219 / 8; - dst[0] = (v << 11) | (v << 6) | v; - - v = (*src >> 24) & 0xff; - v = (v - 16) * 255 / 219 / 8; - dst[1] = (v << 11) | (v << 6) | v; + if (x2) { + for (; pixels > 0; src++, dst++, pixels--) { + v = (*src >> 8) & 0xff; + v = (v - 16) * 255 / 219 / 8; + *dst = (v << 11) | (v << 6) | v; + } + } + else { + for (; pixels > 0; src++, dst += 2, pixels -= 2) { + v = (*src >> 8) & 0xff; + v = (v - 16) * 255 / 219 / 8; + dst[0] = (v << 11) | (v << 6) | v; + + v = (*src >> 24) & 0xff; + v = (v - 16) * 255 / 219 / 8; + dst[1] = (v << 11) | (v << 6) | v; + } + } +} + +static void overlay_resize(int force) +{ + int x2_mul = !in_menu && plat_target.vout_method > 1 ? 2 : 1; // lame + int w = in_menu ? g_menuscreen_w : psx_w; + int h = in_menu ? g_menuscreen_h : psx_h; + + if (!force && plat_sdl_overlay && w * x2_mul == plat_sdl_overlay->w + && h == plat_sdl_overlay->h) + return; + if (plat_sdl_overlay) + SDL_FreeYUVOverlay(plat_sdl_overlay); + plat_sdl_overlay = SDL_CreateYUVOverlay(w * x2_mul, h, SDL_UYVY_OVERLAY, + plat_sdl_screen); + if (plat_sdl_overlay) { + //printf("overlay: %dx%d %08x hw=%d\n", plat_sdl_overlay->w, plat_sdl_overlay->h, + // plat_sdl_overlay->format, plat_sdl_overlay->hw_overlay); + if (SDL_LockYUVOverlay(plat_sdl_overlay) == 0) { + plat_sdl_overlay_clear(); + SDL_UnlockYUVOverlay(plat_sdl_overlay); + } + } + else + fprintf(stderr, "overlay resize to %dx%d failed\n", w, h); + handle_scaler_resize(w, h); +} + +static void overlay_check_enable(void) +{ + // we no longer unconditionally call plat_sdl_change_video_mode() + // to not disturb the window, need to look for config change + if ((plat_target.vout_method == 0 || plat_sdl_gl_active) && plat_sdl_overlay) { + SDL_FreeYUVOverlay(plat_sdl_overlay); + plat_sdl_overlay = NULL; } + else if (plat_target.vout_method > 0 && !plat_sdl_gl_active) // lame + overlay_resize(0); } static void overlay_blit(int doffs, const void *src_, int w, int h, @@ -210,6 +281,7 @@ static void overlay_blit(int doffs, const void *src_, int w, int h, const unsigned short *src = src_; unsigned short *dst; int dstride = plat_sdl_overlay->w; + int x2 = dstride >= 2 * w; SDL_LockYUVOverlay(plat_sdl_overlay); dst = (void *)plat_sdl_overlay->pixels[0]; @@ -217,11 +289,11 @@ static void overlay_blit(int doffs, const void *src_, int w, int h, dst += doffs; if (bgr24) { for (; h > 0; dst += dstride, src += sstride, h--) - bgr888_to_uyvy(dst, src, w); + bgr888_to_uyvy(dst, src, w, x2); } else { for (; h > 0; dst += dstride, src += sstride, h--) - bgr555_to_uyvy(dst, src, w); + bgr555_to_uyvy(dst, src, w, x2); } SDL_UnlockYUVOverlay(plat_sdl_overlay); @@ -229,7 +301,11 @@ static void overlay_blit(int doffs, const void *src_, int w, int h, static void overlay_hud_print(int x, int y, const char *str, int bpp) { + int x2; SDL_LockYUVOverlay(plat_sdl_overlay); + x2 = plat_sdl_overlay->w >= psx_w * 2; + if (x2) + x *= 2; basic_text_out_uyvy_nf(plat_sdl_overlay->pixels[0], plat_sdl_overlay->w, x, y, str); SDL_UnlockYUVOverlay(plat_sdl_overlay); } @@ -241,13 +317,39 @@ static void centered_clear(void) int h = plat_sdl_screen->h; unsigned short *dst; - SDL_LockSurface(plat_sdl_screen); + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_LockSurface(plat_sdl_screen); dst = plat_sdl_screen->pixels; for (; h > 0; dst += dstride, h--) memset(dst, 0, w * 2); - SDL_UnlockSurface(plat_sdl_screen); + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_UnlockSurface(plat_sdl_screen); + + if (plat_sdl_overlay != NULL) { + // apply the parts not covered by the overlay + forced_flips = 3; + } +} + +static int adj_src_dst(const SDL_Surface *sfc, int w, int pp, int *h, + unsigned short **dst, const unsigned short **src) +{ + int line_w = w; + if (sfc->w > w) + *dst += (sfc->w - w) / 2; + else { + *src += (w - sfc->w) / 2; + line_w = sfc->w; + } + if (sfc->h > *h) + *dst += sfc->pitch * (sfc->h - *h) / 2 / 2; + else { + *src += pp * (*h - sfc->h) / 2; + *h = sfc->h; + } + return line_w; } static void centered_blit(int doffs, const void *src_, int w, int h, @@ -257,12 +359,12 @@ static void centered_blit(int doffs, const void *src_, int w, int h, unsigned short *dst; int dstride; - SDL_LockSurface(plat_sdl_screen); + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_LockSurface(plat_sdl_screen); dst = plat_sdl_screen->pixels; dstride = plat_sdl_screen->pitch / 2; + w = adj_src_dst(plat_sdl_screen, w, sstride, &h, &dst, &src); - dst += doffs + (plat_sdl_screen->w - w) / 2; - dst += dstride * (plat_sdl_screen->h - h) / 2; if (bgr24) { for (; h > 0; dst += dstride, src += sstride, h--) bgr888_to_rgb565(dst, src, w * 3); @@ -272,7 +374,8 @@ static void centered_blit(int doffs, const void *src_, int w, int h, bgr555_to_rgb565(dst, src, w * 2); } - SDL_UnlockSurface(plat_sdl_screen); + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_UnlockSurface(plat_sdl_screen); } static void centered_blit_menu(void) @@ -281,30 +384,39 @@ static void centered_blit_menu(void) int w = g_menuscreen_w; int h = g_menuscreen_h; unsigned short *dst; - int dstride; + int dstride, len; + + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_LockSurface(plat_sdl_screen); - SDL_LockSurface(plat_sdl_screen); dst = plat_sdl_screen->pixels; dstride = plat_sdl_screen->pitch / 2; + len = adj_src_dst(plat_sdl_screen, w, g_menuscreen_pp, &h, &dst, &src); - dst += (plat_sdl_screen->w - w) / 2; - dst += dstride * (plat_sdl_screen->h - h) / 2; for (; h > 0; dst += dstride, src += g_menuscreen_pp, h--) - memcpy(dst, src, w * 2); + memcpy(dst, src, len * 2); - SDL_UnlockSurface(plat_sdl_screen); + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_UnlockSurface(plat_sdl_screen); } static void centered_hud_print(int x, int y, const char *str, int bpp) { - x += (plat_sdl_screen->w - psx_w) / 2; - y += (plat_sdl_screen->h - psx_h) / 2; - SDL_LockSurface(plat_sdl_screen); + int w_diff, h_diff; + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_LockSurface(plat_sdl_screen); + w_diff = plat_sdl_screen->w - psx_w; + h_diff = plat_sdl_screen->h - psx_h; + if (w_diff > 0) x += w_diff / 2; + if (h_diff > 0) y += h_diff / 2; + if (h_diff < 0) y += h_diff; + if (w_diff < 0 && x > 32) x += w_diff; basic_text_out16_nf(plat_sdl_screen->pixels, plat_sdl_screen->pitch / 2, x, y, str); - SDL_UnlockSurface(plat_sdl_screen); + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_UnlockSurface(plat_sdl_screen); } -static void *setup_blit_callbacks(int w) +static void *setup_blit_callbacks(int w, int h) { pl_plat_clear = NULL; pl_plat_blit = NULL; @@ -318,43 +430,134 @@ static void *setup_blit_callbacks(int w) return shadow_fb; } else { - if (w == plat_sdl_screen->w) + pl_plat_clear = centered_clear; + + if (!SDL_MUSTLOCK(plat_sdl_screen) && w == plat_sdl_screen->w && + h == plat_sdl_screen->h) return plat_sdl_screen->pixels; + + pl_plat_blit = centered_blit; + pl_plat_hud_print = centered_hud_print; + } + return NULL; +} + +// not using plat_sdl_change_video_mode() since we need +// different size overlay vs plat_sdl_screen layer +static void change_mode(int w, int h) +{ + int set_w = w, set_h = h, had_overlay = 0; + if (plat_target.vout_fullscreen && (plat_target.vout_method != 0 || !sdl12_compat)) + set_w = fs_w, set_h = fs_h; + if (plat_sdl_screen->w != set_w || plat_sdl_screen->h != set_h || + plat_target.vout_fullscreen != vout_fullscreen_old) + { + Uint32 flags = plat_sdl_screen->flags; + if (plat_target.vout_fullscreen) + flags |= SDL_FULLSCREEN; else { - pl_plat_clear = centered_clear; - pl_plat_blit = centered_blit; - pl_plat_hud_print = centered_hud_print; + flags &= ~SDL_FULLSCREEN; + if (plat_sdl_is_windowed()) + flags |= SDL_RESIZABLE; // sdl12-compat 1.2.68 loses this flag + } + if (plat_sdl_overlay) { + SDL_FreeYUVOverlay(plat_sdl_overlay); + plat_sdl_overlay = NULL; + had_overlay = 1; } + SDL_PumpEvents(); + plat_sdl_screen = SDL_SetVideoMode(set_w, set_h, 16, flags); + //printf("mode: %dx%d %x -> %dx%d\n", set_w, set_h, flags, + // plat_sdl_screen->w, plat_sdl_screen->h); + assert(plat_sdl_screen); + if (vout_fullscreen_old && !plat_target.vout_fullscreen) + // why is this needed?? (on 1.2.68) + SDL_WM_GrabInput(SDL_GRAB_OFF); + // overlay needs the latest plat_sdl_screen + if (had_overlay) + overlay_resize(1); + centered_clear(); + vout_fullscreen_old = plat_target.vout_fullscreen; + } +} + +static void handle_scaler_resize(int w, int h) +{ + int ww = plat_sdl_screen->w; + int wh = plat_sdl_screen->h; + int layer_w_old = g_layer_w; + int layer_h_old = g_layer_h; + pl_update_layer_size(w, h, ww, wh); + if (layer_w_old != g_layer_w || layer_h_old != g_layer_h) + forced_clears = 3; +} + +static void handle_window_resize(void) +{ + // sdl12-compat: a hack to take advantage of sdl2 scaling + if (resized && (plat_target.vout_method != 0 || !sdl12_compat)) { + change_mode(window_w, window_h); + setup_blit_callbacks(psx_w, psx_h); + forced_clears = 3; + resized = 0; } - return NULL; } void *plat_gvideo_set_mode(int *w, int *h, int *bpp) { psx_w = *w; psx_h = *h; - change_video_mode(0); - if (plat_sdl_gl_active) - memset(shadow_fb, 0, psx_w * psx_h * 2); - return setup_blit_callbacks(*w); + + if (plat_sdl_overlay != NULL) + overlay_resize(0); + else if (plat_sdl_gl_active) + memset(shadow_fb, 0, (*w) * (*h) * 2); + else if (plat_target.vout_method == 0) // && sdl12_compat + change_mode(*w, *h); + + handle_scaler_resize(*w, *h); // override the value from pl_vout_set_mode() + return setup_blit_callbacks(*w, *h); } void *plat_gvideo_flip(void) { + void *ret = NULL; + int do_flip = 0; if (plat_sdl_overlay != NULL) { - SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h }; + SDL_Rect dstrect = { + (plat_sdl_screen->w - g_layer_w) / 2, + (plat_sdl_screen->h - g_layer_h) / 2, + g_layer_w, g_layer_h + }; + SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect); - return NULL; } else if (plat_sdl_gl_active) { gl_flip(shadow_fb, psx_w, psx_h); - return shadow_fb; + ret = shadow_fb; } - else { - // XXX: no locking, but should be fine with SDL_SWSURFACE? + else + do_flip |= 2; + + if (forced_flips > 0) { + forced_flips--; + do_flip |= 1; + } + if (do_flip) SDL_Flip(plat_sdl_screen); - return plat_sdl_screen->pixels; + handle_window_resize(); + if (do_flip) { + if (forced_clears > 0) { + forced_clears--; + centered_clear(); + } + if (!SDL_MUSTLOCK(plat_sdl_screen) && plat_sdl_screen->w == psx_w && + plat_sdl_screen->h == psx_h && (do_flip & 2)) { + ret = plat_sdl_screen->pixels; + } } + assert(ret || pl_plat_clear != NULL); + return ret; } void plat_gvideo_close(void) @@ -363,35 +566,65 @@ void plat_gvideo_close(void) void plat_video_menu_enter(int is_rom_loaded) { - int force_mode_change = 0; - in_menu = 1; /* surface will be lost, must adjust pl_vout_buf for menu bg */ if (plat_sdl_overlay != NULL) - uyvy_to_rgb565(menubg_img, plat_sdl_overlay->pixels[0], psx_w * psx_h); + uyvy_to_rgb565(menubg_img, psx_w * psx_h); else if (plat_sdl_gl_active) memcpy(menubg_img, shadow_fb, psx_w * psx_h * 2); - else - memcpy(menubg_img, plat_sdl_screen->pixels, psx_w * psx_h * 2); + else { + unsigned short *dst = menubg_img; + const unsigned short *src; + int h; + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_LockSurface(plat_sdl_screen); + src = plat_sdl_screen->pixels; + src += (plat_sdl_screen->w - psx_w) / 2; + src += plat_sdl_screen->pitch * (plat_sdl_screen->h - psx_h) / 2 / 2; + for (h = psx_h; h > 0; dst += psx_w, src += plat_sdl_screen->pitch / 2, h--) + memcpy(dst, src, psx_w * 2); + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_UnlockSurface(plat_sdl_screen); + } pl_vout_buf = menubg_img; - /* gles plugin messes stuff up.. */ - if (pl_rearmed_cbs.gpu_caps & GPU_CAP_OWNS_DISPLAY) - force_mode_change = 1; - - change_video_mode(force_mode_change); + if (plat_target.vout_method == 0) + change_mode(g_menuscreen_w, g_menuscreen_h); + else + overlay_check_enable(); + centered_clear(); } void plat_video_menu_begin(void) { + void *old_ovl = plat_sdl_overlay; + static int g_scaler_old; + int scaler_changed = g_scaler_old != g_scaler; + g_scaler_old = g_scaler; + if (plat_target.vout_fullscreen != vout_fullscreen_old || + (plat_target.vout_fullscreen && scaler_changed)) { + change_mode(g_menuscreen_w, g_menuscreen_h); + } + else + overlay_check_enable(); + handle_scaler_resize(g_menuscreen_w, g_menuscreen_h); + + if (old_ovl != plat_sdl_overlay || scaler_changed) + centered_clear(); g_menuscreen_ptr = shadow_fb; } void plat_video_menu_end(void) { + int do_flip = 0; + if (plat_sdl_overlay != NULL) { - SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h }; + SDL_Rect dstrect = { + (plat_sdl_screen->w - g_layer_w) / 2, + (plat_sdl_screen->h - g_layer_h) / 2, + g_layer_w, g_layer_h + }; SDL_LockYUVOverlay(plat_sdl_overlay); rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb, @@ -405,21 +638,31 @@ void plat_video_menu_end(void) } else { centered_blit_menu(); - SDL_Flip(plat_sdl_screen); + do_flip |= 2; } + + if (forced_flips > 0) { + forced_flips--; + do_flip |= 1; + } + if (do_flip) + SDL_Flip(plat_sdl_screen); + + handle_window_resize(); g_menuscreen_ptr = NULL; } void plat_video_menu_leave(void) { - void *fb = NULL; - if (plat_sdl_overlay != NULL || plat_sdl_gl_active) - fb = shadow_fb; - else if (plat_sdl_screen) - fb = plat_sdl_screen->pixels; - if (fb) - memset(fb, 0, g_menuscreen_w * g_menuscreen_h * 2); in_menu = 0; + if (plat_sdl_overlay != NULL || plat_sdl_gl_active) + memset(shadow_fb, 0, g_menuscreen_w * g_menuscreen_h * 2); + + if (plat_target.vout_fullscreen) + change_mode(fs_w, fs_h); + else + overlay_check_enable(); + centered_clear(); } /* unused stuff */ diff --git a/frontend/plugin_lib.c b/frontend/plugin_lib.c index 98e86ea3..81998d5b 100644 --- a/frontend/plugin_lib.c +++ b/frontend/plugin_lib.c @@ -54,7 +54,7 @@ void *tsdev; void *pl_vout_buf; int g_layer_x, g_layer_y, g_layer_w, g_layer_h; static int pl_vout_w, pl_vout_h, pl_vout_bpp; /* output display/layer */ -static int pl_vout_scale_w, pl_vout_scale_h, pl_vout_yoffset; +static int pl_vout_scale_w, pl_vout_scale_h; static int psx_w, psx_h, psx_bpp; static int vsync_cnt; static int is_pal, frame_interval, frame_interval1024; @@ -178,7 +178,7 @@ static void print_hud(int x, int w, int h) } /* update scaler target size according to user settings */ -static void update_layer_size(int w, int h) +void pl_update_layer_size(int w, int h, int fw, int fh) { float mult; int imult; @@ -190,39 +190,45 @@ static void update_layer_size(int w, int h) case SCALE_2_2: g_layer_w = w; g_layer_h = h; - if (w * 2 <= g_menuscreen_w) + if (w * 2 <= fw) g_layer_w = w * 2; - if (h * 2 <= g_menuscreen_h) + if (h * 2 <= fh) g_layer_h = h * 2; break; case SCALE_4_3v2: - if (h > g_menuscreen_h || (240 < h && h <= 360)) - goto fractional_4_3; +#ifdef PANDORA + if (h <= fh && !(240 < h && h <= 360)) + { +#endif // 4:3 that prefers integer scaling - imult = g_menuscreen_h / h; + imult = fh / h; + if (imult < 1) + imult = 1; g_layer_w = w * imult; g_layer_h = h * imult; mult = (float)g_layer_w / (float)g_layer_h; if (mult < 1.25f || mult > 1.666f) g_layer_w = 4.0f/3.0f * (float)g_layer_h; - printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult); + //printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult); break; +#ifdef PANDORA + } +#endif - fractional_4_3: case SCALE_4_3: mult = 240.0f / (float)h * 4.0f / 3.0f; if (h > 256) mult *= 2.0f; - g_layer_w = mult * (float)g_menuscreen_h; - g_layer_h = g_menuscreen_h; - printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult); + g_layer_w = mult * (float)fh; + g_layer_h = fh; + //printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult); break; case SCALE_FULLSCREEN: - g_layer_w = g_menuscreen_w; - g_layer_h = g_menuscreen_h; + g_layer_w = fw; + g_layer_h = fh; break; default: @@ -230,11 +236,11 @@ static void update_layer_size(int w, int h) } if (g_scaler != SCALE_CUSTOM) { - g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2; - g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2; + g_layer_x = fw / 2 - g_layer_w / 2; + g_layer_y = fh / 2 - g_layer_h / 2; } - if (g_layer_w > g_menuscreen_w * 2) g_layer_w = g_menuscreen_w * 2; - if (g_layer_h > g_menuscreen_h * 2) g_layer_h = g_menuscreen_h * 2; + if (g_layer_w > fw * 2) g_layer_w = fw * 2; + if (g_layer_h > fh * 2) g_layer_h = fh * 2; } // XXX: this is platform specific really @@ -246,7 +252,6 @@ static inline int resolution_ok(int w, int h) static void pl_vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) { int vout_w, vout_h, vout_bpp; - int buf_yoffset = 0; // special h handling, Wipeout likes to change it by 1-6 static int vsync_cnt_ms_prev; @@ -285,7 +290,7 @@ static void pl_vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) vout_w *= pl_vout_scale_w; vout_h *= pl_vout_scale_h; - update_layer_size(vout_w, vout_h); + pl_update_layer_size(vout_w, vout_h, g_menuscreen_w, g_menuscreen_h); pl_vout_buf = plat_gvideo_set_mode(&vout_w, &vout_h, &vout_bpp); if (pl_vout_buf == NULL && pl_plat_blit == NULL) @@ -295,11 +300,7 @@ static void pl_vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) pl_vout_w = vout_w; pl_vout_h = vout_h; pl_vout_bpp = vout_bpp; - pl_vout_yoffset = buf_yoffset; } - if (pl_vout_buf != NULL) - pl_vout_buf = (char *)pl_vout_buf - + pl_vout_yoffset * pl_vout_w * pl_vout_bpp / 8; menu_notify_mode_change(pl_vout_w, pl_vout_h, pl_vout_bpp); } @@ -317,7 +318,7 @@ static void pl_vout_flip(const void *vram_, int vram_ofs, int bgr24, unsigned char *dest = pl_vout_buf; const unsigned char *vram = vram_; int dstride = pl_vout_w, h1 = h; - int h_full = pl_vout_h - pl_vout_yoffset; + int h_full = pl_vout_h; int enhres = w > psx_w; int xoffs = 0, doffs; int hwrapped; @@ -465,9 +466,6 @@ out: // let's flip now pl_vout_buf = plat_gvideo_flip(); - if (pl_vout_buf != NULL) - pl_vout_buf = (char *)pl_vout_buf - + pl_vout_yoffset * pl_vout_w * pl_vout_bpp / 8; pl_rearmed_cbs.flip_cnt++; } diff --git a/frontend/plugin_lib.h b/frontend/plugin_lib.h index 855c716d..74a73729 100644 --- a/frontend/plugin_lib.h +++ b/frontend/plugin_lib.h @@ -48,6 +48,7 @@ void pl_force_clear(void); void pl_timing_prepare(int is_pal); void pl_frame_limit(void); +void pl_update_layer_size(int w, int h, int fw, int fh); // for communication with gpulib struct rearmed_cbs { -- 2.39.5