1/*
2 * Copyright © 2001 Keith Packard
3 *             2010 Intel Corporation
4 *             2012,2015 Advanced Micro Devices, Inc.
5 *
6 * Partly based on code Copyright © 2008 Red Hat, Inc.
7 * Partly based on code Copyright © 2000 SuSE, Inc.
8 *
9 * Partly based on code that is Copyright © The XFree86 Project Inc.
10 *
11 * Permission to use, copy, modify, distribute, and sell this software and its
12 * documentation for any purpose is hereby granted without fee, provided that
13 * the above copyright notice appear in all copies and that both that
14 * copyright notice and this permission notice appear in supporting
15 * documentation, and that the name of the opyright holders not be used in
16 * advertising or publicity pertaining to distribution of the software without
17 * specific, written prior permission.  The copyright holders make no
18 * representations about the suitability of this software for any purpose.  It
19 * is provided "as is" without express or implied warranty.
20 *
21 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
23 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
25 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
26 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27 * PERFORMANCE OF THIS SOFTWARE.
28 */
29
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#ifdef USE_GLAMOR
36
37#include "amdgpu_drv.h"
38#include "amdgpu_glamor.h"
39#include "amdgpu_pixmap.h"
40
41
42/* Are there any outstanding GPU operations for this pixmap? */
43static Bool
44amdgpu_glamor_gpu_pending(uint_fast32_t gpu_synced, uint_fast32_t gpu_access)
45{
46	return (int_fast32_t)(gpu_access - gpu_synced) > 0;
47}
48
49/*
50 * Pixmap CPU access wrappers
51 */
52
53static Bool
54amdgpu_glamor_prepare_access_cpu(ScrnInfoPtr scrn, AMDGPUInfoPtr info,
55				 PixmapPtr pixmap, struct amdgpu_pixmap *priv,
56				 Bool need_sync)
57{
58	struct amdgpu_buffer *bo = priv->bo;
59	int ret;
60
61	/* When falling back to swrast, flush all pending operations */
62	if (need_sync)
63		amdgpu_glamor_flush(scrn);
64
65	if (!pixmap->devPrivate.ptr) {
66		ret = amdgpu_bo_map(scrn, bo);
67		if (ret) {
68			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
69				   "%s: bo map failed: %s\n", __FUNCTION__,
70				   strerror(-ret));
71			return FALSE;
72		}
73
74		pixmap->devPrivate.ptr = bo->cpu_ptr;
75		info->gpu_synced = info->gpu_flushed;
76	} else if (need_sync) {
77		char pixel[4];
78
79		info->glamor.SavedGetImage(&pixmap->drawable, 0, 0, 1, 1,
80					   ZPixmap, ~0, pixel);
81		info->gpu_synced = info->gpu_flushed;
82	}
83
84	return TRUE;
85}
86
87static Bool
88amdgpu_glamor_prepare_access_cpu_ro(ScrnInfoPtr scrn, PixmapPtr pixmap,
89				    struct amdgpu_pixmap *priv)
90{
91	AMDGPUInfoPtr info;
92	Bool need_sync;
93
94	if (!priv)
95		return TRUE;
96
97	info = AMDGPUPTR(scrn);
98	need_sync = amdgpu_glamor_gpu_pending(info->gpu_synced, priv->gpu_write);
99	return amdgpu_glamor_prepare_access_cpu(scrn, AMDGPUPTR(scrn), pixmap,
100						priv, need_sync);
101}
102
103static Bool
104amdgpu_glamor_prepare_access_cpu_rw(ScrnInfoPtr scrn, PixmapPtr pixmap,
105				    struct amdgpu_pixmap *priv)
106{
107	AMDGPUInfoPtr info;
108	uint_fast32_t gpu_synced;
109	Bool need_sync;
110
111	if (!priv)
112		return TRUE;
113
114	info = AMDGPUPTR(scrn);
115	gpu_synced = info->gpu_synced;
116	need_sync = amdgpu_glamor_gpu_pending(gpu_synced, priv->gpu_write) |
117		amdgpu_glamor_gpu_pending(gpu_synced, priv->gpu_read);
118	return amdgpu_glamor_prepare_access_cpu(scrn, info, pixmap, priv,
119						need_sync);
120}
121
122static void
123amdgpu_glamor_finish_access_cpu(PixmapPtr pixmap)
124{
125	/* Nothing to do */
126}
127
128/*
129 * Pixmap GPU access wrappers
130 */
131
132static Bool
133amdgpu_glamor_use_gpu(PixmapPtr pixmap, struct amdgpu_pixmap *priv)
134{
135	return (pixmap->usage_hint &
136		(AMDGPU_CREATE_PIXMAP_SCANOUT | AMDGPU_CREATE_PIXMAP_DRI2)) != 0 ||
137		(priv && !priv->bo);
138}
139
140static Bool
141amdgpu_glamor_prepare_access_gpu(struct amdgpu_pixmap *priv)
142{
143	return priv != NULL;
144}
145
146static void
147amdgpu_glamor_finish_access_gpu_ro(AMDGPUInfoPtr info,
148				   struct amdgpu_pixmap *priv)
149{
150	priv->gpu_read = info->gpu_flushed + 1;
151}
152
153static void
154amdgpu_glamor_finish_access_gpu_rw(AMDGPUInfoPtr info,
155				   struct amdgpu_pixmap *priv)
156{
157	priv->gpu_write = priv->gpu_read = info->gpu_flushed + 1;
158}
159
160/*
161 * GC CPU access wrappers
162 */
163
164static Bool
165amdgpu_glamor_prepare_access_gc(ScrnInfoPtr scrn, GCPtr pGC)
166{
167	struct amdgpu_pixmap *priv;
168
169	if (pGC->stipple) {
170		priv = amdgpu_get_pixmap_private(pGC->stipple);
171		if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pGC->stipple, priv))
172			return FALSE;
173	}
174	if (pGC->fillStyle == FillTiled) {
175		priv = amdgpu_get_pixmap_private(pGC->tile.pixmap);
176		if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pGC->tile.pixmap,
177						      priv)) {
178			if (pGC->stipple)
179				amdgpu_glamor_finish_access_cpu(pGC->stipple);
180			return FALSE;
181		}
182	}
183	return TRUE;
184}
185
186static void
187amdgpu_glamor_finish_access_gc(GCPtr pGC)
188{
189	if (pGC->fillStyle == FillTiled)
190		amdgpu_glamor_finish_access_cpu(pGC->tile.pixmap);
191	if (pGC->stipple)
192		amdgpu_glamor_finish_access_cpu(pGC->stipple);
193}
194
195/*
196 * Picture CPU access wrappers
197 */
198
199static void
200amdgpu_glamor_picture_finish_access_cpu(PicturePtr picture)
201{
202	/* Nothing to do */
203}
204
205static Bool
206amdgpu_glamor_picture_prepare_access_cpu_ro(ScrnInfoPtr scrn,
207					    PicturePtr picture)
208{
209	PixmapPtr pixmap;
210	struct amdgpu_pixmap *priv;
211
212	if (!picture->pDrawable)
213		return TRUE;
214
215	pixmap = get_drawable_pixmap(picture->pDrawable);
216	priv = amdgpu_get_pixmap_private(pixmap);
217	if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv))
218		return FALSE;
219
220	if (picture->alphaMap) {
221		pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable);
222		priv = amdgpu_get_pixmap_private(pixmap);
223		if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
224			amdgpu_glamor_picture_finish_access_cpu(picture);
225			return FALSE;
226		}
227	}
228
229	return TRUE;
230}
231
232static Bool
233amdgpu_glamor_picture_prepare_access_cpu_rw(ScrnInfoPtr scrn,
234					    PicturePtr picture)
235{
236	PixmapPtr pixmap;
237	struct amdgpu_pixmap *priv;
238
239	pixmap = get_drawable_pixmap(picture->pDrawable);
240	priv = amdgpu_get_pixmap_private(pixmap);
241	if (!amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv))
242		return FALSE;
243
244	if (picture->alphaMap) {
245		pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable);
246		priv = amdgpu_get_pixmap_private(pixmap);
247		if (!amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
248			amdgpu_glamor_picture_finish_access_cpu(picture);
249			return FALSE;
250		}
251	}
252
253	return TRUE;
254}
255
256/*
257 * GC rendering wrappers
258 */
259
260static void
261amdgpu_glamor_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
262			 DDXPointPtr ppt, int *pwidth, int fSorted)
263{
264	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
265	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
266	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
267
268	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
269		if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
270			fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth,
271				    fSorted);
272			amdgpu_glamor_finish_access_gc(pGC);
273		}
274		amdgpu_glamor_finish_access_cpu(pixmap);
275	}
276}
277
278static void
279amdgpu_glamor_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
280			DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
281{
282	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
283	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
284	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
285
286	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
287		fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
288		amdgpu_glamor_finish_access_cpu(pixmap);
289	}
290}
291
292static void
293amdgpu_glamor_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
294			int x, int y, int w, int h, int leftPad, int format,
295			char *bits)
296{
297	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
298	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
299	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
300
301	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
302		fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
303			   bits);
304		amdgpu_glamor_finish_access_cpu(pixmap);
305	}
306}
307
308static RegionPtr
309amdgpu_glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
310			 int srcx, int srcy, int w, int h, int dstx, int dsty,
311			 unsigned long bitPlane)
312{
313	ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pScreen);
314	PixmapPtr dst_pix = get_drawable_pixmap(pDst);
315	struct amdgpu_pixmap *dst_priv = amdgpu_get_pixmap_private(dst_pix);
316	RegionPtr ret = NULL;
317
318	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, dst_pix, dst_priv)) {
319		PixmapPtr src_pix = get_drawable_pixmap(pSrc);
320		struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pix);
321		if (amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) {
322			ret =
323			    fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
324					dsty, bitPlane);
325			amdgpu_glamor_finish_access_cpu(src_pix);
326		}
327		amdgpu_glamor_finish_access_cpu(dst_pix);
328	}
329	return ret;
330}
331
332static RegionPtr
333amdgpu_glamor_copy_plane_nodstbo(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
334				 int srcx, int srcy, int w, int h,
335				 int dstx, int dsty, unsigned long bitPlane)
336{
337	ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pScreen);
338	PixmapPtr src_pix = get_drawable_pixmap(pSrc);
339	struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pix);
340	RegionPtr ret = NULL;
341
342	if (amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) {
343		ret = fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h,
344				  dstx,	dsty, bitPlane);
345		amdgpu_glamor_finish_access_cpu(src_pix);
346	}
347	return ret;
348}
349
350static void
351amdgpu_glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
352			 DDXPointPtr pptInit)
353{
354	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
355	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
356	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
357
358	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
359		fbPolyPoint(pDrawable, pGC, mode, npt, pptInit);
360		amdgpu_glamor_finish_access_cpu(pixmap);
361	}
362}
363
364static void
365amdgpu_glamor_poly_lines(DrawablePtr pDrawable, GCPtr pGC,
366			 int mode, int npt, DDXPointPtr ppt)
367{
368	if (pGC->lineWidth == 0) {
369		ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
370		PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
371		struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
372
373		if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
374			if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
375				fbPolyLine(pDrawable, pGC, mode, npt, ppt);
376				amdgpu_glamor_finish_access_gc(pGC);
377			}
378			amdgpu_glamor_finish_access_cpu(pixmap);
379		}
380		return;
381	}
382	/* fb calls mi functions in the lineWidth != 0 case. */
383	fbPolyLine(pDrawable, pGC, mode, npt, ppt);
384}
385
386static void
387amdgpu_glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC,
388			   int nsegInit, xSegment *pSegInit)
389{
390	if (pGC->lineWidth == 0) {
391		ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
392		PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
393		struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
394
395		if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
396			if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
397				fbPolySegment(pDrawable, pGC, nsegInit,
398					      pSegInit);
399				amdgpu_glamor_finish_access_gc(pGC);
400			}
401			amdgpu_glamor_finish_access_cpu(pixmap);
402		}
403		return;
404	}
405	/* fb calls mi functions in the lineWidth != 0 case. */
406	fbPolySegment(pDrawable, pGC, nsegInit, pSegInit);
407}
408
409static void
410amdgpu_glamor_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
411			     int nrect, xRectangle *prect)
412{
413	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
414	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
415	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
416	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
417
418	if ((info->force_accel || amdgpu_glamor_use_gpu(pixmap, priv)) &&
419	    amdgpu_glamor_prepare_access_gpu(priv)) {
420		info->glamor.SavedPolyFillRect(pDrawable, pGC, nrect, prect);
421		amdgpu_glamor_finish_access_gpu_rw(info, priv);
422		return;
423	}
424
425	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
426		if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
427			fbPolyFillRect(pDrawable, pGC, nrect, prect);
428			amdgpu_glamor_finish_access_gc(pGC);
429		}
430		amdgpu_glamor_finish_access_cpu(pixmap);
431	}
432}
433
434static void
435amdgpu_glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
436			      int x, int y, unsigned int nglyph,
437			      CharInfoPtr *ppci, pointer pglyphBase)
438{
439	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
440	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
441	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
442
443	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
444		if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
445			fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
446					pglyphBase);
447			amdgpu_glamor_finish_access_gc(pGC);
448		}
449		amdgpu_glamor_finish_access_cpu(pixmap);
450	}
451}
452
453static void
454amdgpu_glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
455			     int x, int y, unsigned int nglyph,
456			     CharInfoPtr *ppci, pointer pglyphBase)
457{
458	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
459	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
460	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
461
462	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
463		if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
464			fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
465				       pglyphBase);
466			amdgpu_glamor_finish_access_gc(pGC);
467		}
468		amdgpu_glamor_finish_access_cpu(pixmap);
469	}
470}
471
472static void
473amdgpu_glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
474			  DrawablePtr pDrawable, int w, int h, int x, int y)
475{
476	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
477	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
478	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
479
480	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
481		priv = amdgpu_get_pixmap_private(pBitmap);
482		if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) {
483			if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
484				fbPushPixels(pGC, pBitmap, pDrawable, w, h, x,
485					     y);
486				amdgpu_glamor_finish_access_gc(pGC);
487			}
488			amdgpu_glamor_finish_access_cpu(pBitmap);
489		}
490		amdgpu_glamor_finish_access_cpu(pixmap);
491	}
492}
493
494static void
495amdgpu_glamor_push_pixels_nodstbo(GCPtr pGC, PixmapPtr pBitmap,
496				  DrawablePtr pDrawable, int w, int h,
497				  int x, int y)
498{
499	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
500	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pBitmap);
501
502	if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) {
503		fbPushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
504		amdgpu_glamor_finish_access_cpu(pBitmap);
505	}
506}
507
508static RegionPtr
509amdgpu_glamor_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
510			GCPtr pGC, int srcx, int srcy, int width, int height,
511			int dstx, int dsty)
512{
513	ScreenPtr screen = pDstDrawable->pScreen;
514	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
515	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
516	PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable);
517	PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable);
518	struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pixmap);
519	struct amdgpu_pixmap *dst_priv = amdgpu_get_pixmap_private(dst_pixmap);
520	RegionPtr ret = NULL;
521
522	if (amdgpu_glamor_use_gpu(dst_pixmap, dst_priv) ||
523	    amdgpu_glamor_use_gpu(src_pixmap, src_priv)) {
524		if (!amdgpu_glamor_prepare_access_gpu(dst_priv))
525			goto fallback;
526		if (src_priv != dst_priv &&
527		    !amdgpu_glamor_prepare_access_gpu(src_priv))
528			goto fallback;
529
530		ret = info->glamor.SavedCopyArea(pSrcDrawable, pDstDrawable,
531						 pGC, srcx, srcy,
532						 width, height, dstx, dsty);
533		amdgpu_glamor_finish_access_gpu_rw(info, dst_priv);
534		if (src_priv != dst_priv)
535			amdgpu_glamor_finish_access_gpu_ro(info, src_priv);
536
537		return ret;
538	}
539
540fallback:
541	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, dst_pixmap, dst_priv)) {
542		if (pSrcDrawable == pDstDrawable ||
543			amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pixmap,
544							    src_priv)) {
545			ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC,
546					 srcx, srcy, width, height, dstx, dsty);
547			if (pSrcDrawable != pDstDrawable)
548				amdgpu_glamor_finish_access_cpu(src_pixmap);
549		}
550		amdgpu_glamor_finish_access_cpu(dst_pixmap);
551	}
552
553	return ret;
554}
555
556static RegionPtr
557amdgpu_glamor_copy_area_nodstbo(DrawablePtr pSrcDrawable,
558				DrawablePtr pDstDrawable, GCPtr pGC,
559				int srcx, int srcy, int width, int height,
560				int dstx, int dsty)
561{
562	ScreenPtr screen = pDstDrawable->pScreen;
563	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
564	PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable);
565	PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable);
566	struct amdgpu_pixmap *src_priv;
567	RegionPtr ret = NULL;
568
569	if (src_pixmap != dst_pixmap) {
570		src_priv = amdgpu_get_pixmap_private(src_pixmap);
571
572		if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pixmap,
573							 src_priv))
574			return ret;
575	}
576
577	ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
578			 width, height, dstx, dsty);
579
580	if (src_pixmap != dst_pixmap)
581		amdgpu_glamor_finish_access_cpu(src_pixmap);
582
583	return ret;
584}
585
586static const GCOps amdgpu_glamor_ops = {
587	amdgpu_glamor_fill_spans,
588	amdgpu_glamor_set_spans,
589	amdgpu_glamor_put_image,
590	amdgpu_glamor_copy_area,
591	amdgpu_glamor_copy_plane,
592	amdgpu_glamor_poly_point,
593	amdgpu_glamor_poly_lines,
594	amdgpu_glamor_poly_segment,
595	miPolyRectangle,
596	miPolyArc,
597	miFillPolygon,
598	amdgpu_glamor_poly_fill_rect,
599	miPolyFillArc,
600	miPolyText8,
601	miPolyText16,
602	miImageText8,
603	miImageText16,
604	amdgpu_glamor_image_glyph_blt,
605	amdgpu_glamor_poly_glyph_blt,
606	amdgpu_glamor_push_pixels,
607};
608
609static GCOps amdgpu_glamor_nodstbo_ops;
610
611/**
612 * amdgpu_glamor_validate_gc() sets the ops to our implementations, which may be
613 * accelerated or may sync the card and fall back to fb.
614 */
615static void
616amdgpu_glamor_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
617{
618	ScrnInfoPtr scrn = xf86ScreenToScrn(pGC->pScreen);
619	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
620
621	glamor_validate_gc(pGC, changes, pDrawable);
622	info->glamor.SavedCopyArea = pGC->ops->CopyArea;
623	info->glamor.SavedPolyFillRect = pGC->ops->PolyFillRect;
624
625	if (amdgpu_get_pixmap_private(get_drawable_pixmap(pDrawable)) ||
626	    (pGC->stipple && amdgpu_get_pixmap_private(pGC->stipple)) ||
627	    (pGC->fillStyle == FillTiled &&
628	     amdgpu_get_pixmap_private(pGC->tile.pixmap)))
629		pGC->ops = (GCOps *)&amdgpu_glamor_ops;
630	else
631		pGC->ops = &amdgpu_glamor_nodstbo_ops;
632}
633
634static GCFuncs glamorGCFuncs = {
635	amdgpu_glamor_validate_gc,
636	miChangeGC,
637	miCopyGC,
638	miDestroyGC,
639	miChangeClip,
640	miDestroyClip,
641	miCopyClip
642};
643
644/**
645 * amdgpu_glamor_create_gc makes a new GC and hooks up its funcs handler, so that
646 * amdgpu_glamor_validate_gc() will get called.
647 */
648static int
649amdgpu_glamor_create_gc(GCPtr pGC)
650{
651	static Bool nodstbo_ops_initialized;
652
653	if (!fbCreateGC(pGC))
654		return FALSE;
655
656	if (!nodstbo_ops_initialized) {
657		amdgpu_glamor_nodstbo_ops = amdgpu_glamor_ops;
658
659		amdgpu_glamor_nodstbo_ops.FillSpans = pGC->ops->FillSpans;
660		amdgpu_glamor_nodstbo_ops.SetSpans = pGC->ops->SetSpans;
661		amdgpu_glamor_nodstbo_ops.PutImage = pGC->ops->PutImage;
662		amdgpu_glamor_nodstbo_ops.CopyArea = amdgpu_glamor_copy_area_nodstbo;
663		amdgpu_glamor_nodstbo_ops.CopyPlane = amdgpu_glamor_copy_plane_nodstbo;
664		amdgpu_glamor_nodstbo_ops.PolyPoint = pGC->ops->PolyPoint;
665		amdgpu_glamor_nodstbo_ops.Polylines = pGC->ops->Polylines;
666		amdgpu_glamor_nodstbo_ops.PolySegment = pGC->ops->PolySegment;
667		amdgpu_glamor_nodstbo_ops.PolyFillRect = pGC->ops->PolyFillRect;
668		amdgpu_glamor_nodstbo_ops.ImageGlyphBlt = pGC->ops->ImageGlyphBlt;
669		amdgpu_glamor_nodstbo_ops.PolyGlyphBlt = pGC->ops->PolyGlyphBlt;
670		amdgpu_glamor_nodstbo_ops.PushPixels = amdgpu_glamor_push_pixels_nodstbo;
671
672		nodstbo_ops_initialized = TRUE;
673	}
674
675	pGC->funcs = &glamorGCFuncs;
676
677	return TRUE;
678}
679
680/*
681 * Screen rendering wrappers
682 */
683
684static RegionPtr
685amdgpu_glamor_bitmap_to_region(PixmapPtr pPix)
686{
687	ScrnInfoPtr scrn = xf86ScreenToScrn(pPix->drawable.pScreen);
688	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pPix);
689	RegionPtr ret;
690
691	if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pPix, priv))
692		return NULL;
693	ret = fbPixmapToRegion(pPix);
694	amdgpu_glamor_finish_access_cpu(pPix);
695	return ret;
696}
697
698static void
699amdgpu_glamor_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg,
700			  RegionPtr prgnSrc)
701{
702	ScrnInfoPtr scrn = xf86ScreenToScrn(pWin->drawable.pScreen);
703	PixmapPtr pixmap = get_drawable_pixmap(&pWin->drawable);
704	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
705
706	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
707		fbCopyWindow(pWin, ptOldOrg, prgnSrc);
708		amdgpu_glamor_finish_access_cpu(pixmap);
709	}
710}
711
712static void
713amdgpu_glamor_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
714			unsigned int format, unsigned long planeMask, char *d)
715{
716	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
717	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
718	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
719
720	if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
721		fbGetImage(pDrawable, x, y, w, h, format, planeMask, d);
722		amdgpu_glamor_finish_access_cpu(pixmap);
723	}
724}
725
726static void
727amdgpu_glamor_get_spans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt,
728			int *pwidth, int nspans, char *pdstStart)
729{
730	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
731	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
732	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
733
734	if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
735		fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
736		amdgpu_glamor_finish_access_cpu(pixmap);
737	}
738}
739
740/*
741 * Picture screen rendering wrappers
742 */
743
744#ifdef RENDER
745
746static void
747amdgpu_glamor_composite(CARD8 op,
748			PicturePtr pSrc,
749			PicturePtr pMask,
750			PicturePtr pDst,
751			INT16 xSrc, INT16 ySrc,
752			INT16 xMask, INT16 yMask,
753			INT16 xDst, INT16 yDst,
754			CARD16 width, CARD16 height)
755{
756	ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pDrawable->pScreen);
757	AMDGPUInfoPtr info;
758	PixmapPtr pixmap;
759	struct amdgpu_pixmap *dst_priv, *src_priv = NULL, *mask_priv = NULL;
760	Bool gpu_done = FALSE;
761
762	if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap))
763		goto fallback;
764
765	pixmap = get_drawable_pixmap(pDst->pDrawable);
766	if (&pixmap->drawable != pDst->pDrawable ||
767	    pixmap->usage_hint != AMDGPU_CREATE_PIXMAP_SCANOUT)
768		goto fallback;
769
770	dst_priv = amdgpu_get_pixmap_private(pixmap);
771	if (!amdgpu_glamor_prepare_access_gpu(dst_priv))
772		goto fallback;
773
774	info = AMDGPUPTR(scrn);
775	if (!pSrc->pDrawable ||
776	    ((pixmap = get_drawable_pixmap(pSrc->pDrawable)) &&
777	     (src_priv = amdgpu_get_pixmap_private(pixmap)) &&
778	     amdgpu_glamor_prepare_access_gpu(src_priv))) {
779		if (!pMask || !pMask->pDrawable ||
780		    ((pixmap = get_drawable_pixmap(pMask->pDrawable)) &&
781		     (mask_priv = amdgpu_get_pixmap_private(pixmap)) &&
782		     amdgpu_glamor_prepare_access_gpu(mask_priv))) {
783			info->glamor.SavedComposite(op, pSrc, pMask, pDst,
784						    xSrc, ySrc, xMask, yMask,
785						    xDst, yDst, width, height);
786			gpu_done = TRUE;
787
788			if (mask_priv)
789				amdgpu_glamor_finish_access_gpu_ro(info, mask_priv);
790		}
791
792		if (src_priv)
793			amdgpu_glamor_finish_access_gpu_ro(info, src_priv);
794	}
795	amdgpu_glamor_finish_access_gpu_rw(info, dst_priv);
796
797	if (gpu_done)
798		return;
799
800fallback:
801	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, pDst)) {
802		if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, pSrc)) {
803			if (!pMask ||
804			    amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, pMask)) {
805				fbComposite(op, pSrc, pMask, pDst,
806					    xSrc, ySrc,
807					    xMask, yMask,
808					    xDst, yDst,
809					    width, height);
810				if (pMask)
811					amdgpu_glamor_picture_finish_access_cpu(pMask);
812			}
813			amdgpu_glamor_picture_finish_access_cpu(pSrc);
814		}
815		amdgpu_glamor_picture_finish_access_cpu(pDst);
816	}
817}
818
819static void
820amdgpu_glamor_add_traps(PicturePtr pPicture,
821		    INT16 x_off, INT16 y_off, int ntrap, xTrap *traps)
822{
823	ScrnInfoPtr scrn = xf86ScreenToScrn(pPicture->pDrawable->pScreen);
824
825	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, pPicture)) {
826		fbAddTraps(pPicture, x_off, y_off, ntrap, traps);
827		amdgpu_glamor_picture_finish_access_cpu(pPicture);
828	}
829}
830
831static void
832amdgpu_glamor_glyphs(CARD8 op,
833		     PicturePtr src,
834		     PicturePtr dst,
835		     PictFormatPtr maskFormat,
836		     INT16 xSrc,
837		     INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
838{
839	ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen);
840
841	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
842		if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
843			AMDGPUInfoPtr info = AMDGPUPTR(scrn);
844
845			info->glamor.SavedGlyphs(op, src, dst, maskFormat, xSrc,
846						 ySrc, nlist, list, glyphs);
847			amdgpu_glamor_picture_finish_access_cpu(src);
848		}
849		amdgpu_glamor_picture_finish_access_cpu(dst);
850	}
851}
852
853static void
854amdgpu_glamor_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
855			 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
856			 int ntrap, xTrapezoid *traps)
857{
858	ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen);
859
860	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
861		if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
862			AMDGPUInfoPtr info = AMDGPUPTR(scrn);
863
864			info->glamor.SavedTrapezoids(op, src, dst, maskFormat,
865						     xSrc, ySrc, ntrap, traps);
866			amdgpu_glamor_picture_finish_access_cpu(src);
867		}
868		amdgpu_glamor_picture_finish_access_cpu(dst);
869	}
870}
871
872static void
873amdgpu_glamor_triangles(CARD8 op, PicturePtr src, PicturePtr dst,
874			PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
875			int ntri, xTriangle *tri)
876{
877	ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen);
878
879	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
880		if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
881			AMDGPUInfoPtr info = AMDGPUPTR(scrn);
882
883			info->glamor.SavedTriangles(op, src, dst, maskFormat,
884						    xSrc, ySrc, ntri, tri);
885			amdgpu_glamor_picture_finish_access_cpu(src);
886		}
887		amdgpu_glamor_picture_finish_access_cpu(dst);
888	}
889}
890
891#endif /* RENDER */
892
893
894/**
895 * amdgpu_glamor_close_screen() unwraps its wrapped screen functions and tears
896 * down our screen private, before calling down to the next CloseScreen.
897 */
898static Bool
899amdgpu_glamor_close_screen(ScreenPtr pScreen)
900{
901	AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(pScreen));
902#ifdef RENDER
903	PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
904#endif
905
906	pScreen->CreateGC = info->glamor.SavedCreateGC;
907	pScreen->CloseScreen = info->glamor.SavedCloseScreen;
908	pScreen->GetImage = info->glamor.SavedGetImage;
909	pScreen->GetSpans = info->glamor.SavedGetSpans;
910	pScreen->CopyWindow = info->glamor.SavedCopyWindow;
911	pScreen->ChangeWindowAttributes =
912	    info->glamor.SavedChangeWindowAttributes;
913	pScreen->BitmapToRegion = info->glamor.SavedBitmapToRegion;
914#ifdef RENDER
915	if (ps) {
916		ps->Composite = info->glamor.SavedComposite;
917		ps->Glyphs = info->glamor.SavedGlyphs;
918		ps->UnrealizeGlyph = info->glamor.SavedUnrealizeGlyph;
919		ps->Trapezoids = info->glamor.SavedTrapezoids;
920		ps->AddTraps = info->glamor.SavedAddTraps;
921		ps->Triangles = info->glamor.SavedTriangles;
922
923		ps->UnrealizeGlyph = info->glamor.SavedUnrealizeGlyph;
924	}
925#endif
926
927	return pScreen->CloseScreen(pScreen);
928}
929
930/**
931 * @param screen screen being initialized
932 */
933void
934amdgpu_glamor_screen_init(ScreenPtr screen)
935{
936	AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(screen));
937
938	/*
939	 * Replace various fb screen functions
940	 */
941	info->glamor.SavedCloseScreen = screen->CloseScreen;
942	screen->CloseScreen = amdgpu_glamor_close_screen;
943
944	info->glamor.SavedCreateGC = screen->CreateGC;
945	screen->CreateGC = amdgpu_glamor_create_gc;
946
947	info->glamor.SavedGetImage = screen->GetImage;
948	screen->GetImage = amdgpu_glamor_get_image;
949
950	info->glamor.SavedGetSpans = screen->GetSpans;
951	screen->GetSpans = amdgpu_glamor_get_spans;
952
953	info->glamor.SavedCopyWindow = screen->CopyWindow;
954	screen->CopyWindow = amdgpu_glamor_copy_window;
955
956	info->glamor.SavedBitmapToRegion = screen->BitmapToRegion;
957	screen->BitmapToRegion = amdgpu_glamor_bitmap_to_region;
958
959#ifdef RENDER
960	{
961		PictureScreenPtr ps = GetPictureScreenIfSet(screen);
962		if (ps) {
963			info->glamor.SavedComposite = ps->Composite;
964			ps->Composite = amdgpu_glamor_composite;
965
966			info->glamor.SavedUnrealizeGlyph = ps->UnrealizeGlyph;
967
968			ps->Glyphs = amdgpu_glamor_glyphs;
969			ps->Triangles = amdgpu_glamor_triangles;
970			ps->Trapezoids = amdgpu_glamor_trapezoids;
971
972			info->glamor.SavedAddTraps = ps->AddTraps;
973			ps->AddTraps = amdgpu_glamor_add_traps;
974		}
975	}
976#endif
977}
978
979#endif /* USE_GLAMOR */
980