From b99ea1ff75e96354b8cc11387185cd461f6d6279 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Wed, 17 Jul 2024 18:24:47 -0400 Subject: [PATCH] wayland: Add SDL_VIDEO_DOUBLE_BUFFER support Manual cherry-pick of 9e6b8d56e33f77dab507236d84a3f76b6fea7b2a thanks @vanfanel --- include/SDL3/SDL_hints.h | 1 + src/video/wayland/SDL_waylandopengles.c | 25 ++++++++++++++++++++----- src/video/wayland/SDL_waylandwindow.c | 4 ++++ src/video/wayland/SDL_waylandwindow.h | 1 + 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 4c63c6f735..f6c7cf3385 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -2948,6 +2948,7 @@ extern "C" { * This hint is currently supported on the following drivers: * * - Raspberry Pi (raspberrypi) + * - Wayland (wayland) * * This hint should be set before SDL is initialized. * diff --git a/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c index 6ee1851ba0..0fad3bcf3a 100644 --- a/src/video/wayland/SDL_waylandopengles.c +++ b/src/video/wayland/SDL_waylandopengles.c @@ -120,6 +120,19 @@ int Wayland_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) return 0; } + /* By default, we wait for the Wayland frame callback and then issue the pageflip (eglSwapBuffers), + * but if we want low latency (double buffer scheme), we issue the pageflip and then wait + * immediately for the Wayland frame callback. + */ + if (data->double_buffer) { + /* Feed the frame to Wayland. This will set it so the wl_surface_frame callback can fire again. */ + if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, data->egl_surface)) { + return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers"); + } + + WAYLAND_wl_display_flush(data->waylandData->display); + } + /* Control swap interval ourselves. See comments on Wayland_GLES_SetSwapInterval */ if (swap_interval != 0 && data->surface_status == WAYLAND_SURFACE_STATUS_SHOWN) { SDL_VideoData *videodata = _this->internal; @@ -161,12 +174,14 @@ int Wayland_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_AtomicSet(&data->swap_interval_ready, 0); } - /* Feed the frame to Wayland. This will set it so the wl_surface_frame callback can fire again. */ - if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, data->egl_surface)) { - return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers"); - } + if (!data->double_buffer) { + /* Feed the frame to Wayland. This will set it so the wl_surface_frame callback can fire again. */ + if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, data->egl_surface)) { + return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers"); + } - WAYLAND_wl_display_flush(data->waylandData->display); + WAYLAND_wl_display_flush(data->waylandData->display); + } return 0; } diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 0f14bfc554..853addbd82 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -2484,6 +2484,10 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert data->surface_status = WAYLAND_SURFACE_STATUS_SHOWN; } + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) { + data->double_buffer = SDL_TRUE; + } + SDL_PropertiesID props = SDL_GetWindowProperties(window); SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, data->waylandData->display); SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, data->surface); diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 032c4845ba..ffe762c37e 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -168,6 +168,7 @@ struct SDL_WindowData SDL_bool show_hide_sync_required; SDL_bool scale_to_display; SDL_bool modal_reparenting_required; + SDL_bool double_buffer; SDL_HitTestResult hit_test_result;