SDL: wayland: Only dispatch frame events in Wayland_GLES_SwapWindow

From ad5205739e2f604c38b787abebfcbbf8972ce12f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=A4in=C3=B6=20M=C3=A4kel=C3=A4?=
 <vaino.o.makela@gmail.com>
Date: Wed, 6 Oct 2021 09:52:06 +0300
Subject: [PATCH] wayland: Only dispatch frame events in
 Wayland_GLES_SwapWindow

Dispatching all events in Wayland_GLES_SwapWindow leads to resizes being
acked before the program has a chance to handle the resize. This change
reduces jumping on fullscreen transition with apps that call
SDL_PollEvent before issuing any render calls.
---
 src/video/wayland/SDL_waylandopengles.c | 4 ++--
 src/video/wayland/SDL_waylandsym.h      | 3 +++
 src/video/wayland/SDL_waylandwindow.c   | 9 +++++++--
 src/video/wayland/SDL_waylandwindow.h   | 2 ++
 4 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c
index 959ebc8faf..c6d5659105 100644
--- a/src/video/wayland/SDL_waylandopengles.c
+++ b/src/video/wayland/SDL_waylandopengles.c
@@ -138,7 +138,7 @@ Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
 
             /* !!! FIXME: this is just the crucial piece of Wayland_PumpEvents */
             WAYLAND_wl_display_flush(display);
-            if (WAYLAND_wl_display_dispatch_pending(display) > 0) {
+            if (WAYLAND_wl_display_dispatch_queue_pending(display, data->frame_event_queue) > 0) {
                 /* We dispatched some pending events. Check if the frame callback happened. */
                 continue;
             }
@@ -161,7 +161,7 @@ Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
                 break;
             }
 
-            WAYLAND_wl_display_dispatch(display);
+            WAYLAND_wl_display_dispatch_queue(display, data->frame_event_queue);
             SDL_UnlockMutex(videodata->display_dispatch_lock);
         }
         SDL_AtomicSet(&data->swap_interval_ready, 0);
diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h
index 40e6c99a1f..37c4b42ddf 100644
--- a/src/video/wayland/SDL_waylandsym.h
+++ b/src/video/wayland/SDL_waylandsym.h
@@ -46,6 +46,8 @@ SDL_WAYLAND_SYM(uint32_t, wl_proxy_get_version, (struct wl_proxy *))
 SDL_WAYLAND_SYM(uint32_t, wl_proxy_get_id, (struct wl_proxy *))
 SDL_WAYLAND_SYM(const char *, wl_proxy_get_class, (struct wl_proxy *))
 SDL_WAYLAND_SYM(void, wl_proxy_set_queue, (struct wl_proxy *, struct wl_event_queue *))
+SDL_WAYLAND_SYM(void *, wl_proxy_create_wrapper, (void *))
+SDL_WAYLAND_SYM(void, wl_proxy_wrapper_destroy, (void *))
 SDL_WAYLAND_SYM(struct wl_display *, wl_display_connect, (const char *))
 SDL_WAYLAND_SYM(struct wl_display *, wl_display_connect_to_fd, (int))
 SDL_WAYLAND_SYM(void, wl_display_disconnect, (struct wl_display *))
@@ -58,6 +60,7 @@ SDL_WAYLAND_SYM(int, wl_display_get_error, (struct wl_display *))
 SDL_WAYLAND_SYM(int, wl_display_flush, (struct wl_display *))
 SDL_WAYLAND_SYM(int, wl_display_roundtrip, (struct wl_display *))
 SDL_WAYLAND_SYM(struct wl_event_queue *, wl_display_create_queue, (struct wl_display *))
+SDL_WAYLAND_SYM(void, wl_event_queue_destroy, (struct wl_event_queue *))
 SDL_WAYLAND_SYM(void, wl_log_set_handler_client, (wl_log_func_t))
 SDL_WAYLAND_SYM(void, wl_list_init, (struct wl_list *))
 SDL_WAYLAND_SYM(void, wl_list_insert, (struct wl_list *, struct wl_list *) )
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index f12c142556..02443ec4e8 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -146,7 +146,7 @@ handle_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time)
     SDL_AtomicSet(&wind->swap_interval_ready, 1);  /* mark window as ready to present again. */
 
     /* reset this callback to fire again once a new frame was presented and compositor wants the next one. */
-    wind->frame_callback = wl_surface_frame(wind->surface);
+    wind->frame_callback = wl_surface_frame(wind->frame_surface_wrapper);
     wl_callback_destroy(cb);
     wl_callback_add_listener(wind->frame_callback, &surface_frame_listener, data);
 }
@@ -1237,7 +1237,10 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
      * window isn't visible.
      */
     if (window->flags & SDL_WINDOW_OPENGL) {
-        data->frame_callback = wl_surface_frame(data->surface);
+        data->frame_event_queue = WAYLAND_wl_display_create_queue(data->waylandData->display);
+        data->frame_surface_wrapper = WAYLAND_wl_proxy_create_wrapper(data->surface);
+        WAYLAND_wl_proxy_set_queue((struct wl_proxy *)data->frame_surface_wrapper, data->frame_event_queue);
+        data->frame_callback = wl_surface_frame(data->frame_surface_wrapper);
         wl_callback_add_listener(data->frame_callback, &surface_frame_listener, data);
     }
 
@@ -1477,6 +1480,8 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window)
         SDL_free(wind->outputs);
 
         if (wind->frame_callback) {
+            WAYLAND_wl_event_queue_destroy(wind->frame_event_queue);
+            WAYLAND_wl_proxy_wrapper_destroy(wind->frame_surface_wrapper);
             wl_callback_destroy(wind->frame_callback);
         }
 
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index 852a8dc0a6..1aaa645217 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -53,6 +53,8 @@ typedef struct {
     SDL_VideoData *waylandData;
     struct wl_surface *surface;
     struct wl_callback *frame_callback;
+    struct wl_event_queue *frame_event_queue;
+    struct wl_surface *frame_surface_wrapper;
     union {
 #ifdef HAVE_LIBDECOR_H
         SDL_libdecor_surface libdecor;