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

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