142542f5fSchristos/*
242542f5fSchristos * Copyright (c) 2014 Intel Corporation
342542f5fSchristos *
442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a
542542f5fSchristos * copy of this software and associated documentation files (the "Software"),
642542f5fSchristos * to deal in the Software without restriction, including without limitation
742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense,
842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the
942542f5fSchristos * Software is furnished to do so, subject to the following conditions:
1042542f5fSchristos *
1142542f5fSchristos * The above copyright notice and this permission notice (including the next
1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the
1342542f5fSchristos * Software.
1442542f5fSchristos *
1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2042542f5fSchristos * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2142542f5fSchristos * SOFTWARE.
2242542f5fSchristos *
2342542f5fSchristos */
2442542f5fSchristos
2542542f5fSchristos#ifdef HAVE_CONFIG_H
2642542f5fSchristos#include "config.h"
2742542f5fSchristos#endif
2842542f5fSchristos
2942542f5fSchristos#include <sys/types.h>
3042542f5fSchristos#include <fcntl.h>
3142542f5fSchristos#include <unistd.h>
3242542f5fSchristos#include <errno.h>
3342542f5fSchristos#include <xf86drm.h>
3442542f5fSchristos
3542542f5fSchristos#include "sna.h"
3642542f5fSchristos
3742542f5fSchristos#include <xf86.h>
3842542f5fSchristos#include <dri3.h>
3942542f5fSchristos#include <misyncshm.h>
4042542f5fSchristos#include <misyncstr.h>
4142542f5fSchristos
4242542f5fSchristosstatic DevPrivateKeyRec sna_sync_fence_private_key;
4342542f5fSchristosstruct sna_sync_fence {
4442542f5fSchristos	SyncFenceSetTriggeredFunc set_triggered;
4542542f5fSchristos};
4642542f5fSchristos
4742542f5fSchristosstatic inline struct sna_sync_fence *sna_sync_fence(SyncFence *fence)
4842542f5fSchristos{
4942542f5fSchristos	return dixLookupPrivate(&fence->devPrivates, &sna_sync_fence_private_key);
5042542f5fSchristos}
5142542f5fSchristos
5213496ba1Ssnjstatic inline void mark_dri3_pixmap(struct sna *sna, struct sna_pixmap *priv, struct kgem_bo *bo)
5313496ba1Ssnj{
5413496ba1Ssnj	bo->flush = true;
5513496ba1Ssnj	if (bo->exec)
5613496ba1Ssnj		sna->kgem.flush = 1;
5713496ba1Ssnj	if (bo == priv->gpu_bo)
58fe8aea9eSmrg		priv->flush |= FLUSH_READ | FLUSH_WRITE;
5913496ba1Ssnj	else
6013496ba1Ssnj		priv->shm = true;
6113496ba1Ssnj
62fe8aea9eSmrg	sna_watch_flush(sna, 1);
63fe8aea9eSmrg
64fe8aea9eSmrg	kgem_bo_submit(&sna->kgem, bo);
65fe8aea9eSmrg	kgem_bo_unclean(&sna->kgem, bo);
6613496ba1Ssnj}
6713496ba1Ssnj
6842542f5fSchristosstatic void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv)
6942542f5fSchristos{
7042542f5fSchristos	struct kgem_bo *bo = NULL;
7142542f5fSchristos
7242542f5fSchristos	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber));
7342542f5fSchristos	assert(priv);
7442542f5fSchristos
7542542f5fSchristos	if (priv->pinned & PIN_DRI3) {
7642542f5fSchristos		assert(priv->gpu_bo);
7742542f5fSchristos		assert(priv->pinned & PIN_DRI3);
7842542f5fSchristos		DBG(("%s: flushing prime GPU bo, handle=%ld\n", __FUNCTION__, priv->gpu_bo->handle));
7942542f5fSchristos		if (sna_pixmap_move_to_gpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) {
8042542f5fSchristos			sna_damage_all(&priv->gpu_damage, priv->pixmap);
8142542f5fSchristos			bo = priv->gpu_bo;
8242542f5fSchristos		}
8342542f5fSchristos	} else {
8442542f5fSchristos		assert(priv->cpu_bo);
8542542f5fSchristos		assert(IS_STATIC_PTR(priv->ptr));
8642542f5fSchristos		DBG(("%s: flushing prime CPU bo, handle=%ld\n", __FUNCTION__, priv->cpu_bo->handle));
8742542f5fSchristos		if (sna_pixmap_move_to_cpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT))
8842542f5fSchristos			bo = priv->cpu_bo;
8942542f5fSchristos	}
9042542f5fSchristos
9142542f5fSchristos	if (bo != NULL) {
9242542f5fSchristos		kgem_bo_submit(&sna->kgem, bo);
9342542f5fSchristos		kgem_bo_unclean(&sna->kgem, bo);
9442542f5fSchristos	}
9542542f5fSchristos}
9642542f5fSchristos
9742542f5fSchristosstatic void
9842542f5fSchristossna_sync_fence_set_triggered(SyncFence *fence)
9942542f5fSchristos{
10042542f5fSchristos	struct sna *sna = to_sna_from_screen(fence->pScreen);
10142542f5fSchristos	struct sna_sync_fence *sna_fence = sna_sync_fence(fence);
10242542f5fSchristos
10342542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
10413496ba1Ssnj	sna_accel_flush(sna);
10542542f5fSchristos
10642542f5fSchristos	fence->funcs.SetTriggered = sna_fence->set_triggered;
10742542f5fSchristos	sna_fence->set_triggered(fence);
10842542f5fSchristos	sna_fence->set_triggered = fence->funcs.SetTriggered;
10942542f5fSchristos	fence->funcs.SetTriggered = sna_sync_fence_set_triggered;
11042542f5fSchristos}
11142542f5fSchristos
11242542f5fSchristosstatic void
11342542f5fSchristossna_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool initially_triggered)
11442542f5fSchristos{
11542542f5fSchristos	struct sna *sna = to_sna_from_screen(screen);
11642542f5fSchristos	SyncScreenFuncsPtr funcs = miSyncGetScreenFuncs(screen);
11742542f5fSchristos
11842542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
11942542f5fSchristos
12042542f5fSchristos	funcs->CreateFence = sna->dri3.create_fence;
12142542f5fSchristos	sna->dri3.create_fence(screen, fence, initially_triggered);
12242542f5fSchristos	sna->dri3.create_fence = funcs->CreateFence;
12342542f5fSchristos	funcs->CreateFence = sna_sync_create_fence;
12442542f5fSchristos
12542542f5fSchristos	sna_sync_fence(fence)->set_triggered = fence->funcs.SetTriggered;
12642542f5fSchristos	fence->funcs.SetTriggered = sna_sync_fence_set_triggered;
12742542f5fSchristos}
12842542f5fSchristos
12942542f5fSchristosstatic bool
13042542f5fSchristossna_sync_open(struct sna *sna, ScreenPtr screen)
13142542f5fSchristos{
13242542f5fSchristos	SyncScreenFuncsPtr funcs;
13342542f5fSchristos
13442542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
13542542f5fSchristos
13642542f5fSchristos	if (!miSyncShmScreenInit(screen))
13742542f5fSchristos		return false;
13842542f5fSchristos
13942542f5fSchristos	if (!dixPrivateKeyRegistered(&sna_sync_fence_private_key)) {
14042542f5fSchristos		if (!dixRegisterPrivateKey(&sna_sync_fence_private_key,
14142542f5fSchristos					   PRIVATE_SYNC_FENCE,
14242542f5fSchristos					   sizeof(struct sna_sync_fence)))
14342542f5fSchristos			return false;
14442542f5fSchristos	}
14542542f5fSchristos
14642542f5fSchristos	funcs = miSyncGetScreenFuncs(screen);
14742542f5fSchristos	sna->dri3.create_fence = funcs->CreateFence;
14842542f5fSchristos	funcs->CreateFence = sna_sync_create_fence;
14942542f5fSchristos
15042542f5fSchristos	return true;
15142542f5fSchristos}
15242542f5fSchristos
15342542f5fSchristosstatic int sna_dri3_open_device(ScreenPtr screen,
15442542f5fSchristos				RRProviderPtr provider,
15542542f5fSchristos				int *out)
15642542f5fSchristos{
15742542f5fSchristos	int fd;
15842542f5fSchristos
15942542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
16013496ba1Ssnj	fd = intel_get_client_fd(to_sna_from_screen(screen)->dev);
16142542f5fSchristos	if (fd < 0)
16242542f5fSchristos		return -fd;
16342542f5fSchristos
16442542f5fSchristos	*out = fd;
16542542f5fSchristos	return Success;
16642542f5fSchristos}
16742542f5fSchristos
16842542f5fSchristosstatic PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen,
16942542f5fSchristos					 int fd,
17042542f5fSchristos					 CARD16 width,
17142542f5fSchristos					 CARD16 height,
17242542f5fSchristos					 CARD16 stride,
17342542f5fSchristos					 CARD8 depth,
17442542f5fSchristos					 CARD8 bpp)
17542542f5fSchristos{
17642542f5fSchristos	struct sna *sna = to_sna_from_screen(screen);
17742542f5fSchristos	PixmapPtr pixmap;
17842542f5fSchristos	struct sna_pixmap *priv;
17942542f5fSchristos	struct kgem_bo *bo;
18042542f5fSchristos
18142542f5fSchristos	DBG(("%s(fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d)\n",
18242542f5fSchristos	     __FUNCTION__, fd, width, height, stride, depth, bpp));
18342542f5fSchristos	if (width > INT16_MAX || height > INT16_MAX)
18442542f5fSchristos		return NULL;
18542542f5fSchristos
18642542f5fSchristos	if ((uint32_t)width * bpp > (uint32_t)stride * 8)
18742542f5fSchristos		return NULL;
18842542f5fSchristos
18942542f5fSchristos	if (depth < 8)
19042542f5fSchristos		return NULL;
19142542f5fSchristos
19242542f5fSchristos	switch (bpp) {
19342542f5fSchristos	case 8:
19442542f5fSchristos	case 16:
19542542f5fSchristos	case 32:
19642542f5fSchristos		break;
19742542f5fSchristos	default:
19842542f5fSchristos		return NULL;
19942542f5fSchristos	}
20042542f5fSchristos
20142542f5fSchristos	bo = kgem_create_for_prime(&sna->kgem, fd, (uint32_t)stride * height);
20242542f5fSchristos	if (bo == NULL)
20342542f5fSchristos		return NULL;
20442542f5fSchristos
20542542f5fSchristos	/* Check for a duplicate */
20642542f5fSchristos	list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) {
20742542f5fSchristos		int other_stride = 0;
20842542f5fSchristos		if (bo->snoop) {
20942542f5fSchristos			assert(priv->cpu_bo);
21042542f5fSchristos			assert(IS_STATIC_PTR(priv->ptr));
21142542f5fSchristos			if (bo->handle == priv->cpu_bo->handle)
21242542f5fSchristos				other_stride = priv->cpu_bo->pitch;
21342542f5fSchristos		} else  {
21442542f5fSchristos			assert(priv->gpu_bo);
21542542f5fSchristos			assert(priv->pinned & PIN_DRI3);
21642542f5fSchristos			if (bo->handle == priv->gpu_bo->handle)
21742542f5fSchristos				other_stride = priv->gpu_bo->pitch;
21842542f5fSchristos		}
21942542f5fSchristos		if (other_stride) {
22042542f5fSchristos			pixmap = priv->pixmap;
22142542f5fSchristos			DBG(("%s: imported fd matches existing DRI3 pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
22242542f5fSchristos			bo->handle = 0; /* fudge to prevent gem_close */
22342542f5fSchristos			kgem_bo_destroy(&sna->kgem, bo);
22442542f5fSchristos			if (width != pixmap->drawable.width ||
22542542f5fSchristos			    height != pixmap->drawable.height ||
22642542f5fSchristos			    depth != pixmap->drawable.depth ||
22742542f5fSchristos			    bpp != pixmap->drawable.bitsPerPixel ||
22842542f5fSchristos			    stride != other_stride) {
22942542f5fSchristos				DBG(("%s: imported fd mismatches existing DRI3 pixmap (width=%d, height=%d, depth=%d, bpp=%d, stride=%d)\n", __FUNCTION__,
23042542f5fSchristos				     pixmap->drawable.width,
23142542f5fSchristos				     pixmap->drawable.height,
23242542f5fSchristos				     pixmap->drawable.depth,
23342542f5fSchristos				     pixmap->drawable.bitsPerPixel,
23442542f5fSchristos				     other_stride));
23542542f5fSchristos				return NULL;
23642542f5fSchristos			}
23742542f5fSchristos			sna_sync_flush(sna, priv);
23842542f5fSchristos			pixmap->refcnt++;
23942542f5fSchristos			return pixmap;
24042542f5fSchristos		}
24142542f5fSchristos	}
24242542f5fSchristos
24342542f5fSchristos	if (!kgem_check_surface_size(&sna->kgem,
24442542f5fSchristos				     width, height, bpp,
24542542f5fSchristos				     bo->tiling, stride, kgem_bo_size(bo))) {
24642542f5fSchristos		DBG(("%s: client supplied pitch=%d, size=%d too small for %dx%d surface\n",
24742542f5fSchristos		     __FUNCTION__, stride, kgem_bo_size(bo), width, height));
24842542f5fSchristos		goto free_bo;
24942542f5fSchristos	}
25042542f5fSchristos
25142542f5fSchristos	pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
25242542f5fSchristos	if (pixmap == NullPixmap)
25342542f5fSchristos		goto free_bo;
25442542f5fSchristos
25542542f5fSchristos	if (!screen->ModifyPixmapHeader(pixmap, width, height,
25642542f5fSchristos					depth, bpp, stride, NULL))
25742542f5fSchristos		goto free_pixmap;
25842542f5fSchristos
25942542f5fSchristos	priv = sna_pixmap_attach_to_bo(pixmap, bo);
26042542f5fSchristos	if (priv == NULL)
26142542f5fSchristos		goto free_pixmap;
26242542f5fSchristos
26342542f5fSchristos	bo->pitch = stride;
26442542f5fSchristos	priv->stride = stride;
26542542f5fSchristos
26642542f5fSchristos	if (bo->snoop) {
26742542f5fSchristos		assert(priv->cpu_bo == bo);
26842542f5fSchristos		pixmap->devPrivate.ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
26942542f5fSchristos		if (pixmap->devPrivate.ptr == NULL)
27042542f5fSchristos			goto free_pixmap;
27142542f5fSchristos
27242542f5fSchristos		pixmap->devKind = stride;
27342542f5fSchristos		priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
27442542f5fSchristos	} else {
27542542f5fSchristos		assert(priv->gpu_bo == bo);
276fe8aea9eSmrg		priv->create = kgem_can_create_2d(&sna->kgem,
277fe8aea9eSmrg						  width, height, depth);
27842542f5fSchristos		priv->pinned |= PIN_DRI3;
27942542f5fSchristos	}
28042542f5fSchristos	list_add(&priv->cow_list, &sna->dri3.pixmaps);
28142542f5fSchristos
28213496ba1Ssnj	mark_dri3_pixmap(sna, priv, bo);
28313496ba1Ssnj
28442542f5fSchristos	return pixmap;
28542542f5fSchristos
28642542f5fSchristosfree_pixmap:
28742542f5fSchristos	screen->DestroyPixmap(pixmap);
28842542f5fSchristosfree_bo:
28942542f5fSchristos	kgem_bo_destroy(&sna->kgem, bo);
29042542f5fSchristos	return NULL;
29142542f5fSchristos}
29242542f5fSchristos
29342542f5fSchristosstatic int sna_dri3_fd_from_pixmap(ScreenPtr screen,
29442542f5fSchristos				   PixmapPtr pixmap,
29542542f5fSchristos				   CARD16 *stride,
29642542f5fSchristos				   CARD32 *size)
29742542f5fSchristos{
29842542f5fSchristos	struct sna *sna = to_sna_from_screen(screen);
29942542f5fSchristos	struct sna_pixmap *priv;
30042542f5fSchristos	struct kgem_bo *bo = NULL;
30142542f5fSchristos	int fd;
30242542f5fSchristos
30342542f5fSchristos	DBG(("%s(pixmap=%ld, width=%d, height=%d)\n", __FUNCTION__,
30442542f5fSchristos	     pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height));
30542542f5fSchristos	if (pixmap == sna->front && sna->flags & SNA_TEAR_FREE) {
30642542f5fSchristos		DBG(("%s: DRI3 protocol cannot support TearFree frontbuffers\n", __FUNCTION__));
30742542f5fSchristos		return -1;
30842542f5fSchristos	}
30942542f5fSchristos
31042542f5fSchristos	priv = sna_pixmap(pixmap);
31142542f5fSchristos	if (priv && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) {
31242542f5fSchristos		if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT))
31342542f5fSchristos			bo = priv->cpu_bo;
31442542f5fSchristos	} else {
31542542f5fSchristos		priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE | __MOVE_DRI);
31642542f5fSchristos		if (priv != NULL) {
31742542f5fSchristos			sna_damage_all(&priv->gpu_damage, pixmap);
31842542f5fSchristos			bo = priv->gpu_bo;
31942542f5fSchristos		}
32042542f5fSchristos	}
32142542f5fSchristos	if (bo == NULL) {
32242542f5fSchristos		DBG(("%s: pixmap not supported by GPU\n", __FUNCTION__));
32342542f5fSchristos		return -1;
32442542f5fSchristos	}
32542542f5fSchristos	assert(priv != NULL);
32642542f5fSchristos
32742542f5fSchristos	if (bo->pitch > UINT16_MAX) {
32842542f5fSchristos		DBG(("%s: pixmap pitch (%d) too large for DRI3 protocol\n",
32942542f5fSchristos		     __FUNCTION__, bo->pitch));
33042542f5fSchristos		return -1;
33142542f5fSchristos	}
33242542f5fSchristos
333fe8aea9eSmrg	if (bo->tiling && !sna->kgem.can_fence) {
334fe8aea9eSmrg		if (!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
335fe8aea9eSmrg			DBG(("%s: unable to discard GPU tiling (%d) for DRI3 protocol\n",
336fe8aea9eSmrg			     __FUNCTION__, bo->tiling));
337fe8aea9eSmrg			return -1;
338fe8aea9eSmrg		}
339fe8aea9eSmrg		bo = priv->gpu_bo;
340fe8aea9eSmrg	}
341fe8aea9eSmrg
34242542f5fSchristos	fd = kgem_bo_export_to_prime(&sna->kgem, bo);
34342542f5fSchristos	if (fd == -1) {
34442542f5fSchristos		DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle));
34542542f5fSchristos		return -1;
34642542f5fSchristos	}
34742542f5fSchristos
34842542f5fSchristos	if (bo == priv->gpu_bo)
34942542f5fSchristos		priv->pinned |= PIN_DRI3;
35042542f5fSchristos	list_move(&priv->cow_list, &sna->dri3.pixmaps);
35142542f5fSchristos
35213496ba1Ssnj	mark_dri3_pixmap(sna, priv, bo);
35313496ba1Ssnj
35442542f5fSchristos	*stride = (priv->pinned & PIN_DRI3) ? priv->gpu_bo->pitch : priv->cpu_bo->pitch;
35542542f5fSchristos	*size = kgem_bo_size((priv->pinned & PIN_DRI3) ? priv->gpu_bo : priv->cpu_bo);
35642542f5fSchristos	DBG(("%s: exporting %s pixmap=%ld, handle=%d, stride=%d, size=%d\n",
35742542f5fSchristos	     __FUNCTION__,
35842542f5fSchristos	     (priv->pinned & PIN_DRI3) ? "GPU" : "CPU", pixmap->drawable.serialNumber,
35942542f5fSchristos	     (priv->pinned & PIN_DRI3) ? priv->gpu_bo->handle : priv->cpu_bo->handle,
36042542f5fSchristos	     *stride, *size));
36142542f5fSchristos	return fd;
36242542f5fSchristos}
36342542f5fSchristos
36442542f5fSchristosstatic dri3_screen_info_rec sna_dri3_info = {
36542542f5fSchristos	.version = DRI3_SCREEN_INFO_VERSION,
36642542f5fSchristos
36742542f5fSchristos	.open = sna_dri3_open_device,
36842542f5fSchristos	.pixmap_from_fd = sna_dri3_pixmap_from_fd,
36942542f5fSchristos	.fd_from_pixmap = sna_dri3_fd_from_pixmap,
37042542f5fSchristos};
37142542f5fSchristos
37242542f5fSchristosbool sna_dri3_open(struct sna *sna, ScreenPtr screen)
37342542f5fSchristos{
37442542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
37542542f5fSchristos
37642542f5fSchristos	if (!sna_sync_open(sna, screen))
37742542f5fSchristos		return false;
37842542f5fSchristos
37942542f5fSchristos	list_init(&sna->dri3.pixmaps);
38042542f5fSchristos	return dri3_screen_init(screen, &sna_dri3_info);
38142542f5fSchristos}
38242542f5fSchristos
38342542f5fSchristosvoid sna_dri3_close(struct sna *sna, ScreenPtr screen)
38442542f5fSchristos{
38542542f5fSchristos	SyncScreenFuncsPtr funcs;
38642542f5fSchristos
38742542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
38842542f5fSchristos
38942542f5fSchristos	funcs = miSyncGetScreenFuncs(screen);
39042542f5fSchristos	if (funcs)
39142542f5fSchristos		funcs->CreateFence = sna->dri3.create_fence;
39242542f5fSchristos}
393