From 4ec6ff7ebcd99118fd5d62ddde6ffbdb8e264a2e Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 18 Jan 2026 15:12:31 +1000 Subject: [PATCH] InputManager: Remove second source of truth for window size --- src/core/gpu_thread.cpp | 3 -- src/duckstation-mini/mini_host.cpp | 4 +- src/duckstation-qt/qthost.cpp | 8 ++-- src/util/imgui_manager.cpp | 9 +++- src/util/input_manager.cpp | 70 +++++++++++------------------ src/util/input_manager.h | 7 +-- src/util/sdl_input_source.cpp | 12 ++--- src/util/win32_raw_input_source.cpp | 8 ++-- 8 files changed, 53 insertions(+), 68 deletions(-) diff --git a/src/core/gpu_thread.cpp b/src/core/gpu_thread.cpp index d250f61c5..0d1292de0 100644 --- a/src/core/gpu_thread.cpp +++ b/src/core/gpu_thread.cpp @@ -718,8 +718,6 @@ bool GPUThread::CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool preser if (s_state.requested_fullscreen_ui) FullscreenUI::Initialize(preserve_fsui_state); - InputManager::SetDisplayWindowSize(ImGuiManager::GetWindowWidth(), ImGuiManager::GetWindowHeight()); - if (const GPUSwapChain* swap_chain = g_gpu_device->GetMainSwapChain()) s_state.render_window_info = swap_chain->GetWindowInfo(); else @@ -1416,7 +1414,6 @@ void GPUThread::DisplayWindowResizedOnThread() const float f_width = static_cast(std::max(swap_chain->GetWidth(), 1u)); const float f_height = static_cast(std::max(swap_chain->GetHeight(), 1u)); ImGuiManager::WindowResized(swap_chain->GetFormat(), f_width, f_height); - InputManager::SetDisplayWindowSize(f_width, f_height); // If we're paused, re-present the current frame at the new window size. if (s_state.gpu_backend && IsSystemPaused()) diff --git a/src/duckstation-mini/mini_host.cpp b/src/duckstation-mini/mini_host.cpp index a376919b9..c68ba6183 100644 --- a/src/duckstation-mini/mini_host.cpp +++ b/src/duckstation-mini/mini_host.cpp @@ -858,9 +858,9 @@ void MiniHost::ProcessSDLEvent(const SDL_Event* ev) { Host::RunOnCoreThread([x = ev->wheel.x, y = ev->wheel.y]() { if (x != 0.0f) - InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::WheelX, x); + InputManager::UpdatePointerWheelRelativeDelta(0, InputPointerAxis::WheelX, x); if (y != 0.0f) - InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::WheelY, y); + InputManager::UpdatePointerWheelRelativeDelta(0, InputPointerAxis::WheelY, y); }); } break; diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index f23404dfd..3c27f6631 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -952,9 +952,9 @@ void CoreThread::onDisplayWindowMouseMoveAbsoluteEvent(float x, float y) void CoreThread::onDisplayWindowMouseMoveRelativeEvent(float dx, float dy) { if (dx != 0.0f) - InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::X, dx); + InputManager::UpdatePointerPositionRelativeDelta(0, InputPointerAxis::X, dx); if (dy != 0.0f) - InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::Y, dy); + InputManager::UpdatePointerPositionRelativeDelta(0, InputPointerAxis::Y, dy); } void CoreThread::onDisplayWindowMouseButtonEvent(int button, bool pressed) @@ -970,10 +970,10 @@ void CoreThread::onDisplayWindowMouseWheelEvent(float dx, float dy) DebugAssert(isCurrentThread()); if (dx != 0.0f) - InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::WheelX, dx); + InputManager::UpdatePointerWheelRelativeDelta(0, InputPointerAxis::WheelX, dx); if (dy != 0.0f) - InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::WheelY, dy); + InputManager::UpdatePointerWheelRelativeDelta(0, InputPointerAxis::WheelY, dy); } void CoreThread::onDisplayWindowResized(int width, int height, float scale, float refresh_rate) diff --git a/src/util/imgui_manager.cpp b/src/util/imgui_manager.cpp index 31f18bbc0..704f647e4 100644 --- a/src/util/imgui_manager.cpp +++ b/src/util/imgui_manager.cpp @@ -1306,8 +1306,13 @@ void ImGuiManager::UpdateMousePosition(float x, float y) if (!s_state.imgui_context) return; - s_state.imgui_context->IO.MousePos = ImVec2(x, y); - std::atomic_thread_fence(std::memory_order_release); + GPUThread::RunOnThread([x, y]() { + if (!s_state.imgui_context) [[unlikely]] + return; + + s_state.imgui_context->IO.MousePos.x = x; + s_state.imgui_context->IO.MousePos.y = y; + }); } void ImGuiManager::SetCommonIOOptions(ImGuiIO& io, ImGuiPlatformIO& pio) diff --git a/src/util/input_manager.cpp b/src/util/input_manager.cpp index 1ebe0adb1..23d9042c3 100644 --- a/src/util/input_manager.cpp +++ b/src/util/input_manager.cpp @@ -122,7 +122,7 @@ struct MacroButton struct PointerAxisState { - std::atomic delta; + float delta; float last_value; }; @@ -250,9 +250,6 @@ struct ALIGN_TO_CACHE_LINE State pointer_state; u32 pointer_count = 0; std::array(InputPointerAxis::Count)> pointer_axis_scale; - - // Window size, used for clamping the mouse position in raw input modes. - std::array window_size = {}; }; } // namespace @@ -1446,9 +1443,7 @@ void InputManager::GenerateRelativeMouseEvents() for (u32 axis = 0; axis < static_cast(static_cast(InputPointerAxis::Count)); axis++) { PointerAxisState& state = s_state.pointer_state[device][axis]; - const int deltai = state.delta.load(std::memory_order_acquire); - state.delta.fetch_sub(deltai, std::memory_order_release); - const float delta = static_cast(deltai) / 65536.0f; + const float delta = static_cast(std::exchange(state.delta, 0.0f)); const float unclamped_value = delta * s_state.pointer_axis_scale[axis]; const float value = std::clamp(unclamped_value, -1.0f, 1.0f); @@ -1521,16 +1516,8 @@ void InputManager::UpdatePointerAbsolutePosition(u32 index, float x, float y, bo const float dx = x - std::exchange(s_state.host_pointer_positions[index][static_cast(InputPointerAxis::X)], x); const float dy = y - std::exchange(s_state.host_pointer_positions[index][static_cast(InputPointerAxis::Y)], y); - if (dx != 0.0f) - { - s_state.pointer_state[index][static_cast(InputPointerAxis::X)].delta.fetch_add(static_cast(dx * 65536.0f), - std::memory_order_acq_rel); - } - if (dy != 0.0f) - { - s_state.pointer_state[index][static_cast(InputPointerAxis::Y)].delta.fetch_add(static_cast(dy * 65536.0f), - std::memory_order_acq_rel); - } + s_state.pointer_state[index][static_cast(InputPointerAxis::X)].delta += dx; + s_state.pointer_state[index][static_cast(InputPointerAxis::Y)].delta += dy; if (index == 0) ImGuiManager::UpdateMousePosition(x, y); @@ -1541,29 +1528,37 @@ void InputManager::ResetPointerRelativeDelta(u32 index) if (index >= MAX_POINTER_DEVICES || s_state.relative_mouse_mode_active) [[unlikely]] return; - s_state.pointer_state[index][static_cast(InputPointerAxis::X)].delta.store(0, std::memory_order_release); - s_state.pointer_state[index][static_cast(InputPointerAxis::Y)].delta.store(0, std::memory_order_release); + s_state.pointer_state[index][static_cast(InputPointerAxis::X)].delta = 0.0f; + s_state.pointer_state[index][static_cast(InputPointerAxis::Y)].delta = 0.0f; } -void InputManager::UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, float d, bool raw_input) +void InputManager::UpdatePointerPositionRelativeDelta(u32 index, InputPointerAxis axis, float d) { - if (index >= MAX_POINTER_DEVICES || (axis < InputPointerAxis::WheelX && !s_state.relative_mouse_mode_active)) + DebugAssert(axis <= InputPointerAxis::Y); + if (index >= MAX_POINTER_DEVICES || !s_state.relative_mouse_mode_active) return; - s_state.host_pointer_positions[index][static_cast(axis)] += d; - s_state.pointer_state[index][static_cast(axis)].delta.fetch_add(static_cast(d * 65536.0f), - std::memory_order_acq_rel); + s_state.pointer_state[index][static_cast(axis)].delta += d; // We need to clamp the position ourselves in relative mode. - if (axis <= InputPointerAxis::Y) - { - s_state.host_pointer_positions[index][static_cast(axis)] = std::clamp( - s_state.host_pointer_positions[index][static_cast(axis)], 0.0f, s_state.window_size[static_cast(axis)]); + const WindowInfo& wi = GPUThread::GetRenderWindowInfo(); + const float max_dim = static_cast((axis == InputPointerAxis::X) ? wi.surface_width : wi.surface_height); + s_state.host_pointer_positions[index][static_cast(axis)] = + std::clamp(s_state.host_pointer_positions[index][static_cast(axis)] + d, 0.0f, max_dim); - // Imgui also needs to be updated, since the absolute position won't be set above. - if (index == 0) - ImGuiManager::UpdateMousePosition(s_state.host_pointer_positions[0][0], s_state.host_pointer_positions[0][1]); - } + // Imgui also needs to be updated, since the absolute position won't be set above. + if (index == 0) + ImGuiManager::UpdateMousePosition(s_state.host_pointer_positions[0][0], s_state.host_pointer_positions[0][1]); +} + +void InputManager::UpdatePointerWheelRelativeDelta(u32 index, InputPointerAxis axis, float d) +{ + DebugAssert(axis >= InputPointerAxis::WheelX && axis <= InputPointerAxis::WheelY); + if (index >= MAX_POINTER_DEVICES) + return; + + s_state.host_pointer_positions[index][static_cast(axis)] += d; + s_state.pointer_state[index][static_cast(axis)].delta += d; } void InputManager::UpdateRelativeMouseMode() @@ -1628,17 +1623,6 @@ bool InputManager::IsUsingRawInput() #endif } -void InputManager::SetDisplayWindowSize(float width, float height) -{ - s_state.window_size[0] = width; - s_state.window_size[1] = height; -} - -std::pair InputManager::GetDisplayWindowSize() -{ - return std::make_pair(s_state.window_size[0], s_state.window_size[1]); -} - void InputManager::OnApplicationBackgroundStateChanged(bool in_background) { s_state.application_in_background = in_background; diff --git a/src/util/input_manager.h b/src/util/input_manager.h index 092d3b24f..821c2fdc4 100644 --- a/src/util/input_manager.h +++ b/src/util/input_manager.h @@ -353,7 +353,8 @@ void ResetPointerRelativeDelta(u32 index); /// Updates relative pointer position. Can call from the UI thread, use when host supports relative coordinate /// reporting. -void UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, float d, bool raw_input = false); +void UpdatePointerPositionRelativeDelta(u32 index, InputPointerAxis axis, float d); +void UpdatePointerWheelRelativeDelta(u32 index, InputPointerAxis axis, float d); /// Updates host mouse mode (relative/cursor hiding). void UpdateRelativeMouseMode(); @@ -366,10 +367,6 @@ void SetMacroButtonState(u32 pad, u32 index, bool state); /// Returns true if the raw input source is being used. bool IsUsingRawInput(); -/// Updates InputManager's view of the window size, used for clamping raw input coordinates. -void SetDisplayWindowSize(float width, float height); -std::pair GetDisplayWindowSize(); - /// Called when the application window gains or loses focus. void OnApplicationBackgroundStateChanged(bool in_background); void UpdateInputIgnoreState(); diff --git a/src/util/sdl_input_source.cpp b/src/util/sdl_input_source.cpp index 8c9241a53..8bba4c620 100644 --- a/src/util/sdl_input_source.cpp +++ b/src/util/sdl_input_source.cpp @@ -5,8 +5,10 @@ #include "input_manager.h" #include "core/settings.h" +#include "core/gpu_thread.h" #include "util/translation.h" +#include "util/window_info.h" #include "common/assert.h" #include "common/bitutils.h" @@ -1195,9 +1197,9 @@ bool SDLInputSource::HandleGamepadTouchpadEvent(const SDL_GamepadTouchpadEvent* it->last_touch_y = ev->y; } - const auto& [win_width, win_height] = InputManager::GetDisplayWindowSize(); - const float rel_x = (ev->x - std::exchange(it->last_touch_x, ev->x)) * win_width; - const float rel_y = (ev->y - std::exchange(it->last_touch_y, ev->y)) * win_height; + const WindowInfo& wi = GPUThread::GetRenderWindowInfo(); + const float rel_x = (ev->x - std::exchange(it->last_touch_x, ev->x)) * static_cast(wi.surface_width); + const float rel_y = (ev->y - std::exchange(it->last_touch_y, ev->y)) * static_cast(wi.surface_height); if (!InputManager::IsRelativeMouseModeActive()) { const auto& [current_x, current_y] = InputManager::GetPointerAbsolutePosition(pointer_index); @@ -1206,9 +1208,9 @@ bool SDLInputSource::HandleGamepadTouchpadEvent(const SDL_GamepadTouchpadEvent* else { if (rel_x != 0.0f) - InputManager::UpdatePointerRelativeDelta(pointer_index, InputPointerAxis::X, rel_x); + InputManager::UpdatePointerPositionRelativeDelta(pointer_index, InputPointerAxis::X, rel_x); if (rel_y != 0.0f) - InputManager::UpdatePointerRelativeDelta(pointer_index, InputPointerAxis::Y, rel_y); + InputManager::UpdatePointerPositionRelativeDelta(pointer_index, InputPointerAxis::Y, rel_y); } } diff --git a/src/util/win32_raw_input_source.cpp b/src/util/win32_raw_input_source.cpp index 1526de331..8f0ce7caa 100644 --- a/src/util/win32_raw_input_source.cpp +++ b/src/util/win32_raw_input_source.cpp @@ -469,14 +469,14 @@ bool Win32RawInputSource::ProcessRawInputEvent(const RAWINPUT* event) // relative is easy if (rm.lLastX != 0) { - InputManager::UpdatePointerRelativeDelta(pointer_index, InputPointerAxis::X, static_cast(rm.lLastX), - true); + InputManager::UpdatePointerPositionRelativeDelta(pointer_index, InputPointerAxis::X, + static_cast(rm.lLastX)); } if (rm.lLastY != 0) { - InputManager::UpdatePointerRelativeDelta(pointer_index, InputPointerAxis::Y, static_cast(rm.lLastY), - true); + InputManager::UpdatePointerPositionRelativeDelta(pointer_index, InputPointerAxis::Y, + static_cast(rm.lLastY)); } }