radeon_dri3.c revision 3ed65abb
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 433ed65abbSmrgstatic int open_master_node(ScreenPtr screen, int *out) 440d16fef4Smrg{ 450d16fef4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 460d16fef4Smrg RADEONInfoPtr info = RADEONPTR(scrn); 470d16fef4Smrg drm_magic_t magic; 480d16fef4Smrg int fd; 490d16fef4Smrg 500d16fef4Smrg fd = open(info->dri2.device_name, O_RDWR | O_CLOEXEC); 510d16fef4Smrg if (fd < 0) 520d16fef4Smrg return BadAlloc; 530d16fef4Smrg 540d16fef4Smrg /* Before FD passing in the X protocol with DRI3 (and increased 550d16fef4Smrg * security of rendering with per-process address spaces on the 560d16fef4Smrg * GPU), the kernel had to come up with a way to have the server 570d16fef4Smrg * decide which clients got to access the GPU, which was done by 580d16fef4Smrg * each client getting a unique (magic) number from the kernel, 590d16fef4Smrg * passing it to the server, and the server then telling the 600d16fef4Smrg * kernel which clients were authenticated for using the device. 610d16fef4Smrg * 620d16fef4Smrg * Now that we have FD passing, the server can just set up the 630d16fef4Smrg * authentication on its own and hand the prepared FD off to the 640d16fef4Smrg * client. 650d16fef4Smrg */ 660d16fef4Smrg if (drmGetMagic(fd, &magic) < 0) { 670d16fef4Smrg if (errno == EACCES) { 680d16fef4Smrg /* Assume that we're on a render node, and the fd is 690d16fef4Smrg * already as authenticated as it should be. 700d16fef4Smrg */ 710d16fef4Smrg *out = fd; 720d16fef4Smrg return Success; 730d16fef4Smrg } else { 740d16fef4Smrg close(fd); 750d16fef4Smrg return BadMatch; 760d16fef4Smrg } 770d16fef4Smrg } 780d16fef4Smrg 790d16fef4Smrg if (drmAuthMagic(info->dri2.drm_fd, magic) < 0) { 800d16fef4Smrg close(fd); 810d16fef4Smrg return BadMatch; 820d16fef4Smrg } 830d16fef4Smrg 840d16fef4Smrg *out = fd; 850d16fef4Smrg return Success; 860d16fef4Smrg} 870d16fef4Smrg 883ed65abbSmrgstatic int open_render_node(ScreenPtr screen, int *out) 893ed65abbSmrg{ 903ed65abbSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 913ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 923ed65abbSmrg int fd; 933ed65abbSmrg 943ed65abbSmrg fd = open(pRADEONEnt->render_node, O_RDWR | O_CLOEXEC); 953ed65abbSmrg if (fd < 0) 963ed65abbSmrg return BadAlloc; 973ed65abbSmrg 983ed65abbSmrg *out = fd; 993ed65abbSmrg return Success; 1003ed65abbSmrg} 1013ed65abbSmrg 1023ed65abbSmrgstatic int 1033ed65abbSmrgradeon_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out) 1043ed65abbSmrg{ 1053ed65abbSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1063ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 1073ed65abbSmrg int ret = BadAlloc; 1083ed65abbSmrg 1093ed65abbSmrg if (pRADEONEnt->render_node) 1103ed65abbSmrg ret = open_render_node(screen, out); 1113ed65abbSmrg 1123ed65abbSmrg if (ret != Success) 1133ed65abbSmrg ret = open_master_node(screen, out); 1143ed65abbSmrg 1153ed65abbSmrg return ret; 1163ed65abbSmrg} 1173ed65abbSmrg 1180d16fef4Smrg#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 1190d16fef4Smrg 1200d16fef4Smrgstatic int 1210d16fef4Smrgradeon_dri3_open_client(ClientPtr client, ScreenPtr screen, 1220d16fef4Smrg RRProviderPtr provider, int *out) 1230d16fef4Smrg{ 1240d16fef4Smrg const char *cmdname = GetClientCmdName(client); 1250d16fef4Smrg Bool is_ssh = FALSE; 1260d16fef4Smrg 1270d16fef4Smrg /* If the executable name is "ssh", assume that this client connection 1280d16fef4Smrg * is forwarded from another host via SSH 1290d16fef4Smrg */ 1300d16fef4Smrg if (cmdname) { 1310d16fef4Smrg char *cmd = strdup(cmdname); 1320d16fef4Smrg 1330d16fef4Smrg /* Cut off any colon and whatever comes after it, see 1340d16fef4Smrg * https://lists.freedesktop.org/archives/xorg-devel/2015-December/048164.html 1350d16fef4Smrg */ 1360d16fef4Smrg cmd = strtok(cmd, ":"); 1370d16fef4Smrg 1380d16fef4Smrg is_ssh = strcmp(basename(cmd), "ssh") == 0; 1390d16fef4Smrg free(cmd); 1400d16fef4Smrg } 1410d16fef4Smrg 1420d16fef4Smrg if (!is_ssh) 1430d16fef4Smrg return radeon_dri3_open(screen, provider, out); 1440d16fef4Smrg 1450d16fef4Smrg return BadAccess; 1460d16fef4Smrg} 1470d16fef4Smrg 1480d16fef4Smrg#endif /* DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) */ 1490d16fef4Smrg 1500d16fef4Smrgstatic PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen, 1510d16fef4Smrg int fd, 1520d16fef4Smrg CARD16 width, 1530d16fef4Smrg CARD16 height, 1540d16fef4Smrg CARD16 stride, 1550d16fef4Smrg CARD8 depth, 1560d16fef4Smrg CARD8 bpp) 1570d16fef4Smrg{ 1580d16fef4Smrg PixmapPtr pixmap; 1590d16fef4Smrg 1600d16fef4Smrg#ifdef USE_GLAMOR 1610d16fef4Smrg /* Avoid generating a GEM flink name if possible */ 1620d16fef4Smrg if (RADEONPTR(xf86ScreenToScrn(screen))->use_glamor) { 1630d16fef4Smrg pixmap = glamor_pixmap_from_fd(screen, fd, width, height, 1640d16fef4Smrg stride, depth, bpp); 1650d16fef4Smrg if (pixmap) { 1660d16fef4Smrg struct radeon_pixmap *priv = 1670d16fef4Smrg calloc(1, sizeof(struct radeon_pixmap)); 1680d16fef4Smrg 1690d16fef4Smrg if (priv) { 1700d16fef4Smrg radeon_set_pixmap_private(pixmap, priv); 1710d16fef4Smrg return pixmap; 1720d16fef4Smrg } 1730d16fef4Smrg 1740d16fef4Smrg screen->DestroyPixmap(pixmap); 1757314432eSmrg return NULL; 1760d16fef4Smrg } 1770d16fef4Smrg } 1780d16fef4Smrg#endif 1790d16fef4Smrg 1800d16fef4Smrg if (depth < 8) 1810d16fef4Smrg return NULL; 1820d16fef4Smrg 1830d16fef4Smrg switch (bpp) { 1840d16fef4Smrg case 8: 1850d16fef4Smrg case 16: 1860d16fef4Smrg case 32: 1870d16fef4Smrg break; 1880d16fef4Smrg default: 1890d16fef4Smrg return NULL; 1900d16fef4Smrg } 1910d16fef4Smrg 1920d16fef4Smrg pixmap = screen->CreatePixmap(screen, 0, 0, depth, RADEON_CREATE_PIXMAP_DRI2); 1930d16fef4Smrg if (!pixmap) 1940d16fef4Smrg return NULL; 1950d16fef4Smrg 1960d16fef4Smrg if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, bpp, stride, 1970d16fef4Smrg NULL)) 1980d16fef4Smrg goto free_pixmap; 1990d16fef4Smrg 2000d16fef4Smrg if (screen->SetSharedPixmapBacking(pixmap, (void*)(intptr_t)fd)) 2010d16fef4Smrg return pixmap; 2020d16fef4Smrg 2030d16fef4Smrgfree_pixmap: 2040d16fef4Smrg fbDestroyPixmap(pixmap); 2050d16fef4Smrg return NULL; 2060d16fef4Smrg} 2070d16fef4Smrg 2080d16fef4Smrgstatic int radeon_dri3_fd_from_pixmap(ScreenPtr screen, 2090d16fef4Smrg PixmapPtr pixmap, 2100d16fef4Smrg CARD16 *stride, 2110d16fef4Smrg CARD32 *size) 2120d16fef4Smrg{ 2130d16fef4Smrg struct radeon_bo *bo; 2140d16fef4Smrg int fd; 2150d16fef4Smrg 2160d16fef4Smrg bo = radeon_get_pixmap_bo(pixmap); 2170d16fef4Smrg if (!bo) { 2180d16fef4Smrg#ifdef USE_GLAMOR 2190d16fef4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 2200d16fef4Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2210d16fef4Smrg 2220d16fef4Smrg if (info->use_glamor) 2230d16fef4Smrg return glamor_fd_from_pixmap(screen, pixmap, stride, size); 2240d16fef4Smrg#endif 2250d16fef4Smrg 2260d16fef4Smrg exaMoveInPixmap(pixmap); 2270d16fef4Smrg bo = radeon_get_pixmap_bo(pixmap); 2280d16fef4Smrg if (!bo) 2290d16fef4Smrg return -1; 2300d16fef4Smrg } 2310d16fef4Smrg 2320d16fef4Smrg if (pixmap->devKind > UINT16_MAX) 2330d16fef4Smrg return -1; 2340d16fef4Smrg 2350d16fef4Smrg if (radeon_gem_prime_share_bo(bo, &fd) < 0) 2360d16fef4Smrg return -1; 2370d16fef4Smrg 2380d16fef4Smrg *stride = pixmap->devKind; 2390d16fef4Smrg *size = bo->size; 2400d16fef4Smrg return fd; 2410d16fef4Smrg} 2420d16fef4Smrg 2430d16fef4Smrgstatic dri3_screen_info_rec radeon_dri3_screen_info = { 2440d16fef4Smrg#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 2450d16fef4Smrg .version = 1, 2460d16fef4Smrg .open_client = radeon_dri3_open_client, 2470d16fef4Smrg#else 2480d16fef4Smrg .version = 0, 2490d16fef4Smrg .open = radeon_dri3_open, 2500d16fef4Smrg#endif 2510d16fef4Smrg .pixmap_from_fd = radeon_dri3_pixmap_from_fd, 2520d16fef4Smrg .fd_from_pixmap = radeon_dri3_fd_from_pixmap 2530d16fef4Smrg}; 2540d16fef4Smrg 2550d16fef4SmrgBool 2560d16fef4Smrgradeon_dri3_screen_init(ScreenPtr screen) 2570d16fef4Smrg{ 2580d16fef4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 2593ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 2603ed65abbSmrg 2613ed65abbSmrg pRADEONEnt->render_node = drmGetRenderDeviceNameFromFd(pRADEONEnt->fd); 2620d16fef4Smrg 2630d16fef4Smrg if (!dri3_screen_init(screen, &radeon_dri3_screen_info)) { 2640d16fef4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2650d16fef4Smrg "dri3_screen_init failed\n"); 2660d16fef4Smrg return FALSE; 2670d16fef4Smrg } 2680d16fef4Smrg 2690d16fef4Smrg return TRUE; 2700d16fef4Smrg} 2710d16fef4Smrg 2720d16fef4Smrg#else /* !HAVE_DRI3_H */ 2730d16fef4Smrg 2740d16fef4SmrgBool 2750d16fef4Smrgradeon_dri3_screen_init(ScreenPtr screen) 2760d16fef4Smrg{ 2770d16fef4Smrg xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 2780d16fef4Smrg "Can't initialize DRI3 because dri3.h not available at " 2790d16fef4Smrg "build time\n"); 2800d16fef4Smrg 2810d16fef4Smrg return FALSE; 2820d16fef4Smrg} 2830d16fef4Smrg 2840d16fef4Smrg#endif 285