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