blob: aa450932f1cd8d99dfb676678a05db87e78b61e1 [file] [log] [blame]
From 39e686c1fc7e4bcf78ea722f654af79fca8c2271 Mon Sep 17 00:00:00 2001
From: David Reveman <reveman@chromium.org>
Date: Sat, 10 Mar 2018 14:39:00 +0000
Subject: [PATCH] xwayland virtwl with dmabuf for 1.20.1
---
hw/xwayland/Makefile.am | 11 +--
hw/xwayland/xwayland-cursor.c | 56 ++++++++----
hw/xwayland/xwayland-glamor-gbm.c | 8 ++
hw/xwayland/xwayland-shm.c | 139 ++++++++++++++++++++++++++----
hw/xwayland/xwayland.c | 4 +-
hw/xwayland/xwayland.h | 58 +++++++------
6 files changed, 207 insertions(+), 69 deletions(-)
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index bc1cb8506..377e4b9bf 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -41,18 +41,11 @@ if XV
Xwayland_SOURCES += \
xwayland-glamor-xv.c
endif
-
if XWAYLAND_EGLSTREAM
Xwayland_SOURCES += \
xwayland-glamor-eglstream.c
endif
-glamor_built_sources = \
- drm-client-protocol.h \
- drm-protocol.c
-
-Xwayland_built_sources += $(glamor_built_sources)
-
glamor_lib = $(top_builddir)/glamor/libglamor.la
Xwayland_LDADD += $(GLAMOR_LIBS) $(GBM_LIBS) -lEGL -lGL
@@ -71,7 +64,9 @@ Xwayland_built_sources += \
xdg-output-unstable-v1-protocol.c \
xdg-output-unstable-v1-client-protocol.h \
linux-dmabuf-unstable-v1-client-protocol.h \
- linux-dmabuf-unstable-v1-protocol.c
+ linux-dmabuf-unstable-v1-protocol.c \
+ drm-client-protocol.h \
+ drm-protocol.c
if XWAYLAND_EGLSTREAM
Xwayland_built_sources += \
diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index cf8395f1d..25991f3ba 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -31,19 +31,19 @@
static DevPrivateKeyRec xwl_cursor_private_key;
static void
-expand_source_and_mask(CursorPtr cursor, CARD32 *data)
+expand_source_and_mask(CursorPtr cursor, CARD32 *data, int dataStride)
{
CARD32 *p, d, fg, bg;
CursorBitsPtr bits = cursor->bits;
int x, y, stride, i, bit;
- p = data;
fg = ((cursor->foreRed & 0xff00) << 8) |
(cursor->foreGreen & 0xff00) | (cursor->foreGreen >> 8);
bg = ((cursor->backRed & 0xff00) << 8) |
(cursor->backGreen & 0xff00) | (cursor->backGreen >> 8);
stride = BitmapBytePad(bits->width);
- for (y = 0; y < bits->height; y++)
+ for (y = 0; y < bits->height; y++) {
+ p = data + y * dataStride / sizeof (*p);
for (x = 0; x < bits->width; x++) {
i = y * stride + x / 8;
bit = 1 << (x & 7);
@@ -58,6 +58,7 @@ expand_source_and_mask(CursorPtr cursor, CARD32 *data)
*p++ = d;
}
+ }
}
static Bool
@@ -66,7 +67,8 @@ xwl_realize_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor)
PixmapPtr pixmap;
pixmap = xwl_shm_create_pixmap(screen, cursor->bits->width,
- cursor->bits->height, 32, 0);
+ cursor->bits->height, 32,
+ CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
dixSetPrivate(&cursor->devPrivates, &xwl_cursor_private_key, pixmap);
return TRUE;
@@ -128,7 +130,7 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
struct xwl_cursor *xwl_cursor = &xwl_seat->cursor;
PixmapPtr pixmap;
CursorPtr cursor;
- int stride;
+ int srcStride, dstStride;
if (!xwl_seat->wl_pointer)
return;
@@ -151,12 +153,21 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
if (!pixmap)
return;
- 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);
+ srcStride = cursor->bits->width * 4;
+ dstStride = (int) pixmap->devKind;
+ if (cursor->bits->argb) {
+ CARD8 *s = (CARD8 *) cursor->bits->argb;
+ CARD8 *d = pixmap->devPrivate.ptr;
+ int height = cursor->bits->height;
+
+ while (height--) {
+ memcpy(d, s, srcStride);
+ s += srcStride;
+ d += dstStride;
+ }
+ } else {
+ expand_source_and_mask(cursor, pixmap->devPrivate.ptr, dstStride);
+ }
wl_pointer_set_cursor(xwl_seat->wl_pointer,
xwl_seat->pointer_enter_serial,
@@ -182,7 +193,7 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor;
PixmapPtr pixmap;
CursorPtr cursor;
- int stride;
+ int srcStride, dstStride;
if (!xwl_seat->x_cursor) {
zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
@@ -201,12 +212,21 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
if (!pixmap)
return;
- 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);
+ srcStride = cursor->bits->width * 4;
+ dstStride = (int) pixmap->devKind;
+ if (cursor->bits->argb) {
+ CARD8 *s = (CARD8 *) cursor->bits->argb;
+ CARD8 *d = pixmap->devPrivate.ptr;
+ int height = cursor->bits->height;
+
+ while (height--) {
+ memcpy(d, s, srcStride);
+ s += srcStride;
+ d += dstStride;
+ }
+ } else {
+ expand_source_and_mask(cursor, pixmap->devPrivate.ptr, dstStride);
+ }
zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
xwl_tablet_tool->proximity_in_serial,
diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
index 06fcf5239..ccd67445c 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -304,6 +304,13 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap,
return xwl_pixmap->buffer;
}
+static struct wl_drm *
+xwl_glamor_gbm_get_wl_drm_interface(struct xwl_screen *xwl_screen)
+{
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+ return xwl_gbm->drm;
+}
+
static void
xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen)
{
@@ -933,4 +940,5 @@ xwl_glamor_init_gbm(struct xwl_screen *xwl_screen)
xwl_screen->gbm_backend.init_screen = xwl_glamor_gbm_init_screen;
xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap;
xwl_screen->gbm_backend.is_available = TRUE;
+ xwl_screen->gbm_backend.get_wl_drm_interface = xwl_glamor_gbm_get_wl_drm_interface;
}
diff --git a/hw/xwayland/xwayland-shm.c b/hw/xwayland/xwayland-shm.c
index 29732eaca..274bdefb7 100644
--- a/hw/xwayland/xwayland-shm.c
+++ b/hw/xwayland/xwayland-shm.c
@@ -32,6 +32,7 @@
#include "xwayland.h"
+#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
@@ -39,14 +40,23 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <linux/virtwl.h>
+
+#include "drm-client-protocol.h"
+
+#define DMA_BUF_SYNC_READ (1 << 0)
+#define DMA_BUF_SYNC_WRITE (2 << 0)
+#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE)
+#define DMA_BUF_SYNC_START (0 << 2)
+#define DMA_BUF_SYNC_END (1 << 2)
struct xwl_pixmap {
struct wl_buffer *buffer;
void *data;
size_t size;
+ int dmabuf_fd;
};
-#ifndef HAVE_MKOSTEMP
static int
set_cloexec_or_close(int fd)
{
@@ -68,7 +78,6 @@ set_cloexec_or_close(int fd)
close(fd);
return -1;
}
-#endif
static int
create_tmpfile_cloexec(char *tmpname)
@@ -189,6 +198,27 @@ shm_format_for_depth(int depth)
}
}
+static uint32_t
+drm_format_for_depth(int depth)
+{
+ switch (depth) {
+ case 16:
+ return WL_DRM_FORMAT_RGB565;
+ case 24:
+ return WL_DRM_FORMAT_XRGB8888;
+ default:
+ ErrorF("unexpected depth: %d\n", depth);
+ case 32:
+ return WL_DRM_FORMAT_ARGB8888;
+ }
+}
+
+// Buffer size threshold for which DMABuf should be considered.
+#define DMABUF_SIZE_THRESHOLD 65536
+
+// Maximum number of DMABufs allowed at any given time.
+#define DMABUF_COUNT_MAX 256
+
PixmapPtr
xwl_shm_create_pixmap(ScreenPtr screen,
int width, int height, int depth, unsigned int hint)
@@ -201,7 +231,7 @@ xwl_shm_create_pixmap(ScreenPtr screen,
uint32_t format;
int fd;
- if (hint == CREATE_PIXMAP_USAGE_GLYPH_PICTURE ||
+ if ((hint != CREATE_PIXMAP_USAGE_BACKING_PIXMAP) ||
(width == 0 && height == 0) || depth < 15)
return fbCreatePixmap(screen, width, height, depth, hint);
@@ -216,11 +246,69 @@ xwl_shm_create_pixmap(ScreenPtr screen,
stride = PixmapBytePad(width, depth);
size = stride * height;
xwl_pixmap->buffer = NULL;
- xwl_pixmap->size = size;
- fd = os_create_anonymous_file(size);
- if (fd < 0)
- goto err_free_xwl_pixmap;
+ xwl_pixmap->dmabuf_fd = -1;
+ fd = -1;
+
+ if (xwl_screen->egl_backend &&
+ xwl_screen->egl_backend->get_wl_drm_interface &&
+ xwl_screen->egl_backend->get_wl_drm_interface(xwl_screen) &&
+ size > DMABUF_SIZE_THRESHOLD &&
+ xwl_screen->dmabuf_count < DMABUF_COUNT_MAX) {
+ struct wl_drm *drm = xwl_screen->egl_backend->get_wl_drm_interface(
+ xwl_screen);
+ uint32_t drm_format = drm_format_for_depth(depth);
+ struct virtwl_ioctl_new new_alloc = {
+ .type = VIRTWL_IOCTL_NEW_DMABUF,
+ .fd = -1,
+ .flags = 0,
+ .dmabuf = {
+ .width = width,
+ .height = height,
+ .format = drm_format,
+ },
+ };
+ int ret = ioctl(xwl_screen->wl_fd, VIRTWL_IOCTL_NEW, &new_alloc);
+ if (ret == 0) {
+ fd = set_cloexec_or_close(new_alloc.fd);
+ if (fd >= 0) {
+ struct virtwl_ioctl_dmabuf_sync sync = {0};
+
+ sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;
+ ioctl(fd, VIRTWL_IOCTL_DMABUF_SYNC, &sync);
+
+ stride = new_alloc.dmabuf.stride0;
+ size = stride * height;
+ xwl_pixmap->dmabuf_fd = fd;
+ xwl_pixmap->buffer =
+ wl_drm_create_prime_buffer(drm,
+ fd,
+ width,
+ height,
+ drm_format,
+ 0, stride,
+ 0, 0,
+ 0, 0);
+ }
+ }
+ }
+ if (!xwl_pixmap->buffer) {
+ fd = os_create_anonymous_file(size);
+ if (fd < 0)
+ goto err_free_xwl_pixmap;
+
+ format = shm_format_for_depth(depth);
+ pool = wl_shm_create_pool(xwl_screen->shm, fd, size);
+ xwl_pixmap->buffer = wl_shm_pool_create_buffer(pool,
+ 0,
+ width,
+ height,
+ stride,
+ format);
+ wl_shm_pool_destroy(pool);
+ }
+
+ xwl_pixmap->size = size;
xwl_pixmap->data = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (xwl_pixmap->data == MAP_FAILED)
@@ -231,14 +319,10 @@ xwl_shm_create_pixmap(ScreenPtr screen,
stride, xwl_pixmap->data))
goto err_munmap;
- format = shm_format_for_depth(pixmap->drawable.depth);
- pool = wl_shm_create_pool(xwl_screen->shm, fd, xwl_pixmap->size);
- xwl_pixmap->buffer = wl_shm_pool_create_buffer(pool, 0,
- pixmap->drawable.width,
- pixmap->drawable.height,
- pixmap->devKind, format);
- wl_shm_pool_destroy(pool);
- close(fd);
+ if (xwl_pixmap->dmabuf_fd != -1)
+ xwl_screen->dmabuf_count++;
+ else
+ close(fd);
xwl_pixmap_set_private(pixmap, xwl_pixmap);
@@ -262,9 +346,15 @@ xwl_shm_destroy_pixmap(PixmapPtr pixmap)
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
if (xwl_pixmap && pixmap->refcnt == 1) {
+ struct xwl_screen *xwl_screen =
+ xwl_screen_get(pixmap->drawable.pScreen);
if (xwl_pixmap->buffer)
wl_buffer_destroy(xwl_pixmap->buffer);
munmap(xwl_pixmap->data, xwl_pixmap->size);
+ if (xwl_pixmap->dmabuf_fd != -1) {
+ close(xwl_pixmap->dmabuf_fd);
+ xwl_screen->dmabuf_count--;
+ }
free(xwl_pixmap);
}
@@ -274,7 +364,19 @@ xwl_shm_destroy_pixmap(PixmapPtr pixmap)
struct wl_buffer *
xwl_shm_pixmap_get_wl_buffer(PixmapPtr pixmap)
{
- return xwl_pixmap_get(pixmap)->buffer;
+ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
+
+ if (xwl_pixmap->dmabuf_fd != -1) {
+ struct virtwl_ioctl_dmabuf_sync sync = {0};
+
+ // Trigger a flush by stopping and starting access to buffer.
+ sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;
+ ioctl(xwl_pixmap->dmabuf_fd, VIRTWL_IOCTL_DMABUF_SYNC, &sync);
+ sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;
+ ioctl(xwl_pixmap->dmabuf_fd, VIRTWL_IOCTL_DMABUF_SYNC, &sync);
+ }
+
+ return xwl_pixmap->buffer;
}
Bool
@@ -283,6 +385,11 @@ xwl_shm_create_screen_resources(ScreenPtr screen)
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
int ret;
+ xwl_screen->wl_fd = open("/dev/wl0", O_RDWR);
+ if (xwl_screen->wl_fd < 0)
+ return 0;
+ xwl_screen->dmabuf_count = 0;
+
screen->CreateScreenResources = xwl_screen->CreateScreenResources;
ret = (*screen->CreateScreenResources) (screen);
xwl_screen->CreateScreenResources = screen->CreateScreenResources;
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 96b4db18c..210eaabca 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -43,6 +43,8 @@
_X_EXPORT Bool noXFree86VidModeExtension;
#endif
+#include "drm-client-protocol.h"
+
void
ddxGiveUp(enum ExitCode error)
{
@@ -769,12 +771,10 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 1);
xwl_screen_init_xdg_output(xwl_screen);
}
-#ifdef XWL_HAS_GLAMOR
else if (xwl_screen->glamor) {
xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface,
version);
}
-#endif
}
static void
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index d70ad54bf..a1d839f7b 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -85,31 +85,36 @@ struct xwl_egl_backend {
* this to setup any required wraps around X server callbacks like
* CreatePixmap.
*/
- Bool (*init_screen)(struct xwl_screen *xwl_screen);
-
- /* Called by Xwayland to retrieve a pointer to a valid wl_buffer for
- * the given window/pixmap combo so that damage to the pixmap may be
- * displayed on-screen. Backends should use this to create a new
- * wl_buffer for a currently buffer-less pixmap, or simply return the
- * pixmap they've prepared beforehand.
- */
- struct wl_buffer *(*get_wl_buffer_for_pixmap)(PixmapPtr pixmap,
- Bool *created);
-
- /* Called by Xwayland to perform any pre-wl_surface damage routines
- * that are required by the backend. If your backend is poorly
- * designed and lacks the ability to render directly to a surface,
- * you should implement blitting from the glamor pixmap to the wayland
- * pixmap here. Otherwise, this callback is optional.
- */
- void (*post_damage)(struct xwl_window *xwl_window,
- PixmapPtr pixmap, RegionPtr region);
-
- /* Called by Xwayland to confirm with the egl backend that the given
- * pixmap is completely setup and ready for display on-screen. This
- * callback is optional.
- */
- Bool (*allow_commits)(struct xwl_window *xwl_window);
+ Bool (*init_screen)(struct xwl_screen *xwl_screen);
+
+ /* Called by Xwayland to retrieve a pointer to a valid wl_buffer for
+ * the given window/pixmap combo so that damage to the pixmap may be
+ * displayed on-screen. Backends should use this to create a new
+ * wl_buffer for a currently buffer-less pixmap, or simply return the
+ * pixmap they've prepared beforehand.
+ */
+ struct wl_buffer *(*get_wl_buffer_for_pixmap)(PixmapPtr pixmap,
+ Bool *created);
+
+ /* Called by Xwayland to perform any pre-wl_surface damage routines
+ * that are required by the backend. If your backend is poorly
+ * designed and lacks the ability to render directly to a surface,
+ * you should implement blitting from the glamor pixmap to the wayland
+ * pixmap here. Otherwise, this callback is optional.
+ */
+ void (*post_damage)(struct xwl_window *xwl_window,
+ PixmapPtr pixmap, RegionPtr region);
+
+ /* Called by Xwayland to confirm with the egl backend that the given
+ * pixmap is completely setup and ready for display on-screen. This
+ * callback is optional.
+ */
+ Bool (*allow_commits)(struct xwl_window *xwl_window);
+
+ /* Called by Xwayland to retrieve a pointer to a valid wl_drm for
+ * the given screen such that buffers can shared via dmabuf.
+ */
+ struct wl_drm *(*get_wl_drm_interface)(struct xwl_screen *xwl_screen);
};
struct xwl_screen {
@@ -171,6 +176,9 @@ struct xwl_screen {
struct glamor_context *glamor_ctx;
Atom allow_commits_prop;
+
+ int wl_fd;
+ int dmabuf_count;
};
struct xwl_window {
--
2.19.0.605.g01d371f741-goog