libretro: update frameskip logic
authornotaz <notasas@gmail.com>
Wed, 28 Jan 2026 00:46:28 +0000 (02:46 +0200)
committernotaz <notasas@gmail.com>
Wed, 28 Jan 2026 02:00:04 +0000 (04:00 +0200)
As PSX usually runs at 20fps or so, underruns were not noticed because
the following frame after underrun libretro would indicate none, but the
core's logic would only evaluate it when the game flips the buffers,
which is like every 3rd frame or so. With that frameskip on slow devices
was pretty much ineffective.

frontend/libretro.c
frontend/libretro_core_options.h
plugins/gpulib/gpu.c
plugins/gpulib/gpu.h

index aad3c00..a7ad22e 100644 (file)
@@ -1777,7 +1777,7 @@ static void retro_audio_buff_status_cb(
 {
    retro_audio_buff_active    = active;
    retro_audio_buff_occupancy = occupancy;
-   retro_audio_buff_underrun  = underrun_likely;
+   retro_audio_buff_underrun |= underrun_likely;
 }
 
 static void retro_set_audio_buff_status_cb(void)
@@ -1815,8 +1815,8 @@ static void retro_set_audio_buff_status_cb(void)
           * buffer underruns */
          uint32_t frame_time_usec = 1000000.0 / (is_pal_mode ? 50.0 : 60.0);
 
-         /* Set latency to 6x current frame time... */
-         retro_audio_latency = (unsigned)(6 * frame_time_usec / 1000);
+         /* Set latency... */
+         retro_audio_latency = (unsigned)((4 + frameskip_interval * 2) * frame_time_usec / 1000);
 
          /* ...then round up to nearest multiple of 32 */
          retro_audio_latency = (retro_audio_latency + 0x1F) & ~0x1F;
@@ -1825,6 +1825,7 @@ static void retro_set_audio_buff_status_cb(void)
 
    update_audio_latency = true;
    frameskip_counter    = 0;
+   pl_rearmed_cbs.fskip_force = 0;
 }
 
 static void update_variables(bool in_flight);
@@ -3353,12 +3354,9 @@ void retro_run(void)
    set_vout_fb();
    print_internal_fps();
 
-   /* Check whether current frame should
-    * be skipped */
-   pl_rearmed_cbs.fskip_force = 0;
-   pl_rearmed_cbs.fskip_dirty = 0;
-
-   if (frameskip_type != FRAMESKIP_NONE)
+   /* Check whether current frame should be skipped */
+   if (frameskip_type != FRAMESKIP_NONE && !pl_rearmed_cbs.fskip_force &&
+       frameskip_counter < frameskip_interval)
    {
       bool skip_frame = false;
 
@@ -3377,8 +3375,7 @@ void retro_run(void)
             break;
       }
 
-      if (skip_frame && frameskip_counter < frameskip_interval)
-         pl_rearmed_cbs.fskip_force = 1;
+      pl_rearmed_cbs.fskip_force = skip_frame;
    }
 
    /* If frameskip/timing settings have changed,
@@ -3404,11 +3401,16 @@ void retro_run(void)
    psxRegs.stop = 0;
    psxCpu->Execute(&psxRegs);
 
-   if (pl_rearmed_cbs.fskip_dirty == 1) {
-      if (frameskip_counter < frameskip_interval)
-         frameskip_counter++;
-      else if (frameskip_counter >= frameskip_interval || !pl_rearmed_cbs.fskip_force)
+   if (pl_rearmed_cbs.fskip_dirty) {
+      if (frameskip_counter >= frameskip_interval || !pl_rearmed_cbs.fskip_force)
          frameskip_counter = 0;
+      else
+         frameskip_counter++;
+
+      if (pl_rearmed_cbs.fskip_force)
+         retro_audio_buff_underrun = false;
+      pl_rearmed_cbs.fskip_force = 0;
+      pl_rearmed_cbs.fskip_dirty = 0;
    }
 
    video_cb((vout_fb_dirty || !vout_can_dupe) ? vout_buf_ptr : NULL,
index dc0d4d7..46b1883 100644 (file)
@@ -385,6 +385,10 @@ struct retro_core_option_v2_definition option_defs_us[] = {
          { "54", NULL },
          { "57", NULL },
          { "60", NULL },
+         { "65", NULL },
+         { "70", NULL },
+         { "75", NULL },
+         { "80", NULL },
          { NULL, NULL },
       },
       "33"
index dca0e80..adbfad6 100644 (file)
@@ -228,6 +228,7 @@ static noinline void decide_frameskip(struct psx_gpu *gpu, uint32_t flip_delay)
     gpu->frameskip.frame_ready = 1;
   }
 
+  // note: frontend/libretro only uses 'force'
   if (*gpu->frameskip.force)
     gpu->frameskip.active = 1;
   else if (!gpu->frameskip.active && *gpu->frameskip.advice)
index 66d2e39..16bfedf 100644 (file)
@@ -18,7 +18,7 @@
 //#define RAW_FB_DISPLAY
 
 #define gpu_log(gpu, fmt, ...) \
-  printf("%d:%03d: " fmt, *(gpu)->state.frame_count, *(gpu)->state.hcnt, ##__VA_ARGS__)
+  SysPrintf("%d:%03d: " fmt, *(gpu)->state.frame_count, *(gpu)->state.hcnt, ##__VA_ARGS__)
 
 #ifdef LOG_UNHANDLED
 #define log_anomaly gpu_log