Fix large mouse input delay on GFE 3.14.0 and earlier. Fixes #68

This commit is contained in:
Cameron Gutman 2018-09-14 18:35:28 -07:00
parent 7ca2ca8045
commit 25d97e187a
4 changed files with 33 additions and 8 deletions

View file

@ -29,9 +29,15 @@ NvHTTP::NvHTTP(QString address) :
QVector<int>
NvHTTP::parseQuad(QString quad)
{
QStringList parts = quad.split(".");
QVector<int> ret;
// Return an empty vector for old GFE versions
// that were missing GfeVersion.
if (quad.isEmpty()) {
return ret;
}
QStringList parts = quad.split(".");
for (int i = 0; i < 4; i++)
{
ret.append(parts.at(i).toInt());

View file

@ -24,9 +24,10 @@ const int SdlInputHandler::k_ButtonMap[] = {
UP_FLAG, DOWN_FLAG, LEFT_FLAG, RIGHT_FLAG
};
SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs)
SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer* computer)
: m_LastMouseMotionTime(0),
m_MultiController(prefs.multiController)
m_MultiController(prefs.multiController),
m_NeedsInputDelay(false)
{
// Allow gamepad input when the app doesn't have focus
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
@ -81,6 +82,19 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs)
m_GamepadMask = 0;
}
// Prior to GFE 3.14.1, sending too many mouse motion events can cause
// GFE to choke and input latency to increase significantly. We will
// artificially throttle them to avoid this situation.
QVector<int> gfeVersion = NvHTTP::parseQuad(computer->gfeVersion);
if (gfeVersion.isEmpty() || // Very old versions don't have GfeVersion at all
gfeVersion[0] < 3 ||
(gfeVersion[0] == 3 && gfeVersion[1] < 14) ||
(gfeVersion[0] == 3 && gfeVersion[1] == 14 && gfeVersion[2] < 1)) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"This older version of GFE requires input delay hack");
m_NeedsInputDelay = true;
}
SDL_zero(m_GamepadState);
}
@ -430,9 +444,11 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
short ydelta = (short)event->yrel;
// If we're sending more than one motion event per millisecond,
// delay for 1 ms to allow batching of mouse move events.
// delay for 1 ms to allow batching of mouse move events. On older
// versions of GFE, we will unconditionally wait this 1 ms to
// work around an input processing issue that causes massive mouse latency.
Uint32 currentTime = SDL_GetTicks();
if (!SDL_TICKS_PASSED(currentTime, m_LastMouseMotionTime + 1)) {
if (m_NeedsInputDelay || !SDL_TICKS_PASSED(currentTime, m_LastMouseMotionTime + 1)) {
SDL_Delay(1);
currentTime = SDL_GetTicks();
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "settings/streamingpreferences.h"
#include "backend/computermanager.h"
#include <SDL.h>
@ -20,7 +21,7 @@ struct GamepadState {
class SdlInputHandler
{
public:
explicit SdlInputHandler(StreamingPreferences& prefs);
explicit SdlInputHandler(StreamingPreferences& prefs, NvComputer* computer);
~SdlInputHandler();
@ -48,6 +49,7 @@ private:
Uint32 m_LastMouseMotionTime;
bool m_MultiController;
bool m_NeedsInputDelay;
int m_GamepadMask;
GamepadState m_GamepadState[MAX_GAMEPADS];

View file

@ -287,7 +287,8 @@ Session::Session(NvComputer* computer, NvApp& app)
void Session::initialize()
{
qDebug() << "Server GPU:" << m_Computer->gpuModel;
qInfo() << "Server GPU:" << m_Computer->gpuModel;
qInfo() << "Server GFE version:" << m_Computer->gfeVersion;
LiInitializeVideoCallbacks(&m_VideoCallbacks);
m_VideoCallbacks.setup = drSetup;
@ -731,7 +732,7 @@ void Session::exec(int displayOriginX, int displayOriginY)
// Initialize the gamepad code with our preferences
StreamingPreferences prefs;
SdlInputHandler inputHandler(prefs);
SdlInputHandler inputHandler(prefs, m_Computer);
// The UI should have ensured the old game was already quit
// if we decide to stream a different game.