xserver: Branch 'master' - 3 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Nov 29 08:57:07 UTC 2019


 hw/xwayland/Makefile.am                 |    2 
 hw/xwayland/meson.build                 |    2 
 hw/xwayland/xwayland-glamor-eglstream.c |   12 -
 hw/xwayland/xwayland-glamor-gbm.c       |   10 
 hw/xwayland/xwayland-present.c          |   16 -
 hw/xwayland/xwayland-shm.c              |    8 
 hw/xwayland/xwayland-window-buffers.c   |  330 ++++++++++++++++++++++++++++++++
 hw/xwayland/xwayland-window-buffers.h   |   38 +++
 hw/xwayland/xwayland.c                  |   69 ++++++
 hw/xwayland/xwayland.h                  |    9 
 10 files changed, 480 insertions(+), 16 deletions(-)

New commits:
commit cd999f08c608458d6207110ed237c3a78441870b
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Fri Oct 25 16:28:50 2019 +0200

    xwayland: Use multiple window buffers
    
    Xwayland takes care of not attaching a new buffer if a frame callback is
    pending.
    
    Yet, the existing buffer (which was previously attached) may still be
    updated from the X11 side, causing unexpected visual glitches to the
    buffer.
    
    Add multiple buffering to the xwl_window and alternate between buffers,
    to leave the Wayland buffer untouched between frame callbacks and avoid
    stuttering or tearing issues.
    
    Closes: https://gitlab.freedesktop.org/xorg/xserver/issues/835
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>

diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 3ec754047..fc7932f67 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -24,6 +24,7 @@
  */
 
 #include "xwayland.h"
+#include "xwayland-window-buffers.h"
 
 #include <stdio.h>
 
@@ -902,6 +903,8 @@ ensure_surface_for_window(WindowPtr window)
     xorg_list_init(&xwl_window->link_damage);
     xorg_list_add(&xwl_window->link_window, &xwl_screen->window_list);
 
+    xwl_window_buffers_init(xwl_window);
+
     xwl_window_init_allow_commits(xwl_window);
 
     return TRUE;
@@ -1005,6 +1008,8 @@ xwl_unrealize_window(WindowPtr window)
     xorg_list_del(&xwl_window->link_window);
     unregister_damage(window);
 
+    xwl_window_buffers_dispose(xwl_window);
+
     if (xwl_window->frame_callback)
         wl_callback_destroy(xwl_window->frame_callback);
 
