[PATCH] xwayland: Use drm buffers for cursors if available

Rui Matos tiagomatos at gmail.com
Thu Feb 4 17:10:04 UTC 2016


This should be both more efficient and avoid the file descriptor
exhaustion issue that can happen with shm buffers if we're asked to
realize more cursors than the file descriptor limit.

Signed-off-by: Rui Matos <tiagomatos at gmail.com>
---

On Sat, Dec 5, 2015 at 1:30 AM, Kristian Høgsberg <krh at bitplanet.net> wrote:
> Nice work. I think it would be about the same amount of work to do
> this for shm pixmaps instead of cursors. That way, an application that
> creates a lot of small pixmaps on shm-Xwayland (non-glamor) will also
> not crash the server either.

I looked into doing this for a bit but it seemed very wasteful in
terms of memory usage with this simple allocation algorithm. I fear
the fragmentation after a little while would be pretty bad. At least
with cursors only we know that they're sized all in the same order of
magnitude but for pixmaps in general I think we'd need a smarter
algorithm and a good handful of heuristics.

So, I decided to instead work on adding support for wl_drm cursor
buffers which nicely sidesteps all those issues. Unfortunately, with
this patch and on intel hardware where the hw cursor size isn't 64x64,
compositors have to fallback to "software" cursors, importing the
buffer as an EGLImage since mesa has this size hardcoded in

http://cgit.freedesktop.org/mesa/mesa/tree/src/mesa/drivers/dri/i965/intel_screen.c#n621

which prevents compositors from importing the gbm bo.

Rui

 hw/xwayland/xwayland-cursor.c | 156 ++++++++++++++++++++++++++++++++++++------
 hw/xwayland/xwayland.c        |   6 +-
 2 files changed, 138 insertions(+), 24 deletions(-)

diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index 76729db..7f2aa9a 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -28,7 +28,27 @@
 
 #include <mipointer.h>
 
+#ifdef GLAMOR_HAS_GBM
+#define MESA_EGL_NO_X11_HEADERS
+#include <drm/drm.h>
+#include <gbm.h>
+#include <xf86drm.h>
+#include "drm-client-protocol.h"
+#endif
+
+struct xwl_cursor {
+    struct wl_buffer *buffer;
+    PixmapPtr pixmap;
+#ifdef GLAMOR_HAS_GBM
+    struct gbm_bo *bo;
+#endif
+};
+
 static DevPrivateKeyRec xwl_cursor_private_key;
+#ifdef GLAMOR_HAS_GBM
+static uint64_t hw_cursor_width;
+static uint64_t hw_cursor_height;
+#endif
 
 static void
 expand_source_and_mask(CursorPtr cursor, CARD32 *data)
@@ -61,25 +81,88 @@ expand_source_and_mask(CursorPtr cursor, CARD32 *data)
 }
 
 static Bool
+alloc_gbm_cursor(struct xwl_cursor *cursor, struct xwl_screen *screen, size_t width, size_t height)
+{
+#ifdef GLAMOR_HAS_GBM
+    struct gbm_bo *bo;
+    union gbm_bo_handle handle;
+    int prime_fd = -1;
+
+    if (!screen->glamor)
+        return FALSE;
+    if (width > hw_cursor_width || height > hw_cursor_height)
+        return FALSE;
+
+    bo = gbm_bo_create(screen->gbm, hw_cursor_width, hw_cursor_height,
+                       GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
+    if (!bo)
+        return FALSE;
+
+    handle = gbm_bo_get_handle(bo);
+    if (drmPrimeHandleToFD(screen->drm_fd, handle.u32, 0, &prime_fd) || prime_fd == -1)
+        goto err_free_bo;
+
+    cursor->buffer =
+        wl_drm_create_prime_buffer(screen->drm, prime_fd,
+                                   hw_cursor_width, hw_cursor_height,
+                                   WL_DRM_FORMAT_ARGB8888,
+                                   0, gbm_bo_get_stride(bo),
+                                   0, 0,
+                                   0, 0);
+    close(prime_fd);
+
+    if (!cursor->buffer)
+        goto err_free_bo;
+
+    cursor->bo = bo;
+    return TRUE;
+
+ err_free_bo:
+    gbm_bo_destroy(bo);
+    return FALSE;
+#else
+    return FALSE;
+#endif
+}
+
+static Bool
 xwl_realize_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor)
 {
-    PixmapPtr pixmap;
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_cursor *xwl_cursor;
 
-    pixmap = xwl_shm_create_pixmap(screen, cursor->bits->width,
-                                   cursor->bits->height, 32, 0);
-    dixSetPrivate(&cursor->devPrivates, &xwl_cursor_private_key, pixmap);
+    xwl_cursor = calloc(1, sizeof *xwl_cursor);
+    if (!xwl_cursor)
+        return FALSE;
 
+    if (!alloc_gbm_cursor(xwl_cursor, xwl_screen,
+                          cursor->bits->width, cursor->bits->height))
+        {
+            xwl_cursor->pixmap = xwl_shm_create_pixmap(screen, cursor->bits->width,
+                                                       cursor->bits->height, 32, 0);
+            xwl_cursor->buffer = xwl_shm_pixmap_get_wl_buffer (xwl_cursor->pixmap);
+        }
+
+    dixSetPrivate(&cursor->devPrivates, &xwl_cursor_private_key, xwl_cursor);
     return TRUE;
 }
 
 static Bool
 xwl_unrealize_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor)
 {
-    PixmapPtr pixmap;
+    struct xwl_cursor *xwl_cursor;
+
+    xwl_cursor = dixGetPrivate(&cursor->devPrivates, &xwl_cursor_private_key);
+    wl_buffer_destroy(xwl_cursor->buffer);
+    if (xwl_cursor->pixmap)
+        xwl_shm_destroy_pixmap(xwl_cursor->pixmap);
+#ifdef GLAMOR_HAS_GBM
+    if (xwl_cursor->bo)
+        gbm_bo_destroy(xwl_cursor->bo);
+#endif
+    free(xwl_cursor);
 
-    pixmap = dixGetPrivate(&cursor->devPrivates, &xwl_cursor_private_key);
-
-    return xwl_shm_destroy_pixmap(pixmap);
+    return TRUE;
 }
 
 static void
