From 26c97f259b37c1c118c35cff0763104f1bc13834 Mon Sep 17 00:00:00 2001 From: notaz Date: Sat, 14 Mar 2026 03:39:47 +0200 Subject: [PATCH] gpulib: try a different flip method maybe make it default? or maybe cut the hacks and implement tearing? libretro/pcsx_rearmed#898 --- frontend/main.c | 10 +++++----- frontend/menu.c | 23 ++++++++++++++++++++--- frontend/plugin.c | 4 ---- libpcsxcore/plugins.c | 2 -- libpcsxcore/plugins.h | 2 -- libpcsxcore/psxcounters.c | 2 +- plugins/gpulib/gpu.c | 27 ++++++++++++++++++++++----- plugins/gpulib/gpu.h | 4 +++- 8 files changed, 51 insertions(+), 23 deletions(-) diff --git a/frontend/main.c b/frontend/main.c index 2040f7ca..267eb840 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -845,16 +845,16 @@ int emu_load_state(int slot) #endif // NO_FRONTEND -static void CALLBACK dummy_lace(void) +static void CALLBACK dummy_vBlank(int is_vblank, int lcf) { } void SysReset() { // rearmed hack: EmuReset() runs some code when real BIOS is used, // but we usually do reset from menu while GPU is not open yet, - // so we need to prevent updateLace() call.. - void *real_lace = GPU_updateLace; - GPU_updateLace = dummy_lace; + // so we need to prevent vBlank() call... + void *real_vbl = GPU_vBlank; + GPU_vBlank = dummy_vBlank; g_emu_resetting = 1; // reset can run code, timing must be set @@ -862,7 +862,7 @@ void SysReset() { EmuReset(); - GPU_updateLace = real_lace; + GPU_vBlank = real_vbl; g_emu_resetting = 0; } diff --git a/frontend/menu.c b/frontend/menu.c index 2702be3f..05c8a085 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -1833,13 +1833,17 @@ static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y) for (; h > 0; h--, d += g_menuscreen_w, s += 1024) bgr555_to_rgb565(d, s, w); - smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc); - snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus); - smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc); + snprintf(buff, sizeof(buff), "GPU sr: %08x scn: %3d %3d", gpuf->ulStatus, + gpuf->ulControl[5] & 0x3ff, (gpuf->ulControl[5] >> 10) & 0x1ff); + smalltext_out16(4, ty, buff, 0xe7fc); snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp); smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc); } +static void debug_set_mode(int w, int h, int raw_w, int raw_h, int bpp) {} +static void debug_flip(const void *vram_, int vram_ofs, int bgr24, + int x, int y, int w, int h, int dims_changed) {} + static void debug_menu_loop(void) { int inp, df_x = 0, df_y = 0; @@ -1862,6 +1866,19 @@ static void debug_menu_loop(void) else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; } else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; } else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; } + else if (inp & PBTN_MOK) { + u32 oldframe = frame_counter; + void *old_set_mode = pl_rearmed_cbs.pl_vout_set_mode; + void *old_flip = pl_rearmed_cbs.pl_vout_flip; + pl_rearmed_cbs.pl_vout_set_mode = debug_set_mode; + pl_rearmed_cbs.pl_vout_flip = debug_flip; + psxRegs.stop++; + while (frame_counter == oldframe) + psxCpu->ExecuteBlock(&psxRegs, EXEC_CALLER_OTHER); + psxRegs.stop--; + pl_rearmed_cbs.pl_vout_set_mode = old_set_mode; + pl_rearmed_cbs.pl_vout_flip = old_flip; + } } free(gpuf); diff --git a/frontend/plugin.c b/frontend/plugin.c index 0180e468..83ed65bc 100644 --- a/frontend/plugin.c +++ b/frontend/plugin.c @@ -90,7 +90,6 @@ extern uint32_t GPUreadStatus(void); extern uint32_t GPUreadData(void); extern void GPUreadDataMem(uint32_t *, int); extern long GPUdmaChain(uint32_t *, uint32_t, uint32_t *, int32_t *); -extern void GPUupdateLace(void); extern long GPUfreeze(uint32_t, void *, uint16_t **); extern void GPUvBlank(int, int); extern void GPUgetScreenInfo(int *y, int *base_hres); @@ -125,7 +124,6 @@ static const struct { DIRECT_SPU(SPUplayCDDAchannel), DIRECT_SPU(SPUsetCDvol), /* GPU */ - DIRECT_GPU(GPUupdateLace), DIRECT_GPU(GPUinit), DIRECT_GPU(GPUshutdown), DIRECT_GPU(GPUopen), @@ -211,7 +209,6 @@ pc_hook_func_ret(uint32_t, GPU_readStatus, (void), (), PCNT_GPU) pc_hook_func_ret(uint32_t, GPU_readData, (void), (), PCNT_GPU) pc_hook_func (GPU_readDataMem, (uint32_t *a0, int a1), (a0, a1), PCNT_GPU) pc_hook_func_ret(long, GPU_dmaChain, (uint32_t *a0, int32_t a1), (a0, a1), PCNT_GPU) -pc_hook_func (GPU_updateLace, (void), (), PCNT_GPU) pc_hook_func (SPU_writeRegister, (unsigned long a0, unsigned short a1, uint32_t a2), (a0, a1, a2), PCNT_SPU) pc_hook_func_ret(unsigned short,SPU_readRegister, (unsigned long a0, , unsigned int a1), (a0, a1), PCNT_SPU) @@ -237,7 +234,6 @@ void pcnt_hook_plugins(void) hook_it(GPU_readData); hook_it(GPU_readDataMem); hook_it(GPU_dmaChain); - hook_it(GPU_updateLace); hook_it(SPU_writeRegister); hook_it(SPU_readRegister); hook_it(SPU_writeDMAMem); diff --git a/libpcsxcore/plugins.c b/libpcsxcore/plugins.c index bf1d2832..aefbb645 100644 --- a/libpcsxcore/plugins.c +++ b/libpcsxcore/plugins.c @@ -31,7 +31,6 @@ static char IsoFile[MAXPATHLEN] = ""; static s64 cdOpenCaseTime = 0; -GPUupdateLace GPU_updateLace; GPUinit GPU_init; GPUshutdown GPU_shutdown; GPUopen GPU_open; @@ -147,7 +146,6 @@ static int LoadGPUplugin(const char *GPUdll) { LoadGpuSym1(writeDataMem, "GPUwriteDataMem"); LoadGpuSym1(writeStatus, "GPUwriteStatus"); LoadGpuSym1(dmaChain, "GPUdmaChain"); - LoadGpuSym1(updateLace, "GPUupdateLace"); LoadGpuSym1(freeze, "GPUfreeze"); LoadGpuSym0(vBlank, "GPUvBlank"); LoadGpuSym0(getScreenInfo, "GPUgetScreenInfo"); diff --git a/libpcsxcore/plugins.h b/libpcsxcore/plugins.h index f44e425d..1fe6246d 100644 --- a/libpcsxcore/plugins.h +++ b/libpcsxcore/plugins.h @@ -58,13 +58,11 @@ typedef uint32_t (CALLBACK* GPUreadStatus)(void); typedef uint32_t (CALLBACK* GPUreadData)(void); typedef void (CALLBACK* GPUreadDataMem)(uint32_t *, int); typedef long (CALLBACK* GPUdmaChain)(uint32_t *, uint32_t, uint32_t *, int32_t *); -typedef void (CALLBACK* GPUupdateLace)(void); typedef long (CALLBACK* GPUfreeze)(uint32_t, GPUFreeze_t *, uint16_t **); typedef void (CALLBACK* GPUvBlank)(int, int); typedef void (CALLBACK* GPUgetScreenInfo)(int *, int *); // GPU function pointers -extern GPUupdateLace GPU_updateLace; extern GPUinit GPU_init; extern GPUshutdown GPU_shutdown; extern GPUopen GPU_open; diff --git a/libpcsxcore/psxcounters.c b/libpcsxcore/psxcounters.c index 064c06b6..471980ea 100644 --- a/libpcsxcore/psxcounters.c +++ b/libpcsxcore/psxcounters.c @@ -397,7 +397,7 @@ void psxRcntUpdate() setIrq( 0x01 ); EmuUpdate(); - GPU_updateLace(); + //GPU_updateLace(); // handled by GPU_vBlank() now if( SPU_async ) { diff --git a/plugins/gpulib/gpu.c b/plugins/gpulib/gpu.c index f2a0b478..1ccd151e 100644 --- a/plugins/gpulib/gpu.c +++ b/plugins/gpulib/gpu.c @@ -365,7 +365,7 @@ long GPUshutdown(void) void GPUwriteStatus(uint32_t data) { uint32_t cmd = data >> 24; - uint32_t fb_dirty = 1; + uint32_t fb_dirty = 1, frame; int src_x, src_y, changed; if (cmd < ARRAY_SIZE(gpu.regs)) { @@ -398,9 +398,10 @@ void GPUwriteStatus(uint32_t data) case 0x05: src_x = data & 0x3ff; src_y = (data >> 10) & 0x1ff; changed = src_x != gpu.screen.src_x || src_y != gpu.screen.src_y; + frame = *gpu.state.frame_count; // last_flip_frame check allows frameskip on dheight games // that always set the same display area address - if (changed || gpu.frameskip.last_flip_frame != *gpu.state.frame_count) + if (changed || gpu.frameskip.last_flip_frame != frame) { gpu.state.fb_dirty_display_area |= gpu.state.fb_dirty; gpu.state.fb_dirty = 0; @@ -408,7 +409,7 @@ void GPUwriteStatus(uint32_t data) gpu.screen.src_y = src_y; check_draw_to_display(&gpu); if (gpu.frameskip.set) { - uint32_t flip_delay = *gpu.state.frame_count - gpu.frameskip.last_flip_frame; + uint32_t flip_delay = frame - gpu.frameskip.last_flip_frame; if (flip_delay) decide_frameskip(&gpu, flip_delay); if (!gpu.frameskip.active || !gpu.frameskip.allow) @@ -417,6 +418,16 @@ void GPUwriteStatus(uint32_t data) gpu.frameskip.last_flip_frame = *gpu.state.frame_count; } if (changed) { + if (!gpu.state.vblank && !(gpu.status & PSX_GPU_STATUS_BLANKING) && + !gpu.state.use_alternative_flip) + { + uint32_t fdiff = frame - gpu.state.last_adflip_frame; + gpu.state.last_adflip_frame = frame; + if (fdiff < 9u) { + log_anomaly(&gpu, "active display flip detected\n"); + gpu.state.use_alternative_flip = 1; + } + } if (gpu_async_enabled(&gpu)) gpu_async_notify_screen_change(&gpu); else @@ -1095,7 +1106,7 @@ long GPUfreeze(uint32_t type, GPUFreeze_t *freeze, uint16_t **vram_ptr) return 1; } -void GPUupdateLace(void) +static void GPUupdateLace(void) { int delay_vout_update = 0; int updated = 1; @@ -1124,6 +1135,7 @@ void GPUupdateLace(void) vout_blank(&gpu); gpu.state.blanked = 1; gpu.state.fb_dirty_display_area = 1; + gpu.state.use_alternative_flip = 0; } return; } @@ -1158,7 +1170,9 @@ void GPUupdateLace(void) void GPUvBlank(int is_vblank, int lcf) { - int interlace = gpu.state.allow_interlace + int interlace; + gpu.state.vblank = is_vblank; + interlace = gpu.state.allow_interlace && (gpu.status & PSX_GPU_STATUS_INTERLACE) && (gpu.status & PSX_GPU_STATUS_DHEIGHT); // interlace doesn't look nice on progressive displays, @@ -1182,6 +1196,8 @@ void GPUvBlank(int is_vblank, int lcf) renderer_set_interlace(interlace, !lcf); } } + if ((!is_vblank) == gpu.state.use_alternative_flip) + GPUupdateLace(); } void GPUgetScreenInfo(int *y, int *base_hres) @@ -1207,6 +1223,7 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs) gpu.state.enhancement_enable = cbs->gpu_neon.enhancement_enable; gpu.state.enhancement_active = 0; gpu.state.downscale_enable = cbs->scale_hires; + gpu.state.use_alternative_flip = 0; gpu.state.screen_centering_type_default = cbs->screen_centering_type_default; if (gpu.state.screen_centering_type != cbs->screen_centering_type || gpu.state.screen_centering_x != cbs->screen_centering_x diff --git a/plugins/gpulib/gpu.h b/plugins/gpulib/gpu.h index 177e5aac..21ce8321 100644 --- a/plugins/gpulib/gpu.h +++ b/plugins/gpulib/gpu.h @@ -86,6 +86,8 @@ struct psx_gpu { uint32_t old_interlace:1; uint32_t allow_interlace:2; uint32_t blanked:1; + uint32_t vblank:1; + uint32_t use_alternative_flip:1; uint32_t enhancement_enable:1; uint32_t enhancement_active:1; uint32_t enhancement_was_active:1; @@ -101,6 +103,7 @@ struct psx_gpu { uint32_t hcnt; } last_list; uint32_t last_vram_read_frame; + uint32_t last_adflip_frame; uint16_t w_out_old, h_out_old, src_y_old; uint32_t status_vo_old; short screen_centering_type; @@ -195,7 +198,6 @@ uint32_t GPUreadData(void); uint32_t GPUreadStatus(void); void GPUwriteStatus(uint32_t data); long GPUfreeze(uint32_t type, struct GPUFreeze *freeze, uint16_t **vram_ptr); -void GPUupdateLace(void); long GPUopen(unsigned long *disp, char *cap, char *cfg); long GPUclose(void); void GPUvBlank(int is_vblank, int lcf); -- 2.47.3