[PATCH xserver 1/3] xwayland: Decouple GBM from glamor

Adam Jackson ajax at redhat.com
Fri Apr 20 18:38:03 UTC 2018


From: Lyude Paul <lyude at redhat.com>

This takes all of the gbm related code in wayland-glamor.c and moves it
into it's own EGL backend for Xwayland, xwayland-glamor-gbm.c.
Additionally, we add the egl_backend struct into xwl_screen in order to
provide hooks for alternative EGL backends such as nvidia's EGLStreams.

Signed-off-by: Lyude Paul <lyude at redhat.com>
---
 hw/xwayland/Makefile.am           |   1 +
 hw/xwayland/meson.build           |   6 +-
 hw/xwayland/xwayland-glamor-gbm.c | 892 ++++++++++++++++++++++++++++++
 hw/xwayland/xwayland-glamor.c     | 760 +------------------------
 hw/xwayland/xwayland.c            |  17 +-
 hw/xwayland/xwayland.h            |  58 +-
 6 files changed, 976 insertions(+), 758 deletions(-)
 create mode 100644 hw/xwayland/xwayland-glamor-gbm.c

diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 80d3a1f199..3fd980d0ee 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -35,6 +35,7 @@ Xwayland_built_sources =
 if GLAMOR_EGL
 Xwayland_SOURCES += 				\
 	xwayland-glamor.c			\
+	xwayland-glamor-gbm.c			\
 	xwayland-present.c
 if XV
 Xwayland_SOURCES += 				\
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index 8d178825e7..ef4379aab0 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -52,7 +52,11 @@ srcs += code.process(dmabuf_xml)
 
 xwayland_glamor = []
 if gbm_dep.found()
-    srcs += [ 'xwayland-glamor.c', 'xwayland-present.c' ]
+    srcs += [
+        'xwayland-glamor.c',
+        'xwayland-glamor-gbm.c',
+        'xwayland-present.c',
+    ]
     if build_xv
         srcs += 'xwayland-glamor-xv.c'
     endif
diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
new file mode 100644
index 0000000000..7be1437e86
--- /dev/null
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -0,0 +1,892 @@
+/*
+ * Copyright © 2011-2014 Intel Corporation
+ * Copyright © 2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including
+ * the next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Lyude Paul <lyude at redhat.com>
+ *
+ */
+
+#include "xwayland.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <xf86drm.h>
+#include <drm_fourcc.h>
+
+#define MESA_EGL_NO_X11_HEADERS
+#include <gbm.h>
+#include <glamor_egl.h>
+
+#include <glamor.h>
+#include <glamor_context.h>
+#include <dri3.h>
+#include "drm-client-protocol.h"
+
+struct xwl_gbm_private {
+    char *device_name;
+    struct gbm_device *gbm;
+    struct wl_drm *drm;
+    struct zwp_linux_dmabuf_v1 *dmabuf;
+    int drm_fd;
+    int fd_render_node;
+    Bool drm_authenticated;
+    uint32_t capabilities;
+    int dmabuf_capable;
+};
+
+struct xwl_pixmap {
+    struct wl_buffer *buffer;
+    EGLImage image;
+    unsigned int texture;
+    struct gbm_bo *bo;
+};
+
+static DevPrivateKeyRec xwl_gbm_private_key;
+static DevPrivateKeyRec xwl_auth_state_private_key;
+
+static inline struct xwl_gbm_private *
+xwl_gbm_get(struct xwl_screen *xwl_screen)
+{
+    return dixLookupPrivate(&xwl_screen->screen->devPrivates,
+                            &xwl_gbm_private_key);
+}
+
+static uint32_t
+gbm_format_for_depth(int depth)
+{
+    switch (depth) {
+    case 16:
+        return GBM_FORMAT_RGB565;
+    case 24:
+        return GBM_FORMAT_XRGB8888;
+    case 30:
+        return GBM_FORMAT_ARGB2101010;
+    default:
+        ErrorF("unexpected depth: %d\n", depth);
+    case 32:
+        return GBM_FORMAT_ARGB8888;
+    }
+}
+
+static uint32_t
+wl_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;
+    case 30:
+        return WL_DRM_FORMAT_ARGB2101010;
+    default:
+        ErrorF("unexpected depth: %d\n", depth);
+    case 32:
+        return WL_DRM_FORMAT_ARGB8888;
+    }
+}
+
+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 PixmapPtr
+xwl_glamor_gbm_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) {
+        free(xwl_pixmap);
+        return NULL;
+    }
+
+    if (lastGLContext != xwl_screen->glamor_ctx) {
+        lastGLContext = xwl_screen->glamor_ctx;
+        xwl_screen->glamor_ctx->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);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    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;
+}
+
+static PixmapPtr
+xwl_glamor_gbm_create_pixmap(ScreenPtr screen,
+                             int width, int height, int depth,
+                             unsigned int hint)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_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)) {
+        uint32_t format = gbm_format_for_depth(depth);
+
+#ifdef GBM_BO_WITH_MODIFIERS
+        if (xwl_gbm->dmabuf_capable) {
+            uint32_t num_modifiers;
+            uint64_t *modifiers = NULL;
+
+            glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
+            bo = gbm_bo_create_with_modifiers(xwl_gbm->gbm, width, height,
+                                              format, modifiers, num_modifiers);
+            free(modifiers);
+        }
+        else
+#endif
+        {
+            bo = gbm_bo_create(xwl_gbm->gbm, width, height, format,
+                               GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+        }
+
+        if (bo)
+            return xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth);
+    }
+
+    return glamor_create_pixmap(screen, width, height, depth, hint);
+}
+
+static Bool
+xwl_glamor_gbm_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);
+        if (xwl_pixmap->bo)
+           gbm_bo_destroy(xwl_pixmap->bo);
+        free(xwl_pixmap);
+    }
+
+    return glamor_destroy_pixmap(pixmap);
+}
+
+static struct wl_buffer *
+xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap,
+                                        unsigned short width,
+                                        unsigned short height,
+                                        Bool *created)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
+    struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+    int prime_fd;
+    int num_planes;
+    uint32_t strides[4];
+    uint32_t offsets[4];
+    uint64_t modifier;
+    int i;
+
+    if (xwl_pixmap->buffer) {
+        /* Buffer already exists. Return it and inform caller if interested. */
+        if (created)
+            *created = FALSE;
+        return xwl_pixmap->buffer;
+    }
+
+    /* Buffer does not exist yet. Create now and inform caller if interested. */
+    if (created)
+        *created = TRUE;
+
+    if (!xwl_pixmap->bo)
+       return NULL;
+
+    prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
+    if (prime_fd == -1)
+        return NULL;
+
+#ifdef GBM_BO_WITH_MODIFIERS
+    num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo);
+    modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
+    for (i = 0; i < num_planes; i++) {
+        strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
+        offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
+    }
+#else
+    num_planes = 1;
+    modifier = DRM_FORMAT_MOD_INVALID;
+    strides[0] = gbm_go_get_stride(xwl_pixmap->bo);
+    offsets[0] = 0;
+#endif
+
+    if (xwl_gbm->dmabuf && modifier != DRM_FORMAT_MOD_INVALID) {
+        struct zwp_linux_buffer_params_v1 *params;
+
+        params = zwp_linux_dmabuf_v1_create_params(xwl_gbm->dmabuf);
+        for (i = 0; i < num_planes; i++) {
+            zwp_linux_buffer_params_v1_add(params, prime_fd, i,
+                                           offsets[i], strides[i],
+                                           modifier >> 32, modifier & 0xffffffff);
+        }
+
+        xwl_pixmap->buffer =
+           zwp_linux_buffer_params_v1_create_immed(params, width, height,
+                                                   wl_drm_format_for_depth(pixmap->drawable.depth),
+                                                   0);
+        zwp_linux_buffer_params_v1_destroy(params);
+    } else if (num_planes == 1) {
+        xwl_pixmap->buffer =
+            wl_drm_create_prime_buffer(xwl_gbm->drm, prime_fd, width, height,
+                                       wl_drm_format_for_depth(pixmap->drawable.depth),
+                                       0, gbm_bo_get_stride(xwl_pixmap->bo),
+                                       0, 0,
+                                       0, 0);
+    }
+
+    close(prime_fd);
+    return xwl_pixmap->buffer;
+}
+
+static void
+xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen)
+{
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+    if (xwl_gbm->device_name)
+        free(xwl_gbm->device_name);
+    if (xwl_gbm->drm_fd)
+        close(xwl_gbm->drm_fd);
+    if (xwl_gbm->drm)
+        wl_drm_destroy(xwl_gbm->drm);
+    if (xwl_gbm->gbm)
+        gbm_device_destroy(xwl_gbm->gbm);
+
+    free(xwl_gbm);
+}
+
+struct xwl_auth_state {
+    int fd;
+    ClientPtr client;
+    struct wl_callback *callback;
+};
+
+static void
+free_xwl_auth_state(ClientPtr pClient, struct xwl_auth_state *state)
+{
+    dixSetPrivate(&pClient->devPrivates, &xwl_auth_state_private_key, NULL);
+    if (state) {
+        wl_callback_destroy(state->callback);
+        free(state);
+    }
+}
+
+static void
+xwl_auth_state_client_callback(CallbackListPtr *pcbl, void *unused, void *data)
+{
+    NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
+    ClientPtr pClient = clientinfo->client;
+    struct xwl_auth_state *state;
+
+    switch (pClient->clientState) {
+    case ClientStateGone:
+    case ClientStateRetained:
+        state = dixLookupPrivate(&pClient->devPrivates,
+                                 &xwl_auth_state_private_key);
+        free_xwl_auth_state(pClient, state);
+        break;
+    default:
+        break;
+    }
+}
+
+static void
+sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
+{
+    struct xwl_auth_state *state = data;
+    ClientPtr client = state->client;
+
+    /* if the client is gone, the callback is cancelled so it's safe to
+     * assume the client is still in ClientStateRunning at this point...
+     */
+    dri3_send_open_reply(client, state->fd);
+    AttendClient(client);
+    free_xwl_auth_state(client, state);
+}
+
+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_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+    struct xwl_auth_state *state;
+    drm_magic_t magic;
+    int fd;
+
+    fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC);
+    if (fd < 0)
+        return BadAlloc;
+    if (xwl_gbm->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_gbm->drm, magic);
+    state->callback = wl_display_sync(xwl_screen->display);
+    wl_callback_add_listener(state->callback, &sync_listener, state);
+    dixSetPrivate(&client->devPrivates, &xwl_auth_state_private_key, state);
+
+    IgnoreClient(client);
+
+    return Success;
+}
+
+_X_EXPORT PixmapPtr
+glamor_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, const int *fds,
+                       CARD16 width, CARD16 height,
+                       const CARD32 *strides, const CARD32 *offsets,
+                       CARD8 depth, CARD8 bpp, uint64_t modifier)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+    struct gbm_bo *bo = NULL;
+    PixmapPtr pixmap;
+    int i;
+
+    if (width == 0 || height == 0 || num_fds == 0 ||
+        depth < 15 || bpp != BitsPerPixel(depth) ||
+        strides[0] < width * bpp / 8)
+       goto error;
+
+    if (xwl_gbm->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
+#ifdef GBM_BO_WITH_MODIFIERS
+       struct gbm_import_fd_modifier_data data;
+
+       data.width = width;
+       data.height = height;
+       data.num_fds = num_fds;
+       data.format = gbm_format_for_depth(depth);
+       data.modifier = modifier;
+       for (i = 0; i < num_fds; i++) {
+          data.fds[i] = fds[i];
+          data.strides[i] = strides[i];
+          data.offsets[i] = offsets[i];
+       }
+       bo = gbm_bo_import(xwl_gbm->gbm, GBM_BO_IMPORT_FD_MODIFIER, &data, 0);
+#endif
+    } else if (num_fds == 1) {
+       struct gbm_import_fd_data data;
+
+       data.fd = fds[0];
+       data.width = width;
+       data.height = height;
+       data.stride = strides[0];
+       data.format = gbm_format_for_depth(depth);
+       bo = gbm_bo_import(xwl_gbm->gbm, GBM_BO_IMPORT_FD, &data,
+             GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+    } else {
+       goto error;
+    }
+
+    if (bo == NULL)
+       goto error;
+
+    pixmap = xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth);
+    if (pixmap == NULL) {
+       gbm_bo_destroy(bo);
+       goto error;
+    }
+
+    return pixmap;
+
+error:
+    return NULL;
+}
+
+_X_EXPORT int
+glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
+                           uint32_t *strides, uint32_t *offsets,
+                           uint64_t *modifier)
+{
+    struct xwl_pixmap *xwl_pixmap;
+#ifdef GBM_BO_WITH_MODIFIERS
+    uint32_t num_fds;
+    int i;
+#endif
+
+    xwl_pixmap = xwl_pixmap_get(pixmap);
+
+    if (!xwl_pixmap->bo)
+       return 0;
+
+#ifdef GBM_BO_WITH_MODIFIERS
+    num_fds = gbm_bo_get_plane_count(xwl_pixmap->bo);
+    *modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
+
+    for (i = 0; i < num_fds; i++) {
+        fds[i] = gbm_bo_get_fd(xwl_pixmap->bo);
+        strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
+        offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
+    }
+
+    return num_fds;
+#else
+    *modifier = DRM_FORMAT_MOD_INVALID;
+    fds[0] = gbm_bo_get_fd(xwl_pixmap->bo);
+    strides[0] = gbm_bo_get_stride(xwl_pixmap->bo);
+    offsets[0] = 0;
+    return 1;
+#endif
+}
+
+_X_EXPORT Bool
+glamor_get_formats(ScreenPtr screen,
+                   CARD32 *num_formats, CARD32 **formats)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+    int i;
+
+    if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf)
+        return FALSE;
+
+    if (xwl_screen->num_formats == 0) {
+       *num_formats = 0;
+       return TRUE;
+    }
+
+    *formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
+    if (*formats == NULL) {
+        *num_formats = 0;
+        return FALSE;
+    }
+
+    for (i = 0; i < xwl_screen->num_formats; i++)
+       (*formats)[i] = xwl_screen->formats[i].format;
+    *num_formats = xwl_screen->num_formats;
+
+    return TRUE;
+}
+
+_X_EXPORT Bool
+glamor_get_modifiers(ScreenPtr screen, CARD32 format,
+                     CARD32 *num_modifiers, uint64_t **modifiers)
+{
+    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+    struct xwl_format *xwl_format = NULL;
+    int i;
+
+    if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf)
+        return FALSE;
+
+    /* Explicitly zero the count as the caller may ignore the return value */
+    *num_modifiers = 0;
+
+    if (xwl_screen->num_formats == 0)
+       return TRUE;
+
+    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)
+        return FALSE;
+
+    *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
+    if (*modifiers == NULL)
+        return FALSE;
+
+    for (i = 0; i < xwl_format->num_modifiers; i++)
+       (*modifiers)[i] = xwl_format->modifiers[i];
+    *num_modifiers = xwl_format->num_modifiers;
+
+    return TRUE;
+}
+
+static const dri3_screen_info_rec xwl_dri3_info = {
+    .version = 2,
+    .open = NULL,
+    .pixmap_from_fds = glamor_pixmap_from_fds,
+    .fds_from_pixmap = glamor_fds_from_pixmap,
+    .open_client = xwl_dri3_open_client,
+    .get_formats = glamor_get_formats,
+    .get_modifiers = glamor_get_modifiers,
+    .get_drawable_modifiers = glamor_get_drawable_modifiers,
+};
+
+static void
+xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
+{
+   struct xwl_screen *xwl_screen = data;
+   struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+   drm_magic_t magic;
+
+   xwl_gbm->device_name = strdup(device);
+   if (!xwl_gbm->device_name) {
+       xwl_glamor_gbm_cleanup(xwl_screen);
+       return;
+   }
+
+   xwl_gbm->drm_fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC);
+   if (xwl_gbm->drm_fd == -1) {
+       ErrorF("wayland-egl: could not open %s (%s)\n",
+              xwl_gbm->device_name, strerror(errno));
+       xwl_glamor_gbm_cleanup(xwl_screen);
+       return;
+   }
+
+   if (is_fd_render_node(xwl_gbm->drm_fd)) {
+       xwl_gbm->fd_render_node = 1;
+       xwl_screen->expecting_event--;
+   } else {
+       drmGetMagic(xwl_gbm->drm_fd, &magic);
+       wl_drm_authenticate(xwl_gbm->drm, magic);
+   }
+}
+
+static void
+xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
+{
+}
+
+static void
+xwl_drm_handle_authenticated(void *data, struct wl_drm *drm)
+{
+    struct xwl_screen *xwl_screen = data;
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+    xwl_gbm->drm_authenticated = TRUE;
+    xwl_screen->expecting_event--;
+}
+
+static void
+xwl_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
+{
+    xwl_gbm_get(data)->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
+};
+
+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_set_drm_interface(struct xwl_screen *xwl_screen,
+                             uint32_t id, uint32_t version)
+{
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+    if (version < 2)
+        return FALSE;
+
+    xwl_gbm->drm =
+        wl_registry_bind(xwl_screen->registry, id, &wl_drm_interface, 2);
+    wl_drm_add_listener(xwl_gbm->drm, &xwl_drm_listener, xwl_screen);
+    xwl_screen->expecting_event++;
+
+    return TRUE;
+}
+
+Bool
+xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
+                                uint32_t id, uint32_t version)
+{
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+    if (version < 3)
+        return FALSE;
+
+    xwl_gbm->dmabuf =
+        wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
+    zwp_linux_dmabuf_v1_add_listener(xwl_gbm->dmabuf, &xwl_dmabuf_listener, xwl_screen);
+
+    return TRUE;
+}
+
+static void
+xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen,
+                                struct wl_registry *wl_registry,
+                                const char *name,
+                                uint32_t id, uint32_t version)
+{
+    if (strcmp(name, "wl_drm") == 0)
+        xwl_screen_set_drm_interface(xwl_screen, id, version);
+    else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0)
+        xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
+}
+
+static Bool
+xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
+{
+    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+    EGLint major, minor;
+    Bool egl_initialized = FALSE;
+    static const EGLint config_attribs_core[] = {
+        EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
+        EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
+        EGL_CONTEXT_MAJOR_VERSION_KHR,
+        GLAMOR_GL_CORE_VER_MAJOR,
+        EGL_CONTEXT_MINOR_VERSION_KHR,
+        GLAMOR_GL_CORE_VER_MINOR,
+        EGL_NONE
+    };
+
+    if (!xwl_gbm->fd_render_node && !xwl_gbm->drm_authenticated) {
+        ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n");
+	return FALSE;
+    }
+
+    xwl_gbm->gbm = gbm_create_device(xwl_gbm->drm_fd);
+    if (!xwl_gbm->gbm) {
+        ErrorF("couldn't create gbm device\n");
+        goto error;
+    }
+
+    xwl_screen->egl_display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA,
+                                                     xwl_gbm->gbm);
+    if (xwl_screen->egl_display == EGL_NO_DISPLAY) {
+        ErrorF("glamor_egl_get_display() failed\n");
+        goto error;
+    }
+
+    egl_initialized = eglInitialize(xwl_screen->egl_display, &major, &minor);
+    if (!egl_initialized) {
+        ErrorF("eglInitialize() failed\n");
+        goto error;
+    }
+
+    eglBindAPI(EGL_OPENGL_API);
+
+    xwl_screen->egl_context = eglCreateContext(
+        xwl_screen->egl_display, NULL, EGL_NO_CONTEXT, config_attribs_core);
+    if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
+        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");
+        goto error;
+    }
+
+    if (!eglMakeCurrent(xwl_screen->egl_display,
+                        EGL_NO_SURFACE, EGL_NO_SURFACE,
+                        xwl_screen->egl_context)) {
+        ErrorF("Failed to make EGL context current\n");
+        goto error;
+    }
+
+    if (!epoxy_has_gl_extension("GL_OES_EGL_image"))
+        ErrorF("GL_OES_EGL_image not available\n");
+
+    if (epoxy_has_egl_extension(xwl_screen->egl_display,
+                                "EXT_image_dma_buf_import") &&
+        epoxy_has_egl_extension(xwl_screen->egl_display,
+                                "EXT_image_dma_buf_import_modifiers"))
+       xwl_gbm->dmabuf_capable = TRUE;
+
+    return TRUE;
+error:
+    if (xwl_screen->egl_context != EGL_NO_CONTEXT) {
+        eglDestroyContext(xwl_screen->egl_display, xwl_screen->egl_context);
+        xwl_screen->egl_context = EGL_NO_CONTEXT;
+    }
+
+    if (xwl_screen->egl_display != EGL_NO_DISPLAY) {
+        eglTerminate(xwl_screen->egl_display);
+        xwl_screen->egl_display = EGL_NO_DISPLAY;
+    }
+
+    xwl_glamor_gbm_cleanup(xwl_screen);
+    return FALSE;
+}
+
+static Bool
+xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen)
+{
+    if (!dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) {
+        ErrorF("Failed to initialize dri3\n");
+        goto error;
+    }
+
+    if (!dixRegisterPrivateKey(&xwl_auth_state_private_key, PRIVATE_CLIENT,
+                               0)) {
+        ErrorF("Failed to register private key\n");
+        goto error;
+    }
+
+    if (!AddCallback(&ClientStateCallback, xwl_auth_state_client_callback,
+                     NULL)) {
+        ErrorF("Failed to add client state callback\n");
+        goto error;
+    }
+
+    xwl_screen->screen->CreatePixmap = xwl_glamor_gbm_create_pixmap;
+    xwl_screen->screen->DestroyPixmap = xwl_glamor_gbm_destroy_pixmap;
+
+    return TRUE;
+error:
+    xwl_glamor_gbm_cleanup(xwl_screen);
+    return FALSE;
+}
+
+Bool
+xwl_glamor_init_gbm(struct xwl_screen *xwl_screen)
+{
+    struct xwl_gbm_private *xwl_gbm;
+
+    if (!dixRegisterPrivateKey(&xwl_gbm_private_key, PRIVATE_SCREEN, 0))
+        return FALSE;
+
+    xwl_gbm = calloc(sizeof(*xwl_gbm), 1);
+    if (!xwl_gbm) {
+        ErrorF("glamor: Not enough memory to setup GBM, disabling\n");
+        return FALSE;
+    }
+
+    dixSetPrivate(&xwl_screen->screen->devPrivates, &xwl_gbm_private_key,
+                  xwl_gbm);
+
+    xwl_screen->egl_backend.init_wl_registry = xwl_glamor_gbm_init_wl_registry;
+    xwl_screen->egl_backend.init_egl = xwl_glamor_gbm_init_egl;
+    xwl_screen->egl_backend.init_screen = xwl_glamor_gbm_init_screen;
+    xwl_screen->egl_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap;
+
+    return TRUE;
+}
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 1b9a6b0309..7b24ce7e40 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -25,28 +25,11 @@
 
 #include "xwayland.h"
 
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <xf86drm.h>
-#include <drm_fourcc.h>
-
 #define MESA_EGL_NO_X11_HEADERS
