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> 40446f62d6Smrg#include <gbm.h> 410d16fef4Smrg#include <errno.h> 420d16fef4Smrg#include <libgen.h> 430d16fef4Smrg 443ed65abbSmrgstatic int open_master_node(ScreenPtr screen, int *out) 450d16fef4Smrg{ 460d16fef4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 478bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 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 818bf5c682Smrg if (drmAuthMagic(pRADEONEnt->fd, magic) < 0) { 820d16fef4Smrg close(fd); 830d16fef4Smrg return BadMatch; 840d16fef4Smrg } 850d16fef4Smrg 860d16fef4Smrg *out = fd; 870d16fef4Smrg return Success; 880d16fef4Smrg} 890d16fef4Smrg 903ed65abbSmrgstatic int open_render_node(ScreenPtr screen, int *out) 913ed65abbSmrg{ 923ed65abbSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 933ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 943ed65abbSmrg int fd; 953ed65abbSmrg 963ed65abbSmrg fd = open(pRADEONEnt->render_node, O_RDWR | O_CLOEXEC); 973ed65abbSmrg if (fd < 0) 983ed65abbSmrg return BadAlloc; 993ed65abbSmrg 1003ed65abbSmrg *out = fd; 1013ed65abbSmrg return Success; 1023ed65abbSmrg} 1033ed65abbSmrg 1043ed65abbSmrgstatic int 1053ed65abbSmrgradeon_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out) 1063ed65abbSmrg{ 1073ed65abbSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1083ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 1093ed65abbSmrg int ret = BadAlloc; 1103ed65abbSmrg 1113ed65abbSmrg if (pRADEONEnt->render_node) 1123ed65abbSmrg ret = open_render_node(screen, out); 1133ed65abbSmrg 1143ed65abbSmrg if (ret != Success) 1153ed65abbSmrg ret = open_master_node(screen, out); 1163ed65abbSmrg 1173ed65abbSmrg return ret; 1183ed65abbSmrg} 1193ed65abbSmrg 1200d16fef4Smrg#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 1210d16fef4Smrg 1220d16fef4Smrgstatic int 1230d16fef4Smrgradeon_dri3_open_client(ClientPtr client, ScreenPtr screen, 1240d16fef4Smrg RRProviderPtr provider, int *out) 1250d16fef4Smrg{ 1260d16fef4Smrg const char *cmdname = GetClientCmdName(client); 1270d16fef4Smrg Bool is_ssh = FALSE; 1280d16fef4Smrg 1290d16fef4Smrg /* If the executable name is "ssh", assume that this client connection 1300d16fef4Smrg * is forwarded from another host via SSH 1310d16fef4Smrg */ 1320d16fef4Smrg if (cmdname) { 1330d16fef4Smrg char *cmd = strdup(cmdname); 1340d16fef4Smrg 1350d16fef4Smrg /* Cut off any colon and whatever comes after it, see 1360d16fef4Smrg * https://lists.freedesktop.org/archives/xorg-devel/2015-December/048164.html 1370d16fef4Smrg */ 1380d16fef4Smrg cmd = strtok(cmd, ":"); 1390d16fef4Smrg 1400d16fef4Smrg is_ssh = strcmp(basename(cmd), "ssh") == 0; 1410d16fef4Smrg free(cmd); 1420d16fef4Smrg } 1430d16fef4Smrg 1440d16fef4Smrg if (!is_ssh) 1450d16fef4Smrg return radeon_dri3_open(screen, provider, out); 1460d16fef4Smrg 1470d16fef4Smrg return BadAccess; 1480d16fef4Smrg} 1490d16fef4Smrg 1500d16fef4Smrg#endif /* DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) */ 1510d16fef4Smrg 1520d16fef4Smrgstatic PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen, 1530d16fef4Smrg int fd, 1540d16fef4Smrg CARD16 width, 1550d16fef4Smrg CARD16 height, 1560d16fef4Smrg CARD16 stride, 1570d16fef4Smrg CARD8 depth, 1580d16fef4Smrg CARD8 bpp) 1590d16fef4Smrg{ 1600d16fef4Smrg PixmapPtr pixmap; 1610d16fef4Smrg 1620d16fef4Smrg#ifdef USE_GLAMOR 1630d16fef4Smrg /* Avoid generating a GEM flink name if possible */ 1640d16fef4Smrg if (RADEONPTR(xf86ScreenToScrn(screen))->use_glamor) { 1650d16fef4Smrg pixmap = glamor_pixmap_from_fd(screen, fd, width, height, 1660d16fef4Smrg stride, depth, bpp); 1670d16fef4Smrg if (pixmap) { 1680d16fef4Smrg struct radeon_pixmap *priv = 1690d16fef4Smrg calloc(1, sizeof(struct radeon_pixmap)); 1700d16fef4Smrg 1710d16fef4Smrg if (priv) { 1720d16fef4Smrg radeon_set_pixmap_private(pixmap, priv); 17339413783Smrg pixmap->usage_hint |= RADEON_CREATE_PIXMAP_DRI2; 1740d16fef4Smrg return pixmap; 1750d16fef4Smrg } 1760d16fef4Smrg 1770d16fef4Smrg screen->DestroyPixmap(pixmap); 1787314432eSmrg return NULL; 1790d16fef4Smrg } 1800d16fef4Smrg } 1810d16fef4Smrg#endif 1820d16fef4Smrg 1830d16fef4Smrg if (depth < 8) 1840d16fef4Smrg return NULL; 1850d16fef4Smrg 1860d16fef4Smrg switch (bpp) { 1870d16fef4Smrg case 8: 1880d16fef4Smrg case 16: 1890d16fef4Smrg case 32: 1900d16fef4Smrg break; 1910d16fef4Smrg default: 1920d16fef4Smrg return NULL; 1930d16fef4Smrg } 1940d16fef4Smrg 1950d16fef4Smrg pixmap = screen->CreatePixmap(screen, 0, 0, depth, RADEON_CREATE_PIXMAP_DRI2); 1960d16fef4Smrg if (!pixmap) 1970d16fef4Smrg return NULL; 1980d16fef4Smrg 1990d16fef4Smrg if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, bpp, stride, 2000d16fef4Smrg NULL)) 2010d16fef4Smrg goto free_pixmap; 2020d16fef4Smrg 2030d16fef4Smrg if (screen->SetSharedPixmapBacking(pixmap, (void*)(intptr_t)fd)) 2040d16fef4Smrg return pixmap; 2050d16fef4Smrg 2060d16fef4Smrgfree_pixmap: 2070d16fef4Smrg fbDestroyPixmap(pixmap); 2080d16fef4Smrg return NULL; 2090d16fef4Smrg} 2100d16fef4Smrg 2110d16fef4Smrgstatic int radeon_dri3_fd_from_pixmap(ScreenPtr screen, 2120d16fef4Smrg PixmapPtr pixmap, 2130d16fef4Smrg CARD16 *stride, 2140d16fef4Smrg CARD32 *size) 2150d16fef4Smrg{ 216446f62d6Smrg struct radeon_buffer *bo; 2170d16fef4Smrg int fd; 2180d16fef4Smrg#ifdef USE_GLAMOR 21939413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 22039413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2210d16fef4Smrg 222446f62d6Smrg if (info->use_glamor) { 2230d2a5547Smrg int ret = glamor_fd_from_pixmap(screen, pixmap, stride, size); 224446f62d6Smrg 2250d2a5547Smrg /* Any pending drawing operations need to be flushed to the 2260d2a5547Smrg * kernel driver before the client starts using the pixmap 2270d2a5547Smrg * storage for direct rendering. 228446f62d6Smrg */ 2290d2a5547Smrg if (ret >= 0) 230446f62d6Smrg radeon_cs_flush_indirect(scrn); 231446f62d6Smrg 232446f62d6Smrg return ret; 233446f62d6Smrg } 2340d16fef4Smrg#endif 2350d16fef4Smrg 236446f62d6Smrg bo = radeon_get_pixmap_bo(pixmap); 23739413783Smrg if (!bo) { 2380d16fef4Smrg exaMoveInPixmap(pixmap); 239446f62d6Smrg bo = radeon_get_pixmap_bo(pixmap); 2400d16fef4Smrg if (!bo) 2410d16fef4Smrg return -1; 2420d16fef4Smrg } 2430d16fef4Smrg 2440d16fef4Smrg if (pixmap->devKind > UINT16_MAX) 2450d16fef4Smrg return -1; 2460d16fef4Smrg 247446f62d6Smrg if (radeon_gem_prime_share_bo(bo->bo.radeon, &fd) < 0) 2480d16fef4Smrg return -1; 2490d16fef4Smrg 2500d16fef4Smrg *stride = pixmap->devKind; 251446f62d6Smrg *size = bo->bo.radeon->size; 2520d16fef4Smrg return fd; 2530d16fef4Smrg} 2540d16fef4Smrg 2550d16fef4Smrgstatic dri3_screen_info_rec radeon_dri3_screen_info = { 2560d16fef4Smrg#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 2570d16fef4Smrg .version = 1, 2580d16fef4Smrg .open_client = radeon_dri3_open_client, 2590d16fef4Smrg#else 2600d16fef4Smrg .version = 0, 2610d16fef4Smrg .open = radeon_dri3_open, 2620d16fef4Smrg#endif 2630d16fef4Smrg .pixmap_from_fd = radeon_dri3_pixmap_from_fd, 2640d16fef4Smrg .fd_from_pixmap = radeon_dri3_fd_from_pixmap 2650d16fef4Smrg}; 2660d16fef4Smrg 2670d16fef4SmrgBool 2680d16fef4Smrgradeon_dri3_screen_init(ScreenPtr screen) 2690d16fef4Smrg{ 2700d16fef4Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 2713ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 2723ed65abbSmrg 2733ed65abbSmrg pRADEONEnt->render_node = drmGetRenderDeviceNameFromFd(pRADEONEnt->fd); 2740d16fef4Smrg 2750d16fef4Smrg if (!dri3_screen_init(screen, &radeon_dri3_screen_info)) { 2760d16fef4Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2770d16fef4Smrg "dri3_screen_init failed\n"); 2780d16fef4Smrg return FALSE; 2790d16fef4Smrg } 2800d16fef4Smrg 2810d16fef4Smrg return TRUE; 2820d16fef4Smrg} 2830d16fef4Smrg 2840d16fef4Smrg#else /* !HAVE_DRI3_H */ 2850d16fef4Smrg 2860d16fef4SmrgBool 2870d16fef4Smrgradeon_dri3_screen_init(ScreenPtr screen) 2880d16fef4Smrg{ 2890d16fef4Smrg xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 2900d16fef4Smrg "Can't initialize DRI3 because dri3.h not available at " 2910d16fef4Smrg "build time\n"); 2920d16fef4Smrg 2930d16fef4Smrg return FALSE; 2940d16fef4Smrg} 2950d16fef4Smrg 2960d16fef4Smrg#endif 297