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

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