From c8c276c9569b3ca1e695682a5443f1b615c606bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis-Francis=20Ratt=C3=A9-Boulianne?= Date: Wed, 28 Feb 2018 01:19:43 +0000 Subject: [PATCH] glamor: Implement PixmapFromBuffers and BuffersFromPixmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It relies on GBM >= 17.1.0 where we can import BO with multiple planes and a format modifier (GBM_BO_IMPORT_FD_MODIFIER). v2: Properly free fds in Xwayland [Also add glamor_egl_ext.h to Makefile.am for distcheck's sake - ajax] Signed-off-by: Louis-Francis Ratté-Boulianne Reviewed-by: Daniel Stone Acked-by: Keith Packard Reviewed-by: Adam Jackson --- configure.ac | 4 + glamor/Makefile.am | 1 + glamor/glamor.c | 37 ++++-- glamor/glamor.h | 65 +++++----- glamor/glamor_egl.c | 136 +++++++++++++++++---- glamor/glamor_egl.h | 1 + glamor/glamor_egl_ext.h | 65 ++++++++++ glamor/glamor_egl_stubs.c | 16 ++- hw/xwayland/.gitignore | 2 + hw/xwayland/Makefile.am | 10 +- hw/xwayland/meson.build | 5 +- hw/xwayland/xwayland-glamor.c | 217 ++++++++++++++++++++++++++-------- hw/xwayland/xwayland.c | 6 +- hw/xwayland/xwayland.h | 10 +- include/dix-config.h.in | 3 + include/meson.build | 2 + 16 files changed, 461 insertions(+), 119 deletions(-) create mode 100644 glamor/glamor_egl_ext.h diff --git a/configure.ac b/configure.ac index f4534e30b..773567b53 100644 --- a/configure.ac +++ b/configure.ac @@ -2095,6 +2095,10 @@ if test "x$GLAMOR" = xyes; then [AC_DEFINE(GLAMOR_HAS_GBM_LINEAR, 1, [Have GBM_BO_USE_LINEAR])], [], [#include #include ]) + dnl 17.1.0 is required for gbm_bo_create_with_modifiers + PKG_CHECK_EXISTS(gbm >= 17.1.0, + [AC_DEFINE(GBM_BO_WITH_MODIFIERS, 1, [Have gbm_bo_create_with_modifiers])], + []) else if test "x$XORG" = xyes; then AC_MSG_ERROR([Glamor for Xorg requires $LIBGBM]) diff --git a/glamor/Makefile.am b/glamor/Makefile.am index 8c79994e0..aaf0aab17 100644 --- a/glamor/Makefile.am +++ b/glamor/Makefile.am @@ -56,6 +56,7 @@ endif libglamor_egl_stubs_la_SOURCES = \ glamor_egl_stubs.c \ + glamor_egl_ext.h \ glamor_egl.h sdk_HEADERS = glamor.h diff --git a/glamor/glamor.c b/glamor/glamor.c index d61e27563..c890d0ce0 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -32,6 +32,7 @@ */ #include +#include #include "glamor_priv.h" #include "mipict.h" @@ -793,8 +794,9 @@ glamor_supports_pixmap_import_export(ScreenPtr screen) } _X_EXPORT int -glamor_fd_from_pixmap(ScreenPtr screen, - PixmapPtr pixmap, CARD16 *stride, CARD32 *size) +glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, + uint32_t *strides, uint32_t *offsets, + uint64_t *modifier) { glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); glamor_screen_private *glamor_priv = @@ -808,10 +810,9 @@ glamor_fd_from_pixmap(ScreenPtr screen, if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ? GL_RGB10_A2 : GL_RGBA, 0)) return -1; - return glamor_egl_dri3_fd_name_from_tex(screen, - pixmap, - pixmap_priv->fbo->tex, - FALSE, stride, size); + return glamor_egl_fds_from_pixmap(screen, pixmap, fds, + strides, offsets, + modifier); default: break; } @@ -824,6 +825,9 @@ glamor_shareable_fd_from_pixmap(ScreenPtr screen, { unsigned orig_usage_hint = pixmap->usage_hint; int ret; + int fds[4]; + uint32_t strides[4], offsets[4]; + uint64_t modifier; /* * The actual difference between a sharable and non sharable buffer @@ -832,7 +836,20 @@ glamor_shareable_fd_from_pixmap(ScreenPtr screen, * 2 of those calls are also exported API, so we cannot just add a flag. */ pixmap->usage_hint = CREATE_PIXMAP_USAGE_SHARED; - ret = glamor_fd_from_pixmap(screen, pixmap, stride, size); + ret = glamor_fds_from_pixmap(screen, pixmap, fds, strides, offsets, + &modifier); + + /* Pixmaps with multi-planes/modifier are not shareable */ + if (ret > 1) { + while (ret > 0) + close(fds[--ret]); + return -1; + } + + ret = fds[0]; + *stride = strides[0]; + *size = pixmap->drawable.height * *stride; + pixmap->usage_hint = orig_usage_hint; return ret; @@ -849,10 +866,8 @@ glamor_name_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size) if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ? GL_RGB10_A2 : GL_RGBA, 0)) return -1; - return glamor_egl_dri3_fd_name_from_tex(pixmap->drawable.pScreen, - pixmap, - pixmap_priv->fbo->tex, - TRUE, stride, size); + return glamor_egl_fd_name_from_pixmap(pixmap->drawable.pScreen, + pixmap, stride, size); default: break; } diff --git a/glamor/glamor.h b/glamor/glamor.h index 5b15a46e5..8f8c31b45 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -138,15 +138,17 @@ extern _X_EXPORT void glamor_pixmap_exchange_fbos(PixmapPtr front, /* The DDX is not supposed to call these three functions */ extern _X_EXPORT void glamor_enable_dri3(ScreenPtr screen); -extern _X_EXPORT int glamor_egl_dri3_fd_name_from_tex(ScreenPtr, PixmapPtr, - unsigned int, Bool, - CARD16 *, CARD32 *); +extern _X_EXPORT int glamor_egl_fds_from_pixmap(ScreenPtr, PixmapPtr, int *, + uint32_t *, uint32_t *, + uint64_t *); +extern _X_EXPORT int glamor_egl_fd_name_from_pixmap(ScreenPtr, PixmapPtr, + CARD16 *, CARD32 *); extern _X_EXPORT struct gbm_device *glamor_egl_get_gbm_device(ScreenPtr screen); /* @glamor_supports_pixmap_import_export: Returns whether - * glamor_fd_from_pixmap(), glamor_name_from_pixmap(), and - * glamor_pixmap_from_fd() are supported. + * glamor_fds_from_pixmap(), glamor_name_from_pixmap(), and + * glamor_pixmap_from_fds() are supported. * * @screen: Current screen pointer. * @@ -159,20 +161,22 @@ extern _X_EXPORT struct gbm_device *glamor_egl_get_gbm_device(ScreenPtr screen); * */ extern _X_EXPORT Bool glamor_supports_pixmap_import_export(ScreenPtr screen); -/* @glamor_fd_from_pixmap: Get a dma-buf fd from a pixmap. +/* @glamor_fds_from_pixmap: Get a dma-buf fd from a pixmap. * * @screen: Current screen pointer. * @pixmap: The pixmap from which we want the fd. - * @stride, @size: Pointers to fill the stride and size of the - * buffer associated to the fd. + * @fds, @strides, @offsets: Pointers to fill info of each plane. + * @modifier: Pointer to fill the modifier of the buffer. * - * the pixmap and the buffer associated by the fd will share the same - * content. - * Returns the fd on success, -1 on error. + * the pixmap and the buffer associated by the fds will share the same + * content. The caller is responsible to close the returned file descriptors. + * Returns the number of planes, -1 on error. * */ -extern _X_EXPORT int glamor_fd_from_pixmap(ScreenPtr screen, - PixmapPtr pixmap, - CARD16 *stride, CARD32 *size); +extern _X_EXPORT int glamor_fds_from_pixmap(ScreenPtr screen, + PixmapPtr pixmap, + int *fds, + uint32_t *strides, uint32_t *offsets, + uint64_t *modifier); /* @glamor_shareable_fd_from_pixmap: Get a dma-buf fd suitable for sharing * with other GPUs from a pixmap. @@ -224,25 +228,30 @@ extern _X_EXPORT int glamor_name_from_pixmap(PixmapPtr pixmap, extern _X_EXPORT struct gbm_bo *glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap); -/* @glamor_pixmap_from_fd: Creates a pixmap to wrap a dma-buf fd. +/* @glamor_pixmap_from_fds: Creates a pixmap to wrap a dma-buf fds. * * @screen: Current screen pointer. - * @fd: The dma-buf fd to import. - * @width: The width of the buffer. - * @height: The height of the buffer. - * @stride: The stride of the buffer. - * @depth: The depth of the buffer. - * @bpp: The number of bpp of the buffer. + * @num_fds: Number of fds to import + * @fds: The dma-buf fds to import. + * @width: The width of the buffers. + * @height: The height of the buffers. + * @stride: The stride of the buffers. + * @depth: The depth of the buffers. + * @bpp: The bpp of the buffers. + * @modifier: The modifier of the buffers. * * Returns a valid pixmap if the import succeeded, else NULL. * */ -extern _X_EXPORT PixmapPtr glamor_pixmap_from_fd(ScreenPtr screen, - int fd, - CARD16 width, - CARD16 height, - CARD16 stride, - CARD8 depth, - CARD8 bpp); +extern _X_EXPORT PixmapPtr glamor_pixmap_from_fds(ScreenPtr screen, + CARD8 num_fds, + int *fds, + CARD16 width, + CARD16 height, + CARD32 *strides, + CARD32 *offsets, + CARD8 depth, + CARD8 bpp, + uint64_t modifier); /* @glamor_back_pixmap_from_fd: Backs an existing pixmap with a dma-buf fd. * diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c index eb5e68b8e..cf2513491 100644 --- a/glamor/glamor_egl.c +++ b/glamor/glamor_egl.c @@ -56,6 +56,7 @@ struct glamor_egl_screen_private { CloseScreenProcPtr CloseScreen; int fd; struct gbm_device *gbm; + int dmabuf_capable; CloseScreenProcPtr saved_close_screen; DestroyPixmapProcPtr saved_destroy_pixmap; @@ -330,10 +331,51 @@ glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap) } int -glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, - PixmapPtr pixmap, - unsigned int tex, - Bool want_name, CARD16 *stride, CARD32 *size) +glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, + uint32_t *strides, uint32_t *offsets, + uint64_t *modifier) +{ +#ifdef GLAMOR_HAS_GBM + struct gbm_bo *bo; + int num_fds; +#ifdef GBM_BO_WITH_MODIFIERS + int i; +#endif + + if (!glamor_make_pixmap_exportable(pixmap)) + return 0; + + bo = glamor_gbm_bo_from_pixmap(screen, pixmap); + if (!bo) + return 0; + +#ifdef GBM_BO_WITH_MODIFIERS + num_fds = gbm_bo_get_plane_count(bo); + for (i = 0; i < num_fds; i++) { + fds[i] = gbm_bo_get_fd(bo); + strides[i] = gbm_bo_get_stride_for_plane(bo, i); + offsets[i] = gbm_bo_get_offset(bo, i); + } + *modifier = gbm_bo_get_modifier(bo); +#else + num_fds = 1; + fds[0] = gbm_bo_get_fd(bo); + strides[0] = gbm_bo_get_stride(bo); + offsets[0] = 0; + *modifier = DRM_FORMAT_MOD_INVALID; +#endif + + gbm_bo_destroy(bo); + return num_fds; +#else + return 0; +#endif +} + +int +glamor_egl_fd_name_from_pixmap(ScreenPtr screen, + PixmapPtr pixmap, + CARD16 *stride, CARD32 *size) { struct glamor_egl_screen_private *glamor_egl; struct gbm_bo *bo; @@ -347,12 +389,7 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, pixmap->devKind = gbm_bo_get_stride(bo); - if (want_name) { - glamor_get_name_from_bo(glamor_egl->fd, bo, &fd); - } - else { - fd = gbm_bo_get_fd(bo); - } + glamor_get_name_from_bo(glamor_egl->fd, bo, &fd); *stride = pixmap->devKind; *size = pixmap->devKind * gbm_bo_get_height(bo); @@ -399,19 +436,68 @@ glamor_back_pixmap_from_fd(PixmapPtr pixmap, return ret; } +static uint32_t +gbm_format_for_depth(CARD8 depth) +{ + switch (depth) { + case 16: + return GBM_FORMAT_RGB565; + case 24: + return GBM_FORMAT_XRGB8888; + default: + ErrorF("unexpected depth: %d\n", depth); + case 32: + return GBM_FORMAT_ARGB8888; + } +} + _X_EXPORT PixmapPtr -glamor_pixmap_from_fd(ScreenPtr screen, - int fd, - CARD16 width, - CARD16 height, - CARD16 stride, CARD8 depth, CARD8 bpp) +glamor_pixmap_from_fds(ScreenPtr screen, + CARD8 num_fds, int *fds, + CARD16 width, CARD16 height, + CARD32 *strides, CARD32 *offsets, + CARD8 depth, CARD8 bpp, + uint64_t modifier) { PixmapPtr pixmap; - Bool ret; + struct glamor_egl_screen_private *glamor_egl; + Bool ret = FALSE; + int i; + + glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0); - ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height, - stride, depth, bpp); + +#ifdef GBM_BO_WITH_MODIFIERS + if (glamor_egl->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) { + struct gbm_import_fd_modifier_data import_data = { 0 }; + struct gbm_bo *bo; + + import_data.width = width; + import_data.height = height; + import_data.num_fds = num_fds; + import_data.modifier = modifier; + for (i = 0; i < num_fds; i++) { + import_data.fds[i] = fds[i]; + import_data.strides[i] = strides[i]; + import_data.offsets[i] = offsets[i]; + } + import_data.format = gbm_format_for_depth(depth); + bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD_MODIFIER, &import_data, 0); + if (bo) { + screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL); + ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo); + gbm_bo_destroy(bo); + } + } else +#endif + { + if (num_fds == 1) { + ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height, + strides[0], depth, bpp); + } + } + if (ret == FALSE) { screen->DestroyPixmap(pixmap); return NULL; @@ -536,10 +622,10 @@ glamor_dri3_open_client(ClientPtr client, } static dri3_screen_info_rec glamor_dri3_info = { - .version = 1, + .version = 2, .open_client = glamor_dri3_open_client, - .pixmap_from_fd = glamor_pixmap_from_fd, - .fd_from_pixmap = glamor_fd_from_pixmap, + .pixmap_from_fds = glamor_pixmap_from_fds, + .fds_from_pixmap = glamor_egl_fds_from_pixmap, }; #endif /* DRI3 */ @@ -737,6 +823,14 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd) xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n", glGetString(GL_RENDERER)); +#ifdef GBM_BO_WITH_MODIFIERS + if (epoxy_has_egl_extension(glamor_egl->display, + "EGL_EXT_image_dma_buf_import") && + epoxy_has_egl_extension(glamor_egl->display, + "EGL_EXT_image_dma_buf_import_modifiers")) + glamor_egl->dmabuf_capable = TRUE; +#endif + glamor_egl->saved_free_screen = scrn->FreeScreen; scrn->FreeScreen = glamor_egl_free_screen; return TRUE; diff --git a/glamor/glamor_egl.h b/glamor/glamor_egl.h index 6bb1185bf..2f7566b24 100644 --- a/glamor/glamor_egl.h +++ b/glamor/glamor_egl.h @@ -30,6 +30,7 @@ #define MESA_EGL_NO_X11_HEADERS #include #include +#include /* * Create an EGLDisplay from a native display type. This is a little quirky diff --git a/glamor/glamor_egl_ext.h b/glamor/glamor_egl_ext.h new file mode 100644 index 000000000..436e52137 --- /dev/null +++ b/glamor/glamor_egl_ext.h @@ -0,0 +1,65 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * 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. + */ +/* Extensions used by Glamor, copied from Mesa's eglmesaext.h, */ + +#ifndef GLAMOR_EGL_EXT_H +#define GLAMOR_EGL_EXT_H + +/* Define needed tokens from EGL_EXT_image_dma_buf_import extension + * here to avoid having to add ifdefs everywhere.*/ +#ifndef EGL_EXT_image_dma_buf_import +#define EGL_LINUX_DMA_BUF_EXT 0x3270 +#define EGL_LINUX_DRM_FOURCC_EXT 0x3271 +#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 +#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 +#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 +#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275 +#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276 +#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277 +#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278 +#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279 +#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A +#endif + +/* Define tokens from EGL_EXT_image_dma_buf_import_modifiers */ +#ifndef EGL_EXT_image_dma_buf_import_modifiers +#define EGL_EXT_image_dma_buf_import_modifiers 1 +#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440 +#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441 +#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442 +#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443 +#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444 +#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445 +#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446 +#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447 +#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448 +#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449 +#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); +#endif + +#endif /* GLAMOR_EGL_EXT_H */ diff --git a/glamor/glamor_egl_stubs.c b/glamor/glamor_egl_stubs.c index 40f7fcc01..aae909e9f 100644 --- a/glamor/glamor_egl_stubs.c +++ b/glamor/glamor_egl_stubs.c @@ -36,10 +36,18 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) } int -glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, - PixmapPtr pixmap, - unsigned int tex, - Bool want_name, CARD16 *stride, CARD32 *size) +glamor_egl_fd_name_from_pixmap(ScreenPtr screen, + PixmapPtr pixmap, + CARD16 *stride, CARD32 *size) +{ + return -1; +} + + +int +glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, + uint32_t *offsets, uint32_t *strides, + uint64_t *modifier) { return 0; } diff --git a/hw/xwayland/.gitignore b/hw/xwayland/.gitignore index 38ada56d1..c0320b555 100644 --- a/hw/xwayland/.gitignore +++ b/hw/xwayland/.gitignore @@ -5,3 +5,5 @@ pointer-constraints-unstable-v1-client-protocol.h pointer-constraints-unstable-v1-protocol.c relative-pointer-unstable-v1-client-protocol.h relative-pointer-unstable-v1-protocol.c +linux-dmabuf-unstable-v1-client-protocol.h +linux-dmabuf-unstable-v1-protocol.c diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am index 173686e31..f44a7ded3 100644 --- a/hw/xwayland/Makefile.am +++ b/hw/xwayland/Makefile.am @@ -62,8 +62,9 @@ Xwayland_built_sources += \ xwayland-keyboard-grab-unstable-v1-protocol.c \ xwayland-keyboard-grab-unstable-v1-client-protocol.h \ xdg-output-unstable-v1-protocol.c \ - xdg-output-unstable-v1-client-protocol.h - + xdg-output-unstable-v1-client-protocol.h \ + linux-dmabuf-unstable-v1-client-protocol.h \ + linux-dmabuf-unstable-v1-protocol.c nodist_Xwayland_SOURCES = $(Xwayland_built_sources) CLEANFILES = $(Xwayland_built_sources) @@ -100,6 +101,11 @@ xdg-output-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-ou xdg-output-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-output/xdg-output-unstable-v1.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ +linux-dmabuf-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ +linux-dmabuf-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + %-protocol.c : %.xml $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index f6f75001c..7e24c5d63 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -12,7 +12,7 @@ srcs = [ scanner_dep = dependency('wayland-scanner', native: true) scanner = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner')) -protocols_dep = dependency('wayland-protocols') +protocols_dep = dependency('wayland-protocols', version: '>= 1.8') protodir = protocols_dep.get_pkgconfig_variable('pkgdatadir') pointer_xml = join_paths(protodir, 'unstable', 'pointer-constraints', 'pointer-constraints-unstable-v1.xml') @@ -20,6 +20,7 @@ relative_xml = join_paths(protodir, 'unstable', 'relative-pointer', 'relative-po tablet_xml = join_paths(protodir, 'unstable', 'tablet', 'tablet-unstable-v2.xml') kbgrab_xml = join_paths(protodir, 'unstable', 'xwayland-keyboard-grab', 'xwayland-keyboard-grab-unstable-v1.xml') xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unstable-v1.xml') +dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml') client_header = generator(scanner, output : '@BASENAME@-client-protocol.h', @@ -34,11 +35,13 @@ srcs += client_header.process(pointer_xml) srcs += client_header.process(tablet_xml) srcs += client_header.process(kbgrab_xml) srcs += client_header.process(xdg_output_xml) +srcs += client_header.process(dmabuf_xml) srcs += code.process(relative_xml) srcs += code.process(pointer_xml) srcs += code.process(tablet_xml) srcs += code.process(kbgrab_xml) srcs += code.process(xdg_output_xml) +srcs += code.process(dmabuf_xml) xwayland_glamor = [] if gbm_dep.found() diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c index 0933e9411..774a18893 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -28,6 +28,7 @@ #include #include #include +#include #define MESA_EGL_NO_X11_HEADERS #include @@ -158,25 +159,65 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap) struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); int prime_fd; + int num_planes; + uint32_t strides[4]; + uint32_t offsets[4]; + uint64_t modifier; + int i; if (xwl_pixmap->buffer) return xwl_pixmap->buffer; + if (!xwl_pixmap->bo) + return NULL; + prime_fd = gbm_bo_get_fd(xwl_pixmap->bo); if (prime_fd == -1) return NULL; - xwl_pixmap->buffer = - wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd, - pixmap->drawable.width, - pixmap->drawable.height, - wl_drm_format_for_depth(pixmap->drawable.depth), - 0, gbm_bo_get_stride(xwl_pixmap->bo), - 0, 0, - 0, 0); +#ifdef GBM_BO_WITH_MODIFIERS + num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo); + modifier = gbm_bo_get_modifier(xwl_pixmap->bo); + for (i = 0; i < num_planes; i++) { + strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i); + offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i); + } +#else + num_planes = 1; + modifier = DRM_FORMAT_MOD_INVALID; + strides[0] = gbm_go_get_stride(xwl_pixmap->bo); + offsets[0] = 0; +#endif + + if (xwl_screen->dmabuf && modifier != DRM_FORMAT_MOD_INVALID) { + struct zwp_linux_buffer_params_v1 *params; + + params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf); + for (i = 0; i < num_planes; i++) { + zwp_linux_buffer_params_v1_add(params, prime_fd, i, + offsets[i], strides[i], + modifier >> 32, modifier & 0xffffffff); + } + + xwl_pixmap->buffer = + zwp_linux_buffer_params_v1_create_immed(params, + pixmap->drawable.width, + pixmap->drawable.height, + wl_drm_format_for_depth(pixmap->drawable.depth), + 0); + zwp_linux_buffer_params_v1_destroy(params); + } else if (num_planes == 1) { + xwl_pixmap->buffer = + wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd, + pixmap->drawable.width, + pixmap->drawable.height, + wl_drm_format_for_depth(pixmap->drawable.depth), + 0, gbm_bo_get_stride(xwl_pixmap->bo), + 0, 0, + 0, 0); + } close(prime_fd); - return xwl_pixmap->buffer; } @@ -213,7 +254,8 @@ xwl_glamor_destroy_pixmap(PixmapPtr pixmap) wl_buffer_destroy(xwl_pixmap->buffer); eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); - gbm_bo_destroy(xwl_pixmap->bo); + if (xwl_pixmap->bo) + gbm_bo_destroy(xwl_pixmap->bo); free(xwl_pixmap); } @@ -282,8 +324,6 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen) if (xwl_screen->egl_display) return; - xwl_screen->expecting_event--; - xwl_screen->gbm = gbm_create_device(xwl_screen->drm_fd); if (xwl_screen->gbm == NULL) { ErrorF("couldn't get display device\n"); @@ -327,6 +367,12 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen) return; } + if (epoxy_has_egl_extension(xwl_screen->egl_display, + "EXT_image_dma_buf_import") && + epoxy_has_egl_extension(xwl_screen->egl_display, + "EXT_image_dma_buf_import_modifiers")) + xwl_screen->dmabuf_capable = TRUE; + return; } @@ -347,12 +393,14 @@ xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device) return; } + xwl_screen->expecting_event--; + if (is_fd_render_node(xwl_screen->drm_fd)) { xwl_screen->fd_render_node = 1; - xwl_drm_init_egl(xwl_screen); } else { drmGetMagic(xwl_screen->drm_fd, &magic); wl_drm_authenticate(xwl_screen->drm, magic); + xwl_screen->expecting_event++; /* wait for 'authenticated' */ } } @@ -379,8 +427,8 @@ xwl_drm_handle_authenticated(void *data, struct wl_drm *drm) { struct xwl_screen *xwl_screen = data; - if (!xwl_screen->egl_display) - xwl_drm_init_egl(xwl_screen); + xwl_screen->drm_authenticated = 1; + xwl_screen->expecting_event--; } static void @@ -399,8 +447,8 @@ static const struct wl_drm_listener xwl_drm_listener = { }; Bool -xwl_screen_init_glamor(struct xwl_screen *xwl_screen, - uint32_t id, uint32_t version) +xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version) { if (version < 2) return FALSE; @@ -413,11 +461,23 @@ xwl_screen_init_glamor(struct xwl_screen *xwl_screen, return TRUE; } +Bool +xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version) +{ + if (version < 3) + return FALSE; + + xwl_screen->dmabuf = + wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3); + + return TRUE; +} + int -glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, - PixmapPtr pixmap, - unsigned int tex, - Bool want_name, CARD16 *stride, CARD32 *size) +glamor_egl_fd_name_from_pixmap(ScreenPtr screen, + PixmapPtr pixmap, + CARD16 *stride, CARD32 *size) { return 0; } @@ -518,58 +578,111 @@ xwl_dri3_open_client(ClientPtr client, return Success; } -static PixmapPtr -xwl_dri3_pixmap_from_fd(ScreenPtr screen, int fd, - CARD16 width, CARD16 height, CARD16 stride, - CARD8 depth, CARD8 bpp) +_X_EXPORT PixmapPtr +glamor_pixmap_from_fds(ScreenPtr screen, + CARD8 num_fds, int *fds, + CARD16 width, CARD16 height, + CARD32 *strides, CARD32 *offsets, + CARD8 depth, CARD8 bpp, uint64_t modifier) { struct xwl_screen *xwl_screen = xwl_screen_get(screen); - struct gbm_import_fd_data data; - struct gbm_bo *bo; + struct gbm_bo *bo = NULL; PixmapPtr pixmap; + int i; - if (width == 0 || height == 0 || - depth < 15 || bpp != BitsPerPixel(depth) || stride < width * bpp / 8) - return NULL; + if (width == 0 || height == 0 || num_fds == 0 || + depth < 15 || bpp != BitsPerPixel(depth) || + strides[0] < width * bpp / 8) + goto error; + + if (xwl_screen->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) { +#ifdef GBM_BO_WITH_MODIFIERS + struct gbm_import_fd_modifier_data data; + + data.width = width; + data.height = height; + data.num_fds = num_fds; + data.format = gbm_format_for_depth(depth); + data.modifier = modifier; + for (i = 0; i < num_fds; i++) { + data.fds[i] = fds[i]; + data.strides[i] = strides[i]; + data.offsets[i] = offsets[i]; + } + bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD_MODIFIER, &data, 0); +#endif + } else if (num_fds == 1) { + struct gbm_import_fd_data data; + + data.fd = fds[0]; + data.width = width; + data.height = height; + data.stride = strides[0]; + data.format = gbm_format_for_depth(depth); + bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + } else { + goto error; + } - data.fd = fd; - data.width = width; - data.height = height; - data.stride = stride; - data.format = gbm_format_for_depth(depth); - bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); if (bo == NULL) - return NULL; + goto error; pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, depth); if (pixmap == NULL) { - gbm_bo_destroy(bo); - return NULL; + gbm_bo_destroy(bo); + goto error; } return pixmap; + +error: + for (i = 0; i < num_fds; i++) + close(fds[i]); + return NULL; } -static int -xwl_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, - CARD16 *stride, CARD32 *size) +_X_EXPORT int +glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, + uint32_t *strides, uint32_t *offsets, + uint64_t *modifier) { struct xwl_pixmap *xwl_pixmap; +#ifdef GBM_BO_WITH_MODIFIERS + uint32_t num_fds; + int i; +#endif xwl_pixmap = xwl_pixmap_get(pixmap); - *stride = gbm_bo_get_stride(xwl_pixmap->bo); - *size = pixmap->drawable.width * *stride; + if (!xwl_pixmap->bo) + return 0; - return gbm_bo_get_fd(xwl_pixmap->bo); +#ifdef GBM_BO_WITH_MODIFIERS + num_fds = gbm_bo_get_plane_count(xwl_pixmap->bo); + *modifier = gbm_bo_get_modifier(xwl_pixmap->bo); + + for (i = 0; i < num_fds; i++) { + fds[i] = gbm_bo_get_fd(xwl_pixmap->bo); + strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i); + offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i); + } + + return num_fds; +#else + *modifier = DRM_FORMAT_MOD_INVALID; + fds[0] = gbm_bo_get_fd(xwl_pixmap->bo); + strides[0] = gbm_bo_get_stride(xwl_pixmap->bo); + offsets[0] = 0; + return 1; +#endif } static dri3_screen_info_rec xwl_dri3_info = { - .version = 1, + .version = 2, .open = NULL, - .pixmap_from_fd = xwl_dri3_pixmap_from_fd, - .fd_from_pixmap = xwl_dri3_fd_from_pixmap, + .pixmap_from_fds = glamor_pixmap_from_fds, + .fds_from_pixmap = glamor_fds_from_pixmap, .open_client = xwl_dri3_open_client, }; @@ -585,6 +698,12 @@ xwl_glamor_init(struct xwl_screen *xwl_screen) return FALSE; } + if (!xwl_screen->fd_render_node && !xwl_screen->drm_authenticated) { + ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n"); + return FALSE; + } + + xwl_drm_init_egl(xwl_screen); if (xwl_screen->egl_context == EGL_NO_CONTEXT) { ErrorF("Disabling glamor and dri3, EGL setup failed\n"); return FALSE; diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index 73bc47a67..d6a2887ac 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -728,7 +728,11 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, #ifdef GLAMOR_HAS_GBM else if (xwl_screen->glamor && strcmp(interface, "wl_drm") == 0 && version >= 2) { - xwl_screen_init_glamor(xwl_screen, id, version); + xwl_screen_set_drm_interface(xwl_screen, id, version); + } + else if (xwl_screen->glamor && + strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) { + xwl_screen_set_dmabuf_interface(xwl_screen, id, version); } #endif } diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index ffa0d7297..be95bab55 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -47,6 +47,7 @@ #include "tablet-unstable-v2-client-protocol.h" #include "xwayland-keyboard-grab-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" struct xwl_screen { int width; @@ -96,12 +97,15 @@ struct xwl_screen { char *device_name; int drm_fd; int fd_render_node; + int drm_authenticated; struct wl_drm *drm; + struct zwp_linux_dmabuf_v1 *dmabuf; uint32_t formats; uint32_t capabilities; void *egl_display, *egl_context; struct gbm_device *gbm; struct glamor_context *glamor_ctx; + int dmabuf_capable; Atom allow_commits_prop; }; @@ -326,8 +330,10 @@ struct wl_buffer *xwl_shm_pixmap_get_wl_buffer(PixmapPtr pixmap); Bool xwl_glamor_init(struct xwl_screen *xwl_screen); -Bool xwl_screen_init_glamor(struct xwl_screen *xwl_screen, - uint32_t id, uint32_t version); +Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version); +Bool xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version); struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap); void xwl_screen_release_tablet_manager(struct xwl_screen *xwl_screen); diff --git a/include/dix-config.h.in b/include/dix-config.h.in index 65d655ca8..ea932c46d 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -488,6 +488,9 @@ /* Build glamor/gbm has linear support */ #undef GLAMOR_HAS_GBM_LINEAR +/* GBM has modifiers support */ +#undef GBM_BO_WITH_MODIFIERS + /* Build glamor use new drmGetDeviceNameFromFD2 */ #undef GLAMOR_HAS_DRM_NAME_FROM_FD_2 diff --git a/include/meson.build b/include/meson.build index b83180f7c..c39c00420 100644 --- a/include/meson.build +++ b/include/meson.build @@ -84,6 +84,8 @@ conf_data.set('GLAMOR', build_glamor) conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found()) conf_data.set('GLAMOR_HAS_GBM_LINEAR', gbm_dep.found() and gbm_dep.version().version_compare('>= 10.6')) +conf_data.set('GBM_BO_WITH_MODIFIERS', + gbm_dep.found() and gbm_dep.version().version_compare('>= 17.1')) conf_data.set_quoted('SERVER_MISC_CONFIG_PATH', serverconfigdir) conf_data.set_quoted('PROJECTROOT', get_option('prefix'))