| 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 |
| |