[client] use SDL_SetEventFilter for better mouse performance

This partially resolves lag issues on hosts running the amdgpu driver.
If mouse caputure is enable the lag issue returns, this is because SDL
calls `XSync` in `X11_WarpMouse` and `X11_WarpMouseGlobal`, if these
calls are removed all input lag issues dissapear.

This issue has been reported to SDL as the calls to `XSync` are not
required per the xlib documentation.
This commit is contained in:
Geoffrey McRae 2018-01-24 23:46:11 +11:00
parent 3d9d275d61
commit 37ea662998

View file

@ -177,7 +177,7 @@ static inline void updatePositionInfo()
state.lgr->on_resize(state.lgrData, w, h, state.dstRect); state.lgr->on_resize(state.lgrData, w, h, state.dstRect);
} }
void mainThread() int renderThread(void * unused)
{ {
while(state.running) while(state.running)
{ {
@ -189,6 +189,8 @@ void mainThread()
else else
usleep(1000); usleep(1000);
} }
return 0;
} }
int cursorThread(void * unused) int cursorThread(void * unused)
@ -418,205 +420,191 @@ static inline const uint32_t mapScancode(SDL_Scancode scancode)
return ps2; return ps2;
} }
int eventThread(void * arg) struct eventState
{ {
bool serverMode = false; bool serverMode;
bool realignGuest = true; bool realignGuest;
bool keyDown[SDL_NUM_SCANCODES]; bool keyDown[SDL_NUM_SCANCODES];
};
memset(keyDown, 0, sizeof(keyDown)); int eventFilter(void * userdata, SDL_Event * event)
{
static bool serverMode = false;
static bool realignGuest = true;
static bool keyDown[SDL_NUM_SCANCODES] = {false};
// ensure mouse acceleration is identical in server mode if (event->type == SDL_WINDOWEVENT)
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1", SDL_HINT_OVERRIDE);
while(state.running)
{ {
SDL_Event event; switch(event->window.event)
if (!SDL_PollEvent(&event))
{ {
usleep(1000); case SDL_WINDOWEVENT_ENTER:
continue; realignGuest = true;
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
updatePositionInfo();
realignGuest = true;
break;
}
return 0;
}
if (!params.useSpice)
return 1;
switch(event->type)
{
case SDL_MOUSEMOTION:
{
if (
!serverMode && (
event->motion.x < state.dstRect.x ||
event->motion.x > state.dstRect.x + state.dstRect.w ||
event->motion.y < state.dstRect.y ||
event->motion.y > state.dstRect.y + state.dstRect.h
)
)
{
realignGuest = true;
break;
}
int x = 0;
int y = 0;
if (realignGuest && state.haveCursorPos)
{
x = event->motion.x - state.dstRect.x;
y = event->motion.y - state.dstRect.y;
if (params.scaleMouseInput)
{
x = (float)x * state.scaleX;
y = (float)y * state.scaleY;
}
x -= state.cursor.x;
y -= state.cursor.y;
realignGuest = false;
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("SDL_MOUSEMOTION: failed to send message");
break;
}
x = event->motion.xrel;
y = event->motion.yrel;
if (x != 0 || y != 0)
{
if (params.scaleMouseInput)
{
x = (float)x * state.scaleX;
y = (float)y * state.scaleY;
}
if (!spice_mouse_motion(x, y))
{
DEBUG_ERROR("SDL_MOUSEMOTION: failed to send message");
break;
}
}
break;
} }
switch(event.type) case SDL_KEYDOWN:
{ {
case SDL_QUIT: SDL_Scancode sc = event->key.keysym.scancode;
if (!params.ignoreQuit) if (sc == SDL_SCANCODE_SCROLLLOCK)
state.running = false; {
if (event->key.repeat)
break;
serverMode = !serverMode;
spice_mouse_mode(serverMode);
SDL_SetRelativeMouseMode(serverMode);
DEBUG_INFO("Server Mode: %s", serverMode ? "on" : "off");
if (!serverMode)
realignGuest = true;
break;
}
uint32_t scancode = mapScancode(sc);
if (scancode == 0)
break;
if (spice_key_down(scancode))
keyDown[sc] = true;
else
{
DEBUG_ERROR("SDL_KEYDOWN: failed to send message");
break;
}
break;
}
case SDL_KEYUP:
{
SDL_Scancode sc = event->key.keysym.scancode;
if (sc == SDL_SCANCODE_SCROLLLOCK)
break;
// avoid sending key up events when we didn't send a down
if (!keyDown[sc])
break;
uint32_t scancode = mapScancode(sc);
if (scancode == 0)
break;
if (spice_key_up(scancode))
keyDown[sc] = false;
else
{
DEBUG_ERROR("SDL_KEYUP: failed to send message");
break;
}
break;
}
case SDL_MOUSEWHEEL:
if (
!spice_mouse_press (event->wheel.y == 1 ? 4 : 5) ||
!spice_mouse_release(event->wheel.y == 1 ? 4 : 5)
)
{
DEBUG_ERROR("SDL_MOUSEWHEEL: failed to send messages");
break;
}
break; break;
case SDL_WINDOWEVENT: case SDL_MOUSEBUTTONDOWN:
// The SPICE protocol doesn't support more than a standard PS/2 3 button mouse
if (event->button.button > 3)
break;
if (
!spice_mouse_position(event->button.x, event->button.y) ||
!spice_mouse_press(event->button.button)
)
{ {
switch(event.window.event) DEBUG_ERROR("SDL_MOUSEBUTTONDOWN: failed to send message");
{
case SDL_WINDOWEVENT_ENTER:
realignGuest = true;
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
updatePositionInfo();
realignGuest = true;
break;
}
break; break;
} }
} break;
if (!params.useSpice) case SDL_MOUSEBUTTONUP:
continue; // The SPICE protocol doesn't support more than a standard PS/2 3 button mouse
if (event->button.button > 3)
switch(event.type) break;
{ if (
case SDL_KEYDOWN: !spice_mouse_position(event->button.x, event->button.y) ||
!spice_mouse_release(event->button.button)
)
{ {
SDL_Scancode sc = event.key.keysym.scancode; DEBUG_ERROR("SDL_MOUSEBUTTONUP: failed to send message");
if (sc == SDL_SCANCODE_SCROLLLOCK)
{
if (event.key.repeat)
break;
serverMode = !serverMode;
spice_mouse_mode(serverMode);
SDL_SetRelativeMouseMode(serverMode);
if (!serverMode)
realignGuest = true;
break;
}
uint32_t scancode = mapScancode(sc);
if (scancode == 0)
break;
if (spice_key_down(scancode))
keyDown[sc] = true;
else
{
DEBUG_ERROR("SDL_KEYDOWN: failed to send message");
break;
}
break; break;
} }
break;
case SDL_KEYUP: default:
{ return 1;
SDL_Scancode sc = event.key.keysym.scancode;
if (sc == SDL_SCANCODE_SCROLLLOCK)
break;
// avoid sending key up events when we didn't send a down
if (!keyDown[sc])
break;
uint32_t scancode = mapScancode(sc);
if (scancode == 0)
break;
if (spice_key_up(scancode))
keyDown[sc] = false;
else
{
DEBUG_ERROR("SDL_KEYUP: failed to send message");
break;
}
break;
}
case SDL_MOUSEWHEEL:
if (
!spice_mouse_press (event.wheel.y == 1 ? 4 : 5) ||
!spice_mouse_release(event.wheel.y == 1 ? 4 : 5)
)
{
DEBUG_ERROR("SDL_MOUSEWHEEL: failed to send messages");
break;
}
break;
case SDL_MOUSEMOTION:
{
if (
!serverMode && (
event.motion.x < state.dstRect.x ||
event.motion.x > state.dstRect.x + state.dstRect.w ||
event.motion.y < state.dstRect.y ||
event.motion.y > state.dstRect.y + state.dstRect.h
)
)
{
realignGuest = true;
break;
}
int x = 0;
int y = 0;
if (realignGuest && state.haveCursorPos)
{
x = event.motion.x - state.dstRect.x;
y = event.motion.y - state.dstRect.y;
if (params.scaleMouseInput)
{
x = (float)x * state.scaleX;
y = (float)y * state.scaleY;
}
x -= state.cursor.x;
y -= state.cursor.y;
realignGuest = false;
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("SDL_MOUSEMOTION: failed to send message");
break;
}
x = event.motion.xrel;
y = event.motion.yrel;
if (x != 0 || y != 0)
{
if (params.scaleMouseInput)
{
x = (float)x * state.scaleX;
y = (float)y * state.scaleY;
}
if (!spice_mouse_motion(x, y))
{
DEBUG_ERROR("SDL_MOUSEMOTION: failed to send message");
break;
}
}
break;
}
case SDL_MOUSEBUTTONDOWN:
// The SPICE protocol doesn't support more than a standard PS/2 3 button mouse
if (event.button.button > 3)
break;
if (
!spice_mouse_position(event.button.x, event.button.y) ||
!spice_mouse_press(event.button.button)
)
{
DEBUG_ERROR("SDL_MOUSEBUTTONDOWN: failed to send message");
break;
}
break;
case SDL_MOUSEBUTTONUP:
// The SPICE protocol doesn't support more than a standard PS/2 3 button mouse
if (event.button.button > 3)
break;
if (
!spice_mouse_position(event.button.x, event.button.y) ||
!spice_mouse_release(event.button.button)
)
{
DEBUG_ERROR("SDL_MOUSEBUTTONUP: failed to send message");
break;
}
break;
default:
break;
}
} }
return 0; return 0;
@ -851,7 +839,7 @@ int run()
} }
SDL_Thread *t_spice = NULL; SDL_Thread *t_spice = NULL;
SDL_Thread *t_event = NULL; SDL_Thread *t_main = NULL;
while(1) while(1)
{ {
@ -885,12 +873,6 @@ int run()
} }
} }
if (!(t_event = SDL_CreateThread(eventThread, "eventThread", NULL)))
{
DEBUG_ERROR("event create thread failed");
break;
}
// flag the host that we are starting up this is important so that // flag the host that we are starting up this is important so that
// the host wakes up if it is waiting on an interrupt, the host will // the host wakes up if it is waiting on an interrupt, the host will
// also send us the current mouse shape since we won't know it yet // also send us the current mouse shape since we won't know it yet
@ -914,26 +896,48 @@ int run()
break; break;
} }
if (!(t_event = SDL_CreateThread(cursorThread, "cursorThread", NULL)))
if (!(t_main = SDL_CreateThread(cursorThread, "cursorThread", NULL)))
{ {
DEBUG_ERROR("cursor create thread failed"); DEBUG_ERROR("cursor create thread failed");
break; break;
} }
if (!(t_event = SDL_CreateThread(frameThread, "frameThread", NULL))) if (!(t_main = SDL_CreateThread(frameThread, "frameThread", NULL)))
{ {
DEBUG_ERROR("frame create thread failed"); DEBUG_ERROR("frame create thread failed");
break; break;
} }
mainThread(); if (!(t_main = SDL_CreateThread(renderThread, "renderThread", NULL)))
{
DEBUG_ERROR("render create thread failed");
break;
}
// ensure mouse acceleration is identical in server mode
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1", SDL_HINT_OVERRIDE);
SDL_SetEventFilter(eventFilter, NULL);
while(state.running)
{
SDL_Event event;
while(SDL_PollEvent(&event))
if (event.type == SDL_QUIT)
{
if (!params.ignoreQuit)
state.running = false;
break;
}
}
break; break;
} }
state.running = false; state.running = false;
if (t_event) if (t_main)
SDL_WaitThread(t_event, NULL); SDL_WaitThread(t_main, NULL);
if (t_spice) if (t_spice)
SDL_WaitThread(t_spice, NULL); SDL_WaitThread(t_spice, NULL);
@ -1422,6 +1426,5 @@ int main(int argc, char * argv[])
free(opts->argv); free(opts->argv);
} }
return ret; return ret;
} }