From c5469c409a047c016ad14a76f87b711e30888fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 6 Nov 2023 17:44:43 -0600 Subject: [PATCH 1/4] Add specific sysprop for accelerometer --- Common/System/System.h | 1 + SDL/SDLMain.cpp | 6 ++++++ UI/GameSettingsScreen.cpp | 4 ++-- UWP/PPSSPP_UWPMain.cpp | 2 ++ android/jni/app-android.cpp | 2 ++ ios/main.mm | 2 ++ 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Common/System/System.h b/Common/System/System.h index 5b009c571870..48cfaa280af6 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -130,6 +130,7 @@ enum SystemProperty { SYSPROP_HAS_IMAGE_BROWSER, SYSPROP_HAS_BACK_BUTTON, SYSPROP_HAS_KEYBOARD, + SYSPROP_HAS_ACCELEROMETER, // Used to enable/disable tilt input settings SYSPROP_HAS_OPEN_DIRECTORY, SYSPROP_HAS_LOGIN_DIALOG, SYSPROP_HAS_TEXT_INPUT_DIALOG, // Indicates that System_InputBoxGetString is available. diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index dae1b693461e..b7e0572d96a7 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -584,6 +584,12 @@ bool System_GetPropertyBool(SystemProperty prop) { case SYSPROP_HAS_FOLDER_BROWSER: case SYSPROP_HAS_FILE_BROWSER: return true; +#endif + case SYSPROP_HAS_ACCELEROMETER: +#if defined(MOBILE_DEVICE) + return true; +#else + return false; #endif default: return false; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 0a3a4cfc16be..0ed4537fc81a 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -643,10 +643,10 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings) controlsSettings->Add(new CheckBox(&g_Config.bGamepadOnlyFocused, co->T("Ignore gamepads when not focused"))); #endif - if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) { + if (System_GetPropertyBool(SYSPROP_HAS_ACCELEROMETER)) { Choice *customizeTilt = controlsSettings->Add(new Choice(co->T("Tilt control setup"))); customizeTilt->OnClick.Handle(this, &GameSettingsScreen::OnTiltCustomize); - } else if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { + } else if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { // TODO: This seems like a regression controlsSettings->Add(new CheckBox(&g_Config.bHapticFeedback, co->T("HapticFeedback", "Haptic Feedback (vibration)"))); } diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 4293ac2a0b05..52e1b37acac2 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -416,6 +416,8 @@ bool System_GetPropertyBool(SystemProperty prop) { return true; // we just use the file browser case SYSPROP_HAS_BACK_BUTTON: return true; + case SYSPROP_HAS_ACCELEROMETER: + return IsMobile(); case SYSPROP_APP_GOLD: #ifdef GOLD return true; diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index d6d1ea905f1c..aea792207bc4 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -530,6 +530,8 @@ bool System_GetPropertyBool(SystemProperty prop) { } case SYSPROP_HAS_KEYBOARD: return deviceType != DEVICE_TYPE_VR; + case SYSPROP_HAS_ACCELEROMETER: + return deviceType == DEVICE_TYPE_MOBILE; #ifndef HTTPS_NOT_AVAILABLE case SYSPROP_SUPPORTS_HTTPS: return !g_Config.bDisableHTTPS; diff --git a/ios/main.mm b/ios/main.mm index 4ca2f041ddbd..c111208abad5 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -160,6 +160,8 @@ bool System_GetPropertyBool(SystemProperty prop) { return false; case SYSPROP_HAS_BACK_BUTTON: return false; + case SYSPROP_HAS_ACCELEROMETER: + return true; case SYSPROP_APP_GOLD: #ifdef GOLD return true; From 73932603e3c0f42b3042ff600f111f7ade69d8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 6 Nov 2023 17:56:56 -0600 Subject: [PATCH 2/4] IniFile: Remove redundant function, add a debug assert --- Common/Data/Format/IniFile.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/Common/Data/Format/IniFile.cpp b/Common/Data/Format/IniFile.cpp index b4bb21e81112..bb7cc1ea6619 100644 --- a/Common/Data/Format/IniFile.cpp +++ b/Common/Data/Format/IniFile.cpp @@ -7,6 +7,7 @@ #include +// Hm, what's this for? #ifndef _MSC_VER #include #endif @@ -19,23 +20,14 @@ #include #include "Common/Data/Format/IniFile.h" +#include "Common/Data/Text/Parsers.h" #include "Common/File/VFS/VFS.h" #include "Common/File/FileUtil.h" -#include "Common/Data/Text/Parsers.h" - -#ifdef _WIN32 -#include "Common/Data/Encoding/Utf8.h" -#endif +#include "Common/Log.h" +#include "Common/Math/math_util.h" #include "Common/StringUtils.h" -bool StringViewEqualCaseInsensitive(const std::string_view lhs, const std::string_view rhs) { - if (lhs.size() != rhs.size()) { - return false; - } - return ::strncasecmp(lhs.data(), rhs.data(), rhs.size()) == 0; -} - // This unescapes # signs. // NOTE: These parse functions can make better use of the string_view - the pos argument should not be needed, for example. static bool ParseLineKey(std::string_view line, size_t &pos, std::string *keyOut) { @@ -199,7 +191,7 @@ void Section::Clear() { ParsedIniLine *Section::GetLine(const char *key) { for (auto &line : lines_) { - if (StringViewEqualCaseInsensitive(line.Key(), key)) + if (equalsNoCase(line.Key(), key)) return &line; } return nullptr; @@ -207,7 +199,7 @@ ParsedIniLine *Section::GetLine(const char *key) { const ParsedIniLine *Section::GetLine(const char* key) const { for (auto &line : lines_) { - if (StringViewEqualCaseInsensitive(line.Key(), key)) + if (equalsNoCase(line.Key(), key)) return &line; } return nullptr; @@ -222,6 +214,7 @@ void Section::Set(const char* key, uint64_t newValue) { } void Section::Set(const char* key, float newValue) { + _dbg_assert_(!my_isnanorinf(newValue)); Set(key, StringFromFormat("%f", newValue).c_str()); } @@ -397,7 +390,7 @@ bool Section::Get(const char* key, double* value, double defaultValue) const bool Section::Exists(const char *key) const { for (auto &line : lines_) { - if (StringViewEqualCaseInsensitive(key, line.Key())) + if (equalsNoCase(key, line.Key())) return true; } return false; From 25ab1206b51e11dea6e2e3b8b7ba087b6ece3be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 6 Nov 2023 18:28:53 -0600 Subject: [PATCH 3/4] Fix stepping of tilt low end radius setting. Add some asserts. --- Common/UI/PopupScreens.cpp | 3 +++ Common/UI/View.cpp | 4 ++++ UI/TiltAnalogSettingsScreen.cpp | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 1d470d1242da..60c343dadaf5 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -167,12 +167,15 @@ PopupSliderChoice::PopupSliderChoice(int *value, int minValue, int maxValue, int PopupSliderChoiceFloat::PopupSliderChoiceFloat(float *value, float minValue, float maxValue, float defaultValue, const std::string &text, ScreenManager *screenManager, const std::string &units, LayoutParams *layoutParams) : AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), minValue_(minValue), maxValue_(maxValue), defaultValue_(defaultValue), step_(1.0f), units_(units), screenManager_(screenManager) { + _dbg_assert_(maxValue > minValue); fmt_ = "%2.2f"; OnClick.Handle(this, &PopupSliderChoiceFloat::HandleClick); } PopupSliderChoiceFloat::PopupSliderChoiceFloat(float *value, float minValue, float maxValue, float defaultValue, const std::string &text, float step, ScreenManager *screenManager, const std::string &units, LayoutParams *layoutParams) : AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), minValue_(minValue), maxValue_(maxValue), defaultValue_(defaultValue), step_(step), units_(units), screenManager_(screenManager) { + _dbg_assert_(step > 0.0f); + _dbg_assert_(maxValue > minValue); fmt_ = "%2.2f"; OnClick.Handle(this, &PopupSliderChoiceFloat::HandleClick); } diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 2ef4df534882..9959c9b7b5cf 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -1557,6 +1557,9 @@ bool SliderFloat::ApplyKey(InputKeyCode keyCode) { default: return false; } + + _dbg_assert_(!my_isnanorinf(*value_)); + EventParams params{}; params.v = this; params.a = (uint32_t)(*value_); @@ -1584,6 +1587,7 @@ bool SliderFloat::Touch(const TouchInput &input) { } void SliderFloat::Clamp() { + _dbg_assert_(!my_isnanorinf(*value_)); if (*value_ < minValue_) *value_ = minValue_; else if (*value_ > maxValue_) diff --git a/UI/TiltAnalogSettingsScreen.cpp b/UI/TiltAnalogSettingsScreen.cpp index af4456a54599..4f3d3d215ad0 100644 --- a/UI/TiltAnalogSettingsScreen.cpp +++ b/UI/TiltAnalogSettingsScreen.cpp @@ -122,8 +122,8 @@ void TiltAnalogSettingsScreen::CreateViews() { settings->Add(new ItemHeader(co->T("Sensitivity"))); if (g_Config.iTiltInputType == 1) { - settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltAnalogDeadzoneRadius, 0.0f, 0.8f, 0.0f, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc); - settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltInverseDeadzone, 0.0f, 0.8f, 0.0f, co->T("Low end radius"), 0.0f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc); + settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltAnalogDeadzoneRadius, 0.0f, 0.8f, 0.0f, co->T("Deadzone radius"), 0.02f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc); + settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltInverseDeadzone, 0.0f, 0.8f, 0.0f, co->T("Low end radius"), 0.02f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc); settings->Add(new CheckBox(&g_Config.bTiltCircularInverseDeadzone, co->T("Circular low end radius")))->SetEnabledFunc(enabledFunc); } settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityX, 0, 100, 60, co->T("Tilt Sensitivity along X axis"), screenManager(), "%"))->SetEnabledFunc(enabledFunc); From 4f2f1c439212dae8952c37c4f04965bb0a8c3467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 9 Nov 2023 19:14:31 +0100 Subject: [PATCH 4/4] Tilt: Fix some edge cases leading to division by zero and similar. --- Core/TiltEventProcessor.cpp | 19 +++++++++++++++++-- GPU/Common/GPUStateUtils.h | 2 -- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Core/TiltEventProcessor.cpp b/Core/TiltEventProcessor.cpp index 571f58f84f55..63003d47f8ae 100644 --- a/Core/TiltEventProcessor.cpp +++ b/Core/TiltEventProcessor.cpp @@ -35,8 +35,11 @@ void GenerateTriggerButtonEvent(int digitalX, int digitalY); // deadzone is normalized - 0 to 1 // sensitivity controls how fast the deadzone reaches max value inline float ApplyDeadzone(float x, float deadzone) { + if (deadzone >= 0.99f) { + // Meaningless, and not reachable with normal controls. + return x; + } const float factor = 1.0f / (1.0f - deadzone); - if (x > deadzone) { return (x - deadzone) * factor + deadzone; } else if (x < -deadzone) { @@ -55,7 +58,9 @@ inline void ApplyInverseDeadzone(float x, float y, float *outX, float *outY, flo } if (circular) { float magnitude = sqrtf(x * x + y * y); - magnitude = (magnitude + inverseDeadzone) / magnitude; + if (magnitude > 0.00001f) { + magnitude = (magnitude + inverseDeadzone) / magnitude; + } *outX = Clamp(x * magnitude, -1.0f, 1.0f); *outY = Clamp(y * magnitude, -1.0f, 1.0f); } else { @@ -83,6 +88,10 @@ void ProcessTilt(bool landscape, float calibrationAngle, float x, float y, float float yAngle = angleAroundX - calibrationAngle; float xAngle = asinf(down.x); + _dbg_assert_(!my_isnanorinf(angleAroundX)); + _dbg_assert_(!my_isnanorinf(yAngle)); + _dbg_assert_(!my_isnanorinf(xAngle)); + float tiltX = xAngle; float tiltY = yAngle; @@ -107,11 +116,17 @@ void ProcessTilt(bool landscape, float calibrationAngle, float x, float y, float float adjustedTiltX = ApplyDeadzone(tiltX, g_Config.fTiltAnalogDeadzoneRadius); float adjustedTiltY = ApplyDeadzone(tiltY, g_Config.fTiltAnalogDeadzoneRadius); + _dbg_assert_(!my_isnanorinf(adjustedTiltX)); + _dbg_assert_(!my_isnanorinf(adjustedTiltY)); + // Unlike regular deadzone, where per-axis is okay, inverse deadzone (to compensate for game deadzones) really needs to be // applied on the two axes together. // TODO: Share this code with the joystick code. For now though, we keep it separate. ApplyInverseDeadzone(adjustedTiltX, adjustedTiltY, &adjustedTiltX, &adjustedTiltY, g_Config.fTiltInverseDeadzone, g_Config.bTiltCircularInverseDeadzone); + _dbg_assert_(!my_isnanorinf(adjustedTiltX)); + _dbg_assert_(!my_isnanorinf(adjustedTiltY)); + rawTiltAnalogX = adjustedTiltX; rawTiltAnalogY = adjustedTiltY; GenerateAnalogStickEvent(adjustedTiltX, adjustedTiltY); diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index a786190f6046..af1f6c6ed38b 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -249,8 +249,6 @@ struct GenericLogicState { // Same logicOp is kept. } } - - void Log(); }; struct ComputedPipelineState {