-#include <gbm.h>
 #include <glamor_egl.h>
 
 #include <glamor.h>
 #include <glamor_context.h>
-#include <dri3.h>
-#include "drm-client-protocol.h"
-
-static DevPrivateKeyRec xwl_auth_state_private_key;
-
-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)
@@ -59,42 +42,6 @@ xwl_glamor_egl_make_current(struct glamor_context *glamor_ctx)
         FatalError("Failed to make EGL context current\n");
 }
 
-static uint32_t
-wl_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;
-    case 30:
-        return WL_DRM_FORMAT_ARGB2101010;
-    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;
-    case 30:
-        return GBM_FORMAT_ARGB2101010;
-    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)
 {
@@ -108,53 +55,15 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
     xwl_screen->glamor_ctx = glamor_ctx;
 }
 
-static PixmapPtr
-xwl_glamor_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, int depth)
+void
+xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen,
+                            struct wl_registry *registry,
+                            uint32_t id, const char *interface,
+                            uint32_t version)
 {
-    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);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-    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;
+    if (xwl_screen->egl_backend.init_wl_registry)
+        xwl_screen->egl_backend.init_wl_registry(xwl_screen, registry,
+                                                 interface, id, version);
 }
 
 struct wl_buffer *
@@ -164,133 +73,14 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap,
                                 Bool *created)
 {
     struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
-    struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
-    int prime_fd;
-    int num_planes;
-    uint32_t strides[4];
-    uint32_t offsets[4];
-    uint64_t modifier;
-    int i;
 
-    if (xwl_pixmap->buffer) {
-        /* Buffer already exists. Return it and inform caller if interested. */
-        if (created)
-            *created = FALSE;
-        return xwl_pixmap->buffer;
-    }
+    if (xwl_screen->egl_backend.get_wl_buffer_for_pixmap)
+        return xwl_screen->egl_backend.get_wl_buffer_for_pixmap(pixmap,
+                                                                width,
+                                                                height,
+                                                                created);
 
-    /* Buffer does not exist yet. Create now and inform caller if interested. */
-    if (created)
-        *created = TRUE;
-
-    if (!xwl_pixmap->bo)
-       return NULL;
-
-    prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
-    if (prime_fd == -1)
-        return NULL;
-
-#ifdef GBM_BO_WITH_MODIFIERS
-    num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo);
-    modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
-    for (i = 0; i < num_planes; i++) {
-        strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
-        offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
-    }
-#else
-    num_planes = 1;
-    modifier = DRM_FORMAT_MOD_INVALID;
-    strides[0] = gbm_go_get_stride(xwl_pixmap->bo);
-    offsets[0] = 0;
-#endif
-
-    if (xwl_screen->dmabuf && modifier != DRM_FORMAT_MOD_INVALID) {
-        struct zwp_linux_buffer_params_v1 *params;
-
-        params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf);
-        for (i = 0; i < num_planes; i++) {
-            zwp_linux_buffer_params_v1_add(params, prime_fd, i,
-                                           offsets[i], strides[i],
-                                           modifier >> 32, modifier & 0xffffffff);
-        }
-
-        xwl_pixmap->buffer =
-           zwp_linux_buffer_params_v1_create_immed(params,
-                                                   width,
-                                                   height,
-                                                   wl_drm_format_for_depth(pixmap->drawable.depth),
-                                                   0);
-        zwp_linux_buffer_params_v1_destroy(params);
-    } else if (num_planes == 1) {
-        xwl_pixmap->buffer =
-            wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
-                                       width,
-                                       height,
-                                       wl_drm_format_for_depth(pixmap->drawable.depth),
-                                       0, gbm_bo_get_stride(xwl_pixmap->bo),
-                                       0, 0,
-                                       0, 0);
-    }
-
-    close(prime_fd);
-    return xwl_pixmap->buffer;
-}
-
-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;
-    uint32_t format;
-
-    if (width > 0 && height > 0 && depth >= 15 &&
-        (hint == 0 ||
-         hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP ||
-         hint == CREATE_PIXMAP_USAGE_SHARED)) {
-        format = gbm_format_for_depth(depth);
-
-#ifdef GBM_BO_WITH_MODIFIERS
-        if (xwl_screen->dmabuf_capable) {
-            uint32_t num_modifiers;
-            uint64_t *modifiers = NULL;
-
-            glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
-            bo = gbm_bo_create_with_modifiers(xwl_screen->gbm, width, height,
-                                              format, modifiers, num_modifiers);
-            free(modifiers);
-        }
-        else
-#endif
-        {
-            bo = gbm_bo_create(xwl_screen->gbm, width, height, format,
-                               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);
-        if (xwl_pixmap->bo)
-           gbm_bo_destroy(xwl_pixmap->bo);
-        free(xwl_pixmap);
-    }
-
-    return glamor_destroy_pixmap(pixmap);
+    return NULL;
 }
 
 static Bool
