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 
42 static DevPrivateKeyRec sna_sync_fence_private_key;
43 struct sna_sync_fence {
44 	SyncFenceSetTriggeredFunc set_triggered;
45 };
46 
sna_sync_fence(SyncFence * fence)47 static inline struct sna_sync_fence *sna_sync_fence(SyncFence *fence)
48 {
49 	return dixLookupPrivate(&fence->devPrivates, &sna_sync_fence_private_key);
50 }
51 
mark_dri3_pixmap(struct sna * sna,struct sna_pixmap * priv,struct kgem_bo * bo)52 static inline void mark_dri3_pixmap(struct sna *sna, struct sna_pixmap *priv, struct kgem_bo *bo)
53 {
54 	bo->flush = true;
55 	if (bo->exec)
56 		sna->kgem.flush = 1;
57 	if (bo == priv->gpu_bo)
58 		priv->flush |= FLUSH_READ | FLUSH_WRITE;
59 	else
60 		priv->shm = true;
61 
62 	sna_watch_flush(sna, 1);
63 
64 	kgem_bo_submit(&sna->kgem, bo);
65 	kgem_bo_unclean(&sna->kgem, bo);
66 }
67 
sna_sync_flush(struct sna * sna,struct sna_pixmap * priv)68 static void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv)
69 {
70 	struct kgem_bo *bo = NULL;
71 
72 	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber));
73 	assert(priv);
74 
75 	if (priv->pinned & PIN_DRI3) {
76 		assert(priv->gpu_bo);
77 		assert(priv->pinned & PIN_DRI3);
78 		DBG(("%s: flushing prime GPU bo, handle=%ld\n", __FUNCTION__, priv->gpu_bo->handle));
79 		if (sna_pixmap_move_to_gpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) {
80 			sna_damage_all(&priv->gpu_damage, priv->pixmap);
81 			bo = priv->gpu_bo;
82 		}
83 	} else {
84 		assert(priv->cpu_bo);
85 		assert(IS_STATIC_PTR(priv->ptr));
86 		DBG(("%s: flushing prime CPU bo, handle=%ld\n", __FUNCTION__, priv->cpu_bo->handle));
87 		if (sna_pixmap_move_to_cpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT))
88 			bo = priv->cpu_bo;
89 	}
90 
91 	if (bo != NULL) {
92 		kgem_bo_submit(&sna->kgem, bo);
93 		kgem_bo_unclean(&sna->kgem, bo);
94 	}
95 }
96 
97 static void
sna_sync_fence_set_triggered(SyncFence * fence)98 sna_sync_fence_set_triggered(SyncFence *fence)
99 {
100 	struct sna *sna = to_sna_from_screen(fence->pScreen);
101 	struct sna_sync_fence *sna_fence = sna_sync_fence(fence);
102 
103 	DBG(("%s()\n", __FUNCTION__));
104 	sna_accel_flush(sna);
105 
106 	fence->funcs.SetTriggered = sna_fence->set_triggered;
107 	sna_fence->set_triggered(fence);
108 	sna_fence->set_triggered = fence->funcs.SetTriggered;
109 	fence->funcs.SetTriggered = sna_sync_fence_set_triggered;
110 }
111 
112 static void
sna_sync_create_fence(ScreenPtr screen,SyncFence * fence,Bool initially_triggered)113 sna_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool initially_triggered)
114 {
115 	struct sna *sna = to_sna_from_screen(screen);
116 	SyncScreenFuncsPtr funcs = miSyncGetScreenFuncs(screen);
117 
118 	DBG(("%s()\n", __FUNCTION__));
119 
120 	funcs->CreateFence = sna->dri3.create_fence;
121 	sna->dri3.create_fence(screen, fence, initially_triggered);
122 	sna->dri3.create_fence = funcs->CreateFence;
123 	funcs->CreateFence = sna_sync_create_fence;
124 
125 	sna_sync_fence(fence)->set_triggered = fence->funcs.SetTriggered;
126 	fence->funcs.SetTriggered = sna_sync_fence_set_triggered;
127 }
128 
129 static bool
sna_sync_open(struct sna * sna,ScreenPtr screen)130 sna_sync_open(struct sna *sna, ScreenPtr screen)
131 {
132 	SyncScreenFuncsPtr funcs;
133 
134 	DBG(("%s()\n", __FUNCTION__));
135 
136 	if (!miSyncShmScreenInit(screen))
137 		return false;
138 
139 	if (!dixPrivateKeyRegistered(&sna_sync_fence_private_key)) {
140 		if (!dixRegisterPrivateKey(&sna_sync_fence_private_key,
141 					   PRIVATE_SYNC_FENCE,
142 					   sizeof(struct sna_sync_fence)))
143 			return false;
144 	}
145 
146 	funcs = miSyncGetScreenFuncs(screen);
147 	sna->dri3.create_fence = funcs->CreateFence;
148 	funcs->CreateFence = sna_sync_create_fence;
149 
150 	return true;
151 }
152 
sna_dri3_open_device(ScreenPtr screen,RRProviderPtr provider,int * out)153 static int sna_dri3_open_device(ScreenPtr screen,
154 				RRProviderPtr provider,
155 				int *out)
156 {
157 	int fd;
158 
159 	DBG(("%s()\n", __FUNCTION__));
160 	fd = intel_get_client_fd(to_sna_from_screen(screen)->dev);
161 	if (fd < 0)
162 		return -fd;
163 
164 	*out = fd;
165 	return Success;
166 }
167 
sna_dri3_pixmap_from_fd(ScreenPtr screen,int fd,CARD16 width,CARD16 height,CARD16 stride,CARD8 depth,CARD8 bpp)168 static PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen,
169 					 int fd,
170 					 CARD16 width,
171 					 CARD16 height,
172 					 CARD16 stride,
173 					 CARD8 depth,
174 					 CARD8 bpp)
175 {
176 	struct sna *sna = to_sna_from_screen(screen);
177 	PixmapPtr pixmap;
178 	struct sna_pixmap *priv;
179 	struct kgem_bo *bo;
180 
181 	DBG(("%s(fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d)\n",
182 	     __FUNCTION__, fd, width, height, stride, depth, bpp));
183 	if (width > INT16_MAX || height > INT16_MAX)
184 		return NULL;
185 
186 	if ((uint32_t)width * bpp > (uint32_t)stride * 8)
187 		return NULL;
188 
189 	if (depth < 8)
190 		return NULL;
191 
192 	switch (bpp) {
193 	case 8:
194 	case 16:
195 	case 32:
196 		break;
197 	default:
198 		return NULL;
199 	}
200 
201 	bo = kgem_create_for_prime(&sna->kgem, fd, (uint32_t)stride * height);
202 	if (bo == NULL)
203 		return NULL;
204 
205 	/* Check for a duplicate */
206 	list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) {
207 		int other_stride = 0;
208 		if (bo->snoop) {
209 			assert(priv->cpu_bo);
210 			assert(IS_STATIC_PTR(priv->ptr));
211 			if (bo->handle == priv->cpu_bo->handle)
212 				other_stride = priv->cpu_bo->pitch;
213 		} else  {
214 			assert(priv->gpu_bo);
215 			assert(priv->pinned & PIN_DRI3);
216 			if (bo->handle == priv->gpu_bo->handle)
217 				other_stride = priv->gpu_bo->pitch;
218 		}
219 		if (other_stride) {
220 			pixmap = priv->pixmap;
221 			DBG(("%s: imported fd matches existing DRI3 pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
222 			bo->handle = 0; /* fudge to prevent gem_close */
223 			kgem_bo_destroy(&sna->kgem, bo);
224 			if (width != pixmap->drawable.width ||
225 			    height != pixmap->drawable.height ||
226 			    depth != pixmap->drawable.depth ||
227 			    bpp != pixmap->drawable.bitsPerPixel ||
228 			    stride != other_stride) {
229 				DBG(("%s: imported fd mismatches existing DRI3 pixmap (width=%d, height=%d, depth=%d, bpp=%d, stride=%d)\n", __FUNCTION__,
230 				     pixmap->drawable.width,
231 				     pixmap->drawable.height,
232 				     pixmap->drawable.depth,
233 				     pixmap->drawable.bitsPerPixel,
234 				     other_stride));
235 				return NULL;
236 			}
237 			sna_sync_flush(sna, priv);
238 			pixmap->refcnt++;
239 			return pixmap;
240 		}
241 	}
242 
243 	if (!kgem_check_surface_size(&sna->kgem,
244 				     width, height, bpp,
245 				     bo->tiling, stride, kgem_bo_size(bo))) {
246 		DBG(("%s: client supplied pitch=%d, size=%d too small for %dx%d surface\n",
247 		     __FUNCTION__, stride, kgem_bo_size(bo), width, height));
248 		goto free_bo;
249 	}
250 
251 	pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
252 	if (pixmap == NullPixmap)
253 		goto free_bo;
254 
255 	if (!screen->ModifyPixmapHeader(pixmap, width, height,
256 					depth, bpp, stride, NULL))
257 		goto free_pixmap;
258 
259 	priv = sna_pixmap_attach_to_bo(pixmap, bo);
260 	if (priv == NULL)
261 		goto free_pixmap;
262 
263 	bo->pitch = stride;
264 	priv->stride = stride;
265 
266 	if (bo->snoop) {
267 		assert(priv->cpu_bo == bo);
268 		pixmap->devPrivate.ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
269 		if (pixmap->devPrivate.ptr == NULL)
270 			goto free_pixmap;
271 
272 		pixmap->devKind = stride;
273 		priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
274 	} else {
275 		assert(priv->gpu_bo == bo);
276 		priv->create = kgem_can_create_2d(&sna->kgem,
277 						  width, height, depth);
278 		priv->pinned |= PIN_DRI3;
279 	}
280 	list_add(&priv->cow_list, &sna->dri3.pixmaps);
281 
282 	mark_dri3_pixmap(sna, priv, bo);
283 
284 	return pixmap;
285 
286 free_pixmap:
287 	screen->DestroyPixmap(pixmap);
288 free_bo:
289 	kgem_bo_destroy(&sna->kgem, bo);
290 	return NULL;
291 }
292 
sna_dri3_fd_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)293 static int sna_dri3_fd_from_pixmap(ScreenPtr screen,
294 				   PixmapPtr pixmap,
295 				   CARD16 *stride,
296 				   CARD32 *size)
297 {
298 	struct sna *sna = to_sna_from_screen(screen);
299 	struct sna_pixmap *priv;
300 	struct kgem_bo *bo = NULL;
301 	int fd;
302 
303 	DBG(("%s(pixmap=%ld, width=%d, height=%d)\n", __FUNCTION__,
304 	     pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height));
305 	if (pixmap == sna->front && sna->flags & SNA_TEAR_FREE) {
306 		DBG(("%s: DRI3 protocol cannot support TearFree frontbuffers\n", __FUNCTION__));
307 		return -1;
308 	}
309 
310 	priv = sna_pixmap(pixmap);
311 	if (priv && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) {
312 		if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT))
313 			bo = priv->cpu_bo;
314 	} else {
315 		priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE | __MOVE_DRI);
316 		if (priv != NULL) {
317 			sna_damage_all(&priv->gpu_damage, pixmap);
318 			bo = priv->gpu_bo;
319 		}
320 	}
321 	if (bo == NULL) {
322 		DBG(("%s: pixmap not supported by GPU\n", __FUNCTION__));
323 		return -1;
324 	}
325 	assert(priv != NULL);
326 
327 	if (bo->pitch > UINT16_MAX) {
328 		DBG(("%s: pixmap pitch (%d) too large for DRI3 protocol\n",
329 		     __FUNCTION__, bo->pitch));
330 		return -1;
331 	}
332 
333 	if (bo->tiling && !sna->kgem.can_fence) {
334 		if (!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
335 			DBG(("%s: unable to discard GPU tiling (%d) for DRI3 protocol\n",
336 			     __FUNCTION__, bo->tiling));
337 			return -1;
338 		}
339 		bo = priv->gpu_bo;
340 	}
341 
342 	fd = kgem_bo_export_to_prime(&sna->kgem, bo);
343 	if (fd == -1) {
344 		DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle));
345 		return -1;
346 	}
347 
348 	if (bo == priv->gpu_bo)
349 		priv->pinned |= PIN_DRI3;
350 	list_move(&priv->cow_list, &sna->dri3.pixmaps);
351 
352 	mark_dri3_pixmap(sna, priv, bo);
353 
354 	*stride = (priv->pinned & PIN_DRI3) ? priv->gpu_bo->pitch : priv->cpu_bo->pitch;
355 	*size = kgem_bo_size((priv->pinned & PIN_DRI3) ? priv->gpu_bo : priv->cpu_bo);
356 	DBG(("%s: exporting %s pixmap=%ld, handle=%d, stride=%d, size=%d\n",
357 	     __FUNCTION__,
358 	     (priv->pinned & PIN_DRI3) ? "GPU" : "CPU", pixmap->drawable.serialNumber,
359 	     (priv->pinned & PIN_DRI3) ? priv->gpu_bo->handle : priv->cpu_bo->handle,
360 	     *stride, *size));
361 	return fd;
362 }
363 
364 static dri3_screen_info_rec sna_dri3_info = {
365 	.version = DRI3_SCREEN_INFO_VERSION,
366 
367 	.open = sna_dri3_open_device,
368 	.pixmap_from_fd = sna_dri3_pixmap_from_fd,
369 	.fd_from_pixmap = sna_dri3_fd_from_pixmap,
370 };
371 
sna_dri3_open(struct sna * sna,ScreenPtr screen)372 bool sna_dri3_open(struct sna *sna, ScreenPtr screen)
373 {
374 	DBG(("%s()\n", __FUNCTION__));
375 
376 	if (!sna_sync_open(sna, screen))
377 		return false;
378 
379 	list_init(&sna->dri3.pixmaps);
380 	return dri3_screen_init(screen, &sna_dri3_info);
381 }
382 
sna_dri3_close(struct sna * sna,ScreenPtr screen)383 void sna_dri3_close(struct sna *sna, ScreenPtr screen)
384 {
385 	SyncScreenFuncsPtr funcs;
386 
387 	DBG(("%s()\n", __FUNCTION__));
388 
389 	funcs = miSyncGetScreenFuncs(screen);
390 	if (funcs)
391 		funcs->CreateFence = sna->dri3.create_fence;
392 }
393