amdgpu_dri3.c revision 35d5b7c7
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); 17135d5b7c7Smrg pixmap->usage_hint |= AMDGPU_CREATE_PIXMAP_DRI2; 172504d986fSmrg return pixmap; 173504d986fSmrg } 174504d986fSmrg 175504d986fSmrg screen->DestroyPixmap(pixmap); 176504d986fSmrg return NULL; 177d6c0b56eSmrg } 178d6c0b56eSmrg } 179d6c0b56eSmrg#endif 180d6c0b56eSmrg 181d6c0b56eSmrg if (depth < 8) 182d6c0b56eSmrg return NULL; 183d6c0b56eSmrg 184d6c0b56eSmrg switch (bpp) { 185d6c0b56eSmrg case 8: 186d6c0b56eSmrg case 16: 187d6c0b56eSmrg case 32: 188d6c0b56eSmrg break; 189d6c0b56eSmrg default: 190d6c0b56eSmrg return NULL; 191d6c0b56eSmrg } 192d6c0b56eSmrg 193d6c0b56eSmrg pixmap = screen->CreatePixmap(screen, 0, 0, depth, 194d6c0b56eSmrg AMDGPU_CREATE_PIXMAP_DRI2); 195d6c0b56eSmrg if (!pixmap) 196d6c0b56eSmrg return NULL; 197d6c0b56eSmrg 198d6c0b56eSmrg if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, bpp, stride, 199d6c0b56eSmrg NULL)) 200d6c0b56eSmrg goto free_pixmap; 201d6c0b56eSmrg 202d6c0b56eSmrg if (screen->SetSharedPixmapBacking(pixmap, (void*)(intptr_t)fd)) 203d6c0b56eSmrg return pixmap; 204d6c0b56eSmrg 205d6c0b56eSmrgfree_pixmap: 206d6c0b56eSmrg fbDestroyPixmap(pixmap); 207d6c0b56eSmrg return NULL; 208d6c0b56eSmrg} 209d6c0b56eSmrg 210d6c0b56eSmrgstatic int amdgpu_dri3_fd_from_pixmap(ScreenPtr screen, 211d6c0b56eSmrg PixmapPtr pixmap, 212d6c0b56eSmrg CARD16 *stride, 213d6c0b56eSmrg CARD32 *size) 214d6c0b56eSmrg{ 215d6c0b56eSmrg struct amdgpu_buffer *bo; 216d6c0b56eSmrg struct amdgpu_bo_info bo_info; 217d6c0b56eSmrg uint32_t fd; 218d6c0b56eSmrg#ifdef USE_GLAMOR 219d6c0b56eSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 220d6c0b56eSmrg AMDGPUInfoPtr info = AMDGPUPTR(scrn); 221d6c0b56eSmrg 222d6c0b56eSmrg if (info->use_glamor) 223d6c0b56eSmrg return glamor_fd_from_pixmap(screen, pixmap, stride, size); 224d6c0b56eSmrg#endif 225d6c0b56eSmrg 226d6c0b56eSmrg bo = amdgpu_get_pixmap_bo(pixmap); 227d6c0b56eSmrg if (!bo) 228d6c0b56eSmrg return -1; 229d6c0b56eSmrg 230d6c0b56eSmrg if (pixmap->devKind > UINT16_MAX) 231d6c0b56eSmrg return -1; 232d6c0b56eSmrg 233d6c0b56eSmrg if (amdgpu_bo_query_info(bo->bo.amdgpu, &bo_info) != 0) 234d6c0b56eSmrg return -1; 235d6c0b56eSmrg 236d6c0b56eSmrg if (amdgpu_bo_export(bo->bo.amdgpu, amdgpu_bo_handle_type_dma_buf_fd, 237d6c0b56eSmrg &fd) != 0) 238d6c0b56eSmrg return -1; 239d6c0b56eSmrg 240d6c0b56eSmrg *stride = pixmap->devKind; 241d6c0b56eSmrg *size = bo_info.alloc_size; 242d6c0b56eSmrg return fd; 243d6c0b56eSmrg} 244d6c0b56eSmrg 245d6c0b56eSmrgstatic dri3_screen_info_rec amdgpu_dri3_screen_info = { 246d6c0b56eSmrg#if DRI3_SCREEN_INFO_VERSION >= 1 && XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,18,99,1,0) 247d6c0b56eSmrg .version = 1, 248d6c0b56eSmrg .open_client = amdgpu_dri3_open_client, 249d6c0b56eSmrg#else 250d6c0b56eSmrg .version = 0, 251d6c0b56eSmrg .open = amdgpu_dri3_open, 252d6c0b56eSmrg#endif 253d6c0b56eSmrg .pixmap_from_fd = amdgpu_dri3_pixmap_from_fd, 254d6c0b56eSmrg .fd_from_pixmap = amdgpu_dri3_fd_from_pixmap 255d6c0b56eSmrg}; 256d6c0b56eSmrg 257d6c0b56eSmrgBool 258d6c0b56eSmrgamdgpu_dri3_screen_init(ScreenPtr screen) 259d6c0b56eSmrg{ 260d6c0b56eSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 26111bf0794Smrg AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 26211bf0794Smrg 26311bf0794Smrg pAMDGPUEnt->render_node = drmGetRenderDeviceNameFromFd(pAMDGPUEnt->fd); 264d6c0b56eSmrg 265d6c0b56eSmrg if (!dri3_screen_init(screen, &amdgpu_dri3_screen_info)) { 266d6c0b56eSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 267d6c0b56eSmrg "dri3_screen_init failed\n"); 268d6c0b56eSmrg return FALSE; 269d6c0b56eSmrg } 270d6c0b56eSmrg 271d6c0b56eSmrg return TRUE; 272d6c0b56eSmrg} 273d6c0b56eSmrg 274d6c0b56eSmrg#else /* !HAVE_DRI3_H */ 275d6c0b56eSmrg 276d6c0b56eSmrgBool 277d6c0b56eSmrgamdgpu_dri3_screen_init(ScreenPtr screen) 278d6c0b56eSmrg{ 279d6c0b56eSmrg xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, 280d6c0b56eSmrg "Can't initialize DRI3 because dri3.h not available at " 281d6c0b56eSmrg "build time\n"); 282d6c0b56eSmrg 283d6c0b56eSmrg return FALSE; 284d6c0b56eSmrg} 285d6c0b56eSmrg 286d6c0b56eSmrg#endif 287