radeon_dri3.c revision 0d16fef4
10d16fef4Smrg/* 20d16fef4Smrg * Copyright © 2013-2014 Intel Corporation 30d16fef4Smrg * Copyright © 2015 Advanced Micro Devices, Inc. 40d16fef4Smrg * 50d16fef4Smrg * Permission to use, copy, modify, distribute, and sell this software and its 60d16fef4Smrg * documentation for any purpose is hereby granted without fee, provided that 70d16fef4Smrg * the above copyright notice appear in all copies and that both that copyright 80d16fef4Smrg * notice and this permission notice appear in supporting documentation, and 90d16fef4Smrg * that the name of the copyright holders not be used in advertising or 100d16fef4Smrg * publicity pertaining to distribution of the software without specific, 110d16fef4Smrg * written prior permission. The copyright holders make no representations 120d16fef4Smrg * about the suitability of this software for any purpose. It is provided "as 130d16fef4Smrg * is" without express or implied warranty. 140d16fef4Smrg * 150d16fef4Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 160d16fef4Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 170d16fef4Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 180d16fef4Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 190d16fef4Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 200d16fef4Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 210d16fef4Smrg * OF THIS SOFTWARE. 220d16fef4Smrg */ 230d16fef4Smrg 240d16fef4Smrg 250d16fef4Smrg#ifdef HAVE_CONFIG_H 260d16fef4Smrg#include "config.h" 270d16fef4Smrg#endif 280d16fef4Smrg 290d16fef4Smrg#include "radeon.h" 300d16fef4Smrg 310d16fef4Smrg#ifdef HAVE_DRI3_H 320d16fef4Smrg 330d16fef4Smrg#include "radeon_bo_gem.h" 340d16fef4Smrg#include "radeon_glamor.h" 350d16fef4Smrg#include "dri3.h" 360d16fef4Smrg 370d16fef4Smrg#include <sys/types.h> 380d16fef4Smrg#include <sys/stat.h> 390d16fef4Smrg#include <fcntl.h> 400d16fef4Smrg#include <errno.h> 410d16fef4Smrg#include <libgen.h> 420d16fef4Smrg 430d16fef4Smrg 440d16fef4Smrgstatic int 450d16fef4Smrgradeon_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out) 460d16fef4Smrg{ 470d16fef4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 480d16fef4Smrg RADEONInfoPtr info = RADEONPTR(scrn); 490d16fef4Smrg drm_magic_t magic; 500d16fef4Smrg int fd; 510d16fef4Smrg 520d16fef4Smrg fd = open(info->dri2.device_name, O_RDWR | O_CLOEXEC); 530d16fef4Smrg if (fd < 0) 540d16fef4Smrg return BadAlloc; 550d16fef4Smrg 560d16fef4Smrg /* Before FD passing in the X protocol with DRI3 (and increased 570d16fef4Smrg * security of rendering with per-process address spaces on the 580d16fef4Smrg * GPU), the kernel had to come up with a way to have the server 590d16fef4Smrg * decide which clients got to access the GPU, which was done by 600d16fef4Smrg * each client getting a unique (magic) number from the kernel, 610d16fef4Smrg * passing it to the server, and the server then telling the 620d16fef4Smrg * kernel which clients were authenticated for using the device. 630d16fef4Smrg * 640d16fef4Smrg * Now that we have FD passing, the server can just set up the 650d16fef4Smrg * authentication on its own and hand the prepared FD off to the 660d16fef4Smrg * client. 670d16fef4Smrg */ 680d16fef4Smrg if (drmGetMagic(fd, &magic) < 0) { 690d16fef4Smrg if (errno == EACCES) { 700d16fef4Smrg /* Assume that we're on a render node, and the fd is 710d16fef4Smrg * already as authenticated as it should be. 720d16fef4Smrg */ 730d16fef4Smrg *out = fd; 740d16fef4Smrg return Success; 750d16fef4Smrg } else { 760d16fef4Smrg close(fd); 770d16fef4Smrg return BadMatch; 780d16fef4Smrg } 790d16fef4Smrg } 800d16fef4Smrg 810d16fef4Smrg if (drmAuthMagic(info->dri2.drm_fd, magic) < 0) { 820d16fef4Smrg close(fd); 830d16fef4Smrg return BadMatch; 840d16fef4Smrg } 850d16fef4Smrg 860d16fef4Smrg *out = fd; 870d16fef4Smrg return Success; 880d16fef4Smrg} 890d16fef4Smrg 900d16fef4Smrg#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 910d16fef4Smrg 920d16fef4Smrgstatic int 930d16fef4Smrgradeon_dri3_open_client(ClientPtr client, ScreenPtr screen, 940d16fef4Smrg RRProviderPtr provider, int *out) 950d16fef4Smrg{ 960d16fef4Smrg const char *cmdname = GetClientCmdName(client); 970d16fef4Smrg Bool is_ssh = FALSE; 980d16fef4Smrg 990d16fef4Smrg /* If the executable name is "ssh", assume that this client connection 1000d16fef4Smrg * is forwarded from another host via SSH 1010d16fef4Smrg */ 1020d16fef4Smrg if (cmdname) { 1030d16fef4Smrg char *cmd = strdup(cmdname); 1040d16fef4Smrg 1050d16fef4Smrg /* Cut off any colon and whatever comes after it, see 1060d16fef4Smrg * https://lists.freedesktop.org/archives/xorg-devel/2015-December/048164.html 1070d16fef4Smrg */ 1080d16fef4Smrg cmd = strtok(cmd, ":"); 1090d16fef4Smrg 1100d16fef4Smrg is_ssh = strcmp(basename(cmd), "ssh") == 0; 1110d16fef4Smrg free(cmd); 1120d16fef4Smrg } 1130d16fef4Smrg 1140d16fef4Smrg if (!is_ssh) 1150d16fef4Smrg return radeon_dri3_open(screen, provider, out); 1160d16fef4Smrg 1170d16fef4Smrg return BadAccess; 1180d16fef4Smrg} 1190d16fef4Smrg 1200d16fef4Smrg#endif /* DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) */ 1210d16fef4Smrg 1220d16fef4Smrgstatic PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen, 1230d16fef4Smrg int fd, 1240d16fef4Smrg CARD16 width, 1250d16fef4Smrg CARD16 height, 1260d16fef4Smrg CARD16 stride, 1270d16fef4Smrg CARD8 depth, 1280d16fef4Smrg CARD8 bpp) 1290d16fef4Smrg{ 1300d16fef4Smrg PixmapPtr pixmap; 1310d16fef4Smrg 1320d16fef4Smrg#ifdef USE_GLAMOR 1330d16fef4Smrg /* Avoid generating a GEM flink name if possible */ 1340d16fef4Smrg if (RADEONPTR(xf86ScreenToScrn(screen))->use_glamor) { 1350d16fef4Smrg pixmap = glamor_pixmap_from_fd(screen, fd, width, height, 1360d16fef4Smrg stride, depth, bpp); 1370d16fef4Smrg if (pixmap) { 1380d16fef4Smrg struct radeon_pixmap *priv = 1390d16fef4Smrg calloc(1, sizeof(struct radeon_pixmap)); 1400d16fef4Smrg 1410d16fef4Smrg if (priv) { 1420d16fef4Smrg radeon_set_pixmap_private(pixmap, priv); 1430d16fef4Smrg return pixmap; 1440d16fef4Smrg } 1450d16fef4Smrg 1460d16fef4Smrg screen->DestroyPixmap(pixmap); 1470d16fef4Smrg } 1480d16fef4Smrg } 1490d16fef4Smrg#endif 1500d16fef4Smrg 1510d16fef4Smrg if (depth < 8) 1520d16fef4Smrg return NULL; 1530d16fef4Smrg 1540d16fef4Smrg switch (bpp) { 1550d16fef4Smrg case 8: 1560d16fef4Smrg case 16: 1570d16fef4Smrg case 32: 1580d16fef4Smrg break; 1590d16fef4Smrg default: 1600d16fef4Smrg return NULL; 1610d16fef4Smrg } 1620d16fef4Smrg 1630d16fef4Smrg pixmap = screen->CreatePixmap(screen, 0, 0, depth, RADEON_CREATE_PIXMAP_DRI2); 1640d16fef4Smrg if (!pixmap) 1650d16fef4Smrg return NULL; 1660d16fef4Smrg 1670d16fef4Smrg if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, bpp, stride, 1680d16fef4Smrg NULL)) 1690d16fef4Smrg goto free_pixmap; 1700d16fef4Smrg 1710d16fef4Smrg if (screen->SetSharedPixmapBacking(pixmap, (void*)(intptr_t)fd)) 1720d16fef4Smrg return pixmap; 1730d16fef4Smrg 1740d16fef4Smrgfree_pixmap: 1750d16fef4Smrg fbDestroyPixmap(pixmap); 1760d16fef4Smrg return NULL; 1770d16fef4Smrg} 1780d16fef4Smrg 1790d16fef4Smrgstatic int radeon_dri3_fd_from_pixmap(ScreenPtr screen, 1800d16fef4Smrg PixmapPtr pixmap, 1810d16fef4Smrg CARD16 *stride, 1820d16fef4Smrg CARD32 *size) 1830d16fef4Smrg{ 1840d16fef4Smrg struct radeon_bo *bo; 1850d16fef4Smrg int fd; 1860d16fef4Smrg 1870d16fef4Smrg bo = radeon_get_pixmap_bo(pixmap); 1880d16fef4Smrg if (!bo) { 1890d16fef4Smrg#ifdef USE_GLAMOR 1900d16fef4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1910d16fef4Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1920d16fef4Smrg 1930d16fef4Smrg if (info->use_glamor) 1940d16fef4Smrg return glamor_fd_from_pixmap(screen, pixmap, stride, size); 1950d16fef4Smrg#endif 1960d16fef4Smrg 1970d16fef4Smrg exaMoveInPixmap(pixmap); 1980d16fef4Smrg bo = radeon_get_pixmap_bo(pixmap); 1990d16fef4Smrg if (!bo) 2000d16fef4Smrg return -1; 2010d16fef4Smrg } 2020d16fef4Smrg 2030d16fef4Smrg if (pixmap->devKind > UINT16_MAX) 2040d16fef4Smrg return -1; 2050d16fef4Smrg 2060d16fef4Smrg if (radeon_gem_prime_share_bo(bo, &fd) < 0) 2070d16fef4Smrg return -1; 2080d16fef4Smrg 2090d16fef4Smrg *stride = pixmap->devKind; 2100d16fef4Smrg *size = bo->size; 2110d16fef4Smrg return fd; 2120d16fef4Smrg} 2130d16fef4Smrg 2140d16fef4Smrgstatic dri3_screen_info_rec radeon_dri3_screen_info = { 2150d16fef4Smrg#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 2160d16fef4Smrg .version = 1, 2170d16fef4Smrg .open_client = radeon_dri3_open_client, 2180d16fef4Smrg#else 2190d16fef4Smrg .version = 0, 2200d16fef4Smrg .open = radeon_dri3_open, 2210d16fef4Smrg#endif 2220d16fef4Smrg .pixmap_from_fd = radeon_dri3_pixmap_from_fd, 2230d16fef4Smrg .fd_from_pixmap = radeon_dri3_fd_from_pixmap 2240d16fef4Smrg}; 2250d16fef4Smrg 2260d16fef4SmrgBool 2270d16fef4Smrgradeon_dri3_screen_init(ScreenPtr screen) 2280d16fef4Smrg{ 2290d16fef4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 2300d16fef4Smrg 2310d16fef4Smrg if (!dri3_screen_init(screen, &radeon_dri3_screen_info)) { 2320d16fef4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2330d16fef4Smrg "dri3_screen_init failed\n"); 2340d16fef4Smrg return FALSE; 2350d16fef4Smrg } 2360d16fef4Smrg 2370d16fef4Smrg return TRUE; 2380d16fef4Smrg} 2390d16fef4Smrg 2400d16fef4Smrg#else /* !HAVE_DRI3_H */ 2410d16fef4Smrg 2420d16fef4SmrgBool 2430d16fef4Smrgradeon_dri3_screen_init(ScreenPtr screen) 2440d16fef4Smrg{ 2450d16fef4Smrg xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 2460d16fef4Smrg "Can't initialize DRI3 because dri3.h not available at " 2470d16fef4Smrg "build time\n"); 2480d16fef4Smrg 2490d16fef4Smrg return FALSE; 2500d16fef4Smrg} 2510d16fef4Smrg 2520d16fef4Smrg#endif 253