@@ -312,10 +102,9 @@ xwl_glamor_create_screen_resources(ScreenPtr screen)
             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);
+        screen->devPrivate = screen->CreatePixmap(
+            screen, screen->width, screen->height, screen->rootDepth,
+            CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
     }
 
     SetRootClip(screen, xwl_screen->root_clip_mode);
@@ -323,224 +112,6 @@ xwl_glamor_create_screen_resources(ScreenPtr screen)
     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;
-    static const EGLint config_attribs_core[] = {
-        EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
-        EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
-        EGL_CONTEXT_MAJOR_VERSION_KHR,
-        GLAMOR_GL_CORE_VER_MAJOR,
-        EGL_CONTEXT_MINOR_VERSION_KHR,
-        GLAMOR_GL_CORE_VER_MINOR,
-        EGL_NONE
-    };
-
-    if (xwl_screen->egl_display)
-        return;
-
-    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 = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA,
-                                                     xwl_screen->gbm);
-    if (xwl_screen->egl_display == EGL_NO_DISPLAY) {
-        ErrorF("glamor_egl_get_display() failed\n");
-        return;
-    }
-
-    if (!eglInitialize(xwl_screen->egl_display, &major, &minor)) {
-        ErrorF("eglInitialize() failed\n");
-        return;
-    }
-
-    eglBindAPI(EGL_OPENGL_API);
-
-    xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display,
-                                               NULL, EGL_NO_CONTEXT, config_attribs_core);
-    if (!xwl_screen->egl_context)
-        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 not available\n");
-        return;
-    }
-
-    if (epoxy_has_egl_extension(xwl_screen->egl_display,
-                                "EXT_image_dma_buf_import") &&
-        epoxy_has_egl_extension(xwl_screen->egl_display,
-                                "EXT_image_dma_buf_import_modifiers"))
-       xwl_screen->dmabuf_capable = TRUE;
-
-    return;
-}
-
-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)\n",
-              xwl_screen->device_name, strerror(errno));
-       return;
-   }
-
-   xwl_screen->expecting_event--;
-
-   if (is_fd_render_node(xwl_screen->drm_fd)) {
-       xwl_screen->fd_render_node = 1;
-   } else {
-       drmGetMagic(xwl_screen->drm_fd, &magic);
-       wl_drm_authenticate(xwl_screen->drm, magic);
-       xwl_screen->expecting_event++; /* wait for 'authenticated' */
-   }
-}
-
-static void
-xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
-{
-}
-
-static void
-xwl_drm_handle_authenticated(void *data, struct wl_drm *drm)
-{
-    struct xwl_screen *xwl_screen = data;
-
-    xwl_screen->drm_authenticated = 1;
-    xwl_screen->expecting_event--;
-}
-
-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
-};
-
-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_set_drm_interface(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;
-}
-
-Bool
-xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
-                                uint32_t id, uint32_t version)
-{
-    if (version < 3)
-        return FALSE;
-
-    xwl_screen->dmabuf =
-        wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
-    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,
@@ -549,277 +120,6 @@ glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
     return 0;
 }
 
