// Copyright 2017 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "DolphinQt/Settings/AdvancedPane.h" #include #include #include #include #include #include #include #include #include #include #include #include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/SystemTimers.h" #include "Core/HW/VideoInterface.h" #include "Core/PowerPC/PowerPC.h" #include "Core/System.h" #include "DolphinQt/Config/ConfigControls/ConfigBool.h" #include "DolphinQt/Config/ConfigControls/ConfigFloatSlider.h" #include "DolphinQt/Config/ConfigControls/ConfigSlider.h" #include "DolphinQt/QtUtils/QtUtils.h" #include "DolphinQt/QtUtils/SignalBlocking.h" #include "DolphinQt/Settings.h" static const std::map CPU_CORE_NAMES = { {PowerPC::CPUCore::Interpreter, QT_TR_NOOP("Interpreter (slowest)")}, {PowerPC::CPUCore::CachedInterpreter, QT_TR_NOOP("Cached Interpreter (slower)")}, {PowerPC::CPUCore::JIT64, QT_TR_NOOP("JIT Recompiler for x86-64 (recommended)")}, {PowerPC::CPUCore::JITARM64, QT_TR_NOOP("JIT Recompiler for ARM64 (recommended)")}, }; AdvancedPane::AdvancedPane(QWidget* parent) : QWidget(parent) { CreateLayout(); Update(); ConnectLayout(); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, &AdvancedPane::Update); } void AdvancedPane::CreateLayout() { auto* main_layout = new QVBoxLayout(); setLayout(main_layout); auto* cpu_options_group = new QGroupBox(tr("CPU Options")); auto* cpu_options_group_layout = new QVBoxLayout(); cpu_options_group->setLayout(cpu_options_group_layout); main_layout->addWidget(cpu_options_group); auto* cpu_emulation_engine_layout = new QFormLayout; cpu_emulation_engine_layout->setFormAlignment(Qt::AlignLeft | Qt::AlignTop); cpu_emulation_engine_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); cpu_options_group_layout->addLayout(cpu_emulation_engine_layout); m_cpu_emulation_engine_combobox = new QComboBox(this); cpu_emulation_engine_layout->addRow(tr("CPU Emulation Engine:"), m_cpu_emulation_engine_combobox); for (PowerPC::CPUCore cpu_core : PowerPC::AvailableCPUCores()) { m_cpu_emulation_engine_combobox->addItem(tr(CPU_CORE_NAMES.at(cpu_core))); } m_enable_mmu_checkbox = new ConfigBool(tr("Enable MMU"), Config::MAIN_MMU); m_enable_mmu_checkbox->SetDescription( tr("Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = " "Fast)

If unsure, leave this unchecked.")); cpu_options_group_layout->addWidget(m_enable_mmu_checkbox); m_pause_on_panic_checkbox = new ConfigBool(tr("Pause on Panic"), Config::MAIN_PAUSE_ON_PANIC); m_pause_on_panic_checkbox->SetDescription( tr("Pauses the emulation if a Read/Write or Unknown Instruction panic occurs.
Enabling " "will affect performance.
The performance impact is the same as having Enable MMU " "on.

If unsure, leave this unchecked.")); cpu_options_group_layout->addWidget(m_pause_on_panic_checkbox); m_accurate_cpu_cache_checkbox = new ConfigBool(tr("Enable Write-Back Cache (slow)"), Config::MAIN_ACCURATE_CPU_CACHE); m_accurate_cpu_cache_checkbox->SetDescription( tr("Enables emulation of the CPU write-back cache.
Enabling will have a significant " "impact on performance.
This should be left disabled unless absolutely " "needed.

