radeon_dri3.c revision 3ed65abb
1/* 2 * Copyright © 2013-2014 Intel Corporation 3 * Copyright © 2015 Advanced Micro Devices, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting documentation, and 9 * that the name of the copyright holders not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. The copyright holders make no representations 12 * about the suitability of this software for any purpose. It is provided "as 13 * is" without express or implied warranty. 14 * 15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 21 * OF THIS SOFTWARE. 22 */ 23 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include "radeon.h" 30 31#ifdef HAVE_DRI3_H 32 33#include "radeon_bo_gem.h" 34#include "radeon_glamor.h" 35#include "dri3.h" 36 37#include <sys/types.h> 38#include <sys/stat.h> 39#include <fcntl.h> 40#include <errno.h> 41#include <libgen.h> 42 43static int open_master_node(ScreenPtr screen, int *out) 44{ 45 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 46 RADEONInfoPtr info = RADEONPTR(scrn); 47 drm_magic_t magic; 48 int fd; 49 50 fd = open(info->dri2.device_name, O_RDWR | O_CLOEXEC); 51 if (fd < 0) 52 return BadAlloc; 53 54 /* Before FD passing in the X protocol with DRI3 (and increased 55 * security of rendering with per-process address spaces on the 56 * GPU), the kernel had to come up with a way to have the server 57 * decide which clients got to access the GPU, which was done by 58 * each client getting a unique (magic) number from the kernel, 59 * passing it to the server, and the server then telling the 60 * kernel which clients were authenticated for using the device. 61 * 62 * Now that we have FD passing, the server can just set up the 63 * authentication on its own and hand the prepared FD off to the 64 * client. 65 */ 66 if (drmGetMagic(fd, &magic) < 0) { 67 if (errno == EACCES) { 68 /* Assume that we're on a render node, and the fd is 69 * already as authenticated as it should be. 70 */ 71 *out = fd; 72 return Success; 73 } else { 74 close(fd); 75 return BadMatch; 76 } 77 } 78 79 if (drmAuthMagic(info->dri2.drm_fd, magic) < 0) { 80 close(fd); 81 return BadMatch; 82 } 83 84 *out = fd; 85 return Success; 86} 87 88static int open_render_node(ScreenPtr screen, int *out) 89{ 90 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 91 RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 92 int fd; 93 94 fd = open(pRADEONEnt->render_node, O_RDWR | O_CLOEXEC); 95 if (fd < 0) 96 return BadAlloc; 97 98 *out = fd; 99 return Success; 100} 101 102static int 103radeon_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out) 104{ 105 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 106 RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 107 int ret = BadAlloc; 108 109 if (pRADEONEnt->render_node) 110 ret = open_render_node(screen, out); 111 112 if (ret != Success) 113 ret = open_master_node(screen, out); 114 115 return ret; 116} 117 118#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 119 120static int 121radeon_dri3_open_client(ClientPtr client, ScreenPtr screen, 122 RRProviderPtr provider, int *out) 123{ 124 const char *cmdname = GetClientCmdName(client); 125 Bool is_ssh = FALSE; 126 127 /* If the executable name is "ssh", assume that this client connection 128 * is forwarded from another host via SSH 129 */ 130 if (cmdname) { 131 char *cmd = strdup(cmdname); 132 133 /* Cut off any colon and whatever comes after it, see 134 * https://lists.freedesktop.org/archives/xorg-devel/2015-December/048164.html 135 */ 136 cmd = strtok(cmd, ":"); 137 138 is_ssh = strcmp(basename(cmd), "ssh") == 0; 139 free(cmd); 140 } 141 142 if (!is_ssh) 143 return radeon_dri3_open(screen, provider, out); 144 145 return BadAccess; 146} 147 148#endif /* DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) */ 149 150static PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen, 151 int fd, 152 CARD16 width, 153 CARD16 height, 154 CARD16 stride, 155 CARD8 depth, 156 CARD8 bpp) 157{ 158 PixmapPtr pixmap; 159 160#ifdef USE_GLAMOR 161 /* Avoid generating a GEM flink name if possible */ 162 if (RADEONPTR(xf86ScreenToScrn(screen))->use_glamor) { 163 pixmap = glamor_pixmap_from_fd(screen, fd, width, height, 164 stride, depth, bpp); 165 if (pixmap) { 166 struct radeon_pixmap *priv = 167 calloc(1, sizeof(struct radeon_pixmap)); 168 169 if (priv) { 170 radeon_set_pixmap_private(pixmap, priv); 171 return pixmap; 172 } 173 174 screen->DestroyPixmap(pixmap); 175 return NULL; 176 } 177 } 178#endif 179 180 if (depth < 8) 181 return NULL; 182 183 switch (bpp) { 184 case 8: 185 case 16: 186 case 32: 187 break; 188 default: 189 return NULL; 190 } 191 192 pixmap = screen->CreatePixmap(screen, 0, 0, depth, RADEON_CREATE_PIXMAP_DRI2); 193 if (!pixmap) 194 return NULL; 195 196 if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, bpp, stride, 197 NULL)) 198 goto free_pixmap; 199 200 if (screen->SetSharedPixmapBacking(pixmap, (void*)(intptr_t)fd)) 201 return pixmap; 202 203free_pixmap: 204 fbDestroyPixmap(pixmap); 205 return NULL; 206} 207 208static int radeon_dri3_fd_from_pixmap(ScreenPtr screen, 209 PixmapPtr pixmap, 210 CARD16 *stride, 211 CARD32 *size) 212{ 213 struct radeon_bo *bo; 214 int fd; 215 216 bo = radeon_get_pixmap_bo(pixmap); 217 if (!bo) { 218#ifdef USE_GLAMOR 219 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 220 RADEONInfoPtr info = RADEONPTR(scrn); 221 222 if (info->use_glamor) 223 return glamor_fd_from_pixmap(screen, pixmap, stride, size); 224#endif 225 226 exaMoveInPixmap(pixmap); 227 bo = radeon_get_pixmap_bo(pixmap); 228 if (!bo) 229 return -1; 230 } 231 232 if (pixmap->devKind > UINT16_MAX) 233 return -1; 234 235 if (radeon_gem_prime_share_bo(bo, &fd) < 0) 236 return -1; 237 238 *stride = pixmap->devKind; 239 *size = bo->size; 240 return fd; 241} 242 243static dri3_screen_info_rec radeon_dri3_screen_info = { 244#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 245 .version = 1, 246 .open_client = radeon_dri3_open_client, 247#else 248 .version = 0, 249 .open = radeon_dri3_open, 250#endif 251 .pixmap_from_fd = radeon_dri3_pixmap_from_fd, 252 .fd_from_pixmap = radeon_dri3_fd_from_pixmap 253}; 254 255Bool 256radeon_dri3_screen_init(ScreenPtr screen) 257{ 258 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 259 RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 260 261 pRADEONEnt->render_node = drmGetRenderDeviceNameFromFd(pRADEONEnt->fd); 262 263 if (!dri3_screen_init(screen, &radeon_dri3_screen_info)) { 264 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 265 "dri3_screen_init failed\n"); 266 return FALSE; 267 } 268 269 return TRUE; 270} 271 272#else /* !HAVE_DRI3_H */ 273 274Bool 275radeon_dri3_screen_init(ScreenPtr screen) 276{ 277 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 278 "Can't initialize DRI3 because dri3.h not available at " 279 "build time\n"); 280 281 return FALSE; 282} 283 284#endif 285