This change enables to change the window pixmap, and have
xwayland send the correct buffer to the Wayland compositor.

Signed-off-by: Axel Davy <axel.d...@ens.fr>
---
v2: fix indentation and remove a call that had to be in patch 4
 hw/xfree86/xwayland/xwayland-drm.c     | 10 +++-
 hw/xfree86/xwayland/xwayland-private.h | 10 +++-
 hw/xfree86/xwayland/xwayland-window.c  | 83 +++++++++++++++++++++++++++++-----
 hw/xfree86/xwayland/xwayland.c         | 38 ++++++++++------
 4 files changed, 113 insertions(+), 28 deletions(-)

diff --git a/hw/xfree86/xwayland/xwayland-drm.c 
b/hw/xfree86/xwayland/xwayland-drm.c
index 5250857..30ec176 100644
--- a/hw/xfree86/xwayland/xwayland-drm.c
+++ b/hw/xfree86/xwayland/xwayland-drm.c
@@ -217,6 +217,7 @@ xwl_create_window_buffer_drm(struct xwl_window *xwl_window,
     VisualID visual;
     WindowPtr window = xwl_window->window;
     ScreenPtr screen = window->drawable.pScreen;
+    struct wl_buffer *buffer;
     uint32_t format;
     int i;
 
@@ -238,7 +239,7 @@ xwl_create_window_buffer_drm(struct xwl_window *xwl_window,
         break;
     }
 
-    xwl_window->buffer =
+    buffer =
       wl_drm_create_buffer(xwl_window->xwl_screen->drm,
                           name,
                           pixmap->drawable.width,
@@ -246,5 +247,10 @@ xwl_create_window_buffer_drm(struct xwl_window *xwl_window,
                           pixmap->devKind,
                           format);
 
-    return xwl_window->buffer ? Success : BadDrawable;
+    if (!buffer)
+       return BadDrawable;
+
+    xwl_pixmap_attach_buffer(pixmap, buffer);
+
+    return Success;
 }
diff --git a/hw/xfree86/xwayland/xwayland-private.h 
b/hw/xfree86/xwayland/xwayland-private.h
index bdecf8a..853ab3b 100644
--- a/hw/xfree86/xwayland/xwayland-private.h
+++ b/hw/xfree86/xwayland/xwayland-private.h
@@ -29,13 +29,16 @@
 struct xwl_window {
     struct xwl_screen          *xwl_screen;
     struct wl_surface          *surface;
-    struct wl_buffer           *buffer;
     WindowPtr                   window;
     DamagePtr                   damage;
     struct xorg_list            link;
     struct xorg_list            link_damage;
 };
 
+struct xwl_pixmap {
+    struct wl_buffer           *buffer;
+};
+
 struct xwl_output;
 
 struct xwl_screen {
@@ -72,6 +75,7 @@ struct xwl_screen {
     RealizeWindowProcPtr        RealizeWindow;
     UnrealizeWindowProcPtr      UnrealizeWindow;
     SetWindowPixmapProcPtr      SetWindowPixmap;
+    DestroyPixmapProcPtr        DestroyPixmap;
     MoveWindowProcPtr           MoveWindow;
     miPointerSpriteFuncPtr      sprite_funcs;
 };
@@ -135,6 +139,10 @@ void xwl_seat_set_cursor(struct xwl_seat *xwl_seat);
 
 void xwl_output_remove(struct xwl_output *output);
 
+void xwl_pixmap_attach_buffer(PixmapPtr pixmap, struct wl_buffer *buffer);
+struct xwl_pixmap *xwl_window_get_buffer(struct xwl_window *xwl_window);
+struct xwl_window *get_xwl_window(WindowPtr window);
+
 extern const struct xserver_listener xwl_server_listener;
 
 #endif /* _XWAYLAND_PRIVATE_H_ */
diff --git a/hw/xfree86/xwayland/xwayland-window.c 
b/hw/xfree86/xwayland/xwayland-window.c
index a2a8206..1e6c09b 100644
--- a/hw/xfree86/xwayland/xwayland-window.c
+++ b/hw/xfree86/xwayland/xwayland-window.c
@@ -41,6 +41,13 @@
 #include "xserver-client-protocol.h"
 
 static DevPrivateKeyRec xwl_window_private_key;
+static DevPrivateKeyRec xwl_pixmap_private_key;
+
+struct xwl_window *
+get_xwl_window(WindowPtr window)
+{
+    return dixLookupPrivate(&window->devPrivates, &xwl_window_private_key);
+}
 
 static void
 free_pixmap(void *data, struct wl_callback *callback, uint32_t time)
@@ -56,25 +63,38 @@ static const struct wl_callback_listener 
free_pixmap_listener = {
        free_pixmap,
 };
 
+void
+xwl_pixmap_attach_buffer(PixmapPtr pixmap, struct wl_buffer *buffer)
+{
+    struct xwl_pixmap *xwl_pixmap = calloc(sizeof *xwl_pixmap, 1);
+    if (!xwl_pixmap) {
+       wl_buffer_destroy(buffer);
+       return;
+    }
+    xwl_pixmap->buffer = buffer;
+    dixSetPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key, xwl_pixmap);
+}
+
 static void
 xwl_window_attach(struct xwl_window *xwl_window, PixmapPtr pixmap)
 {
     struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
     struct wl_callback *callback;
+    struct xwl_pixmap *xwl_pixmap =
+       dixLookupPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key);
 
-    /* We can safely destroy the buffer because we only use one buffer
-     * per surface in xwayland model */
-    if (xwl_window->buffer)
-        wl_buffer_destroy(xwl_window->buffer);
-
-    xwl_screen->driver->create_window_buffer(xwl_window, pixmap);
+    if (!xwl_pixmap) {
+       xwl_screen->driver->create_window_buffer(xwl_window, pixmap);
+       xwl_pixmap =
+           dixLookupPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key);
 
-    if (!xwl_window->buffer) {
-        ErrorF("failed to create buffer\n");
-       return;
+       if (!xwl_pixmap) {
+           ErrorF("failed to create buffer\n");
+           return;
+       }
     }
 
-    wl_surface_attach(xwl_window->surface, xwl_window->buffer, 0, 0);
+    wl_surface_attach(xwl_window->surface, xwl_pixmap->buffer, 0, 0);
     wl_surface_damage(xwl_window->surface, 0, 0,
                      pixmap->drawable.width,
                      pixmap->drawable.height);
@@ -84,6 +104,23 @@ xwl_window_attach(struct xwl_window *xwl_window, PixmapPtr 
pixmap)
     pixmap->refcnt++;
 }
 
