[Mesa-dev] [PATCH v3 8/8] egl/wayland: Use linux-dmabuf interface for buffers

Daniel Stone daniels at collabora.com
Fri Jul 14 13:36:42 UTC 2017


When available, use the zwp_linux_dambuf_v1 interface to create buffers,
which allows multiple planes and buffer modifiers to be used.

Reviewed-by: Emil Velikov <emil.velikov at collabora.com>
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 configure.ac                            |   5 +-
 src/egl/Makefile.am                     |  23 +++-
 src/egl/drivers/dri2/.gitignore         |   2 +
 src/egl/drivers/dri2/egl_dri2.c         |   7 ++
 src/egl/drivers/dri2/egl_dri2.h         |  10 ++
 src/egl/drivers/dri2/platform_wayland.c | 195 +++++++++++++++++++++++++++++---
 6 files changed, 221 insertions(+), 21 deletions(-)
 create mode 100644 src/egl/drivers/dri2/.gitignore

diff --git a/configure.ac b/configure.ac
index 46fcd8f3fe..c5803e0f6e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,6 +88,7 @@ LIBOMXIL_BELLAGIO_REQUIRED=0.0
 LIBVA_REQUIRED=0.38.0
 VDPAU_REQUIRED=1.1
 WAYLAND_REQUIRED=1.11
+WAYLAND_PROTOCOLS_REQUIRED=1.8
 XCB_REQUIRED=1.9.3
 XCBDRI2_REQUIRED=1.8
 XCBGLX_REQUIRED=1.8.1
@@ -1686,7 +1687,9 @@ for plat in $platforms; do
 	case "$plat" in
 	wayland)
 
