Blame SOURCES/0013-xwayland-eglstream-Dissociate-pending-stream-from-wi.patch

b6a310
From 90188c2648edb137f3564bdea53012355473f105 Mon Sep 17 00:00:00 2001
b6a310
From: Olivier Fourdan <ofourdan@redhat.com>
b6a310
Date: Fri, 16 Apr 2021 10:38:23 +0200
b6a310
Subject: [PATCH xserver 13/27] xwayland/eglstream: Dissociate pending stream
b6a310
 from window
b6a310
MIME-Version: 1.0
b6a310
Content-Type: text/plain; charset=UTF-8
b6a310
Content-Transfer-Encoding: 8bit
b6a310
b6a310
Previously, we would have pending streams associated with top level X11
b6a310
windows, keeping temporary accounting for the pending streams before
b6a310
they get fully initialized for the xwl_pixmap which would be associated
b6a310
with X11 pixmaps.
b6a310
b6a310
If the window content changes before the stream is ready, the
b6a310
corresponding pending stream would be marked as invalid and the pending
b6a310
stream would be eventually removed once the stream becomes ready.
b6a310
b6a310
Since commit affc47452 - "xwayland: Drop the separate refcount for the
b6a310
xwl_pixmap", we no longer keep a separate reference counter for the
b6a310
xwl_pixmap, but rather tie it to the X11 pixmap lifespan. Yet, the
b6a310
pending stream would still be associated with the X11 toplevel window.
b6a310
b6a310
Dissociate the pending streams from the X11 toplevel window, to keep it
b6a310
tied only to the xwl_pixmap so that we can have:
b6a310
b6a310
 - pixmap <-> xwl_pixmap
b6a310
 - xwl_pixmap <-> pending stream
b6a310
b6a310
Of course, the pending streams remain temporary and get removed as soon
b6a310
as the ready callback is triggered, but the pending streams are not
b6a310
linked to the X11 window anymore which can change their content, and
b6a310
therefore their X11 pixmap at any time.
b6a310
b6a310
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
b6a310
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
b6a310
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
b6a310
(cherry picked from commit cb61ecc7291cfbed2f76d4437cd7450b8e4dab00)
b6a310
---
b6a310
 hw/xwayland/xwayland-glamor-eglstream.c | 131 +++++++++++-------------
b6a310
 1 file changed, 60 insertions(+), 71 deletions(-)
b6a310
b6a310
diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c
b6a310
index 77b24a4b4..32f9a326f 100644
b6a310
--- a/hw/xwayland/xwayland-glamor-eglstream.c
b6a310
+++ b/hw/xwayland/xwayland-glamor-eglstream.c
b6a310
@@ -93,6 +93,7 @@ struct xwl_pixmap {
b6a310
     /* add any new <= 4-byte member here to avoid holes on 64-bit */
b6a310
     struct xwl_screen *xwl_screen;
b6a310
     struct wl_buffer *buffer;
b6a310
+    struct xwl_eglstream_pending_stream *pending_stream;
b6a310
 
b6a310
     /* XWL_PIXMAP_EGLSTREAM. */
b6a310
     EGLStreamKHR stream;
b6a310
@@ -103,7 +104,6 @@ struct xwl_pixmap {
b6a310
 };
b6a310
 
b6a310
 static DevPrivateKeyRec xwl_eglstream_private_key;
b6a310
-static DevPrivateKeyRec xwl_eglstream_window_private_key;
b6a310
 
b6a310
 static inline struct xwl_eglstream_private *
b6a310
 xwl_eglstream_get(struct xwl_screen *xwl_screen)
b6a310
@@ -112,21 +112,6 @@ xwl_eglstream_get(struct xwl_screen *xwl_screen)
b6a310
                             &xwl_eglstream_private_key);
b6a310
 }
b6a310
 
b6a310
-static inline struct xwl_eglstream_pending_stream *
b6a310
-xwl_eglstream_window_get_pending(WindowPtr window)
b6a310
-{
b6a310
-    return dixLookupPrivate(&window->devPrivates,
b6a310
-                            &xwl_eglstream_window_private_key);
b6a310
-}
b6a310
-
b6a310
-static inline void
b6a310
-xwl_eglstream_window_set_pending(WindowPtr window,
b6a310
-                                 struct xwl_eglstream_pending_stream *stream)
b6a310
-{
b6a310
-    dixSetPrivate(&window->devPrivates,
b6a310
-                  &xwl_eglstream_window_private_key, stream);
b6a310
-}
b6a310
-
b6a310
 static GLint
