[RFC xserver 16/16] xwayland: Use unstable dmabuf extension to support modifiers

Daniel Stone daniels at collabora.com
Thu Jun 8 18:43:42 UTC 2017


From: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>

Use linux-dmabuf-unstable-v1 extension to retrieve supported
formats and modifiers and to create wl_buffers from multi-fds
pixmaps.

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 hw/xwayland/.gitignore        |   3 +
 hw/xwayland/Makefile.am       |   9 ++-
 hw/xwayland/xwayland-glamor.c | 175 ++++++++++++++++++++++++++++--------------
 hw/xwayland/xwayland.c        |   6 +-
 hw/xwayland/xwayland.h        |  17 +++-
 5 files changed, 146 insertions(+), 64 deletions(-)

diff --git a/hw/xwayland/.gitignore b/hw/xwayland/.gitignore
index 38ada56d1..5ce020835 100644
--- a/hw/xwayland/.gitignore
+++ b/hw/xwayland/.gitignore
@@ -5,3 +5,6 @@ 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 7eda9be34..5a65de026 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -57,7 +57,9 @@ Xwayland_built_sources +=					\
 	pointer-constraints-unstable-v1-client-protocol.h	\
 	pointer-constraints-unstable-v1-protocol.c		\
 	tablet-unstable-v2-client-protocol.h			\
-	tablet-unstable-v2-protocol.c
+	tablet-unstable-v2-protocol.c				\
+	linux-dmabuf-unstable-v1-client-protocol.h		\
+	linux-dmabuf-unstable-v1-protocol.c
 
 nodist_Xwayland_SOURCES = $(Xwayland_built_sources)
 CLEANFILES = $(Xwayland_built_sources)
@@ -85,6 +87,11 @@ tablet-unstable-v2-protocol.c: $(WAYLAND_PROTOCOLS_DATADIR)/unstable/tablet/tabl
 tablet-unstable-v2-client-protocol.h: $(WAYLAND_PROTOCOLS_DATADIR)/unstable/tablet/tablet-unstable-v2.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/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index de9769028..49950f997 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -307,29 +307,47 @@ 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;
 
     if (xwl_pixmap->buffer)
         return xwl_pixmap->buffer;
 
-    /* XXX If xwl_pimxap is not backed by a bo (dmabuf),
-     * should we create a wl_buffer using the zwp_linux_dmabuf
-     * interface? Is it safe to use in Xorg server? */
+    if (xwl_pixmap->bo) {
+        int prime_fd;
 
-    prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
-    if (prime_fd == -1)
-        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,
-                                   drm_format_for_depth(pixmap->drawable.depth),
-                                   0, gbm_bo_get_stride(xwl_pixmap->bo),
-                                   0, 0,
-                                   0, 0);
+        xwl_pixmap->buffer =
+            wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
+                                       pixmap->drawable.width,
+                                       pixmap->drawable.height,
+                                       drm_format_for_depth(pixmap->drawable.depth),
+                                       0, gbm_bo_get_stride(xwl_pixmap->bo),
+                                       0, 0,
+                                       0, 0);
+
+        close(prime_fd);
+    } else if (xwl_pixmap->num_fds > 0) {
+        struct  zwp_linux_buffer_params_v1 *params;
+        int i;
+
+        params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf);
+        for (i = 0; i < xwl_pixmap->num_fds; i++) {
+            zwp_linux_buffer_params_v1_add(params, xwl_pixmap->fds[i], i,
+                                           xwl_pixmap->offsets[i],
+                                           xwl_pixmap->strides[i],
+                                           xwl_pixmap->modifier >> 32,
+                                           xwl_pixmap->modifier & 0xffffffff);
+        }
 
-    close(prime_fd);
+        xwl_pixmap->buffer =
+           zwp_linux_buffer_params_v1_create_immed(params,
+                                                   pixmap->drawable.width,
+                                                   pixmap->drawable.height,
+                                                   drm_format_for_depth(pixmap->drawable.depth),
+                                                   0);
+    }
 
     return xwl_pixmap->buffer;
 }
@@ -548,19 +566,6 @@ xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
 static void
 xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
 {
-   struct xwl_screen *xwl_screen = data;
-
-   switch (format) {
-   case WL_DRM_FORMAT_ARGB8888:
-      xwl_screen->formats |= XWL_FORMAT_ARGB8888;
-      break;
-   case WL_DRM_FORMAT_XRGB8888:
-      xwl_screen->formats |= XWL_FORMAT_XRGB8888;
-      break;
-   case WL_DRM_FORMAT_RGB565:
-      xwl_screen->formats |= XWL_FORMAT_RGB565;
-      break;
-   }
 }
 
 static void
@@ -587,9 +592,57 @@ static const struct wl_drm_listener xwl_drm_listener = {
     xwl_drm_handle_capabilities
 };
 
