From ce115869c92390136f7775f6cb803d447b622efb Mon Sep 17 00:00:00 2001 From: GPUCode Date: Wed, 29 Mar 2023 23:42:04 +0300 Subject: [PATCH] citra_qt: Add option to adjust screen refresh rate --- src/citra_qt/configuration/config.cpp | 2 + .../configuration/configure_debug.cpp | 38 +++++++- src/citra_qt/configuration/configure_debug.ui | 94 ++++++++++++++++--- src/common/settings.cpp | 4 + src/common/settings.h | 1 + src/core/hw/gpu.cpp | 10 ++ src/core/hw/gpu.h | 7 +- src/core/perf_stats.cpp | 2 +- 8 files changed, 138 insertions(+), 20 deletions(-) diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 6da3dec9b..432a3f0e9 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -447,6 +447,7 @@ void Config::ReadCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); ReadGlobalSetting(Settings::values.cpu_clock_percentage); + ReadGlobalSetting(Settings::values.refresh_rate); if (global) { ReadBasicSetting(Settings::values.use_cpu_jit); @@ -963,6 +964,7 @@ void Config::SaveCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); WriteGlobalSetting(Settings::values.cpu_clock_percentage); + WriteGlobalSetting(Settings::values.refresh_rate); if (global) { WriteBasicSetting(Settings::values.use_cpu_jit); diff --git a/src/citra_qt/configuration/configure_debug.cpp b/src/citra_qt/configuration/configure_debug.cpp index a75592fe0..f878c200d 100644 --- a/src/citra_qt/configuration/configure_debug.cpp +++ b/src/citra_qt/configuration/configure_debug.cpp @@ -42,13 +42,21 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) // Set a minimum width for the label to prevent the slider from changing size. // This scales across DPIs. (This value should be enough for "xxx%") ui->clock_display_label->setMinimumWidth(40); + ui->refresh_display_label->setMinimumWidth(40); connect(ui->slider_clock_speed, &QSlider::valueChanged, this, [&](int value) { ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value))); }); - ui->clock_speed_label->setVisible(Settings::IsConfiguringGlobal()); - ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal()); + connect(ui->slider_refresh_rate, &QSlider::valueChanged, this, [&](int value) { + ui->refresh_display_label->setText(QStringLiteral("%1Hz").arg(value)); + }); + + const bool is_global = Settings::IsConfiguringGlobal(); + ui->clock_speed_label->setVisible(is_global); + ui->refresh_rate_label->setVisible(is_global); + ui->clock_speed_combo->setVisible(!is_global); + ui->refresh_rate_combo->setVisible(!is_global); SetupPerGameUI(); } @@ -73,14 +81,26 @@ void ConfigureDebug::SetConfiguration() { ui->clock_speed_combo->setCurrentIndex(1); ui->slider_clock_speed->setEnabled(true); } + if (Settings::values.refresh_rate.UsingGlobal()) { + ui->refresh_rate_combo->setCurrentIndex(0); + ui->slider_refresh_rate->setEnabled(false); + } else { + ui->refresh_rate_combo->setCurrentIndex(1); + ui->slider_refresh_rate->setEnabled(true); + } ConfigurationShared::SetHighlight(ui->clock_speed_widget, !Settings::values.cpu_clock_percentage.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->refresh_rate_widget, + !Settings::values.refresh_rate.UsingGlobal()); } ui->slider_clock_speed->setValue( SettingsToSlider(Settings::values.cpu_clock_percentage.GetValue())); ui->clock_display_label->setText( QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage.GetValue())); + ui->slider_refresh_rate->setValue(Settings::values.refresh_rate.GetValue()); + ui->refresh_display_label->setText( + QStringLiteral("%1Hz").arg(Settings::values.refresh_rate.GetValue())); } void ConfigureDebug::ApplyConfiguration() { @@ -98,22 +118,32 @@ void ConfigureDebug::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting( &Settings::values.cpu_clock_percentage, ui->clock_speed_combo, [this](s32) { return SliderToSettings(ui->slider_clock_speed->value()); }); + + ConfigurationShared::ApplyPerGameSetting( + &Settings::values.refresh_rate, ui->refresh_rate_combo, + [this](s32) { return ui->slider_refresh_rate->value(); }); } void ConfigureDebug::SetupPerGameUI() { // Block the global settings if a game is currently running that overrides them if (Settings::IsConfiguringGlobal()) { ui->slider_clock_speed->setEnabled(Settings::values.cpu_clock_percentage.UsingGlobal()); + ui->slider_refresh_rate->setEnabled(Settings::values.refresh_rate.UsingGlobal()); return; } + connect(ui->refresh_rate_combo, qOverload(&QComboBox::activated), this, [this](int index) { + ui->slider_refresh_rate->setEnabled(index == 1); + ConfigurationShared::SetHighlight(ui->refresh_rate_widget, index == 1); + }); + connect(ui->clock_speed_combo, qOverload(&QComboBox::activated), this, [this](int index) { ui->slider_clock_speed->setEnabled(index == 1); ConfigurationShared::SetHighlight(ui->clock_speed_widget, index == 1); }); - ui->groupBox->setVisible(false); - ui->groupBox_2->setVisible(false); + ui->gdb_group->setVisible(false); + ui->logging_group->setVisible(false); ui->toggle_cpu_jit->setVisible(false); } diff --git a/src/citra_qt/configuration/configure_debug.ui b/src/citra_qt/configuration/configure_debug.ui index afdbc2b8f..131883df9 100644 --- a/src/citra_qt/configuration/configure_debug.ui +++ b/src/citra_qt/configuration/configure_debug.ui @@ -7,7 +7,7 @@ 0 0 523 - 447 + 495 @@ -17,7 +17,7 @@ - + GDB @@ -66,7 +66,7 @@ - + Logging @@ -107,18 +107,15 @@ - + CPU - - - - <html><head/><body><p>Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes</p></body></html> - + + - Enable CPU JIT + Enable debug renderer @@ -203,10 +200,81 @@ - - - Enable debug renderer + + + <html><head/><body><p>Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes</p></body></html> + + Enable CPU JIT + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Use global refresh rate + + + + + Set refresh rate: + + + + + + + + Refresh rate + + + + + + + 30 + + + 360 + + + 30 + + + 30 + + + 60 + + + Qt::Horizontal + + + + + + + + + + + diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 46aa2e8e1..17419caed 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -51,6 +51,8 @@ void Apply() { GDBStub::SetServerPort(values.gdbstub_port.GetValue()); GDBStub::ToggleServer(values.use_gdbstub.GetValue()); + GPU::SetRefreshRate(values.refresh_rate.GetValue()); + VideoCore::g_shader_jit_enabled = values.use_shader_jit.GetValue(); VideoCore::g_hw_shader_enabled = values.use_hw_shader.GetValue(); VideoCore::g_separable_shader_enabled = values.separable_shader.GetValue(); @@ -112,6 +114,7 @@ void LogSettings() { LOG_INFO(Config, "Citra Configuration:"); log_setting("Core_UseCpuJit", values.use_cpu_jit.GetValue()); log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage.GetValue()); + log_setting("Core_RefreshRate", values.refresh_rate.GetValue()); log_setting("Renderer_UseGLES", values.use_gles.GetValue()); log_setting("Renderer_GraphicsAPI", GetGraphicsAPIName(values.graphics_api.GetValue())); log_setting("Renderer_UseHwShader", values.use_hw_shader.GetValue()); @@ -195,6 +198,7 @@ void RestoreGlobalState(bool is_powered_on) { // Core values.cpu_clock_percentage.SetGlobal(true); + values.refresh_rate.SetGlobal(true); values.is_new_3ds.SetGlobal(true); // Renderer diff --git a/src/common/settings.h b/src/common/settings.h index bd25c1b13..56dc01e30 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -490,6 +490,7 @@ struct Values { std::unordered_map lle_modules; Setting use_gdbstub{false, "use_gdbstub"}; Setting gdbstub_port{24689, "gdbstub_port"}; + SwitchableSetting refresh_rate{60, 30, 360, "refresh_rate"}; // Miscellaneous Setting log_filter{"*:Info", "log_filter"}; diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index b2619986f..292ac59d4 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -27,6 +27,11 @@ namespace GPU { +// Measured on hardware to be 2240568 timer cycles or 4481136 ARM11 cycles +u64 frame_ticks = 4481136ull; + +double SCREEN_REFRESH_RATE = BASE_CLOCK_RATE_ARM11 / static_cast(frame_ticks); + Regs g_regs; Memory::MemorySystem* g_memory; @@ -561,4 +566,9 @@ void Shutdown() { LOG_DEBUG(HW_GPU, "shutdown OK"); } +void SetRefreshRate(u32 refresh) { + frame_ticks = (4481136ull * 60) / refresh; + SCREEN_REFRESH_RATE = BASE_CLOCK_RATE_ARM11 / static_cast(frame_ticks); +} + } // namespace GPU diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index b865dcd6e..dc86897a4 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h @@ -21,11 +21,11 @@ class MemorySystem; namespace GPU { // Measured on hardware to be 2240568 timer cycles or 4481136 ARM11 cycles -constexpr u64 frame_ticks = 4481136ull; +extern u64 frame_ticks; // Refresh rate defined by ratio of ARM11 frequency to ARM11 ticks per frame // (268,111,856) / (4,481,136) = 59.83122493939037Hz -constexpr double SCREEN_REFRESH_RATE = BASE_CLOCK_RATE_ARM11 / static_cast(frame_ticks); +extern double SCREEN_REFRESH_RATE; // Returns index corresponding to the Regs member labeled by field_name #define GPU_REG_INDEX(field_name) (offsetof(GPU::Regs, field_name) / sizeof(u32)) @@ -328,4 +328,7 @@ void Init(Memory::MemorySystem& memory); /// Shutdown hardware void Shutdown(); +/// Sets the screen refresh rate +void SetRefreshRate(u32 refresh); + } // namespace GPU diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index 6dffec97f..269e0d062 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -115,7 +115,7 @@ PerfStats::Results PerfStats::GetAndResetStats(microseconds current_system_time_ double PerfStats::GetLastFrameTimeScale() const { std::lock_guard lock{object_mutex}; - constexpr double FRAME_LENGTH = 1.0 / GPU::SCREEN_REFRESH_RATE; + const double FRAME_LENGTH = 1.0 / GPU::SCREEN_REFRESH_RATE; return duration_cast(previous_frame_length).count() / FRAME_LENGTH; }