radeon_dri3.c revision 0d16fef4
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 43 44static int 45radeon_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out) 46{ 47 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 48 RADEONInfoPtr info = RADEONPTR(scrn); 49 drm_magic_t magic; 50 int fd; 51 52 fd = open(info->dri2.device_name, O_RDWR | O_CLOEXEC); 53 if (fd < 0) 54 return BadAlloc; 55 56 /* Before FD passing in the X protocol with DRI3 (and increased 57 * security of rendering with per-process address spaces on the 58 * GPU), the kernel had to come up with a way to have the server 59 * decide which clients got to access the GPU, which was done by 60 * each client getting a unique (magic) number from the kernel, 61 * passing it to the server, and the server then telling the 62 * kernel which clients were authenticated for using the device. 63 * 64 * Now that we have FD passing, the server can just set up the 65 * authentication on its own and hand the prepared FD off to the 66 * client. 67 */ 68 if (drmGetMagic(fd, &magic) < 0) { 69 if (errno == EACCES) { 70 /* Assume that we're on a render node, and the fd is 71 * already as authenticated as it should be. 72 */ 73 *out = fd; 74 return Success; 75 } else { 76 close(fd); 77 return BadMatch; 78 } 79 } 80 81 if (drmAuthMagic(info->dri2.drm_fd, magic) < 0) { 82 close(fd); 83 return BadMatch; 84 } 85 86 *out = fd; 87 return Success; 88} 89 90#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 91 92static int 93radeon_dri3_open_client(ClientPtr client, ScreenPtr screen, 94 RRProviderPtr provider, int *out) 95{ 96 const char *cmdname = GetClientCmdName(client); 97 Bool is_ssh = FALSE; 98 99 /* If the executable name is "ssh", assume that this client connection 100 * is forwarded from another host via SSH 101 */ 102 if (cmdname) { 103 char *cmd = strdup(cmdname); 104 105 /* Cut off any colon and whatever comes after it, see 106 * https://lists.freedesktop.org/archives/xorg-devel/2015-December/048164.html 107 */ 108 cmd = strtok(cmd, ":"); 109 110 is_ssh = strcmp(basename(cmd), "ssh") == 0; 111 free(cmd); 112 } 113 114 if (!is_ssh) 115 return radeon_dri3_open(screen, provider, out); 116 117 return BadAccess; 118} 119 120#endif /* DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) */ 121 122static PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen, 123 int fd, 124 CARD16 width, 125 CARD16 height, 126 CARD16 stride, 127 CARD8 depth, 128 CARD8 bpp) 129{ 130 PixmapPtr pixmap; 131 132#ifdef USE_GLAMOR 133 /* Avoid generating a GEM flink name if possible */ 134 if (RADEONPTR(xf86ScreenToScrn(screen))->use_glamor) { 135 pixmap = glamor_pixmap_from_fd(screen, fd, width, height, 136 stride, depth, bpp); 137 if (pixmap) { 138 struct radeon_pixmap *priv = 139 calloc(1, sizeof(struct radeon_pixmap)); 140 141 if (priv) { 142 radeon_set_pixmap_private(pixmap, priv); 143 return pixmap; 144 } 145 146 screen->DestroyPixmap(pixmap); 147 } 148 } 149#endif 150 151 if (depth < 8) 152 return NULL; 153 154 switch (bpp) { 155 case 8: 156 case 16: 157 case 32: 158 break; 159 default: 160 return NULL; 161 } 162 163 pixmap = screen->CreatePixmap(screen, 0, 0, depth, RADEON_CREATE_PIXMAP_DRI2); 164 if (!pixmap) 165 return NULL; 166 167 if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, bpp, stride, 168 NULL)) 169 goto free_pixmap; 170 171 if (screen->SetSharedPixmapBacking(pixmap, (void*)(intptr_t)fd)) 172 return pixmap; 173 174free_pixmap: 175 fbDestroyPixmap(pixmap); 176 return NULL; 177} 178 179static int radeon_dri3_fd_from_pixmap(ScreenPtr screen, 180 PixmapPtr pixmap, 181 CARD16 *stride, 182 CARD32 *size) 183{ 184 struct radeon_bo *bo; 185 int fd; 186 187 bo = radeon_get_pixmap_bo(pixmap); 188 if (!bo) { 189#ifdef USE_GLAMOR 190 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 191 RADEONInfoPtr info = RADEONPTR(scrn); 192 193 if (info->use_glamor) 194 return glamor_fd_from_pixmap(screen, pixmap, stride, size); 195#endif 196 197 exaMoveInPixmap(pixmap); 198 bo = radeon_get_pixmap_bo(pixmap); 199 if (!bo) 200 return -1; 201 } 202 203 if (pixmap->devKind > UINT16_MAX) 204 return -1; 205 206 if (radeon_gem_prime_share_bo(bo, &fd) < 0) 207 return -1; 208 209 *stride = pixmap->devKind; 210 *size = bo->size; 211 return fd; 212} 213 214static dri3_screen_info_rec radeon_dri3_screen_info = { 215#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 216 .version = 1, 217 .open_client = radeon_dri3_open_client, 218#else 219 .version = 0, 220 .open = radeon_dri3_open, 221#endif 222 .pixmap_from_fd = radeon_dri3_pixmap_from_fd, 223 .fd_from_pixmap = radeon_dri3_fd_from_pixmap 224}; 225 226Bool 227radeon_dri3_screen_init(ScreenPtr screen) 228{ 229 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 230 231 if (!dri3_screen_init(screen, &radeon_dri3_screen_info)) { 232 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 233 "dri3_screen_init failed\n"); 234 return FALSE; 235 } 236 237 return TRUE; 238} 239 240#else /* !HAVE_DRI3_H */ 241 242Bool 243radeon_dri3_screen_init(ScreenPtr screen) 244{ 245 xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 246 "Can't initialize DRI3 because dri3.h not available at " 247 "build time\n"); 248 249 return FALSE; 250} 251 252#endif 253