[PATCH xserver v8 11/14] glamor: Implement PixmapFromBuffers and BuffersFromPixmap
Daniel Stone
daniels at collabora.com
Wed Feb 28 01:19:43 UTC 2018
From: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
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
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Reviewed-by: Daniel Stone <daniels at collabora.com>
---
configure.ac | 4 +
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 | 219 ++++++++++++++++++++++++++++++++----------
hw/xwayland/xwayland.c | 6 +-
hw/xwayland/xwayland.h | 10 +-
include/dix-config.h.in | 3 +
include/meson.build | 2 +
15 files changed, 461 insertions(+), 120 deletions(-)
create mode 100644 glamor/glamor_egl_ext.h
diff --git a/configure.ac b/configure.ac
index 283d8e20c..392511541 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2100,6 +2100,10 @@ if test "x$GLAMOR" = xyes; then
[AC_DEFINE(GLAMOR_HAS_GBM_LINEAR, 1, [Have GBM_BO_USE_LINEAR])], [],
[#include <stdlib.h>
#include <gbm.h>])
+ 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/glamor.c b/glamor/glamor.c
index d61e27563..c890d0ce0 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -32,6 +32,7 @@
*/
#include <stdlib.h>
+#include <unistd.h>
#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 <epoxy/gl.h>
#include <epoxy/egl.h>
+#include <glamor_egl_ext.h>
/*
* 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 at -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 <fcntl.h>
#include <sys/stat.h>
#include <xf86drm.h>
+#include <drm_fourcc.h>
#define MESA_EGL_NO_X11_HEADERS
#include <gbm.h>
@@ -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
- close(prime_fd);
+ 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 || 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;
+ }
- if (width == 0 || height == 0 ||
- depth < 15 || bpp != BitsPerPixel(depth) || stride < width * bpp / 8)
- return NULL;
-
- 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 bbb7d14e8..88ced768f 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -85,6 +85,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'))
--
2.14.3
More information about the xorg-devel
mailing list