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

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