@@ -1053,6 +1058,7 @@ xwl_resize_window(WindowPtr window,
     screen->ResizeWindow = xwl_resize_window;
 
     if (xwl_window) {
+        xwl_window_buffers_recycle(xwl_window);
         xwl_window->x = x;
         xwl_window->y = y;
         xwl_window->width = width;
@@ -1124,7 +1130,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
     assert(!xwl_window->frame_callback);
 
     region = DamageRegion(window_get_damage(xwl_window->window));
-    pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window);
+    pixmap = xwl_window_buffers_get_pixmap(xwl_window, region);
 
 #ifdef XWL_HAS_GLAMOR
     if (xwl_screen->glamor)
commit 1c6f875f52d74d2137161399e134c4888c4eadf2
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Nov 6 11:49:33 2019 +0100

    xwayland: Add multiple window buffering support
    
    Add a mechanism to create, recycle and destroy window buffers when
    needed.
    
    Typically, this adds a new `xwl_window_buffer` structure which
    represents a buffer for a given Xwayland window.
    
    Each Xwayland window has two different pools of buffers:
    
     - The available buffers pool:
       Those are buffers which where created previously and that have either
       not been submitted to the compositor or submitted and released.
    
     - The unavailable buffers pool:
       Those are typically the buffers which are being used by the
       compositor, awaiting a release.
    
    Initially, an Xwayland window starts with both pools empty. As soon as a
    new buffer is needed, it's either created (if there is none available)
    or picked from the pool of available buffers.
    
    Once submitted to the compositor, the buffer is moved to the pool of
    unavailable buffers. When the corresponding `wl_buffer` is released by
    the compositor, it is moved back to pool of available buffers again to
    be reused when needed.
    
    To avoid keeping too many buffers around doing nothing, a garbage
    collection of older, unused buffers also takes care of disposing the
    buffers being unused for some time.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>

diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 8366cc222..042906074 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -17,6 +17,8 @@ Xwayland_SOURCES =				\
 	xwayland-output.c			\
 	xwayland-cvt.c				\
 	xwayland-vidmode.c			\
+	xwayland-window-buffers.c		\
+	xwayland-window-buffers.h		\
 	xwayland.h				\
 	$(top_srcdir)/Xi/stubs.c		\
 	$(top_srcdir)/mi/miinitext.c
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index 4cea5d792..6b76c494e 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -6,6 +6,8 @@ srcs = [
     'xwayland-output.c',
     'xwayland-cvt.c',
     'xwayland-vidmode.c',
+    'xwayland-window-buffers.c',
+    'xwayland-window-buffers.h',
     '../../mi/miinitext.c',
 ]
 
diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c
new file mode 100644
index 000000000..62999091d
--- /dev/null
+++ b/hw/xwayland/xwayland-window-buffers.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *      Olivier Fourdan <ofourdan at redhat.com>
+ */
+
+#include "xwayland-window-buffers.h"
+
+#define BUFFER_TIMEOUT 1 * 1000 /* ms */
+
+struct xwl_window_buffer {
+    struct xwl_window *xwl_window;
+    PixmapPtr pixmap;
+    RegionPtr damage_region;
+    Bool recycle_on_release;
+    uint32_t time;
+    struct xorg_list link_buffer;
+};
+
+static Bool
+copy_pixmap_area(PixmapPtr src_pixmap, PixmapPtr dst_pixmap,
+                 int x, int y, int width, int height)
+{
+    GCPtr pGC;
+    pGC = GetScratchGC(dst_pixmap->drawable.depth,
+                       dst_pixmap->drawable.pScreen);
+    if (pGC) {
+        ValidateGC(&dst_pixmap->drawable, pGC);
+        (void) (*pGC->ops->CopyArea) (&src_pixmap->drawable,
+                                      &dst_pixmap->drawable,
+                                      pGC,
+                                      x, y,
+                                      width, height,
+                                      x, y);
+        FreeScratchGC(pGC);
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static struct xwl_window_buffer *
+xwl_window_buffer_new(struct xwl_window *xwl_window)
+{
+    struct xwl_window_buffer *xwl_window_buffer;
+
+    xwl_window_buffer = calloc (1, sizeof(struct xwl_window_buffer));
+    if (!xwl_window_buffer)
+        return NULL;
+
+    xwl_window_buffer->xwl_window = xwl_window;
+    xwl_window_buffer->damage_region = RegionCreate(NullBox, 1);
+    xwl_window_buffer->pixmap = NullPixmap;
+
+    xorg_list_append(&xwl_window_buffer->link_buffer,
+                     &xwl_window->window_buffers_available);
+
+    return xwl_window_buffer;
+}
+
+static void
+xwl_window_buffer_destroy_pixmap(struct xwl_window_buffer *xwl_window_buffer)
+{
+    ScreenPtr pScreen = xwl_window_buffer->pixmap->drawable.pScreen;
+
+    xwl_pixmap_del_buffer_release_cb(xwl_window_buffer->pixmap);
+    (*pScreen->DestroyPixmap) (xwl_window_buffer->pixmap);
+    xwl_window_buffer->pixmap = NullPixmap;
+}
+
+static void
+xwl_window_buffer_dispose(struct xwl_window_buffer *xwl_window_buffer)
+{
+    RegionDestroy(xwl_window_buffer->damage_region);
+
+    if (xwl_window_buffer->pixmap)
+        xwl_window_buffer_destroy_pixmap (xwl_window_buffer);
+
+    xorg_list_del(&xwl_window_buffer->link_buffer);
+    free(xwl_window_buffer);
+}
+
+static void
+xwl_window_buffer_recycle(struct xwl_window_buffer *xwl_window_buffer)
+{
+    RegionEmpty(xwl_window_buffer->damage_region);
+    xwl_window_buffer->recycle_on_release = FALSE;
+
+    if (xwl_window_buffer->pixmap)
+        xwl_window_buffer_destroy_pixmap (xwl_window_buffer);
+}
+
+static void
+xwl_window_buffer_add_damage_region(struct xwl_window *xwl_window,
+                                    RegionPtr damage_region)
+{
+    struct xwl_window_buffer *xwl_window_buffer;
+
+    /* Add damage region to all buffers */
+    xorg_list_for_each_entry(xwl_window_buffer,
+                             &xwl_window->window_buffers_available,
+                             link_buffer) {
+        RegionUnion(xwl_window_buffer->damage_region,
+                    xwl_window_buffer->damage_region,
+                    damage_region);
+    }
+    xorg_list_for_each_entry(xwl_window_buffer,
+                             &xwl_window->window_buffers_unavailable,
+                             link_buffer) {
+        RegionUnion(xwl_window_buffer->damage_region,
+                    xwl_window_buffer->damage_region,
+                    damage_region);
+    }
+}
+
+static struct xwl_window_buffer *
+xwl_window_buffer_get_available(struct xwl_window *xwl_window)
+{
+    if (xorg_list_is_empty(&xwl_window->window_buffers_available))
+        return xwl_window_buffer_new(xwl_window);
+
+    return xorg_list_last_entry(&xwl_window->window_buffers_available,
+                                struct xwl_window_buffer,
+                                link_buffer);
+}
+
+static CARD32
+xwl_window_buffer_timer_callback(OsTimerPtr timer, CARD32 time, void *arg)
+{
+    struct xwl_window *xwl_window = arg;
+    struct xwl_window_buffer *xwl_window_buffer, *tmp;
+
+    /* Dispose older available buffers */
+    xorg_list_for_each_entry_safe(xwl_window_buffer, tmp,
+                                  &xwl_window->window_buffers_available,
+                                  link_buffer) {
+        if ((int64_t)(time - xwl_window_buffer->time) >= BUFFER_TIMEOUT)
+            xwl_window_buffer_dispose(xwl_window_buffer);
+    }
+
+    /* If there are still available buffers, re-arm the timer */
+    if (!xorg_list_is_empty(&xwl_window->window_buffers_available)) {
+        struct xwl_window_buffer *oldest_available_buffer =
+            xorg_list_first_entry(&xwl_window->window_buffers_available,
+                                  struct xwl_window_buffer,
+                                  link_buffer);
+
+        return oldest_available_buffer->time + BUFFER_TIMEOUT - time;
+    }
+
+    /* Don't re-arm the timer */
+    return 0;
+}
+
+static void
+xwl_window_buffer_release_callback(PixmapPtr pixmap, void *data)
+{
+    struct xwl_window_buffer *xwl_window_buffer = data;
+    struct xwl_window *xwl_window = xwl_window_buffer->xwl_window;
+    struct xwl_window_buffer *oldest_available_buffer;
+
+    if (xwl_window_buffer->recycle_on_release)
+        xwl_window_buffer_recycle(xwl_window_buffer);
+
+    /* We append the buffers to the end of the list, as we pick the last
+     * entry again when looking for new available buffers, that means the
+     * least used buffers will remain at the beginning of the list so that
+     * they can be garbage collected automatically after some time unused.
+     */
+
+    xorg_list_del(&xwl_window_buffer->link_buffer);
+    xorg_list_append(&xwl_window_buffer->link_buffer,
+                     &xwl_window->window_buffers_available);
+    xwl_window_buffer->time = (uint32_t) GetTimeInMillis();
+
+    oldest_available_buffer =
+        xorg_list_first_entry(&xwl_window->window_buffers_available,
+                             struct xwl_window_buffer,
+                             link_buffer);
+
+    /* Schedule next timer based on time of the oldest buffer */
+    xwl_window->window_buffers_timer =
+        TimerSet(xwl_window->window_buffers_timer,
+                 TimerAbsolute,
+                 oldest_available_buffer->time + BUFFER_TIMEOUT,
+                 &xwl_window_buffer_timer_callback,
+                 xwl_window);
+}
+
+void
+xwl_window_buffers_init(struct xwl_window *xwl_window)
+{
+    xorg_list_init(&xwl_window->window_buffers_available);
+    xorg_list_init(&xwl_window->window_buffers_unavailable);
+}
+
+void
+xwl_window_buffers_recycle(struct xwl_window *xwl_window)
+{
+    struct xwl_window_buffer *xwl_window_buffer, *tmp;
+
+    /* Dispose available buffers */
+    xorg_list_for_each_entry_safe(xwl_window_buffer, tmp,
+                                  &xwl_window->window_buffers_available,
+                                  link_buffer) {
+        xwl_window_buffer_dispose(xwl_window_buffer);
+    }
+
+    if (xwl_window->window_buffers_timer)
+        TimerCancel(xwl_window->window_buffers_timer);
+
+    /* Mark the others for recycle on release */
+    xorg_list_for_each_entry(xwl_window_buffer,
+                             &xwl_window->window_buffers_unavailable,
+                             link_buffer) {
+        xwl_window_buffer->recycle_on_release = TRUE;
+    }
+}
+
+void
+xwl_window_buffers_dispose(struct xwl_window *xwl_window)
+{
+    struct xwl_window_buffer *xwl_window_buffer, *tmp;
+
+    xorg_list_for_each_entry_safe(xwl_window_buffer, tmp,
+                                  &xwl_window->window_buffers_available,
+                                  link_buffer) {
+        xwl_window_buffer_dispose(xwl_window_buffer);
+    }
+
+    xorg_list_for_each_entry_safe(xwl_window_buffer, tmp,
+                                  &xwl_window->window_buffers_unavailable,
+                                  link_buffer) {
+        xwl_window_buffer_dispose(xwl_window_buffer);
+    }
+
+    if (xwl_window->window_buffers_timer) {
+        TimerFree(xwl_window->window_buffers_timer);
+        xwl_window->window_buffers_timer = 0;
+    }
+}
+
+PixmapPtr
+xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window,
+                              RegionPtr damage_region)
+{
+    struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+    struct xwl_window_buffer *xwl_window_buffer;
+    PixmapPtr window_pixmap;
+    RegionPtr full_damage;
+
+    window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window);
+
+    xwl_window_buffer = xwl_window_buffer_get_available(xwl_window);
+    if (!xwl_window_buffer)
+        return window_pixmap;
+
+    xwl_window_buffer_add_damage_region(xwl_window, damage_region);
+
+    full_damage = xwl_window_buffer->damage_region;
+
+    if (xwl_window_buffer->pixmap) {
+        BoxPtr pBox = RegionRects(full_damage);
+        int nBox = RegionNumRects(full_damage);
+        while (nBox--) {
+            if (!copy_pixmap_area(window_pixmap,
+                                  xwl_window_buffer->pixmap,
+                                  pBox->x1, pBox->y1,
+                                  pBox->x2 - pBox->x1, pBox->y2 - pBox->y1))
+                return window_pixmap;
+
+            pBox++;
+        }
+    } else {
+        xwl_window_buffer->pixmap =
+            (*xwl_screen->screen->CreatePixmap) (window_pixmap->drawable.pScreen,
+                                                 window_pixmap->drawable.width,
+                                                 window_pixmap->drawable.height,
+                                                 window_pixmap->drawable.depth,
+                                                 CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
+
+        if (!xwl_window_buffer->pixmap)
+            return window_pixmap;
+
+        if (!copy_pixmap_area(window_pixmap,
+                              xwl_window_buffer->pixmap,
+                              0, 0,
+                              window_pixmap->drawable.width,
+                              window_pixmap->drawable.height)) {
+            xwl_window_buffer_recycle(xwl_window_buffer);
+            return window_pixmap;
+        }
+    }
+
+    RegionEmpty(xwl_window_buffer->damage_region);
+
+    xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap,
+                                     xwl_window_buffer_release_callback,
+                                     xwl_window_buffer);
+
+    xorg_list_del(&xwl_window_buffer->link_buffer);
+    xorg_list_append(&xwl_window_buffer->link_buffer,
+                     &xwl_window->window_buffers_unavailable);
+
+    if (xorg_list_is_empty(&xwl_window->window_buffers_available))
+        TimerCancel(xwl_window->window_buffers_timer);
+
+    return xwl_window_buffer->pixmap;
+}
diff --git a/hw/xwayland/xwayland-window-buffers.h b/hw/xwayland/xwayland-window-buffers.h
new file mode 100644
index 000000000..c6b2092e3
--- /dev/null
+++ b/hw/xwayland/xwayland-window-buffers.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *      Olivier Fourdan <ofourdan at redhat.com>
+ */
+
+#include "xwayland.h"
+
+#ifndef XWAYLAND_WINDOW_BUFFERS_H
+#define XWAYLAND_WINDOW_BUFFERS_H
+
+void xwl_window_buffers_init(struct xwl_window *xwl_window);
+void xwl_window_buffers_recycle(struct xwl_window *xwl_window);
+void xwl_window_buffers_dispose(struct xwl_window *xwl_window);
+PixmapPtr xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window,
+                                        RegionPtr damage_region);
+
+#endif /* XWAYLAND_WINDOW_BUFFERS_H */
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 21e833cc9..132dfc10a 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -189,6 +189,9 @@ struct xwl_window {
     struct xorg_list link_window;
     struct wl_callback *frame_callback;
     Bool allow_commits;
+    struct xorg_list window_buffers_available;
+    struct xorg_list window_buffers_unavailable;
+    OsTimerPtr window_buffers_timer;
 #ifdef GLAMOR_HAS_GBM
     Bool present_flipped;
 #endif
commit 77658741869f6a01cec0bdf49827494fb0f06edf
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Oct 30 13:17:34 2019 +0100

    xwayland: Add buffer release callback
    
    The API `wl_buffer_add_listener` is misleading in the sense that there
    can be only one `wl_buffer` release callback, and trying to add a new
    listener when once is already in place will lead to a protocol error.
    
    The Xwayland EGL backends may need to set up their own `wl_buffer`
    release listener, meaning that there is no way to our own `wl_buffer`
    release callback.
    
    To avoid the problem, add our own callback API to be notified when the
    `wl_buffer` associated with an `xwl_pixmap` is released, triggered from
    the different `xwl_pixmap` implementations.
    
    Also update the Present code to use the new buffer release callback API.
    
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>

diff --git a/hw/xwayland/xwayland-glamor-eglstream.c b/hw/xwayland/xwayland-glamor-eglstream.c
index c897c74a8..ed10355ed 100644
--- a/hw/xwayland/xwayland-glamor-eglstream.c
+++ b/hw/xwayland/xwayland-glamor-eglstream.c
@@ -305,9 +305,10 @@ xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap)
 {
     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
 
-    if (xwl_pixmap && pixmap->refcnt == 1)
+    if (xwl_pixmap && pixmap->refcnt == 1) {
+        xwl_pixmap_del_buffer_release_cb(pixmap);
         xwl_eglstream_unref_pixmap_stream(xwl_pixmap);
-
+    }
     return glamor_destroy_pixmap(pixmap);
 }
 