If unsure, leave this unchecked.")); cpu_options_group_layout->addWidget(m_accurate_cpu_cache_checkbox); auto* clock_override = new QGroupBox(tr("Clock Override")); auto* clock_override_layout = new QVBoxLayout(); clock_override->setLayout(clock_override_layout); main_layout->addWidget(clock_override); m_cpu_clock_override_checkbox = new ConfigBool(tr("Enable Emulated CPU Clock Override"), Config::MAIN_OVERCLOCK_ENABLE); clock_override_layout->addWidget(m_cpu_clock_override_checkbox); connect(m_cpu_clock_override_checkbox, &QCheckBox::toggled, this, &AdvancedPane::Update); auto* cpu_clock_override_slider_layout = new QHBoxLayout(); cpu_clock_override_slider_layout->setContentsMargins(0, 0, 0, 0); clock_override_layout->addLayout(cpu_clock_override_slider_layout); m_cpu_clock_override_slider = new ConfigFloatSlider(0.01f, 4.0f, Config::MAIN_OVERCLOCK, 0.01f); cpu_clock_override_slider_layout->addWidget(m_cpu_clock_override_slider); m_cpu_label = new QLabel(); cpu_clock_override_slider_layout->addWidget(m_cpu_label); std::function cpu_text = [this]() { const float multi = Config::Get(Config::MAIN_OVERCLOCK); const int percent = static_cast(std::round(multi * 100.f)); const int core_clock = Core::System::GetInstance().GetSystemTimers().GetTicksPerSecond() / std::pow(10, 6); const int clock = static_cast(std::round(multi * core_clock)); m_cpu_label->setText(tr("%1% (%2 MHz)").arg(QString::number(percent), QString::number(clock))); }; cpu_text(); connect(m_cpu_clock_override_slider, &QSlider::valueChanged, this, [this, cpu_text]() { cpu_text(); }); m_cpu_clock_override_checkbox->SetDescription( tr("Adjusts the emulated CPU's clock rate.

" "On games that have an unstable frame rate despite full emulation speed, " "higher values can improve their performance, requiring a powerful device. " "Lower values reduce the emulated console's performance, but improve the " "emulation speed.

" "WARNING: Changing this from the default (100%) can and will " "break games and cause glitches. Do so at your own risk. " "Please do not report bugs that occur with a non-default clock." "

If unsure, leave this unchecked.")); auto* vi_rate_override = new QGroupBox(tr("VBI Frequency Override")); auto* vi_rate_override_layout = new QVBoxLayout(); vi_rate_override->setLayout(vi_rate_override_layout); main_layout->addWidget(vi_rate_override); m_vi_rate_override_checkbox = new ConfigBool(tr("Enable VBI Frequency Override"), Config::MAIN_VI_OVERCLOCK_ENABLE); vi_rate_override_layout->addWidget(m_vi_rate_override_checkbox); connect(m_vi_rate_override_checkbox, &QCheckBox::toggled, this, &AdvancedPane::Update); auto* vi_rate_override_slider_layout = new QHBoxLayout(); vi_rate_override_slider_layout->setContentsMargins(0, 0, 0, 0); vi_rate_override_layout->addLayout(vi_rate_override_slider_layout); m_vi_rate_override_slider = new ConfigFloatSlider(0.01f, 5.0f, Config::MAIN_VI_OVERCLOCK, 0.01f); vi_rate_override_slider_layout->addWidget(m_vi_rate_override_slider); m_vi_label = new QLabel(); vi_rate_override_slider_layout->addWidget(m_vi_label); std::function vi_text = [this]() { const int percent = static_cast(std::round(Config::Get(Config::MAIN_VI_OVERCLOCK) * 100.f)); float vps = static_cast(Core::System::GetInstance().GetVideoInterface().GetTargetRefreshRate()); if (vps == 0.0f || !Config::Get(Config::MAIN_VI_OVERCLOCK_ENABLE)) vps = 59.94f * Config::Get(Config::MAIN_VI_OVERCLOCK); m_vi_label->setText( tr("%1% (%2 VPS)").arg(QString::number(percent), QString::number(vps, 'f', 2))); }; vi_text(); connect(m_vi_rate_override_slider, &QSlider::valueChanged, this, [this, vi_text]() { vi_text(); }); m_vi_rate_override_checkbox->SetDescription( tr("Adjusts the VBI frequency. Also adjusts the emulated CPU's " "clock rate, to keep it relatively the same.

