[PATCH] xwayland: Add glamor and DRI3 support

Kristian Høgsberg krh at bitplanet.net
Mon Jun 16 11:34:55 PDT 2014


Reviewed-by: Axel Davy <axel.davy at ens.fr>
Signed-off-by: Kristian Høgsberg <krh at bitplanet.net>
---

This patch comes in after the 1.16 feature freeze, but we had to wait for
mesa 10.2 to come out.  The mesa release brings the new gbm api that we
use to implement dri3 and glamor support in Xwayland.

As can be seen from the diffstat below, the only change outside hw/xwayland
is the configure.ac change to look for a new enough gbm and to look up the
wayland-scanner binary.

Kristian

 configure.ac                  |   6 +-
 hw/xwayland/Makefile.am       |  31 ++-
 hw/xwayland/drm.xml           | 182 ++++++++++++++
 hw/xwayland/xwayland-glamor.c | 570 ++++++++++++++++++++++++++++++++++++++++++
 hw/xwayland/xwayland.c        |  38 ++-
 hw/xwayland/xwayland.h        |  17 ++
 6 files changed, 837 insertions(+), 7 deletions(-)
 create mode 100644 hw/xwayland/drm.xml
 create mode 100644 hw/xwayland/xwayland-glamor.c

diff --git a/configure.ac b/configure.ac
index 0a6e772..2056323 100644
--- a/configure.ac
+++ b/configure.ac
@@ -810,7 +810,7 @@ LIBDMX="dmx >= 1.0.99.1"
 LIBDRI="dri >= 7.8.0"
 LIBDRM="libdrm >= 2.3.0"
 LIBEGL="egl"
-LIBGBM="gbm >= 9"
+LIBGBM="gbm >= 10.2.0"
 LIBGL="gl >= 7.1.0"
 LIBXEXT="xext >= 1.0.99.4"
 LIBXFONT="xfont >= 1.4.2"
@@ -2459,6 +2459,10 @@ if test "x$XWAYLAND" = xyes; then
 	XWAYLAND_SYS_LIBS="$XWAYLANDMODULES_LIBS $GLX_SYS_LIBS"
 	AC_SUBST([XWAYLAND_LIBS])
 	AC_SUBST([XWAYLAND_SYS_LIBS])
+
+	WAYLAND_PREFIX=`$PKG_CONFIG --variable=prefix wayland-client`
+	AC_PATH_PROG([WAYLAND_SCANNER], [wayland-scanner],,
+		     [${WAYLAND_PREFIX}/bin$PATH_SEPARATOR$PATH])
 fi
 
 
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 36e6127..dc16b8b 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -1,10 +1,13 @@
 bin_PROGRAMS = Xwayland
 
 Xwayland_CFLAGS =				\
+	-I$(top_srcdir)/glamor			\
 	-I$(top_srcdir)/dri3			\
 	-DHAVE_DIX_CONFIG_H			\
 	$(XWAYLANDMODULES_CFLAGS)		\
-	$(DIX_CFLAGS)
+	$(DIX_CFLAGS)				\
+	$(GLAMOR_CFLAGS)			\
+	$(GBM_CFLAGS)
 
 Xwayland_SOURCES =				\
 	xwayland.c				\
@@ -19,6 +22,7 @@ Xwayland_SOURCES =				\
 	$(top_srcdir)/mi/miinitext.c
 
 Xwayland_LDADD =				\
+	$(glamor_lib)				\
 	$(XWAYLAND_LIBS)			\
 	$(XWAYLAND_SYS_LIBS)			\
 	$(XSERVER_SYS_LIBS)
@@ -26,5 +30,30 @@ Xwayland_DEPENDENCIES = $(XWAYLAND_LIBS)
 Xwayland_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
 
 
+if GLAMOR_EGL
+Xwayland_SOURCES += xwayland-glamor.c
+
+nodist_Xwayland_SOURCES =			\
+	drm-client-protocol.h			\
+	drm-protocol.c
+
+CLEANFILES = $(nodist_Xwayland_SOURCES)
+
+EXTRA_DIST = drm.xml
+
+xwayland-glamor.c : $(nodist_Xwayland_SOURCES)
+
+glamor_lib = $(top_builddir)/glamor/libglamor.la
+
+Xwayland_LDADD += $(GLAMOR_LIBS) $(GBM_LIBS) -lEGL -lGL
+endif
+
+
 relink:
 	$(AM_V_at)rm -f Xwayland$(EXEEXT) && $(MAKE) Xwayland$(EXEEXT)