@@ -475,7 +476,10 @@ xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen,
 static void
 xwl_eglstream_buffer_release_callback(void *data, struct wl_buffer *wl_buffer)
 {
-    xwl_eglstream_unref_pixmap_stream(data);
+    struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(data);
+
+    xwl_pixmap_buffer_release_cb(data, wl_buffer);
+    xwl_eglstream_unref_pixmap_stream(xwl_pixmap);
 }
 
 static const struct wl_buffer_listener xwl_eglstream_buffer_release_listener = {
@@ -517,7 +521,7 @@ xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen,
 
     wl_buffer_add_listener(xwl_pixmap->buffer,
                            &xwl_eglstream_buffer_release_listener,
-                           xwl_pixmap);
+                           pixmap);
 
     wl_eglstream_controller_attach_eglstream_consumer(
         xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer);
diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
index e3a4ba382..9b7d6e286 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -260,6 +260,7 @@ xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap)
     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
 
     if (xwl_pixmap && pixmap->refcnt == 1) {
+        xwl_pixmap_del_buffer_release_cb(pixmap);
         if (xwl_pixmap->buffer)
             wl_buffer_destroy(xwl_pixmap->buffer);
 
@@ -272,6 +273,10 @@ xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap)
     return glamor_destroy_pixmap(pixmap);
 }
 
