From: notaz Date: Wed, 16 Aug 2023 22:55:11 +0000 (+0300) Subject: try to emulate borders properly X-Git-Tag: r24l~233 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5bbe183f3aa15f21613fcf58ead2016c9283a842;p=pcsx_rearmed.git try to emulate borders properly --- diff --git a/frontend/cspace.c b/frontend/cspace.c index 06167a90..bd5e7a3e 100644 --- a/frontend/cspace.c +++ b/frontend/cspace.c @@ -215,7 +215,7 @@ void bgr555_to_uyvy(void *d, const void *s, int pixels) int r0, g0, b0, r1, g1, b1; int y0, y1, u, v; - for (; pixels > 0; src += 2, dst++, pixels -= 2) + for (; pixels > 1; src += 2, dst++, pixels -= 2) { b0 = (src[0] >> 10) & 0x1f; g0 = (src[0] >> 5) & 0x1f; diff --git a/frontend/libretro.c b/frontend/libretro.c index 72939585..0be62b94 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -80,7 +80,7 @@ static unsigned msg_interface_version = 0; static void *vout_buf; static void *vout_buf_ptr; static int vout_width, vout_height; -static int vout_doffs_old, vout_fb_dirty; +static int vout_fb_dirty; static bool vout_can_dupe; static bool duping_enable; static bool found_bios; @@ -267,29 +267,22 @@ static void convert(void *buf, size_t bytes) } #endif -static void vout_flip(const void *vram, int stride, int bgr24, int w, int h) +static void vout_flip(const void *vram, int stride, int bgr24, + int x, int y, int w, int h, int dims_changed) { unsigned short *dest = vout_buf_ptr; const unsigned short *src = vram; int dstride = vout_width, h1 = h; - int doffs; - if (vram == NULL) + if (vram == NULL || dims_changed) { + memset(vout_buf_ptr, 0, dstride * vout_height * 2); // blanking - memset(vout_buf_ptr, 0, dstride * h * 2); - goto out; + if (vram == NULL) + goto out; } - doffs = (vout_height - h) * dstride; - doffs += (dstride - w) / 2 & ~1; - if (doffs != vout_doffs_old) - { - // clear borders - memset(vout_buf_ptr, 0, dstride * h * 2); - vout_doffs_old = doffs; - } - dest += doffs; + dest += x + y * dstride; if (bgr24) { @@ -2152,11 +2145,37 @@ static void update_variables(bool in_flight) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { if (strcmp(var.value, "disabled") == 0) - Config.GpuListWalking = 0; + Config.GpuListWalking = 0; else if (strcmp(var.value, "enabled") == 0) - Config.GpuListWalking = 1; + Config.GpuListWalking = 1; else // auto - Config.GpuListWalking = -1; + Config.GpuListWalking = -1; + } + + var.value = NULL; + var.key = "pcsx_rearmed_screen_centering"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "game") == 0) + pl_rearmed_cbs.screen_centering_type = 1; + else if (strcmp(var.value, "manual") == 0) + pl_rearmed_cbs.screen_centering_type = 2; + else // auto + pl_rearmed_cbs.screen_centering_type = 0; + } + + var.value = NULL; + var.key = "pcsx_rearmed_screen_centering_x"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + pl_rearmed_cbs.screen_centering_x = atoi(var.value); + } + + var.value = NULL; + var.key = "pcsx_rearmed_screen_centering_y"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + pl_rearmed_cbs.screen_centering_y = atoi(var.value); } #ifdef THREAD_RENDERING diff --git a/frontend/libretro_core_options.h b/frontend/libretro_core_options.h index 389e9e68..f633d48c 100644 --- a/frontend/libretro_core_options.h +++ b/frontend/libretro_core_options.h @@ -435,6 +435,50 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, "auto", }, + { + "pcsx_rearmed_screen_centering", + "(GPU) Screen centering", + NULL, + "The PSX has a feature allowing it to shift the image position on screen. Some (mostly PAL) games used this feature in a strange way making the image miscentered and causing borders to appear. With 'Auto' the emulator tries to correct this miscentering automatically. 'Game-controlled' uses the settings supplied by the game. 'Manual' allows to override those values with the settings below.", + NULL, + "video", + { + { "auto", "Auto" }, + { "game", "Game-controlled" }, + { "manual", "Manual" }, + { NULL, NULL }, + }, + "auto", + }, +#define V(x) { #x, NULL } + { + "pcsx_rearmed_screen_centering_x", + "(GPU) Manual screen centering X", + NULL, + "X offset of the frame buffer. Only effective when 'Screen centering' is set to 'Manual'.", + NULL, + "video", + { + V(-16), V(-14), V(-12), V(-10), V(-8), V(-6), V(-4), V(-2), V(0), V(2), V(4), V(6), V(8), V(10), V(12), V(14), V(16), + { NULL, NULL }, + }, + "0", + }, + { + "pcsx_rearmed_screen_centering_y", + "(GPU) Manual screen centering Y", + NULL, + "Y offset of the frame buffer. Only effective when 'Screen centering' is set to 'Manual'.", + NULL, + "video", + { + V(-16), V(-15), V(-14), V(-13), V(-12), V(-11), V(-10), V(-9), V(-8), V(-7), V(-6), V(-5), V(-4), V(-3), V(-2), V(-1), + V(0), V(1), V(2), V(3), V(4), V(5), V(6), V(7), V(8), V(9), V(10), V(11), V(12), V(13), V(14), V(15), V(16), + { NULL, NULL }, + }, + "0", + }, +#undef V #ifdef GPU_NEON { "pcsx_rearmed_neon_interlace_enable_v2", diff --git a/frontend/menu.c b/frontend/menu.c index cdeeae2c..4272154a 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -87,6 +87,7 @@ typedef enum MA_OPT_VOUT_MODE, MA_OPT_SCANLINES, MA_OPT_SCANLINE_LEVEL, + MA_OPT_CENTERING, } menu_id; static int last_vout_w, last_vout_h, last_vout_bpp; @@ -452,6 +453,9 @@ static const struct { CE_INTVAL_P(gpu_peopsgl.iVRamSize), CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection), CE_INTVAL_P(gpu_peopsgl.dwActFixes), + CE_INTVAL_P(screen_centering_type), + CE_INTVAL_P(screen_centering_x), + CE_INTVAL_P(screen_centering_y), CE_INTVAL(spu_config.iUseReverb), CE_INTVAL(spu_config.iXAPitch), CE_INTVAL(spu_config.iUseInterpolation), @@ -1254,6 +1258,7 @@ static const char *men_soft_filter[] = { "None", #endif NULL }; static const char *men_dummy[] = { NULL }; +static const char *men_centering[] = { "Auto", "Ingame", "Force", NULL }; static const char h_scaler[] = "int. 2x - scales w. or h. 2x if it fits on screen\n" "int. 4:3 - uses integer if possible, else fractional"; static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n" @@ -1318,6 +1323,7 @@ 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_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 ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1), @@ -2585,7 +2591,7 @@ void menu_init(void) i = plat_target.cpu_clock_set != NULL && plat_target.cpu_clock_get != NULL && cpu_clock_st > 0; - me_enable(e_menu_gfx_options, MA_OPT_CPU_CLOCKS, i); + me_enable(e_menu_options, MA_OPT_CPU_CLOCKS, i); i = me_id2offset(e_menu_gfx_options, MA_OPT_VOUT_MODE); e_menu_gfx_options[i].data = plat_target.vout_methods; diff --git a/frontend/plugin_lib.c b/frontend/plugin_lib.c index d5cec766..bdf09c71 100644 --- a/frontend/plugin_lib.c +++ b/frontend/plugin_lib.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "libpicofe/fonts.h" #include "libpicofe/input.h" @@ -118,9 +119,9 @@ static void print_fps(int h, int border) pl_rearmed_cbs.vsps_cur); } -static void print_cpu_usage(int w, int h, int border) +static void print_cpu_usage(int x, int h) { - hud_printf(pl_vout_buf, pl_vout_w, pl_vout_w - border - 28, + hud_printf(pl_vout_buf, pl_vout_w, x - 28, h - HUD_HEIGHT, "%3d", pl_rearmed_cbs.cpu_usage); } @@ -154,13 +155,11 @@ static __attribute__((noinline)) void draw_active_chans(int vout_w, int vout_h) } } -static void print_hud(int w, int h, int xborder) +static void print_hud(int x, int w, int h) { - if (h < 16) + if (h < 192) return; - if (w < pl_vout_w) - xborder += (pl_vout_w - w) / 2; if (h > pl_vout_h) h = pl_vout_h; @@ -168,12 +167,12 @@ static void print_hud(int w, int h, int xborder) draw_active_chans(w, h); if (hud_msg[0] != 0) - print_msg(h, xborder); + print_msg(h, x); else if (g_opts & OPT_SHOWFPS) - print_fps(h, xborder); + print_fps(h, x); if (g_opts & OPT_SHOWCPU) - print_cpu_usage(w, h, xborder); + print_cpu_usage(x + w, h); } /* update scaler target size according to user settings */ @@ -262,11 +261,7 @@ static void pl_vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) if (pl_rearmed_cbs.only_16bpp) vout_bpp = 16; - // don't use very low heights - if (vout_h < 192) { - buf_yoffset = (192 - vout_h) / 2; - vout_h = 192; - } + assert(vout_h >= 192); pl_vout_scale_w = pl_vout_scale_h = 1; #ifdef __ARM_NEON__ @@ -307,14 +302,15 @@ static void pl_vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) menu_notify_mode_change(pl_vout_w, pl_vout_h, pl_vout_bpp); } -static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h) +static void pl_vout_flip(const void *vram, int stride, int bgr24, + int x, int y, int w, int h, int dims_changed) { - static int doffs_old, clear_counter; + static int clear_counter; unsigned char *dest = pl_vout_buf; const unsigned short *src = vram; int dstride = pl_vout_w, h1 = h; int h_full = pl_vout_h - pl_vout_yoffset; - int doffs; + int xoffs = 0, doffs; pcnt_start(PCNT_BLIT); @@ -328,12 +324,15 @@ static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h) goto out_hud; } - // borders - doffs = (dstride - w * pl_vout_scale_w) / 2 & ~1; + assert(x + w <= pl_vout_w); + assert(y + h <= pl_vout_h); + + // offset + xoffs = x * pl_vout_scale_w; + doffs = xoffs + y * dstride; - if (doffs > doffs_old) + if (dims_changed) clear_counter = 2; - doffs_old = doffs; if (clear_counter > 0) { if (pl_plat_clear) @@ -409,7 +408,7 @@ static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h) } out_hud: - print_hud(w * pl_vout_scale_w, h * pl_vout_scale_h, 0); + print_hud(xoffs, w * pl_vout_scale_w, (y + h) * pl_vout_scale_h); out: pcnt_end(PCNT_BLIT); diff --git a/frontend/plugin_lib.h b/frontend/plugin_lib.h index 7caa87c8..e48ed521 100644 --- a/frontend/plugin_lib.h +++ b/frontend/plugin_lib.h @@ -54,7 +54,7 @@ struct rearmed_cbs { int (*pl_vout_open)(void); void (*pl_vout_set_mode)(int w, int h, int raw_w, int raw_h, int bpp); void (*pl_vout_flip)(const void *vram, int stride, int bgr24, - int w, int h); + int x, int y, int w, int h, int dims_changed); void (*pl_vout_close)(void); void *(*mmap)(unsigned int size); void (*munmap)(void *ptr, unsigned int size); @@ -110,6 +110,9 @@ struct rearmed_cbs { } gpu_peopsgl; // misc int gpu_caps; + int screen_centering_type; // 0 - auto, 1 - game conrolled, 2 - manual + int screen_centering_x; + int screen_centering_y; }; extern struct rearmed_cbs pl_rearmed_cbs; diff --git a/plugins/gpu_neon/psx_gpu_if.c b/plugins/gpu_neon/psx_gpu_if.c index fc4706c1..fe3a7ecd 100644 --- a/plugins/gpu_neon/psx_gpu_if.c +++ b/plugins/gpu_neon/psx_gpu_if.c @@ -57,7 +57,7 @@ int do_cmd_list(uint32_t *list, int count, int *last_cmd) #define ENHANCEMENT_BUF_SIZE (1024 * 1024 * 2 * 4 + 4096 * 2) -static uint16_t *get_enhancement_bufer(int *x, int *y, int *w, int *h, +static void *get_enhancement_bufer(int *x, int *y, int *w, int *h, int *vram_h) { uint16_t *ret = select_enhancement_buf_ptr(&egpu, *x); diff --git a/plugins/gpulib/gpu.c b/plugins/gpulib/gpu.c index ed04d731..6c811d8d 100644 --- a/plugins/gpulib/gpu.c +++ b/plugins/gpulib/gpu.c @@ -9,6 +9,7 @@ */ #include +#include #include #include /* for calloc */ @@ -65,28 +66,90 @@ static noinline void do_reset(void) gpu.regs[3] = 1; gpu.screen.hres = gpu.screen.w = 256; gpu.screen.vres = gpu.screen.h = 240; + gpu.screen.x = gpu.screen.y = 0; } static noinline void update_width(void) { + static const short hres_all[8] = { 256, 368, 320, 368, 512, 368, 640, 368 }; + static const uint8_t hdivs[8] = { 10, 7, 8, 7, 5, 7, 4, 7 }; + uint8_t hdiv = hdivs[(gpu.status >> 16) & 7]; + int hres = hres_all[(gpu.status >> 16) & 7]; + int pal = gpu.status & PSX_GPU_STATUS_PAL; int sw = gpu.screen.x2 - gpu.screen.x1; - if (sw <= 0 || sw >= 2560) - // full width - gpu.screen.w = gpu.screen.hres; - else - gpu.screen.w = sw * gpu.screen.hres / 2560; + int x = 0, x_auto; + if (sw <= 0) + /* nothing displayed? */; + else { + int s = pal ? 656 : 608; // or 600? pal is just a guess + x = (gpu.screen.x1 - s) / hdiv; + x = (x + 1) & ~1; // blitter limitation + sw /= hdiv; + sw = (sw + 2) & ~3; // according to nocash + switch (gpu.state.screen_centering_type) { + case 1: + break; + case 2: + x = gpu.state.screen_centering_x; + break; + default: + // correct if slightly miscentered + x_auto = (hres - sw) / 2 & ~3; + if ((uint32_t)x_auto <= 8u && abs(x) < 24) + x = x_auto; + } + if (x + sw > hres) + sw = hres - x; + // .x range check is done in vout_update() + } + // reduce the unpleasant right border that a few games have + if (gpu.state.screen_centering_type == 0 + && x <= 4 && hres - (x + sw) >= 4) + hres -= 4; + gpu.screen.x = x; + gpu.screen.w = sw; + gpu.screen.hres = hres; + gpu.state.dims_changed = 1; + //printf("xx %d %d -> %2d, %d / %d\n", + // gpu.screen.x1, gpu.screen.x2, x, sw, hres); } static noinline void update_height(void) { - // TODO: emulate this properly.. + int pal = gpu.status & PSX_GPU_STATUS_PAL; + int dheight = gpu.status & PSX_GPU_STATUS_DHEIGHT; + int y = gpu.screen.y1 - (pal ? 39 : 16); // 39 for spyro int sh = gpu.screen.y2 - gpu.screen.y1; - if (gpu.status & PSX_GPU_STATUS_DHEIGHT) - sh *= 2; - if (sh <= 0 || sh > gpu.screen.vres) - sh = gpu.screen.vres; - + int center_tol = 16; + int vres = 240; + + if (pal && (sh > 240 || gpu.screen.vres == 256)) + vres = 256; + if (dheight) + y *= 2, sh *= 2, vres *= 2, center_tol *= 2; + if (sh <= 0) + /* nothing displayed? */; + else { + switch (gpu.state.screen_centering_type) { + case 1: + break; + case 2: + y = gpu.state.screen_centering_y; + break; + default: + // correct if slightly miscentered + if ((uint32_t)(vres - sh) <= 1 && abs(y) <= center_tol) + y = 0; + } + if (y + sh > vres) + sh = vres - y; + } + gpu.screen.y = y; gpu.screen.h = sh; + gpu.screen.vres = vres; + gpu.state.dims_changed = 1; + //printf("yy %d %d -> %d, %d / %d\n", + // gpu.screen.y1, gpu.screen.y2, y, sh, vres); } static noinline void decide_frameskip(void) @@ -123,8 +186,8 @@ static noinline int decide_frameskip_allow(uint32_t cmd_e3) uint32_t x = cmd_e3 & 0x3ff; uint32_t y = (cmd_e3 >> 10) & 0x3ff; gpu.frameskip.allow = (gpu.status & PSX_GPU_STATUS_INTERLACE) || - (uint32_t)(x - gpu.screen.x) >= (uint32_t)gpu.screen.w || - (uint32_t)(y - gpu.screen.y) >= (uint32_t)gpu.screen.h; + (uint32_t)(x - gpu.screen.src_x) >= (uint32_t)gpu.screen.w || + (uint32_t)(y - gpu.screen.src_y) >= (uint32_t)gpu.screen.h; return gpu.frameskip.allow; } @@ -266,11 +329,6 @@ long GPUshutdown(void) void GPUwriteStatus(uint32_t data) { - //senquack TODO: Would it be wise to add cmd buffer flush here, since - // status settings can affect commands already in buffer? - - static const short hres[8] = { 256, 368, 320, 384, 512, 512, 640, 640 }; - static const short vres[4] = { 240, 480, 256, 480 }; uint32_t cmd = data >> 24; if (cmd < ARRAY_SIZE(gpu.regs)) { @@ -289,8 +347,10 @@ void GPUwriteStatus(uint32_t data) do_cmd_reset(); break; case 0x03: - if (data & 1) + if (data & 1) { gpu.status |= PSX_GPU_STATUS_BLANKING; + gpu.state.dims_changed = 1; // for hud clearing + } else gpu.status &= ~PSX_GPU_STATUS_BLANKING; break; @@ -299,8 +359,8 @@ void GPUwriteStatus(uint32_t data) gpu.status |= PSX_GPU_STATUS_DMA(data & 3); break; case 0x05: - gpu.screen.x = data & 0x3ff; - gpu.screen.y = (data >> 10) & 0x1ff; + gpu.screen.src_x = data & 0x3ff; + gpu.screen.src_y = (data >> 10) & 0x1ff; if (gpu.frameskip.set) { decide_frameskip_allow(gpu.ex_regs[3]); if (gpu.frameskip.last_flip_frame != *gpu.state.frame_count) { @@ -321,8 +381,6 @@ void GPUwriteStatus(uint32_t data) break; case 0x08: gpu.status = (gpu.status & ~0x7f0000) | ((data & 0x3F) << 17) | ((data & 0x40) << 10); - gpu.screen.hres = hres[(gpu.status >> 16) & 7]; - gpu.screen.vres = vres[(gpu.status >> 19) & 3]; update_width(); update_height(); renderer_notify_res_change(); @@ -832,15 +890,23 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs) gpu.frameskip.set = cbs->frameskip; gpu.frameskip.advice = &cbs->fskip_advice; gpu.frameskip.force = &cbs->fskip_force; - gpu.frameskip.dirty = &cbs->fskip_dirty; + gpu.frameskip.dirty = (void *)&cbs->fskip_dirty; gpu.frameskip.active = 0; gpu.frameskip.frame_ready = 1; gpu.state.hcnt = cbs->gpu_hcnt; gpu.state.frame_count = cbs->gpu_frame_count; gpu.state.allow_interlace = cbs->gpu_neon.allow_interlace; gpu.state.enhancement_enable = cbs->gpu_neon.enhancement_enable; + if (gpu.state.screen_centering_type != cbs->screen_centering_type + || gpu.state.screen_centering_x != cbs->screen_centering_x + || gpu.state.screen_centering_y != cbs->screen_centering_y) { + gpu.state.screen_centering_type = cbs->screen_centering_type; + gpu.state.screen_centering_x = cbs->screen_centering_x; + gpu.state.screen_centering_y = cbs->screen_centering_y; + update_width(); + update_height(); + } - gpu.useDithering = cbs->gpu_neon.allow_dithering; gpu.mmap = cbs->mmap; gpu.munmap = cbs->munmap; diff --git a/plugins/gpulib/gpu.h b/plugins/gpulib/gpu.h index f710d3f1..28f10fa4 100644 --- a/plugins/gpulib/gpu.h +++ b/plugins/gpulib/gpu.h @@ -34,6 +34,7 @@ extern "C" { #define BIT(x) (1 << (x)) #define PSX_GPU_STATUS_DHEIGHT BIT(19) +#define PSX_GPU_STATUS_PAL BIT(20) #define PSX_GPU_STATUS_RGB24 BIT(21) #define PSX_GPU_STATUS_INTERLACE BIT(22) #define PSX_GPU_STATUS_BLANKING BIT(23) @@ -53,6 +54,7 @@ struct psx_gpu { int x, y, w, h; int x1, x2; int y1, y2; + int src_x, src_y; } screen; struct { int x, y, w, h; @@ -69,6 +71,7 @@ struct psx_gpu { uint32_t enhancement_active:1; uint32_t downscale_enable:1; uint32_t downscale_active:1; + uint32_t dims_changed:1; uint32_t *frame_count; uint32_t *hcnt; /* hsync count */ struct { @@ -79,6 +82,9 @@ struct psx_gpu { } last_list; uint32_t last_vram_read_frame; uint32_t w_out_old, h_out_old, status_vo_old; + int screen_centering_type; // 0 - auto, 1 - game conrolled, 2 - manual + int screen_centering_x; + int screen_centering_y; } state; struct { int32_t set:3; /* -1 auto, 0 off, 1-3 fixed */ @@ -93,8 +99,7 @@ struct psx_gpu { uint32_t pending_fill[3]; } frameskip; uint32_t scratch_ex_regs[8]; // for threaded rendering - int useDithering:1; /* 0 - off , 1 - on */ - uint16_t *(*get_enhancement_bufer) + void *(*get_enhancement_bufer) (int *x, int *y, int *w, int *h, int *vram_h); uint16_t *(*get_downscale_buffer) (int *x, int *y, int *w, int *h, int *vram_h); diff --git a/plugins/gpulib/vout_pl.c b/plugins/gpulib/vout_pl.c index ac55fa73..3bd1d05b 100644 --- a/plugins/gpulib/vout_pl.c +++ b/plugins/gpulib/vout_pl.c @@ -28,7 +28,7 @@ int vout_finish(void) static void check_mode_change(int force) { int w = gpu.screen.hres; - int h = gpu.screen.h; + int h = gpu.screen.vres; int w_out = w; int h_out = h; @@ -65,50 +65,62 @@ static void check_mode_change(int force) void vout_update(void) { + int bpp = (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 16; + uint8_t *vram = (uint8_t *)gpu.vram; + int src_x = gpu.screen.src_x; + int src_y = gpu.screen.src_y; int x = gpu.screen.x; int y = gpu.screen.y; int w = gpu.screen.w; int h = gpu.screen.h; - uint16_t *vram = gpu.vram; int vram_h = 512; + int src_x2 = 0; + + if (x < 0) { w += x; src_x2 = -x; x = 0; } + if (y < 0) { h += y; src_y -= y; y = 0; } - if (w == 0 || h == 0) + if (w <= 0 || h <= 0) return; check_mode_change(0); - if (gpu.state.enhancement_active) - vram = gpu.get_enhancement_bufer(&x, &y, &w, &h, &vram_h); + if (gpu.state.enhancement_active) { + vram = gpu.get_enhancement_bufer(&src_x, &src_y, &w, &h, &vram_h); + x *= 2; y *= 2; + } if (gpu.state.downscale_active) - vram = gpu.get_downscale_buffer(&x, &y, &w, &h, &vram_h); + vram = (void *)gpu.get_downscale_buffer(&src_x, &src_y, &w, &h, &vram_h); - if (y + h > vram_h) { - if (y + h - vram_h > h / 2) { + if (src_y + h > vram_h) { + if (src_y + h - vram_h > h / 2) { // wrap - h -= vram_h - y; - y = 0; + h -= vram_h - src_y; + src_y = 0; } else // clip - h = vram_h - y; + h = vram_h - src_y; } - vram += y * 1024 + x; + vram += (src_y * 1024 + src_x) * 2; + vram += src_x2 * bpp / 8; - cbs->pl_vout_flip(vram, 1024, !!(gpu.status & PSX_GPU_STATUS_RGB24), w, h); + cbs->pl_vout_flip(vram, 1024, !!(gpu.status & PSX_GPU_STATUS_RGB24), + x, y, w, h, gpu.state.dims_changed); + gpu.state.dims_changed = 0; } void vout_blank(void) { int w = gpu.screen.hres; - int h = gpu.screen.h; + int h = gpu.screen.vres; check_mode_change(0); if (gpu.state.enhancement_active) { w *= 2; h *= 2; } - cbs->pl_vout_flip(NULL, 1024, !!(gpu.status & PSX_GPU_STATUS_RGB24), w, h); + cbs->pl_vout_flip(NULL, 1024, !!(gpu.status & PSX_GPU_STATUS_RGB24), 0, 0, w, h, 0); } long GPUopen(void **unused)