+
+%-protocol.c : %.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
+
+%-client-protocol.h : %.xml
+	$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
diff --git a/hw/xwayland/drm.xml b/hw/xwayland/drm.xml
new file mode 100644
index 0000000..8a3ad69
--- /dev/null
+++ b/hw/xwayland/drm.xml
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="drm">
+
+  <copyright>
+    Copyright © 2008-2011 Kristian Høgsberg
+    Copyright © 2010-2011 Intel Corporation
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that\n the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+  <!-- drm support. This object is created by the server and published
+       using the display's global event. -->
+  <interface name="wl_drm" version="2">
+    <enum name="error">
+      <entry name="authenticate_fail" value="0"/>
+      <entry name="invalid_format" value="1"/>
+      <entry name="invalid_name" value="2"/>
+    </enum>
+
+    <enum name="format">
+      <!-- The drm format codes match the #defines in drm_fourcc.h.
+           The formats actually supported by the compositor will be
+           reported by the format event. -->
+      <entry name="c8" value="0x20203843"/>
+      <entry name="rgb332" value="0x38424752"/>
+      <entry name="bgr233" value="0x38524742"/>
+      <entry name="xrgb4444" value="0x32315258"/>
+      <entry name="xbgr4444" value="0x32314258"/>
+      <entry name="rgbx4444" value="0x32315852"/>
+      <entry name="bgrx4444" value="0x32315842"/>
+      <entry name="argb4444" value="0x32315241"/>
+      <entry name="abgr4444" value="0x32314241"/>
+      <entry name="rgba4444" value="0x32314152"/>
+      <entry name="bgra4444" value="0x32314142"/>
+      <entry name="xrgb1555" value="0x35315258"/>
+      <entry name="xbgr1555" value="0x35314258"/>
+      <entry name="rgbx5551" value="0x35315852"/>
+      <entry name="bgrx5551" value="0x35315842"/>
+      <entry name="argb1555" value="0x35315241"/>
+      <entry name="abgr1555" value="0x35314241"/>
+      <entry name="rgba5551" value="0x35314152"/>
+      <entry name="bgra5551" value="0x35314142"/>
+      <entry name="rgb565" value="0x36314752"/>
+      <entry name="bgr565" value="0x36314742"/>
+      <entry name="rgb888" value="0x34324752"/>
+      <entry name="bgr888" value="0x34324742"/>
+      <entry name="xrgb8888" value="0x34325258"/>
+      <entry name="xbgr8888" value="0x34324258"/>
+      <entry name="rgbx8888" value="0x34325852"/>
+      <entry name="bgrx8888" value="0x34325842"/>
+      <entry name="argb8888" value="0x34325241"/>
+      <entry name="abgr8888" value="0x34324241"/>
+      <entry name="rgba8888" value="0x34324152"/>
+      <entry name="bgra8888" value="0x34324142"/>
+      <entry name="xrgb2101010" value="0x30335258"/>
+      <entry name="xbgr2101010" value="0x30334258"/>
+      <entry name="rgbx1010102" value="0x30335852"/>
+      <entry name="bgrx1010102" value="0x30335842"/>
+      <entry name="argb2101010" value="0x30335241"/>
+      <entry name="abgr2101010" value="0x30334241"/>
+      <entry name="rgba1010102" value="0x30334152"/>
+      <entry name="bgra1010102" value="0x30334142"/>
+      <entry name="yuyv" value="0x56595559"/>
+      <entry name="yvyu" value="0x55595659"/>
+      <entry name="uyvy" value="0x59565955"/>
+      <entry name="vyuy" value="0x59555956"/>
+      <entry name="ayuv" value="0x56555941"/>
+      <entry name="nv12" value="0x3231564e"/>
+      <entry name="nv21" value="0x3132564e"/>
+      <entry name="nv16" value="0x3631564e"/>
+      <entry name="nv61" value="0x3136564e"/>
+      <entry name="yuv410" value="0x39565559"/>
+      <entry name="yvu410" value="0x39555659"/>
+      <entry name="yuv411" value="0x31315559"/>
+      <entry name="yvu411" value="0x31315659"/>
+      <entry name="yuv420" value="0x32315559"/>
+      <entry name="yvu420" value="0x32315659"/>
+      <entry name="yuv422" value="0x36315559"/>
+      <entry name="yvu422" value="0x36315659"/>
+      <entry name="yuv444" value="0x34325559"/>
+      <entry name="yvu444" value="0x34325659"/>
+    </enum>
+
+    <!-- Call this request with the magic received from drmGetMagic().
+         It will be passed on to the drmAuthMagic() or
+         DRIAuthConnection() call.  This authentication must be
+         completed before create_buffer could be used. -->
+    <request name="authenticate">
+      <arg name="id" type="uint"/>
+    </request>
+
+    <!-- Create a wayland buffer for the named DRM buffer.  The DRM
+         surface must have a name using the flink ioctl -->
+    <request name="create_buffer">
+      <arg name="id" type="new_id" interface="wl_buffer"/>
+      <arg name="name" type="uint"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="stride" type="uint"/>
+      <arg name="format" type="uint"/>
+    </request>
+
+    <!-- Create a wayland buffer for the named DRM buffer.  The DRM
+         surface must have a name using the flink ioctl -->
+    <request name="create_planar_buffer">
+      <arg name="id" type="new_id" interface="wl_buffer"/>
+      <arg name="name" type="uint"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="format" type="uint"/>
+      <arg name="offset0" type="int"/>
+      <arg name="stride0" type="int"/>
+      <arg name="offset1" type="int"/>
+      <arg name="stride1" type="int"/>
+      <arg name="offset2" type="int"/>
+      <arg name="stride2" type="int"/>
+    </request>
+
+    <!-- Create a wayland buffer for the prime fd.  Use for regular and planar
+         buffers.  Pass 0 for offset and stride for unused planes. -->
+    <request name="create_prime_buffer" since="2">
+      <arg name="id" type="new_id" interface="wl_buffer"/>
+      <arg name="name" type="fd"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="format" type="uint"/>
+      <arg name="offset0" type="int"/>
+      <arg name="stride0" type="int"/>
+      <arg name="offset1" type="int"/>
+      <arg name="stride1" type="int"/>
+      <arg name="offset2" type="int"/>
+      <arg name="stride2" type="int"/>
+    </request>
+
+    <!-- Notification of the path of the drm device which is used by
+         the server.  The client should use this device for creating
+         local buffers.  Only buffers created from this device should
+         be be passed to the server using this drm object's
+         create_buffer request. -->
+    <event name="device">
+      <arg name="name" type="string"/>
+    </event>
+
+    <event name="format">
+      <arg name="format" type="uint"/>
+    </event>
+
+    <!-- Raised if the authenticate request succeeded -->
+    <event name="authenticated"/>
+
+    <enum name="capability" since="2">
+      <description summary="wl_drm capability bitmask">
+        Bitmask of capabilities.
+      </description>
+      <entry name="prime" value="1" summary="wl_drm prime available"/>
+    </enum>
+
+    <event name="capabilities">
+      <arg name="value" type="uint"/>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
new file mode 100644
index 0000000..4be883f
--- /dev/null
+++ b/hw/xwayland/xwayland-glamor.c
@@ -0,0 +1,570 @@
+/*
+ * Copyright © 2011-2014 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "xwayland.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <xf86drm.h>
+
+#define MESA_EGL_NO_X11_HEADERS
+#include <gbm.h>
+#include <epoxy/egl.h>
+#include <epoxy/gl.h>
+
+#include <glamor.h>
+#include <glamor_context.h>
+#include <dri3.h>
+#include "drm-client-protocol.h"
+
+struct xwl_pixmap {
+    struct wl_buffer *buffer;
+    struct gbm_bo *bo;
+    void *image;
+    unsigned int texture;
+};
+
+static void
+xwl_glamor_egl_make_current(struct glamor_context *glamor_ctx)
+{
+    eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE,
+                   EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    if (!eglMakeCurrent(glamor_ctx->display,
+                        EGL_NO_SURFACE, EGL_NO_SURFACE,
+                        glamor_ctx->ctx))
+        FatalError("Failed to make EGL context current\n");
+}
+
+static uint32_t
+drm_format_for_depth(int depth)
+{
+    switch (depth) {
+    case 15:
+        return WL_DRM_FORMAT_XRGB1555;
+    case 16:
+        return WL_DRM_FORMAT_RGB565;
+    case 24:
+        return WL_DRM_FORMAT_XRGB8888;
+    default:
+        ErrorF("unexpected depth: %d\n", depth);
+    case 32:
+        return WL_DRM_FORMAT_ARGB8888;
+    }
+}
+
+static uint32_t
+gbm_format_for_depth(int 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;
+    }
+}
+
+void
+glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+
+    glamor_ctx->ctx = xwl_screen->egl_context;
+    glamor_ctx->display = xwl_screen->egl_display;
+
+    glamor_ctx->make_current = xwl_glamor_egl_make_current;
+
+    xwl_screen->glamor_ctx = glamor_ctx;
+}
+
+static PixmapPtr
+xwl_glamor_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, int depth)
+{
+    PixmapPtr pixmap;
+    struct xwl_pixmap *xwl_pixmap;
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+
+    xwl_pixmap = malloc(sizeof *xwl_pixmap);
+    if (xwl_pixmap == NULL)
+        return NULL;
+
+    pixmap = glamor_create_pixmap(screen,
+                                  gbm_bo_get_width(bo),
+                                  gbm_bo_get_height(bo),
+                                  depth,
+                                  GLAMOR_CREATE_PIXMAP_NO_TEXTURE);
+    if (pixmap == NULL) {
+        free(xwl_pixmap);
+        return NULL;
+    }
+
+    if (lastGLContext != xwl_screen->glamor_ctx) {
+        lastGLContext = xwl_screen->glamor_ctx;
+        xwl_glamor_egl_make_current(xwl_screen->glamor_ctx);
+    }
+
+    xwl_pixmap->bo = bo;
+    xwl_pixmap->buffer = NULL;
+    xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
+                                          xwl_screen->egl_context,
+                                          EGL_NATIVE_PIXMAP_KHR,
+                                          xwl_pixmap->bo, NULL);
+
+    glGenTextures(1, &xwl_pixmap->texture);
+    glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture);
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    xwl_pixmap_set_private(pixmap, xwl_pixmap);
+
+    glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture);
+    glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+
+    return pixmap;
+}
+
+struct wl_buffer *
+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;
+
+    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);
+
+    close(prime_fd);
+
+    return xwl_pixmap->buffer;
+}
+
+static PixmapPtr
+xwl_glamor_create_pixmap(ScreenPtr screen,
+                         int width, int height, int depth, unsigned int hint)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct gbm_bo *bo;
+
+    if (width > 0 && height > 0 && depth >= 15 &&
+        (hint == 0 ||
+         hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP ||
+         hint == CREATE_PIXMAP_USAGE_SHARED)) {
+        bo = gbm_bo_create(xwl_screen->gbm, width, height,
+                           gbm_format_for_depth(depth),
+                           GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+
+        if (bo)
+            return xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
+    }
+
+    return glamor_create_pixmap(screen, width, height, depth, hint);
+}
+
+static Bool
+xwl_glamor_destroy_pixmap(PixmapPtr pixmap)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
+    struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
+
+    if (xwl_pixmap && pixmap->refcnt == 1) {
+        if (xwl_pixmap->buffer)
+            wl_buffer_destroy(xwl_pixmap->buffer);
+
+        eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
+        gbm_bo_destroy(xwl_pixmap->bo);
+        free(xwl_pixmap);
+    }
+
+    return glamor_destroy_pixmap(pixmap);
+}
+
+static Bool
+xwl_glamor_create_screen_resources(ScreenPtr screen)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    int ret;
+
+    screen->CreateScreenResources = xwl_screen->CreateScreenResources;
+    ret = (*screen->CreateScreenResources) (screen);
+    xwl_screen->CreateScreenResources = screen->CreateScreenResources;
+    screen->CreateScreenResources = xwl_glamor_create_screen_resources;
+
+    if (!ret)
+        return ret;
+
+    if (xwl_screen->rootless)
+        screen->devPrivate =
+            fbCreatePixmap(screen, 0, 0, screen->rootDepth, 0);
+    else {
+        screen->devPrivate =
+            xwl_glamor_create_pixmap(screen, screen->width, screen->height,
+                                     screen->rootDepth,
+                                     CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
+        if (screen->devPrivate)
+            glamor_set_screen_pixmap(screen->devPrivate, NULL);
+    }
+
+    return screen->devPrivate != NULL;
+}
+
+static char
+is_fd_render_node(int fd)
+{
+    struct stat render;
+
+    if (fstat(fd, &render))
+        return 0;
+    if (!S_ISCHR(render.st_mode))
+        return 0;
+    if (render.st_rdev & 0x80)
+        return 1;
+
+    return 0;
+}
+
+static void
+xwl_drm_init_egl(struct xwl_screen *xwl_screen)
+{
+    EGLint major, minor;
+    const char *version;
+
+    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");
+        return;
+    }
+
+    xwl_screen->egl_display = eglGetDisplay(xwl_screen->gbm);
+    if (xwl_screen->egl_display == EGL_NO_DISPLAY) {
+        ErrorF("eglGetDisplay() failed\n");
+        return;
+    }
+
+    eglBindAPI(EGL_OPENGL_API);
+    if (!eglInitialize(xwl_screen->egl_display, &major, &minor)) {
+        ErrorF("eglInitialize() failed\n");
+        return;
+    }
+
+    version = eglQueryString(xwl_screen->egl_display, EGL_VERSION);
+    ErrorF("glamor: EGL version %s:\n", version);
+
+    xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display,
+                                               NULL, EGL_NO_CONTEXT, NULL);
+    if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
+        ErrorF("Failed to create EGL context\n");
+        return;
+    }
+
+    if (!eglMakeCurrent(xwl_screen->egl_display,
+                        EGL_NO_SURFACE, EGL_NO_SURFACE,
+                        xwl_screen->egl_context)) {
+        ErrorF("Failed to make EGL context current\n");
+        return;
+    }
+
+    if (!epoxy_has_gl_extension("GL_OES_EGL_image")) {
+        ErrorF("GL_OES_EGL_image no available");
+        return;
+    }
+
+    return;
+}
+
+static void
+xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
+{
+   struct xwl_screen *xwl_screen = data;
+   drm_magic_t magic;
+
+   xwl_screen->device_name = strdup(device);
+   if (!xwl_screen->device_name)
+      return;
+
+   xwl_screen->drm_fd = open(xwl_screen->device_name, O_RDWR | O_CLOEXEC);
+   if (xwl_screen->drm_fd == -1) {
+       ErrorF("wayland-egl: could not open %s (%s)",
+	      xwl_screen->device_name, strerror(errno));
+       return;
+   }
+
+   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);
+   }
+}
+
+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
+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);
+}
+
+static void
+xwl_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
+{
+   struct xwl_screen *xwl_screen = data;
+
+   xwl_screen->capabilities = value;
+}
+
+static const struct wl_drm_listener xwl_drm_listener = {
+    xwl_drm_handle_device,
+    xwl_drm_handle_format,
+    xwl_drm_handle_authenticated,
+    xwl_drm_handle_capabilities
+};
+
+Bool
+xwl_screen_init_glamor(struct xwl_screen *xwl_screen,
+                       uint32_t id, uint32_t version)
+{
+    if (version < 2)
+        return FALSE;
+
+    xwl_screen->drm =
+        wl_registry_bind(xwl_screen->registry, id, &wl_drm_interface, 2);
+    wl_drm_add_listener(xwl_screen->drm, &xwl_drm_listener, xwl_screen);
+    xwl_screen->expecting_event++;
+
+    return TRUE;
+}
+
+void
+glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap)
+{
+    glamor_destroy_textured_pixmap(pixmap);
+}
+
+int
+glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
+                                 PixmapPtr pixmap,
+                                 unsigned int tex,
+                                 Bool want_name, CARD16 *stride, CARD32 *size)
+{
+    return 0;
+}
+
+unsigned int
+glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h)
+{
+    return 0;
+}
+
+struct xwl_auth_state {
+    int fd;
+    ClientPtr client;
+};
+
+static void
+sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
+{
+    struct xwl_auth_state *state = data;
+
+    dri3_send_open_reply(state->client, state->fd);
+    AttendClient(state->client);
+    free(state);
+    wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener sync_listener = {
+   sync_callback
+};
+
+static int
+xwl_dri3_open_client(ClientPtr client,
+                     ScreenPtr screen,
+                     RRProviderPtr provider,
+                     int *pfd)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_auth_state *state;
+    struct wl_callback *callback;
+    drm_magic_t magic;
+    int fd;
+
+    fd = open(xwl_screen->device_name, O_RDWR | O_CLOEXEC);
+    if (fd < 0)
+        return BadAlloc;
+    if (xwl_screen->fd_render_node) {
+        *pfd = fd;
+        return Success;
+    }
+
+    state = malloc(sizeof *state);
+    if (state == NULL) {
+        close(fd);
+        return BadAlloc;
+    }
+
+    state->client = client;
+    state->fd = fd;
+
+    if (drmGetMagic(state->fd, &magic) < 0) {
+        close(state->fd);
+        free(state);
+        return BadMatch;
+    }
+
+    wl_drm_authenticate(xwl_screen->drm, magic);
+    callback = wl_display_sync(xwl_screen->display);
+    wl_callback_add_listener(callback, &sync_listener, state);
+
+    IgnoreClient(client);
+
+    return Success;
+}
+
+static PixmapPtr
+xwl_dri3_pixmap_from_fd(ScreenPtr screen, int fd,
+                        CARD16 width, CARD16 height, CARD16 stride,
+                        CARD8 depth, CARD8 bpp)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct gbm_import_fd_data data;
+    struct gbm_bo *bo;
+    PixmapPtr pixmap;
+
+    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;
+
+    pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
+    if (pixmap == NULL) {
+        gbm_bo_destroy(bo);
+        return NULL;
+    }
+
+    return pixmap;
+}
+
+static int
+xwl_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
+                        CARD16 *stride, CARD32 *size)
+{
+    struct xwl_pixmap *xwl_pixmap;
+
+    xwl_pixmap = xwl_pixmap_get(pixmap);
+
+    *stride = gbm_bo_get_stride(xwl_pixmap->bo);
+    *size = pixmap->drawable.width * *stride;
+
+    return gbm_bo_get_fd(xwl_pixmap->bo);
+}
+
+static dri3_screen_info_rec xwl_dri3_info = {
+    .version = 1,
+    .open = NULL,
+    .pixmap_from_fd = xwl_dri3_pixmap_from_fd,
+    .fd_from_pixmap = xwl_dri3_fd_from_pixmap,
+    .open_client = xwl_dri3_open_client,
+};
+
+Bool
+xwl_glamor_init(struct xwl_screen *xwl_screen)
+{
+    ScreenPtr screen = xwl_screen->screen;
+
+    if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
+        ErrorF("Disabling glamor and dri3, EGL setup failed\n");
+        return FALSE;
+    }
+
+    if (!glamor_init(xwl_screen->screen,
+                     GLAMOR_INVERTED_Y_AXIS |
+                     GLAMOR_USE_EGL_SCREEN |
+                     GLAMOR_USE_SCREEN |
+                     GLAMOR_USE_PICTURE_SCREEN)) {
+        ErrorF("Failed to initialize glamor\n");
+        return FALSE;
+    }
+
+    if (!dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) {
+        ErrorF("Failed to initialize dri3\n");
+        return FALSE;
+    }
+
+    xwl_screen->CreateScreenResources = screen->CreateScreenResources;
+    screen->CreateScreenResources = xwl_glamor_create_screen_resources;
+    screen->CreatePixmap = xwl_glamor_create_pixmap;
+    screen->DestroyPixmap = xwl_glamor_destroy_pixmap;
+
+    return TRUE;
+}
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index b966e50..17b7bf7 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -337,7 +337,13 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen)
 
         pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window);
 
-        buffer = xwl_shm_pixmap_get_wl_buffer(pixmap);
+#if GLAMOR_HAS_GBM
+        if (xwl_screen->glamor)
+            buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap);
+#endif
+        if (!xwl_screen->glamor)
+            buffer = xwl_shm_pixmap_get_wl_buffer(pixmap);
+
         wl_surface_attach(xwl_window->surface, buffer, 0, 0);
         for (i = 0; i < count; i++) {
             box = &RegionRects(region)[i];
@@ -373,6 +379,12 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
         xwl_output_create(xwl_screen, id);
         xwl_screen->expecting_event++;
     }
+#ifdef GLAMOR_HAS_GBM
+    else if (xwl_screen->glamor &&
+             strcmp(interface, "wl_drm") == 0 && version >= 2) {
+        xwl_screen_init_glamor(xwl_screen, id, version);
+    }
+#endif
 }
 
 static void
@@ -495,6 +507,10 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     dixSetPrivate(&pScreen->devPrivates, &xwl_screen_private_key, xwl_screen);
     xwl_screen->screen = pScreen;
 
+#ifdef GLAMOR_HAS_GBM
+    xwl_screen->glamor = 1;
+#endif
+
     for (i = 1; i < argc; i++) {
         if (strcmp(argv[i], "-rootless") == 0) {
             xwl_screen->rootless = 1;
@@ -514,6 +530,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
                 atoi(argv[i + 1]);
             i++;
         }
+        else if (strcmp(argv[i], "-shm") == 0) {
+            xwl_screen->glamor = 0;
+        }
     }
 
     if (xwl_screen->listen_fd_count > 0) {
@@ -591,10 +610,19 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
     if (!xwl_screen_init_cursor(xwl_screen))
         return FALSE;
 
-    xwl_screen->CreateScreenResources = pScreen->CreateScreenResources;
-    pScreen->CreateScreenResources = xwl_shm_create_screen_resources;
-    pScreen->CreatePixmap = xwl_shm_create_pixmap;
-    pScreen->DestroyPixmap = xwl_shm_destroy_pixmap;
+#ifdef GLAMOR_HAS_GBM
+    if (xwl_screen->glamor && !xwl_glamor_init(xwl_screen)) {
+        ErrorF("Failed to initialize glamor, falling back to sw\n");
+        xwl_screen->glamor = 0;
+    }
+#endif
+
+    if (!xwl_screen->glamor) {
+        xwl_screen->CreateScreenResources = pScreen->CreateScreenResources;
+        pScreen->CreateScreenResources = xwl_shm_create_screen_resources;
+        pScreen->CreatePixmap = xwl_shm_create_pixmap;
+        pScreen->DestroyPixmap = xwl_shm_destroy_pixmap;
+    }
 
     xwl_screen->RealizeWindow = pScreen->RealizeWindow;
     pScreen->RealizeWindow = xwl_realize_window;
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 8157e71..fc68550 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -55,6 +55,7 @@ struct xwl_screen {
     int listen_fds[5];
     int listen_fd_count;
     int rootless;
+    int glamor;
 
     CreateScreenResourcesProcPtr CreateScreenResources;
     CloseScreenProcPtr CloseScreen;
@@ -83,6 +84,16 @@ struct xwl_screen {
 #define XWL_FORMAT_RGB565   (1 << 2)
 
     int prepare_read;
+
+    char *device_name;
+    int drm_fd;
+    int fd_render_node;
+    struct wl_drm *drm;
+    uint32_t formats;
+    uint32_t capabilities;
+    void *egl_display, *egl_context;
+    struct gbm_device *gbm;
+    struct glamor_context *glamor_ctx;
 };
 
 struct xwl_window {
@@ -161,4 +172,10 @@ Bool xwl_shm_destroy_pixmap(PixmapPtr pixmap);
 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);
+struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap);
+
 #endif
-- 
2.0.0



More information about the xorg-devel mailing list