gpulib: try a different flip method master github/master
authornotaz <notasas@gmail.com>
Sat, 14 Mar 2026 01:39:47 +0000 (03:39 +0200)
committernotaz <notasas@gmail.com>
Sat, 14 Mar 2026 02:08:08 +0000 (04:08 +0200)
maybe make it default?
or maybe cut the hacks and implement tearing?

libretro/pcsx_rearmed#898

frontend/main.c
frontend/menu.c
frontend/plugin.c
libpcsxcore/plugins.c
libpcsxcore/plugins.h
libpcsxcore/psxcounters.c
plugins/gpulib/gpu.c
plugins/gpulib/gpu.h

index 2040f7c..267eb84 100644 (file)
@@ -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;
 }
 
index 2702be3..05c8a08 100644 (file)
@@ -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);
index 0180e46..83ed65b 100644 (file)
@@ -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);
index bf1d283..aefbb64 100644 (file)
@@ -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");
index f44e425..1fe6246 100644 (file)
@@ -58,13 +58,11 @@ typedef uint32_t (CALLBACK* GPUreadStatus)(void);
 typedef uint32_t (CALLBACK* GPUreadData)(void);\r
 typedef void (CALLBACK* GPUreadDataMem)(uint32_t *, int);\r
 typedef long (CALLBACK* GPUdmaChain)(uint32_t *, uint32_t, uint32_t *, int32_t *);\r
-typedef void (CALLBACK* GPUupdateLace)(void);\r
 typedef long (CALLBACK* GPUfreeze)(uint32_t, GPUFreeze_t *, uint16_t **);\r
 typedef void (CALLBACK* GPUvBlank)(int, int);\r
 typedef void (CALLBACK* GPUgetScreenInfo)(int *, int *);\r
 \r
 // GPU function pointers\r
-extern GPUupdateLace    GPU_updateLace;\r
 extern GPUinit          GPU_init;\r
 extern GPUshutdown      GPU_shutdown; \r
 extern GPUopen          GPU_open;\r
index 064c06b..471980e 100644 (file)
@@ -397,7 +397,7 @@ void psxRcntUpdate()
             setIrq( 0x01 );
 
             EmuUpdate();
-            GPU_updateLace();
+            //GPU_updateLace(); // handled by GPU_vBlank() now
 
             if( SPU_async )
             {
index f2a0b47..1ccd151 100644 (file)
@@ -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
index 177e5aa..21ce832 100644 (file)
@@ -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);