Blame SOURCES/0002-xwayland-eglstream-Remove-stream-validity.patch

9ca68e
From d9005a02e9c109e57dcc81b51de3b5778915af26 Mon Sep 17 00:00:00 2001
9ca68e
From: Olivier Fourdan <ofourdan@redhat.com>
9ca68e
Date: Fri, 30 Apr 2021 09:56:05 +0200
9ca68e
Subject: [PATCH xserver 2/2] xwayland/eglstream: Remove stream validity
9ca68e
MIME-Version: 1.0
9ca68e
Content-Type: text/plain; charset=UTF-8
9ca68e
Content-Transfer-Encoding: 8bit
9ca68e
9ca68e
To avoid an EGL stream in the wrong state, if the window pixmap changed
9ca68e
before the stream was connected, we would still keep the pending stream
9ca68e
but mark it as invalid. Once the callback is received, the pending would
9ca68e
be simply discarded.
9ca68e
9ca68e
But all of this is actually to avoid a bug in egl-wayland, there should
9ca68e
not be any problem with Xwayland destroying an EGL stream while the
9ca68e
compositor is still using it.
9ca68e
9ca68e
With that bug now fixed in egl-wayland 1.1.7, we can safely drop all
9ca68e
that logic from Xwayland EGLstream backend.
9ca68e
9ca68e
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
9ca68e
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
9ca68e
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1189
9ca68e
(cherry picked from commit 7d509b6f342d9732b567dc4efa867ea24919853b)
9ca68e
---
9ca68e
 hw/xwayland/xwayland-glamor-eglstream.c | 165 ++++--------------------
9ca68e
 1 file changed, 28 insertions(+), 137 deletions(-)
9ca68e
9ca68e
diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c
9ca68e
index 2eae9494c..8d18caaf5 100644
9ca68e
--- a/hw/xwayland/xwayland-glamor-eglstream.c
9ca68e
+++ b/hw/xwayland/xwayland-glamor-eglstream.c
9ca68e
@@ -52,15 +52,6 @@
9ca68e
 #include "wayland-eglstream-controller-client-protocol.h"
9ca68e
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
9ca68e
 
