diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index c7f5bbf28..3c5c53e24 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -21,12 +21,13 @@ #include "core/hle/service/vi/display/vi_display.h" #include "core/hle/service/vi/layer/vi_layer.h" #include "core/perf_stats.h" +#include "core/settings.h" #include "video_core/renderer_base.h" namespace Service::NVFlinger { -constexpr std::size_t SCREEN_REFRESH_RATE = 60; -constexpr s64 frame_ticks = static_cast(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); +constexpr s64 frame_ticks = static_cast(Core::Timing::BASE_CLOCK_RATE / 60); +constexpr s64 frame_ticks_30fps = static_cast(Core::Timing::BASE_CLOCK_RATE / 30); NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} { displays.emplace_back(0, "Default"); @@ -36,13 +37,15 @@ NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_t displays.emplace_back(4, "Null"); // Schedule the screen composition events - composition_event = - core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) { + const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : frame_ticks; + + composition_event = core_timing.RegisterEvent( + "ScreenComposition", [this, ticks](u64 userdata, s64 cycles_late) { Compose(); - this->core_timing.ScheduleEvent(frame_ticks - cycles_late, composition_event); + this->core_timing.ScheduleEvent(ticks - cycles_late, composition_event); }); - core_timing.ScheduleEvent(frame_ticks, composition_event); + core_timing.ScheduleEvent(ticks, composition_event); } NVFlinger::~NVFlinger() { @@ -62,6 +65,7 @@ std::optional NVFlinger::OpenDisplay(std::string_view name) { const auto itr = std::find_if(displays.begin(), displays.end(), [&](const VI::Display& display) { return display.GetName() == name; }); + if (itr == displays.end()) { return {}; } diff --git a/src/core/settings.h b/src/core/settings.h index d543eb32f..b84390745 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -393,6 +393,7 @@ struct Values { bool use_disk_shader_cache; bool use_accurate_gpu_emulation; bool use_asynchronous_gpu_emulation; + bool force_30fps_mode; float bg_red; float bg_green; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ca60bc0c9..8725a78dc 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -394,6 +394,7 @@ void Config::ReadValues() { ReadSetting("use_accurate_gpu_emulation", false).toBool(); Settings::values.use_asynchronous_gpu_emulation = ReadSetting("use_asynchronous_gpu_emulation", false).toBool(); + Settings::values.force_30fps_mode = ReadSetting("force_30fps_mode", false).toBool(); Settings::values.bg_red = ReadSetting("bg_red", 0.0).toFloat(); Settings::values.bg_green = ReadSetting("bg_green", 0.0).toFloat(); @@ -664,6 +665,7 @@ void Config::SaveValues() { WriteSetting("use_accurate_gpu_emulation", Settings::values.use_accurate_gpu_emulation, false); WriteSetting("use_asynchronous_gpu_emulation", Settings::values.use_asynchronous_gpu_emulation, false); + WriteSetting("force_30fps_mode", Settings::values.force_30fps_mode, false); // Cast to double because Qt's written float values are not human-readable WriteSetting("bg_red", (double)Settings::values.bg_red, 0.0); diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index dd1d67488..0a9883d37 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -77,6 +77,8 @@ void ConfigureGraphics::setConfiguration() { ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation); ui->use_asynchronous_gpu_emulation->setEnabled(!Core::System::GetInstance().IsPoweredOn()); ui->use_asynchronous_gpu_emulation->setChecked(Settings::values.use_asynchronous_gpu_emulation); + ui->force_30fps_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn()); + ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode); UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue)); } @@ -90,6 +92,7 @@ void ConfigureGraphics::applyConfiguration() { Settings::values.use_accurate_gpu_emulation = ui->use_accurate_gpu_emulation->isChecked(); Settings::values.use_asynchronous_gpu_emulation = ui->use_asynchronous_gpu_emulation->isChecked(); + Settings::values.force_30fps_mode = ui->force_30fps_mode->isChecked(); Settings::values.bg_red = static_cast(bg_color.redF()); Settings::values.bg_green = static_cast(bg_color.greenF()); Settings::values.bg_blue = static_cast(bg_color.blueF()); diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index c6767e0ca..15ab18ecd 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -70,6 +70,13 @@ + + + + Force 30 FPS mode + + +