b6a310
 xwl_eglstream_compile_glsl_prog(GLenum type, const char *source)
b6a310
 {
b6a310
@@ -323,7 +308,6 @@ xwl_glamor_eglstream_destroy_pending_stream(struct xwl_eglstream_pending_stream
b6a310
 {
b6a310
     if (pending->cb)
b6a310
         wl_callback_destroy(pending->cb);
b6a310
-    xwl_eglstream_window_set_pending(pending->window, NULL);
b6a310
     xorg_list_del(&pending->link);
b6a310
     free(pending);
b6a310
 }
b6a310
@@ -331,16 +315,9 @@ xwl_glamor_eglstream_destroy_pending_stream(struct xwl_eglstream_pending_stream
b6a310
 static void
b6a310
 xwl_glamor_eglstream_remove_pending_stream(struct xwl_pixmap *xwl_pixmap)
b6a310
 {
b6a310
-    struct xwl_eglstream_private *xwl_eglstream =
b6a310
-        xwl_eglstream_get(xwl_pixmap->xwl_screen);
b6a310
-    struct xwl_eglstream_pending_stream *pending;
b6a310
-
b6a310
-    xorg_list_for_each_entry(pending,
b6a310
-                             &xwl_eglstream->pending_streams, link) {
b6a310
-        if (pending->xwl_pixmap == xwl_pixmap) {
b6a310
-            xwl_glamor_eglstream_destroy_pending_stream(pending);
b6a310
-            break;
b6a310
-        }
b6a310
+    if (xwl_pixmap->pending_stream) {
b6a310
+        xwl_glamor_eglstream_destroy_pending_stream(xwl_pixmap->pending_stream);
b6a310
+        xwl_pixmap->pending_stream = NULL;
b6a310
     }
b6a310
 }
b6a310
 
b6a310
@@ -363,23 +340,41 @@ xwl_glamor_eglstream_get_wl_buffer_for_pixmap(PixmapPtr pixmap)
b6a310
     return xwl_pixmap_get(pixmap)->buffer;
b6a310
 }
b6a310
 
b6a310
+static void
b6a310
+xwl_eglstream_maybe_set_pending_stream_invalid(PixmapPtr pixmap)
b6a310
+{
b6a310
+    struct xwl_pixmap *xwl_pixmap;
b6a310
+    struct xwl_eglstream_pending_stream *pending;
b6a310
+
b6a310
+    xwl_pixmap = xwl_pixmap_get(pixmap);
b6a310
+    if (!xwl_pixmap)
b6a310
+        return;
b6a310
+
b6a310
+    pending = xwl_pixmap->pending_stream;
b6a310
+    if (!pending)
b6a310
+        return;
b6a310
+
b6a310
+    pending->is_valid = FALSE;
b6a310
+}
b6a310
+
b6a310
 static void
b6a310
 xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
b6a310
 {
b6a310
-    struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
b6a310
+    ScreenPtr screen = window->drawable.pScreen;
b6a310
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
b6a310
     struct xwl_eglstream_private *xwl_eglstream =
b6a310
         xwl_eglstream_get(xwl_screen);
b6a310
-    struct xwl_eglstream_pending_stream *pending;
b6a310
+    PixmapPtr old_pixmap;
b6a310
 
b6a310
-    pending = xwl_eglstream_window_get_pending(window);
b6a310
-    if (pending) {
b6a310
-        /* The pixmap for this window has changed before the compositor
b6a310
-         * finished attaching the consumer for the window's pixmap's original
b6a310
-         * eglstream. A producer can no longer be attached, so the stream's
b6a310
-         * useless
b6a310
-         */
b6a310
-        pending->is_valid = FALSE;
b6a310
-    }
b6a310
+    /* The pixmap for this window has changed.
b6a310
+     * If that occurs while there is a stream pending, i.e. before the
b6a310
+     * compositor has finished attaching the consumer for the window's
b6a310
+     * pixmap's original eglstream, then a producer could no longer be
b6a310
+     * attached, so the stream would be useless.
b6a310
+     */
b6a310
+    old_pixmap = (*screen->GetWindowPixmap) (window);
b6a310
+    if (old_pixmap)
b6a310
+        xwl_eglstream_maybe_set_pending_stream_invalid(old_pixmap);
b6a310
 
b6a310
     xwl_screen->screen->SetWindowPixmap = xwl_eglstream->SetWindowPixmap;
b6a310
     (*xwl_screen->screen->SetWindowPixmap)(window, pixmap);
b6a310
@@ -489,16 +484,18 @@ xwl_eglstream_print_error(EGLDisplay egl_display,
b6a310
  * - Receive pixmap B's stream callback, fall over and fail because the
b6a310
  *   window's surface now incorrectly has pixmap A's stream attached to it.
b6a310
  *
b6a310
- * We work around this problem by keeping a queue of pending streams, and
b6a310
- * only allowing one queue entry to exist for each window. In the scenario
b6a310
- * listed above, this should happen:
b6a310
+ * We work around this problem by keeping a pending stream associated with
b6a310
+ * the xwl_pixmap, which itself is associated with the window pixmap.
b6a310
+ * In the scenario listed above, this should happen:
b6a310
  *
b6a310
  * - Begin processing X events...
b6a310
- * - A window is resized, causing us to add an eglstream (known as eglstream
b6a310
- *   A) waiting for its consumer to finish attachment to be added to the
b6a310
- *   queue.
b6a310
+ * - A window is resized, a new window pixmap is created causing us to
b6a310
+ *   add an eglstream (known as eglstream A) waiting for its consumer
b6a310
+ *   to finish attachment.
b6a310
  * - Resize on same window happens. We invalidate the previously pending
b6a310
- *   stream and add another one to the pending queue (known as eglstream B).
b6a310
+ *   stream on the old window pixmap.
b6a310
+ *   A new window pixmap is attached to the window and another pending
b6a310
+ *   stream is created for that new pixmap (known as eglstream B).
b6a310
  * - Begin processing Wayland events...
b6a310
  * - Receive invalidated callback from compositor for eglstream A, destroy
b6a310
  *   stream.
b6a310
@@ -515,6 +512,7 @@ xwl_eglstream_consumer_ready_callback(void *data,
b6a310
         xwl_eglstream_get(xwl_screen);
b6a310
     struct xwl_pixmap *xwl_pixmap;
b6a310
     struct xwl_eglstream_pending_stream *pending;
b6a310
+    PixmapPtr pixmap;
b6a310
     Bool found = FALSE;
b6a310
 
b6a310
     xorg_list_for_each_entry(pending, &xwl_eglstream->pending_streams, link) {
b6a310
@@ -528,6 +526,9 @@ xwl_eglstream_consumer_ready_callback(void *data,
b6a310
     wl_callback_destroy(callback);
b6a310
     pending->cb = NULL;
b6a310
 
b6a310
+    xwl_pixmap = pending->xwl_pixmap;
b6a310
+    pixmap = pending->pixmap;
b6a310
+
b6a310
     if (!pending->is_valid) {
b6a310
         xwl_eglstream_destroy_pixmap_stream(pending->xwl_pixmap);
b6a310
         goto out;
b6a310
@@ -535,12 +536,11 @@ xwl_eglstream_consumer_ready_callback(void *data,
b6a310
 
b6a310
     xwl_glamor_egl_make_current(xwl_screen);
b6a310
 
b6a310
-    xwl_pixmap = pending->xwl_pixmap;
b6a310
     xwl_pixmap->surface = eglCreateStreamProducerSurfaceKHR(
b6a310
         xwl_screen->egl_display, xwl_eglstream->config,
b6a310
         xwl_pixmap->stream, (int[]) {
b6a310
-            EGL_WIDTH,  pending->pixmap->drawable.width,
b6a310
-            EGL_HEIGHT, pending->pixmap->drawable.height,
b6a310
+            EGL_WIDTH,  pixmap->drawable.width,
b6a310
+            EGL_HEIGHT, pixmap->drawable.height,
b6a310
             EGL_NONE
b6a310
         });
b6a310
 
b6a310
@@ -555,14 +555,14 @@ xwl_eglstream_consumer_ready_callback(void *data,
b6a310
            pending->window->drawable.id, pending->pixmap);
b6a310
 
b6a310
 out:
b6a310
-    xwl_glamor_eglstream_destroy_pending_stream(pending);
b6a310
+    xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap);
b6a310
 }
b6a310
 
b6a310
 static const struct wl_callback_listener consumer_ready_listener = {
b6a310
     xwl_eglstream_consumer_ready_callback
b6a310
 };
b6a310
 
b6a310
-static void
b6a310
+static struct xwl_eglstream_pending_stream *
b6a310
 xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen,
b6a310
                                    WindowPtr window, PixmapPtr pixmap)
b6a310
 {
b6a310
@@ -570,14 +570,8 @@ xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen,
b6a310
         xwl_eglstream_get(xwl_screen);
b6a310
     struct xwl_eglstream_pending_stream *pending_stream;
b6a310
 
b6a310
-#ifdef DEBUG
b6a310
-    if (!xwl_eglstream_window_get_pending(window))
b6a310
-        DebugF("eglstream: win %d begins new eglstream for pixmap %p\n",
b6a310
-               window->drawable.id, pixmap);
b6a310
-    else
b6a310
-        DebugF("eglstream: win %d interrupts and replaces pending eglstream for pixmap %p\n",
b6a310
-               window->drawable.id, pixmap);
b6a310
-#endif
b6a310
+    DebugF("eglstream: win %d queues new pending stream for pixmap %p\n",
b6a310
+           window->drawable.id, pixmap);
b6a310
 
b6a310
     pending_stream = malloc(sizeof(*pending_stream));
b6a310
     pending_stream->window = window;
b6a310
@@ -586,11 +580,12 @@ xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen,
b6a310
     pending_stream->is_valid = TRUE;
b6a310
     xorg_list_init(&pending_stream->link);
b6a310
     xorg_list_add(&pending_stream->link, &xwl_eglstream->pending_streams);
b6a310
-    xwl_eglstream_window_set_pending(window, pending_stream);
b6a310
 
b6a310
     pending_stream->cb = wl_display_sync(xwl_screen->display);
b6a310
     wl_callback_add_listener(pending_stream->cb, &consumer_ready_listener,
b6a310
                              xwl_screen);
b6a310
+
b6a310
+    return pending_stream;
b6a310
 }
b6a310
 
b6a310
 static void
b6a310
@@ -663,7 +658,8 @@ xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen,
b6a310
     wl_eglstream_controller_attach_eglstream_consumer(
b6a310
         xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer);
b6a310
 
b6a310
-    xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap);
b6a310
+    xwl_pixmap->pending_stream =
b6a310
+        xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap);
b6a310
 
b6a310
 fail:
b6a310
     if (stream_fd >= 0)
b6a310
@@ -674,22 +670,19 @@ static Bool
b6a310
 xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window)
b6a310
 {
b6a310
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
b6a310
-    struct xwl_eglstream_pending_stream *pending =
b6a310
-        xwl_eglstream_window_get_pending(xwl_window->window);
b6a310
     PixmapPtr pixmap =
b6a310
         (*xwl_screen->screen->GetWindowPixmap)(xwl_window->window);
b6a310
     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
b6a310
 
b6a310
     if (xwl_pixmap) {
b6a310
+        struct xwl_eglstream_pending_stream *pending = xwl_pixmap->pending_stream;
b6a310
+
b6a310
         if (pending) {
b6a310
             /* Wait for the compositor to finish connecting the consumer for
b6a310
              * this eglstream */
b6a310
-            if (pending->is_valid)
b6a310
-                return FALSE;
b6a310
+            assert(pending->is_valid);
b6a310
 
b6a310
-            /* The pixmap for this window was changed before the compositor
b6a310
-             * finished connecting the eglstream for the window's previous
b6a310
-             * pixmap. Begin creating a new eglstream. */
b6a310
+            return FALSE;
b6a310
         } else {
b6a310
             return TRUE;
b6a310
         }
b6a310
@@ -1190,10 +1183,6 @@ xwl_glamor_eglstream_init_screen(struct xwl_screen *xwl_screen)
b6a310
     xwl_eglstream->SetWindowPixmap = screen->SetWindowPixmap;
b6a310
     screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap;
b6a310
 
b6a310
-    if (!dixRegisterPrivateKey(&xwl_eglstream_window_private_key,
b6a310
-                               PRIVATE_WINDOW, 0))
b6a310
-        return FALSE;
b6a310
-
b6a310
     return TRUE;
b6a310
 }
b6a310
 
b6a310
-- 
b6a310
2.31.1
b6a310