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

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