diff --git a/glamor/glamor.h b/glamor/glamor.h index 041004e9d..e12f497cb 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -67,10 +67,12 @@ typedef enum glamor_pixmap_type { #define GLAMOR_USE_SCREEN (1 << 1) #define GLAMOR_USE_PICTURE_SCREEN (1 << 2) #define GLAMOR_USE_EGL_SCREEN (1 << 3) +#define GLAMOR_NO_DRI3 (1 << 4) #define GLAMOR_VALID_FLAGS (GLAMOR_INVERTED_Y_AXIS \ | GLAMOR_USE_SCREEN \ | GLAMOR_USE_PICTURE_SCREEN \ - | GLAMOR_USE_EGL_SCREEN) + | GLAMOR_USE_EGL_SCREEN \ + | GLAMOR_NO_DRI3) /* @glamor_init: Initialize glamor internal data structure. * diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c index 56d89138e..05e6bd02e 100644 --- a/glamor/glamor_egl.c +++ b/glamor/glamor_egl.c @@ -50,6 +50,7 @@ #include "glamor.h" #include "glamor_priv.h" +#include "dri3.h" static const char glamor_name[] = "glamor"; @@ -68,6 +69,7 @@ struct glamor_egl_screen_private { EGLDisplay display; EGLContext context; EGLint major, minor; + char *device_path; CreateScreenResourcesProcPtr CreateScreenResources; CloseScreenProcPtr CloseScreen; @@ -627,10 +629,67 @@ glamor_egl_has_extension(struct glamor_egl_screen_private *glamor_egl, return FALSE; } +static int +glamor_dri3_open(ScreenPtr screen, + RRProviderPtr provider, + int *fdp) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + struct glamor_egl_screen_private *glamor_egl = + glamor_egl_get_screen_private(scrn); + int fd; + drm_magic_t magic; + + fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC); + if (fd < 0) + return BadAlloc; + + /* Before FD passing in the X protocol with DRI3 (and increased + * security of rendering with per-process address spaces on the + * GPU), the kernel had to come up with a way to have the server + * decide which clients got to access the GPU, which was done by + * each client getting a unique (magic) number from the kernel, + * passing it to the server, and the server then telling the + * kernel which clients were authenticated for using the device. + * + * Now that we have FD passing, the server can just set up the + * authentication on its own and hand the prepared FD off to the + * client. + */ + if (drmGetMagic(fd, &magic) < 0) { + if (errno == EACCES) { + /* Assume that we're on a render node, and the fd is + * already as authenticated as it should be. + */ + *fdp = fd; + return Success; + } else { + close(fd); + return BadMatch; + } + } + + if (drmAuthMagic(glamor_egl->fd, magic) < 0) { + close(fd); + return BadMatch; + } + + *fdp = fd; + return Success; +} + +static dri3_screen_info_rec glamor_dri3_info = { + .version = 0, + .open = glamor_dri3_open, + .pixmap_from_fd = glamor_pixmap_from_fd, + .fd_from_pixmap = glamor_fd_from_pixmap, +}; + void glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); struct glamor_egl_screen_private *glamor_egl = glamor_egl_get_screen_private(scrn); @@ -642,6 +701,30 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) glamor_ctx->get_context = glamor_egl_get_context; glamor_ctx->put_context = glamor_egl_put_context; + + if (glamor_egl->dri3_capable) { + /* Tell the core that we have the interfaces for import/export + * of pixmaps. + */ + glamor_enable_dri3(screen); + + /* If the driver wants to do its own auth dance (e.g. Xwayland + * on pre-3.15 kernels that don't have render nodes and thus + * has the wayland compositor as a master), then it needs us + * to stay out of the way and let it init DRI3 on its own. + */ + if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) { + /* To do DRI3 device FD generation, we need to open a new fd + * to the same device we were handed in originally. + */ + glamor_egl->device_path = drmGetDeviceNameFromFd(glamor_egl->fd); + + if (!dri3_screen_init(screen, &glamor_dri3_info)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to initialize DRI3.\n"); + } + } + } } static void @@ -658,6 +741,8 @@ glamor_egl_free_screen(ScrnInfoPtr scrn) if (glamor_egl->gbm) gbm_device_destroy(glamor_egl->gbm); #endif + free(glamor_egl->device_path); + scrn->FreeScreen = glamor_egl->saved_free_screen; free(glamor_egl); scrn->FreeScreen(scrn); diff --git a/hw/xfree86/glamor_egl/Makefile.am b/hw/xfree86/glamor_egl/Makefile.am index bb1b51166..85e1c0c06 100644 --- a/hw/xfree86/glamor_egl/Makefile.am +++ b/hw/xfree86/glamor_egl/Makefile.am @@ -36,5 +36,8 @@ libglamoregl_la_LIBADD = \ $(top_builddir)/glamor/libglamor.la \ $() -AM_CPPFLAGS = $(XORG_INCS) +AM_CPPFLAGS = $(XORG_INCS) \ + -I$(top_srcdir)/dri3 \ + $() + AM_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS) $(GLAMOR_CFLAGS) $(GBM_CFLAGS)