xserver: Branch 'master'

Keith Packard keithp at kemper.freedesktop.org
Tue Jun 24 15:19:46 PDT 2014


 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(-)

New commits:
commit 2f113d68f6c1572576bc57ecca12e44cc9e438eb
Author: Kristian Høgsberg <krh at bitplanet.net>
Date:   Mon Jun 16 11:34:55 2014 -0700

    xwayland: Add glamor and DRI3 support
    
    Reviewed-by: Axel Davy <axel.davy at ens.fr>
    Signed-off-by: Kristian Høgsberg <krh at bitplanet.net>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/configure.ac b/configure.ac
index dabebb9..2daa6be 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


More information about the xorg-commit mailing list