-struct xwl_auth_state {
-    int fd;
-    ClientPtr client;
-    struct wl_callback *callback;
-};
-
-static void
-free_xwl_auth_state(ClientPtr pClient, struct xwl_auth_state *state)
-{
-    dixSetPrivate(&pClient->devPrivates, &xwl_auth_state_private_key, NULL);
-    if (state) {
-        wl_callback_destroy(state->callback);
-        free(state);
-    }
-}
-
-static void
-xwl_auth_state_client_callback(CallbackListPtr *pcbl, void *unused, void *data)
-{
-    NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
-    ClientPtr pClient = clientinfo->client;
-    struct xwl_auth_state *state;
-
-    switch (pClient->clientState) {
-    case ClientStateGone:
-    case ClientStateRetained:
-        state = dixLookupPrivate(&pClient->devPrivates, &xwl_auth_state_private_key);
-        free_xwl_auth_state(pClient, state);
-        break;
-    default:
-        break;
-    }
-}
-
-static void
-sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
-{
-    struct xwl_auth_state *state = data;
-    ClientPtr client = state->client;
-
-    /* if the client is gone, the callback is cancelled so it's safe to
-     * assume the client is still in ClientStateRunning at this point...
-     */
-    dri3_send_open_reply(client, state->fd);
-    AttendClient(client);
-    free_xwl_auth_state(client, state);
-}
-
-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;
-    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);
-    state->callback = wl_display_sync(xwl_screen->display);
-    wl_callback_add_listener(state->callback, &sync_listener, state);
-    dixSetPrivate(&client->devPrivates, &xwl_auth_state_private_key, state);
-
-    IgnoreClient(client);
-
-    return Success;
-}
-
-_X_EXPORT PixmapPtr
-glamor_pixmap_from_fds(ScreenPtr screen,
-                       CARD8 num_fds, const int *fds,
-                       CARD16 width, CARD16 height,
-                       const CARD32 *strides, const CARD32 *offsets,
-                       CARD8 depth, CARD8 bpp, uint64_t modifier)
-{
-    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
-    struct gbm_bo *bo = NULL;
-    PixmapPtr pixmap;
-    int i;
-
-    if (width == 0 || height == 0 || num_fds == 0 ||
-        depth < 15 || bpp != BitsPerPixel(depth) ||
-        strides[0] < width * bpp / 8)
-       goto error;
-
-    if (xwl_screen->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
-#ifdef GBM_BO_WITH_MODIFIERS
-       struct gbm_import_fd_modifier_data data;
-
-       data.width = width;
-       data.height = height;
-       data.num_fds = num_fds;
-       data.format = gbm_format_for_depth(depth);
-       data.modifier = modifier;
-       for (i = 0; i < num_fds; i++) {
-          data.fds[i] = fds[i];
-          data.strides[i] = strides[i];
-          data.offsets[i] = offsets[i];
-       }
-       bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD_MODIFIER, &data, 0);
-#endif
-    } else if (num_fds == 1) {
-       struct gbm_import_fd_data data;
-
-       data.fd = fds[0];
-       data.width = width;
-       data.height = height;
-       data.stride = strides[0];
-       data.format = gbm_format_for_depth(depth);
-       bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
-             GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
-    } else {
-       goto error;
-    }
-
-    if (bo == NULL)
-       goto error;
-
-    pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
-    if (pixmap == NULL) {
-       gbm_bo_destroy(bo);
-       goto error;
-    }
-
-    return pixmap;
-
-error:
-    return NULL;
-}
-
-_X_EXPORT int
-glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
-                           uint32_t *strides, uint32_t *offsets,
-                           uint64_t *modifier)
-{
-    struct xwl_pixmap *xwl_pixmap;
-#ifdef GBM_BO_WITH_MODIFIERS
-    uint32_t num_fds;
-    int i;
-#endif
-
-    xwl_pixmap = xwl_pixmap_get(pixmap);
-
-    if (!xwl_pixmap->bo)
-       return 0;
-
-#ifdef GBM_BO_WITH_MODIFIERS
-    num_fds = gbm_bo_get_plane_count(xwl_pixmap->bo);
-    *modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
-
-    for (i = 0; i < num_fds; i++) {
-        fds[i] = gbm_bo_get_fd(xwl_pixmap->bo);
-        strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
-        offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
-    }
-
-    return num_fds;
-#else
-    *modifier = DRM_FORMAT_MOD_INVALID;
-    fds[0] = gbm_bo_get_fd(xwl_pixmap->bo);
-    strides[0] = gbm_bo_get_stride(xwl_pixmap->bo);
-    offsets[0] = 0;
-    return 1;
-#endif
-}
-
-_X_EXPORT Bool
-glamor_get_formats(ScreenPtr screen,
-                   CARD32 *num_formats, CARD32 **formats)
-{
-    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
-    int i;
-
-    /* Explicitly zero the count as the caller may ignore the return value */
-    *num_formats = 0;
-
-    if (!xwl_screen->dmabuf_capable || !xwl_screen->dmabuf)
-        return FALSE;
-
-    if (xwl_screen->num_formats == 0)
-       return TRUE;
-
-    *formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
-    if (*formats == NULL)
-        return FALSE;
-
-    for (i = 0; i < xwl_screen->num_formats; i++)
-       (*formats)[i] = xwl_screen->formats[i].format;
-    *num_formats = xwl_screen->num_formats;
-
-    return TRUE;
-}
-
-_X_EXPORT Bool
-glamor_get_modifiers(ScreenPtr screen, CARD32 format,
-                     CARD32 *num_modifiers, uint64_t **modifiers)
-{
-    struct xwl_screen *xwl_screen = xwl_screen_get(screen);
-    struct xwl_format *xwl_format = NULL;
-    int i;
-
-    /* Explicitly zero the count as the caller may ignore the return value */
-    *num_modifiers = 0;
-
-    if (!xwl_screen->dmabuf_capable || !xwl_screen->dmabuf)
-        return FALSE;
-
-    if (xwl_screen->num_formats == 0)
-        return TRUE;
-
-    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)
-        return FALSE;
-
-    *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
-    if (*modifiers == NULL)
-        return FALSE;
-
-    for (i = 0; i < xwl_format->num_modifiers; i++)
-       (*modifiers)[i] = xwl_format->modifiers[i];
-    *num_modifiers = xwl_format->num_modifiers;
-
-    return TRUE;
-}
-
-
-static const dri3_screen_info_rec xwl_dri3_info = {
-    .version = 2,
-    .open = NULL,
-    .pixmap_from_fds = glamor_pixmap_from_fds,
-    .fds_from_pixmap = glamor_fds_from_pixmap,
-    .open_client = xwl_dri3_open_client,
-    .get_formats = glamor_get_formats,
-    .get_modifiers = glamor_get_modifiers,
-    .get_drawable_modifiers = glamor_get_drawable_modifiers,
-};
-
 Bool
 xwl_glamor_init(struct xwl_screen *xwl_screen)
 {
@@ -832,14 +132,8 @@ xwl_glamor_init(struct xwl_screen *xwl_screen)
         return FALSE;
     }
 
