diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp index 831d3a309e..d450372017 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp @@ -73,6 +73,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* settings_dialog, dialog()->registerWidgetHelp(m_ui.eeClampMode, tr("Clamping Mode"), tr("Normal (Default)"), tr("Changes how ARMSX2 handles keeping floats in a standard x86 range. " + "Exact is Full plus the rest of the EE multiplier's one-ULP deficit, and is slower than Full. " "The default value handles the vast majority of games; modifying this setting when a game is not having a visible problem can cause instability.")); dialog()->registerWidgetHelp(m_ui.eeRecompiler, tr("Enable Recompiler"), tr("Checked"), @@ -103,7 +104,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* settings_dialog, dialog()->registerWidgetHelp(m_ui.eeFpuGuardedAddSub, tr("FPU Add/Sub Guard Bits"), tr("Checked"), //: "Guard bits" = extra low mantissa bits a standards-compliant FPU keeps during add/sub; the PS2's EE FPU does not, so the recompiler masks them to match. tr("Emulates the EE FPU's missing add/sub mantissa guard bits for hardware-accurate results. Leave checked; a few games (e.g. True Crime, Jak 3) misrender without it. " - "Unchecking is a minor speedup for EE-FPU-heavy games verified to render correctly without it. Has no effect when the EE Clamping Mode is set to Full.")); + "Unchecking is a minor speedup for EE-FPU-heavy games verified to render correctly without it. Has no effect when the EE Clamping Mode is set to Full or Exact.")); dialog()->registerWidgetHelp(m_ui.vu0RoundingMode, tr("VU0 Rounding Mode"), tr("Chop/Zero (Default)"), tr("Changes how ARMSX2 handles rounding while emulating the Emotion Engine's Vector Unit 0 (EE VU0). " "The default value handles the vast majority of games; modifying this setting when a game is not having a visible problem will cause stability issues and/or crashes.")); @@ -160,6 +161,10 @@ AdvancedSettingsWidget::~AdvancedSettingsWidget() = default; int AdvancedSettingsWidget::getGlobalClampingModeIndex(int vunum) const { + // eeClampMode 4 has no VU counterpart. + if (vunum < 0 && Host::GetBaseBoolSettingValue("EmuCore/CPU/Recompiler", "fpuExactMode", false)) + return 4; + if (Host::GetBaseBoolSettingValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0SignOverflow" : "vu1SignOverflow") : "fpuFullMode"), false)) return 3; @@ -182,6 +187,9 @@ int AdvancedSettingsWidget::getClampingModeIndex(int vunum) const std::optional default_false = dialog()->isPerGameSettings() ? std::nullopt : std::optional(false); std::optional default_true = dialog()->isPerGameSettings() ? std::nullopt : std::optional(true); + std::optional fourth; + if (vunum < 0) + fourth = dialog()->getBoolValue("EmuCore/CPU/Recompiler", "fpuExactMode", default_false); std::optional third = dialog()->getBoolValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0SignOverflow" : "vu1SignOverflow") : "fpuFullMode"), default_false); std::optional second = dialog()->getBoolValue("EmuCore/CPU/Recompiler", @@ -189,6 +197,8 @@ int AdvancedSettingsWidget::getClampingModeIndex(int vunum) const std::optional first = dialog()->getBoolValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0Overflow" : "vu1Overflow") : "fpuOverflow"), default_true); + if (fourth.has_value() && fourth.value()) + return base + 4; if (third.has_value() && third.value()) return base + 3; if (second.has_value() && second.value()) @@ -203,11 +213,12 @@ int AdvancedSettingsWidget::getClampingModeIndex(int vunum) const void AdvancedSettingsWidget::setClampingMode(int vunum, int index) { - std::optional first, second, third; + std::optional first, second, third, fourth; if (!dialog()->isPerGameSettings() || index > 0) { const bool base = dialog()->isPerGameSettings() ? 1 : 0; + fourth = (index >= (base + 4)); third = (index >= (base + 3)); second = (index >= (base + 2)); first = (index >= (base + 1)); @@ -220,15 +231,11 @@ void AdvancedSettingsWidget::setClampingMode(int vunum, int index) dialog()->setBoolSettingValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0Overflow" : "vu1Overflow") : "fpuOverflow"), first); - // Clear fpuExactMode (eeClampMode 4, not on this picker): ApplySanityCheck - // rejects a config with a mode set above the one picked. + // fpuExactMode is eeClampMode 4's bit, and the VUs have none. It is written + // with the other three because ApplySanityCheck drops a config whose bits + // are not a whole mode to the default, not to the mode that was picked. if (vunum < 0) - { - std::optional fourth; - if (first.has_value()) - fourth = false; dialog()->setBoolSettingValue("EmuCore/CPU/Recompiler", "fpuExactMode", fourth); - } } void AdvancedSettingsWidget::onSavestateCompressionTypeChanged() diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui index ce17e93239..8974f7c982 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui @@ -127,6 +127,11 @@ Full + + + Exact + + diff --git a/pcsx2/Docs/GameIndex.md b/pcsx2/Docs/GameIndex.md index cb152fc41d..db69eb2eea 100644 --- a/pcsx2/Docs/GameIndex.md +++ b/pcsx2/Docs/GameIndex.md @@ -122,8 +122,7 @@ The clamp modes are also numerically based. * `2` = Clamp **Extra+Preserve Sign** (clamp results as well as operands) * `3` = **Full Clamping** for FPU * `4` = **Exact**: mode 3 plus the rest of the EE multiplier's one-ULP deficit. - Multiplies it cannot decide from ft's mantissa call out of line. GameDB and - INI only — there is no picker entry. + Multiplies it cannot decide from ft's mantissa call out of line. ### vuClampMode diff --git a/pcsx2/ImGui/FullscreenUI_Settings.cpp b/pcsx2/ImGui/FullscreenUI_Settings.cpp index 8c1101aeec..9993ceef3d 100644 --- a/pcsx2/ImGui/FullscreenUI_Settings.cpp +++ b/pcsx2/ImGui/FullscreenUI_Settings.cpp @@ -2678,6 +2678,10 @@ void FullscreenUI::DrawClampingModeSetting(SettingsInterface* bsi, const char* t std::optional default_false = IsEditingGameSettings(bsi) ? std::nullopt : std::optional(false); std::optional default_true = IsEditingGameSettings(bsi) ? std::nullopt : std::optional(true); + // eeClampMode 4 has no VU counterpart. + std::optional fourth; + if (vunum < 0) + fourth = bsi->GetOptionalBoolValue("EmuCore/CPU/Recompiler", "fpuExactMode", default_false); std::optional third = bsi->GetOptionalBoolValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0SignOverflow" : "vu1SignOverflow") : "fpuFullMode"), default_false); std::optional second = bsi->GetOptionalBoolValue("EmuCore/CPU/Recompiler", @@ -2686,7 +2690,9 @@ void FullscreenUI::DrawClampingModeSetting(SettingsInterface* bsi, const char* t "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0Overflow" : "vu1Overflow") : "fpuOverflow"), default_true); int index; - if (third.has_value() && third.value()) + if (fourth.has_value() && fourth.value()) + index = base + 4; + else if (third.has_value() && third.value()) index = base + 3; else if (second.has_value() && second.value()) index = base + 2; @@ -2703,6 +2709,7 @@ void FullscreenUI::DrawClampingModeSetting(SettingsInterface* bsi, const char* t FSUI_NSTR("Normal (Default)"), FSUI_NSTR("Extra + Preserve Sign"), FSUI_NSTR("Full"), + FSUI_NSTR("Exact"), }; static constexpr const char* vu_clamping_mode_settings[] = { FSUI_NSTR("Use Global Setting"), @@ -2712,13 +2719,14 @@ void FullscreenUI::DrawClampingModeSetting(SettingsInterface* bsi, const char* t FSUI_NSTR("Extra + Preserve Sign"), }; const char* const* options = (vunum >= 0) ? vu_clamping_mode_settings : ee_clamping_mode_settings; + const int option_count = static_cast((vunum >= 0) ? std::size(vu_clamping_mode_settings) : std::size(ee_clamping_mode_settings)); const int setting_offset = IsEditingGameSettings(bsi) ? 0 : 1; if (MenuButtonWithValue(title, summary, Host::TranslateToCString(TR_CONTEXT, options[index + setting_offset]))) { ImGuiFullscreen::ChoiceDialogOptions cd_options; - cd_options.reserve(std::size(ee_clamping_mode_settings)); - for (int i = setting_offset; i < static_cast(std::size(ee_clamping_mode_settings)); i++) + cd_options.reserve(option_count); + for (int i = setting_offset; i < option_count; i++) cd_options.emplace_back(Host::TranslateToString(TR_CONTEXT, options[i]), (i == (index + setting_offset))); OpenChoiceDialog(title, false, std::move(cd_options), [game_settings = IsEditingGameSettings(bsi), vunum](s32 index, const std::string& title, bool checked) { @@ -2726,11 +2734,12 @@ void FullscreenUI::DrawClampingModeSetting(SettingsInterface* bsi, const char* t { auto lock = Host::GetSettingsLock(); - std::optional first, second, third; + std::optional first, second, third, fourth; if (!game_settings || index > 0) { const bool base = game_settings ? 1 : 0; + fourth = (index >= (base + 4)); third = (index >= (base + 3)); second = (index >= (base + 2)); first = (index >= (base + 1)); @@ -2745,12 +2754,7 @@ void FullscreenUI::DrawClampingModeSetting(SettingsInterface* bsi, const char* t "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0Overflow" : "vu1Overflow") : "fpuOverflow"), first); // Same write as AdvancedSettingsWidget::setClampingMode. if (vunum < 0) - { - std::optional fourth; - if (first.has_value()) - fourth = false; bsi->SetOptionalBoolValue("EmuCore/CPU/Recompiler", "fpuExactMode", fourth); - } SetSettingsChanged(bsi); } @@ -6459,6 +6463,7 @@ TRANSLATE_NOOP("FullscreenUI", "2 Frames"); TRANSLATE_NOOP("FullscreenUI", "3 Frames"); TRANSLATE_NOOP("FullscreenUI", "Extra + Preserve Sign"); TRANSLATE_NOOP("FullscreenUI", "Full"); +TRANSLATE_NOOP("FullscreenUI", "Exact"); TRANSLATE_NOOP("FullscreenUI", "Extra"); TRANSLATE_NOOP("FullscreenUI", "Automatic (Default)"); TRANSLATE_NOOP("FullscreenUI", "Direct3D 11 (Legacy)"); @@ -6951,7 +6956,6 @@ TRANSLATE_NOOP("FullscreenUI", "Enable PINE"); TRANSLATE_NOOP("FullscreenUI", "PINE Slot"); TRANSLATE_NOOP("FullscreenUI", "Show Cheats For All CRCs"); TRANSLATE_NOOP("FullscreenUI", "Show Patches For All CRCs"); -TRANSLATE_NOOP("FullscreenUI", "FPU Multiply Hack"); TRANSLATE_NOOP("FullscreenUI", "Use Software Renderer For FMVs"); TRANSLATE_NOOP("FullscreenUI", "Skip MPEG Hack"); TRANSLATE_NOOP("FullscreenUI", "Preload TLB Hack");