From b941f40b329af9edacfda5a04ddf7fbf41462f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 14 Dec 2023 10:44:18 +0100 Subject: [PATCH 1/6] Remove unused function --- UI/ControlMappingScreen.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 188c391cc2bc..13d0c38a65e7 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -413,25 +413,9 @@ bool KeyMappingNewMouseKeyDialog::key(const KeyInput &key) { return true; } -static bool IgnoreAxisForMapping(int axis) { - switch (axis) { - case JOYSTICK_AXIS_ACCELEROMETER_X: - case JOYSTICK_AXIS_ACCELEROMETER_Y: - case JOYSTICK_AXIS_ACCELEROMETER_Z: - // Ignore the accelerometer for mapping for now. - // We use tilt control for these. - return true; - - default: - return false; - } -} - void KeyMappingNewKeyDialog::axis(const AxisInput &axis) { if (time_now_d() < delayUntil_) return; - if (IgnoreAxisForMapping(axis.axisId)) - return; if (ignoreInput_) return; @@ -468,8 +452,6 @@ void KeyMappingNewKeyDialog::axis(const AxisInput &axis) { void KeyMappingNewMouseKeyDialog::axis(const AxisInput &axis) { if (mapped_) return; - if (IgnoreAxisForMapping(axis.axisId)) - return; if (axis.value > AXIS_BIND_THRESHOLD) { mapped_ = true; @@ -698,10 +680,6 @@ bool TouchTestScreen::key(const KeyInput &key) { } void TouchTestScreen::axis(const AxisInput &axis) { - // This just filters out accelerometer events. We show everything else. - if (IgnoreAxisForMapping(axis.axisId)) - return; - char buf[512]; snprintf(buf, sizeof(buf), "Axis: %s (%d) (value %1.3f) Device ID: %d", KeyMap::GetAxisName(axis.axisId).c_str(), axis.axisId, axis.value, axis.deviceId); From ed4941f41653e8757c72ae2a866829e154d17ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 14 Dec 2023 11:01:45 +0100 Subject: [PATCH 2/6] Remove Vulkan (and Windows.h) include from DevScreens.cpp --- Common/GPU/Vulkan/thin3d_vulkan.cpp | 20 ++++++++++++++++++++ Common/GPU/thin3d.h | 2 ++ UI/DevScreens.cpp | 27 ++++----------------------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 7a24231d3c09..a509a3b1acbc 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -392,6 +392,26 @@ class VKContext : public DrawContext { } return list; } + std::vector GetPresentModeList(const char *currentMarkerString) const override { + std::vector list; + for (auto mode : vulkan_->GetAvailablePresentModes()) { + std::string str = VulkanPresentModeToString(mode); + if (mode == vulkan_->GetPresentMode()) { + str += std::string(" (") + currentMarkerString + ")"; + } + list.push_back(str); + } + return list; + } + std::vector GetSurfaceFormatList() const override { + std::vector list; + for (auto &format : vulkan_->SurfaceFormats()) { + std::string str = StringFromFormat("%s : %s", VulkanFormatToString(format.format), VulkanColorSpaceToString(format.colorSpace)); + list.push_back(str); + } + return list; + } + uint32_t GetSupportedShaderLanguages() const override { return (uint32_t)ShaderLanguage::GLSL_VULKAN; } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 47ef9295a3a9..e0db174ed1d7 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -698,6 +698,8 @@ class DrawContext { virtual std::vector GetFeatureList() const { return std::vector(); } virtual std::vector GetExtensionList(bool device, bool enabledOnly) const { return std::vector(); } virtual std::vector GetDeviceList() const { return std::vector(); } + virtual std::vector GetPresentModeList(const char *currentMarkerString) const { return std::vector(); } + virtual std::vector GetSurfaceFormatList() const { return std::vector(); } // Describes the primary shader language that this implementation prefers. const ShaderLanguageDesc &GetShaderLanguageDesc() { diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index ff91a4de784a..ac7e896036ca 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -34,9 +34,6 @@ #include "Common/System/OSD.h" #include "Common/GPU/OpenGL/GLFeatures.h" -#if !PPSSPP_PLATFORM(UWP) -#include "Common/GPU/Vulkan/VulkanContext.h" -#endif #include "Common/File/AndroidStorage.h" #include "Common/Data/Text/I18n.h" #include "Common/Data/Encoding/Utf8.h" @@ -72,9 +69,7 @@ #include "UI/ControlMappingScreen.h" #include "UI/GameSettingsScreen.h" - #ifdef _WIN32 -#include "Common/CommonWindows.h" // Want to avoid including the full header here as it includes d3dx.h int GetD3DCompilerVersion(); #endif @@ -799,11 +794,6 @@ void SystemInfoScreen::CreateTabs() { } } else if (GetGPUBackend() == GPUBackend::VULKAN) { LinearLayout *gpuExtensions = AddTab("DevSystemInfoOGLExt", si->T("Vulkan Features")); -#if !PPSSPP_PLATFORM(UWP) - // Vulkan specific code here, can't be bothered to abstract. - // OK because of above check. - - VulkanContext *vk = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); CollapsibleSection *vulkanFeatures = gpuExtensions->Add(new CollapsibleSection(si->T("Vulkan Features"))); std::vector features = draw->GetFeatureList(); @@ -812,23 +802,14 @@ void SystemInfoScreen::CreateTabs() { } CollapsibleSection *presentModes = gpuExtensions->Add(new CollapsibleSection(si->T("Present Modes"))); - for (auto mode : vk->GetAvailablePresentModes()) { - std::string str = VulkanPresentModeToString(mode); - if (mode == vk->GetPresentMode()) { - str += std::string(" (") + di->T("Current") + ")"; - } - presentModes->Add(new TextView(str, new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); + for (auto mode : draw->GetPresentModeList(di->T("Current"))) { + presentModes->Add(new TextView(mode, new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); } CollapsibleSection *colorFormats = gpuExtensions->Add(new CollapsibleSection(si->T("Display Color Formats"))); - if (vk) { - for (auto &format : vk->SurfaceFormats()) { - std::string line = StringFromFormat("%s : %s", VulkanFormatToString(format.format), VulkanColorSpaceToString(format.colorSpace)); - colorFormats->Add(new TextView(line, - new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); - } + for (auto &format : draw->GetSurfaceFormatList()) { + colorFormats->Add(new TextView(format, new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetFocusable(true); } -#endif CollapsibleSection *enabledExtensions = gpuExtensions->Add(new CollapsibleSection(std::string(si->T("Vulkan Extensions")) + " (" + di->T("Enabled") + ")")); std::vector extensions = draw->GetExtensionList(true, true); From 812b1024f0c34306d48a5cf1393e320357540295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 14 Dec 2023 11:10:36 +0100 Subject: [PATCH 3/6] Move TouchTestScreen to DevScreens --- Common/Render/ManagedTexture.cpp | 2 - Common/UI/Context.cpp | 2 + Common/UI/Context.h | 4 + UI/ControlMappingScreen.cpp | 212 ------------------------------- UI/ControlMappingScreen.h | 41 ------ UI/DevScreens.cpp | 212 +++++++++++++++++++++++++++++++ UI/DevScreens.h | 41 ++++++ UI/NativeApp.cpp | 1 + 8 files changed, 260 insertions(+), 255 deletions(-) diff --git a/Common/Render/ManagedTexture.cpp b/Common/Render/ManagedTexture.cpp index 0aeef5ba513d..36a50312639c 100644 --- a/Common/Render/ManagedTexture.cpp +++ b/Common/Render/ManagedTexture.cpp @@ -173,7 +173,6 @@ Draw::Texture *CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t } Draw::Texture *CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType type, bool generateMips) { - INFO_LOG(SYSTEM, "CreateTextureFromFile(%s)", filename); size_t fileSize; uint8_t *buffer = g_VFS.ReadFile(filename, &fileSize); if (!buffer) { @@ -203,7 +202,6 @@ Draw::Texture *ManagedTexture::GetTexture() { ManagedTexture::ManagedTexture(Draw::DrawContext *draw, std::string_view filename, ImageFileType type, bool generateMips) : draw_(draw), filename_(filename), type_(type), generateMips_(generateMips) { - INFO_LOG(SYSTEM, "ManagedTexture::ManagedTexture (%s)", filename_.c_str()); StartLoadTask(); } diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index c92bbb794f6a..1a69b6bad6b3 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -11,6 +11,7 @@ #include "Common/Render/Text/draw_text.h" #include "Common/Render/ManagedTexture.h" #include "Common/Log.h" +#include "Common/TimeUtil.h" #include "Common/LogReporting.h" UIContext::UIContext() { @@ -44,6 +45,7 @@ void UIContext::setUIAtlas(const std::string &name) { } void UIContext::BeginFrame() { + frameStartTime_ = time_now_d(); if (!uitexture_ || UIAtlas_ != lastUIAtlas_) { uitexture_ = CreateTextureFromFile(draw_, UIAtlas_.c_str(), ImageFileType::ZIM, false); lastUIAtlas_ = UIAtlas_; diff --git a/Common/UI/Context.h b/Common/UI/Context.h index 754814f419f1..b64fd1f1ad1e 100644 --- a/Common/UI/Context.h +++ b/Common/UI/Context.h @@ -61,6 +61,8 @@ class UIContext { void RebindTexture() const; void BindFontTexture() const; + double FrameStartTime() const { return frameStartTime_; } + // TODO: Support transformed bounds using stencil void PushScissor(const Bounds &bounds); void PopScissor(); @@ -119,6 +121,8 @@ class UIContext { Draw::DrawContext *draw_ = nullptr; Bounds bounds_; + double frameStartTime_ = 0.0; + float fontScaleX_ = 1.0f; float fontScaleY_ = 1.0f; UI::FontStyle *fontStyle_ = nullptr; diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 13d0c38a65e7..50c5ae56a3c4 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -565,218 +565,6 @@ UI::EventReturn AnalogSetupScreen::OnResetToDefaults(UI::EventParams &e) { return UI::EVENT_DONE; } -void TouchTestScreen::touch(const TouchInput &touch) { - UIDialogScreenWithGameBackground::touch(touch); - if (touch.flags & TOUCH_DOWN) { - bool found = false; - for (int i = 0; i < MAX_TOUCH_POINTS; i++) { - if (touches_[i].id == touch.id) { - WARN_LOG(SYSTEM, "Double touch"); - touches_[i].x = touch.x; - touches_[i].y = touch.y; - found = true; - } - } - if (!found) { - for (int i = 0; i < MAX_TOUCH_POINTS; i++) { - if (touches_[i].id == -1) { - touches_[i].id = touch.id; - touches_[i].x = touch.x; - touches_[i].y = touch.y; - break; - } - } - } - } - if (touch.flags & TOUCH_MOVE) { - bool found = false; - for (int i = 0; i < MAX_TOUCH_POINTS; i++) { - if (touches_[i].id == touch.id) { - touches_[i].x = touch.x; - touches_[i].y = touch.y; - found = true; - } - } - if (!found) { - WARN_LOG(SYSTEM, "Move without touch down: %d", touch.id); - } - } - if (touch.flags & TOUCH_UP) { - bool found = false; - for (int i = 0; i < MAX_TOUCH_POINTS; i++) { - if (touches_[i].id == touch.id) { - found = true; - touches_[i].id = -1; - break; - } - } - if (!found) { - WARN_LOG(SYSTEM, "Touch release without touch down"); - } - } -} - -// TODO: Move this screen out into its own file. -void TouchTestScreen::CreateViews() { - using namespace UI; - - auto di = GetI18NCategory(I18NCat::DIALOG); - auto gr = GetI18NCategory(I18NCat::GRAPHICS); - root_ = new LinearLayout(ORIENT_VERTICAL); - LinearLayout *theTwo = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)); - - lastKeyEvents_ = theTwo->Add(new TextView("-", new LayoutParams(FILL_PARENT, WRAP_CONTENT))); - - root_->Add(theTwo); - -#if !PPSSPP_PLATFORM(UWP) - static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" }; - PopupMultiChoice *renderingBackendChoice = root_->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, (int)GPUBackend::OPENGL, ARRAY_SIZE(renderingBackend), I18NCat::GRAPHICS, screenManager())); - renderingBackendChoice->OnChoice.Handle(this, &TouchTestScreen::OnRenderingBackend); - - if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL)) - renderingBackendChoice->HideChoice((int)GPUBackend::OPENGL); - if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D9)) - renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D9); - if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11)) - renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D11); - if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN)) - renderingBackendChoice->HideChoice((int)GPUBackend::VULKAN); -#endif - -#if PPSSPP_PLATFORM(ANDROID) - root_->Add(new Choice(gr->T("Recreate Activity")))->OnClick.Handle(this, &TouchTestScreen::OnRecreateActivity); -#endif - root_->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &TouchTestScreen::OnImmersiveModeChange); - root_->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); -} - -void TouchTestScreen::UpdateLogView() { - while (keyEventLog_.size() > 8) { - keyEventLog_.erase(keyEventLog_.begin()); - } - - std::string text; - for (auto &iter : keyEventLog_) { - text += iter + "\n"; - } - - if (lastKeyEvents_) { - lastKeyEvents_->SetText(text); - } -} - -bool TouchTestScreen::key(const KeyInput &key) { - UIScreen::key(key); - char buf[512]; - snprintf(buf, sizeof(buf), "%s (%d) Device ID: %d [%s%s%s%s]", KeyMap::GetKeyName(key.keyCode).c_str(), key.keyCode, key.deviceId, - (key.flags & KEY_IS_REPEAT) ? "REP" : "", - (key.flags & KEY_UP) ? "UP" : "", - (key.flags & KEY_DOWN) ? "DOWN" : "", - (key.flags & KEY_CHAR) ? "CHAR" : ""); - keyEventLog_.push_back(buf); - UpdateLogView(); - return true; -} - -void TouchTestScreen::axis(const AxisInput &axis) { - char buf[512]; - snprintf(buf, sizeof(buf), "Axis: %s (%d) (value %1.3f) Device ID: %d", - KeyMap::GetAxisName(axis.axisId).c_str(), axis.axisId, axis.value, axis.deviceId); - - keyEventLog_.push_back(buf); - if (keyEventLog_.size() > 8) { - keyEventLog_.erase(keyEventLog_.begin()); - } - UpdateLogView(); -} - -void TouchTestScreen::DrawForeground(UIContext &dc) { - Bounds bounds = dc.GetLayoutBounds(); - - double now = time_now_d(); - double delta = now - lastFrameTime_; - lastFrameTime_ = now; - - dc.BeginNoTex(); - for (int i = 0; i < MAX_TOUCH_POINTS; i++) { - if (touches_[i].id != -1) { - dc.Draw()->Circle(touches_[i].x, touches_[i].y, 100.0, 3.0, 80, 0.0f, 0xFFFFFFFF, 1.0); - } - } - dc.Flush(); - - dc.Begin(); - - char buffer[4096]; - for (int i = 0; i < MAX_TOUCH_POINTS; i++) { - if (touches_[i].id != -1) { - dc.Draw()->Circle(touches_[i].x, touches_[i].y, 100.0, 3.0, 80, 0.0f, 0xFFFFFFFF, 1.0); - snprintf(buffer, sizeof(buffer), "%0.1fx%0.1f", touches_[i].x, touches_[i].y); - dc.DrawText(buffer, touches_[i].x, touches_[i].y + (touches_[i].y > g_display.dp_yres - 100.0f ? -135.0f : 95.0f), 0xFFFFFFFF, ALIGN_HCENTER | FLAG_DYNAMIC_ASCII); - } - } - - char extra_debug[2048]{}; - -#if PPSSPP_PLATFORM(ANDROID) - truncate_cpy(extra_debug, Android_GetInputDeviceDebugString().c_str()); -#endif - - snprintf(buffer, sizeof(buffer), -#if PPSSPP_PLATFORM(ANDROID) - "display_res: %dx%d\n" -#endif - "dp_res: %dx%d pixel_res: %dx%d\n" - "g_dpi: %0.3f g_dpi_scale: %0.3fx%0.3f\n" - "g_dpi_scale_real: %0.3fx%0.3f\n" - "delta: %0.2f ms fps: %0.3f\n%s", -#if PPSSPP_PLATFORM(ANDROID) - System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES), -#endif - g_display.dp_xres, g_display.dp_yres, g_display.pixel_xres, g_display.pixel_yres, - g_display.dpi, g_display.dpi_scale_x, g_display.dpi_scale_y, - g_display.dpi_scale_real_x, g_display.dpi_scale_real_y, - delta * 1000.0, 1.0 / delta, - extra_debug); - - // On Android, also add joystick debug data. - - dc.DrawTextShadow(buffer, bounds.centerX(), bounds.y + 20.0f, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII); - dc.Flush(); -} - -void RecreateActivity() { - const int SYSTEM_JELLYBEAN = 16; - if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= SYSTEM_JELLYBEAN) { - INFO_LOG(SYSTEM, "Sending recreate"); - System_Notify(SystemNotification::FORCE_RECREATE_ACTIVITY); - INFO_LOG(SYSTEM, "Got back from recreate"); - } else { - auto gr = GetI18NCategory(I18NCat::GRAPHICS); - System_Toast(gr->T("Must Restart", "You must restart PPSSPP for this change to take effect")); - } -} - -UI::EventReturn TouchTestScreen::OnImmersiveModeChange(UI::EventParams &e) { - System_Notify(SystemNotification::IMMERSIVE_MODE_CHANGE); - if (g_Config.iAndroidHwScale != 0) { - RecreateActivity(); - } - return UI::EVENT_DONE; -} - -UI::EventReturn TouchTestScreen::OnRenderingBackend(UI::EventParams &e) { - g_Config.Save("GameSettingsScreen::RenderingBackend"); - System_RestartApp("--touchscreentest"); - return UI::EVENT_DONE; -} - -UI::EventReturn TouchTestScreen::OnRecreateActivity(UI::EventParams &e) { - RecreateActivity(); - return UI::EVENT_DONE; -} - class Backplate : public UI::InertView { public: Backplate(float scale, UI::LayoutParams *layoutParams = nullptr) : InertView(layoutParams), scale_(scale) {} diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h index 3f66bb1a998f..b2202bd3a8d5 100644 --- a/UI/ControlMappingScreen.h +++ b/UI/ControlMappingScreen.h @@ -138,47 +138,6 @@ class AnalogSetupScreen : public UIDialogScreenWithGameBackground { JoystickHistoryView *stickView_[2]{}; }; -class TouchTestScreen : public UIDialogScreenWithGameBackground { -public: - TouchTestScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { - for (int i = 0; i < MAX_TOUCH_POINTS; i++) { - touches_[i].id = -1; - } - } - - void touch(const TouchInput &touch) override; - void DrawForeground(UIContext &dc) override; - - bool key(const KeyInput &key) override; - void axis(const AxisInput &axis) override; - - const char *tag() const override { return "TouchTest"; } - -protected: - struct TrackedTouch { - int id; - float x; - float y; - }; - enum { - MAX_TOUCH_POINTS = 10, - }; - TrackedTouch touches_[MAX_TOUCH_POINTS]{}; - - std::vector keyEventLog_; - - UI::TextView *lastKeyEvents_ = nullptr; - - double lastFrameTime_ = 0.0; - - void CreateViews() override; - void UpdateLogView(); - - UI::EventReturn OnImmersiveModeChange(UI::EventParams &e); - UI::EventReturn OnRenderingBackend(UI::EventParams &e); - UI::EventReturn OnRecreateActivity(UI::EventParams &e); -}; - class MockPSP; class VisualMappingScreen : public UIDialogScreenWithGameBackground { diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index ac7e896036ca..1bc7a66ce3ee 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -1452,3 +1452,215 @@ void FrameDumpTestScreen::update() { RecreateViews(); } } + +void TouchTestScreen::touch(const TouchInput &touch) { + UIDialogScreenWithGameBackground::touch(touch); + if (touch.flags & TOUCH_DOWN) { + bool found = false; + for (int i = 0; i < MAX_TOUCH_POINTS; i++) { + if (touches_[i].id == touch.id) { + WARN_LOG(SYSTEM, "Double touch"); + touches_[i].x = touch.x; + touches_[i].y = touch.y; + found = true; + } + } + if (!found) { + for (int i = 0; i < MAX_TOUCH_POINTS; i++) { + if (touches_[i].id == -1) { + touches_[i].id = touch.id; + touches_[i].x = touch.x; + touches_[i].y = touch.y; + break; + } + } + } + } + if (touch.flags & TOUCH_MOVE) { + bool found = false; + for (int i = 0; i < MAX_TOUCH_POINTS; i++) { + if (touches_[i].id == touch.id) { + touches_[i].x = touch.x; + touches_[i].y = touch.y; + found = true; + } + } + if (!found) { + WARN_LOG(SYSTEM, "Move without touch down: %d", touch.id); + } + } + if (touch.flags & TOUCH_UP) { + bool found = false; + for (int i = 0; i < MAX_TOUCH_POINTS; i++) { + if (touches_[i].id == touch.id) { + found = true; + touches_[i].id = -1; + break; + } + } + if (!found) { + WARN_LOG(SYSTEM, "Touch release without touch down"); + } + } +} + +// TODO: Move this screen out into its own file. +void TouchTestScreen::CreateViews() { + using namespace UI; + + auto di = GetI18NCategory(I18NCat::DIALOG); + auto gr = GetI18NCategory(I18NCat::GRAPHICS); + root_ = new LinearLayout(ORIENT_VERTICAL); + LinearLayout *theTwo = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)); + + lastKeyEvents_ = theTwo->Add(new TextView("-", new LayoutParams(FILL_PARENT, WRAP_CONTENT))); + + root_->Add(theTwo); + +#if !PPSSPP_PLATFORM(UWP) + static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" }; + PopupMultiChoice *renderingBackendChoice = root_->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, (int)GPUBackend::OPENGL, ARRAY_SIZE(renderingBackend), I18NCat::GRAPHICS, screenManager())); + renderingBackendChoice->OnChoice.Handle(this, &TouchTestScreen::OnRenderingBackend); + + if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL)) + renderingBackendChoice->HideChoice((int)GPUBackend::OPENGL); + if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D9)) + renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D9); + if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11)) + renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D11); + if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN)) + renderingBackendChoice->HideChoice((int)GPUBackend::VULKAN); +#endif + +#if PPSSPP_PLATFORM(ANDROID) + root_->Add(new Choice(gr->T("Recreate Activity")))->OnClick.Handle(this, &TouchTestScreen::OnRecreateActivity); +#endif + root_->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &TouchTestScreen::OnImmersiveModeChange); + root_->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); +} + +void TouchTestScreen::UpdateLogView() { + while (keyEventLog_.size() > 8) { + keyEventLog_.erase(keyEventLog_.begin()); + } + + std::string text; + for (auto &iter : keyEventLog_) { + text += iter + "\n"; + } + + if (lastKeyEvents_) { + lastKeyEvents_->SetText(text); + } +} + +bool TouchTestScreen::key(const KeyInput &key) { + UIScreen::key(key); + char buf[512]; + snprintf(buf, sizeof(buf), "%s (%d) Device ID: %d [%s%s%s%s]", KeyMap::GetKeyName(key.keyCode).c_str(), key.keyCode, key.deviceId, + (key.flags & KEY_IS_REPEAT) ? "REP" : "", + (key.flags & KEY_UP) ? "UP" : "", + (key.flags & KEY_DOWN) ? "DOWN" : "", + (key.flags & KEY_CHAR) ? "CHAR" : ""); + keyEventLog_.push_back(buf); + UpdateLogView(); + return true; +} + +void TouchTestScreen::axis(const AxisInput &axis) { + char buf[512]; + snprintf(buf, sizeof(buf), "Axis: %s (%d) (value %1.3f) Device ID: %d", + KeyMap::GetAxisName(axis.axisId).c_str(), axis.axisId, axis.value, axis.deviceId); + + keyEventLog_.push_back(buf); + if (keyEventLog_.size() > 8) { + keyEventLog_.erase(keyEventLog_.begin()); + } + UpdateLogView(); +} + +void TouchTestScreen::DrawForeground(UIContext &dc) { + Bounds bounds = dc.GetLayoutBounds(); + + double now = dc.FrameStartTime(); + double delta = now - lastFrameTime_; + lastFrameTime_ = now; + + dc.BeginNoTex(); + for (int i = 0; i < MAX_TOUCH_POINTS; i++) { + if (touches_[i].id != -1) { + dc.Draw()->Circle(touches_[i].x, touches_[i].y, 100.0, 3.0, 80, 0.0f, 0xFFFFFFFF, 1.0); + } + } + dc.Flush(); + + dc.Begin(); + + char buffer[4096]; + for (int i = 0; i < MAX_TOUCH_POINTS; i++) { + if (touches_[i].id != -1) { + dc.Draw()->Circle(touches_[i].x, touches_[i].y, 100.0, 3.0, 80, 0.0f, 0xFFFFFFFF, 1.0); + snprintf(buffer, sizeof(buffer), "%0.1fx%0.1f", touches_[i].x, touches_[i].y); + dc.DrawText(buffer, touches_[i].x, touches_[i].y + (touches_[i].y > g_display.dp_yres - 100.0f ? -135.0f : 95.0f), 0xFFFFFFFF, ALIGN_HCENTER | FLAG_DYNAMIC_ASCII); + } + } + + char extra_debug[2048]{}; + +#if PPSSPP_PLATFORM(ANDROID) + truncate_cpy(extra_debug, Android_GetInputDeviceDebugString().c_str()); +#endif + + snprintf(buffer, sizeof(buffer), +#if PPSSPP_PLATFORM(ANDROID) + "display_res: %dx%d\n" +#endif + "dp_res: %dx%d pixel_res: %dx%d\n" + "g_dpi: %0.3f g_dpi_scale: %0.3fx%0.3f\n" + "g_dpi_scale_real: %0.3fx%0.3f\n" + "delta: %0.2f ms fps: %0.3f\n%s", +#if PPSSPP_PLATFORM(ANDROID) + System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES), +#endif + g_display.dp_xres, g_display.dp_yres, g_display.pixel_xres, g_display.pixel_yres, + g_display.dpi, g_display.dpi_scale_x, g_display.dpi_scale_y, + g_display.dpi_scale_real_x, g_display.dpi_scale_real_y, + delta * 1000.0, 1.0 / delta, + extra_debug); + + // On Android, also add joystick debug data. + + dc.DrawTextShadow(buffer, bounds.centerX(), bounds.y + 20.0f, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII); + dc.Flush(); +} + +void RecreateActivity() { + const int SYSTEM_JELLYBEAN = 16; + if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= SYSTEM_JELLYBEAN) { + INFO_LOG(SYSTEM, "Sending recreate"); + System_Notify(SystemNotification::FORCE_RECREATE_ACTIVITY); + INFO_LOG(SYSTEM, "Got back from recreate"); + } else { + auto gr = GetI18NCategory(I18NCat::GRAPHICS); + System_Toast(gr->T("Must Restart", "You must restart PPSSPP for this change to take effect")); + } +} + +UI::EventReturn TouchTestScreen::OnImmersiveModeChange(UI::EventParams &e) { + System_Notify(SystemNotification::IMMERSIVE_MODE_CHANGE); + if (g_Config.iAndroidHwScale != 0) { + RecreateActivity(); + } + return UI::EVENT_DONE; +} + +UI::EventReturn TouchTestScreen::OnRenderingBackend(UI::EventParams &e) { + g_Config.Save("GameSettingsScreen::RenderingBackend"); + System_RestartApp("--touchscreentest"); + return UI::EVENT_DONE; +} + +UI::EventReturn TouchTestScreen::OnRecreateActivity(UI::EventParams &e) { + RecreateActivity(); + return UI::EVENT_DONE; +} diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 3572061c9f24..551cc719016d 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -222,6 +222,47 @@ class FrameDumpTestScreen : public UIDialogScreenWithBackground { std::shared_ptr dumpDownload_; }; +class TouchTestScreen : public UIDialogScreenWithGameBackground { +public: + TouchTestScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { + for (int i = 0; i < MAX_TOUCH_POINTS; i++) { + touches_[i].id = -1; + } + } + + void touch(const TouchInput &touch) override; + void DrawForeground(UIContext &dc) override; + + bool key(const KeyInput &key) override; + void axis(const AxisInput &axis) override; + + const char *tag() const override { return "TouchTest"; } + +protected: + struct TrackedTouch { + int id; + float x; + float y; + }; + enum { + MAX_TOUCH_POINTS = 10, + }; + TrackedTouch touches_[MAX_TOUCH_POINTS]{}; + + std::vector keyEventLog_; + + UI::TextView *lastKeyEvents_ = nullptr; + + double lastFrameTime_ = 0.0; + + void CreateViews() override; + void UpdateLogView(); + + UI::EventReturn OnImmersiveModeChange(UI::EventParams &e); + UI::EventReturn OnRenderingBackend(UI::EventParams &e); + UI::EventReturn OnRecreateActivity(UI::EventParams &e); +}; + void DrawProfile(UIContext &ui); const char *GetCompilerABI(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 0e069c1c7337..4994dfce22aa 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -114,6 +114,7 @@ #include "UI/AudioCommon.h" #include "UI/BackgroundAudio.h" #include "UI/ControlMappingScreen.h" +#include "UI/DevScreens.h" #include "UI/DiscordIntegration.h" #include "UI/EmuScreen.h" #include "UI/GameInfoCache.h" From 7b0ee5440d5254bbfaf34f0fda17e988ba46ba75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 14 Dec 2023 19:00:01 +0100 Subject: [PATCH 4/6] Move the mouse event processing code out from NativeApp --- Core/TiltEventProcessor.cpp | 45 +++++++++++++++++++++++++++++++++++++ Core/TiltEventProcessor.h | 7 ++++++ UI/NativeApp.cpp | 28 +++-------------------- 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/Core/TiltEventProcessor.cpp b/Core/TiltEventProcessor.cpp index 1ec92f741c15..703d64184e5d 100644 --- a/Core/TiltEventProcessor.cpp +++ b/Core/TiltEventProcessor.cpp @@ -2,11 +2,13 @@ #include #include +#include #include "Common/Math/math_util.h" #include "Common/Math/lin/vec3.h" #include "Common/Math/lin/matrix4x4.h" #include "Common/Log.h" +#include "Common/System/Display.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -301,3 +303,46 @@ void ResetTiltEvents() { } } // namespace TiltEventProcessor + +namespace MouseEventProcessor { + +// Technically, we may be OK without a mutex here. +// But, the cost isn't high. +std::mutex g_mouseMutex; + +float g_mouseDeltaX = 0; +float g_mouseDeltaY = 0; + +void ProcessDelta(float dx, float dy) { + std::unique_lock lock(g_mouseMutex); + // Accumulate mouse deltas, for some kind of smoothing. + g_mouseDeltaX += dx; + g_mouseDeltaY += dy; +} + +void MouseDeltaToAxes(double now, float *mx, float *my) { + std::unique_lock lock(g_mouseMutex); + + static double lastTime = 0.0f; + if (lastTime == 0.0) { + lastTime = now; + *mx = 0.0f; + *my = 0.0f; + return; + } + double dt = now - lastTime; + lastTime = now; + + float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity; + float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity; + + *mx = clamp_value(g_mouseDeltaX * scaleFactor_x, -1.0f, 1.0f); + *my = clamp_value(g_mouseDeltaY * scaleFactor_y, -1.0f, 1.0f); + + // Decay the mouse deltas. This is where we should use dt. + float decay = expf(-dt * 50.0f * (1.0f - g_Config.fMouseSmoothing)); + g_mouseDeltaX *= decay; + g_mouseDeltaY *= decay; +} + +} // namespace diff --git a/Core/TiltEventProcessor.h b/Core/TiltEventProcessor.h index d16f0020d6f4..793a5b127217 100644 --- a/Core/TiltEventProcessor.h +++ b/Core/TiltEventProcessor.h @@ -16,3 +16,10 @@ extern float rawTiltAnalogX; extern float rawTiltAnalogY; } // namespace + +namespace MouseEventProcessor { + +void ProcessDelta(float dx, float dy); +void MouseDeltaToAxes(double now, float *mx, float *my); + +} // namespace diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 4994dfce22aa..a087c10f1370 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1324,40 +1324,18 @@ void NativeAxis(const AxisInput *axes, size_t count) { } } -float g_mouseDeltaX = 0; -float g_mouseDeltaY = 0; - void NativeMouseDelta(float dx, float dy) { // Remap, shared code. Then send it as a regular axis event. if (!g_Config.bMouseControl) return; - // Accumulate mouse deltas, for some kind of smoothing. - g_mouseDeltaX += dx; - g_mouseDeltaY += dy; + MouseEventProcessor::ProcessDelta(dx, dy); } // Called from NativeFrame. static void SendMouseDeltaAxis() { - static double lastTime = 0.0f; - double now = time_now_d(); - if (lastTime == 0.0) { - lastTime = now; - return; - } - double dt = now - lastTime; - lastTime = now; - - float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity; - float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity; - - float mx = clamp_value(g_mouseDeltaX * scaleFactor_x, -1.0f, 1.0f); - float my = clamp_value(g_mouseDeltaY * scaleFactor_y, -1.0f, 1.0f); - - // Decay the mouse deltas. This is where we should use dt. - float decay = expf(-dt * 50.0f * (1.0f - g_Config.fMouseSmoothing)); - g_mouseDeltaX *= decay; - g_mouseDeltaY *= decay; + float mx, my; + MouseEventProcessor::MouseDeltaToAxes(time_now_d(), &mx, &my); AxisInput axis[2]; axis[0].axisId = JOYSTICK_AXIS_MOUSE_REL_X; From d397635e49445508b5a100efd73b3cfd6f60e065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 14 Dec 2023 19:24:39 +0100 Subject: [PATCH 5/6] Mouse input: Approximate the old smoothing function --- Core/TiltEventProcessor.cpp | 88 +++++++++++++++++++++++++------------ Core/TiltEventProcessor.h | 2 +- UI/NativeApp.cpp | 2 +- Windows/WindowsHost.cpp | 2 +- 4 files changed, 62 insertions(+), 32 deletions(-) diff --git a/Core/TiltEventProcessor.cpp b/Core/TiltEventProcessor.cpp index 703d64184e5d..5e352a599671 100644 --- a/Core/TiltEventProcessor.cpp +++ b/Core/TiltEventProcessor.cpp @@ -34,6 +34,8 @@ void GenerateDPadEvent(int digitalX, int digitalY); void GenerateActionButtonEvent(int digitalX, int digitalY); void GenerateTriggerButtonEvent(int digitalX, int digitalY); +} + // deadzone is normalized - 0 to 1 // sensitivity controls how fast the deadzone reaches max value inline float ApplyDeadzoneAxis(float x, float deadzone) { @@ -51,32 +53,35 @@ inline float ApplyDeadzoneAxis(float x, float deadzone) { } } -inline void ApplyDeadzoneXY(float tiltX, float tiltY, float *adjustedTiltX, float *adjustedTiltY, float deadzone, bool circular) { + +inline void ApplyDeadzoneXY(float x, float y, float *adjustedX, float *adjustedY, float deadzone, bool circular) { if (circular) { - if (tiltX == 0.0f && tiltY == 0.0f) { - *adjustedTiltX = 0.0f; - *adjustedTiltY = 0.0f; + if (x == 0.0f && y == 0.0f) { + *adjustedX = 0.0f; + *adjustedY = 0.0f; return; } - float magnitude = sqrtf(tiltX * tiltX + tiltY * tiltY); + float magnitude = sqrtf(x * x + y * y); if (magnitude <= deadzone + 0.00001f) { - *adjustedTiltX = 0.0f; - *adjustedTiltY = 0.0f; + *adjustedX = 0.0f; + *adjustedY = 0.0f; return; } float factor = 1.0f / (1.0f - deadzone); float newMagnitude = (magnitude - deadzone) * factor; - *adjustedTiltX = (tiltX / magnitude) * newMagnitude; - *adjustedTiltY = (tiltY / magnitude) * newMagnitude; + *adjustedX = (x / magnitude) * newMagnitude; + *adjustedY = (y / magnitude) * newMagnitude; } else { - *adjustedTiltX = ApplyDeadzoneAxis(tiltX, deadzone); - *adjustedTiltY = ApplyDeadzoneAxis(tiltY, deadzone); + *adjustedX = ApplyDeadzoneAxis(x, deadzone); + *adjustedY = ApplyDeadzoneAxis(y, deadzone); } } +namespace TiltEventProcessor { + // Also clamps to -1.0..1.0. // This applies a (circular if desired) inverse deadzone. inline void ApplyInverseDeadzone(float x, float y, float *outX, float *outY, float inverseDeadzone, bool circular) { @@ -310,39 +315,64 @@ namespace MouseEventProcessor { // But, the cost isn't high. std::mutex g_mouseMutex; -float g_mouseDeltaX = 0; -float g_mouseDeltaY = 0; +float g_mouseDeltaXAccum = 0; +float g_mouseDeltaYAccum = 0; -void ProcessDelta(float dx, float dy) { - std::unique_lock lock(g_mouseMutex); - // Accumulate mouse deltas, for some kind of smoothing. - g_mouseDeltaX += dx; - g_mouseDeltaY += dy; -} +float g_mouseDeltaX; +float g_mouseDeltaY; -void MouseDeltaToAxes(double now, float *mx, float *my) { - std::unique_lock lock(g_mouseMutex); +void DecayMouse(double now) { + g_mouseDeltaX = g_mouseDeltaXAccum; + g_mouseDeltaY = g_mouseDeltaYAccum; + + const float decay = g_Config.fMouseSmoothing; static double lastTime = 0.0f; if (lastTime == 0.0) { lastTime = now; - *mx = 0.0f; - *my = 0.0f; return; } double dt = now - lastTime; lastTime = now; + // Decay the mouse deltas. We do an approximation of the old polling. + // Should be able to use a smooth exponential here, when I get around to doing + // the math. + static double accumDt = 0.0; + accumDt += dt; + const double oldPollInterval = 1.0 / 250.0; // See Windows "PollControllers". + while (accumDt > oldPollInterval) { + accumDt -= oldPollInterval; + g_mouseDeltaXAccum *= decay; + g_mouseDeltaYAccum *= decay; + } +} + +void ProcessDelta(double now, float dx, float dy) { + std::unique_lock lock(g_mouseMutex); + + // Accumulate mouse deltas, for some kind of smoothing. + g_mouseDeltaXAccum += dx; + g_mouseDeltaYAccum += dy; + + DecayMouse(now); +} + +void MouseDeltaToAxes(double now, float *mx, float *my) { + std::unique_lock lock(g_mouseMutex); + float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity; float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity; - *mx = clamp_value(g_mouseDeltaX * scaleFactor_x, -1.0f, 1.0f); - *my = clamp_value(g_mouseDeltaY * scaleFactor_y, -1.0f, 1.0f); + DecayMouse(now); + + // TODO: Make configurable. + float mouseDeadZone = 0.1f; + + float outX = clamp_value(g_mouseDeltaX * scaleFactor_x, -1.0f, 1.0f); + float outY = clamp_value(g_mouseDeltaY * scaleFactor_y, -1.0f, 1.0f); - // Decay the mouse deltas. This is where we should use dt. - float decay = expf(-dt * 50.0f * (1.0f - g_Config.fMouseSmoothing)); - g_mouseDeltaX *= decay; - g_mouseDeltaY *= decay; + ApplyDeadzoneXY(outX, outY, mx, my, mouseDeadZone, true); } } // namespace diff --git a/Core/TiltEventProcessor.h b/Core/TiltEventProcessor.h index 793a5b127217..3fb0ef7671ce 100644 --- a/Core/TiltEventProcessor.h +++ b/Core/TiltEventProcessor.h @@ -19,7 +19,7 @@ extern float rawTiltAnalogY; namespace MouseEventProcessor { -void ProcessDelta(float dx, float dy); +void ProcessDelta(double now, float dx, float dy); void MouseDeltaToAxes(double now, float *mx, float *my); } // namespace diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index a087c10f1370..eac395444e5a 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1329,7 +1329,7 @@ void NativeMouseDelta(float dx, float dy) { if (!g_Config.bMouseControl) return; - MouseEventProcessor::ProcessDelta(dx, dy); + MouseEventProcessor::ProcessDelta(time_now_d(), dx, dy); } // Called from NativeFrame. diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 8a693f3c5979..2e3e8809e7ea 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -77,7 +77,7 @@ void WindowsInputManager::Init() { } void WindowsInputManager::PollControllers() { - static const int CHECK_FREQUENCY = 71; + static const int CHECK_FREQUENCY = 71; // Just an arbitrary prime to try to not collide with other periodic checks. if (checkCounter_++ > CHECK_FREQUENCY) { #ifndef _M_ARM size_t newCount = DinputDevice::getNumPads(); From ce6b05174a068c37c4d770bd1ab0c7371fd5088a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 14 Dec 2023 19:30:03 +0100 Subject: [PATCH 6/6] Also call SendMouseDeltaAxis directly from NativeMouseDelta for lower latency. --- UI/NativeApp.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index eac395444e5a..3f22acd0af9b 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1324,15 +1324,7 @@ void NativeAxis(const AxisInput *axes, size_t count) { } } -void NativeMouseDelta(float dx, float dy) { - // Remap, shared code. Then send it as a regular axis event. - if (!g_Config.bMouseControl) - return; - - MouseEventProcessor::ProcessDelta(time_now_d(), dx, dy); -} - -// Called from NativeFrame. +// Called from NativeFrame and from NativeMouseDelta. static void SendMouseDeltaAxis() { float mx, my; MouseEventProcessor::MouseDeltaToAxes(time_now_d(), &mx, &my); @@ -1356,6 +1348,16 @@ static void SendMouseDeltaAxis() { } } +void NativeMouseDelta(float dx, float dy) { + // Remap, shared code. Then send it as a regular axis event. + if (!g_Config.bMouseControl) + return; + + MouseEventProcessor::ProcessDelta(time_now_d(), dx, dy); + + SendMouseDeltaAxis(); +} + void NativeAccelerometer(float tiltX, float tiltY, float tiltZ) { if (g_Config.iTiltInputType == TILT_NULL) { // if tilt events are disabled, don't do anything special.