-    if (!xwl_screen->fd_render_node && !xwl_screen->drm_authenticated) {
-        ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n");
-	return FALSE;
-    }
-
-    xwl_drm_init_egl(xwl_screen);
-    if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
-        ErrorF("Disabling glamor and dri3, EGL setup failed\n");
+    if (!xwl_screen->egl_backend.init_egl(xwl_screen)) {
+        ErrorF("EGL setup failed, disabling glamor\n");
         return FALSE;
     }
 
@@ -848,25 +142,13 @@ xwl_glamor_init(struct xwl_screen *xwl_screen)
         return FALSE;
     }
 
-    if (!dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) {
-        ErrorF("Failed to initialize dri3\n");
-        return FALSE;
-    }
-
-    if (!dixRegisterPrivateKey(&xwl_auth_state_private_key, PRIVATE_CLIENT, 0)) {
-        ErrorF("Failed to register private key\n");
-        return FALSE;
-    }
-
-    if (!AddCallback(&ClientStateCallback, xwl_auth_state_client_callback, NULL)) {
-        ErrorF("Failed to add client state callback\n");
+    if (!xwl_screen->egl_backend.init_screen(xwl_screen)) {
+        ErrorF("EGL backend init_screen() failed, disabling glamor\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;
 
 #ifdef XV
     if (!xwl_glamor_xv_init(screen))
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 72493285e2..b37b62c786 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -755,13 +755,9 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
         xwl_screen_init_xdg_output(xwl_screen);
     }
 #ifdef GLAMOR_HAS_GBM
-    else if (xwl_screen->glamor &&
-             strcmp(interface, "wl_drm") == 0 && version >= 2) {
-        xwl_screen_set_drm_interface(xwl_screen, id, version);
-    }
-    else if (xwl_screen->glamor &&
-             strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
-        xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
+    else if (xwl_screen->glamor) {
+        xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface,
+                                    version);
     }
 #endif
 }
@@ -970,6 +966,13 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
         }
     }
 
