X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=frontend%2Fplat_sdl.c;h=5e11cf8434aaeaf10a34bb8aafe96cce4f275e3e;hb=refs%2Fheads%2Fmaster;hp=ec2d9c24ab6270e82794e8b97827a9a337ef5000;hpb=5b9aa74918361ff5d306c39cb695a77d7ea40b8f;p=pcsx_rearmed.git diff --git a/frontend/plat_sdl.c b/frontend/plat_sdl.c index ec2d9c24..09b17783 100644 --- a/frontend/plat_sdl.c +++ b/frontend/plat_sdl.c @@ -1,5 +1,5 @@ /* - * (C) Gražvydas "notaz" Ignotas, 2011,2012 + * (C) Gražvydas "notaz" Ignotas, 2011-2013 * * This work is licensed under the terms of any of these licenses * (at your option): @@ -9,20 +9,27 @@ */ #include +#include #include +#include "../libpcsxcore/plugins.h" #include "libpicofe/input.h" #include "libpicofe/in_sdl.h" #include "libpicofe/menu.h" #include "libpicofe/fonts.h" #include "libpicofe/plat_sdl.h" +#include "libpicofe/plat.h" #include "libpicofe/gl.h" -#include "../plugins/gpulib/cspace.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 }, @@ -52,49 +59,168 @@ static const struct in_default_bind in_sdl_defbinds[] = { { 0, 0, 0 } }; -static int psx_w, psx_h; +const struct menu_keymap in_sdl_key_map[] = +{ + { 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[] = +{ + { 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 }, +}; + +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]), +}; + +static int psx_w = 256, psx_h = 240; static void *shadow_fb, *menubg_img; +static int vout_fullscreen_old; +static int forced_clears; +static int forced_flips; +static int sdl12_compat; +static int resized; static int in_menu; -static int change_video_mode(void) +static int gl_w_prev, gl_h_prev, gl_quirks_prev; +static float gl_vertices[] = { + -1.0f, 1.0f, 0.0f, // 0 0 1 + 1.0f, 1.0f, 0.0f, // 1 ^ + -1.0f, -1.0f, 0.0f, // 2 | 2 3 + 1.0f, -1.0f, 0.0f, // 3 +--> +}; + +static void handle_window_resize(void); +static void handle_scaler_resize(int w, int h); +static void centered_clear(void); + +static int plugin_owns_display(void) { - int w, h; + // if true, a plugin is drawing and flipping + return (pl_rearmed_cbs.gpu_caps & GPU_CAP_OWNS_DISPLAY); +} - if (in_menu) { - w = g_menuscreen_w; - h = g_menuscreen_h; - } - else { - w = psx_w; - h = psx_h; +static void plugin_update(void) +{ + // used by some plugins... + pl_rearmed_cbs.screen_w = plat_sdl_screen->w; + pl_rearmed_cbs.screen_h = plat_sdl_screen->h; + pl_rearmed_cbs.gles_display = gl_es_display; + pl_rearmed_cbs.gles_surface = gl_es_surface; + plugin_call_rearmed_cbs(); +} + +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; + if (!in_menu && plat_sdl_gl_active && plugin_owns_display()) { + // the plugin flips by itself so resize has to be handled here + handle_window_resize(); + if (GPU_open != NULL) { + int ret = GPU_open(&gpuDisp, "PCSX", NULL); + if (ret) + fprintf(stderr, "GPU_open: %d\n", ret); + } + } + } + return; + case SDL_ACTIVEEVENT: + // no need to redraw? + return; + default: + break; } + plat_sdl_event_handler(event_); +} - return plat_sdl_change_video_mode(w, h); +static void quit_cb(void) +{ + emu_core_ask_exit(); +} + +static void get_layer_pos(int *x, int *y, int *w, int *h) +{ + // always fill entire SDL window + *x = *y = 0; + *w = pl_rearmed_cbs.screen_w; + *h = pl_rearmed_cbs.screen_h; } void plat_init(void) { + static const char *hwfilters[] = { "linear", "nearest", NULL }; + const SDL_version *ver; + int shadow_size; int ret; + plat_sdl_quit_cb = quit_cb; + + old_fullscreen = -1; // hack + ret = plat_sdl_init(); 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); - shadow_fb = malloc(640 * 512 * 2); - menubg_img = malloc(640 * 512 * 2); + shadow_size = g_menuscreen_w * g_menuscreen_h * 2; + // alloc enough for double res. rendering + if (shadow_size < 1024 * 512 * 2) + shadow_size = 1024 * 512 * 2; + + shadow_fb = malloc(shadow_size); + menubg_img = malloc(shadow_size); if (shadow_fb == NULL || menubg_img == NULL) { fprintf(stderr, "OOM\n"); exit(1); } - in_sdl_init(in_sdl_defbinds, 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(); + + assert(plat_sdl_screen); + plugin_update(); + if (plat_target.vout_method == vout_mode_gl) + gl_w_prev = plat_sdl_screen->w, gl_h_prev = plat_sdl_screen->h; + if (vout_mode_gl != -1) + plat_target.hwfilters = hwfilters; } void plat_finish(void) @@ -110,22 +236,60 @@ 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; + 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; + } + } +} - 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); + plat_target.vout_method = 0; } + handle_scaler_resize(w, h); } static void overlay_blit(int doffs, const void *src_, int w, int h, @@ -134,6 +298,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]; @@ -141,11 +306,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); @@ -153,49 +318,351 @@ 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); } -void *plat_gvideo_set_mode(int *w, int *h, int *bpp) +static void gl_finish_pl(void) { - psx_w = *w; - psx_h = *h; - change_video_mode(); + if (plugin_owns_display() && GPU_close != NULL) + GPU_close(); + gl_destroy(); +} + +static void gl_resize(void) +{ + int w = in_menu ? g_menuscreen_w : psx_w; + int h = in_menu ? g_menuscreen_h : psx_h; + + gl_quirks &= ~(GL_QUIRK_SCALING_NEAREST | GL_QUIRK_VSYNC_ON); + if (plat_target.hwfilter) // inverted from plat_sdl_gl_scaling() + gl_quirks |= GL_QUIRK_SCALING_NEAREST; + if (g_opts & OPT_VSYNC) + gl_quirks |= GL_QUIRK_VSYNC_ON; + + if (plugin_owns_display()) + w = plat_sdl_screen->w, h = plat_sdl_screen->h; + if (plat_sdl_gl_active) { + if (w == gl_w_prev && h == gl_h_prev && gl_quirks == gl_quirks_prev) + return; + gl_finish_pl(); + } + plat_sdl_gl_active = (gl_create(window, &gl_quirks, w, h) == 0); + if (plat_sdl_gl_active) + gl_w_prev = w, gl_h_prev = h, gl_quirks_prev = gl_quirks; + else { + fprintf(stderr, "warning: could not init GL.\n"); + plat_target.vout_method = 0; + } + handle_scaler_resize(w, h); + plugin_update(); + forced_flips = 0; // interferes with gl +} + +static void overlay_or_gl_check_enable(void) +{ + int ovl_on = plat_target.vout_method == vout_mode_overlay || + plat_target.vout_method == vout_mode_overlay2x; + int gl_on = plat_target.vout_method == vout_mode_gl; + if (!gl_on && plat_sdl_gl_active) { + gl_finish_pl(); + pl_rearmed_cbs.gles_display = gl_es_display; + pl_rearmed_cbs.gles_surface = gl_es_surface; + plat_sdl_gl_active = 0; + } + if (!ovl_on && plat_sdl_overlay) { + SDL_FreeYUVOverlay(plat_sdl_overlay); + plat_sdl_overlay = NULL; + } + if (ovl_on) + overlay_resize(0); + else if (gl_on) + gl_resize(); +} + +static void centered_clear(void) +{ + int dstride = plat_sdl_screen->pitch / 2; + int w = plat_sdl_screen->w; + int h = plat_sdl_screen->h; + unsigned short *dst; + + if (plat_sdl_gl_active) { + gl_clear(); + return; + } + + 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); + + 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, + int sstride, int bgr24) +{ + const unsigned short *src = src_; + unsigned short *dst; + int dstride; + + 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); + + if (bgr24) { + for (; h > 0; dst += dstride, src += sstride, h--) + bgr888_to_rgb565(dst, src, w * 3); + } + else { + for (; h > 0; dst += dstride, src += sstride, h--) + bgr555_to_rgb565(dst, src, w * 2); + } + + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_UnlockSurface(plat_sdl_screen); +} + +static void centered_blit_menu(void) +{ + const unsigned short *src = g_menuscreen_ptr; + int w = g_menuscreen_w; + int h = g_menuscreen_h; + unsigned short *dst; + int dstride, len; + + if (SDL_MUSTLOCK(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); + + for (; h > 0; dst += dstride, src += g_menuscreen_pp, h--) + memcpy(dst, src, len * 2); + + 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) +{ + 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); + if (SDL_MUSTLOCK(plat_sdl_screen)) + SDL_UnlockSurface(plat_sdl_screen); +} + +static void *setup_blit_callbacks(int w, int h) +{ + pl_plat_clear = NULL; + pl_plat_blit = NULL; + pl_plat_hud_print = NULL; if (plat_sdl_overlay != NULL) { pl_plat_clear = plat_sdl_overlay_clear; pl_plat_blit = overlay_blit; pl_plat_hud_print = overlay_hud_print; - return NULL; + } + else if (plat_sdl_gl_active) { + return shadow_fb; } else { - pl_plat_clear = NULL; - pl_plat_blit = NULL; - pl_plat_hud_print = NULL; - if (plat_sdl_gl_active) - return shadow_fb; - else + 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, had_gl = 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 { + 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; + } + if (plat_sdl_gl_active) { + gl_finish_pl(); + plat_sdl_gl_active = 0; + had_gl = 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); + if (vout_mode_gl != -1) + update_wm_display_window(); + // overlay needs the latest plat_sdl_screen + if (had_overlay) + overlay_resize(1); + if (had_gl) + gl_resize(); + centered_clear(); + plugin_update(); + 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; + float w_mul, h_mul; + int x, y; + pl_update_layer_size(w, h, ww, wh); + if (layer_w_old != g_layer_w || layer_h_old != g_layer_h) + forced_clears = 3; + + w_mul = 2.0f / ww; + h_mul = 2.0f / wh; + x = (ww - g_layer_w) / 2; + y = (wh - g_layer_h) / 2; + gl_vertices[3*0+0] = gl_vertices[3*2+0] = -1.0f + x * w_mul; + gl_vertices[3*1+0] = gl_vertices[3*3+0] = -1.0f + (x + g_layer_w) * w_mul; + gl_vertices[3*2+1] = gl_vertices[3*3+1] = -1.0f + y * h_mul; + gl_vertices[3*0+1] = gl_vertices[3*1+1] = -1.0f + (y + g_layer_h) * h_mul; +} + +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; +} + +void *plat_gvideo_set_mode(int *w, int *h, int *bpp) +{ + psx_w = *w; + psx_h = *h; + + if (plat_sdl_gl_active && plugin_owns_display()) + return NULL; + + if (plat_sdl_overlay != NULL) + overlay_resize(0); + else if (plat_sdl_gl_active) { + memset(shadow_fb, 0, (*w) * (*h) * 2); + gl_resize(); } + 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; + gl_flip_v(shadow_fb, psx_w, psx_h, g_scaler != SCALE_FULLSCREEN ? gl_vertices : NULL); + 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) @@ -204,35 +671,69 @@ void plat_gvideo_close(void) void plat_video_menu_enter(int is_rom_loaded) { + int d; + 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; - change_video_mode(); + if (plat_target.vout_method == 0) + change_mode(g_menuscreen_w, g_menuscreen_h); + else + overlay_or_gl_check_enable(); + centered_clear(); + + for (d = 0; d < IN_MAX_DEVS; d++) + in_set_config_int(d, IN_CFG_ANALOG_MAP_ULDR, 1); } void plat_video_menu_begin(void) { - if (plat_sdl_overlay != NULL || plat_sdl_gl_active) { - g_menuscreen_ptr = shadow_fb; - } - else { - SDL_LockSurface(plat_sdl_screen); - g_menuscreen_ptr = plat_sdl_screen->pixels; + 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); } + overlay_or_gl_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, @@ -242,27 +743,58 @@ void plat_video_menu_end(void) SDL_DisplayYUVOverlay(plat_sdl_overlay, &dstrect); } else if (plat_sdl_gl_active) { - gl_flip(g_menuscreen_ptr, g_menuscreen_w, g_menuscreen_h); + gl_flip_v(g_menuscreen_ptr, g_menuscreen_w, g_menuscreen_h, + g_scaler != SCALE_FULLSCREEN ? gl_vertices : NULL); } else { - SDL_UnlockSurface(plat_sdl_screen); - SDL_Flip(plat_sdl_screen); + centered_blit_menu(); + 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) { + int d; + 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); + overlay_or_gl_check_enable(); + centered_clear(); + setup_blit_callbacks(psx_w, psx_h); + + for (d = 0; d < IN_MAX_DEVS; d++) + in_set_config_int(d, IN_CFG_ANALOG_MAP_ULDR, 0); } -/* unused stuff */ void *plat_prepare_screenshot(int *w, int *h, int *bpp) { - return 0; + if (plat_sdl_screen && !SDL_MUSTLOCK(plat_sdl_screen) && + plat_sdl_overlay == NULL && !plat_sdl_gl_active) + { + *w = plat_sdl_screen->pitch / 2; + *h = plat_sdl_screen->h; + *bpp = 16; + return plat_sdl_screen->pixels; + } + fprintf(stderr, "screenshot not implemented in current mode\n"); + return NULL; } -void plat_trigger_vibrate(int is_strong) +void plat_trigger_vibrate(int pad, int low, int high) { }