1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright (c) 2014 Intel Corporation
3428d7b3dSmrg *
4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"),
6428d7b3dSmrg * to deal in the Software without restriction, including without limitation
7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions:
10428d7b3dSmrg *
11428d7b3dSmrg * The above copyright notice and this permission notice (including the next
12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the
13428d7b3dSmrg * Software.
14428d7b3dSmrg *
15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21428d7b3dSmrg * SOFTWARE.
22428d7b3dSmrg *
23428d7b3dSmrg */
24428d7b3dSmrg
25428d7b3dSmrg#ifdef HAVE_CONFIG_H
26428d7b3dSmrg#include "config.h"
27428d7b3dSmrg#endif
28428d7b3dSmrg
29428d7b3dSmrg#include <sys/types.h>
30428d7b3dSmrg#include <fcntl.h>
31428d7b3dSmrg#include <unistd.h>
32428d7b3dSmrg#include <errno.h>
33428d7b3dSmrg#include <xf86drm.h>
34428d7b3dSmrg
35428d7b3dSmrg#include "sna.h"
36428d7b3dSmrg
37428d7b3dSmrg#include <xf86.h>
38428d7b3dSmrg#include <dri3.h>
39428d7b3dSmrg#include <misyncshm.h>
40428d7b3dSmrg#include <misyncstr.h>
41428d7b3dSmrg
42428d7b3dSmrgstatic DevPrivateKeyRec sna_sync_fence_private_key;
43428d7b3dSmrgstruct sna_sync_fence {
44428d7b3dSmrg	SyncFenceSetTriggeredFunc set_triggered;
45428d7b3dSmrg};
46428d7b3dSmrg
47428d7b3dSmrgstatic inline struct sna_sync_fence *sna_sync_fence(SyncFence *fence)
48428d7b3dSmrg{
49428d7b3dSmrg	return dixLookupPrivate(&fence->devPrivates, &sna_sync_fence_private_key);
50428d7b3dSmrg}
51428d7b3dSmrg
52428d7b3dSmrgstatic inline void mark_dri3_pixmap(struct sna *sna, struct sna_pixmap *priv, struct kgem_bo *bo)
53428d7b3dSmrg{
54428d7b3dSmrg	bo->flush = true;
55428d7b3dSmrg	if (bo->exec)
56428d7b3dSmrg		sna->kgem.flush = 1;
57428d7b3dSmrg	if (bo == priv->gpu_bo)
58428d7b3dSmrg		priv->flush |= 3;
59428d7b3dSmrg	else
60428d7b3dSmrg		priv->shm = true;
61428d7b3dSmrg
62428d7b3dSmrg	sna_accel_watch_flush(sna, 1);
63428d7b3dSmrg}
64428d7b3dSmrg
65428d7b3dSmrgstatic void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv)
66428d7b3dSmrg{
67428d7b3dSmrg	struct kgem_bo *bo = NULL;
68428d7b3dSmrg
69428d7b3dSmrg	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber));
70428d7b3dSmrg	assert(priv);
71428d7b3dSmrg
72428d7b3dSmrg	if (priv->pinned & PIN_DRI3) {
73428d7b3dSmrg		assert(priv->gpu_bo);
74428d7b3dSmrg		assert(priv->pinned & PIN_DRI3);
75428d7b3dSmrg		DBG(("%s: flushing prime GPU bo, handle=%ld\n", __FUNCTION__, priv->gpu_bo->handle));
76428d7b3dSmrg		if (sna_pixmap_move_to_gpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) {
77428d7b3dSmrg			sna_damage_all(&priv->gpu_damage, priv->pixmap);
78428d7b3dSmrg			bo = priv->gpu_bo;
79428d7b3dSmrg		}
80428d7b3dSmrg	} else {
81428d7b3dSmrg		assert(priv->cpu_bo);
82428d7b3dSmrg		assert(IS_STATIC_PTR(priv->ptr));
83428d7b3dSmrg		DBG(("%s: flushing prime CPU bo, handle=%ld\n", __FUNCTION__, priv->cpu_bo->handle));
84428d7b3dSmrg		if (sna_pixmap_move_to_cpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT))
85428d7b3dSmrg			bo = priv->cpu_bo;
86428d7b3dSmrg	}
87428d7b3dSmrg
88428d7b3dSmrg	if (bo != NULL) {
89428d7b3dSmrg		kgem_bo_submit(&sna->kgem, bo);
90428d7b3dSmrg		kgem_bo_unclean(&sna->kgem, bo);
91428d7b3dSmrg	}
92428d7b3dSmrg}
93428d7b3dSmrg
94428d7b3dSmrgstatic void
95428d7b3dSmrgsna_sync_fence_set_triggered(SyncFence *fence)
96428d7b3dSmrg{
97428d7b3dSmrg	struct sna *sna = to_sna_from_screen(fence->pScreen);
98428d7b3dSmrg	struct sna_sync_fence *sna_fence = sna_sync_fence(fence);
99428d7b3dSmrg
100428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
101428d7b3dSmrg	sna_accel_flush(sna);
102428d7b3dSmrg
103428d7b3dSmrg	fence->funcs.SetTriggered = sna_fence->set_triggered;
104428d7b3dSmrg	sna_fence->set_triggered(fence);
105428d7b3dSmrg	sna_fence->set_triggered = fence->funcs.SetTriggered;
106428d7b3dSmrg	fence->funcs.SetTriggered = sna_sync_fence_set_triggered;
107428d7b3dSmrg}
108428d7b3dSmrg
109428d7b3dSmrgstatic void
110428d7b3dSmrgsna_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool initially_triggered)
111428d7b3dSmrg{
112428d7b3dSmrg	struct sna *sna = to_sna_from_screen(screen);
113428d7b3dSmrg	SyncScreenFuncsPtr funcs = miSyncGetScreenFuncs(screen);
114428d7b3dSmrg
115428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
116428d7b3dSmrg
117428d7b3dSmrg	funcs->CreateFence = sna->dri3.create_fence;
118428d7b3dSmrg	sna->dri3.create_fence(screen, fence, initially_triggered);
119428d7b3dSmrg	sna->dri3.create_fence = funcs->CreateFence;
120428d7b3dSmrg	funcs->CreateFence = sna_sync_create_fence;
121428d7b3dSmrg
122428d7b3dSmrg	sna_sync_fence(fence)->set_triggered = fence->funcs.SetTriggered;
123428d7b3dSmrg	fence->funcs.SetTriggered = sna_sync_fence_set_triggered;
124428d7b3dSmrg}
125428d7b3dSmrg
126428d7b3dSmrgstatic bool
127428d7b3dSmrgsna_sync_open(struct sna *sna, ScreenPtr screen)
128428d7b3dSmrg{
129428d7b3dSmrg	SyncScreenFuncsPtr funcs;
130428d7b3dSmrg
131428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
132428d7b3dSmrg
133428d7b3dSmrg	if (!miSyncShmScreenInit(screen))
134428d7b3dSmrg		return false;
135428d7b3dSmrg
136428d7b3dSmrg	if (!dixPrivateKeyRegistered(&sna_sync_fence_private_key)) {
137428d7b3dSmrg		if (!dixRegisterPrivateKey(&sna_sync_fence_private_key,
138428d7b3dSmrg					   PRIVATE_SYNC_FENCE,
139428d7b3dSmrg					   sizeof(struct sna_sync_fence)))
140428d7b3dSmrg			return false;
141428d7b3dSmrg	}
142428d7b3dSmrg
143428d7b3dSmrg	funcs = miSyncGetScreenFuncs(screen);
144428d7b3dSmrg	sna->dri3.create_fence = funcs->CreateFence;
145428d7b3dSmrg	funcs->CreateFence = sna_sync_create_fence;
146428d7b3dSmrg
147428d7b3dSmrg	return true;
148428d7b3dSmrg}
149428d7b3dSmrg
150428d7b3dSmrgstatic int sna_dri3_open_device(ScreenPtr screen,
151428d7b3dSmrg				RRProviderPtr provider,
152428d7b3dSmrg				int *out)
153428d7b3dSmrg{
154428d7b3dSmrg	int fd;
155428d7b3dSmrg
156428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
157428d7b3dSmrg	fd = intel_get_client_fd(to_sna_from_screen(screen)->dev);
158428d7b3dSmrg	if (fd < 0)
159428d7b3dSmrg		return -fd;
160428d7b3dSmrg
161428d7b3dSmrg	*out = fd;
162428d7b3dSmrg	return Success;
163428d7b3dSmrg}
164428d7b3dSmrg
165428d7b3dSmrgstatic PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen,
166428d7b3dSmrg					 int fd,
167428d7b3dSmrg					 CARD16 width,
168428d7b3dSmrg					 CARD16 height,
169428d7b3dSmrg					 CARD16 stride,
170428d7b3dSmrg					 CARD8 depth,
171428d7b3dSmrg					 CARD8 bpp)
172428d7b3dSmrg{
173428d7b3dSmrg	struct sna *sna = to_sna_from_screen(screen);
174428d7b3dSmrg	PixmapPtr pixmap;
175428d7b3dSmrg	struct sna_pixmap *priv;
176428d7b3dSmrg	struct kgem_bo *bo;
177428d7b3dSmrg
178428d7b3dSmrg	DBG(("%s(fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d)\n",
179428d7b3dSmrg	     __FUNCTION__, fd, width, height, stride, depth, bpp));
180428d7b3dSmrg	if (width > INT16_MAX || height > INT16_MAX)
181428d7b3dSmrg		return NULL;
182428d7b3dSmrg
183428d7b3dSmrg	if ((uint32_t)width * bpp > (uint32_t)stride * 8)
184428d7b3dSmrg		return NULL;
185428d7b3dSmrg
186428d7b3dSmrg	if (depth < 8)
187428d7b3dSmrg		return NULL;
188428d7b3dSmrg
189428d7b3dSmrg	switch (bpp) {
190428d7b3dSmrg	case 8:
191428d7b3dSmrg	case 16:
192428d7b3dSmrg	case 32:
193428d7b3dSmrg		break;
194428d7b3dSmrg	default:
195428d7b3dSmrg		return NULL;
196428d7b3dSmrg	}
197428d7b3dSmrg
198428d7b3dSmrg	bo = kgem_create_for_prime(&sna->kgem, fd, (uint32_t)stride * height);
199428d7b3dSmrg	if (bo == NULL)
200428d7b3dSmrg		return NULL;
201428d7b3dSmrg
202428d7b3dSmrg	/* Check for a duplicate */
203428d7b3dSmrg	list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) {
204428d7b3dSmrg		int other_stride = 0;
205428d7b3dSmrg		if (bo->snoop) {
206428d7b3dSmrg			assert(priv->cpu_bo);
207428d7b3dSmrg			assert(IS_STATIC_PTR(priv->ptr));
208428d7b3dSmrg			if (bo->handle == priv->cpu_bo->handle)
209428d7b3dSmrg				other_stride = priv->cpu_bo->pitch;
210428d7b3dSmrg		} else  {
211428d7b3dSmrg			assert(priv->gpu_bo);
212428d7b3dSmrg			assert(priv->pinned & PIN_DRI3);
213428d7b3dSmrg			if (bo->handle == priv->gpu_bo->handle)
214428d7b3dSmrg				other_stride = priv->gpu_bo->pitch;
215428d7b3dSmrg		}
216428d7b3dSmrg		if (other_stride) {
217428d7b3dSmrg			pixmap = priv->pixmap;
218428d7b3dSmrg			DBG(("%s: imported fd matches existing DRI3 pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
219428d7b3dSmrg			bo->handle = 0; /* fudge to prevent gem_close */
220428d7b3dSmrg			kgem_bo_destroy(&sna->kgem, bo);
221428d7b3dSmrg			if (width != pixmap->drawable.width ||
222428d7b3dSmrg			    height != pixmap->drawable.height ||
223428d7b3dSmrg			    depth != pixmap->drawable.depth ||
224428d7b3dSmrg			    bpp != pixmap->drawable.bitsPerPixel ||
225428d7b3dSmrg			    stride != other_stride) {
226428d7b3dSmrg				DBG(("%s: imported fd mismatches existing DRI3 pixmap (width=%d, height=%d, depth=%d, bpp=%d, stride=%d)\n", __FUNCTION__,
227428d7b3dSmrg				     pixmap->drawable.width,
228428d7b3dSmrg				     pixmap->drawable.height,
229428d7b3dSmrg				     pixmap->drawable.depth,
230428d7b3dSmrg				     pixmap->drawable.bitsPerPixel,
231428d7b3dSmrg				     other_stride));
232428d7b3dSmrg				return NULL;
233428d7b3dSmrg			}
234428d7b3dSmrg			sna_sync_flush(sna, priv);
235428d7b3dSmrg			pixmap->refcnt++;
236428d7b3dSmrg			return pixmap;
237428d7b3dSmrg		}
238428d7b3dSmrg	}
239428d7b3dSmrg
240428d7b3dSmrg	if (!kgem_check_surface_size(&sna->kgem,
241428d7b3dSmrg				     width, height, bpp,
242428d7b3dSmrg				     bo->tiling, stride, kgem_bo_size(bo))) {
243428d7b3dSmrg		DBG(("%s: client supplied pitch=%d, size=%d too small for %dx%d surface\n",
244428d7b3dSmrg		     __FUNCTION__, stride, kgem_bo_size(bo), width, height));
245428d7b3dSmrg		goto free_bo;
246428d7b3dSmrg	}
247428d7b3dSmrg
248428d7b3dSmrg	pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
249428d7b3dSmrg	if (pixmap == NullPixmap)
250428d7b3dSmrg		goto free_bo;
251428d7b3dSmrg
252428d7b3dSmrg	if (!screen->ModifyPixmapHeader(pixmap, width, height,
253428d7b3dSmrg					depth, bpp, stride, NULL))
254428d7b3dSmrg		goto free_pixmap;
255428d7b3dSmrg
256428d7b3dSmrg	priv = sna_pixmap_attach_to_bo(pixmap, bo);
257428d7b3dSmrg	if (priv == NULL)
258428d7b3dSmrg		goto free_pixmap;
259428d7b3dSmrg
260428d7b3dSmrg	bo->pitch = stride;
261428d7b3dSmrg	priv->stride = stride;
262428d7b3dSmrg
263428d7b3dSmrg	if (bo->snoop) {
264428d7b3dSmrg		assert(priv->cpu_bo == bo);
265428d7b3dSmrg		pixmap->devPrivate.ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
266428d7b3dSmrg		if (pixmap->devPrivate.ptr == NULL)
267428d7b3dSmrg			goto free_pixmap;
268428d7b3dSmrg
269428d7b3dSmrg		pixmap->devKind = stride;
270428d7b3dSmrg		priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
271428d7b3dSmrg	} else {
272428d7b3dSmrg		assert(priv->gpu_bo == bo);
273428d7b3dSmrg		priv->pinned |= PIN_DRI3;
274428d7b3dSmrg	}
275428d7b3dSmrg	list_add(&priv->cow_list, &sna->dri3.pixmaps);
276428d7b3dSmrg
277428d7b3dSmrg	mark_dri3_pixmap(sna, priv, bo);
278428d7b3dSmrg
279428d7b3dSmrg	return pixmap;
280428d7b3dSmrg
281428d7b3dSmrgfree_pixmap:
282428d7b3dSmrg	screen->DestroyPixmap(pixmap);
283428d7b3dSmrgfree_bo:
284428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, bo);
285428d7b3dSmrg	return NULL;
286428d7b3dSmrg}
287428d7b3dSmrg
288428d7b3dSmrgstatic int sna_dri3_fd_from_pixmap(ScreenPtr screen,
289428d7b3dSmrg				   PixmapPtr pixmap,
290428d7b3dSmrg				   CARD16 *stride,
291428d7b3dSmrg				   CARD32 *size)
292428d7b3dSmrg{
293428d7b3dSmrg	struct sna *sna = to_sna_from_screen(screen);
294428d7b3dSmrg	struct sna_pixmap *priv;
295428d7b3dSmrg	struct kgem_bo *bo = NULL;
296428d7b3dSmrg	int fd;
297428d7b3dSmrg
298428d7b3dSmrg	DBG(("%s(pixmap=%ld, width=%d, height=%d)\n", __FUNCTION__,
299428d7b3dSmrg	     pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height));
300428d7b3dSmrg	if (pixmap == sna->front && sna->flags & SNA_TEAR_FREE) {
301428d7b3dSmrg		DBG(("%s: DRI3 protocol cannot support TearFree frontbuffers\n", __FUNCTION__));
302428d7b3dSmrg		return -1;
303428d7b3dSmrg	}
304428d7b3dSmrg
305428d7b3dSmrg	priv = sna_pixmap(pixmap);
306428d7b3dSmrg	if (priv && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) {
307428d7b3dSmrg		if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT))
308428d7b3dSmrg			bo = priv->cpu_bo;
309428d7b3dSmrg	} else {
310428d7b3dSmrg		priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE | __MOVE_DRI);
311428d7b3dSmrg		if (priv != NULL) {
312428d7b3dSmrg			sna_damage_all(&priv->gpu_damage, pixmap);
313428d7b3dSmrg			bo = priv->gpu_bo;
314428d7b3dSmrg		}
315428d7b3dSmrg	}
316428d7b3dSmrg	if (bo == NULL) {
317428d7b3dSmrg		DBG(("%s: pixmap not supported by GPU\n", __FUNCTION__));
318428d7b3dSmrg		return -1;
319428d7b3dSmrg	}
320428d7b3dSmrg	assert(priv != NULL);
321428d7b3dSmrg
322428d7b3dSmrg	if (bo->pitch > UINT16_MAX) {
323428d7b3dSmrg		DBG(("%s: pixmap pitch (%d) too large for DRI3 protocol\n",
324428d7b3dSmrg		     __FUNCTION__, bo->pitch));
325428d7b3dSmrg		return -1;
326428d7b3dSmrg	}
327428d7b3dSmrg
328428d7b3dSmrg	fd = kgem_bo_export_to_prime(&sna->kgem, bo);
329428d7b3dSmrg	if (fd == -1) {
330428d7b3dSmrg		DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle));
331428d7b3dSmrg		return -1;
332428d7b3dSmrg	}
333428d7b3dSmrg
334428d7b3dSmrg	if (bo == priv->gpu_bo)
335428d7b3dSmrg		priv->pinned |= PIN_DRI3;
336428d7b3dSmrg	list_move(&priv->cow_list, &sna->dri3.pixmaps);
337428d7b3dSmrg
338428d7b3dSmrg	mark_dri3_pixmap(sna, priv, bo);
339428d7b3dSmrg
340428d7b3dSmrg	*stride = (priv->pinned & PIN_DRI3) ? priv->gpu_bo->pitch : priv->cpu_bo->pitch;
341428d7b3dSmrg	*size = kgem_bo_size((priv->pinned & PIN_DRI3) ? priv->gpu_bo : priv->cpu_bo);
342428d7b3dSmrg	DBG(("%s: exporting %s pixmap=%ld, handle=%d, stride=%d, size=%d\n",
343428d7b3dSmrg	     __FUNCTION__,
344428d7b3dSmrg	     (priv->pinned & PIN_DRI3) ? "GPU" : "CPU", pixmap->drawable.serialNumber,
345428d7b3dSmrg	     (priv->pinned & PIN_DRI3) ? priv->gpu_bo->handle : priv->cpu_bo->handle,
346428d7b3dSmrg	     *stride, *size));
347428d7b3dSmrg	return fd;
348428d7b3dSmrg}
349428d7b3dSmrg
350428d7b3dSmrgstatic dri3_screen_info_rec sna_dri3_info = {
351428d7b3dSmrg	.version = DRI3_SCREEN_INFO_VERSION,
352428d7b3dSmrg
353428d7b3dSmrg	.open = sna_dri3_open_device,
354428d7b3dSmrg	.pixmap_from_fd = sna_dri3_pixmap_from_fd,
355428d7b3dSmrg	.fd_from_pixmap = sna_dri3_fd_from_pixmap,
356428d7b3dSmrg};
357428d7b3dSmrg
358428d7b3dSmrgbool sna_dri3_open(struct sna *sna, ScreenPtr screen)
359428d7b3dSmrg{
360428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
361428d7b3dSmrg
362428d7b3dSmrg	if (!sna_sync_open(sna, screen))
363428d7b3dSmrg		return false;
364428d7b3dSmrg
365428d7b3dSmrg	list_init(&sna->dri3.pixmaps);
366428d7b3dSmrg	return dri3_screen_init(screen, &sna_dri3_info);
367428d7b3dSmrg}
368428d7b3dSmrg
369428d7b3dSmrgvoid sna_dri3_close(struct sna *sna, ScreenPtr screen)
370428d7b3dSmrg{
371428d7b3dSmrg	SyncScreenFuncsPtr funcs;
372428d7b3dSmrg
373428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
374428d7b3dSmrg
375428d7b3dSmrg	funcs = miSyncGetScreenFuncs(screen);
376428d7b3dSmrg	if (funcs)
377428d7b3dSmrg		funcs->CreateFence = sna->dri3.create_fence;
378428d7b3dSmrg}
379