/* 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)
}
}
-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;
+ }
+ }
}
MA_OPT_SWFILTER,
MA_OPT_GAMMA,
MA_OPT_VOUT_MODE,
+ MA_OPT_VOUT_FULL,
MA_OPT_SCANLINES,
MA_OPT_SCANLINE_LEVEL,
MA_OPT_CENTERING,
#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
#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; }
// ------------ 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
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),
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,
#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);
*/
#include <stdio.h>
+#include <assert.h>
#include <SDL.h>
#include "libpicofe/input.h"
#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 },
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)
void plat_init(void)
{
+ const SDL_version *ver;
int shadow_size;
int ret;
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);
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)
{
}
-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,
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];
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);
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);
}
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,
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);
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)
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;
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)
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,
}
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 */
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;
}
/* 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;
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:
}
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
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;
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)
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);
}
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;
// 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++;
}