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