+static void
+xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
+                         uint32_t format)
+{
+}
+
+static void
+xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
+                           uint32_t format, uint32_t modifier_hi,
+                           uint32_t modifier_lo)
+{
+   struct xwl_screen *xwl_screen = data;
+    struct xwl_format *xwl_format = NULL;
+    int i;
+
+    for (i = 0; i < xwl_screen->num_formats; i++) {
+        if (xwl_screen->formats[i].format == format) {
+            xwl_format = &xwl_screen->formats[i];
+            break;
+        }
+    }
+
+    if (xwl_format == NULL) {
+       xwl_screen->num_formats++;
+       xwl_screen->formats = realloc(xwl_screen->formats,
+                                     xwl_screen->num_formats * sizeof(*xwl_format));
+       if (!xwl_screen->formats)
+          return;
+       xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1];
+       xwl_format->format = format;
+       xwl_format->num_modifiers = 0;
+       xwl_format->modifiers = NULL;
+    }
+
+    xwl_format->num_modifiers++;
+    xwl_format->modifiers = realloc(xwl_format->modifiers,
+                                    xwl_format->num_modifiers * sizeof(uint64_t));
+    if (!xwl_format->modifiers)
+       return;
+    xwl_format->modifiers[xwl_format->num_modifiers - 1]  = (uint64_t) modifier_lo;
+    xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32;
+}
+
+static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
+    .format   = xwl_dmabuf_handle_format,
+    .modifier = xwl_dmabuf_handle_modifier
+};
+
 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;
@@ -602,6 +655,20 @@ 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 < 2)
+        return FALSE;
+
+    xwl_screen->dmabuf =
+        wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 2);
+    zwp_linux_dmabuf_v1_add_listener(xwl_screen->dmabuf, &xwl_dmabuf_listener, xwl_screen);
+
+    return TRUE;
+}
+
 int
 glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
                                PixmapPtr pixmap,
@@ -800,29 +867,21 @@ xwl_dri3_get_formats(ScreenPtr screen,
     return FALSE;
 #else
     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
-    EGLint num;
+    int i;
 
-    if (!xwl_screen->modifiers_capable)
+    if (!xwl_screen->modifiers_capable || !xwl_screen->dmabuf)
         return FALSE;
 
-    if (!eglQueryDmaBufFormatsEXT(xwl_screen->egl_display, 0, NULL, &num)) {
-        *num_formats = 0;
-        return FALSE;
-    }
-
-    *formats = calloc(num, sizeof(CARD32));
+    *formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
     if (*formats == NULL) {
         *num_formats = 0;
         return FALSE;
     }
 
-    if (!eglQueryDmaBufFormatsEXT(xwl_screen->egl_display, num, (EGLint *) *formats, &num)) {
-        *num_formats = 0;
-        free(*formats);
-        return FALSE;
-    }
+    for (i = 0; i < xwl_screen->num_formats; i++)
+       (*formats)[i] = xwl_screen->formats[i].format;
+    *num_formats = xwl_screen->num_formats;
 
-    *num_formats = num;
     return TRUE;
 #endif
 }
@@ -835,31 +894,29 @@ xwl_dri3_get_modifiers(ScreenPtr screen, CARD32 format,
     return FALSE;
 #else
     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
-    EGLint num;
+    struct xwl_format *xwl_format = NULL;
+    int i;
 
-    if (!xwl_screen->modifiers_capable)
+    if (!xwl_screen->modifiers_capable || !xwl_screen->dmabuf)
         return FALSE;
 
-    if (!eglQueryDmaBufModifiersEXT(xwl_screen->egl_display, format, 0, NULL,
-                                    NULL, &num)) {
-        *num_modifiers = 0;
-        return FALSE;
+    for (i = 0; i < xwl_screen->num_formats; i++) {
+       if (xwl_screen->formats[i].format == format) {
+          xwl_format = &xwl_screen->formats[i];
+          break;
+       }
     }
 
-    *modifiers = calloc(num, sizeof(uint64_t));
+    *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
     if (*modifiers == NULL) {
         *num_modifiers = 0;
         return FALSE;
     }
 
-    if (!eglQueryDmaBufModifiersEXT(xwl_screen->egl_display, format, num,
-                                  *modifiers, NULL, &num)) {
-        *num_modifiers = 0;
-        free(*modifiers);
-        return FALSE;
-    }
+    for (i = 0; i < xwl_format->num_modifiers; i++)
+       (*modifiers)[i] = xwl_format->modifiers[i];
+    *num_modifiers = xwl_format->num_modifiers;
 
-    *num_modifiers = num;
     return TRUE;
 #endif
 }
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 551443f93..67c00e7e0 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -678,7 +678,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 >= 2) {
+        xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
     }
 #endif
 }
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index df2a3087d..25fac5d6f 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -45,6 +45,13 @@
 #include "relative-pointer-unstable-v1-client-protocol.h"
 #include "pointer-constraints-unstable-v1-client-protocol.h"
 #include "tablet-unstable-v2-client-protocol.h"
+#include "linux-dmabuf-unstable-v1-client-protocol.h"
+
+struct xwl_format {
+    uint32_t format;
+    int num_modifiers;
+    uint64_t *modifiers;
+};
 
 struct xwl_screen {
     int width;
@@ -94,7 +101,9 @@ struct xwl_screen {
     int drm_fd;
     int fd_render_node;
     struct wl_drm *drm;
-    uint32_t formats;
+    struct zwp_linux_dmabuf_v1 *dmabuf;
+    uint32_t num_formats;
+    struct xwl_format *formats;
     uint32_t capabilities;
     void *egl_display, *egl_context;
     struct gbm_device *gbm;
@@ -317,8 +326,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);
-- 
2.13.0



More information about the xorg-devel mailing list