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");