summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLyude Paul <lyude@redhat.com>2018-04-20 14:38:03 -0400
committerAdam Jackson <ajax@redhat.com>2018-04-24 14:58:16 -0400
commit1545e2dbadcb147d7d52b546d053149de866a031 (patch)
tree5e2c326e24cf82d6bc497517e6b6adacdd869acf
parentd2d664df974ac5a55d5819f0379fcdac05d22fa3 (diff)
xwayland: Decouple GBM from glamor
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@redhat.com> Reviewed-by: Lyude Paul <lyude@redhat.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Adam Jackson <ajax@redhat.com>
-rw-r--r--hw/xwayland/Makefile.am1
-rw-r--r--hw/xwayland/meson.build6
-rw-r--r--hw/xwayland/xwayland-glamor-gbm.c891
-rw-r--r--hw/xwayland/xwayland-glamor.c760
-rw-r--r--hw/xwayland/xwayland.c17
-rw-r--r--hw/xwayland/xwayland.h58
6 files changed, 975 insertions, 758 deletions
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 80d3a1f19..3fd980d0e 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 8d178825e..ef4379aab 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 000000000..c03ba3da1
--- /dev/null
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -0,0 +1,891 @@
+/*
+ * 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@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;
+
+ /* Explicitly zero the count as the caller may ignore the return value */
+ *num_formats = 0;
+
+ if (!xwl_gbm->dmabuf_capable || !xwl_gbm->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_gbm_private *xwl_gbm = xwl_gbm_get(xwl_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_gbm->dmabuf_capable || !xwl_gbm->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,
+};
+
+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 1b9a6b030..7b24ce7e4 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;
- }
-
- /* 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);
+ if (xwl_screen->egl_backend.get_wl_buffer_for_pixmap)
+ return xwl_screen->egl_backend.get_wl_buffer_for_pixmap(pixmap,
+ width,
+ height,
+ created);
- 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 72493285e..b37b62c78 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 11a9f4816..82cbfc9d3 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