+static const struct wl_buffer_listener xwl_glamor_gbm_buffer_listener = {
+    xwl_pixmap_buffer_release_cb,
+};
+
 static struct wl_buffer *
 xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap,
                                         Bool *created)
@@ -348,6 +353,11 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap,
     }
 
     close(prime_fd);
+
+    /* Add our listener now */
+    wl_buffer_add_listener(xwl_pixmap->buffer,
+                           &xwl_glamor_gbm_buffer_listener, pixmap);
+
     return xwl_pixmap->buffer;
 }
 
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index b7da261b7..7f0b951ab 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -169,13 +169,14 @@ xwl_present_free_event(struct xwl_present_event *event)
 }
 
 static void
-xwl_present_buffer_release(void *data, struct wl_buffer *buffer)
+xwl_present_buffer_release(PixmapPtr pixmap, void *data)
 {
     struct xwl_present_event *event = data;
+
     if (!event)
         return;
 
-    wl_buffer_set_user_data(buffer, NULL);
+    xwl_pixmap_del_buffer_release_cb(pixmap);
     event->buffer_released = TRUE;
 
     if (event->abort) {
@@ -193,10 +194,6 @@ xwl_present_buffer_release(void *data, struct wl_buffer *buffer)
     }
 }
 
-static const struct wl_buffer_listener xwl_present_release_listener = {
-    xwl_present_buffer_release
-};
-
 static void
 xwl_present_msc_bump(struct xwl_present_window *xwl_present_window)
 {
@@ -452,7 +449,6 @@ xwl_present_flip(WindowPtr present_window,
     struct xwl_window           *xwl_window = xwl_window_from_window(present_window);
     struct xwl_present_window   *xwl_present_window = xwl_present_window_priv(present_window);
     BoxPtr                      damage_box;
-    Bool                        buffer_created;
     struct wl_buffer            *buffer;
     struct xwl_present_event    *event;
 
@@ -465,7 +461,7 @@ xwl_present_flip(WindowPtr present_window,
     if (!event)
         return FALSE;
 
-    buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, &buffer_created);
+    buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, NULL);
 
     event->event_id = event_id;
     event->xwl_present_window = xwl_present_window;
@@ -482,9 +478,7 @@ xwl_present_flip(WindowPtr present_window,
         xorg_list_add(&event->list, &xwl_present_window->release_queue);
     }
 
-    if (buffer_created)
-        wl_buffer_add_listener(buffer, &xwl_present_release_listener, NULL);
-    wl_buffer_set_user_data(buffer, event);
+    xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event);
 
     /* We can flip directly to the main surface (full screen window without clips) */
     wl_surface_attach(xwl_window->surface, buffer, 0, 0);
