Config: Make the setting tables constexpr

SETTING now takes offsets with offsetof and passes them along with the
setting's type, instead of the block and member pointers, and the
ConfigSetting constructors are constexpr. So the tables are built at compile
time, and later per-setting metadata can be checked by the compiler too.

Defaults that weren't constants had to change:
- AutoFrameSkip called IsVREnabled() during static initialization, before VR
  is set up. It's now a default callback, evaluated when the config is
  loaded or reset, which can turn it on by default on VR devices.
- DisplayRefreshRate read g_Config's own initial value, which is 60.

Path defaults now share the string member of the default union.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-22 15:34:47 +02:00
1 parent 71b38e58e6
commit 729047d449
3 files changed
+115 -150

No files matched your search

+38 -28
View File
@@ -16,10 +16,12 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include <cstddef>
#include <cstdlib>
#include <ctime>
#include <mutex>
#include <set>
#include <type_traits>
#include <sstream>
#include <thread>
@@ -249,11 +251,19 @@ static int DefaultScreenRotation() {
#endif
}
#define SETTING(a, x) &a, &a.x
#define SETTING_IDX(a, x, i) &a, &a.x[i]
#if defined(__GNUC__) || defined(__clang__)
// offsetof on classes with virtual functions (like ConfigBlock) is conditionally supported, and our compilers do support it.
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
// The type of the block a setting lives in, from an expression like g_Config or g_Config.gestureControls[0].
#define CONFIG_BLOCK_TYPE(a) std::remove_reference_t<decltype(a)>
// Offsets are taken with offsetof, so the tables can be constexpr.
#define SETTING(a, x) ConfigSettingOffset<decltype(CONFIG_BLOCK_TYPE(a)::x)>{ (uint32_t)offsetof(CONFIG_BLOCK_TYPE(a), x) }
#define SETTING_IDX(a, x, i) ConfigSettingOffset<std::remove_extent_t<decltype(CONFIG_BLOCK_TYPE(a)::x)>>{ (uint32_t)(offsetof(CONFIG_BLOCK_TYPE(a), x) + (i) * sizeof(std::remove_extent_t<decltype(CONFIG_BLOCK_TYPE(a)::x)>)) }
// All relative to g_Config.
static const ConfigSetting generalSettings[] = {
static constexpr ConfigSetting generalSettings[] = {
ConfigSetting("FirstRun", SETTING(g_Config, bFirstRun), true, CfgFlag::DEFAULT),
ConfigSetting("RunCount", SETTING(g_Config, iRunCount), 0, CfgFlag::DEFAULT),
ConfigSetting("Enable Logging", SETTING(g_Config, bEnableLogging), true, CfgFlag::PER_GAME),
@@ -405,7 +415,7 @@ static bool DefaultSasThread() {
return cpu_info.num_cores > 1;
}
static const ConfigSetting achievementSettings[] = {
static constexpr ConfigSetting achievementSettings[] = {
// Core settings
ConfigSetting("AchievementsEnable", SETTING(g_Config, bAchievementsEnable), false, CfgFlag::PER_GAME),
ConfigSetting("AchievementsEnableRAIntegration", SETTING(g_Config, bAchievementsEnableRAIntegration), false, CfgFlag::DEFAULT),
@@ -435,7 +445,7 @@ static const ConfigSetting achievementSettings[] = {
ConfigSetting("AchievementsUnlockedPos", SETTING(g_Config, iAchievementsUnlockedPos), (int)ScreenEdgePosition::TOP_CENTER, CfgFlag::PER_GAME | CfgFlag::DEFAULT),
};
static const ConfigSetting cpuSettings[] = {
static constexpr ConfigSetting cpuSettings[] = {
ConfigSetting("CPUCore", SETTING(g_Config, iCpuCore), &DefaultCpuCore, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("SeparateSASThread", SETTING(g_Config, bSeparateSASThread), &DefaultSasThread, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("IOTimingMethod", SETTING(g_Config, iIOTimingMethod), IOTIMING_FAST, CfgFlag::PER_GAME | CfgFlag::REPORT),
@@ -676,7 +686,7 @@ bool DisplayLayoutConfig::ResetToDefault(std::string_view blockName) {
// These were previously part of Graphics.
// It's instantiated into g_Config.displayLayoutLandscape and g_Config.displayLayoutPortrait.
// Defaults are set directly on the struct declaration (and adjusted per instance in ResetToDefault above).
static const ConfigSetting displayLayoutSettings[] = {
static constexpr ConfigSetting displayLayoutSettings[] = {
ConfigSetting("BufferFiltering", SETTING(g_Config.displayLayoutLandscape, iDisplayFilter), CfgFlag::PER_GAME),
ConfigSetting("DisplayStretch", SETTING(g_Config.displayLayoutLandscape, bDisplayStretch), CfgFlag::PER_GAME),
ConfigSetting("DisplayOffsetX", SETTING(g_Config.displayLayoutLandscape, fDisplayOffsetX), CfgFlag::PER_GAME),
@@ -702,7 +712,7 @@ bool GestureControlConfig::ResetToDefault(std::string_view blockName) {
}
// These were previously mostly part of General (which was wrong).
static const ConfigSetting gestureControlSettings[] = {
static constexpr ConfigSetting gestureControlSettings[] = {
ConfigSetting("SwipeUp", SETTING(g_Config.gestureControls[0], iSwipeUp), 0, CfgFlag::PER_GAME),
ConfigSetting("SwipeDown", SETTING(g_Config.gestureControls[0], iSwipeDown), 0, CfgFlag::PER_GAME),
ConfigSetting("SwipeLeft", SETTING(g_Config.gestureControls[0], iSwipeLeft), 0, CfgFlag::PER_GAME),
@@ -732,7 +742,7 @@ static int DefaultAnalogAltSpeedPercent() {
return LegacyFpsLimitToPercent(g_Config.iLegacyAnalogFpsLimit);
}
static const ConfigSetting graphicsSettings[] = {
static constexpr ConfigSetting graphicsSettings[] = {
ConfigSetting("iShowStatusFlags", SETTING(g_Config, iShowStatusFlags), 0, CfgFlag::PER_GAME),
ConfigSetting("GraphicsBackend", SETTING(g_Config, iGPUBackend), &DefaultGPUBackend, &GPUBackendTranslator::To, &GPUBackendTranslator::From, CfgFlag::DEFAULT | CfgFlag::REPORT),
#if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64)
@@ -758,7 +768,7 @@ static const ConfigSetting graphicsSettings[] = {
ConfigSetting("AndroidHwScale", SETTING(g_Config, iAndroidHwScale), 0, CfgFlag::DEFAULT),
ConfigSetting("HighQualityDepth", SETTING(g_Config, bHighQualityDepth), true, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("FrameSkip", SETTING(g_Config, iFrameSkip), 0, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("AutoFrameSkip", SETTING(g_Config, bAutoFrameSkip), IsVREnabled(), CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("AutoFrameSkip", SETTING(g_Config, bAutoFrameSkip), &IsVREnabled, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("StereoRendering", SETTING(g_Config, bStereoRendering), false, CfgFlag::PER_GAME),
ConfigSetting("StereoToMonoShader", SETTING(g_Config, sStereoToMonoShader), "RedBlue", CfgFlag::PER_GAME),
// Read before the new settings, which use them as defaults.
@@ -823,7 +833,7 @@ static const ConfigSetting graphicsSettings[] = {
ConfigSetting("UberShaderVertex", SETTING(g_Config, bUberShaderVertex), true, CfgFlag::DEFAULT),
ConfigSetting("DisplayRefreshRate", SETTING(g_Config, iDisplayRefreshRate), g_Config.iDisplayRefreshRate, CfgFlag::PER_GAME),
ConfigSetting("DisplayRefreshRate", SETTING(g_Config, iDisplayRefreshRate), 60, CfgFlag::PER_GAME),
};
static int LegacyVolumeToNewVolume(int legacy, int max) {
@@ -864,7 +874,7 @@ bool DefaultAudioMixWithOthers() {
#endif
}
static const ConfigSetting soundSettings[] = {
static constexpr ConfigSetting soundSettings[] = {
ConfigSetting("Enable", SETTING(g_Config, bEnableSound), true, CfgFlag::PER_GAME),
ConfigSetting("ExtraAudioBuffering", SETTING(g_Config, bExtraAudioBuffering), false, CfgFlag::DEFAULT),
ConfigSetting("AudioBufferSize", SETTING(g_Config, iSDLAudioBufferSize), 256, CfgFlag::DEFAULT),
@@ -904,9 +914,9 @@ static bool DefaultShowTouchControls() {
}
}
static const float defaultControlScale = 1.15f;
static const ConfigTouchPos defaultTouchPosShow = { -1.0f, -1.0f, defaultControlScale, true };
static const ConfigTouchPos defaultTouchPosHide = { -1.0f, -1.0f, defaultControlScale, false };
static constexpr float defaultControlScale = 1.15f;
static constexpr ConfigTouchPos defaultTouchPosShow = { -1.0f, -1.0f, defaultControlScale, true };
static constexpr ConfigTouchPos defaultTouchPosHide = { -1.0f, -1.0f, defaultControlScale, false };
void TouchControlConfig::ResetLayout() {
// reset puts the settings in a state so they'll then get properly reinitialized in InitPadLayout.
@@ -954,7 +964,7 @@ bool TouchControlConfig::ResetToDefault(std::string_view blockName) {
return true;
}
static const ConfigSetting touchControlSettings[] = {
static constexpr ConfigSetting touchControlSettings[] = {
ConfigSetting("ShowTouchCross", SETTING(g_Config.touchControlsLandscape, bShowTouchCross), true, CfgFlag::PER_GAME),
ConfigSetting("ShowTouchCircle", SETTING(g_Config.touchControlsLandscape, bShowTouchCircle), true, CfgFlag::PER_GAME),
ConfigSetting("ShowTouchSquare", SETTING(g_Config.touchControlsLandscape, bShowTouchSquare), true, CfgFlag::PER_GAME),
@@ -1003,7 +1013,7 @@ static const ConfigSetting touchControlSettings[] = {
ConfigSetting("HideStickBackground", SETTING(g_Config.touchControlsLandscape, bHideStickBackground), CfgFlag::PER_GAME),
};
static const ConfigSetting controlSettings[] = {
static constexpr ConfigSetting controlSettings[] = {
ConfigSetting("HapticFeedback", SETTING(g_Config, bHapticFeedback), false, CfgFlag::PER_GAME),
#if PPSSPP_PLATFORM(WINDOWS)
@@ -1094,7 +1104,7 @@ static const ConfigSetting controlSettings[] = {
static const std::vector<std::string_view> emptyList;
static const ConfigSetting networkSettings[] = {
static constexpr ConfigSetting networkSettings[] = {
ConfigSetting("EnableWlan", SETTING(g_Config, bEnableWlan), false, CfgFlag::PER_GAME),
ConfigSetting("EnableAdhocServer", SETTING(g_Config, bEnableAdhocServer), false, CfgFlag::PER_GAME),
ConfigSetting("proAdhocServer", SETTING(g_Config, sProAdhocServer), &DefaultProAdhocServer, CfgFlag::PER_GAME),
@@ -1121,14 +1131,14 @@ static const ConfigSetting networkSettings[] = {
ConfigSetting("ChatScreenPosition", SETTING(g_Config, iChatScreenPosition), (int)ScreenEdgePosition::BOTTOM_LEFT, CfgFlag::PER_GAME),
ConfigSetting("ChatTimestamps", SETTING(g_Config, bChatTimestamps), true, CfgFlag::PER_GAME),
ConfigSetting("EnableQuickChat", SETTING(g_Config, bEnableQuickChat), true, CfgFlag::PER_GAME),
ConfigSetting("QuickChat1", SETTING(g_Config, sQuickChat[0]), "Quick Chat 1", CfgFlag::PER_GAME),
ConfigSetting("QuickChat2", SETTING(g_Config, sQuickChat[1]), "Quick Chat 2", CfgFlag::PER_GAME),
ConfigSetting("QuickChat3", SETTING(g_Config, sQuickChat[2]), "Quick Chat 3", CfgFlag::PER_GAME),
ConfigSetting("QuickChat4", SETTING(g_Config, sQuickChat[3]), "Quick Chat 4", CfgFlag::PER_GAME),
ConfigSetting("QuickChat5", SETTING(g_Config, sQuickChat[4]), "Quick Chat 5", CfgFlag::PER_GAME),
ConfigSetting("QuickChat1", SETTING_IDX(g_Config, sQuickChat, 0), "Quick Chat 1", CfgFlag::PER_GAME),
ConfigSetting("QuickChat2", SETTING_IDX(g_Config, sQuickChat, 1), "Quick Chat 2", CfgFlag::PER_GAME),
ConfigSetting("QuickChat3", SETTING_IDX(g_Config, sQuickChat, 2), "Quick Chat 3", CfgFlag::PER_GAME),
ConfigSetting("QuickChat4", SETTING_IDX(g_Config, sQuickChat, 3), "Quick Chat 4", CfgFlag::PER_GAME),
ConfigSetting("QuickChat5", SETTING_IDX(g_Config, sQuickChat, 4), "Quick Chat 5", CfgFlag::PER_GAME),
};
static const ConfigSetting systemParamSettings[] = {
static constexpr ConfigSetting systemParamSettings[] = {
ConfigSetting("PSPModel", SETTING(g_Config, iPSPModel), PSP_MODEL_SLIM, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("PSPFirmwareVersion", SETTING(g_Config, iFirmwareVersion), PSP_DEFAULT_FIRMWARE, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("NickName", SETTING(g_Config, sNickName), "PPSSPP", CfgFlag::PER_GAME),
@@ -1149,7 +1159,7 @@ static const ConfigSetting systemParamSettings[] = {
ConfigSetting("FuseID", SETTING(g_Config, sFuseID), "", CfgFlag::DEFAULT),
};
static const ConfigSetting debuggerSettings[] = {
static constexpr ConfigSetting debuggerSettings[] = {
ConfigSetting("DisasmWindowX", SETTING(g_Config, iDisasmWindowX), -1, CfgFlag::DEFAULT),
ConfigSetting("DisasmWindowY", SETTING(g_Config, iDisasmWindowY), -1, CfgFlag::DEFAULT),
ConfigSetting("DisasmWindowW", SETTING(g_Config, iDisasmWindowW), -1, CfgFlag::DEFAULT),
@@ -1174,21 +1184,21 @@ static const ConfigSetting debuggerSettings[] = {
ConfigSetting("AutoSaveLoadSymbols", SETTING(g_Config, bAutoSaveLoadSymbols), false, CfgFlag::DEFAULT),
};
static const ConfigSetting jitSettings[] = {
static constexpr ConfigSetting jitSettings[] = {
ConfigSetting("DiscardRegsOnJRRA", SETTING(g_Config, bDiscardRegsOnJRRA), false, CfgFlag::DONT_SAVE | CfgFlag::REPORT),
};
static const ConfigSetting upgradeSettings[] = {
static constexpr ConfigSetting upgradeSettings[] = {
ConfigSetting("UpgradeMessage", SETTING(g_Config, sUpgradeMessage), "", CfgFlag::DEFAULT),
ConfigSetting("UpgradeVersion", SETTING(g_Config, sUpgradeVersion), "", CfgFlag::DEFAULT),
ConfigSetting("DismissedVersion", SETTING(g_Config, sDismissedVersion), "", CfgFlag::DEFAULT),
};
static const ConfigSetting themeSettings[] = {
static constexpr ConfigSetting themeSettings[] = {
ConfigSetting("ThemeName", SETTING(g_Config, sThemeName), "Default", CfgFlag::DEFAULT),
};
static const ConfigSetting vrSettings[] = {
static constexpr ConfigSetting vrSettings[] = {
ConfigSetting("VREnable", SETTING(g_Config, bEnableVR), true, CfgFlag::PER_GAME),
ConfigSetting("VREnable6DoF", SETTING(g_Config, bEnable6DoF), false, CfgFlag::PER_GAME),
ConfigSetting("VREnableStereo", SETTING(g_Config, bEnableStereo), false, CfgFlag::PER_GAME),