@@ -102,9 +185,10 @@ static const struct wl_callback_listener frame_listener = {
 void
 xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
 {
-    PixmapPtr pixmap;
+    struct xwl_cursor *xwl_cursor;
     CursorPtr cursor;
-    int stride;
+    uint32_t width, height, stride;
+    uint8_t *pixels;
 
     if (!xwl_seat->wl_pointer)
         return;
@@ -121,13 +205,35 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
     }
 
     cursor = xwl_seat->x_cursor;
-    pixmap = dixGetPrivate(&cursor->devPrivates, &xwl_cursor_private_key);
-    stride = cursor->bits->width * 4;
-    if (cursor->bits->argb)
-        memcpy(pixmap->devPrivate.ptr,
-               cursor->bits->argb, cursor->bits->height * stride);
-    else
-        expand_source_and_mask(cursor, pixmap->devPrivate.ptr);
+    xwl_cursor = dixGetPrivate(&cursor->devPrivates, &xwl_cursor_private_key);
+    width = cursor->bits->width;
+    height = cursor->bits->height;
+    stride = width * 4;
+
+    if (cursor->bits->argb) {
+        pixels = (uint8_t *) cursor->bits->argb;
+    } else {
+        pixels = alloca(height * stride);
+        expand_source_and_mask(cursor, (CARD32 *) pixels);
+    }
+
+#ifdef GLAMOR_HAS_GBM
+    if (xwl_cursor->bo) {
+        uint i;
+        uint hw_stride = 4 * hw_cursor_width;
+        uint8_t buf[hw_stride * hw_cursor_height];
+
+        memset(buf, 0, sizeof(buf));
+        for (i = 0; i < height; i++)
+            memcpy(buf + i * hw_stride, pixels + i * stride, stride);
+
+        gbm_bo_write(xwl_cursor->bo, buf, sizeof(buf));
+
+        width = hw_cursor_width;
+        height = hw_cursor_height;
+    } else
+#endif
+        memcpy(xwl_cursor->pixmap->devPrivate.ptr, pixels, height * stride);
 
     wl_pointer_set_cursor(xwl_seat->wl_pointer,
                           xwl_seat->pointer_enter_serial,
@@ -135,10 +241,8 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
                           xwl_seat->x_cursor->bits->xhot,
                           xwl_seat->x_cursor->bits->yhot);
     wl_surface_attach(xwl_seat->cursor,
-                      xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0);
-    wl_surface_damage(xwl_seat->cursor, 0, 0,
-                      xwl_seat->x_cursor->bits->width,
-                      xwl_seat->x_cursor->bits->height);
+                      xwl_cursor->buffer, 0, 0);
+    wl_surface_damage(xwl_seat->cursor, 0, 0, width, height);
 
     xwl_seat->cursor_frame_cb = wl_surface_frame(xwl_seat->cursor);
     wl_callback_add_listener(xwl_seat->cursor_frame_cb, &frame_listener, xwl_seat);
@@ -214,6 +318,16 @@ xwl_screen_init_cursor(struct xwl_screen *xwl_screen)
     if (!dixRegisterPrivateKey(&xwl_cursor_private_key, PRIVATE_CURSOR_BITS, 0))
         return FALSE;
 
+#ifdef GLAMOR_HAS_GBM
+    if (xwl_screen->glamor) {
+        if (drmGetCap (xwl_screen->drm_fd, DRM_CAP_CURSOR_WIDTH, &hw_cursor_width) ||
+            drmGetCap (xwl_screen->drm_fd, DRM_CAP_CURSOR_HEIGHT, &hw_cursor_height)) {
+                hw_cursor_width = 64;
+                hw_cursor_height = 64;
+        }
+    }
+#endif
+
     return miPointerInitialize(xwl_screen->screen,
                                &xwl_pointer_sprite_funcs,
                                &xwl_pointer_screen_funcs, TRUE);
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 3d36205..6e4473f 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -662,9 +662,6 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
 
     ret = fbCreateDefColormap(pScreen);
 
-    if (!xwl_screen_init_cursor(xwl_screen))
-        return FALSE;
-
 #ifdef GLAMOR_HAS_GBM
     if (xwl_screen->glamor && !xwl_glamor_init(xwl_screen)) {
         ErrorF("Failed to initialize glamor, falling back to sw\n");
@@ -672,6 +669,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     }
 #endif
 
+    if (!xwl_screen_init_cursor(xwl_screen))
+        return FALSE;
+
     if (!xwl_screen->glamor) {
         xwl_screen->CreateScreenResources = pScreen->CreateScreenResources;
         pScreen->CreateScreenResources = xwl_shm_create_screen_resources;
-- 
2.5.0



More information about the xorg-devel mailing list