9ca68e
-struct xwl_eglstream_pending_stream {
9ca68e
-    PixmapPtr pixmap;
9ca68e
-    WindowPtr window;
9ca68e
-
9ca68e
-    struct wl_callback *cb;
9ca68e
-
9ca68e
-    Bool is_valid;
9ca68e
-};
9ca68e
-
9ca68e
 struct xwl_eglstream_private {
9ca68e
     EGLDeviceEXT egl_device;
9ca68e
     struct wl_eglstream_display *display;
9ca68e
@@ -90,7 +81,7 @@ struct xwl_pixmap {
9ca68e
     /* add any new <= 4-byte member here to avoid holes on 64-bit */
9ca68e
     struct xwl_screen *xwl_screen;
9ca68e
     struct wl_buffer *buffer;
9ca68e
-    struct xwl_eglstream_pending_stream *pending_stream;
9ca68e
+    struct wl_callback *pending_cb;
9ca68e
     Bool wait_for_buffer_release;
9ca68e
 
9ca68e
     /* XWL_PIXMAP_EGLSTREAM. */
9ca68e
@@ -301,20 +292,12 @@ xwl_eglstream_destroy_pixmap_stream(struct xwl_pixmap *xwl_pixmap)
9ca68e
     free(xwl_pixmap);
9ca68e
 }
9ca68e
 
9ca68e
-static void
9ca68e
-xwl_glamor_eglstream_destroy_pending_stream(struct xwl_eglstream_pending_stream *pending)
9ca68e
-{
9ca68e
-    if (pending->cb)
9ca68e
-        wl_callback_destroy(pending->cb);
9ca68e
-    free(pending);
9ca68e
-}
9ca68e
-
9ca68e
 static void
9ca68e
 xwl_glamor_eglstream_remove_pending_stream(struct xwl_pixmap *xwl_pixmap)
9ca68e
 {
9ca68e
-    if (xwl_pixmap->pending_stream) {
9ca68e
-        xwl_glamor_eglstream_destroy_pending_stream(xwl_pixmap->pending_stream);
9ca68e
-        xwl_pixmap->pending_stream = NULL;
9ca68e
+    if (xwl_pixmap->pending_cb) {
9ca68e
+        wl_callback_destroy(xwl_pixmap->pending_cb);
9ca68e
+        xwl_pixmap->pending_cb = NULL;
9ca68e
     }
9ca68e
 }
9ca68e
 
9ca68e
@@ -338,27 +321,13 @@ xwl_glamor_eglstream_get_wl_buffer_for_pixmap(PixmapPtr pixmap)
9ca68e
 }
9ca68e
 
9ca68e
 static void
9ca68e
-xwl_eglstream_maybe_set_pending_stream_invalid(PixmapPtr pixmap)
9ca68e
+xwl_eglstream_cancel_pending_stream(PixmapPtr pixmap)
9ca68e
 {
9ca68e
     struct xwl_pixmap *xwl_pixmap;
9ca68e
-    struct xwl_eglstream_pending_stream *pending;
9ca68e
 
9ca68e
     xwl_pixmap = xwl_pixmap_get(pixmap);
9ca68e
-    if (!xwl_pixmap)
9ca68e
-        return;
9ca68e
-
9ca68e
-    pending = xwl_pixmap->pending_stream;
9ca68e
-    if (!pending)
9ca68e
-        return;
9ca68e
-
9ca68e
-    pending->is_valid = FALSE;
9ca68e
-
9ca68e
-    /* The compositor may still be using the stream, so we can't destroy
9ca68e
-     * it yet. We'll only have a guarantee that the stream is safe to
9ca68e
-     * destroy once we receive the pending wl_display_sync() for this
9ca68e
-     * stream
9ca68e
-     */
9ca68e
-    pending->pixmap->refcnt++;
9ca68e
+    if (xwl_pixmap)
9ca68e
+        xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap);
9ca68e
 }
9ca68e
 
9ca68e
 static void
9ca68e
@@ -378,7 +347,7 @@ xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
9ca68e
      */
9ca68e
     old_pixmap = (*screen->GetWindowPixmap) (window);
9ca68e
     if (old_pixmap && old_pixmap != pixmap)
9ca68e
-        xwl_eglstream_maybe_set_pending_stream_invalid(old_pixmap);
9ca68e
+        xwl_eglstream_cancel_pending_stream(old_pixmap);
9ca68e
 
9ca68e
     xwl_screen->screen->SetWindowPixmap = xwl_eglstream->SetWindowPixmap;
9ca68e
     (*xwl_screen->screen->SetWindowPixmap)(window, pixmap);
9ca68e
@@ -464,68 +433,19 @@ xwl_eglstream_print_error(EGLDisplay egl_display,
9ca68e
     }
9ca68e
 }
9ca68e
 
