citra_qt: Add option to adjust screen refresh rate

This commit is contained in:
GPUCode 2023-03-29 23:42:04 +03:00
parent b5d6f645bd
commit ce115869c9
8 changed files with 138 additions and 20 deletions

View file

@ -447,6 +447,7 @@ void Config::ReadCoreValues() {
qt_config->beginGroup(QStringLiteral("Core")); qt_config->beginGroup(QStringLiteral("Core"));
ReadGlobalSetting(Settings::values.cpu_clock_percentage); ReadGlobalSetting(Settings::values.cpu_clock_percentage);
ReadGlobalSetting(Settings::values.refresh_rate);
if (global) { if (global) {
ReadBasicSetting(Settings::values.use_cpu_jit); ReadBasicSetting(Settings::values.use_cpu_jit);
@ -963,6 +964,7 @@ void Config::SaveCoreValues() {
qt_config->beginGroup(QStringLiteral("Core")); qt_config->beginGroup(QStringLiteral("Core"));
WriteGlobalSetting(Settings::values.cpu_clock_percentage); WriteGlobalSetting(Settings::values.cpu_clock_percentage);
WriteGlobalSetting(Settings::values.refresh_rate);
if (global) { if (global) {
WriteBasicSetting(Settings::values.use_cpu_jit); WriteBasicSetting(Settings::values.use_cpu_jit);

View file

@ -42,13 +42,21 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
// Set a minimum width for the label to prevent the slider from changing size. // 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%") // This scales across DPIs. (This value should be enough for "xxx%")
ui->clock_display_label->setMinimumWidth(40); ui->clock_display_label->setMinimumWidth(40);
ui->refresh_display_label->setMinimumWidth(40);
connect(ui->slider_clock_speed, &QSlider::valueChanged, this, [&](int value) { connect(ui->slider_clock_speed, &QSlider::valueChanged, this, [&](int value) {
ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value))); ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value)));
}); });
ui->clock_speed_label->setVisible(Settings::IsConfiguringGlobal()); connect(ui->slider_refresh_rate, &QSlider::valueChanged, this, [&](int value) {
ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal()); 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(); SetupPerGameUI();
} }
@ -73,14 +81,26 @@ void ConfigureDebug::SetConfiguration() {
ui->clock_speed_combo->setCurrentIndex(1); ui->clock_speed_combo->setCurrentIndex(1);
ui->slider_clock_speed->setEnabled(true); 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, ConfigurationShared::SetHighlight(ui->clock_speed_widget,
!Settings::values.cpu_clock_percentage.UsingGlobal()); !Settings::values.cpu_clock_percentage.UsingGlobal());
ConfigurationShared::SetHighlight(ui->refresh_rate_widget,
!Settings::values.refresh_rate.UsingGlobal());
} }
ui->slider_clock_speed->setValue( ui->slider_clock_speed->setValue(
SettingsToSlider(Settings::values.cpu_clock_percentage.GetValue())); SettingsToSlider(Settings::values.cpu_clock_percentage.GetValue()));
ui->clock_display_label->setText( ui->clock_display_label->setText(
QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage.GetValue())); 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() { void ConfigureDebug::ApplyConfiguration() {
@ -98,22 +118,32 @@ void ConfigureDebug::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting( ConfigurationShared::ApplyPerGameSetting(
&Settings::values.cpu_clock_percentage, ui->clock_speed_combo, &Settings::values.cpu_clock_percentage, ui->clock_speed_combo,
[this](s32) { return SliderToSettings(ui->slider_clock_speed->value()); }); [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() { void ConfigureDebug::SetupPerGameUI() {
// Block the global settings if a game is currently running that overrides them // Block the global settings if a game is currently running that overrides them
if (Settings::IsConfiguringGlobal()) { if (Settings::IsConfiguringGlobal()) {
ui->slider_clock_speed->setEnabled(Settings::values.cpu_clock_percentage.UsingGlobal()); ui->slider_clock_speed->setEnabled(Settings::values.cpu_clock_percentage.UsingGlobal());
ui->slider_refresh_rate->setEnabled(Settings::values.refresh_rate.UsingGlobal());
return; return;
} }
connect(ui->refresh_rate_combo, qOverload<int>(&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<int>(&QComboBox::activated), this, [this](int index) { connect(ui->clock_speed_combo, qOverload<int>(&QComboBox::activated), this, [this](int index) {
ui->slider_clock_speed->setEnabled(index == 1); ui->slider_clock_speed->setEnabled(index == 1);
ConfigurationShared::SetHighlight(ui->clock_speed_widget, index == 1); ConfigurationShared::SetHighlight(ui->clock_speed_widget, index == 1);
}); });
ui->groupBox->setVisible(false); ui->gdb_group->setVisible(false);
ui->groupBox_2->setVisible(false); ui->logging_group->setVisible(false);
ui->toggle_cpu_jit->setVisible(false); ui->toggle_cpu_jit->setVisible(false);
} }

View file

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>523</width> <width>523</width>
<height>447</height> <height>495</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -17,7 +17,7 @@
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="gdb_group">
<property name="title"> <property name="title">
<string>GDB</string> <string>GDB</string>
</property> </property>
@ -66,7 +66,7 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="groupBox_2"> <widget class="QGroupBox" name="logging_group">
<property name="title"> <property name="title">
<string>Logging</string> <string>Logging</string>
</property> </property>
@ -107,18 +107,15 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="groupBox_4"> <widget class="QGroupBox" name="cpu_group">
<property name="title"> <property name="title">
<string>CPU</string> <string>CPU</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0"> <item row="4" column="0">
<widget class="QCheckBox" name="toggle_cpu_jit"> <widget class="QCheckBox" name="toggle_renderer_debug">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>Enable CPU JIT</string> <string>Enable debug renderer</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -203,10 +200,81 @@
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QCheckBox" name="toggle_renderer_debug"> <widget class="QCheckBox" name="toggle_cpu_jit">
<property name="text"> <property name="toolTip">
<string>Enable debug renderer</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text">
<string>Enable CPU JIT</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QWidget" name="refresh_rate_widget" native="true">
<layout class="QHBoxLayout" name="refresh_rate_widget_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="refresh_rate_combo">
<item>
<property name="text">
<string>Use global refresh rate</string>
</property>
</item>
<item>
<property name="text">
<string>Set refresh rate:</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="refresh_rate_label">
<property name="text">
<string>Refresh rate</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="slider_refresh_rate">
<property name="minimum">
<number>30</number>
</property>
<property name="maximum">
<number>360</number>
</property>
<property name="singleStep">
<number>30</number>
</property>
<property name="pageStep">
<number>30</number>
</property>
<property name="value">
<number>60</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="refresh_display_label">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
</layout> </layout>

View file

@ -51,6 +51,8 @@ void Apply() {
GDBStub::SetServerPort(values.gdbstub_port.GetValue()); GDBStub::SetServerPort(values.gdbstub_port.GetValue());
GDBStub::ToggleServer(values.use_gdbstub.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_shader_jit_enabled = values.use_shader_jit.GetValue();
VideoCore::g_hw_shader_enabled = values.use_hw_shader.GetValue(); VideoCore::g_hw_shader_enabled = values.use_hw_shader.GetValue();
VideoCore::g_separable_shader_enabled = values.separable_shader.GetValue(); VideoCore::g_separable_shader_enabled = values.separable_shader.GetValue();
@ -112,6 +114,7 @@ void LogSettings() {
LOG_INFO(Config, "Citra Configuration:"); LOG_INFO(Config, "Citra Configuration:");
log_setting("Core_UseCpuJit", values.use_cpu_jit.GetValue()); log_setting("Core_UseCpuJit", values.use_cpu_jit.GetValue());
log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage.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_UseGLES", values.use_gles.GetValue());
log_setting("Renderer_GraphicsAPI", GetGraphicsAPIName(values.graphics_api.GetValue())); log_setting("Renderer_GraphicsAPI", GetGraphicsAPIName(values.graphics_api.GetValue()));
log_setting("Renderer_UseHwShader", values.use_hw_shader.GetValue()); log_setting("Renderer_UseHwShader", values.use_hw_shader.GetValue());
@ -195,6 +198,7 @@ void RestoreGlobalState(bool is_powered_on) {
// Core // Core
values.cpu_clock_percentage.SetGlobal(true); values.cpu_clock_percentage.SetGlobal(true);
values.refresh_rate.SetGlobal(true);
values.is_new_3ds.SetGlobal(true); values.is_new_3ds.SetGlobal(true);
// Renderer // Renderer

View file

@ -490,6 +490,7 @@ struct Values {
std::unordered_map<std::string, bool> lle_modules; std::unordered_map<std::string, bool> lle_modules;
Setting<bool> use_gdbstub{false, "use_gdbstub"}; Setting<bool> use_gdbstub{false, "use_gdbstub"};
Setting<u16> gdbstub_port{24689, "gdbstub_port"}; Setting<u16> gdbstub_port{24689, "gdbstub_port"};
SwitchableSetting<u32, true> refresh_rate{60, 30, 360, "refresh_rate"};
// Miscellaneous // Miscellaneous
Setting<std::string> log_filter{"*:Info", "log_filter"}; Setting<std::string> log_filter{"*:Info", "log_filter"};

View file

@ -27,6 +27,11 @@
namespace GPU { 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<double>(frame_ticks);
Regs g_regs; Regs g_regs;
Memory::MemorySystem* g_memory; Memory::MemorySystem* g_memory;
@ -561,4 +566,9 @@ void Shutdown() {
LOG_DEBUG(HW_GPU, "shutdown OK"); LOG_DEBUG(HW_GPU, "shutdown OK");
} }
void SetRefreshRate(u32 refresh) {
frame_ticks = (4481136ull * 60) / refresh;
SCREEN_REFRESH_RATE = BASE_CLOCK_RATE_ARM11 / static_cast<double>(frame_ticks);
}
} // namespace GPU } // namespace GPU

View file

@ -21,11 +21,11 @@ class MemorySystem;
namespace GPU { namespace GPU {
// Measured on hardware to be 2240568 timer cycles or 4481136 ARM11 cycles // 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 // Refresh rate defined by ratio of ARM11 frequency to ARM11 ticks per frame
// (268,111,856) / (4,481,136) = 59.83122493939037Hz // (268,111,856) / (4,481,136) = 59.83122493939037Hz
constexpr double SCREEN_REFRESH_RATE = BASE_CLOCK_RATE_ARM11 / static_cast<double>(frame_ticks); extern double SCREEN_REFRESH_RATE;
// Returns index corresponding to the Regs member labeled by field_name // Returns index corresponding to the Regs member labeled by field_name
#define GPU_REG_INDEX(field_name) (offsetof(GPU::Regs, field_name) / sizeof(u32)) #define GPU_REG_INDEX(field_name) (offsetof(GPU::Regs, field_name) / sizeof(u32))
@ -328,4 +328,7 @@ void Init(Memory::MemorySystem& memory);
/// Shutdown hardware /// Shutdown hardware
void Shutdown(); void Shutdown();
/// Sets the screen refresh rate
void SetRefreshRate(u32 refresh);
} // namespace GPU } // namespace GPU

View file

@ -115,7 +115,7 @@ PerfStats::Results PerfStats::GetAndResetStats(microseconds current_system_time_
double PerfStats::GetLastFrameTimeScale() const { double PerfStats::GetLastFrameTimeScale() const {
std::lock_guard lock{object_mutex}; 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<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH; return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
} }