+    if (xwl_screen->glamor) {
+        if (!xwl_glamor_init_gbm(xwl_screen)) {
+            ErrorF("xwayland glamor: failed to setup GBM backend, falling back to sw accel\n");
+            xwl_screen->glamor = 0;
+        }
+    }
+
     /* In rootless mode, we don't have any screen storage, and the only
      * rendering should be to redirected mode. */
     if (xwl_screen->rootless)
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index 11a9f48165..82cbfc9d34 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -55,6 +55,9 @@ struct xwl_format {
     uint64_t *modifiers;
 };
 
+struct xwl_pixmap;
+struct xwl_window;
+
 struct xwl_screen {
     int width;
     int height;
@@ -101,19 +104,46 @@ struct xwl_screen {
     int prepare_read;
     int wait_flush;
 
-    char *device_name;
-    int drm_fd;
-    int fd_render_node;
-    int drm_authenticated;
-    struct wl_drm *drm;
-    struct zwp_linux_dmabuf_v1 *dmabuf;
     uint32_t num_formats;
     struct xwl_format *formats;
-    uint32_t capabilities;
     void *egl_display, *egl_context;
-    struct gbm_device *gbm;
+
+    /* the current backend for creating pixmaps on wayland */
+    struct {
+        /* Called once for each interface in the global registry. Backends
+         * should use this to bind to any wayland interfaces they need. This
+         * callback is optional.
+         */
+        void (*init_wl_registry)(struct xwl_screen *xwl_screen,
+                                 struct wl_registry *wl_registry,
+                                 const char *name, uint32_t id,
+                                 uint32_t version);
+
+        /* Called before glamor has been initialized. Backends should setup a
+         * valid, glamor compatible EGL context in this hook.
+         */
+        Bool (*init_egl)(struct xwl_screen *xwl_screen);
+
+        /* Called after glamor has been initialized, and after all of the
+         * common Xwayland DDX hooks have been connected. Backends should use
+         * this to setup any required wraps around X server callbacks like
+         * CreatePixmap.
+         */
+        Bool (*init_screen)(struct xwl_screen *xwl_screen);
+
+        /* Called by Xwayland to retrieve a pointer to a valid wl_buffer for
+         * the given window/pixmap combo so that damage to the pixmap may be
+         * displayed on-screen. Backends should use this to create a new
+         * wl_buffer for a currently buffer-less pixmap, or simply return the
+         * pixmap they've prepared beforehand.
+         */
+        struct wl_buffer *(*get_wl_buffer_for_pixmap)(PixmapPtr pixmap,
+                                                      unsigned short width,
+                                                      unsigned short height,
+                                                      Bool *created);
+    } egl_backend;
+
     struct glamor_context *glamor_ctx;
-    int dmabuf_capable;
 
     Atom allow_commits_prop;
 };
@@ -318,8 +348,6 @@ struct xwl_output {
     Bool xdg_output_done;
 };
 
-struct xwl_pixmap;
-
 void xwl_sync_events (struct xwl_screen *xwl_screen);
 
 Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen);
@@ -380,6 +408,10 @@ struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap,
                                                   unsigned short width,
                                                   unsigned short height,
                                                   Bool *created);
+void xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen,
+                                 struct wl_registry *registry,
+                                 uint32_t id, const char *interface,
+                                 uint32_t version);
 
 #ifdef GLAMOR_HAS_GBM
 Bool xwl_present_init(ScreenPtr screen);
@@ -400,4 +432,8 @@ Bool xwl_glamor_xv_init(ScreenPtr pScreen);
 void xwlVidModeExtensionInit(void);
 #endif
 
+#ifdef GLAMOR_HAS_GBM
+Bool xwl_glamor_init_gbm(struct xwl_screen *xwl_screen);
+#endif
+
 #endif
-- 
2.17.0



More information about the xorg-devel mailing list