diff --git a/src/core/freebsd/SDL_evdev_kbd_freebsd.c b/src/core/freebsd/SDL_evdev_kbd_freebsd.c index 8504b80d2..a4fd0e48b 100644 --- a/src/core/freebsd/SDL_evdev_kbd_freebsd.c +++ b/src/core/freebsd/SDL_evdev_kbd_freebsd.c @@ -321,6 +321,18 @@ void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd) SDL_free(kbd); } +void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted) +{ +} + +void SDL_EVDEV_kbd_set_vt_switch_callbacks(SDL_EVDEV_keyboard_state *state, void (*release_callback)(void*), void *release_callback_data, void (*acquire_callback)(void*), void *acquire_callback_data) +{ +} + +void SDL_EVDEV_kbd_update(SDL_EVDEV_keyboard_state *state) +{ +} + /* * Helper Functions. */ @@ -468,10 +480,6 @@ static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_ } } -void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted) -{ -} - void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down) { keymap_t key_map; diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c index 22b686051..89777e69e 100644 --- a/src/core/linux/SDL_evdev.c +++ b/src/core/linux/SDL_evdev.c @@ -283,6 +283,14 @@ static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_cl } #endif /* SDL_USE_LIBUDEV */ +void SDL_EVDEV_SetVTSwitchCallbacks(void (*release_callback)(void*), void *release_callback_data, + void (*acquire_callback)(void*), void *acquire_callback_data) +{ + SDL_EVDEV_kbd_set_vt_switch_callbacks(_this->kbd, + release_callback, release_callback_data, + acquire_callback, acquire_callback_data); +} + int SDL_EVDEV_GetDeviceCount(int device_class) { SDL_evdevlist_item *item; @@ -314,6 +322,8 @@ void SDL_EVDEV_Poll(void) SDL_UDEV_Poll(); #endif + SDL_EVDEV_kbd_update(_this->kbd); + mouse = SDL_GetMouse(); for (item = _this->first; item != NULL; item = item->next) { diff --git a/src/core/linux/SDL_evdev.h b/src/core/linux/SDL_evdev.h index 7f9ac3620..6951a7cac 100644 --- a/src/core/linux/SDL_evdev.h +++ b/src/core/linux/SDL_evdev.h @@ -30,6 +30,8 @@ extern int SDL_EVDEV_Init(void); extern void SDL_EVDEV_Quit(void); +extern void SDL_EVDEV_SetVTSwitchCallbacks(void (*release_callback)(void*), void *release_callback_data, + void (*acquire_callback)(void*), void *acquire_callback_data); extern int SDL_EVDEV_GetDeviceCount(int device_class); extern void SDL_EVDEV_Poll(void); diff --git a/src/core/linux/SDL_evdev_kbd.c b/src/core/linux/SDL_evdev_kbd.c index 73d14848c..823bcd64a 100644 --- a/src/core/linux/SDL_evdev_kbd.c +++ b/src/core/linux/SDL_evdev_kbd.c @@ -100,6 +100,10 @@ struct SDL_EVDEV_keyboard_state char shift_state; char text[128]; unsigned int text_len; + void (*vt_release_callback)(void *); + void *vt_release_callback_data; + void (*vt_acquire_callback)(void *); + void *vt_acquire_callback_data; }; #ifdef DUMP_ACCENTS @@ -297,6 +301,126 @@ static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state *kbd) } } +enum { + VT_SIGNAL_NONE, + VT_SIGNAL_RELEASE, + VT_SIGNAL_ACQUIRE, +}; +static int vt_release_signal; +static int vt_acquire_signal; +static SDL_atomic_t vt_signal_pending; + +typedef void (*signal_handler)(int signum); + +static void kbd_vt_release_signal_action(int signum) +{ + SDL_AtomicSet(&vt_signal_pending, VT_SIGNAL_RELEASE); +} + +static void kbd_vt_acquire_signal_action(int signum) +{ + SDL_AtomicSet(&vt_signal_pending, VT_SIGNAL_ACQUIRE); +} + +static SDL_bool setup_vt_signal(int signum, signal_handler handler) +{ + struct sigaction *old_action_p; + struct sigaction new_action; + old_action_p = &(old_sigaction[signum]); + SDL_zero(new_action); + new_action.sa_handler = handler; + new_action.sa_flags = SA_RESTART; + if (sigaction(signum, &new_action, old_action_p) < 0) { + return SDL_FALSE; + } + if (old_action_p->sa_handler != SIG_DFL) { + /* This signal is already in use */ + sigaction(signum, old_action_p, NULL); + return SDL_FALSE; + } + return SDL_TRUE; +} + +static int find_free_signal(signal_handler handler) +{ +#ifdef SIGRTMIN + int i; + + for (i = SIGRTMIN + 2; i <= SIGRTMAX; ++i) { + if (setup_vt_signal(i, handler)) { + return i; + } + } +#endif + if (setup_vt_signal(SIGUSR1, handler)) { + return SIGUSR1; + } + if (setup_vt_signal(SIGUSR2, handler)) { + return SIGUSR2; + } + return 0; +} + +static void kbd_vt_quit(int console_fd) +{ + struct vt_mode mode; + + if (vt_release_signal) { + sigaction(vt_release_signal, &old_sigaction[vt_release_signal], NULL); + vt_release_signal = 0; + } + if (vt_acquire_signal) { + sigaction(vt_acquire_signal, &old_sigaction[vt_acquire_signal], NULL); + vt_acquire_signal = 0; + } + + SDL_zero(mode); + mode.mode = VT_AUTO; + ioctl(console_fd, VT_SETMODE, &mode); +} + +static int kbd_vt_init(int console_fd) +{ + struct vt_mode mode; + + vt_release_signal = find_free_signal(kbd_vt_release_signal_action); + vt_acquire_signal = find_free_signal(kbd_vt_acquire_signal_action); + if (!vt_release_signal || !vt_acquire_signal ) { + kbd_vt_quit(console_fd); + return -1; + } + + SDL_zero(mode); + mode.mode = VT_PROCESS; + mode.relsig = vt_release_signal; + mode.acqsig = vt_acquire_signal; + mode.frsig = SIGIO; + if (ioctl(console_fd, VT_SETMODE, &mode) < 0) { + kbd_vt_quit(console_fd); + return -1; + } + return 0; +} + +static void kbd_vt_update(SDL_EVDEV_keyboard_state *state) +{ + int signal_pending = SDL_AtomicGet(&vt_signal_pending); + if (signal_pending != VT_SIGNAL_NONE) { + if (signal_pending == VT_SIGNAL_RELEASE) { + if (state->vt_release_callback) { + state->vt_release_callback(state->vt_release_callback_data); + } + ioctl(state->console_fd, VT_RELDISP, 1); + } else { + if (state->vt_acquire_callback) { + state->vt_acquire_callback(state->vt_acquire_callback_data); + } + ioctl(state->console_fd, VT_RELDISP, VT_ACKACQ); + } + SDL_AtomicCAS(&vt_signal_pending, signal_pending, VT_SIGNAL_NONE); + } +} + SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void) { SDL_EVDEV_keyboard_state *kbd; @@ -334,35 +458,11 @@ SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void) ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE); } + kbd_vt_init(kbd->console_fd); + return kbd; } -void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state) -{ - if (state == NULL) { - return; - } - - SDL_EVDEV_kbd_set_muted(state, SDL_FALSE); - - if (state->console_fd >= 0) { - close(state->console_fd); - state->console_fd = -1; - } - - if (state->key_maps && state->key_maps != default_key_maps) { - int i; - for (i = 0; i < MAX_NR_KEYMAPS; ++i) { - if (state->key_maps[i]) { - SDL_free(state->key_maps[i]); - } - } - SDL_free(state->key_maps); - } - - SDL_free(state); -} - void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted) { if (state == NULL) { @@ -397,6 +497,55 @@ void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted) state->muted = muted; } +void SDL_EVDEV_kbd_set_vt_switch_callbacks(SDL_EVDEV_keyboard_state *state, void (*release_callback)(void*), void *release_callback_data, void (*acquire_callback)(void*), void *acquire_callback_data) +{ + if (state == NULL) { + return; + } + + state->vt_release_callback = release_callback; + state->vt_release_callback_data = release_callback_data; + state->vt_acquire_callback = acquire_callback; + state->vt_acquire_callback_data = acquire_callback_data; +} + +void SDL_EVDEV_kbd_update(SDL_EVDEV_keyboard_state *state) +{ + if (!state) { + return; + } + + kbd_vt_update(state); +} + +void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state) +{ + if (state == NULL) { + return; + } + + SDL_EVDEV_kbd_set_muted(state, SDL_FALSE); + + kbd_vt_quit(state->console_fd); + + if (state->console_fd >= 0) { + close(state->console_fd); + state->console_fd = -1; + } + + if (state->key_maps && state->key_maps != default_key_maps) { + int i; + for (i = 0; i < MAX_NR_KEYMAPS; ++i) { + if (state->key_maps[i]) { + SDL_free(state->key_maps[i]); + } + } + SDL_free(state->key_maps); + } + + SDL_free(state); +} + /* * Helper Functions. */ @@ -831,6 +980,14 @@ void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted) { } +void SDL_EVDEV_kbd_set_vt_switch_callbacks(SDL_EVDEV_keyboard_state *state, void (*release_callback)(void*), void *release_callback_data, void (*acquire_callback)(void*), void *acquire_callback_data) +{ +} + +void SDL_EVDEV_kbd_update(SDL_EVDEV_keyboard_state *state) +{ +} + void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down) { } diff --git a/src/core/linux/SDL_evdev_kbd.h b/src/core/linux/SDL_evdev_kbd.h index cb4b6da10..539ad6cfd 100644 --- a/src/core/linux/SDL_evdev_kbd.h +++ b/src/core/linux/SDL_evdev_kbd.h @@ -27,6 +27,8 @@ typedef struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state; extern SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void); extern void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted); +extern void SDL_EVDEV_kbd_set_vt_switch_callbacks(SDL_EVDEV_keyboard_state *state, void (*release_callback)(void*), void *release_callback_data, void (*acquire_callback)(void*), void *acquire_callback_data); +extern void SDL_EVDEV_kbd_update(SDL_EVDEV_keyboard_state *state); extern void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down); extern void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state); diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c index 8dc2bfdc6..513694c59 100644 --- a/src/video/kmsdrm/SDL_kmsdrmopengles.c +++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c @@ -24,6 +24,7 @@ #if SDL_VIDEO_DRIVER_KMSDRM #include "SDL_log.h" +#include "SDL_timer.h" #include "SDL_kmsdrmvideo.h" #include "SDL_kmsdrmopengles.h" @@ -97,6 +98,13 @@ int KMSDRM_GLES_SwapWindow(_THIS, SDL_Window *window) even if you do async flips. */ uint32_t flip_flags = DRM_MODE_PAGE_FLIP_EVENT; + /* Skip the swap if we've switched away to another VT */ + if (windata->egl_surface == EGL_NO_SURFACE) { + /* Wait a bit, throttling to ~100 FPS */ + SDL_Delay(10); + return 0; + } + /* Recreate the GBM / EGL surfaces if the display mode has changed */ if (windata->egl_surface_dirty) { KMSDRM_CreateSurfaces(_this, window); @@ -117,7 +125,7 @@ int KMSDRM_GLES_SwapWindow(_THIS, SDL_Window *window) windata->bo = windata->next_bo; - /* Mark a buffer to becume the next front buffer. + /* Mark a buffer to become the next front buffer. This won't happen until pagelip completes. */ if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, windata->egl_surface))) { diff --git a/src/video/kmsdrm/SDL_kmsdrmsym.h b/src/video/kmsdrm/SDL_kmsdrmsym.h index 8b9e7b257..ef12c36b8 100644 --- a/src/video/kmsdrm/SDL_kmsdrmsym.h +++ b/src/video/kmsdrm/SDL_kmsdrmsym.h @@ -42,6 +42,7 @@ SDL_KMSDRM_SYM(void,drmModeFreeConnector,(drmModeConnectorPtr ptr)) SDL_KMSDRM_SYM(void,drmModeFreeEncoder,(drmModeEncoderPtr ptr)) SDL_KMSDRM_SYM(int,drmGetCap,(int fd, uint64_t capability, uint64_t *value)) SDL_KMSDRM_SYM(int,drmSetMaster,(int fd)) +SDL_KMSDRM_SYM(int,drmDropMaster,(int fd)) SDL_KMSDRM_SYM(int,drmAuthMagic,(int fd, drm_magic_t magic)) SDL_KMSDRM_SYM(drmModeResPtr,drmModeGetResources,(int fd)) SDL_KMSDRM_SYM(int,drmModeAddFB,(int fd, uint32_t width, uint32_t height, uint8_t depth, diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index ebe15fe9c..f5e2577de 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -1206,6 +1206,36 @@ cleanup: return ret; } +static void KMSDRM_ReleaseVT(void *userdata) +{ + SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata; + SDL_VideoData *viddata = _this->driverdata; + int i; + + for (i = 0; i < viddata->num_windows; i++) { + SDL_Window *window = viddata->windows[i]; + if (!(window->flags & SDL_WINDOW_VULKAN)) { + KMSDRM_DestroySurfaces(_this, window); + } + } + KMSDRM_drmDropMaster(viddata->drm_fd); +} + +static void KMSDRM_AcquireVT(void *userdata) +{ + SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata; + SDL_VideoData *viddata = _this->driverdata; + int i; + + KMSDRM_drmSetMaster(viddata->drm_fd); + for (i = 0; i < viddata->num_windows; i++) { + SDL_Window *window = viddata->windows[i]; + if (!(window->flags & SDL_WINDOW_VULKAN)) { + KMSDRM_CreateSurfaces(_this, window); + } + } +} + int KMSDRM_VideoInit(_THIS) { int ret = 0; @@ -1226,6 +1256,7 @@ int KMSDRM_VideoInit(_THIS) #ifdef SDL_INPUT_LINUXEV SDL_EVDEV_Init(); + SDL_EVDEV_SetVTSwitchCallbacks(KMSDRM_ReleaseVT, _this, KMSDRM_AcquireVT, _this); #elif defined(SDL_INPUT_WSCONS) SDL_WSCONS_Init(); #endif @@ -1244,6 +1275,7 @@ void KMSDRM_VideoQuit(_THIS) KMSDRM_DeinitDisplays(_this); #ifdef SDL_INPUT_LINUXEV + SDL_EVDEV_SetVTSwitchCallbacks(NULL, NULL, NULL, NULL); SDL_EVDEV_Quit(); #elif defined(SDL_INPUT_WSCONS) SDL_WSCONS_Quit();