Browse Source

wayland: Add SDL_VIDEO_DOUBLE_BUFFER support

Manual cherry-pick of 9e6b8d56e33f77dab507236d84a3f76b6fea7b2a

thanks @vanfanel
Frank Praznik 9 months ago
parent
commit
b99ea1ff75

+ 1 - 0
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.
  *

+ 20 - 5
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;
 }

+ 4 - 0
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);

+ 1 - 0
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;