From acf0df69b8055edd56d1c4d4db3c7b05b0ada50a Mon Sep 17 00:00:00 2001 From: HolographicWings Date: Mon, 15 May 2023 11:45:29 +0200 Subject: [PATCH] Added Video framerate limiter Will fix cinematics and videos when readed over their framerate --- src/common/settings.cpp | 3 +++ src/common/settings.h | 2 ++ src/video_core/host1x/codecs/codec.cpp | 18 +++++++++++++ src/yuzu/configuration/config.cpp | 4 +++ src/yuzu/configuration/configure_general.cpp | 21 +++++++++++++++ src/yuzu/configuration/configure_general.h | 1 + src/yuzu/configuration/configure_general.ui | 27 ++++++++++++++++++++ 7 files changed, 76 insertions(+) diff --git a/src/common/settings.cpp b/src/common/settings.cpp index db1774c715..26087e40ae 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -54,6 +54,7 @@ void LogSettings() { log_setting("Renderer_AntiAliasing", values.anti_aliasing.GetValue()); log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue()); log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue()); + log_setting("Renderer_VideoFramerate", values.video_framerate.GetValue()); log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue()); log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); log_setting("Renderer_UseAsynchronousGpuEmulation", @@ -218,6 +219,8 @@ void RestoreGlobalState(bool is_powered_on) { values.max_anisotropy.SetGlobal(true); values.use_speed_limit.SetGlobal(true); values.speed_limit.SetGlobal(true); + values.use_video_framerate.SetGlobal(true); + values.video_framerate.SetGlobal(true); values.use_disk_shader_cache.SetGlobal(true); values.gpu_accuracy.SetGlobal(true); values.use_asynchronous_gpu_emulation.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index 5f4caaab98..2a1bc52945 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -456,6 +456,8 @@ struct Values { SwitchableSetting max_anisotropy{0, 0, 5, "max_anisotropy"}; SwitchableSetting use_speed_limit{true, "use_speed_limit"}; SwitchableSetting speed_limit{100, 0, 9999, "speed_limit"}; + SwitchableSetting use_video_framerate{false, "use_video_framerate"}; + SwitchableSetting video_framerate{30, 1, 240, "video_framerate"}; SwitchableSetting use_disk_shader_cache{true, "use_disk_shader_cache"}; SwitchableSetting gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal, GPUAccuracy::Extreme, "gpu_accuracy"}; diff --git a/src/video_core/host1x/codecs/codec.cpp b/src/video_core/host1x/codecs/codec.cpp index 3e9022dce4..51bcf0227d 100644 --- a/src/video_core/host1x/codecs/codec.cpp +++ b/src/video_core/host1x/codecs/codec.cpp @@ -278,14 +278,32 @@ void Codec::Decode() { } } +std::chrono::steady_clock::time_point last_frame_time = std::chrono::steady_clock::now(); +std::chrono::microseconds min_call_interval = std::chrono::microseconds(1000/Settings::values.video_framerate.GetValue()*1000); AVFramePtr Codec::GetCurrentFrame() { // Sometimes VIC will request more frames than have been decoded. // in this case, return a nullptr and don't overwrite previous frame data if (av_frames.empty()) { return AVFramePtr{nullptr, AVFrameDeleter}; } + AVFramePtr frame = std::move(av_frames.front()); av_frames.pop(); + + if (Settings::values.use_video_framerate.GetValue()) { + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + std::chrono::microseconds elapsed = + std::chrono::duration_cast(now - last_frame_time); + + if (elapsed < min_call_interval) { + std::this_thread::sleep_for(min_call_interval - elapsed); + now = std::chrono::steady_clock::now(); + elapsed = std::chrono::duration_cast(now - last_frame_time); + } + + last_frame_time = now; + } + return frame; } diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index b94d368388..21c05d2091 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -705,6 +705,8 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.anti_aliasing); ReadGlobalSetting(Settings::values.max_anisotropy); ReadGlobalSetting(Settings::values.speed_limit); + ReadGlobalSetting(Settings::values.use_video_framerate); + ReadGlobalSetting(Settings::values.video_framerate); ReadGlobalSetting(Settings::values.use_disk_shader_cache); ReadGlobalSetting(Settings::values.gpu_accuracy); ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); @@ -1346,6 +1348,8 @@ void Config::SaveRendererValues() { Settings::values.anti_aliasing.UsingGlobal()); WriteGlobalSetting(Settings::values.max_anisotropy); WriteGlobalSetting(Settings::values.speed_limit); + WriteGlobalSetting(Settings::values.use_video_framerate); + WriteGlobalSetting(Settings::values.video_framerate); WriteGlobalSetting(Settings::values.use_disk_shader_cache); WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()), static_cast(Settings::values.gpu_accuracy.GetValue(global)), diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 26258d7447..8e711643cc 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -20,6 +20,9 @@ ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent) SetConfiguration(); if (Settings::IsConfiguringGlobal()) { + connect(ui->toggle_video_framerate, &QCheckBox::clicked, ui->video_framerate, [this]() { + ui->video_framerate->setEnabled(ui->toggle_video_framerate->isChecked()); + }); connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); }); } @@ -41,14 +44,19 @@ void ConfigureGeneral::SetConfiguration() { ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue()); ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue()); + ui->toggle_video_framerate->setChecked(Settings::values.use_video_framerate.GetValue()); + ui->video_framerate->setValue(Settings::values.video_framerate.GetValue()); + ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); ui->button_reset_defaults->setEnabled(runtime_lock); if (Settings::IsConfiguringGlobal()) { + ui->video_framerate->setEnabled(Settings::values.use_video_framerate.GetValue()); ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue()); } else { + ui->video_framerate->setEnabled(Settings::values.use_video_framerate.GetValue() && use_video_framerate != ConfigurationShared::CheckState::Global); ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() && use_speed_limit != ConfigurationShared::CheckState::Global); } @@ -83,6 +91,12 @@ void ConfigureGeneral::ApplyConfiguration() { UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); + if (Settings::values.use_video_framerate.UsingGlobal()) { + Settings::values.use_video_framerate.SetValue( + ui->toggle_video_framerate->checkState() == + Qt::Checked); + Settings::values.video_framerate.SetValue(ui->video_framerate->value()); + } // Guard if during game and set to game-specific value if (Settings::values.use_speed_limit.UsingGlobal()) { Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == @@ -118,6 +132,8 @@ void ConfigureGeneral::SetupPerGameUI() { // Disables each setting if: // - A game is running (thus settings in use), and // - A non-global setting is applied. + ui->toggle_video_framerate->setEnabled(Settings::values.use_video_framerate.UsingGlobal()); + ui->video_framerate->setEnabled(Settings::values.video_framerate.UsingGlobal()); ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal()); ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal()); @@ -131,11 +147,16 @@ void ConfigureGeneral::SetupPerGameUI() { ui->button_reset_defaults->setVisible(false); + ConfigurationShared::SetColoredTristate(ui->toggle_video_framerate, Settings::values.use_video_framerate, use_video_framerate); ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit, Settings::values.use_speed_limit, use_speed_limit); ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, use_multi_core); + connect(ui->toggle_video_framerate, &QCheckBox::clicked, ui->video_framerate, [this]() { + ui->video_framerate->setEnabled(ui->toggle_video_framerate->isChecked() && + (use_video_framerate != ConfigurationShared::CheckState::Global)); + }); connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && (use_speed_limit != ConfigurationShared::CheckState::Global)); diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h index 7ff63f4253..34b9f02443 100644 --- a/src/yuzu/configuration/configure_general.h +++ b/src/yuzu/configuration/configure_general.h @@ -46,6 +46,7 @@ private: std::unique_ptr ui; ConfigurationShared::CheckState use_speed_limit; + ConfigurationShared::CheckState use_video_framerate; ConfigurationShared::CheckState use_multi_core; const Core::System& system; diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index 986a1625bb..0441bff90a 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -89,6 +89,33 @@ + + + + + + Limit Videos Framerate + + + + + + + fps + + + 1 + + + 240 + + + 30 + + + + +