libretro: add a Vblank Pacing option (#2562)

Without threaded rendering a run ends when a frame is presented, or
after 50 ms of emulated time without one. Frontends that pace retro_run
by the frame rate instead of blocking on audio, Kodi among them, then
get several vblanks per run through loading screens and have to drop
the extra audio. With the option on, every run ends at the next vblank.
[ci skip]
This commit is contained in:
Chris Dixon authored and GitHub committed 2026-10-27 11:47:43 +01:00
1 parent e88b0ced22
commit 11ba75f843
6 files changed
+19 -2

No files matched your search

+1
View File
@@ -110,6 +110,7 @@ Option<int64_t> PixelBufferSize("rend.PixelBufferSize", 512_MB);
Option<int> AnisotropicFiltering("rend.AnisotropicFiltering", 1);
Option<int> TextureFiltering("rend.TextureFiltering", 0); // Default
Option<bool> ThreadedRendering("rend.ThreadedRendering", true);
Option<bool> VblankPacing("");
Option<bool> DupeFrames("rend.DupeFrames", false);
Option<int> PerPixelLayers("rend.PerPixelLayers", 32);
#ifdef TARGET_UWP
+1
View File
@@ -471,6 +471,7 @@ extern Option<int64_t> PixelBufferSize;
extern Option<int> AnisotropicFiltering;
extern Option<int> TextureFiltering; // 0: default, 1: force nearest, 2: force linear
extern Option<bool> ThreadedRendering;
extern Option<bool> VblankPacing;
extern Option<bool> DupeFrames;
extern Option<bool> NativeDepthInterpolation;
extern Option<bool> EmulateFramebuffer;
+1 -1
View File
@@ -1088,7 +1088,7 @@ void Emulator::vblank()
EventManager::event(Event::VBlank);
runner.execTasks();
// Time out if a frame hasn't been rendered for 50 ms
if (sh4_sched_now64() - startTime <= 50_sh4ms)
if (!config::VblankPacing && sh4_sched_now64() - startTime <= 50_sh4ms)
return;
if (ggpo::active())
ggpo::endOfFrame();
+1 -1
View File
@@ -268,7 +268,7 @@ private:
if (renderer->Present())
{
presented = true;
if (!config::ThreadedRendering && !ggpo::active())
if (!config::ThreadedRendering && !config::VblankPacing && !ggpo::active())
emu.getSh4Executor()->Stop();
#ifdef LIBRETRO
retro_rend_present();
+14
View File
@@ -644,6 +644,20 @@ struct retro_core_option_v2_definition option_defs_us[] = {
},
"enabled",
},
{
CORE_OPTION_NAME "_vblank_pacing",
"Vblank Pacing",
NULL,
"Each frame the frontend runs emulates exactly one vblank, whether or not the game drew. For frontends that pace the core by its frame rate rather than by blocking on audio; without it, loading screens that draw nothing run several vblanks per frame and their sound arrives in bursts. Needs Threaded Rendering disabled.",
NULL,
"performance",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL },
},
"disabled",
},
{
CORE_OPTION_NAME "_auto_skip_frame",
"Auto Skip Frame",
+1
View File
@@ -89,6 +89,7 @@ Option<bool> IntegerScale("");
Option<bool> LinearInterpolation("", true);
Option<bool> VSync("", true);
Option<bool> ThreadedRendering(CORE_OPTION_NAME "_threaded_rendering", true);
Option<bool> VblankPacing(CORE_OPTION_NAME "_vblank_pacing");
Option<int> AnisotropicFiltering(CORE_OPTION_NAME "_anisotropic_filtering");
Option<int> TextureFiltering(CORE_OPTION_NAME "_texture_filtering");
Option<bool> PowerVR2Filter(CORE_OPTION_NAME "_pvr2_filtering");