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