wayland: Use a separate frame callback for setting the surface damage region Previously, the surface damage region was being set in the same callback used for preventing render hangs in the GL backend when the surface was not visible. This was not ideal, as the callback was never fired in the case of using a different render backend or having a swap interval of 0. Use a separate frame callback for setting the surface damage region to ensure that it fires reliably, regardless of the backend being used or swap interval.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
diff --git a/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c
index 4c834fd..26626ee 100644
--- a/src/video/wayland/SDL_waylandopengles.c
+++ b/src/video/wayland/SDL_waylandopengles.c
@@ -140,9 +140,9 @@ Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
/* wl_display_prepare_read_queue() will return -1 if the event queue is not empty.
* If the event queue is empty, it will prepare us for our SDL_IOReady() call. */
- if (WAYLAND_wl_display_prepare_read_queue(display, data->frame_event_queue) != 0) {
+ if (WAYLAND_wl_display_prepare_read_queue(display, data->gles_swap_frame_event_queue) != 0) {
/* We have some pending events. Check if the frame callback happened. */
- WAYLAND_wl_display_dispatch_queue_pending(display, data->frame_event_queue);
+ WAYLAND_wl_display_dispatch_queue_pending(display, data->gles_swap_frame_event_queue);
continue;
}
@@ -163,7 +163,7 @@ Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
/* We have events. Read and dispatch them. */
WAYLAND_wl_display_read_events(display);
- WAYLAND_wl_display_dispatch_queue_pending(display, data->frame_event_queue);
+ WAYLAND_wl_display_dispatch_queue_pending(display, data->gles_swap_frame_event_queue);
}
SDL_AtomicSet(&data->swap_interval_ready, 0);
}
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 2c70d40..8be9cd9 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -426,27 +426,44 @@ SetFullscreen(SDL_Window *window, struct wl_output *output, SDL_bool commit)
}
}
-static const struct wl_callback_listener surface_frame_listener;
+const struct wl_callback_listener surface_damage_frame_listener;
static void
-handle_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time)
+surface_damage_frame_done(void *data, struct wl_callback *cb, uint32_t time)
{
- SDL_WindowData *wind = (SDL_WindowData *) data;
- SDL_AtomicSet(&wind->swap_interval_ready, 1); /* mark window as ready to present again. */
+ SDL_WindowData *wind = (SDL_WindowData *)data;
+ /* Manually set the damage region when using a viewport. */
if (!SDL_RectEmpty(&wind->viewport_rect)) {
wl_surface_damage(wind->surface, wind->viewport_rect.x, wind->viewport_rect.y,
wind->viewport_rect.w, wind->viewport_rect.h);
}
+ wl_callback_destroy(cb);
+ wind->surface_damage_frame_callback = wl_surface_frame(wind->surface);
+ wl_callback_add_listener(wind->surface_damage_frame_callback, &surface_damage_frame_listener, data);
+}
+
+const struct wl_callback_listener surface_damage_frame_listener = {
+ surface_damage_frame_done
+};
+
+static const struct wl_callback_listener gles_swap_frame_listener;
+
+static void
+gles_swap_frame_done(void *data, struct wl_callback *cb, uint32_t time)
+{
+ SDL_WindowData *wind = (SDL_WindowData *) data;
+ 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->frame_surface_wrapper);
+ wind->gles_swap_frame_callback = wl_surface_frame(wind->gles_swap_frame_surface_wrapper);
wl_callback_destroy(cb);
- wl_callback_add_listener(wind->frame_callback, &surface_frame_listener, data);
+ wl_callback_add_listener(wind->gles_swap_frame_callback, &gles_swap_frame_listener, data);
}
-static const struct wl_callback_listener surface_frame_listener = {
- handle_surface_frame_done
+static const struct wl_callback_listener gles_swap_frame_listener = {
+ gles_swap_frame_done
};
@@ -1838,13 +1855,17 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
* window isn't visible.
*/
if (window->flags & SDL_WINDOW_OPENGL) {
- 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);
+ data->gles_swap_frame_event_queue = WAYLAND_wl_display_create_queue(data->waylandData->display);
+ data->gles_swap_frame_surface_wrapper = WAYLAND_wl_proxy_create_wrapper(data->surface);
+ WAYLAND_wl_proxy_set_queue((struct wl_proxy *)data->gles_swap_frame_surface_wrapper, data->gles_swap_frame_event_queue);
+ data->gles_swap_frame_callback = wl_surface_frame(data->gles_swap_frame_surface_wrapper);
+ wl_callback_add_listener(data->gles_swap_frame_callback, &gles_swap_frame_listener, data);
}
+ /* Fire a callback when the compositor wants a new frame to set the surface damage region. */
+ data->surface_damage_frame_callback = wl_surface_frame(data->surface);
+ wl_callback_add_listener(data->surface_damage_frame_callback, &surface_damage_frame_listener, data);
+
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
if (c->surface_extension) {
data->extended_surface = qt_surface_extension_get_extended_surface(
@@ -2107,10 +2128,14 @@ 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);
+ if (wind->gles_swap_frame_callback) {
+ WAYLAND_wl_event_queue_destroy(wind->gles_swap_frame_event_queue);
+ WAYLAND_wl_proxy_wrapper_destroy(wind->gles_swap_frame_surface_wrapper);
+ wl_callback_destroy(wind->gles_swap_frame_callback);
+ }
+
+ if (wind->surface_damage_frame_callback) {
+ wl_callback_destroy(wind->surface_damage_frame_callback);
}
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index e77cb80..703ec53 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -42,9 +42,10 @@ typedef struct {
SDL_Window *sdlwindow;
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;
+ struct wl_callback *gles_swap_frame_callback;
+ struct wl_event_queue *gles_swap_frame_event_queue;
+ struct wl_surface *gles_swap_frame_surface_wrapper;
+ struct wl_callback *surface_damage_frame_callback;
union {
#ifdef HAVE_LIBDECOR_H