From 37ea662998c103ae56bc94aab9aec7a60607767f Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Wed, 24 Jan 2018 23:46:11 +1100 Subject: [PATCH] [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. --- client/main.c | 393 +++++++++++++++++++++++++------------------------- 1 file changed, 198 insertions(+), 195 deletions(-) diff --git a/client/main.c b/client/main.c index e045a281..d2e863cf 100644 --- a/client/main.c +++ b/client/main.c @@ -177,7 +177,7 @@ static inline void updatePositionInfo() state.lgr->on_resize(state.lgrData, w, h, state.dstRect); } -void mainThread() +int renderThread(void * unused) { while(state.running) { @@ -189,6 +189,8 @@ void mainThread() else usleep(1000); } + + return 0; } int cursorThread(void * unused) @@ -418,205 +420,191 @@ static inline const uint32_t mapScancode(SDL_Scancode scancode) return ps2; } -int eventThread(void * arg) +struct eventState { - bool serverMode = false; - bool realignGuest = true; + bool serverMode; + bool realignGuest; 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 - SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1", SDL_HINT_OVERRIDE); - - while(state.running) + if (event->type == SDL_WINDOWEVENT) { - SDL_Event event; - if (!SDL_PollEvent(&event)) + switch(event->window.event) { - usleep(1000); - continue; + case SDL_WINDOWEVENT_ENTER: + 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: - if (!params.ignoreQuit) - state.running = false; + SDL_Scancode sc = event->key.keysym.scancode; + if (sc == SDL_SCANCODE_SCROLLLOCK) + { + 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; - 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) - { - case SDL_WINDOWEVENT_ENTER: - realignGuest = true; - break; - - case SDL_WINDOWEVENT_SIZE_CHANGED: - updatePositionInfo(); - realignGuest = true; - break; - } + DEBUG_ERROR("SDL_MOUSEBUTTONDOWN: failed to send message"); break; } - } + break; - if (!params.useSpice) - continue; - - switch(event.type) - { - case SDL_KEYDOWN: + 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) + ) { - SDL_Scancode sc = event.key.keysym.scancode; - 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; - } + DEBUG_ERROR("SDL_MOUSEBUTTONUP: 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; - - 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; - } + default: + return 1; } return 0; @@ -851,7 +839,7 @@ int run() } SDL_Thread *t_spice = NULL; - SDL_Thread *t_event = NULL; + SDL_Thread *t_main = NULL; 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 // 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 @@ -914,26 +896,48 @@ int run() break; } - if (!(t_event = SDL_CreateThread(cursorThread, "cursorThread", NULL))) + + if (!(t_main = SDL_CreateThread(cursorThread, "cursorThread", NULL))) { DEBUG_ERROR("cursor create thread failed"); break; } - if (!(t_event = SDL_CreateThread(frameThread, "frameThread", NULL))) + if (!(t_main = SDL_CreateThread(frameThread, "frameThread", NULL))) { DEBUG_ERROR("frame create thread failed"); 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; } state.running = false; - if (t_event) - SDL_WaitThread(t_event, NULL); + if (t_main) + SDL_WaitThread(t_main, NULL); if (t_spice) SDL_WaitThread(t_spice, NULL); @@ -1422,6 +1426,5 @@ int main(int argc, char * argv[]) free(opts->argv); } - return ret; -} +} \ No newline at end of file