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