| Summary: | SDL_PollEvent/SDL_PumpEvents for keyboard events takes 4-5 ms. It's too slow | ||
|---|---|---|---|
| Product: | SDL | Reporter: | Roman Shuvalov <roman> |
| Component: | events | Assignee: | Ryan C. Gordon <icculus> |
| Status: | ASSIGNED --- | QA Contact: | Sam Lantinga <slouken> |
| Severity: | normal | ||
| Priority: | P2 | CC: | cameron.gutman |
| Version: | don't know | ||
| Hardware: | x86_64 | ||
| OS: | Linux | ||
I haven't seen that here. Can you build SDL with timing sprinkled inside the X11 keyboard code to see where the delay is happening? Found source of a problem, it's X11_DispatchEvent() call (/src/video/x11/SDL_x11events.c, line 1463). If argument is keyboard event, X11_DispatchEvent() takes 3-4 milliseconds. Whoops, it's implemented right there in same file, continuing searching inside X11_DispatchEvent()... Found: dbus.connection_send_with_reply_and_block() causes delay. It's called in src/core/linux/SDL_dbus.c:189, used if SDL_USE_IME and (probably) IBUS enabled. "Backtrace": X11_DispatchEvent - SDL_IME_ProcessKeyEvent - SDL_IBus_ProcessKeyEvent - SDL_DBus_CallMethodOnConnection - SDL_DBus_CallMethodInternal - dbus.connection_send_with_reply_and_block. Hey Ryan, any idea what to do here? If you don't actually need IME support in your program, you can call SDL_StopTextInput(). That will avoid calling out to the IME. |
If a window has keyboard events pending, SDL_PumpEvents or first call of SDL_PollEvent takes around 4-5 milliseconds which is too slow. For example, each frame of 60 fps game lasts only 1000/60 = 16.7 ms, and wasting 4 ms just for resolving keyboard events is huge performance issue. Here is minimal program to reproduce a problem. Tested on Debian 10. Mouse moving above the window causes only around 300 microseconds (0.3 ms) delay which is absolutely fine. But hitting even a single key increases delay to 4000+ microseconds. Holding a key probably "stacks" delay times up to 20-30 ms which is insane. ----------------------------------- #include <SDL2/SDL.h> #include <time.h> uint64_t get_time_us() { struct timespec tspec; clock_gettime(CLOCK_MONOTONIC_RAW, &tspec); uint64_t sec = tspec.tv_sec; uint64_t usec = tspec.tv_nsec / 1000; return sec*1000000L + usec; } int main (int argc, char ** args) { if( SDL_Init( SDL_INIT_EVERYTHING ) != 0 ) { return 1; } SDL_Window* window = SDL_CreateWindow("SDL2 Event Delay Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 300, SDL_WINDOW_SHOWN); if ( window == NULL ) { return 1; }; int quit = 0; SDL_Event e; while ( !quit ) { uint64_t t[3]; t[0] = get_time_us(); SDL_PumpEvents(); // or it will be called on first SDL_PollEvent() and cause same delay t[1] = get_time_us(); while( SDL_PollEvent( &e ) != 0 ) { if( e.type == SDL_QUIT ) { quit = 1; }; }; printf("SDL_PumpEvents() took %ld us (%ld ms)\n", t[1]-t[0], (t[1]-t[0])/1000 ); SDL_Delay(100); }; SDL_DestroyWindow(window); SDL_Quit(); return 0; };