9ca68e
-/* Because we run asynchronously with our wayland compositor, it's possible
9ca68e
- * that an X client event could cause us to begin creating a stream for a
9ca68e
- * pixmap/window combo before the stream for the pixmap this window
9ca68e
- * previously used has been fully initialized. An example:
9ca68e
- *
9ca68e
- * - Start processing X client events.
9ca68e
- * - X window receives resize event, causing us to create a new pixmap and
9ca68e
- *   begin creating the corresponding eglstream. This pixmap is known as
9ca68e
- *   pixmap A.
9ca68e
- * - X window receives another resize event, and again changes its current
9ca68e
- *   pixmap causing us to create another corresponding eglstream for the same
9ca68e
- *   window. This pixmap is known as pixmap B.
9ca68e
- * - Start handling events from the wayland compositor.
9ca68e
- *
9ca68e
- * Since both pixmap A and B will have scheduled wl_display_sync events to
9ca68e
- * indicate when their respective streams are connected, we will receive each
9ca68e
- * callback in the original order the pixmaps were created. This means the
9ca68e
- * following would happen:
9ca68e
- *
9ca68e
- * - Receive pixmap A's stream callback, attach its stream to the surface of
9ca68e
- *   the window that just orphaned it.
9ca68e
- * - Receive pixmap B's stream callback, fall over and fail because the
9ca68e
- *   window's surface now incorrectly has pixmap A's stream attached to it.
9ca68e
- *
9ca68e
- * We work around this problem by keeping a pending stream associated with
9ca68e
- * the xwl_pixmap, which itself is associated with the window pixmap.
9ca68e
- * In the scenario listed above, this should happen:
9ca68e
- *
9ca68e
- * - Begin processing X events...
9ca68e
- * - A window is resized, a new window pixmap is created causing us to
9ca68e
- *   add an eglstream (known as eglstream A) waiting for its consumer
9ca68e
- *   to finish attachment.
9ca68e
- * - Resize on same window happens. We invalidate the previously pending
9ca68e
- *   stream on the old window pixmap.
9ca68e
- *   A new window pixmap is attached to the window and another pending
9ca68e
- *   stream is created for that new pixmap (known as eglstream B).
9ca68e
- * - Begin processing Wayland events...
9ca68e
- * - Receive invalidated callback from compositor for eglstream A, destroy
9ca68e
- *   stream.
9ca68e
- * - Receive callback from compositor for eglstream B, create producer.
9ca68e
- * - Success!
9ca68e
- */
9ca68e
 static void
9ca68e
 xwl_eglstream_consumer_ready_callback(void *data,
9ca68e
                                       struct wl_callback *callback,
9ca68e
                                       uint32_t time)
9ca68e
 {
9ca68e
-    struct xwl_eglstream_pending_stream *pending = data;
9ca68e
-    PixmapPtr pixmap = pending->pixmap;
9ca68e
+    PixmapPtr pixmap = data;
9ca68e
     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
9ca68e
     struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen;
9ca68e
     struct xwl_eglstream_private *xwl_eglstream =
9ca68e
         xwl_eglstream_get(xwl_screen);
9ca68e
 
9ca68e
     wl_callback_destroy(callback);
9ca68e
-    pending->cb = NULL;
9ca68e
-
9ca68e
-    if (!pending->is_valid) {
9ca68e
-        xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap);
9ca68e
-        dixDestroyPixmap(pixmap, 0);
9ca68e
-        return;
9ca68e
-    }
9ca68e
+    xwl_pixmap->pending_cb = NULL;
9ca68e
 
9ca68e
     xwl_glamor_egl_make_current(xwl_screen);
9ca68e
 
9ca68e
@@ -541,42 +461,16 @@ xwl_eglstream_consumer_ready_callback(void *data,
9ca68e
         ErrorF("eglstream: Failed to create EGLSurface for pixmap\n");
9ca68e
         xwl_eglstream_print_error(xwl_screen->egl_display,
9ca68e
                                   xwl_pixmap->stream, eglGetError());
9ca68e
-        goto out;
9ca68e
+    } else {
9ca68e
+        DebugF("eglstream: completes eglstream for pixmap %p, congrats!\n",
9ca68e
+               pixmap);
9ca68e
     }
9ca68e
-
9ca68e
-    DebugF("eglstream: win %d completes eglstream for pixmap %p, congrats!\n",
9ca68e
-           pending->window->drawable.id, pending->pixmap);
9ca68e
-
9ca68e
-out:
9ca68e
-    xwl_glamor_eglstream_remove_pending_stream(xwl_pixmap);
9ca68e
 }
9ca68e
 
9ca68e
 static const struct wl_callback_listener consumer_ready_listener = {
9ca68e
     xwl_eglstream_consumer_ready_callback
9ca68e
 };
9ca68e
 