+struct xwl_pixmap *
+xwl_window_get_buffer(struct xwl_window *xwl_window)
+{
+    PixmapPtr pixmap = (*xwl_window->xwl_screen->screen->GetWindowPixmap)
+       (xwl_window->window);
+    struct xwl_pixmap *xwl_pixmap =
+       dixLookupPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key);
+
+    if (!xwl_pixmap) {
+       xwl_window_attach(xwl_window, pixmap);
+       return dixLookupPrivate(&pixmap->devPrivates,
+                               &xwl_pixmap_private_key);
+    } else {
+       return xwl_pixmap;
+    }
+}
+
 static void
 damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data)
 {
@@ -184,8 +221,6 @@ xwl_unrealize_window(WindowPtr window)
     if (!xwl_window)
        return ret;
 
-    if (xwl_window->buffer)
-       wl_buffer_destroy(xwl_window->buffer);
     wl_surface_destroy(xwl_window->surface);
     xorg_list_del(&xwl_window->link);
     if (RegionNotEmpty(DamageRegion(xwl_window->damage)))
@@ -218,6 +253,24 @@ xwl_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
        xwl_window_attach(xwl_window, pixmap);
 }
 
+static Bool
+xwl_destroy_pixmap(PixmapPtr pixmap)
+{
+    ScreenPtr screen = pixmap->drawable.pScreen;
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    if (pixmap->refcnt == 1) {
+       struct xwl_pixmap *xwl_pixmap =
+           dixLookupPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key);
+       if (xwl_pixmap) {
+           wl_buffer_destroy(xwl_pixmap->buffer);
+           dixSetPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key,
+                         NULL);
+           free(xwl_pixmap);
+       }
+    }
+    return xwl_screen->DestroyPixmap(pixmap);
+}
+
 static void
 xwl_move_window(WindowPtr window, int x, int y,
                   WindowPtr sibling, VTKind kind)
@@ -245,6 +298,9 @@ xwl_screen_init_window(struct xwl_screen *xwl_screen, 
ScreenPtr screen)
     if (!dixRegisterPrivateKey(&xwl_window_private_key, PRIVATE_WINDOW, 0))
        return BadAlloc;
 