" "Makes games run at a different frame rate, making the emulation less " "demanding when lowered, or improving smoothness when increased. This may " "affect gameplay speed, as it is often tied to the frame rate.

" "WARNING: Changing this from the default (100%) can and will " "break games and cause glitches. Do so at your own risk. " "Please do not report bugs that occur with a non-default frequency." "

If unsure, leave this unchecked.")); auto* ram_override = new QGroupBox(tr("Memory Override")); auto* ram_override_layout = new QVBoxLayout(); ram_override->setLayout(ram_override_layout); main_layout->addWidget(ram_override); m_ram_override_checkbox = new ConfigBool(tr("Enable Emulated Memory Size Override"), Config::MAIN_RAM_OVERRIDE_ENABLE); ram_override_layout->addWidget(m_ram_override_checkbox); connect(m_ram_override_checkbox, &QCheckBox::toggled, this, &AdvancedPane::Update); auto* mem1_override_slider_layout = new QHBoxLayout(); mem1_override_slider_layout->setContentsMargins(0, 0, 0, 0); ram_override_layout->addLayout(mem1_override_slider_layout); m_mem1_override_slider = new ConfigSliderU32(24, 64, Config::MAIN_MEM1_SIZE, 0x100000); mem1_override_slider_layout->addWidget(m_mem1_override_slider); m_mem1_label = new QLabel(tr("%1 MB (MEM1)").arg(QString::number(m_mem1_override_slider->value()))); mem1_override_slider_layout->addWidget(m_mem1_label); connect(m_mem1_override_slider, &QSlider::valueChanged, this, [this](int value) { m_mem1_label->setText(tr("%1 MB (MEM1)").arg(QString::number(value))); }); auto* mem2_override_slider_layout = new QHBoxLayout(); mem2_override_slider_layout->setContentsMargins(0, 0, 0, 0); ram_override_layout->addLayout(mem2_override_slider_layout); m_mem2_override_slider = new ConfigSliderU32(64, 128, Config::MAIN_MEM2_SIZE, 0x100000); mem2_override_slider_layout->addWidget(m_mem2_override_slider); m_mem2_label = new QLabel(tr("%1 MB (MEM2)").arg(QString::number(m_mem2_override_slider->value()))); mem2_override_slider_layout->addWidget(m_mem2_label); connect(m_mem2_override_slider, &QSlider::valueChanged, this, [this](int value) { m_mem2_label->setText(tr("%1 MB (MEM2)").arg(QString::number(value))); }); m_ram_override_checkbox->SetDescription( tr("Adjusts the amount of RAM in the emulated console.

" "WARNING: Enabling this will completely break many games.
Only a small " "number " "of games can benefit from this." "

If unsure, leave this unchecked.")); auto* rtc_options = new QGroupBox(tr("Custom RTC Options")); rtc_options->setLayout(new QVBoxLayout()); main_layout->addWidget(rtc_options); m_custom_rtc_checkbox = new ConfigBool(tr("Enable Custom RTC"), Config::MAIN_CUSTOM_RTC_ENABLE); rtc_options->layout()->addWidget(m_custom_rtc_checkbox); connect(m_custom_rtc_checkbox, &QCheckBox::toggled, this, &AdvancedPane::Update); m_custom_rtc_datetime = new QDateTimeEdit(); // Show seconds m_custom_rtc_datetime->setDisplayFormat(m_custom_rtc_datetime->displayFormat().replace( QStringLiteral("mm"), QStringLiteral("mm:ss"))); QtUtils::ShowFourDigitYear(m_custom_rtc_datetime); m_custom_rtc_datetime->setDateTimeRange(QDateTime({2000, 1, 1}, {0, 0, 0}, Qt::UTC), QDateTime({2099, 12, 31}, {23, 59, 59}, Qt::UTC)); m_custom_rtc_datetime->setTimeSpec(Qt::UTC); rtc_options->layout()->addWidget(m_custom_rtc_datetime); m_custom_rtc_checkbox->SetDescription( tr("This setting allows you to set a custom real time clock (RTC) separate from " "your current system time." "