9ca68e
-static struct xwl_eglstream_pending_stream *
9ca68e
-xwl_eglstream_queue_pending_stream(WindowPtr window, PixmapPtr pixmap)
9ca68e
-{
9ca68e
-    struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
9ca68e
-    struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen;
9ca68e
-    struct xwl_eglstream_pending_stream *pending_stream;
9ca68e
-
9ca68e
-    DebugF("eglstream: win %d queues new pending stream for pixmap %p\n",
9ca68e
-           window->drawable.id, pixmap);
9ca68e
-
9ca68e
-    pending_stream = calloc(1, sizeof(*pending_stream));
9ca68e
-    pending_stream->window = window;
9ca68e
-    pending_stream->pixmap = pixmap;
9ca68e
-    pending_stream->is_valid = TRUE;
9ca68e
-
9ca68e
-    pending_stream->cb = wl_display_sync(xwl_screen->display);
9ca68e
-    wl_callback_add_listener(pending_stream->cb, &consumer_ready_listener,
9ca68e
-                             pending_stream);
9ca68e
-
9ca68e
-    return pending_stream;
9ca68e
-}
9ca68e
-
9ca68e
 static void
9ca68e
 xwl_eglstream_buffer_release_callback(void *data)
9ca68e
 {
9ca68e
@@ -656,9 +550,9 @@ xwl_eglstream_create_pixmap_and_stream(struct xwl_screen *xwl_screen,
9ca68e
     wl_eglstream_controller_attach_eglstream_consumer(
9ca68e
         xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer);
9ca68e
 
9ca68e
-    xwl_pixmap->pending_stream =
9ca68e
-        xwl_eglstream_queue_pending_stream(window, pixmap);
9ca68e
-
9ca68e
+    xwl_pixmap->pending_cb = wl_display_sync(xwl_screen->display);
9ca68e
+    wl_callback_add_listener(xwl_pixmap->pending_cb, &consumer_ready_listener,
9ca68e
+                             pixmap);
9ca68e
 fail:
9ca68e
     if (stream_fd >= 0)
9ca68e
         close(stream_fd);
9ca68e
@@ -673,25 +567,22 @@ xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window)
9ca68e
     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
9ca68e
 
9ca68e
     if (xwl_pixmap) {
9ca68e
-        struct xwl_eglstream_pending_stream *pending = xwl_pixmap->pending_stream;
9ca68e
-
9ca68e
-        if (pending) {
9ca68e
+        if (xwl_pixmap->pending_cb) {
9ca68e
             /* Wait for the compositor to finish connecting the consumer for
9ca68e
              * this eglstream */
9ca68e
-            assert(pending->is_valid);
9ca68e
-
9ca68e
             return FALSE;
9ca68e
-        } else {
9ca68e
-            if (xwl_pixmap->surface != EGL_NO_SURFACE ||
9ca68e
-                xwl_pixmap->type == XWL_PIXMAP_DMA_BUF)
9ca68e
-                return TRUE;
9ca68e
-
9ca68e
-            /* The pending stream got removed, we have a xwl_pixmap and
9ca68e
-             * yet we do not have a surface.
9ca68e
-             * So something went wrong with the surface creation, retry.
9ca68e
-             */
9ca68e
-            xwl_eglstream_destroy_pixmap_stream(xwl_pixmap);
9ca68e
         }
9ca68e
+
9ca68e
+        if (xwl_pixmap->surface != EGL_NO_SURFACE ||
9ca68e
+            xwl_pixmap->type == XWL_PIXMAP_DMA_BUF) {
9ca68e
+            return TRUE;
9ca68e
+        }
9ca68e
+
9ca68e
+        /* The pending stream got removed, we have a xwl_pixmap and
9ca68e
+         * yet we do not have a surface.
9ca68e
+         * So something went wrong with the surface creation, retry.
9ca68e
+         */
9ca68e
+         xwl_eglstream_destroy_pixmap_stream(xwl_pixmap);
9ca68e
     }
9ca68e
 
9ca68e
     /* Glamor pixmap has no backing stream yet; begin making one and disallow
9ca68e
-- 
9ca68e
2.31.1
9ca68e