sna_dri3.c revision 42542f5f
1/*
2 * Copyright (c) 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <sys/types.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <errno.h>
33#include <xf86drm.h>
34
35#include "sna.h"
36
37#include <xf86.h>
38#include <dri3.h>
39#include <misyncshm.h>
40#include <misyncstr.h>
41
42static DevPrivateKeyRec sna_sync_fence_private_key;
43struct sna_sync_fence {
44	SyncFenceSetTriggeredFunc set_triggered;
45};
46
47static inline struct sna_sync_fence *sna_sync_fence(SyncFence *fence)
48{
49	return dixLookupPrivate(&fence->devPrivates, &sna_sync_fence_private_key);
50}
51
52static void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv)
53{
54	struct kgem_bo *bo = NULL;
55
56	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber));
57	assert(priv);
58
59	if (priv->pinned & PIN_DRI3) {
60		assert(priv->gpu_bo);
61		assert(priv->pinned & PIN_DRI3);
62		DBG(("%s: flushing prime GPU bo, handle=%ld\n", __FUNCTION__, priv->gpu_bo->handle));
63		if (sna_pixmap_move_to_gpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) {
64			sna_damage_all(&priv->gpu_damage, priv->pixmap);
65			bo = priv->gpu_bo;
66		}
67	} else {
68		assert(priv->cpu_bo);
69		assert(IS_STATIC_PTR(priv->ptr));
70		DBG(("%s: flushing prime CPU bo, handle=%ld\n", __FUNCTION__, priv->cpu_bo->handle));
71		if (sna_pixmap_move_to_cpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT))
72			bo = priv->cpu_bo;
73	}
74
75	if (bo != NULL) {
76		kgem_bo_submit(&sna->kgem, bo);
77		kgem_bo_unclean(&sna->kgem, bo);
78	}
79}
80
81static void
82sna_sync_fence_set_triggered(SyncFence *fence)
83{
84	struct sna *sna = to_sna_from_screen(fence->pScreen);
85	struct sna_sync_fence *sna_fence = sna_sync_fence(fence);
86	DrawablePtr draw = NULL;
87
88	DBG(("%s()\n", __FUNCTION__));
89
90#if 0
91	draw = miSyncShmFenceGetDrawable(fence);
92#endif
93	if (draw) {
94		DBG(("%s: associated pixmap=%ld\n", __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber));
95		sna_sync_flush(sna, sna_pixmap(get_drawable_pixmap(draw)));
96	} else { /* SyncFence are currently per-screen, sigh */
97		struct sna_pixmap *priv;
98
99		DBG(("%s: flushing all DRI3 pixmaps\n", __FUNCTION__));
100		list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list)
101			sna_sync_flush(sna, priv);
102
103		sna_accel_flush(sna);
104	}
105
106	DBG(("%s: complete, chaining up\n", __FUNCTION__));
107	fence->funcs.SetTriggered = sna_fence->set_triggered;
108	sna_fence->set_triggered(fence);
109	sna_fence->set_triggered = fence->funcs.SetTriggered;
110	fence->funcs.SetTriggered = sna_sync_fence_set_triggered;
111}
112
113static void
114sna_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool initially_triggered)
115{
116	struct sna *sna = to_sna_from_screen(screen);
117	SyncScreenFuncsPtr funcs = miSyncGetScreenFuncs(screen);
118
119	DBG(("%s()\n", __FUNCTION__));
120
121	funcs->CreateFence = sna->dri3.create_fence;
122	sna->dri3.create_fence(screen, fence, initially_triggered);
123	sna->dri3.create_fence = funcs->CreateFence;
124	funcs->CreateFence = sna_sync_create_fence;
125
126	sna_sync_fence(fence)->set_triggered = fence->funcs.SetTriggered;
127	fence->funcs.SetTriggered = sna_sync_fence_set_triggered;
128}
129
130static bool
131sna_sync_open(struct sna *sna, ScreenPtr screen)
132{
133	SyncScreenFuncsPtr funcs;
134
135	DBG(("%s()\n", __FUNCTION__));
136
137	if (!miSyncShmScreenInit(screen))
138		return false;
139
140	if (!dixPrivateKeyRegistered(&sna_sync_fence_private_key)) {
141		if (!dixRegisterPrivateKey(&sna_sync_fence_private_key,
142					   PRIVATE_SYNC_FENCE,
143					   sizeof(struct sna_sync_fence)))
144			return false;
145	}
146
147	funcs = miSyncGetScreenFuncs(screen);
148	sna->dri3.create_fence = funcs->CreateFence;
149	funcs->CreateFence = sna_sync_create_fence;
150
151	return true;
152}
153
154static int sna_dri3_open_device(ScreenPtr screen,
155				RRProviderPtr provider,
156				int *out)
157{
158	int fd;
159
160	DBG(("%s()\n", __FUNCTION__));
161	fd = intel_get_client_fd(xf86ScreenToScrn(screen));
162	if (fd < 0)
163		return -fd;
164
165	*out = fd;
166	return Success;
167}
168
169static PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen,
170					 int fd,
171					 CARD16 width,
172					 CARD16 height,
173					 CARD16 stride,
174					 CARD8 depth,
175					 CARD8 bpp)
176{
177	struct sna *sna = to_sna_from_screen(screen);
178	PixmapPtr pixmap;
179	struct sna_pixmap *priv;
180	struct kgem_bo *bo;
181
182	DBG(("%s(fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d)\n",
183	     __FUNCTION__, fd, width, height, stride, depth, bpp));
184	if (width > INT16_MAX || height > INT16_MAX)
185		return NULL;
186
187	if ((uint32_t)width * bpp > (uint32_t)stride * 8)
188		return NULL;
189
190	if (depth < 8)
191		return NULL;
192
193	switch (bpp) {
194	case 8:
195	case 16:
196	case 32:
197		break;
198	default:
199		return NULL;
200	}
201
202	bo = kgem_create_for_prime(&sna->kgem, fd, (uint32_t)stride * height);
203	if (bo == NULL)
204		return NULL;
205
206	/* Check for a duplicate */
207	list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) {
208		int other_stride = 0;
209		if (bo->snoop) {
210			assert(priv->cpu_bo);
211			assert(IS_STATIC_PTR(priv->ptr));
212			if (bo->handle == priv->cpu_bo->handle)
213				other_stride = priv->cpu_bo->pitch;
214		} else  {
215			assert(priv->gpu_bo);
216			assert(priv->pinned & PIN_DRI3);
217			if (bo->handle == priv->gpu_bo->handle)
218				other_stride = priv->gpu_bo->pitch;
219		}
220		if (other_stride) {
221			pixmap = priv->pixmap;
222			DBG(("%s: imported fd matches existing DRI3 pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
223			bo->handle = 0; /* fudge to prevent gem_close */
224			kgem_bo_destroy(&sna->kgem, bo);
225			if (width != pixmap->drawable.width ||
226			    height != pixmap->drawable.height ||
227			    depth != pixmap->drawable.depth ||
228			    bpp != pixmap->drawable.bitsPerPixel ||
229			    stride != other_stride) {
230				DBG(("%s: imported fd mismatches existing DRI3 pixmap (width=%d, height=%d, depth=%d, bpp=%d, stride=%d)\n", __FUNCTION__,
231				     pixmap->drawable.width,
232				     pixmap->drawable.height,
233				     pixmap->drawable.depth,
234				     pixmap->drawable.bitsPerPixel,
235				     other_stride));
236				return NULL;
237			}
238			sna_sync_flush(sna, priv);
239			pixmap->refcnt++;
240			return pixmap;
241		}
242	}
243
244	if (!kgem_check_surface_size(&sna->kgem,
245				     width, height, bpp,
246				     bo->tiling, stride, kgem_bo_size(bo))) {
247		DBG(("%s: client supplied pitch=%d, size=%d too small for %dx%d surface\n",
248		     __FUNCTION__, stride, kgem_bo_size(bo), width, height));
249		goto free_bo;
250	}
251
252	pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
253	if (pixmap == NullPixmap)
254		goto free_bo;
255
256	if (!screen->ModifyPixmapHeader(pixmap, width, height,
257					depth, bpp, stride, NULL))
258		goto free_pixmap;
259
260	priv = sna_pixmap_attach_to_bo(pixmap, bo);
261	if (priv == NULL)
262		goto free_pixmap;
263
264	bo->pitch = stride;
265	priv->stride = stride;
266
267	if (bo->snoop) {
268		assert(priv->cpu_bo == bo);
269		pixmap->devPrivate.ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
270		if (pixmap->devPrivate.ptr == NULL)
271			goto free_pixmap;
272
273		pixmap->devKind = stride;
274		priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
275	} else {
276		assert(priv->gpu_bo == bo);
277		priv->pinned |= PIN_DRI3;
278	}
279	list_add(&priv->cow_list, &sna->dri3.pixmaps);
280
281	return pixmap;
282
283free_pixmap:
284	screen->DestroyPixmap(pixmap);
285free_bo:
286	kgem_bo_destroy(&sna->kgem, bo);
287	return NULL;
288}
289
290static int sna_dri3_fd_from_pixmap(ScreenPtr screen,
291				   PixmapPtr pixmap,
292				   CARD16 *stride,
293				   CARD32 *size)
294{
295	struct sna *sna = to_sna_from_screen(screen);
296	struct sna_pixmap *priv;
297	struct kgem_bo *bo = NULL;
298	int fd;
299
300	DBG(("%s(pixmap=%ld, width=%d, height=%d)\n", __FUNCTION__,
301	     pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height));
302	if (pixmap == sna->front && sna->flags & SNA_TEAR_FREE) {
303		DBG(("%s: DRI3 protocol cannot support TearFree frontbuffers\n", __FUNCTION__));
304		return -1;
305	}
306
307	priv = sna_pixmap(pixmap);
308	if (priv && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) {
309		if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT))
310			bo = priv->cpu_bo;
311	} else {
312		priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE | __MOVE_DRI);
313		if (priv != NULL) {
314			sna_damage_all(&priv->gpu_damage, pixmap);
315			bo = priv->gpu_bo;
316		}
317	}
318	if (bo == NULL) {
319		DBG(("%s: pixmap not supported by GPU\n", __FUNCTION__));
320		return -1;
321	}
322	assert(priv != NULL);
323
324	if (bo->pitch > UINT16_MAX) {
325		DBG(("%s: pixmap pitch (%d) too large for DRI3 protocol\n",
326		     __FUNCTION__, bo->pitch));
327		return -1;
328	}
329
330	fd = kgem_bo_export_to_prime(&sna->kgem, bo);
331	if (fd == -1) {
332		DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle));
333		return -1;
334	}
335
336	if (bo == priv->gpu_bo)
337		priv->pinned |= PIN_DRI3;
338	list_move(&priv->cow_list, &sna->dri3.pixmaps);
339
340	*stride = (priv->pinned & PIN_DRI3) ? priv->gpu_bo->pitch : priv->cpu_bo->pitch;
341	*size = kgem_bo_size((priv->pinned & PIN_DRI3) ? priv->gpu_bo : priv->cpu_bo);
342	DBG(("%s: exporting %s pixmap=%ld, handle=%d, stride=%d, size=%d\n",
343	     __FUNCTION__,
344	     (priv->pinned & PIN_DRI3) ? "GPU" : "CPU", pixmap->drawable.serialNumber,
345	     (priv->pinned & PIN_DRI3) ? priv->gpu_bo->handle : priv->cpu_bo->handle,
346	     *stride, *size));
347	return fd;
348}
349
350static dri3_screen_info_rec sna_dri3_info = {
351	.version = DRI3_SCREEN_INFO_VERSION,
352
353	.open = sna_dri3_open_device,
354	.pixmap_from_fd = sna_dri3_pixmap_from_fd,
355	.fd_from_pixmap = sna_dri3_fd_from_pixmap,
356};
357
358bool sna_dri3_open(struct sna *sna, ScreenPtr screen)
359{
360	DBG(("%s()\n", __FUNCTION__));
361
362	if (!sna_sync_open(sna, screen))
363		return false;
364
365	list_init(&sna->dri3.pixmaps);
366	return dri3_screen_init(screen, &sna_dri3_info);
367}
368
369void sna_dri3_close(struct sna *sna, ScreenPtr screen)
370{
371	SyncScreenFuncsPtr funcs;
372
373	DBG(("%s()\n", __FUNCTION__));
374
375	funcs = miSyncGetScreenFuncs(screen);
376	if (funcs)
377		funcs->CreateFence = sna->dri3.create_fence;
378}
379