+    if (!dixRegisterPrivateKey(&xwl_pixmap_private_key, PRIVATE_PIXMAP, 0))
+       return BadAlloc;
+
     xwl_screen->RealizeWindow = screen->RealizeWindow;
     screen->RealizeWindow = xwl_realize_window;
 
@@ -254,6 +310,9 @@ xwl_screen_init_window(struct xwl_screen *xwl_screen, 
ScreenPtr screen)
     xwl_screen->SetWindowPixmap = screen->SetWindowPixmap;
     screen->SetWindowPixmap = xwl_set_window_pixmap;
 
+    xwl_screen->DestroyPixmap = screen->DestroyPixmap;
+    screen->DestroyPixmap = xwl_destroy_pixmap;
+
     xwl_screen->MoveWindow = screen->MoveWindow;
     screen->MoveWindow = xwl_move_window;
 
diff --git a/hw/xfree86/xwayland/xwayland.c b/hw/xfree86/xwayland/xwayland.c
index c70a52d..15308b0 100644
--- a/hw/xfree86/xwayland/xwayland.c
+++ b/hw/xfree86/xwayland/xwayland.c
@@ -247,6 +247,7 @@ xwl_create_window_buffer_shm(struct xwl_window *xwl_window,
     WindowPtr window = xwl_window->window;
     ScreenPtr screen = window->drawable.pScreen;
     VisualID visual = wVisual(window);
+    struct wl_buffer *buffer;
     uint32_t format;
     int size, stride, bpp, i;
 
@@ -277,13 +278,18 @@ xwl_create_window_buffer_shm(struct xwl_window 
*xwl_window,
     size = stride * pixmap->drawable.height;
 
     pool = wl_shm_create_pool(xwl_window->xwl_screen->shm, fd, size);
-    xwl_window->buffer =  wl_shm_pool_create_buffer(pool, 0,
+    buffer =  wl_shm_pool_create_buffer(pool, 0,
                           pixmap->drawable.width,
                           pixmap->drawable.height,
                           stride, format);
     wl_shm_pool_destroy(pool);
 
-    return xwl_window->buffer ? Success : BadDrawable;
+    if (!buffer)
+       return BadDrawable;
+
+    xwl_pixmap_attach_buffer(pixmap, buffer);
+
+    return Success;
 }
 
 void xwl_screen_close(struct xwl_screen *xwl_screen)
@@ -302,7 +308,6 @@ void xwl_screen_close(struct xwl_screen *xwl_screen)
     }
     xorg_list_for_each_entry_safe(xwl_window, wtmp,
                                  &xwl_screen->window_list, link) {
-       wl_buffer_destroy(xwl_window->buffer);
        wl_surface_destroy(xwl_window->surface);
        free(xwl_window);
     }
@@ -334,22 +339,29 @@ void xwl_screen_post_damage(struct xwl_screen *xwl_screen)
     RegionPtr region;
     BoxPtr box;
     int count, i;
+    struct xwl_pixmap *xwl_pixmap;
 
     xorg_list_for_each_entry(xwl_window, &xwl_screen->damage_window_list,
                             link_damage) {
        region = DamageRegion(xwl_window->damage);
        count = RegionNumRects(region);
-       for (i = 0; i < count; i++) {
-           box = &RegionRects(region)[i];
-           wl_surface_damage(xwl_window->surface,
-                             box->x1, box->y1,
-                             box->x2 - box->x1,
-                             box->y2 - box->y1);
+       xwl_pixmap = xwl_window_get_buffer(xwl_window);
+       /* in the case we have no xwl_buffer associated to a xwl_window,
+        * because of incompatible pixmap, or memory shortage, we are
+        * going to retry later to create the buffer */
+       if (xwl_pixmap) {
+           for (i = 0; i < count; i++) {
+               box = &RegionRects(region)[i];
+               wl_surface_damage(xwl_window->surface,
+                                 box->x1, box->y1,
+                                 box->x2 - box->x1,
+                                 box->y2 - box->y1);
+           }
+           wl_surface_attach(xwl_window->surface,
+                             xwl_pixmap->buffer,
+                             0, 0);
+           wl_surface_commit(xwl_window->surface);
        }
-       wl_surface_attach(xwl_window->surface,
-                         xwl_window->buffer,
-                         0, 0);
-       wl_surface_commit(xwl_window->surface);
        DamageEmpty(xwl_window->damage);
     }
 
-- 
1.8.3.2

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to