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

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