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