Add support for target FPS frame pacing
This commit is contained in:
parent
71e035f83b
commit
7b9dd4c6a1
|
|
@ -439,6 +439,13 @@ struct Values {
|
|||
"accelerate_astc",
|
||||
Category::RendererAdvanced};
|
||||
|
||||
SwitchableSetting<FramePacingMode, true> frame_pacing_mode{linkage,
|
||||
FramePacingMode::Default,
|
||||
FramePacingMode::Default,
|
||||
FramePacingMode::Target_120,
|
||||
"frame_pacing_mode",
|
||||
Category::RendererAdvanced};
|
||||
|
||||
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||
AstcRecompression::Uncompressed,
|
||||
"astc_recompression",
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
|
|||
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16, X32, X64, None);
|
||||
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
||||
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||
ENUM(FramePacingMode, Default, Target_30, Target_60, Target_120);
|
||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
||||
|
|
|
|||
|
|
@ -225,6 +225,8 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
"intermediate format: RGBA8.\n"
|
||||
"BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format,\n"
|
||||
" saving VRAM but degrading image quality."));
|
||||
INSERT(Settings, frame_pacing_mode, tr("Frame Pacing Mode (Vulkan only)"),
|
||||
tr("Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent."));
|
||||
INSERT(Settings,
|
||||
vram_usage_mode,
|
||||
tr("VRAM Usage Mode:"),
|
||||
|
|
@ -497,6 +499,13 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
|||
PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
|
||||
PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::FramePacingMode>::Index(),
|
||||
{
|
||||
PAIR(FramePacingMode, Default, tr("Default")),
|
||||
PAIR(FramePacingMode, Target_30, tr("30 FPS")),
|
||||
PAIR(FramePacingMode, Target_60, tr("60 FPS")),
|
||||
PAIR(FramePacingMode, Target_120, tr("120 FPS")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
|
||||
{
|
||||
PAIR(VramUsageMode, Conservative, tr("Conservative")),
|
||||
|
|
|
|||
|
|
@ -120,6 +120,22 @@ public:
|
|||
master_semaphore->Wait(tick);
|
||||
}
|
||||
|
||||
/// Waits until the next game frame based on the current game FPS.
|
||||
void WaitFPS(u64 tick, double target_fps) {
|
||||
if (master_semaphore->CurrentTick() >= tick) {
|
||||
return;
|
||||
}
|
||||
static auto next_frame_time = std::chrono::steady_clock::now();
|
||||
auto frame_duration = std::chrono::duration<double>(1.0 / target_fps);
|
||||
next_frame_time += std::chrono::duration_cast<std::chrono::steady_clock::duration>(frame_duration);
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (next_frame_time > now) {
|
||||
std::this_thread::sleep_until(next_frame_time);
|
||||
} else {
|
||||
next_frame_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the master timeline semaphore.
|
||||
[[nodiscard]] MasterSemaphore& GetMasterSemaphore() const noexcept {
|
||||
return *master_semaphore;
|
||||
|
|
|
|||
|
|
@ -194,7 +194,25 @@ bool Swapchain::AcquireNextImage() {
|
|||
break;
|
||||
}
|
||||
|
||||
scheduler.Wait(resource_ticks[image_index]);
|
||||
if (!Settings::values.use_speed_limit.GetValue()) {
|
||||
scheduler.Wait(resource_ticks[image_index]);
|
||||
} else {
|
||||
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||
case Settings::FramePacingMode::Default:
|
||||
scheduler.Wait(resource_ticks[image_index]);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_30:
|
||||
scheduler.WaitFPS(resource_ticks[image_index], 30.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_60:
|
||||
scheduler.WaitFPS(resource_ticks[image_index], 60.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_120:
|
||||
scheduler.WaitFPS(resource_ticks[image_index], 120.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resource_ticks[image_index] = scheduler.CurrentTick();
|
||||
|
||||
return is_suboptimal || is_outdated;
|
||||
|
|
|
|||
Loading…
Reference in New Issue