diff --git a/hw/xwayland/xwayland-shm.c b/hw/xwayland/xwayland-shm.c
index bce74fa1d..b76ab1a8f 100644
--- a/hw/xwayland/xwayland-shm.c
+++ b/hw/xwayland/xwayland-shm.c
@@ -189,6 +189,10 @@ shm_format_for_depth(int depth)
     }
 }
 
+static const struct wl_buffer_listener xwl_shm_buffer_listener = {
+    xwl_pixmap_buffer_release_cb,
+};
+
 PixmapPtr
 xwl_shm_create_pixmap(ScreenPtr screen,
                       int width, int height, int depth, unsigned int hint)
@@ -241,6 +245,9 @@ xwl_shm_create_pixmap(ScreenPtr screen,
     wl_shm_pool_destroy(pool);
     close(fd);
 
+    wl_buffer_add_listener(xwl_pixmap->buffer,
+                           &xwl_shm_buffer_listener, pixmap);
+
     xwl_pixmap_set_private(pixmap, xwl_pixmap);
 
     return pixmap;
@@ -263,6 +270,7 @@ xwl_shm_destroy_pixmap(PixmapPtr pixmap)
     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
 
     if (xwl_pixmap && pixmap->refcnt == 1) {
+        xwl_pixmap_del_buffer_release_cb(pixmap);
         if (xwl_pixmap->buffer)
             wl_buffer_destroy(xwl_pixmap->buffer);
         munmap(xwl_pixmap->data, xwl_pixmap->size);
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index acb77a638..3ec754047 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -169,6 +169,7 @@ static DevPrivateKeyRec xwl_client_private_key;
 static DevPrivateKeyRec xwl_window_private_key;
 static DevPrivateKeyRec xwl_screen_private_key;
 static DevPrivateKeyRec xwl_pixmap_private_key;
+static DevPrivateKeyRec xwl_pixmap_cb_private_key;
 static DevPrivateKeyRec xwl_damage_private_key;
 
 struct xwl_client *
@@ -298,6 +299,64 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure,
         xwl_window_property_allow_commits(xwl_window, rec);
 }
 
+struct xwl_pixmap_buffer_release_cb {
+    xwl_pixmap_cb callback;
+    void *data;
+};
+
+Bool
+xwl_pixmap_set_buffer_release_cb(PixmapPtr pixmap,
+                                 xwl_pixmap_cb func, void *data)
+{
+    struct xwl_pixmap_buffer_release_cb *xwl_pixmap_buffer_release_cb;
+
+    xwl_pixmap_buffer_release_cb = dixLookupPrivate(&pixmap->devPrivates,
+                                                    &xwl_pixmap_cb_private_key);
+
+    if (xwl_pixmap_buffer_release_cb == NULL) {
+        xwl_pixmap_buffer_release_cb =
+            calloc(1, sizeof (struct xwl_pixmap_buffer_release_cb));
+
+        if (xwl_pixmap_buffer_release_cb == NULL) {
+            ErrorF("Failed to allocate pixmap callback data\n");
+            return FALSE;
+        }
+        dixSetPrivate(&pixmap->devPrivates, &xwl_pixmap_cb_private_key,
+                      xwl_pixmap_buffer_release_cb);
+    }
+
+    xwl_pixmap_buffer_release_cb->callback = func;
+    xwl_pixmap_buffer_release_cb->data = data;
+
+    return TRUE;
+}
+
+void
+xwl_pixmap_del_buffer_release_cb(PixmapPtr pixmap)
+{
+    struct xwl_pixmap_buffer_release_cb *xwl_pixmap_buffer_release_cb;
+
+    xwl_pixmap_buffer_release_cb = dixLookupPrivate(&pixmap->devPrivates,
+                                                    &xwl_pixmap_cb_private_key);
+    if (xwl_pixmap_buffer_release_cb) {
+        dixSetPrivate(&pixmap->devPrivates, &xwl_pixmap_cb_private_key, NULL);
+        free(xwl_pixmap_buffer_release_cb);
+    }
+}
+
+void
+xwl_pixmap_buffer_release_cb(void *data, struct wl_buffer *wl_buffer)
+{
+    PixmapPtr pixmap = data;
+    struct xwl_pixmap_buffer_release_cb *xwl_pixmap_buffer_release_cb;
+
+    xwl_pixmap_buffer_release_cb = dixLookupPrivate(&pixmap->devPrivates,
+                                                    &xwl_pixmap_cb_private_key);
+    if (xwl_pixmap_buffer_release_cb)
+        (*xwl_pixmap_buffer_release_cb->callback)
+            (pixmap, xwl_pixmap_buffer_release_cb->data);
+}
+
 static Bool
 xwl_close_screen(ScreenPtr screen)
 {
@@ -1348,6 +1407,8 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
         return FALSE;
     if (!dixRegisterPrivateKey(&xwl_pixmap_private_key, PRIVATE_PIXMAP, 0))
         return FALSE;
+    if (!dixRegisterPrivateKey(&xwl_pixmap_cb_private_key, PRIVATE_PIXMAP, 0))
+        return FALSE;
     if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0))
         return FALSE;
     /* There are no easy to use new / delete client hooks, we could use a
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 9728cc512..21e833cc9 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -60,6 +60,8 @@ struct xwl_pixmap;
 struct xwl_window;
 struct xwl_screen;
 
+typedef void (*xwl_pixmap_cb) (PixmapPtr pixmap, void *data);
+
 struct xwl_egl_backend {
     /* Set by the backend if available */
     Bool is_available;
@@ -461,6 +463,10 @@ RRModePtr xwayland_cvt(int HDisplay, int VDisplay,
 
 void xwl_pixmap_set_private(PixmapPtr pixmap, struct xwl_pixmap *xwl_pixmap);
 struct xwl_pixmap *xwl_pixmap_get(PixmapPtr pixmap);
+Bool xwl_pixmap_set_buffer_release_cb(PixmapPtr pixmap,
+                                      xwl_pixmap_cb func, void *data);
+void xwl_pixmap_del_buffer_release_cb(PixmapPtr pixmap);
+void xwl_pixmap_buffer_release_cb(void *data, struct wl_buffer *wl_buffer);
 
 struct xwl_window *xwl_window_from_window(WindowPtr window);
 


More information about the xorg-commit mailing list