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