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

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