If unsure, leave this unchecked.")); main_layout->addStretch(1); } void AdvancedPane::ConnectLayout() { connect(m_cpu_emulation_engine_combobox, &QComboBox::currentIndexChanged, [](int index) { const auto cpu_cores = PowerPC::AvailableCPUCores(); if (index >= 0 && static_cast(index) < cpu_cores.size()) Config::SetBaseOrCurrent(Config::MAIN_CPU_CORE, cpu_cores[index]); }); m_ram_override_checkbox->setChecked(Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE)); connect(m_ram_override_checkbox, &QCheckBox::toggled, [this](bool enable_ram_override) { Config::SetBaseOrCurrent(Config::MAIN_RAM_OVERRIDE_ENABLE, enable_ram_override); Update(); }); connect(m_custom_rtc_datetime, &QDateTimeEdit::dateTimeChanged, [this](QDateTime date_time) { Config::SetBaseOrCurrent(Config::MAIN_CUSTOM_RTC_VALUE, static_cast(date_time.toSecsSinceEpoch())); Update(); }); } void AdvancedPane::Update() { const bool is_uninitialized = Core::IsUninitialized(Core::System::GetInstance()); const bool enable_cpu_clock_override_widgets = Config::Get(Config::MAIN_OVERCLOCK_ENABLE); const bool enable_vi_rate_override_widgets = Config::Get(Config::MAIN_VI_OVERCLOCK_ENABLE); const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE); const bool enable_custom_rtc_widgets = Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE) && is_uninitialized; const auto available_cpu_cores = PowerPC::AvailableCPUCores(); const auto cpu_core = Config::Get(Config::MAIN_CPU_CORE); for (size_t i = 0; i < available_cpu_cores.size(); ++i) { if (available_cpu_cores[i] == cpu_core) m_cpu_emulation_engine_combobox->setCurrentIndex(int(i)); } m_cpu_emulation_engine_combobox->setEnabled(is_uninitialized); m_enable_mmu_checkbox->setEnabled(is_uninitialized); m_pause_on_panic_checkbox->setEnabled(is_uninitialized); { QFont bf = font(); bf.setBold(Config::GetActiveLayerForConfig(Config::MAIN_OVERCLOCK_ENABLE) != Config::LayerType::Base); const QSignalBlocker blocker(m_cpu_clock_override_checkbox); m_cpu_clock_override_checkbox->setFont(bf); m_cpu_clock_override_checkbox->setChecked(enable_cpu_clock_override_widgets); } m_cpu_clock_override_slider->setEnabled(enable_cpu_clock_override_widgets); m_cpu_label->setEnabled(enable_cpu_clock_override_widgets); QFont vi_bf = font(); vi_bf.setBold(Config::GetActiveLayerForConfig(Config::MAIN_VI_OVERCLOCK_ENABLE) != Config::LayerType::Base); m_vi_rate_override_checkbox->setFont(vi_bf); m_vi_rate_override_checkbox->setChecked(enable_vi_rate_override_widgets); m_vi_rate_override_slider->setEnabled(enable_vi_rate_override_widgets); m_vi_label->setEnabled(enable_vi_rate_override_widgets); m_ram_override_checkbox->setEnabled(is_uninitialized); SignalBlocking(m_ram_override_checkbox)->setChecked(enable_ram_override_widgets); m_mem1_override_slider->setEnabled(enable_ram_override_widgets && is_uninitialized); m_mem1_label->setEnabled(enable_ram_override_widgets && is_uninitialized); m_mem2_override_slider->setEnabled(enable_ram_override_widgets && is_uninitialized); m_mem2_label->setEnabled(enable_ram_override_widgets && is_uninitialized); m_custom_rtc_checkbox->setEnabled(is_uninitialized); SignalBlocking(m_custom_rtc_checkbox)->setChecked(Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE)); QDateTime initial_date_time; initial_date_time.setSecsSinceEpoch(Config::Get(Config::MAIN_CUSTOM_RTC_VALUE)); m_custom_rtc_datetime->setEnabled(enable_custom_rtc_widgets); SignalBlocking(m_custom_rtc_datetime)->setDateTime(initial_date_time); }