diff --git a/app/streaming/input/input.cpp b/app/streaming/input/input.cpp index c837c167..0679f9bb 100644 --- a/app/streaming/input/input.cpp +++ b/app/streaming/input/input.cpp @@ -13,6 +13,7 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s : m_MultiController(prefs.multiController), m_GamepadMouse(prefs.gamepadMouse), m_MouseMoveTimer(0), + m_MousePositionLock(0), m_FakeCaptureActive(false), m_LongPressTimer(0), m_StreamWidth(streamWidth), @@ -108,9 +109,11 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s SDL_zero(m_LastTouchDownEvent); SDL_zero(m_LastTouchUpEvent); SDL_zero(m_TouchDownEvent); + SDL_zero(m_MousePositionReport); SDL_AtomicSet(&m_MouseDeltaX, 0); SDL_AtomicSet(&m_MouseDeltaY, 0); + SDL_AtomicSet(&m_MousePositionUpdated, 0); Uint32 pollingInterval = QString(qgetenv("MOUSE_POLLING_INTERVAL")).toUInt(); if (pollingInterval == 0) { diff --git a/app/streaming/input/input.h b/app/streaming/input/input.h index 5078515f..f3d4432b 100644 --- a/app/streaming/input/input.h +++ b/app/streaming/input/input.h @@ -114,6 +114,14 @@ private: SDL_TimerID m_MouseMoveTimer; SDL_atomic_t m_MouseDeltaX; SDL_atomic_t m_MouseDeltaY; + + SDL_SpinLock m_MousePositionLock; + struct { + int x, y; + int windowWidth, windowHeight; + } m_MousePositionReport; + SDL_atomic_t m_MousePositionUpdated; + int m_GamepadMask; GamepadState m_GamepadState[MAX_GAMEPADS]; QSet m_KeysDown; diff --git a/app/streaming/input/mouse.cpp b/app/streaming/input/mouse.cpp index 98502287..3649ed3c 100644 --- a/app/streaming/input/mouse.cpp +++ b/app/streaming/input/mouse.cpp @@ -67,29 +67,23 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event) return; } + // Batch until the next mouse polling window or we'll get awful + // input lag everything except GFE 3.14 and 3.15. if (m_AbsoluteMouseMode) { - SDL_Rect src, dst; + int windowWidth, windowHeight; - src.x = src.y = 0; - src.w = m_StreamWidth; - src.h = m_StreamHeight; + // Call SDL_GetWindowSize() before entering the spinlock + SDL_GetWindowSize(m_Window, &windowWidth, &windowHeight); - dst.x = dst.y = 0; - SDL_GetWindowSize(m_Window, &dst.w, &dst.h); - - // Use the stream and window sizes to determine the video region - StreamUtils::scaleSourceToDestinationSurface(&src, &dst); - - // Clamp motion to the video region - short x = qMin(qMax(event->x - dst.x, 0), dst.w); - short y = qMin(qMax(event->y - dst.y, 0), dst.h); - - // Send the mouse position update - LiSendMousePositionEvent(x, y, dst.w, dst.h); + SDL_AtomicLock(&m_MousePositionLock); + m_MousePositionReport.x = event->x; + m_MousePositionReport.y = event->y; + m_MousePositionReport.windowWidth = windowWidth; + m_MousePositionReport.windowHeight = windowHeight; + SDL_AtomicUnlock(&m_MousePositionLock); + SDL_AtomicSet(&m_MousePositionUpdated, 1); } else { - // Batch until the next mouse polling window or we'll get awful - // input lag everything except GFE 3.14 and 3.15. SDL_AtomicAdd(&m_MouseDeltaX, event->xrel); SDL_AtomicAdd(&m_MouseDeltaY, event->yrel); } @@ -122,6 +116,36 @@ Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param) LiSendMouseMoveEvent(deltaX, deltaY); } + bool hasNewPosition = SDL_AtomicSet(&me->m_MousePositionUpdated, 0) != 0; + if (hasNewPosition) { + // If the lock is held now, the main thread is trying to update + // the mouse position. We'll pick up the new position next time. + if (SDL_AtomicTryLock(&me->m_MousePositionLock)) { + SDL_Rect src, dst; + + src.x = src.y = 0; + src.w = me->m_StreamWidth; + src.h = me->m_StreamHeight; + + dst.x = dst.y = 0; + dst.w = me->m_MousePositionReport.windowWidth; + dst.h = me->m_MousePositionReport.windowHeight; + + // Use the stream and window sizes to determine the video region + StreamUtils::scaleSourceToDestinationSurface(&src, &dst); + + // Clamp motion to the video region + short x = qMin(qMax(me->m_MousePositionReport.x - dst.x, 0), dst.w); + short y = qMin(qMax(me->m_MousePositionReport.y - dst.y, 0), dst.h); + + // Release the spinlock to unblock the main thread + SDL_AtomicUnlock(&me->m_MousePositionLock); + + // Send the mouse position update + LiSendMousePositionEvent(x, y, dst.w, dst.h); + } + } + #ifdef Q_OS_WIN32 // See comment in SdlInputHandler::notifyMouseLeave() if (me->m_AbsoluteMouseMode && me->m_PendingMouseLeaveButtonUp != 0 && me->isCaptureActive()) {