-		PKG_CHECK_MODULES([WAYLAND], [wayland-client >= $WAYLAND_REQUIRED wayland-server >= $WAYLAND_REQUIRED])
+		PKG_CHECK_MODULES([WAYLAND], [wayland-client >= $WAYLAND_REQUIRED wayland-server >= $WAYLAND_REQUIRED wayland-protocols >= $WAYLAND_PROTOCOLS_REQUIRED])
+                ac_wayland_protocols_pkgdatadir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`
+                AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, $ac_wayland_protocols_pkgdatadir)
 
 		if test "x$WAYLAND_SCANNER" = "x:"; then
 			AC_MSG_ERROR([wayland-scanner is needed to compile the wayland platform])
diff --git a/src/egl/Makefile.am b/src/egl/Makefile.am
index 81090387b5..19295de3ed 100644
--- a/src/egl/Makefile.am
+++ b/src/egl/Makefile.am
@@ -21,6 +21,8 @@
 
 include Makefile.sources
 
+BUILT_SOURCES =
+
 AM_CFLAGS = \
 	-I$(top_srcdir)/include \
 	-I$(top_srcdir)/src/egl/main \
@@ -61,11 +63,27 @@ endif
 endif
 
 if HAVE_PLATFORM_WAYLAND
+WL_DMABUF_XML = $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
+
+drivers/dri2/linux-dmabuf-unstable-v1-protocol.c: $(WL_DMABUF_XML)
+	$(MKDIR_GEN)
+	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
+
+drivers/dri2/linux-dmabuf-unstable-v1-client-protocol.h: $(WL_DMABUF_XML)
+	$(MKDIR_GEN)
+	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+
+BUILT_SOURCES += \
+	drivers/dri2/linux-dmabuf-unstable-v1-protocol.c \
+	drivers/dri2/linux-dmabuf-unstable-v1-client-protocol.h
+
 AM_CFLAGS += $(WAYLAND_CFLAGS)
 libEGL_common_la_LIBADD += $(WAYLAND_LIBS)
 libEGL_common_la_LIBADD += $(LIBDRM_LIBS)
 libEGL_common_la_LIBADD += $(top_builddir)/src/egl/wayland/wayland-drm/libwayland-drm.la
-dri2_backend_FILES += drivers/dri2/platform_wayland.c
+libEGL_common_la_LIBADD += $(top_builddir)/src/util/libmesautil.la
+dri2_backend_FILES += drivers/dri2/platform_wayland.c	\
+	drivers/dri2/linux-dmabuf-unstable-v1-protocol.c
 endif
 
 if HAVE_PLATFORM_DRM
@@ -85,6 +103,7 @@ endif
 
 AM_CFLAGS += \
 	-I$(top_srcdir)/src/loader \
+	-I$(top_builddir)/src/egl/drivers/dri2 \ 
 	-I$(top_srcdir)/src/egl/drivers/dri2 \
 	-I$(top_srcdir)/src/gbm/backends/dri \
 	-I$(top_srcdir)/src/egl/wayland/wayland-egl \
@@ -118,7 +137,7 @@ g_egldispatchstubs.h: $(GLVND_GEN_DEPS)
 		$(top_srcdir)/src/egl/generate/egl.xml \
 		$(top_srcdir)/src/egl/generate/egl_other.xml > $@
 
-BUILT_SOURCES = g_egldispatchstubs.c g_egldispatchstubs.h
+BUILT_SOURCES += g_egldispatchstubs.c g_egldispatchstubs.h
 CLEANFILES = $(BUILT_SOURCES)
 
 if USE_LIBGLVND
diff --git a/src/egl/drivers/dri2/.gitignore b/src/egl/drivers/dri2/.gitignore
new file mode 100644
index 0000000000..e96becbb54
--- /dev/null
+++ b/src/egl/drivers/dri2/.gitignore
@@ -0,0 +1,2 @@
+linux-dmabuf-unstable-v1-client-protocol.h
+linux-dmabuf-unstable-v1-protocol.c
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 5bf36bf309..e16aefff3c 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -53,6 +53,7 @@
 #ifdef HAVE_WAYLAND_PLATFORM
 #include "wayland-drm.h"
 #include "wayland-drm-client-protocol.h"
+#include "linux-dmabuf-unstable-v1-client-protocol.h"
 #endif
 
 #ifdef HAVE_X11_PLATFORM
@@ -62,6 +63,7 @@
 #include "egl_dri2.h"
 #include "loader/loader.h"
 #include "util/u_atomic.h"
+#include "util/u_vector.h"
 
 /* The kernel header drm_fourcc.h defines the DRM formats below.  We duplicate
  * some of the definitions here so that building Mesa won't bleeding-edge
@@ -934,11 +936,16 @@ dri2_display_destroy(_EGLDisplay *disp)
    case _EGL_PLATFORM_WAYLAND:
       if (dri2_dpy->wl_drm)
           wl_drm_destroy(dri2_dpy->wl_drm);
+      if (dri2_dpy->wl_dmabuf)
+          zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf);
       if (dri2_dpy->wl_shm)
           wl_shm_destroy(dri2_dpy->wl_shm);
       wl_registry_destroy(dri2_dpy->wl_registry);
       wl_event_queue_destroy(dri2_dpy->wl_queue);
       wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
+      u_vector_finish(&dri2_dpy->wl_modifiers.argb8888);
+      u_vector_finish(&dri2_dpy->wl_modifiers.xrgb8888);
+      u_vector_finish(&dri2_dpy->wl_modifiers.rgb565);
       if (dri2_dpy->own_device) {
          wl_display_disconnect(dri2_dpy->wl_dpy);
       }
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 4a5cf8e4ef..db19bb7809 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -45,6 +45,8 @@
 #ifdef HAVE_WAYLAND_PLATFORM
 #include <wayland-client.h>
 #include "wayland-egl-priv.h"
+/* forward declarations of protocol elements */
+struct zwp_linux_dmabuf_v1;
 #endif
 
 #include <GL/gl.h>
@@ -73,6 +75,8 @@
 #include "eglimage.h"
 #include "eglsync.h"
 
+#include "util/u_vector.h"
+
 struct wl_buffer;
 
 struct dri2_egl_driver
@@ -211,6 +215,12 @@ struct dri2_egl_display
    struct wl_drm            *wl_drm;
    struct wl_shm            *wl_shm;
    struct wl_event_queue    *wl_queue;
+   struct zwp_linux_dmabuf_v1 *wl_dmabuf;
+   struct {
+      struct u_vector        xrgb8888;
+      struct u_vector        argb8888;
+      struct u_vector        rgb565;
+   } wl_modifiers;
    bool                      authenticated;
    int                       formats;
    uint32_t                  capabilities;
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index 4f941a16aa..211036f45f 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -36,14 +36,25 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <xf86drm.h>
+#include <drm_fourcc.h>
 #include <sys/mman.h>
 
 #include "egl_dri2.h"
 #include "egl_dri2_fallbacks.h"
 #include "loader.h"
+#include "util/u_vector.h"
 
 #include <wayland-client.h>
 #include "wayland-drm-client-protocol.h"
+#include "linux-dmabuf-unstable-v1-client-protocol.h"
+
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
+#endif
+
+#ifndef DRM_FORMAT_MOD_LINEAR
+#define DRM_FORMAT_MOD_LINEAR 0
+#endif
 
 enum wl_drm_format_flags {
    HAS_ARGB8888 = 1,
@@ -331,6 +342,8 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
       dri2_egl_display(dri2_surf->base.Resource.Display);
    int use_flags;
    unsigned int dri_image_format;
+   uint64_t *modifiers;
+   int num_modifiers;
 
    /* currently supports three WL DRM formats,
     * WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888,
@@ -339,12 +352,18 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
    switch (dri2_surf->format) {
    case WL_DRM_FORMAT_ARGB8888:
       dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888;
+      modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.argb8888);
+      num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.argb8888);
       break;
    case WL_DRM_FORMAT_XRGB8888:
       dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888;
+      modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.xrgb8888);
+      num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.xrgb8888);
       break;
    case WL_DRM_FORMAT_RGB565:
       dri_image_format = __DRI_IMAGE_FORMAT_RGB565;
+      modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.rgb565);
+      num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.rgb565);
       break;
    default:
       /* format is not supported */
@@ -382,27 +401,60 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
 
    if (dri2_dpy->is_different_gpu &&
        dri2_surf->back->linear_copy == NULL) {
-       dri2_surf->back->linear_copy =
-          dri2_dpy->image->createImage(dri2_dpy->dri_screen,
-                                      dri2_surf->base.Width,
-                                      dri2_surf->base.Height,
-                                      dri_image_format,
-                                      use_flags |
-                                      __DRI_IMAGE_USE_LINEAR,
-                                      NULL);
+      /* The LINEAR modifier should be a perfect alias of the LINEAR use
+       * flag; try the new interface first before the old, then fall back. */
+      if (dri2_dpy->image->base.version >= 15 &&
+           dri2_dpy->image->createImageWithModifiers) {
+         uint64_t linear_mod = DRM_FORMAT_MOD_LINEAR;
+
+         dri2_surf->back->linear_copy =
+            dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
+                                                      dri2_surf->base.Width,
+                                                      dri2_surf->base.Height,
+                                                      dri_image_format,
+                                                      &linear_mod,
+                                                      1,
+                                                      NULL);
+      } else {
+         dri2_surf->back->linear_copy =
+            dri2_dpy->image->createImage(dri2_dpy->dri_screen,
+                                         dri2_surf->base.Width,
+                                         dri2_surf->base.Height,
+                                         dri_image_format,
+                                         use_flags |
+                                         __DRI_IMAGE_USE_LINEAR,
+                                         NULL);
+      }
       if (dri2_surf->back->linear_copy == NULL)
           return -1;
    }
 
    if (dri2_surf->back->dri_image == NULL) {
-      dri2_surf->back->dri_image =
-         dri2_dpy->image->createImage(dri2_dpy->dri_screen,
-                                      dri2_surf->base.Width,
-                                      dri2_surf->base.Height,
-                                      dri_image_format,
-                                      dri2_dpy->is_different_gpu ?
-                                         0 : use_flags,
-                                      NULL);
+      /* If our DRIImage implementation does not support
+       * createImageWithModifiers, then fall back to the old createImage,
+       * and hope it allocates an image which is acceptable to the winsys.
+        */
+      if (num_modifiers && dri2_dpy->image->base.version >= 15 &&
+          dri2_dpy->image->createImageWithModifiers) {
+         dri2_surf->back->dri_image =
+           dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
+                                                     dri2_surf->base.Width,
+                                                     dri2_surf->base.Height,
+                                                     dri_image_format,
+                                                     modifiers,
+                                                     num_modifiers,
+                                                     NULL);
+      } else {
+         dri2_surf->back->dri_image =
+            dri2_dpy->image->createImage(dri2_dpy->dri_screen,
+                                         dri2_surf->base.Width,
+                                         dri2_surf->base.Height,
+                                         dri_image_format,
+                                         dri2_dpy->is_different_gpu ?
+                                              0 : use_flags,
+                                         NULL);
+      }
+
       dri2_surf->back->age = 0;
    }
    if (dri2_surf->back->dri_image == NULL)
@@ -643,17 +695,68 @@ create_wl_buffer(struct dri2_egl_display *dri2_dpy,
                  __DRIimage *image)
 {
    struct wl_buffer *ret;
-   int width, height, fourcc;
+   int width, height, fourcc, num_planes;
 
    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC, &fourcc);
+   dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES,
+                               &num_planes);
+
+   if (dri2_dpy->wl_dmabuf && dri2_dpy->image->base.version >= 15) {
+      struct zwp_linux_buffer_params_v1 *params;
+      int mod_hi, mod_lo;
+      int i;
+
+      dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
+                                  &mod_hi);
+      dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
+                                  &mod_lo);
+
+      /* We don't need a wrapper for wl_dmabuf objects, because we have to
+       * create the intermediate params object; we can set the queue on this,
+       * and the wl_buffer inherits it race-free. */
+      params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf);
+      if (dri2_surf)
+         wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue);
+
+      for (i = 0; i < num_planes; i++) {
+         __DRIimage *p_image;
+         int stride, offset, fd;
+
+         if (i == 0)
+            p_image = image;
+         else
+            p_image = dri2_dpy->image->fromPlanar(image, i, NULL);
+         if (!p_image) {
+            zwp_linux_buffer_params_v1_destroy(params);
+            return NULL;
+         }
 
-   if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
+         dri2_dpy->image->queryImage(p_image, __DRI_IMAGE_ATTRIB_FD, &fd);
+         dri2_dpy->image->queryImage(p_image, __DRI_IMAGE_ATTRIB_STRIDE,
+                                     &stride);
+         dri2_dpy->image->queryImage(p_image, __DRI_IMAGE_ATTRIB_OFFSET,
+                                     &offset);
+         if (image != p_image)
+            dri2_dpy->image->destroyImage(p_image);
+
+         zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride,
+                                        mod_hi, mod_lo);
+         close(fd);
+      }
+
+      ret = zwp_linux_buffer_params_v1_create_immed(params, width, height,
+                                                    fourcc, 0);
+      zwp_linux_buffer_params_v1_destroy(params);
+   } else if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
       struct wl_drm *wl_drm =
          dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
       int fd, stride;
 
+      if (num_planes > 1)
+         return NULL;
+
       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
       ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0,
@@ -664,6 +767,9 @@ create_wl_buffer(struct dri2_egl_display *dri2_dpy,
          dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
       int name, stride;
 
+      if (num_planes > 1)
+         return NULL;
+
       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
       ret = wl_drm_create_buffer(wl_drm, name, width, height, stride, fourcc);
@@ -949,6 +1055,47 @@ static const struct wl_drm_listener drm_listener = {
 };
 
 static void
+dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
+                     uint32_t format)
+{
+   /* formats are implicitly advertised by the 'modifier' event, so ignore */
+}
+
+static void
+dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
+                       uint32_t format, uint32_t modifier_hi,
+                       uint32_t modifier_lo)
+{
+   struct dri2_egl_display *dri2_dpy = data;
+   uint64_t *mod = NULL;
+
+   switch (format) {
+   case WL_DRM_FORMAT_ARGB8888:
+      mod = u_vector_add(&dri2_dpy->wl_modifiers.argb8888);
+      break;
+   case WL_DRM_FORMAT_XRGB8888:
+      mod = u_vector_add(&dri2_dpy->wl_modifiers.xrgb8888);
+      break;
+   case WL_DRM_FORMAT_RGB565:
+      mod = u_vector_add(&dri2_dpy->wl_modifiers.rgb565);
+      break;
+   default:
+      break;
+   }
+
+   if (!mod)
+      return;
+
+   *mod = (uint64_t) modifier_hi << 32;
+   *mod |= (uint64_t) (modifier_lo & 0xffffffff);
+}
+
+static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
+   .format = dmabuf_ignore_format,
+   .modifier = dmabuf_handle_modifier,
+};
+
+static void
 registry_handle_global_drm(void *data, struct wl_registry *registry,
                            uint32_t name, const char *interface,
                            uint32_t version)
@@ -959,6 +1106,12 @@ registry_handle_global_drm(void *data, struct wl_registry *registry,
       dri2_dpy->wl_drm =
          wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2));
       wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
+   } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
+      dri2_dpy->wl_dmabuf =
+         wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
+                          MIN2(version, 3));
+      zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,
+                                       dri2_dpy);
    }
 }
 
@@ -1127,6 +1280,12 @@ dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp)
       dri2_dpy->wl_dpy = disp->PlatformDisplay;
    }
 
+   if (!u_vector_init(&dri2_dpy->wl_modifiers.xrgb8888, sizeof(uint64_t), 32) ||
+       !u_vector_init(&dri2_dpy->wl_modifiers.argb8888, sizeof(uint64_t), 32) ||
+       !u_vector_init(&dri2_dpy->wl_modifiers.rgb565, sizeof(uint64_t), 32)) {
+      goto cleanup;
+   }
+
    dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
 
    dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
-- 
2.13.0



More information about the mesa-dev mailing list