Path: blob/master/src/duckstation-qt/consolesettingswidget.cpp
4242 views
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <[email protected]>1// SPDX-License-Identifier: CC-BY-NC-ND-4.023#include "consolesettingswidget.h"4#include "qtutils.h"5#include "settingswindow.h"6#include "settingwidgetbinder.h"78#include "core/game_database.h"9#include "core/system.h"1011#include "util/cd_image.h"1213#include <QtWidgets/QMessageBox>14#include <QtWidgets/QPushButton>1516#include "moc_consolesettingswidget.cpp"1718static constexpr const int CDROM_SPEEDUP_VALUES[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0};1920ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsWindow* dialog, QWidget* parent)21: QWidget(parent), m_dialog(dialog)22{23SettingsInterface* sif = dialog->getSettingsInterface();2425m_ui.setupUi(this);2627SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.region, "Console", "Region", &Settings::ParseConsoleRegionName,28&Settings::GetConsoleRegionName, &Settings::GetConsoleRegionDisplayName,29Settings::DEFAULT_CONSOLE_REGION, ConsoleRegion::Count,30&QtUtils::GetIconForRegion);31SettingWidgetBinder::BindWidgetToEnumSetting(32sif, m_ui.forceVideoTiming, "GPU", "ForceVideoTiming", &Settings::ParseForceVideoTimingName,33&Settings::GetForceVideoTimingName, &Settings::GetForceVideoTimingDisplayName,34Settings::DEFAULT_FORCE_VIDEO_TIMING_MODE, ForceVideoTimingMode::Count, +[](ForceVideoTimingMode mode) {35return QtUtils::GetIconForRegion(36(mode == ForceVideoTimingMode::Disabled) ?37ConsoleRegion::Auto :38((mode == ForceVideoTimingMode::NTSC) ? ConsoleRegion::NTSC_U : ConsoleRegion::PAL));39});40SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBoot, "BIOS", "PatchFastBoot", false);41SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastForwardBoot, "BIOS", "FastForwardBoot", false);42SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enable8MBRAM, "Console", "Enable8MBRAM", false);43SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastForwardMemoryCardAccess, "MemoryCards",44"FastForwardAccess", false);45connect(m_ui.fastBoot, &QCheckBox::checkStateChanged, this, &ConsoleSettingsWidget::onFastBootChanged);46onFastBootChanged();4748SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.cpuExecutionMode, "CPU", "ExecutionMode",49&Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName,50&Settings::GetCPUExecutionModeDisplayName,51Settings::DEFAULT_CPU_EXECUTION_MODE, CPUExecutionMode::Count);52SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableCPUClockSpeedControl, "CPU", "OverclockEnable", false);53SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.recompilerICache, "CPU", "RecompilerICache", false);54SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cdromLoadImageToRAM, "CDROM", "LoadImageToRAM", false);55SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cdromAutoDiscChange, "CDROM", "AutoDiscChange", false);5657if (!m_dialog->isPerGameSettings())58{59SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cdromLoadImagePatches, "CDROM", "LoadImagePatches", false);60SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cdromIgnoreDriveSubcode, "CDROM", "IgnoreHostSubcode",61false);62}63else64{65m_ui.cdromGridLayout->removeWidget(m_ui.cdromIgnoreDriveSubcode);66delete m_ui.cdromIgnoreDriveSubcode;67m_ui.cdromIgnoreDriveSubcode = nullptr;68m_ui.cdromGridLayout->removeWidget(m_ui.cdromLoadImagePatches);69delete m_ui.cdromLoadImagePatches;70m_ui.cdromLoadImagePatches = nullptr;71}7273SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cdromSeekSpeedup, "CDROM", "SeekSpeedup", 1,74CDROM_SPEEDUP_VALUES);75SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cdromReadSpeedup, "CDROM", "ReadSpeedup", 1,76CDROM_SPEEDUP_VALUES);7778dialog->registerWidgetHelp(m_ui.region, tr("Region"), tr("Auto-Detect"),79tr("Determines the emulated hardware type."));80dialog->registerWidgetHelp(81m_ui.forceVideoTiming, tr("Frame Rate"), tr("Auto-Detect"),82tr("Utilizes the chosen frame timing regardless of the active region. This feature can be used to force PAL games "83"to run at 60Hz and NTSC games to run at 50Hz. For most games which have a speed tied to the framerate, this "84"will result in the game running approximately 17% faster or slower. For variable frame rate games, it may not "85"affect the speed."));86m_dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"),87tr("Skips the boot animation. Safe to enable."));88m_dialog->registerWidgetHelp(m_ui.fastForwardBoot, tr("Fast Forward Boot"), tr("Unchecked"),89tr("Fast forwards through the early loading process when fast booting, saving time. "90"Results may vary between games."));91dialog->registerWidgetHelp(92m_ui.enable8MBRAM, tr("Enable 8MB RAM (Dev Console)"), tr("Unchecked"),93tr("Enables an additional 6MB of RAM to obtain a total of 2+6 = 8MB, usually present on dev consoles. Games have "94"to use a larger heap size for "95"this additional RAM to be usable. Titles which rely on memory mirrors may break, so it should only be used "96"with compatible mods."));97m_dialog->registerWidgetHelp(m_ui.fastForwardMemoryCardAccess, tr("Fast Forward Memory Card Access"), tr("Unchecked"),98tr("Fast forwards through memory card access, both loading and saving. Can reduce "99"waiting times in games that frequently access memory cards."));100101dialog->registerWidgetHelp(m_ui.cpuExecutionMode, tr("Execution Mode"), tr("Recompiler (Fastest)"),102tr("Determines how the emulated CPU executes instructions."));103dialog->registerWidgetHelp(m_ui.enableCPUClockSpeedControl,104tr("Enable Clock Speed Control (Overclocking/Underclocking)"), tr("Unchecked"),105tr("When this option is chosen, the clock speed set below will be used."));106dialog->registerWidgetHelp(m_ui.cpuClockSpeed, tr("Overclocking Percentage"), tr("100%"),107tr("Selects the percentage of the normal clock speed the emulated hardware will run at."));108dialog->registerWidgetHelp(m_ui.recompilerICache, tr("Enable Recompiler ICache"), tr("Unchecked"),109tr("Simulates stalls in the recompilers when the emulated CPU would have to fetch "110"instructions into its cache. Makes games run closer to their console framerate, at a "111"small cost to performance. Interpreter mode always simulates the instruction cache."));112113dialog->registerWidgetHelp(114m_ui.cdromReadSpeedup, tr("CD-ROM Read Speedup"), tr("None (Double Speed)"),115tr("Speeds up CD-ROM reads by the specified factor. Only applies to double-speed reads, and is ignored when audio "116"is playing. May improve loading speeds in some games, at the cost of breaking others."));117dialog->registerWidgetHelp(118m_ui.cdromSeekSpeedup, tr("CD-ROM Seek Speedup"), tr("None (Normal Speed)"),119tr("Reduces the simulated time for the CD-ROM sled to move to different areas of the disc. Can improve loading "120"times, but crash games which do not expect the CD-ROM to operate faster."));121dialog->registerWidgetHelp(122m_ui.cdromLoadImageToRAM, tr("Preload Image to RAM"), tr("Unchecked"),123tr("Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay. In some "124"cases also eliminates stutter when games initiate audio track playback."));125dialog->registerWidgetHelp(m_ui.cdromLoadImagePatches, tr("Apply Image Patches"), tr("Unchecked"),126tr("Automatically applies patches to disc images when they are present in the same "127"directory. Currently only PPF patches are supported with this option."));128dialog->registerWidgetHelp(129m_ui.cdromAutoDiscChange, tr("Switch to Next Disc on Stop"), tr("Unchecked"),130tr("Automatically switches to the next disc in the game when the game stops the CD-ROM motor. No switch will occur "131"if the last disc in the game is already selected. <strong>Does not work for all games.</strong>"));132dialog->registerWidgetHelp(133m_ui.cdromIgnoreDriveSubcode, tr("Ignore Drive Subcode"), tr("Unchecked"),134tr("Ignores the subchannel provided by the drive when using physical discs, instead always generating subchannel "135"data. Won't work with libcrypt games, but can improve read reliability on some drives."));136137m_ui.cpuClockSpeed->setEnabled(m_dialog->getEffectiveBoolValue("CPU", "OverclockEnable", false));138139connect(m_ui.enableCPUClockSpeedControl, &QCheckBox::checkStateChanged, this,140&ConsoleSettingsWidget::onEnableCPUClockSpeedControlChecked);141connect(m_ui.cpuClockSpeed, &QSlider::valueChanged, this, &ConsoleSettingsWidget::onCPUClockSpeedValueChanged);142143SettingWidgetBinder::SetAvailability(m_ui.fastBoot, !m_dialog->hasGameTrait(GameDatabase::Trait::ForceFullBoot));144SettingWidgetBinder::SetAvailability(m_ui.fastForwardBoot, !m_dialog->hasGameTrait(GameDatabase::Trait::ForceFullBoot));145SettingWidgetBinder::SetAvailability(146m_ui.cpuExecutionMode, !m_dialog->hasGameTrait(GameDatabase::Trait::ForceInterpreter), m_ui.cpuExecutionModeLabel);147SettingWidgetBinder::SetAvailability(m_ui.cdromReadSpeedup,148!m_dialog->hasGameTrait(GameDatabase::Trait::DisableCDROMReadSpeedup),149m_ui.cdromReadSpeedupLabel);150SettingWidgetBinder::SetAvailability(m_ui.cdromSeekSpeedup,151!m_dialog->hasGameTrait(GameDatabase::Trait::DisableCDROMSeekSpeedup),152m_ui.cdromSeekSpeedupLabel);153154calculateCPUClockValue();155}156157ConsoleSettingsWidget::~ConsoleSettingsWidget() = default;158159void ConsoleSettingsWidget::onFastBootChanged()160{161const bool fast_boot_enabled =162m_dialog->getEffectiveBoolValue("BIOS", "PatchFastBoot", Settings::DEFAULT_FAST_BOOT_VALUE);163m_ui.fastForwardBoot->setEnabled(fast_boot_enabled);164}165166void ConsoleSettingsWidget::updateRecompilerICacheEnabled()167{168const CPUExecutionMode mode =169Settings::ParseCPUExecutionMode(170m_dialog171->getEffectiveStringValue("CPU", "ExecutionMode",172Settings::GetCPUExecutionModeName(Settings::DEFAULT_CPU_EXECUTION_MODE))173.c_str())174.value_or(Settings::DEFAULT_CPU_EXECUTION_MODE);175m_ui.recompilerICache->setEnabled(mode != CPUExecutionMode::Interpreter);176}177178void ConsoleSettingsWidget::onEnableCPUClockSpeedControlChecked(int state)179{180if (state == Qt::Checked &&181(!m_dialog->isPerGameSettings() || !Host::GetBaseBoolSettingValue("CPU", "OverclockEnable", false)) &&182!Host::GetBaseBoolSettingValue("UI", "CPUOverclockingWarningShown", false))183{184const QString message =185tr("Enabling CPU overclocking will break games, cause bugs, reduce performance and can significantly increase "186"system requirements.\n\nBy enabling this option you are agreeing to not create any bug reports unless you "187"have confirmed the bug also occurs with overclocking disabled.\n\nThis warning will only be shown once.");188189QMessageBox mb(QMessageBox::Warning, tr("CPU Overclocking Warning"), message, QMessageBox::NoButton, this);190mb.setWindowModality(Qt::WindowModal);191const QAbstractButton* const yes_button =192mb.addButton(tr("Yes, I will confirm bugs without overclocking before reporting."), QMessageBox::YesRole);193mb.addButton(tr("No, take me back to safety."), QMessageBox::NoRole);194mb.exec();195196if (mb.clickedButton() != yes_button)197{198QSignalBlocker sb(m_ui.enableCPUClockSpeedControl);199if (m_dialog->isPerGameSettings())200{201m_ui.enableCPUClockSpeedControl->setCheckState(Qt::PartiallyChecked);202m_dialog->removeSettingValue("CPU", "OverclockEnable");203}204else205{206m_ui.enableCPUClockSpeedControl->setCheckState(Qt::Unchecked);207m_dialog->setBoolSettingValue("CPU", "OverclockEnable", false);208}209210return;211}212213Host::SetBaseBoolSettingValue("UI", "CPUOverclockingWarningShown", true);214Host::CommitBaseSettingChanges();215}216217m_ui.cpuClockSpeed->setEnabled(m_dialog->getEffectiveBoolValue("CPU", "OverclockEnable", false));218updateCPUClockSpeedLabel();219}220221void ConsoleSettingsWidget::onCPUClockSpeedValueChanged(int value)222{223const u32 percent = static_cast<u32>(m_ui.cpuClockSpeed->value());224u32 numerator, denominator;225Settings::CPUOverclockPercentToFraction(percent, &numerator, &denominator);226m_dialog->setIntSettingValue("CPU", "OverclockNumerator", static_cast<int>(numerator));227m_dialog->setIntSettingValue("CPU", "OverclockDenominator", static_cast<int>(denominator));228updateCPUClockSpeedLabel();229}230231void ConsoleSettingsWidget::updateCPUClockSpeedLabel()232{233const int percent = m_ui.enableCPUClockSpeedControl->isChecked() ? m_ui.cpuClockSpeed->value() : 100;234const double frequency = (static_cast<double>(System::MASTER_CLOCK) * static_cast<double>(percent)) / 100.0;235m_ui.cpuClockSpeedLabel->setText(tr("%1% (%2MHz)").arg(percent).arg(frequency / 1000000.0, 0, 'f', 2));236}237238void ConsoleSettingsWidget::calculateCPUClockValue()239{240const u32 numerator = static_cast<u32>(m_dialog->getEffectiveIntValue("CPU", "OverclockNumerator", 1));241const u32 denominator = static_cast<u32>(m_dialog->getEffectiveIntValue("CPU", "OverclockDenominator", 1));242const u32 percent = Settings::CPUOverclockFractionToPercent(numerator, denominator);243QSignalBlocker sb(m_ui.cpuClockSpeed);244m_ui.cpuClockSpeed->setValue(static_cast<int>(percent));245updateCPUClockSpeedLabel();246}247248249