X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=platform%2Fcommon%2Fplat_sdl.c;h=4446f72e20ad16630d71ec18be014a58284d39b7;hb=refs%2Fremotes%2Fgithub%2Fmaster;hp=3948cc415533a790d5f9457dddf4f494768b06bd;hpb=9cdfc191b60cb8881552d01f84e21bdcbb48758d;p=picodrive.git diff --git a/platform/common/plat_sdl.c b/platform/common/plat_sdl.c index 3948cc41..d1e833f3 100644 --- a/platform/common/plat_sdl.c +++ b/platform/common/plat_sdl.c @@ -1,6 +1,7 @@ /* * PicoDrive * (C) notaz, 2013 + * (C) irixxxx, 2020-2024 * * This work is licensed under the terms of MAME license. * See COPYING file in the top-level directory. @@ -9,86 +10,80 @@ #include #include "../libpicofe/input.h" +#include "../libpicofe/plat.h" #include "../libpicofe/plat_sdl.h" #include "../libpicofe/in_sdl.h" #include "../libpicofe/gl.h" #include "emu.h" #include "menu_pico.h" #include "input_pico.h" +#include "plat_sdl.h" #include "version.h" -#include +#include static void *shadow_fb; +static int shadow_size; +static struct area { int w, h; } area; + +static struct in_pdata in_sdl_platform_data; + +static int sound_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 53000, -1 }; +struct plat_target plat_target = { .sound_rates = sound_rates }; + +#if defined __MIYOO__ +const char *plat_device = "miyoo"; +#elif defined __GCW0__ +const char *plat_device = "gcw0"; +#elif defined __RETROFW__ +const char *plat_device = "retrofw"; +#elif defined __DINGUX__ +const char *plat_device = "dingux"; +#else +const char *plat_device = ""; +#endif + +int plat_parse_arg(int argc, char *argv[], int *x) +{ +#if defined __OPENDINGUX__ + if (*plat_device == '\0' && strcasecmp(argv[*x], "-device") == 0) { + plat_device = argv[++(*x)]; + return 0; + } +#endif + return 1; +} -const struct in_default_bind in_sdl_defbinds[] __attribute__((weak)) = { - { SDLK_UP, IN_BINDTYPE_PLAYER12, GBTN_UP }, - { SDLK_DOWN, IN_BINDTYPE_PLAYER12, GBTN_DOWN }, - { SDLK_LEFT, IN_BINDTYPE_PLAYER12, GBTN_LEFT }, - { SDLK_RIGHT, IN_BINDTYPE_PLAYER12, GBTN_RIGHT }, - { SDLK_z, IN_BINDTYPE_PLAYER12, GBTN_A }, - { SDLK_x, IN_BINDTYPE_PLAYER12, GBTN_B }, - { SDLK_c, IN_BINDTYPE_PLAYER12, GBTN_C }, - { SDLK_a, IN_BINDTYPE_PLAYER12, GBTN_X }, - { SDLK_s, IN_BINDTYPE_PLAYER12, GBTN_Y }, - { SDLK_d, IN_BINDTYPE_PLAYER12, GBTN_Z }, - { SDLK_RETURN, IN_BINDTYPE_PLAYER12, GBTN_START }, - { SDLK_f, IN_BINDTYPE_PLAYER12, GBTN_MODE }, - { SDLK_ESCAPE, IN_BINDTYPE_EMU, PEVB_MENU }, - { SDLK_TAB, IN_BINDTYPE_EMU, PEVB_RESET }, - { SDLK_F1, IN_BINDTYPE_EMU, PEVB_STATE_SAVE }, - { SDLK_F2, IN_BINDTYPE_EMU, PEVB_STATE_LOAD }, - { SDLK_F3, IN_BINDTYPE_EMU, PEVB_SSLOT_PREV }, - { SDLK_F4, IN_BINDTYPE_EMU, PEVB_SSLOT_NEXT }, - { SDLK_F5, IN_BINDTYPE_EMU, PEVB_SWITCH_RND }, - { SDLK_F6, IN_BINDTYPE_EMU, PEVB_PICO_PPREV }, - { SDLK_F7, IN_BINDTYPE_EMU, PEVB_PICO_PNEXT }, - { SDLK_F8, IN_BINDTYPE_EMU, PEVB_PICO_SWINP }, - { SDLK_BACKSPACE, IN_BINDTYPE_EMU, PEVB_FF }, - { 0, 0, 0 } -}; - -const struct menu_keymap in_sdl_key_map[] __attribute__((weak)) = +void plat_early_init(void) { - { SDLK_UP, PBTN_UP }, - { SDLK_DOWN, PBTN_DOWN }, - { SDLK_LEFT, PBTN_LEFT }, - { SDLK_RIGHT, PBTN_RIGHT }, - { SDLK_RETURN, PBTN_MOK }, - { SDLK_ESCAPE, PBTN_MBACK }, - { SDLK_SEMICOLON, PBTN_MA2 }, - { SDLK_QUOTE, PBTN_MA3 }, - { SDLK_LEFTBRACKET, PBTN_L }, - { SDLK_RIGHTBRACKET, PBTN_R }, -}; - -const struct menu_keymap in_sdl_joy_map[] __attribute__((weak)) = +} + +int plat_target_init(void) { - { SDLK_UP, PBTN_UP }, - { SDLK_DOWN, PBTN_DOWN }, - { SDLK_LEFT, PBTN_LEFT }, - { SDLK_RIGHT, PBTN_RIGHT }, - /* joystick */ - { SDLK_WORLD_0, PBTN_MOK }, - { SDLK_WORLD_1, PBTN_MBACK }, - { SDLK_WORLD_2, PBTN_MA2 }, - { SDLK_WORLD_3, PBTN_MA3 }, -}; - -extern const char * const in_sdl_key_names[] __attribute__((weak)); - -static const struct in_pdata in_sdl_platform_data = { - .defbinds = in_sdl_defbinds, - .key_map = in_sdl_key_map, - .kmap_size = sizeof(in_sdl_key_map) / sizeof(in_sdl_key_map[0]), - .joy_map = in_sdl_joy_map, - .jmap_size = sizeof(in_sdl_joy_map) / sizeof(in_sdl_joy_map[0]), - .key_names = in_sdl_key_names, -}; +#if defined __ODBETA__ + if (*plat_device == '\0') { + /* ODbeta should always have a device tree, get the model info from there */ + FILE *f = fopen("/proc/device-tree/compatible", "r"); + if (f) { + char buf[10]; + int c = fread(buf, 1, sizeof(buf), f); + if (strncmp(buf, "gcw,", 4) == 0) + plat_device = "gcw0"; + } + } +#endif + return 0; +} + +void plat_target_finish(void) +{ +} /* 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 unsigned char yuv_y[256]; +static struct uyvy { uint32_t y:8; uint32_t vyu:24; } yuv_uyvy[65536]; void bgr_to_uyvy_init(void) { @@ -119,46 +114,121 @@ void bgr_to_uyvy_init(void) 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]; +#else + 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 pixels) +void rgb565_to_uyvy(void *d, const void *s, int w, int h, int pitch, int dpitch, 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 > 0; src += 2, dst++, pixels -= 2) - { - r0 = (src[0] >> 11) & 0x1f; - g0 = (src[0] >> 6) & 0x1f; - b0 = src[0] & 0x1f; - r1 = (src[1] >> 11) & 0x1f; - g1 = (src[1] >> 6) & 0x1f; - b1 = 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]; - // valid Y range seems to be 16..235 - 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) 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; +#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); +#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]; +#if CPU_IS_LE + 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); +#endif + } + src += pitch - (w-i); + dst += (dpitch - (w-i))/2; } } +static int clear_buf_cnt, clear_stat_cnt; + +static void resize_buffers(void) +{ + // make sure the shadow buffers are big enough in case of resize + if (shadow_size < g_menuscreen_w * g_menuscreen_h * 2) { + shadow_size = g_menuscreen_w * g_menuscreen_h * 2; + shadow_fb = realloc(shadow_fb, shadow_size); + g_menubg_ptr = realloc(g_menubg_ptr, shadow_size); + } +} + +void plat_video_set_size(int w, int h) +{ + 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) { + 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; + } + } +} + +void plat_video_set_shadow(int w, int h) +{ + g_screen_width = w; + g_screen_height = h; + g_screen_ppitch = w; + g_screen_ptr = shadow_fb; +} + void plat_video_flip(void) { + resize_buffers(); + if (plat_sdl_overlay != NULL) { SDL_Rect dstrect = { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h }; - SDL_LockYUVOverlay(plat_sdl_overlay); - rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb, - g_screen_ppitch * g_screen_height); + if (area.w <= plat_sdl_overlay->w && area.h <= plat_sdl_overlay->h) + rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb, + area.w, area.h, g_screen_ppitch, + plat_sdl_overlay->pitches[0]/2, + plat_sdl_overlay->w >= 2*area.w); SDL_UnlockYUVOverlay(plat_sdl_overlay); SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect); } @@ -166,11 +236,33 @@ void plat_video_flip(void) gl_flip(shadow_fb, g_screen_ppitch, g_screen_height); } else { - if (SDL_MUSTLOCK(plat_sdl_screen)) + if (SDL_MUSTLOCK(plat_sdl_screen)) { SDL_UnlockSurface(plat_sdl_screen); - SDL_Flip(plat_sdl_screen); + SDL_Flip(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; - PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2); + 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--; + } + } + + // for overlay/gl modes buffer ptr may change on resize + if ((plat_sdl_overlay || plat_sdl_gl_active) && + (g_screen_ptr != shadow_fb || g_screen_ppitch != g_screen_width)) { + g_screen_ppitch = g_screen_width; + g_screen_ptr = shadow_fb; + plat_video_set_buffer(g_screen_ptr); + } + if (clear_stat_cnt) { + unsigned short *d = (unsigned short *)g_screen_ptr + g_screen_ppitch * g_screen_height; + int l = g_screen_ppitch * 8; + memset((int *)(d - l), 0, l * 2); + clear_stat_cnt--; } } @@ -178,20 +270,39 @@ void plat_video_wait_vsync(void) { } +void plat_video_clear_status(void) +{ + clear_stat_cnt = 3; // do it thrice in case of triple buffering +} + +void plat_video_clear_buffers(void) +{ + if (plat_sdl_overlay || plat_sdl_gl_active) + 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 + } +} + void plat_video_menu_enter(int is_rom_loaded) { - plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, 0); - g_screen_ptr = shadow_fb; + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_UnlockSurface(plat_sdl_screen); } void plat_video_menu_begin(void) { - if (plat_sdl_overlay != NULL || plat_sdl_gl_active) { + plat_sdl_change_video_mode(g_menuscreen_w, g_menuscreen_h, 1); + resize_buffers(); + if (plat_sdl_overlay || plat_sdl_gl_active) { + g_menuscreen_pp = g_menuscreen_w; g_menuscreen_ptr = shadow_fb; } else { if (SDL_MUSTLOCK(plat_sdl_screen)) SDL_LockSurface(plat_sdl_screen); + g_menuscreen_pp = plat_sdl_screen->pitch / 2; g_menuscreen_ptr = plat_sdl_screen->pixels; } } @@ -203,8 +314,11 @@ void plat_video_menu_end(void) { 0, 0, plat_sdl_screen->w, plat_sdl_screen->h }; SDL_LockYUVOverlay(plat_sdl_overlay); - rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb, - g_menuscreen_pp * g_menuscreen_h); + if (g_menuscreen_w <= plat_sdl_overlay->w && g_menuscreen_h <= plat_sdl_overlay->h) + rgb565_to_uyvy(plat_sdl_overlay->pixels[0], shadow_fb, + g_menuscreen_w, g_menuscreen_h, g_menuscreen_pp, + plat_sdl_overlay->pitches[0]/2, + plat_sdl_overlay->w >= 2 * g_menuscreen_w); SDL_UnlockYUVOverlay(plat_sdl_overlay); SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect); @@ -218,7 +332,6 @@ void plat_video_menu_end(void) SDL_Flip(plat_sdl_screen); } g_menuscreen_ptr = NULL; - } void plat_video_menu_leave(void) @@ -227,21 +340,56 @@ void plat_video_menu_leave(void) void plat_video_loop_prepare(void) { - plat_sdl_change_video_mode(g_screen_width, g_screen_height, 0); - - if (plat_sdl_overlay != NULL || plat_sdl_gl_active) { + // take over any new vout settings + 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 + if (plat_sdl_overlay || plat_sdl_gl_active) { + if (g_menuscreen_w * 240 >= g_menuscreen_h * 320) { + g_screen_width = (240 * g_menuscreen_w/g_menuscreen_h) & ~1; + g_screen_height= 240; + } else { + g_screen_width = 320; + g_screen_height= (320 * g_menuscreen_h/g_menuscreen_w) & ~1; + } + g_screen_ppitch = g_screen_width; g_screen_ptr = shadow_fb; } else { + g_screen_width = plat_sdl_screen->w; + g_screen_height = plat_sdl_screen->h; + g_screen_ppitch = plat_sdl_screen->pitch/2; if (SDL_MUSTLOCK(plat_sdl_screen)) SDL_LockSurface(plat_sdl_screen); g_screen_ptr = plat_sdl_screen->pixels; } - PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2); + + plat_video_set_size(g_screen_width, g_screen_height); + plat_video_set_buffer(g_screen_ptr); } -void plat_early_init(void) +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 +#endif + { + 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) @@ -252,19 +400,22 @@ static void plat_sdl_quit(void) void plat_init(void) { - int shadow_size; int ret; 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; +#endif 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_w = plat_sdl_screen->w; - g_menuscreen_h = plat_sdl_screen->h; g_menuscreen_pp = g_menuscreen_w; g_menuscreen_ptr = NULL; @@ -272,8 +423,8 @@ void plat_init(void) if (shadow_size < 320 * 480 * 2) shadow_size = 320 * 480 * 2; - shadow_fb = malloc(shadow_size); - g_menubg_ptr = malloc(shadow_size); + shadow_fb = calloc(1, shadow_size); + g_menubg_ptr = calloc(1, shadow_size); if (shadow_fb == NULL || g_menubg_ptr == NULL) { fprintf(stderr, "OOM\n"); exit(1); @@ -284,10 +435,18 @@ void plat_init(void) g_screen_ppitch = 320; g_screen_ptr = shadow_fb; + plat_target_setup_input(); + in_sdl_platform_data.defbinds = in_sdl_defbinds, + in_sdl_platform_data.kmap_size = in_sdl_key_map_sz, + in_sdl_platform_data.key_map = in_sdl_key_map, + in_sdl_platform_data.jmap_size = in_sdl_joy_map_sz, + in_sdl_platform_data.joy_map = in_sdl_joy_map, + in_sdl_platform_data.key_names = in_sdl_key_names, in_sdl_init(&in_sdl_platform_data, plat_sdl_event_handler); in_probe(); bgr_to_uyvy_init(); + linux_menu_init(); } void plat_finish(void)