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