1d514b0f3Smrg/*
2d514b0f3Smrg * Copyright © 2001 Keith Packard
3d514b0f3Smrg *
4d514b0f3Smrg * Partly based on code that is Copyright © The XFree86 Project Inc.
5d514b0f3Smrg *
6d514b0f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its
7d514b0f3Smrg * documentation for any purpose is hereby granted without fee, provided that
8d514b0f3Smrg * the above copyright notice appear in all copies and that both that
9d514b0f3Smrg * copyright notice and this permission notice appear in supporting
10d514b0f3Smrg * documentation, and that the name of Keith Packard not be used in
11d514b0f3Smrg * advertising or publicity pertaining to distribution of the software without
12d514b0f3Smrg * specific, written prior permission.  Keith Packard makes no
13d514b0f3Smrg * representations about the suitability of this software for any purpose.  It
14d514b0f3Smrg * is provided "as is" without express or implied warranty.
15d514b0f3Smrg *
16d514b0f3Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17d514b0f3Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18d514b0f3Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19d514b0f3Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20d514b0f3Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21d514b0f3Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22d514b0f3Smrg * PERFORMANCE OF THIS SOFTWARE.
23d514b0f3Smrg */
24d514b0f3Smrg
25d514b0f3Smrg#ifdef HAVE_DIX_CONFIG_H
26d514b0f3Smrg#include <dix-config.h>
27d514b0f3Smrg#endif
28d514b0f3Smrg
29d514b0f3Smrg#include <stdlib.h>
30d514b0f3Smrg
31d514b0f3Smrg#include "uxa-priv.h"
32d514b0f3Smrg#include <xorgVersion.h>
33d514b0f3Smrg
34d514b0f3Smrg#ifdef RENDER
35d514b0f3Smrg#include "mipict.h"
36d514b0f3Smrg
37d514b0f3Smrgstatic void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string,
38d514b0f3Smrg					     int n)
39d514b0f3Smrg{
40d514b0f3Smrg	char format[20];
41d514b0f3Smrg	char size[20];
42d514b0f3Smrg	char loc;
43d514b0f3Smrg
44d514b0f3Smrg	if (!pict) {
45d514b0f3Smrg		snprintf(string, n, "None");
46d514b0f3Smrg		return;
47d514b0f3Smrg	}
48d514b0f3Smrg
49d514b0f3Smrg	if (pict->pDrawable == NULL) {
50d514b0f3Smrg		snprintf(string, n, "source-only");
51d514b0f3Smrg		return;
52d514b0f3Smrg	}
53d514b0f3Smrg
54d514b0f3Smrg	switch (pict->format) {
55d514b0f3Smrg	case PICT_a8r8g8b8:
56d514b0f3Smrg		snprintf(format, 20, "ARGB8888");
57d514b0f3Smrg		break;
58d514b0f3Smrg	case PICT_x8r8g8b8:
59d514b0f3Smrg		snprintf(format, 20, "XRGB8888");
60d514b0f3Smrg		break;
61d514b0f3Smrg	case PICT_r5g6b5:
62d514b0f3Smrg		snprintf(format, 20, "RGB565  ");
63d514b0f3Smrg		break;
64d514b0f3Smrg	case PICT_x1r5g5b5:
65d514b0f3Smrg		snprintf(format, 20, "RGB555  ");
66d514b0f3Smrg		break;
67d514b0f3Smrg	case PICT_a8:
68d514b0f3Smrg		snprintf(format, 20, "A8      ");
69d514b0f3Smrg		break;
70d514b0f3Smrg	case PICT_a1:
71d514b0f3Smrg		snprintf(format, 20, "A1      ");
72d514b0f3Smrg		break;
73d514b0f3Smrg	default:
74d514b0f3Smrg		snprintf(format, 20, "0x%x", (int)pict->format);
75d514b0f3Smrg		break;
76d514b0f3Smrg	}
77d514b0f3Smrg
78d514b0f3Smrg	loc = uxa_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm';
79d514b0f3Smrg
80d514b0f3Smrg	snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
81d514b0f3Smrg		 pict->pDrawable->height, pict->repeat ? " R" : "");
82d514b0f3Smrg
83d514b0f3Smrg	snprintf(string, n, "%p:%c fmt %s (%s)%s",
84d514b0f3Smrg		 pict->pDrawable, loc, format, size,
85d514b0f3Smrg		 pict->alphaMap ? " with alpha map" :"");
86d514b0f3Smrg}
87d514b0f3Smrg
88d514b0f3Smrgstatic const char *
89d514b0f3Smrgop_to_string(CARD8 op)
90d514b0f3Smrg{
91d514b0f3Smrg    switch (op) {
92d514b0f3Smrg#define C(x) case PictOp##x: return #x
93d514b0f3Smrg	C(Clear);
94d514b0f3Smrg	C(Src);
95d514b0f3Smrg	C(Dst);
96d514b0f3Smrg	C(Over);
97d514b0f3Smrg	C(OverReverse);
98d514b0f3Smrg	C(In);
99d514b0f3Smrg	C(InReverse);
100d514b0f3Smrg	C(Out);
101d514b0f3Smrg	C(OutReverse);
102d514b0f3Smrg	C(Atop);
103d514b0f3Smrg	C(AtopReverse);
104d514b0f3Smrg	C(Xor);
105d514b0f3Smrg	C(Add);
106d514b0f3Smrg	C(Saturate);
107d514b0f3Smrg
108d514b0f3Smrg	/*
109d514b0f3Smrg	 * Operators only available in version 0.2
110d514b0f3Smrg	 */
111d514b0f3Smrg	C(DisjointClear);
112d514b0f3Smrg	C(DisjointSrc);
113d514b0f3Smrg	C(DisjointDst);
114d514b0f3Smrg	C(DisjointOver);
115d514b0f3Smrg	C(DisjointOverReverse);
116d514b0f3Smrg	C(DisjointIn);
117d514b0f3Smrg	C(DisjointInReverse);
118d514b0f3Smrg	C(DisjointOut);
119d514b0f3Smrg	C(DisjointOutReverse);
120d514b0f3Smrg	C(DisjointAtop);
121d514b0f3Smrg	C(DisjointAtopReverse);
122d514b0f3Smrg	C(DisjointXor);
123d514b0f3Smrg
124d514b0f3Smrg	C(ConjointClear);
125d514b0f3Smrg	C(ConjointSrc);
126d514b0f3Smrg	C(ConjointDst);
127d514b0f3Smrg	C(ConjointOver);
128d514b0f3Smrg	C(ConjointOverReverse);
129d514b0f3Smrg	C(ConjointIn);
130d514b0f3Smrg	C(ConjointInReverse);
131d514b0f3Smrg	C(ConjointOut);
132d514b0f3Smrg	C(ConjointOutReverse);
133d514b0f3Smrg	C(ConjointAtop);
134d514b0f3Smrg	C(ConjointAtopReverse);
135d514b0f3Smrg	C(ConjointXor);
136d514b0f3Smrg
137d514b0f3Smrg	/*
138d514b0f3Smrg	 * Operators only available in version 0.11
139d514b0f3Smrg	 */
140d514b0f3Smrg	C(Multiply);
141d514b0f3Smrg	C(Screen);
142d514b0f3Smrg	C(Overlay);
143d514b0f3Smrg	C(Darken);
144d514b0f3Smrg	C(Lighten);
145d514b0f3Smrg	C(ColorDodge);
146d514b0f3Smrg	C(ColorBurn);
147d514b0f3Smrg	C(HardLight);
148d514b0f3Smrg	C(SoftLight);
149d514b0f3Smrg	C(Difference);
150d514b0f3Smrg	C(Exclusion);
151d514b0f3Smrg	C(HSLHue);
152d514b0f3Smrg	C(HSLSaturation);
153d514b0f3Smrg	C(HSLColor);
154d514b0f3Smrg	C(HSLLuminosity);
155d514b0f3Smrg    default: return "garbage";
156d514b0f3Smrg#undef C
157d514b0f3Smrg    }
158d514b0f3Smrg}
159d514b0f3Smrg
160d514b0f3Smrgstatic void
161d514b0f3Smrguxa_print_composite_fallback(const char *func, CARD8 op,
162d514b0f3Smrg			     PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
163d514b0f3Smrg{
164d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
165d514b0f3Smrg	char srcdesc[40], maskdesc[40], dstdesc[40];
166d514b0f3Smrg
167d514b0f3Smrg	if (! uxa_screen->fallback_debug)
168d514b0f3Smrg		return;
169d514b0f3Smrg
170d514b0f3Smrg	/* Limit the noise if fallbacks are expected. */
171d514b0f3Smrg	if (uxa_screen->force_fallback)
172d514b0f3Smrg		return;
173d514b0f3Smrg
174d514b0f3Smrg	uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40);
175d514b0f3Smrg	uxa_composite_fallback_pict_desc(pMask, maskdesc, 40);
176d514b0f3Smrg	uxa_composite_fallback_pict_desc(pDst, dstdesc, 40);
177d514b0f3Smrg
178d514b0f3Smrg	ErrorF("Composite fallback at %s:\n"
179d514b0f3Smrg	       "  op   %s, \n"
180d514b0f3Smrg	       "  src  %s, \n"
181d514b0f3Smrg	       "  mask %s, \n"
182d514b0f3Smrg	       "  dst  %s, \n"
183d514b0f3Smrg	       "  screen %s\n",
184d514b0f3Smrg	       func, op_to_string (op), srcdesc, maskdesc, dstdesc,
185d514b0f3Smrg	       uxa_screen->swappedOut ? "swapped out" : "normal");
186d514b0f3Smrg}
187d514b0f3Smrg
188d514b0f3SmrgBool uxa_op_reads_destination(CARD8 op)
189d514b0f3Smrg{
190d514b0f3Smrg	/* FALSE (does not read destination) is the list of ops in the protocol
191d514b0f3Smrg	 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
192d514b0f3Smrg	 * That's just Clear and Src.  ReduceCompositeOp() will already have
193d514b0f3Smrg	 * converted con/disjoint clear/src to Clear or Src.
194d514b0f3Smrg	 */
195d514b0f3Smrg	switch (op) {
196d514b0f3Smrg	case PictOpClear:
197d514b0f3Smrg	case PictOpSrc:
198d514b0f3Smrg		return FALSE;
199d514b0f3Smrg	default:
200d514b0f3Smrg		return TRUE;
201d514b0f3Smrg	}
202d514b0f3Smrg}
203d514b0f3Smrg
204d514b0f3Smrgstatic Bool
205d514b0f3Smrguxa_get_pixel_from_rgba(CARD32 * pixel,
206d514b0f3Smrg			CARD16 red,
207d514b0f3Smrg			CARD16 green,
208d514b0f3Smrg			CARD16 blue,
209d514b0f3Smrg			CARD16 alpha,
210d514b0f3Smrg			CARD32 format)
211d514b0f3Smrg{
212d514b0f3Smrg	int rbits, bbits, gbits, abits;
213d514b0f3Smrg	int rshift, bshift, gshift, ashift;
214d514b0f3Smrg
215d514b0f3Smrg	rbits = PICT_FORMAT_R(format);
216d514b0f3Smrg	gbits = PICT_FORMAT_G(format);
217d514b0f3Smrg	bbits = PICT_FORMAT_B(format);
218d514b0f3Smrg	abits = PICT_FORMAT_A(format);
219d514b0f3Smrg	if (abits == 0)
220d514b0f3Smrg	    abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
221d514b0f3Smrg
222d514b0f3Smrg	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
223d514b0f3Smrg		*pixel = alpha >> (16 - abits);
224d514b0f3Smrg		return TRUE;
225d514b0f3Smrg	}
226d514b0f3Smrg
227d514b0f3Smrg	if (!PICT_FORMAT_COLOR(format))
228d514b0f3Smrg		return FALSE;
229d514b0f3Smrg
230d514b0f3Smrg	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
231d514b0f3Smrg		bshift = 0;
232d514b0f3Smrg		gshift = bbits;
233d514b0f3Smrg		rshift = gshift + gbits;
234d514b0f3Smrg		ashift = rshift + rbits;
235d514b0f3Smrg	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
236d514b0f3Smrg		rshift = 0;
237d514b0f3Smrg		gshift = rbits;
238d514b0f3Smrg		bshift = gshift + gbits;
239d514b0f3Smrg		ashift = bshift + bbits;
240d514b0f3Smrg	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
241d514b0f3Smrg		ashift = 0;
242d514b0f3Smrg		rshift = abits;
243d514b0f3Smrg		gshift = rshift + rbits;
244d514b0f3Smrg		bshift = gshift + gbits;
245d514b0f3Smrg	} else {
246d514b0f3Smrg		return FALSE;
247d514b0f3Smrg	}
248d514b0f3Smrg
249d514b0f3Smrg	*pixel = 0;
250d514b0f3Smrg	*pixel |= (blue  >> (16 - bbits)) << bshift;
251d514b0f3Smrg	*pixel |= (green >> (16 - gbits)) << gshift;
252d514b0f3Smrg	*pixel |= (red   >> (16 - rbits)) << rshift;
253d514b0f3Smrg	*pixel |= (alpha >> (16 - abits)) << ashift;
254d514b0f3Smrg
255d514b0f3Smrg	return TRUE;
256d514b0f3Smrg}
257d514b0f3Smrg
258d514b0f3SmrgBool
259d514b0f3Smrguxa_get_rgba_from_pixel(CARD32 pixel,
260d514b0f3Smrg			CARD16 * red,
261d514b0f3Smrg			CARD16 * green,
262d514b0f3Smrg			CARD16 * blue,
263d514b0f3Smrg			CARD16 * alpha,
264d514b0f3Smrg			CARD32 format)
265d514b0f3Smrg{
266d514b0f3Smrg	int rbits, bbits, gbits, abits;
267d514b0f3Smrg	int rshift, bshift, gshift, ashift;
268d514b0f3Smrg
269d514b0f3Smrg	rbits = PICT_FORMAT_R(format);
270d514b0f3Smrg	gbits = PICT_FORMAT_G(format);
271d514b0f3Smrg	bbits = PICT_FORMAT_B(format);
272d514b0f3Smrg	abits = PICT_FORMAT_A(format);
273d514b0f3Smrg
274d514b0f3Smrg	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
275d514b0f3Smrg		rshift = gshift = bshift = ashift = 0;
276d514b0f3Smrg        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
277d514b0f3Smrg		bshift = 0;
278d514b0f3Smrg		gshift = bbits;
279d514b0f3Smrg		rshift = gshift + gbits;
280d514b0f3Smrg		ashift = rshift + rbits;
281d514b0f3Smrg        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
282d514b0f3Smrg		rshift = 0;
283d514b0f3Smrg		gshift = rbits;
284d514b0f3Smrg		bshift = gshift + gbits;
285d514b0f3Smrg		ashift = bshift + bbits;
286d514b0f3Smrg        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
287d514b0f3Smrg		ashift = 0;
288d514b0f3Smrg		rshift = abits;
289d514b0f3Smrg		if (abits == 0)
290d514b0f3Smrg			rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
291d514b0f3Smrg		gshift = rshift + rbits;
292d514b0f3Smrg		bshift = gshift + gbits;
293d514b0f3Smrg	} else {
294d514b0f3Smrg		return FALSE;
295d514b0f3Smrg	}
296d514b0f3Smrg
297d514b0f3Smrg	if (rbits) {
298d514b0f3Smrg		*red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
299d514b0f3Smrg		while (rbits < 16) {
300d514b0f3Smrg			*red |= *red >> rbits;
301d514b0f3Smrg			rbits <<= 1;
302d514b0f3Smrg		}
303d514b0f3Smrg	} else
304d514b0f3Smrg		*red = 0;
305d514b0f3Smrg
306d514b0f3Smrg	if (gbits) {
307d514b0f3Smrg		*green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
308d514b0f3Smrg		while (gbits < 16) {
309d514b0f3Smrg			*green |= *green >> gbits;
310d514b0f3Smrg			gbits <<= 1;
311d514b0f3Smrg		}
312d514b0f3Smrg	} else
313d514b0f3Smrg		*green = 0;
314d514b0f3Smrg
315d514b0f3Smrg	if (bbits) {
316d514b0f3Smrg		*blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
317d514b0f3Smrg		while (bbits < 16) {
318d514b0f3Smrg			*blue |= *blue >> bbits;
319d514b0f3Smrg			bbits <<= 1;
320d514b0f3Smrg		}
321d514b0f3Smrg	} else
322d514b0f3Smrg		*blue = 0;
323d514b0f3Smrg
324d514b0f3Smrg	if (abits) {
325d514b0f3Smrg		*alpha =
326d514b0f3Smrg		    ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
327d514b0f3Smrg		while (abits < 16) {
328d514b0f3Smrg			*alpha |= *alpha >> abits;
329d514b0f3Smrg			abits <<= 1;
330d514b0f3Smrg		}
331d514b0f3Smrg	} else
332d514b0f3Smrg		*alpha = 0xffff;
333d514b0f3Smrg
334d514b0f3Smrg	return TRUE;
335d514b0f3Smrg}
336d514b0f3Smrg
337d514b0f3SmrgBool
338d514b0f3Smrguxa_get_color_for_pixmap (PixmapPtr	 pixmap,
339d514b0f3Smrg			  CARD32	 src_format,
340d514b0f3Smrg			  CARD32	 dst_format,
341d514b0f3Smrg			  CARD32	*pixel)
342d514b0f3Smrg{
343d514b0f3Smrg	CARD16 red, green, blue, alpha;
344d514b0f3Smrg
345d514b0f3Smrg	*pixel = uxa_get_pixmap_first_pixel(pixmap);
346d514b0f3Smrg
347d514b0f3Smrg	if (src_format != dst_format) {
348d514b0f3Smrg	    if (!uxa_get_rgba_from_pixel(*pixel,
349d514b0f3Smrg					 &red, &green, &blue, &alpha,
350d514b0f3Smrg					 src_format))
351d514b0f3Smrg		return FALSE;
352d514b0f3Smrg
353d514b0f3Smrg	    if (!uxa_get_pixel_from_rgba(pixel,
354d514b0f3Smrg					 red, green, blue, alpha,
355d514b0f3Smrg					 dst_format))
356d514b0f3Smrg		return FALSE;
357d514b0f3Smrg	}
358d514b0f3Smrg
359d514b0f3Smrg	return TRUE;
360d514b0f3Smrg}
361d514b0f3Smrg
362d514b0f3Smrgstatic int
363d514b0f3Smrguxa_try_driver_solid_fill(PicturePtr pSrc,
364d514b0f3Smrg			  PicturePtr pDst,
365d514b0f3Smrg			  INT16 xSrc,
366d514b0f3Smrg			  INT16 ySrc,
367d514b0f3Smrg			  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
368d514b0f3Smrg{
369d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
370d514b0f3Smrg	RegionRec region;
371d514b0f3Smrg	BoxPtr pbox;
372d514b0f3Smrg	int nbox;
373d514b0f3Smrg	int dst_off_x, dst_off_y;
374d514b0f3Smrg	PixmapPtr pSrcPix = NULL, pDstPix;
375d514b0f3Smrg	CARD32 pixel;
376d514b0f3Smrg
377d514b0f3Smrg	if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES))
378d514b0f3Smrg		return -1;
379d514b0f3Smrg
380d514b0f3Smrg	pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
381d514b0f3Smrg	if (!pDstPix)
382d514b0f3Smrg		return -1;
383d514b0f3Smrg
384d514b0f3Smrg	xDst += pDst->pDrawable->x;
385d514b0f3Smrg	yDst += pDst->pDrawable->y;
386d514b0f3Smrg
387d514b0f3Smrg	if (pSrc->pDrawable) {
388d514b0f3Smrg		pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
389d514b0f3Smrg		xSrc += pSrc->pDrawable->x;
390d514b0f3Smrg		ySrc += pSrc->pDrawable->y;
391d514b0f3Smrg	}
392d514b0f3Smrg
393d514b0f3Smrg	if (!miComputeCompositeRegion(&region, pSrc, NULL, pDst,
394d514b0f3Smrg				      xSrc, ySrc, 0, 0, xDst, yDst,
395d514b0f3Smrg				      width, height))
396d514b0f3Smrg		return 1;
397d514b0f3Smrg
398d514b0f3Smrg	if (pSrcPix) {
399d514b0f3Smrg		if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) {
400d514b0f3Smrg			REGION_UNINIT(pDst->pDrawable->pScreen, &region);
401d514b0f3Smrg			return -1;
402d514b0f3Smrg		}
403d514b0f3Smrg	} else {
404d514b0f3Smrg		SourcePict *source = pSrc->pSourcePict;
405d514b0f3Smrg		PictSolidFill *solid = &source->solidFill;
406d514b0f3Smrg
407d514b0f3Smrg		if (source == NULL || source->type != SourcePictTypeSolidFill) {
408d514b0f3Smrg			REGION_UNINIT(pDst->pDrawable->pScreen, &region);
409d514b0f3Smrg			return -1;
410d514b0f3Smrg		}
411d514b0f3Smrg
412d514b0f3Smrg		if (pDst->format == PICT_a8r8g8b8) {
413d514b0f3Smrg			pixel = solid->color;
414d514b0f3Smrg		} else if (pDst->format == PICT_x8r8g8b8) {
415d514b0f3Smrg			pixel = solid->color | 0xff000000;
416d514b0f3Smrg		} else {
417d514b0f3Smrg			CARD16 red, green, blue, alpha;
418d514b0f3Smrg
419d514b0f3Smrg			if (!uxa_get_rgba_from_pixel(solid->color,
420d514b0f3Smrg						     &red, &green, &blue, &alpha,
421d514b0f3Smrg						     PIXMAN_a8r8g8b8) ||
422d514b0f3Smrg			    !uxa_get_pixel_from_rgba(&pixel,
423d514b0f3Smrg						     red, green, blue, alpha,
424d514b0f3Smrg						     pDst->format)) {
425d514b0f3Smrg				REGION_UNINIT(pDst->pDrawable->pScreen, &region);
426d514b0f3Smrg				return -1;
427d514b0f3Smrg			}
428d514b0f3Smrg		}
429d514b0f3Smrg	}
430d514b0f3Smrg
431d514b0f3Smrg	if (!(*uxa_screen->info->prepare_solid)
432d514b0f3Smrg	    (pDstPix, GXcopy, FB_ALLONES, pixel)) {
433d514b0f3Smrg		REGION_UNINIT(pDst->pDrawable->pScreen, &region);
434d514b0f3Smrg		return -1;
435d514b0f3Smrg	}
436d514b0f3Smrg
437d514b0f3Smrg	REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
438d514b0f3Smrg
439d514b0f3Smrg	nbox = REGION_NUM_RECTS(&region);
440d514b0f3Smrg	pbox = REGION_RECTS(&region);
441d514b0f3Smrg
442d514b0f3Smrg	while (nbox--) {
443d514b0f3Smrg		(*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1,
444d514b0f3Smrg					    pbox->x2, pbox->y2);
445d514b0f3Smrg		pbox++;
446d514b0f3Smrg	}
447d514b0f3Smrg
448d514b0f3Smrg	(*uxa_screen->info->done_solid) (pDstPix);
449d514b0f3Smrg
450d514b0f3Smrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
451d514b0f3Smrg	return 1;
452d514b0f3Smrg}
453d514b0f3Smrg
454d514b0f3Smrgstatic PicturePtr
455d514b0f3Smrguxa_picture_for_pixman_format(ScreenPtr pScreen,
456d514b0f3Smrg			      pixman_format_code_t format,
457d514b0f3Smrg			      int width, int height)
458d514b0f3Smrg{
459d514b0f3Smrg	PicturePtr pPicture;
460d514b0f3Smrg	PixmapPtr pPixmap;
461d514b0f3Smrg	int error;
462d514b0f3Smrg
463d514b0f3Smrg	if (format == PIXMAN_a1)
464d514b0f3Smrg		format = PIXMAN_a8;
465d514b0f3Smrg
466d514b0f3Smrg	/* fill alpha if unset */
467d514b0f3Smrg	if (PIXMAN_FORMAT_A(format) == 0)
468d514b0f3Smrg	    format = PIXMAN_a8r8g8b8;
469d514b0f3Smrg
470d514b0f3Smrg	pPixmap = (*pScreen->CreatePixmap)(pScreen, width, height,
471d514b0f3Smrg					   PIXMAN_FORMAT_DEPTH(format),
472d514b0f3Smrg					   UXA_CREATE_PIXMAP_FOR_MAP);
473d514b0f3Smrg	if (!pPixmap)
474d514b0f3Smrg		return 0;
475d514b0f3Smrg
476d514b0f3Smrg	pPicture = CreatePicture(0, &pPixmap->drawable,
477d514b0f3Smrg				 PictureMatchFormat(pScreen,
478d514b0f3Smrg						    PIXMAN_FORMAT_DEPTH(format),
479d514b0f3Smrg						    format),
480d514b0f3Smrg				 0, 0, serverClient, &error);
481d514b0f3Smrg	(*pScreen->DestroyPixmap) (pPixmap);
482d514b0f3Smrg	if (!pPicture)
483d514b0f3Smrg		return 0;
484d514b0f3Smrg
485d514b0f3Smrg	ValidatePicture(pPicture);
486d514b0f3Smrg
487d514b0f3Smrg	return pPicture;
488d514b0f3Smrg}
489d514b0f3Smrg
490d514b0f3Smrgstatic PicturePtr
491d514b0f3Smrguxa_picture_from_pixman_image(ScreenPtr screen,
492d514b0f3Smrg			      pixman_image_t * image,
493d514b0f3Smrg			      pixman_format_code_t format)
494d514b0f3Smrg{
495d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
496d514b0f3Smrg	PicturePtr picture;
497d514b0f3Smrg	PixmapPtr pixmap;
498d514b0f3Smrg	int width, height;
499d514b0f3Smrg
500d514b0f3Smrg	width = pixman_image_get_width(image);
501d514b0f3Smrg	height = pixman_image_get_height(image);
502d514b0f3Smrg
503d514b0f3Smrg	picture = uxa_picture_for_pixman_format(screen, format,
504d514b0f3Smrg						width, height);
505d514b0f3Smrg	if (!picture)
506d514b0f3Smrg		return 0;
507d514b0f3Smrg
508d514b0f3Smrg	if (uxa_screen->info->put_image &&
509d514b0f3Smrg	    ((picture->pDrawable->depth << 24) | picture->format) == format &&
510d514b0f3Smrg	    uxa_screen->info->put_image((PixmapPtr)picture->pDrawable,
511d514b0f3Smrg					0, 0,
512d514b0f3Smrg					width, height,
513d514b0f3Smrg					(char *)pixman_image_get_data(image),
514d514b0f3Smrg					pixman_image_get_stride(image)))
515d514b0f3Smrg		return picture;
516d514b0f3Smrg
517d514b0f3Smrg	pixmap = GetScratchPixmapHeader(screen, width, height,
518d514b0f3Smrg					PIXMAN_FORMAT_DEPTH(format),
519d514b0f3Smrg					PIXMAN_FORMAT_BPP(format),
520d514b0f3Smrg					pixman_image_get_stride(image),
521d514b0f3Smrg					pixman_image_get_data(image));
522d514b0f3Smrg	if (!pixmap) {
523d514b0f3Smrg		FreePicture(picture, 0);
524d514b0f3Smrg		return 0;
525d514b0f3Smrg	}
526d514b0f3Smrg
527d514b0f3Smrg	if (((picture->pDrawable->depth << 24) | picture->format) == format) {
528d514b0f3Smrg		GCPtr gc;
529d514b0f3Smrg
530d514b0f3Smrg		gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen);
531d514b0f3Smrg		if (!gc) {
532d514b0f3Smrg			FreeScratchPixmapHeader(pixmap);
533d514b0f3Smrg			FreePicture(picture, 0);
534d514b0f3Smrg			return 0;
535d514b0f3Smrg		}
536d514b0f3Smrg		ValidateGC(picture->pDrawable, gc);
537d514b0f3Smrg
538d514b0f3Smrg		(*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable,
539d514b0f3Smrg				      gc, 0, 0, width, height, 0, 0);
540d514b0f3Smrg
541d514b0f3Smrg		FreeScratchGC(gc);
542d514b0f3Smrg	} else {
543d514b0f3Smrg		PicturePtr src;
544d514b0f3Smrg		int error;
545d514b0f3Smrg
546d514b0f3Smrg		src = CreatePicture(0, &pixmap->drawable,
547d514b0f3Smrg				    PictureMatchFormat(screen,
548d514b0f3Smrg						       PIXMAN_FORMAT_DEPTH(format),
549d514b0f3Smrg						       format),
550d514b0f3Smrg				    0, 0, serverClient, &error);
551d514b0f3Smrg		if (!src) {
552d514b0f3Smrg			FreeScratchPixmapHeader(pixmap);
553d514b0f3Smrg			FreePicture(picture, 0);
554d514b0f3Smrg			return 0;
555d514b0f3Smrg		}
556d514b0f3Smrg		ValidatePicture(src);
557d514b0f3Smrg
558d514b0f3Smrg		if (uxa_prepare_access(picture->pDrawable, NULL, UXA_ACCESS_RW)) {
559d514b0f3Smrg			fbComposite(PictOpSrc, src, NULL, picture,
560d514b0f3Smrg				    0, 0, 0, 0, 0, 0, width, height);
561d514b0f3Smrg			uxa_finish_access(picture->pDrawable);
562d514b0f3Smrg		}
563d514b0f3Smrg
564d514b0f3Smrg		FreePicture(src, 0);
565d514b0f3Smrg	}
566d514b0f3Smrg	FreeScratchPixmapHeader(pixmap);
567d514b0f3Smrg
568d514b0f3Smrg	return picture;
569d514b0f3Smrg}
570d514b0f3Smrg
571d514b0f3Smrgstatic PicturePtr
572d514b0f3Smrguxa_create_solid(ScreenPtr screen, uint32_t color)
573d514b0f3Smrg{
574d514b0f3Smrg	PixmapPtr pixmap;
575d514b0f3Smrg	PicturePtr picture;
576d514b0f3Smrg	XID repeat = RepeatNormal;
577d514b0f3Smrg	int error = 0;
578d514b0f3Smrg
579d514b0f3Smrg	pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32,
580d514b0f3Smrg					 UXA_CREATE_PIXMAP_FOR_MAP);
581d514b0f3Smrg	if (!pixmap)
582d514b0f3Smrg		return 0;
583d514b0f3Smrg
584d514b0f3Smrg	if (!uxa_prepare_access((DrawablePtr)pixmap, NULL, UXA_ACCESS_RW)) {
585d514b0f3Smrg		(*screen->DestroyPixmap)(pixmap);
586d514b0f3Smrg		return 0;
587d514b0f3Smrg	}
588d514b0f3Smrg	*((uint32_t *)pixmap->devPrivate.ptr) = color;
589d514b0f3Smrg	uxa_finish_access((DrawablePtr)pixmap);
590d514b0f3Smrg
591d514b0f3Smrg	picture = CreatePicture(0, &pixmap->drawable,
592d514b0f3Smrg				PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
593d514b0f3Smrg				CPRepeat, &repeat, serverClient, &error);
594d514b0f3Smrg	(*screen->DestroyPixmap)(pixmap);
595d514b0f3Smrg
596d514b0f3Smrg	return picture;
597d514b0f3Smrg}
598d514b0f3Smrg
599d514b0f3Smrgstatic PicturePtr
600d514b0f3Smrguxa_solid_clear(ScreenPtr screen)
601d514b0f3Smrg{
602d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
603d514b0f3Smrg	PicturePtr picture;
604d514b0f3Smrg
605d514b0f3Smrg	if (!uxa_screen->solid_clear) {
606d514b0f3Smrg		uxa_screen->solid_clear = uxa_create_solid(screen, 0);
607d514b0f3Smrg		if (!uxa_screen->solid_clear)
608d514b0f3Smrg			return 0;
609d514b0f3Smrg	}
610d514b0f3Smrg	picture = uxa_screen->solid_clear;
611d514b0f3Smrg	return picture;
612d514b0f3Smrg}
613d514b0f3Smrg
614d514b0f3SmrgPicturePtr
615d514b0f3Smrguxa_acquire_solid(ScreenPtr screen, SourcePict *source)
616d514b0f3Smrg{
617d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
618d514b0f3Smrg	PictSolidFill *solid = &source->solidFill;
619d514b0f3Smrg	PicturePtr picture;
620d514b0f3Smrg	int i;
621d514b0f3Smrg
622d514b0f3Smrg	if ((solid->color >> 24) == 0) {
623d514b0f3Smrg		picture = uxa_solid_clear(screen);
624d514b0f3Smrg		if (!picture)
625d514b0f3Smrg		    return 0;
626d514b0f3Smrg
627d514b0f3Smrg		goto DONE;
628d514b0f3Smrg	} else if (solid->color == 0xff000000) {
629d514b0f3Smrg		if (!uxa_screen->solid_black) {
630d514b0f3Smrg			uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000);
631d514b0f3Smrg			if (!uxa_screen->solid_black)
632d514b0f3Smrg				return 0;
633d514b0f3Smrg		}
634d514b0f3Smrg		picture = uxa_screen->solid_black;
635d514b0f3Smrg		goto DONE;
636d514b0f3Smrg	} else if (solid->color == 0xffffffff) {
637d514b0f3Smrg		if (!uxa_screen->solid_white) {
638d514b0f3Smrg			uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff);
639d514b0f3Smrg			if (!uxa_screen->solid_white)
640d514b0f3Smrg				return 0;
641d514b0f3Smrg		}
642d514b0f3Smrg		picture = uxa_screen->solid_white;
643d514b0f3Smrg		goto DONE;
644d514b0f3Smrg	}
645d514b0f3Smrg
646d514b0f3Smrg	for (i = 0; i < uxa_screen->solid_cache_size; i++) {
647d514b0f3Smrg		if (uxa_screen->solid_cache[i].color == solid->color) {
648d514b0f3Smrg			picture = uxa_screen->solid_cache[i].picture;
649d514b0f3Smrg			goto DONE;
650d514b0f3Smrg		}
651d514b0f3Smrg	}
652d514b0f3Smrg
653d514b0f3Smrg	picture = uxa_create_solid(screen, solid->color);
654d514b0f3Smrg	if (!picture)
655d514b0f3Smrg		return 0;
656d514b0f3Smrg
657d514b0f3Smrg	if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) {
658d514b0f3Smrg		i = rand() % UXA_NUM_SOLID_CACHE;
659d514b0f3Smrg		FreePicture(uxa_screen->solid_cache[i].picture, 0);
660d514b0f3Smrg	} else
661d514b0f3Smrg		uxa_screen->solid_cache_size++;
662d514b0f3Smrg
663d514b0f3Smrg	uxa_screen->solid_cache[i].picture = picture;
664d514b0f3Smrg	uxa_screen->solid_cache[i].color = solid->color;
665d514b0f3Smrg
666d514b0f3SmrgDONE:
667d514b0f3Smrg	picture->refcnt++;
668d514b0f3Smrg	return picture;
669d514b0f3Smrg}
670d514b0f3Smrg
671d514b0f3SmrgPicturePtr
672d514b0f3Smrguxa_acquire_pattern(ScreenPtr pScreen,
673d514b0f3Smrg		    PicturePtr pSrc,
674d514b0f3Smrg		    pixman_format_code_t format,
675d514b0f3Smrg		    INT16 x, INT16 y, CARD16 width, CARD16 height)
676d514b0f3Smrg{
677d514b0f3Smrg	PicturePtr pDst;
678d514b0f3Smrg
679d514b0f3Smrg	if (pSrc->pSourcePict) {
680d514b0f3Smrg		SourcePict *source = pSrc->pSourcePict;
681d514b0f3Smrg		if (source->type == SourcePictTypeSolidFill)
682d514b0f3Smrg			return uxa_acquire_solid (pScreen, source);
683d514b0f3Smrg	}
684d514b0f3Smrg
685d514b0f3Smrg	pDst = uxa_picture_for_pixman_format(pScreen, format, width, height);
686d514b0f3Smrg	if (!pDst)
687d514b0f3Smrg		return 0;
688d514b0f3Smrg
689d514b0f3Smrg	if (uxa_prepare_access(pDst->pDrawable, NULL, UXA_ACCESS_RW)) {
690d514b0f3Smrg		fbComposite(PictOpSrc, pSrc, NULL, pDst,
691d514b0f3Smrg			    x, y, 0, 0, 0, 0, width, height);
692d514b0f3Smrg		uxa_finish_access(pDst->pDrawable);
693d514b0f3Smrg		return pDst;
694d514b0f3Smrg	} else {
695d514b0f3Smrg		FreePicture(pDst, 0);
696d514b0f3Smrg		return 0;
697d514b0f3Smrg	}
698d514b0f3Smrg}
699d514b0f3Smrg
700d514b0f3Smrgstatic Bool
701d514b0f3Smrgtransform_is_integer_translation(PictTransformPtr t, int *tx, int *ty)
702d514b0f3Smrg{
703d514b0f3Smrg	if (t == NULL) {
704d514b0f3Smrg		*tx = *ty = 0;
705d514b0f3Smrg		return TRUE;
706d514b0f3Smrg	}
707d514b0f3Smrg
708d514b0f3Smrg	if (t->matrix[0][0] != IntToxFixed(1) ||
709d514b0f3Smrg	    t->matrix[0][1] != 0 ||
710d514b0f3Smrg	    t->matrix[1][0] != 0 ||
711d514b0f3Smrg	    t->matrix[1][1] != IntToxFixed(1) ||
712d514b0f3Smrg	    t->matrix[2][0] != 0 ||
713d514b0f3Smrg	    t->matrix[2][1] != 0 ||
714d514b0f3Smrg	    t->matrix[2][2] != IntToxFixed(1))
715d514b0f3Smrg		return FALSE;
716d514b0f3Smrg
717d514b0f3Smrg	if (xFixedFrac(t->matrix[0][2]) != 0 ||
718d514b0f3Smrg	    xFixedFrac(t->matrix[1][2]) != 0)
719d514b0f3Smrg		return FALSE;
720d514b0f3Smrg
721d514b0f3Smrg	*tx = xFixedToInt(t->matrix[0][2]);
722d514b0f3Smrg	*ty = xFixedToInt(t->matrix[1][2]);
723d514b0f3Smrg	return TRUE;
724d514b0f3Smrg}
725d514b0f3Smrg
726d514b0f3Smrgstatic PicturePtr
727d514b0f3Smrguxa_render_picture(ScreenPtr screen,
728d514b0f3Smrg		   PicturePtr src,
729d514b0f3Smrg		   pixman_format_code_t format,
730d514b0f3Smrg		   INT16 x, INT16 y,
731d514b0f3Smrg		   CARD16 width, CARD16 height)
732d514b0f3Smrg{
733d514b0f3Smrg	PicturePtr picture;
734d514b0f3Smrg	int ret = 0;
735d514b0f3Smrg
736d514b0f3Smrg	/* XXX we need a mechanism for the card to choose the fallback format */
737d514b0f3Smrg
738d514b0f3Smrg	/* force alpha channel in case source does not entirely cover the extents */
739d514b0f3Smrg	if (PIXMAN_FORMAT_A(format) == 0)
740d514b0f3Smrg		format = PIXMAN_a8r8g8b8; /* available on all hardware */
741d514b0f3Smrg
742d514b0f3Smrg	picture = uxa_picture_for_pixman_format(screen, format, width, height);
743d514b0f3Smrg	if (!picture)
744d514b0f3Smrg		return 0;
745d514b0f3Smrg
746d514b0f3Smrg	if (uxa_prepare_access(picture->pDrawable, NULL, UXA_ACCESS_RW)) {
747d514b0f3Smrg	    if (uxa_prepare_access(src->pDrawable, NULL, UXA_ACCESS_RO)) {
748d514b0f3Smrg			ret = 1;
749d514b0f3Smrg			fbComposite(PictOpSrc, src, NULL, picture,
750d514b0f3Smrg				    x, y, 0, 0, 0, 0, width, height);
751d514b0f3Smrg			uxa_finish_access(src->pDrawable);
752d514b0f3Smrg		}
753d514b0f3Smrg		uxa_finish_access(picture->pDrawable);
754d514b0f3Smrg	}
755d514b0f3Smrg
756d514b0f3Smrg	if (!ret) {
757d514b0f3Smrg		FreePicture(picture, 0);
758d514b0f3Smrg		return 0;
759d514b0f3Smrg	}
760d514b0f3Smrg
761d514b0f3Smrg	return picture;
762d514b0f3Smrg}
763d514b0f3Smrg
764d514b0f3SmrgPicturePtr
765d514b0f3Smrguxa_acquire_drawable(ScreenPtr pScreen,
766d514b0f3Smrg		     PicturePtr pSrc,
767d514b0f3Smrg		     INT16 x, INT16 y,
768d514b0f3Smrg		     CARD16 width, CARD16 height,
769d514b0f3Smrg		     INT16 * out_x, INT16 * out_y)
770d514b0f3Smrg{
771d514b0f3Smrg	PixmapPtr pPixmap;
772d514b0f3Smrg	PicturePtr pDst;
773d514b0f3Smrg	GCPtr pGC;
774d514b0f3Smrg	int depth, error;
775d514b0f3Smrg	int tx, ty;
776d514b0f3Smrg
777d514b0f3Smrg	depth = pSrc->pDrawable->depth;
778d514b0f3Smrg	if (depth == 1 ||
779d514b0f3Smrg	    pSrc->filter == PictFilterConvolution || /* XXX */
780d514b0f3Smrg	    !transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
781d514b0f3Smrg		/* XXX extract the sample extents and do the transformation on the GPU */
782d514b0f3Smrg		pDst = uxa_render_picture(pScreen, pSrc,
783d514b0f3Smrg					  pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24),
784d514b0f3Smrg					  x, y, width, height);
785d514b0f3Smrg
786d514b0f3Smrg		goto done;
787d514b0f3Smrg	} else {
788d514b0f3Smrg		if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->depth) {
789d514b0f3Smrg			*out_x = x + pSrc->pDrawable->x;
790d514b0f3Smrg			*out_y = y + pSrc->pDrawable->y;
791d514b0f3Smrg			return pSrc;
792d514b0f3Smrg		}
793d514b0f3Smrg	}
794d514b0f3Smrg
795d514b0f3Smrg	pPixmap = pScreen->CreatePixmap(pScreen,
796d514b0f3Smrg					width, height, depth,
797d514b0f3Smrg					CREATE_PIXMAP_USAGE_SCRATCH);
798d514b0f3Smrg	if (!pPixmap)
799d514b0f3Smrg		return 0;
800d514b0f3Smrg
801d514b0f3Smrg	/* Skip the copy if the result remains in memory and not a bo */
802d514b0f3Smrg	if (!uxa_drawable_is_offscreen(&pPixmap->drawable)) {
803d514b0f3Smrg		pScreen->DestroyPixmap(pPixmap);
804d514b0f3Smrg		return 0;
805d514b0f3Smrg	}
806d514b0f3Smrg
807d514b0f3Smrg	pGC = GetScratchGC(depth, pScreen);
808d514b0f3Smrg	if (!pGC) {
809d514b0f3Smrg		pScreen->DestroyPixmap(pPixmap);
810d514b0f3Smrg		return 0;
811d514b0f3Smrg	}
812d514b0f3Smrg
813d514b0f3Smrg	ValidateGC(&pPixmap->drawable, pGC);
814d514b0f3Smrg	pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC,
815d514b0f3Smrg			   x + tx, y + ty, width, height, 0, 0);
816d514b0f3Smrg	FreeScratchGC(pGC);
817d514b0f3Smrg
818d514b0f3Smrg	pDst = CreatePicture(0, &pPixmap->drawable,
819d514b0f3Smrg				 PictureMatchFormat(pScreen, depth, pSrc->format),
820d514b0f3Smrg				 0, 0, serverClient, &error);
821d514b0f3Smrg	pScreen->DestroyPixmap(pPixmap);
822d514b0f3Smrg	ValidatePicture(pDst);
823d514b0f3Smrg
824d514b0f3Smrgdone:
825d514b0f3Smrg	pDst->componentAlpha = pSrc->componentAlpha;
826d514b0f3Smrg	*out_x = x;
827d514b0f3Smrg	*out_y = y;
828d514b0f3Smrg	return pDst;
829d514b0f3Smrg}
830d514b0f3Smrg
831d514b0f3Smrgstatic PicturePtr
832d514b0f3Smrguxa_acquire_picture(ScreenPtr screen,
833d514b0f3Smrg		    PicturePtr src,
834d514b0f3Smrg		    pixman_format_code_t format,
835d514b0f3Smrg		    INT16 x, INT16 y,
836d514b0f3Smrg		    CARD16 width, CARD16 height,
837d514b0f3Smrg		    INT16 * out_x, INT16 * out_y)
838d514b0f3Smrg{
839d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
840d514b0f3Smrg
841d514b0f3Smrg	if (uxa_screen->info->check_composite_texture &&
842d514b0f3Smrg	    uxa_screen->info->check_composite_texture(screen, src)) {
843d514b0f3Smrg		if (src->pDrawable) {
844d514b0f3Smrg			*out_x = x + src->pDrawable->x;
845d514b0f3Smrg			*out_y = y + src->pDrawable->y;
846d514b0f3Smrg		} else {
847d514b0f3Smrg			*out_x = 0;
848d514b0f3Smrg			*out_y = 0;
849d514b0f3Smrg		}
850d514b0f3Smrg		return src;
851d514b0f3Smrg	}
852d514b0f3Smrg
853d514b0f3Smrg	if (src->pDrawable) {
854d514b0f3Smrg		PicturePtr dst;
855d514b0f3Smrg
856d514b0f3Smrg		dst = uxa_acquire_drawable(screen, src,
857d514b0f3Smrg					   x, y, width, height,
858d514b0f3Smrg					   out_x, out_y);
859d514b0f3Smrg		if (uxa_screen->info->check_composite_texture &&
860d514b0f3Smrg		    !uxa_screen->info->check_composite_texture(screen, dst)) {
861d514b0f3Smrg			if (dst != src)
862d514b0f3Smrg				FreePicture(dst, 0);
863d514b0f3Smrg			return 0;
864d514b0f3Smrg		}
865d514b0f3Smrg
866d514b0f3Smrg		return dst;
867d514b0f3Smrg	}
868d514b0f3Smrg
869d514b0f3Smrg	*out_x = 0;
870d514b0f3Smrg	*out_y = 0;
871d514b0f3Smrg	return uxa_acquire_pattern(screen, src,
872d514b0f3Smrg				   format, x, y, width, height);
873d514b0f3Smrg}
874d514b0f3Smrg
875d514b0f3Smrgstatic PicturePtr
876d514b0f3Smrguxa_acquire_source(ScreenPtr screen,
877d514b0f3Smrg		   PicturePtr pict,
878d514b0f3Smrg		   INT16 x, INT16 y,
879d514b0f3Smrg		   CARD16 width, CARD16 height,
880d514b0f3Smrg		   INT16 * out_x, INT16 * out_y)
881d514b0f3Smrg{
882d514b0f3Smrg	return uxa_acquire_picture (screen, pict,
883d514b0f3Smrg				    PIXMAN_a8r8g8b8,
884d514b0f3Smrg				    x, y,
885d514b0f3Smrg				    width, height,
886d514b0f3Smrg				    out_x, out_y);
887d514b0f3Smrg}
888d514b0f3Smrg
889d514b0f3Smrgstatic PicturePtr
890d514b0f3Smrguxa_acquire_mask(ScreenPtr screen,
891d514b0f3Smrg		 PicturePtr pict,
892d514b0f3Smrg		 INT16 x, INT16 y,
893d514b0f3Smrg		 INT16 width, INT16 height,
894d514b0f3Smrg		 INT16 * out_x, INT16 * out_y)
895d514b0f3Smrg{
896d514b0f3Smrg	return uxa_acquire_picture (screen, pict,
897d514b0f3Smrg				    PIXMAN_a8,
898d514b0f3Smrg				    x, y,
899d514b0f3Smrg				    width, height,
900d514b0f3Smrg				    out_x, out_y);
901d514b0f3Smrg}
902d514b0f3Smrg
903d514b0f3Smrgstatic Bool
904d514b0f3Smrg_pixman_region_init_rectangles(pixman_region16_t *region,
905d514b0f3Smrg			       int num_rects,
906d514b0f3Smrg			       xRectangle *rects,
907d514b0f3Smrg			       int tx, int ty)
908d514b0f3Smrg{
909d514b0f3Smrg	pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
910d514b0f3Smrg	pixman_bool_t ret;
911d514b0f3Smrg	int i;
912d514b0f3Smrg
913d514b0f3Smrg	if (num_rects > sizeof(stack_boxes) / sizeof(stack_boxes[0])) {
914d514b0f3Smrg		boxes = malloc(sizeof(pixman_box16_t) * num_rects);
915d514b0f3Smrg		if (boxes == NULL)
916d514b0f3Smrg			return FALSE;
917d514b0f3Smrg	}
918d514b0f3Smrg
919d514b0f3Smrg	for (i = 0; i < num_rects; i++) {
920d514b0f3Smrg		boxes[i].x1 = rects[i].x + tx;
921d514b0f3Smrg		boxes[i].y1 = rects[i].y + ty;
922d514b0f3Smrg		boxes[i].x2 = rects[i].x + tx + rects[i].width;
923d514b0f3Smrg		boxes[i].y2 = rects[i].y + ty + rects[i].height;
924d514b0f3Smrg	}
925d514b0f3Smrg
926d514b0f3Smrg	ret = pixman_region_init_rects(region, boxes, num_rects);
927d514b0f3Smrg
928d514b0f3Smrg	if (boxes != stack_boxes)
929d514b0f3Smrg		free(boxes);
930d514b0f3Smrg
931d514b0f3Smrg	return ret;
932d514b0f3Smrg}
933d514b0f3Smrg
934d514b0f3Smrgvoid
935d514b0f3Smrguxa_solid_rects (CARD8		op,
936d514b0f3Smrg		 PicturePtr	dst,
937d514b0f3Smrg		 xRenderColor  *color,
938d514b0f3Smrg		 int		num_rects,
939d514b0f3Smrg		 xRectangle    *rects)
940d514b0f3Smrg{
941d514b0f3Smrg	ScreenPtr screen = dst->pDrawable->pScreen;
942d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
943d514b0f3Smrg	PixmapPtr dst_pixmap, src_pixmap = NULL;
944d514b0f3Smrg	pixman_region16_t region;
945d514b0f3Smrg	pixman_box16_t *boxes, *extents;
946d514b0f3Smrg	PicturePtr src;
947d514b0f3Smrg	int dst_x, dst_y;
948d514b0f3Smrg	int num_boxes;
949d514b0f3Smrg
950d514b0f3Smrg	if (!pixman_region_not_empty(dst->pCompositeClip))
951d514b0f3Smrg		return;
952d514b0f3Smrg
953d514b0f3Smrg	if (dst->alphaMap)
954d514b0f3Smrg		goto fallback;
955d514b0f3Smrg
956d514b0f3Smrg	dst_pixmap = uxa_get_offscreen_pixmap(dst->pDrawable, &dst_x, &dst_y);
957d514b0f3Smrg	if (!dst_pixmap)
958d514b0f3Smrg		goto fallback;
959d514b0f3Smrg
960d514b0f3Smrg	if (!_pixman_region_init_rectangles(&region,
961d514b0f3Smrg					    num_rects, rects,
962d514b0f3Smrg					    dst->pDrawable->x, dst->pDrawable->y))
963d514b0f3Smrg		goto fallback;
964d514b0f3Smrg
965d514b0f3Smrg	if (!pixman_region_intersect(&region, &region, dst->pCompositeClip)) {
966d514b0f3Smrg		pixman_region_fini(&region);
967d514b0f3Smrg		return;
968d514b0f3Smrg	}
969d514b0f3Smrg
970d514b0f3Smrg	/* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must
971d514b0f3Smrg	 * manually append the damaged regions ourselves.
972d514b0f3Smrg	 */
973d514b0f3Smrg	DamageRegionAppend(dst->pDrawable, &region);
974d514b0f3Smrg
975d514b0f3Smrg	pixman_region_translate(&region, dst_x, dst_y);
976d514b0f3Smrg	boxes = pixman_region_rectangles(&region, &num_boxes);
977d514b0f3Smrg	extents = pixman_region_extents (&region);
978d514b0f3Smrg
979d514b0f3Smrg	if (op == PictOpClear)
980d514b0f3Smrg		color->red = color->green = color->blue = color->alpha = 0;
981d514b0f3Smrg	if (color->alpha >= 0xff00 && op == PictOpOver) {
982d514b0f3Smrg		color->alpha = 0xffff;
983d514b0f3Smrg		op = PictOpSrc;
984d514b0f3Smrg	}
985d514b0f3Smrg
986d514b0f3Smrg	/* Using GEM, the relocation costs outweigh the advantages of the blitter */
987d514b0f3Smrg	if (num_boxes == 1 && (op == PictOpSrc || op == PictOpClear)) {
988d514b0f3Smrg		CARD32 pixel;
989d514b0f3Smrg
990d514b0f3Smrgtry_solid:
991d514b0f3Smrg		if (uxa_screen->info->check_solid &&
992d514b0f3Smrg		    !uxa_screen->info->check_solid(&dst_pixmap->drawable, GXcopy, FB_ALLONES))
993d514b0f3Smrg			goto err_region;
994d514b0f3Smrg
995d514b0f3Smrg		if (!uxa_get_pixel_from_rgba(&pixel,
996d514b0f3Smrg					     color->red,
997d514b0f3Smrg					     color->green,
998d514b0f3Smrg					     color->blue,
999d514b0f3Smrg					     color->alpha,
1000d514b0f3Smrg					     dst->format))
1001d514b0f3Smrg			goto err_region;
1002d514b0f3Smrg
1003d514b0f3Smrg		if (!uxa_screen->info->prepare_solid(dst_pixmap, GXcopy, FB_ALLONES, pixel))
1004d514b0f3Smrg			goto err_region;
1005d514b0f3Smrg
1006d514b0f3Smrg		while (num_boxes--) {
1007d514b0f3Smrg			uxa_screen->info->solid(dst_pixmap,
1008d514b0f3Smrg						boxes->x1, boxes->y1,
1009d514b0f3Smrg						boxes->x2, boxes->y2);
1010d514b0f3Smrg			boxes++;
1011d514b0f3Smrg		}
1012d514b0f3Smrg
1013d514b0f3Smrg		uxa_screen->info->done_solid(dst_pixmap);
1014d514b0f3Smrg	} else {
1015d514b0f3Smrg		int error;
1016d514b0f3Smrg
1017d514b0f3Smrg		src = CreateSolidPicture(0, color, &error);
1018d514b0f3Smrg		if (!src)
1019d514b0f3Smrg			goto err_region;
1020d514b0f3Smrg
1021d514b0f3Smrg		if (!uxa_screen->info->check_composite(op, src, NULL, dst,
1022d514b0f3Smrg						       extents->x2 - extents->x1,
1023d514b0f3Smrg						       extents->y2 - extents->y1)) {
1024d514b0f3Smrg			if (op == PictOpSrc || op == PictOpClear) {
1025d514b0f3Smrg				FreePicture(src, 0);
1026d514b0f3Smrg				goto try_solid;
1027d514b0f3Smrg			}
1028d514b0f3Smrg
1029d514b0f3Smrg			goto err_src;
1030d514b0f3Smrg		}
1031d514b0f3Smrg
1032d514b0f3Smrg		if (!uxa_screen->info->check_composite_texture ||
1033d514b0f3Smrg		    !uxa_screen->info->check_composite_texture(screen, src)) {
1034d514b0f3Smrg			PicturePtr solid;
1035d514b0f3Smrg			int src_off_x, src_off_y;
1036d514b0f3Smrg
1037d514b0f3Smrg			solid = uxa_acquire_solid(screen, src->pSourcePict);
1038d514b0f3Smrg			FreePicture(src, 0);
1039d514b0f3Smrg
1040d514b0f3Smrg			src = solid;
1041d514b0f3Smrg			src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable,
1042d514b0f3Smrg							      &src_off_x, &src_off_y);
1043d514b0f3Smrg			if (!src_pixmap)
1044d514b0f3Smrg				goto err_src;
1045d514b0f3Smrg		}
1046d514b0f3Smrg
1047d514b0f3Smrg		if (!uxa_screen->info->prepare_composite(op, src, NULL, dst, src_pixmap, NULL, dst_pixmap))
1048d514b0f3Smrg			goto err_src;
1049d514b0f3Smrg
1050d514b0f3Smrg		while (num_boxes--) {
1051d514b0f3Smrg			uxa_screen->info->composite(dst_pixmap,
1052d514b0f3Smrg						    0, 0, 0, 0,
1053d514b0f3Smrg						    boxes->x1,
1054d514b0f3Smrg						    boxes->y1,
1055d514b0f3Smrg						    boxes->x2 - boxes->x1,
1056d514b0f3Smrg						    boxes->y2 - boxes->y1);
1057d514b0f3Smrg			boxes++;
1058d514b0f3Smrg		}
1059d514b0f3Smrg
1060d514b0f3Smrg		uxa_screen->info->done_composite(dst_pixmap);
1061d514b0f3Smrg		FreePicture(src, 0);
1062d514b0f3Smrg	}
1063d514b0f3Smrg
1064d514b0f3Smrg	pixman_region_fini(&region);
1065d514b0f3Smrg	return;
1066d514b0f3Smrg
1067d514b0f3Smrgerr_src:
1068d514b0f3Smrg	FreePicture(src, 0);
1069d514b0f3Smrgerr_region:
1070d514b0f3Smrg	pixman_region_fini(&region);
1071d514b0f3Smrgfallback:
1072d514b0f3Smrg	uxa_screen->SavedCompositeRects(op, dst, color, num_rects, rects);
1073d514b0f3Smrg}
1074d514b0f3Smrg
1075d514b0f3Smrgstatic int
1076d514b0f3Smrguxa_try_driver_composite(CARD8 op,
1077d514b0f3Smrg			 PicturePtr pSrc,
1078d514b0f3Smrg			 PicturePtr pMask,
1079d514b0f3Smrg			 PicturePtr pDst,
1080d514b0f3Smrg			 INT16 xSrc, INT16 ySrc,
1081d514b0f3Smrg			 INT16 xMask, INT16 yMask,
1082d514b0f3Smrg			 INT16 xDst, INT16 yDst,
1083d514b0f3Smrg			 CARD16 width, CARD16 height)
1084d514b0f3Smrg{
1085d514b0f3Smrg	ScreenPtr screen = pDst->pDrawable->pScreen;
1086d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1087d514b0f3Smrg	RegionRec region;
1088d514b0f3Smrg	BoxPtr pbox;
1089d514b0f3Smrg	int nbox;
1090d514b0f3Smrg	int xDst_copy = 0, yDst_copy = 0;
1091d514b0f3Smrg	int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
1092d514b0f3Smrg	PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
1093d514b0f3Smrg	PicturePtr localSrc, localMask = NULL;
1094d514b0f3Smrg	PicturePtr localDst = pDst;
1095d514b0f3Smrg
1096d514b0f3Smrg	if (uxa_screen->info->check_composite &&
1097d514b0f3Smrg	    !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height))
1098d514b0f3Smrg		return -1;
1099d514b0f3Smrg
1100d514b0f3Smrg	if (uxa_screen->info->check_composite_target &&
1101d514b0f3Smrg	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
1102d514b0f3Smrg		int depth = pDst->pDrawable->depth;
1103d514b0f3Smrg		PixmapPtr pixmap;
1104d514b0f3Smrg		int error;
1105d514b0f3Smrg		GCPtr gc;
1106d514b0f3Smrg
1107d514b0f3Smrg		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
1108d514b0f3Smrg		if (uxa_screen->info->check_copy &&
1109d514b0f3Smrg		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
1110d514b0f3Smrg			return -1;
1111d514b0f3Smrg
1112d514b0f3Smrg		pixmap = screen->CreatePixmap(screen,
1113d514b0f3Smrg					      width, height, depth,
1114d514b0f3Smrg					      CREATE_PIXMAP_USAGE_SCRATCH);
1115d514b0f3Smrg		if (!pixmap)
1116d514b0f3Smrg			return 0;
1117d514b0f3Smrg
1118d514b0f3Smrg		gc = GetScratchGC(depth, screen);
1119d514b0f3Smrg		if (!gc) {
1120d514b0f3Smrg			screen->DestroyPixmap(pixmap);
1121d514b0f3Smrg			return 0;
1122d514b0f3Smrg		}
1123d514b0f3Smrg
1124d514b0f3Smrg		ValidateGC(&pixmap->drawable, gc);
1125d514b0f3Smrg		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
1126d514b0f3Smrg				  xDst, yDst, width, height, 0, 0);
1127d514b0f3Smrg		FreeScratchGC(gc);
1128d514b0f3Smrg
1129d514b0f3Smrg		xDst_copy = xDst; xDst = 0;
1130d514b0f3Smrg		yDst_copy = yDst; yDst = 0;
1131d514b0f3Smrg
1132d514b0f3Smrg		localDst = CreatePicture(0, &pixmap->drawable,
1133d514b0f3Smrg					 PictureMatchFormat(screen, depth, pDst->format),
1134d514b0f3Smrg					 0, 0, serverClient, &error);
1135d514b0f3Smrg		screen->DestroyPixmap(pixmap);
1136d514b0f3Smrg
1137d514b0f3Smrg		if (!localDst)
1138d514b0f3Smrg			return 0;
1139d514b0f3Smrg
1140d514b0f3Smrg		ValidatePicture(localDst);
1141d514b0f3Smrg	}
1142d514b0f3Smrg
1143d514b0f3Smrg	pDstPix =
1144d514b0f3Smrg	    uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y);
1145d514b0f3Smrg	if (!pDstPix) {
1146d514b0f3Smrg		if (localDst != pDst)
1147d514b0f3Smrg			FreePicture(localDst, 0);
1148d514b0f3Smrg		return -1;
1149d514b0f3Smrg	}
1150d514b0f3Smrg
1151d514b0f3Smrg	xDst += localDst->pDrawable->x;
1152d514b0f3Smrg	yDst += localDst->pDrawable->y;
1153d514b0f3Smrg
1154d514b0f3Smrg	localSrc = uxa_acquire_source(screen, pSrc,
1155d514b0f3Smrg				      xSrc, ySrc,
1156d514b0f3Smrg				      width, height,
1157d514b0f3Smrg				      &xSrc, &ySrc);
1158d514b0f3Smrg	if (!localSrc) {
1159d514b0f3Smrg		if (localDst != pDst)
1160d514b0f3Smrg			FreePicture(localDst, 0);
1161d514b0f3Smrg		return 0;
1162d514b0f3Smrg	}
1163d514b0f3Smrg
1164d514b0f3Smrg	if (pMask) {
1165d514b0f3Smrg		localMask = uxa_acquire_mask(screen, pMask,
1166d514b0f3Smrg					     xMask, yMask,
1167d514b0f3Smrg					     width, height,
1168d514b0f3Smrg					     &xMask, &yMask);
1169d514b0f3Smrg		if (!localMask) {
1170d514b0f3Smrg			if (localSrc != pSrc)
1171d514b0f3Smrg				FreePicture(localSrc, 0);
1172d514b0f3Smrg			if (localDst != pDst)
1173d514b0f3Smrg				FreePicture(localDst, 0);
1174d514b0f3Smrg
1175d514b0f3Smrg			return 0;
1176d514b0f3Smrg		}
1177d514b0f3Smrg	}
1178d514b0f3Smrg
1179d514b0f3Smrg	if (!miComputeCompositeRegion(&region, localSrc, localMask, localDst,
1180d514b0f3Smrg				      xSrc, ySrc, xMask, yMask, xDst, yDst,
1181d514b0f3Smrg				      width, height)) {
1182d514b0f3Smrg		if (localSrc != pSrc)
1183d514b0f3Smrg			FreePicture(localSrc, 0);
1184d514b0f3Smrg		if (localMask && localMask != pMask)
1185d514b0f3Smrg			FreePicture(localMask, 0);
1186d514b0f3Smrg		if (localDst != pDst)
1187d514b0f3Smrg			FreePicture(localDst, 0);
1188d514b0f3Smrg
1189d514b0f3Smrg		return 1;
1190d514b0f3Smrg	}
1191d514b0f3Smrg
1192d514b0f3Smrg	if (localSrc->pDrawable) {
1193d514b0f3Smrg		pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable,
1194d514b0f3Smrg						   &src_off_x, &src_off_y);
1195d514b0f3Smrg		if (!pSrcPix) {
1196d514b0f3Smrg			REGION_UNINIT(screen, &region);
1197d514b0f3Smrg
1198d514b0f3Smrg			if (localSrc != pSrc)
1199d514b0f3Smrg				FreePicture(localSrc, 0);
1200d514b0f3Smrg			if (localMask && localMask != pMask)
1201d514b0f3Smrg				FreePicture(localMask, 0);
1202d514b0f3Smrg			if (localDst != pDst)
1203d514b0f3Smrg				FreePicture(localDst, 0);
1204d514b0f3Smrg
1205d514b0f3Smrg			return 0;
1206d514b0f3Smrg		}
1207d514b0f3Smrg	} else {
1208d514b0f3Smrg		pSrcPix = NULL;
1209d514b0f3Smrg	}
1210d514b0f3Smrg
1211d514b0f3Smrg	if (localMask) {
1212d514b0f3Smrg		if (localMask->pDrawable) {
1213d514b0f3Smrg			pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable,
1214d514b0f3Smrg							    &mask_off_x, &mask_off_y);
1215d514b0f3Smrg			if (!pMaskPix) {
1216d514b0f3Smrg				REGION_UNINIT(screen, &region);
1217d514b0f3Smrg
1218d514b0f3Smrg				if (localSrc != pSrc)
1219d514b0f3Smrg					FreePicture(localSrc, 0);
1220d514b0f3Smrg				if (localMask && localMask != pMask)
1221d514b0f3Smrg					FreePicture(localMask, 0);
1222d514b0f3Smrg				if (localDst != pDst)
1223d514b0f3Smrg					FreePicture(localDst, 0);
1224d514b0f3Smrg
1225d514b0f3Smrg				return 0;
1226d514b0f3Smrg			}
1227d514b0f3Smrg		} else {
1228d514b0f3Smrg			pMaskPix = NULL;
1229d514b0f3Smrg		}
1230d514b0f3Smrg	}
1231d514b0f3Smrg
1232d514b0f3Smrg	if (!(*uxa_screen->info->prepare_composite)
1233d514b0f3Smrg	    (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) {
1234d514b0f3Smrg		REGION_UNINIT(screen, &region);
1235d514b0f3Smrg
1236d514b0f3Smrg		if (localSrc != pSrc)
1237d514b0f3Smrg			FreePicture(localSrc, 0);
1238d514b0f3Smrg		if (localMask && localMask != pMask)
1239d514b0f3Smrg			FreePicture(localMask, 0);
1240d514b0f3Smrg		if (localDst != pDst)
1241d514b0f3Smrg			FreePicture(localDst, 0);
1242d514b0f3Smrg
1243d514b0f3Smrg		return -1;
1244d514b0f3Smrg	}
1245d514b0f3Smrg
1246d514b0f3Smrg	if (pMask) {
1247d514b0f3Smrg		xMask = xMask + mask_off_x - xDst;
1248d514b0f3Smrg		yMask = yMask + mask_off_y - yDst;
1249d514b0f3Smrg	}
1250d514b0f3Smrg
1251d514b0f3Smrg	xSrc = xSrc + src_off_x - xDst;
1252d514b0f3Smrg	ySrc = ySrc + src_off_y - yDst;
1253d514b0f3Smrg
1254d514b0f3Smrg	nbox = REGION_NUM_RECTS(&region);
1255d514b0f3Smrg	pbox = REGION_RECTS(&region);
1256d514b0f3Smrg	while (nbox--) {
1257d514b0f3Smrg		(*uxa_screen->info->composite) (pDstPix,
1258d514b0f3Smrg						pbox->x1 + xSrc,
1259d514b0f3Smrg						pbox->y1 + ySrc,
1260d514b0f3Smrg						pbox->x1 + xMask,
1261d514b0f3Smrg						pbox->y1 + yMask,
1262d514b0f3Smrg						pbox->x1 + dst_off_x,
1263d514b0f3Smrg						pbox->y1 + dst_off_y,
1264d514b0f3Smrg						pbox->x2 - pbox->x1,
1265d514b0f3Smrg						pbox->y2 - pbox->y1);
1266d514b0f3Smrg		pbox++;
1267d514b0f3Smrg	}
1268d514b0f3Smrg	(*uxa_screen->info->done_composite) (pDstPix);
1269d514b0f3Smrg
1270d514b0f3Smrg	REGION_UNINIT(screen, &region);
1271d514b0f3Smrg
1272d514b0f3Smrg	if (localSrc != pSrc)
1273d514b0f3Smrg		FreePicture(localSrc, 0);
1274d514b0f3Smrg	if (localMask && localMask != pMask)
1275d514b0f3Smrg		FreePicture(localMask, 0);
1276d514b0f3Smrg
1277d514b0f3Smrg	if (localDst != pDst) {
1278d514b0f3Smrg		GCPtr gc;
1279d514b0f3Smrg
1280d514b0f3Smrg		gc = GetScratchGC(pDst->pDrawable->depth, screen);
1281d514b0f3Smrg		if (gc) {
1282d514b0f3Smrg			ValidateGC(pDst->pDrawable, gc);
1283d514b0f3Smrg			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
1284d514b0f3Smrg					  0, 0, width, height, xDst_copy, yDst_copy);
1285d514b0f3Smrg			FreeScratchGC(gc);
1286d514b0f3Smrg		}
1287d514b0f3Smrg
1288d514b0f3Smrg		FreePicture(localDst, 0);
1289d514b0f3Smrg	}
1290d514b0f3Smrg
1291d514b0f3Smrg	return 1;
1292d514b0f3Smrg}
1293d514b0f3Smrg
1294d514b0f3Smrg/**
1295d514b0f3Smrg * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of
1296d514b0f3Smrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
1297d514b0f3Smrg * alpha and limited 1-tmu cards.
1298d514b0f3Smrg *
1299d514b0f3Smrg * From http://anholt.livejournal.com/32058.html:
1300d514b0f3Smrg *
1301d514b0f3Smrg * The trouble is that component-alpha rendering requires two different sources
1302d514b0f3Smrg * for blending: one for the source value to the blender, which is the
1303d514b0f3Smrg * per-channel multiplication of source and mask, and one for the source alpha
1304d514b0f3Smrg * for multiplying with the destination channels, which is the multiplication
1305d514b0f3Smrg * of the source channels by the mask alpha. So the equation for Over is:
1306d514b0f3Smrg *
1307d514b0f3Smrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
1308d514b0f3Smrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
1309d514b0f3Smrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
1310d514b0f3Smrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
1311d514b0f3Smrg *
1312d514b0f3Smrg * But we can do some simpler operations, right? How about PictOpOutReverse,
1313d514b0f3Smrg * which has a source factor of 0 and dest factor of (1 - source alpha). We
1314d514b0f3Smrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
1315d514b0f3Smrg * blenders pretty easily. So we can do a component-alpha OutReverse, which
1316d514b0f3Smrg * gets us:
1317d514b0f3Smrg *
1318d514b0f3Smrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
1319d514b0f3Smrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
1320d514b0f3Smrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
1321d514b0f3Smrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
1322d514b0f3Smrg *
1323d514b0f3Smrg * OK. And if an op doesn't use the source alpha value for the destination
1324d514b0f3Smrg * factor, then we can do the channel multiplication in the texture blenders
1325d514b0f3Smrg * to get the source value, and ignore the source alpha that we wouldn't use.
1326d514b0f3Smrg * We've supported this in the Radeon driver for a long time. An example would
1327d514b0f3Smrg * be PictOpAdd, which does:
1328d514b0f3Smrg *
1329d514b0f3Smrg * dst.A = src.A * mask.A + dst.A
1330d514b0f3Smrg * dst.R = src.R * mask.R + dst.R
1331d514b0f3Smrg * dst.G = src.G * mask.G + dst.G
1332d514b0f3Smrg * dst.B = src.B * mask.B + dst.B
1333d514b0f3Smrg *
1334d514b0f3Smrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
1335d514b0f3Smrg * after it, we get:
1336d514b0f3Smrg *
1337d514b0f3Smrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
1338d514b0f3Smrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
1339d514b0f3Smrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
1340d514b0f3Smrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
1341d514b0f3Smrg */
1342d514b0f3Smrg
1343d514b0f3Smrgstatic int
1344d514b0f3Smrguxa_try_magic_two_pass_composite_helper(CARD8 op,
1345d514b0f3Smrg					PicturePtr pSrc,
1346d514b0f3Smrg					PicturePtr pMask,
1347d514b0f3Smrg					PicturePtr pDst,
1348d514b0f3Smrg					INT16 xSrc, INT16 ySrc,
1349d514b0f3Smrg					INT16 xMask, INT16 yMask,
1350d514b0f3Smrg					INT16 xDst, INT16 yDst,
1351d514b0f3Smrg					CARD16 width, CARD16 height)
1352d514b0f3Smrg{
1353d514b0f3Smrg	ScreenPtr screen = pDst->pDrawable->pScreen;
1354d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1355d514b0f3Smrg	PicturePtr localDst = pDst;
1356d514b0f3Smrg	int xDst_copy = 0, yDst_copy = 0;
1357d514b0f3Smrg
1358d514b0f3Smrg	assert(op == PictOpOver);
1359d514b0f3Smrg
1360d514b0f3Smrg	if (uxa_screen->info->check_composite &&
1361d514b0f3Smrg	    (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc,
1362d514b0f3Smrg						    pMask, pDst, width, height)
1363d514b0f3Smrg	     || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask,
1364d514b0f3Smrg						       pDst, width, height))) {
1365d514b0f3Smrg		return -1;
1366d514b0f3Smrg	}
1367d514b0f3Smrg
1368d514b0f3Smrg	if (uxa_screen->info->check_composite_target &&
1369d514b0f3Smrg	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
1370d514b0f3Smrg		int depth = pDst->pDrawable->depth;
1371d514b0f3Smrg		PixmapPtr pixmap;
1372d514b0f3Smrg		int error;
1373d514b0f3Smrg		GCPtr gc;
1374d514b0f3Smrg
1375d514b0f3Smrg		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
1376d514b0f3Smrg		if (uxa_screen->info->check_copy &&
1377d514b0f3Smrg		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
1378d514b0f3Smrg			return -1;
1379d514b0f3Smrg
1380d514b0f3Smrg		pixmap = screen->CreatePixmap(screen,
1381d514b0f3Smrg					      width, height, depth,
1382d514b0f3Smrg					      CREATE_PIXMAP_USAGE_SCRATCH);
1383d514b0f3Smrg		if (!pixmap)
1384d514b0f3Smrg			return 0;
1385d514b0f3Smrg
1386d514b0f3Smrg		gc = GetScratchGC(depth, screen);
1387d514b0f3Smrg		if (!gc) {
1388d514b0f3Smrg			screen->DestroyPixmap(pixmap);
1389d514b0f3Smrg			return 0;
1390d514b0f3Smrg		}
1391d514b0f3Smrg
1392d514b0f3Smrg		ValidateGC(&pixmap->drawable, gc);
1393d514b0f3Smrg		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
1394d514b0f3Smrg				  xDst, yDst, width, height, 0, 0);
1395d514b0f3Smrg		FreeScratchGC(gc);
1396d514b0f3Smrg
1397d514b0f3Smrg		xDst_copy = xDst; xDst = 0;
1398d514b0f3Smrg		yDst_copy = yDst; yDst = 0;
1399d514b0f3Smrg
1400d514b0f3Smrg		localDst = CreatePicture(0, &pixmap->drawable,
1401d514b0f3Smrg					 PictureMatchFormat(screen, depth, pDst->format),
1402d514b0f3Smrg					 0, 0, serverClient, &error);
1403d514b0f3Smrg		screen->DestroyPixmap(pixmap);
1404d514b0f3Smrg
1405d514b0f3Smrg		if (!localDst)
1406d514b0f3Smrg			return 0;
1407d514b0f3Smrg
1408d514b0f3Smrg		ValidatePicture(localDst);
1409d514b0f3Smrg	}
1410d514b0f3Smrg
1411d514b0f3Smrg	/* Now, we think we should be able to accelerate this operation. First,
1412d514b0f3Smrg	 * composite the destination to be the destination times the source alpha
1413d514b0f3Smrg	 * factors.
1414d514b0f3Smrg	 */
1415d514b0f3Smrg	uxa_composite(PictOpOutReverse, pSrc, pMask, localDst,
1416d514b0f3Smrg		      xSrc, ySrc,
1417d514b0f3Smrg		      xMask, yMask,
1418d514b0f3Smrg		      xDst, yDst,
1419d514b0f3Smrg		      width, height);
1420d514b0f3Smrg
1421d514b0f3Smrg	/* Then, add in the source value times the destination alpha factors (1.0).
1422d514b0f3Smrg	 */
1423d514b0f3Smrg	uxa_composite(PictOpAdd, pSrc, pMask, localDst,
1424d514b0f3Smrg		      xSrc, ySrc,
1425d514b0f3Smrg		      xMask, yMask,
1426d514b0f3Smrg		      xDst, yDst,
1427d514b0f3Smrg		      width, height);
1428d514b0f3Smrg
1429d514b0f3Smrg	if (localDst != pDst) {
1430d514b0f3Smrg		GCPtr gc;
1431d514b0f3Smrg
1432d514b0f3Smrg		gc = GetScratchGC(pDst->pDrawable->depth, screen);
1433d514b0f3Smrg		if (gc) {
1434d514b0f3Smrg			ValidateGC(pDst->pDrawable, gc);
1435d514b0f3Smrg			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
1436d514b0f3Smrg					0, 0, width, height, xDst_copy, yDst_copy);
1437d514b0f3Smrg			FreeScratchGC(gc);
1438d514b0f3Smrg		}
1439d514b0f3Smrg
1440d514b0f3Smrg		FreePicture(localDst, 0);
1441d514b0f3Smrg	}
1442d514b0f3Smrg
1443d514b0f3Smrg	return 1;
1444d514b0f3Smrg}
1445d514b0f3Smrg
1446d514b0f3Smrgstatic int
1447d514b0f3Smrgcompatible_formats (CARD8 op, PicturePtr dst, PicturePtr src)
1448d514b0f3Smrg{
1449d514b0f3Smrg	if (op == PictOpSrc) {
1450d514b0f3Smrg		if (src->format == dst->format)
1451d514b0f3Smrg			return 1;
1452d514b0f3Smrg
1453d514b0f3Smrg		/* Is the destination an alpha-less version of source? */
1454d514b0f3Smrg		if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format),
1455d514b0f3Smrg					       PICT_FORMAT_TYPE(src->format),
1456d514b0f3Smrg					       0,
1457d514b0f3Smrg					       PICT_FORMAT_R(src->format),
1458d514b0f3Smrg					       PICT_FORMAT_G(src->format),
1459d514b0f3Smrg					       PICT_FORMAT_B(src->format)))
1460d514b0f3Smrg			return 1;
1461d514b0f3Smrg
1462d514b0f3Smrg		/* XXX xrgb is promoted to argb during image upload... */
1463d514b0f3Smrg#if 0
1464d514b0f3Smrg		if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8)
1465d514b0f3Smrg			return 1;
1466d514b0f3Smrg#endif
1467d514b0f3Smrg	} else if (op == PictOpOver) {
1468d514b0f3Smrg		if (PICT_FORMAT_A(src->format))
1469d514b0f3Smrg			return 0;
1470d514b0f3Smrg
1471d514b0f3Smrg		return src->format == dst->format;
1472d514b0f3Smrg	}
1473d514b0f3Smrg
1474d514b0f3Smrg	return 0;
1475d514b0f3Smrg}
1476d514b0f3Smrg
1477d514b0f3Smrgstatic int
1478d514b0f3Smrgdrawable_contains (DrawablePtr drawable, int x, int y, int w, int h)
1479d514b0f3Smrg{
1480d514b0f3Smrg	if (x < 0 || y < 0)
1481d514b0f3Smrg		return FALSE;
1482d514b0f3Smrg
1483d514b0f3Smrg	if (x + w > drawable->width)
1484d514b0f3Smrg		return FALSE;
1485d514b0f3Smrg
1486d514b0f3Smrg	if (y + h > drawable->height)
1487d514b0f3Smrg		return FALSE;
1488d514b0f3Smrg
1489d514b0f3Smrg	return TRUE;
1490d514b0f3Smrg}
1491d514b0f3Smrg
1492d514b0f3Smrgvoid
1493d514b0f3Smrguxa_composite(CARD8 op,
1494d514b0f3Smrg	      PicturePtr pSrc,
1495d514b0f3Smrg	      PicturePtr pMask,
1496d514b0f3Smrg	      PicturePtr pDst,
1497d514b0f3Smrg	      INT16 xSrc, INT16 ySrc,
1498d514b0f3Smrg	      INT16 xMask, INT16 yMask,
1499d514b0f3Smrg	      INT16 xDst, INT16 yDst,
1500d514b0f3Smrg	      CARD16 width, CARD16 height)
1501d514b0f3Smrg{
1502d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
1503d514b0f3Smrg	int ret = -1;
1504d514b0f3Smrg	Bool saveSrcRepeat = pSrc->repeat;
1505d514b0f3Smrg	Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
1506d514b0f3Smrg	RegionRec region;
1507d514b0f3Smrg	int tx, ty;
1508d514b0f3Smrg
1509d514b0f3Smrg	if (uxa_screen->swappedOut || uxa_screen->force_fallback)
1510d514b0f3Smrg		goto fallback;
1511d514b0f3Smrg
1512d514b0f3Smrg	if (!uxa_drawable_is_offscreen(pDst->pDrawable))
1513d514b0f3Smrg		goto fallback;
1514d514b0f3Smrg
1515d514b0f3Smrg	if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap))
1516d514b0f3Smrg		goto fallback;
1517d514b0f3Smrg
1518d514b0f3Smrg	/* Remove repeat in source if useless */
1519d514b0f3Smrg	if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution &&
1520d514b0f3Smrg	    transform_is_integer_translation(pSrc->transform, &tx, &ty) &&
1521d514b0f3Smrg	    (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) &&
1522d514b0f3Smrg	    drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height))
1523d514b0f3Smrg		pSrc->repeat = 0;
1524d514b0f3Smrg
1525d514b0f3Smrg	if (!pMask) {
1526d514b0f3Smrg		if (op == PictOpClear) {
1527d514b0f3Smrg			PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen);
1528d514b0f3Smrg			if (clear &&
1529d514b0f3Smrg			    uxa_try_driver_solid_fill(clear, pDst,
1530d514b0f3Smrg						      xSrc, ySrc,
1531d514b0f3Smrg						      xDst, yDst,
1532d514b0f3Smrg						      width, height) == 1)
1533d514b0f3Smrg				goto done;
1534d514b0f3Smrg		}
1535d514b0f3Smrg
1536d514b0f3Smrg		if (pSrc->pDrawable == NULL) {
1537d514b0f3Smrg			if (pSrc->pSourcePict) {
1538d514b0f3Smrg				SourcePict *source = pSrc->pSourcePict;
1539d514b0f3Smrg				if (source->type == SourcePictTypeSolidFill) {
1540d514b0f3Smrg					if (op == PictOpSrc ||
1541d514b0f3Smrg					    (op == PictOpOver &&
1542d514b0f3Smrg					     (source->solidFill.color & 0xff000000) == 0xff000000)) {
1543d514b0f3Smrg						ret = uxa_try_driver_solid_fill(pSrc, pDst,
1544d514b0f3Smrg										xSrc, ySrc,
1545d514b0f3Smrg										xDst, yDst,
1546d514b0f3Smrg										width, height);
1547d514b0f3Smrg						if (ret == 1)
1548d514b0f3Smrg							goto done;
1549d514b0f3Smrg					}
1550d514b0f3Smrg				}
1551d514b0f3Smrg			}
1552d514b0f3Smrg		} else if (pSrc->pDrawable->width == 1 &&
1553d514b0f3Smrg			   pSrc->pDrawable->height == 1 &&
1554d514b0f3Smrg			   pSrc->repeat &&
1555d514b0f3Smrg			   (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) {
1556d514b0f3Smrg			ret = uxa_try_driver_solid_fill(pSrc, pDst,
1557d514b0f3Smrg							xSrc, ySrc,
1558d514b0f3Smrg							xDst, yDst,
1559d514b0f3Smrg							width, height);
1560d514b0f3Smrg			if (ret == 1)
1561d514b0f3Smrg				goto done;
1562d514b0f3Smrg		} else if (compatible_formats (op, pDst, pSrc) &&
1563d514b0f3Smrg			   pSrc->filter != PictFilterConvolution &&
1564d514b0f3Smrg			   transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
1565d514b0f3Smrg			if (!pSrc->repeat &&
1566d514b0f3Smrg			    drawable_contains(pSrc->pDrawable,
1567d514b0f3Smrg					     xSrc + tx, ySrc + ty,
1568d514b0f3Smrg					     width, height)) {
1569d514b0f3Smrg				xDst += pDst->pDrawable->x;
1570d514b0f3Smrg				yDst += pDst->pDrawable->y;
1571d514b0f3Smrg				xSrc += pSrc->pDrawable->x + tx;
1572d514b0f3Smrg				ySrc += pSrc->pDrawable->y + ty;
1573d514b0f3Smrg
1574d514b0f3Smrg				if (!miComputeCompositeRegion
1575d514b0f3Smrg				    (&region, pSrc, pMask, pDst, xSrc, ySrc,
1576d514b0f3Smrg				     xMask, yMask, xDst, yDst, width, height))
1577d514b0f3Smrg					goto done;
1578d514b0f3Smrg
1579d514b0f3Smrg				uxa_copy_n_to_n(pSrc->pDrawable,
1580d514b0f3Smrg						pDst->pDrawable, NULL,
1581d514b0f3Smrg						REGION_RECTS(&region),
1582d514b0f3Smrg						REGION_NUM_RECTS(&region),
1583d514b0f3Smrg						xSrc - xDst, ySrc - yDst, FALSE,
1584d514b0f3Smrg						FALSE, 0, NULL);
1585d514b0f3Smrg				REGION_UNINIT(pDst->pDrawable->pScreen,
1586d514b0f3Smrg					      &region);
1587d514b0f3Smrg				goto done;
1588d514b0f3Smrg			} else if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
1589d514b0f3Smrg				   pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
1590d514b0f3Smrg				DDXPointRec patOrg;
1591d514b0f3Smrg
1592d514b0f3Smrg				/* Let's see if the driver can do the repeat
1593d514b0f3Smrg				 * in one go
1594d514b0f3Smrg				 */
1595d514b0f3Smrg				if (uxa_screen->info->prepare_composite) {
1596d514b0f3Smrg					ret = uxa_try_driver_composite(op, pSrc,
1597d514b0f3Smrg								       pMask, pDst,
1598d514b0f3Smrg								       xSrc, ySrc,
1599d514b0f3Smrg								       xMask, yMask,
1600d514b0f3Smrg								       xDst, yDst,
1601d514b0f3Smrg								       width, height);
1602d514b0f3Smrg					if (ret == 1)
1603d514b0f3Smrg						goto done;
1604d514b0f3Smrg				}
1605d514b0f3Smrg
1606d514b0f3Smrg				/* Now see if we can use
1607d514b0f3Smrg				 * uxa_fill_region_tiled()
1608d514b0f3Smrg				 */
1609d514b0f3Smrg				xDst += pDst->pDrawable->x;
1610d514b0f3Smrg				yDst += pDst->pDrawable->y;
1611d514b0f3Smrg				xSrc += pSrc->pDrawable->x + tx;
1612d514b0f3Smrg				ySrc += pSrc->pDrawable->y + ty;
1613d514b0f3Smrg
1614d514b0f3Smrg				if (!miComputeCompositeRegion
1615d514b0f3Smrg				    (&region, pSrc, pMask, pDst, xSrc, ySrc,
1616d514b0f3Smrg				     xMask, yMask, xDst, yDst, width, height))
1617d514b0f3Smrg					goto done;
1618d514b0f3Smrg
1619d514b0f3Smrg				/* pattern origin is the point in the
1620d514b0f3Smrg				 * destination drawable
1621d514b0f3Smrg				 * corresponding to (0,0) in the source */
1622d514b0f3Smrg				patOrg.x = xDst - xSrc;
1623d514b0f3Smrg				patOrg.y = yDst - ySrc;
1624d514b0f3Smrg
1625d514b0f3Smrg				ret = uxa_fill_region_tiled(pDst->pDrawable,
1626d514b0f3Smrg							    &region,
1627d514b0f3Smrg							    (PixmapPtr) pSrc->
1628d514b0f3Smrg							    pDrawable, &patOrg,
1629d514b0f3Smrg							    FB_ALLONES, GXcopy);
1630d514b0f3Smrg
1631d514b0f3Smrg				REGION_UNINIT(pDst->pDrawable->pScreen,
1632d514b0f3Smrg					      &region);
1633d514b0f3Smrg
1634d514b0f3Smrg				if (ret)
1635d514b0f3Smrg					goto done;
1636d514b0f3Smrg			}
1637d514b0f3Smrg		}
1638d514b0f3Smrg	}
1639d514b0f3Smrg
1640d514b0f3Smrg	/* Remove repeat in mask if useless */
1641d514b0f3Smrg	if (pMask && pMask->pDrawable && pMask->repeat &&
1642d514b0f3Smrg	    pMask->filter != PictFilterConvolution &&
1643d514b0f3Smrg	    transform_is_integer_translation(pMask->transform, &tx, &ty) &&
1644d514b0f3Smrg	    (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) &&
1645d514b0f3Smrg	    drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height))
1646d514b0f3Smrg		pMask->repeat = 0;
1647d514b0f3Smrg
1648d514b0f3Smrg	if (uxa_screen->info->prepare_composite) {
1649d514b0f3Smrg		Bool isSrcSolid;
1650d514b0f3Smrg
1651d514b0f3Smrg		ret =
1652d514b0f3Smrg		    uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
1653d514b0f3Smrg					     xMask, yMask, xDst, yDst, width,
1654d514b0f3Smrg					     height);
1655d514b0f3Smrg		if (ret == 1)
1656d514b0f3Smrg			goto done;
1657d514b0f3Smrg
1658d514b0f3Smrg		/* For generic masks and solid src pictures, mach64 can do
1659d514b0f3Smrg		 * Over in two passes, similar to the component-alpha case.
1660d514b0f3Smrg		 */
1661d514b0f3Smrg
1662d514b0f3Smrg		isSrcSolid =
1663d514b0f3Smrg			pSrc->pDrawable ?
1664d514b0f3Smrg				pSrc->pDrawable->width == 1 &&
1665d514b0f3Smrg				pSrc->pDrawable->height == 1 &&
1666d514b0f3Smrg				pSrc->repeat :
1667d514b0f3Smrg			pSrc->pSourcePict ?
1668d514b0f3Smrg				pSrc->pSourcePict->type == SourcePictTypeSolidFill :
1669d514b0f3Smrg			0;
1670d514b0f3Smrg
1671d514b0f3Smrg		/* If we couldn't do the Composite in a single pass, and it
1672d514b0f3Smrg		 * was a component-alpha Over, see if we can do it in two
1673d514b0f3Smrg		 * passes with an OutReverse and then an Add.
1674d514b0f3Smrg		 */
1675d514b0f3Smrg		if (ret == -1 && op == PictOpOver && pMask &&
1676d514b0f3Smrg		    (pMask->componentAlpha || isSrcSolid)) {
1677d514b0f3Smrg			ret =
1678d514b0f3Smrg			    uxa_try_magic_two_pass_composite_helper(op, pSrc,
1679d514b0f3Smrg								    pMask, pDst,
1680d514b0f3Smrg								    xSrc, ySrc,
1681d514b0f3Smrg								    xMask, yMask,
1682d514b0f3Smrg								    xDst, yDst,
1683d514b0f3Smrg								    width, height);
1684d514b0f3Smrg			if (ret == 1)
1685d514b0f3Smrg				goto done;
1686d514b0f3Smrg		}
1687d514b0f3Smrg
1688d514b0f3Smrg	}
1689d514b0f3Smrg
1690d514b0f3Smrgfallback:
1691d514b0f3Smrg	uxa_print_composite_fallback("uxa_composite",
1692d514b0f3Smrg				     op, pSrc, pMask, pDst);
1693d514b0f3Smrg
1694d514b0f3Smrg	uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
1695d514b0f3Smrg			    xMask, yMask, xDst, yDst, width, height);
1696d514b0f3Smrg
1697d514b0f3Smrgdone:
1698d514b0f3Smrg	pSrc->repeat = saveSrcRepeat;
1699d514b0f3Smrg	if (pMask)
1700d514b0f3Smrg		pMask->repeat = saveMaskRepeat;
1701d514b0f3Smrg}
1702d514b0f3Smrg#endif
1703d514b0f3Smrg
1704d514b0f3Smrg/**
1705d514b0f3Smrg * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead
1706d514b0f3Smrg * of PolyFillRect to initialize the pixmap after creating it, to prevent
1707d514b0f3Smrg * the pixmap from being migrated.
1708d514b0f3Smrg *
1709d514b0f3Smrg * See the comments about uxa_trapezoids and uxa_triangles.
1710d514b0f3Smrg */
1711d514b0f3Smrgstatic PicturePtr
1712d514b0f3Smrguxa_create_alpha_picture(ScreenPtr pScreen,
1713d514b0f3Smrg			 PicturePtr pDst,
1714d514b0f3Smrg			 PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
1715d514b0f3Smrg{
1716d514b0f3Smrg	PixmapPtr pPixmap;
1717d514b0f3Smrg	PicturePtr pPicture;
1718d514b0f3Smrg	int error;
1719d514b0f3Smrg
1720d514b0f3Smrg	if (width > 32767 || height > 32767)
1721d514b0f3Smrg		return 0;
1722d514b0f3Smrg
1723d514b0f3Smrg	if (!pPictFormat) {
1724d514b0f3Smrg		if (pDst->polyEdge == PolyEdgeSharp)
1725d514b0f3Smrg			pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1726d514b0f3Smrg		else
1727d514b0f3Smrg			pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1728d514b0f3Smrg		if (!pPictFormat)
1729d514b0f3Smrg			return 0;
1730d514b0f3Smrg	}
1731d514b0f3Smrg
1732d514b0f3Smrg	pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1733d514b0f3Smrg					    pPictFormat->depth,
1734d514b0f3Smrg					    UXA_CREATE_PIXMAP_FOR_MAP);
1735d514b0f3Smrg	if (!pPixmap)
1736d514b0f3Smrg		return 0;
1737d514b0f3Smrg	pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
1738d514b0f3Smrg				 0, 0, serverClient, &error);
1739d514b0f3Smrg	(*pScreen->DestroyPixmap) (pPixmap);
1740d514b0f3Smrg	return pPicture;
1741d514b0f3Smrg}
1742d514b0f3Smrg
1743d514b0f3Smrg/**
1744d514b0f3Smrg * uxa_trapezoids is essentially a copy of miTrapezoids that uses
1745d514b0f3Smrg * uxa_create_alpha_picture instead of miCreateAlphaPicture.
1746d514b0f3Smrg *
1747d514b0f3Smrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1748d514b0f3Smrg * to initialize the contents after creating the pixmap, which
1749d514b0f3Smrg * causes the pixmap to be moved in for acceleration. The subsequent
1750d514b0f3Smrg * call to RasterizeTrapezoid won't be accelerated however, which
1751d514b0f3Smrg * forces the pixmap to be moved out again.
1752d514b0f3Smrg *
1753d514b0f3Smrg * uxa_create_alpha_picture avoids this roundtrip by using
1754d514b0f3Smrg * uxa_check_poly_fill_rect to initialize the contents.
1755d514b0f3Smrg */
1756d514b0f3Smrgvoid
1757d514b0f3Smrguxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
1758d514b0f3Smrg	       PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1759d514b0f3Smrg	       int ntrap, xTrapezoid * traps)
1760d514b0f3Smrg{
1761d514b0f3Smrg	ScreenPtr screen = dst->pDrawable->pScreen;
1762d514b0f3Smrg	BoxRec bounds;
1763d514b0f3Smrg	Bool direct;
1764d514b0f3Smrg
1765d514b0f3Smrg	direct = op == PictOpAdd && miIsSolidAlpha(src);
1766d514b0f3Smrg	if (maskFormat || direct) {
1767d514b0f3Smrg		miTrapezoidBounds(ntrap, traps, &bounds);
1768d514b0f3Smrg
1769d514b0f3Smrg		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1770d514b0f3Smrg			return;
1771d514b0f3Smrg	}
1772d514b0f3Smrg
1773d514b0f3Smrg	/*
1774d514b0f3Smrg	 * Check for solid alpha add
1775d514b0f3Smrg	 */
1776d514b0f3Smrg	if (direct) {
1777d514b0f3Smrg		DrawablePtr pDraw = dst->pDrawable;
1778d514b0f3Smrg		PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw);
1779d514b0f3Smrg		int xoff, yoff;
1780d514b0f3Smrg
1781d514b0f3Smrg		uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff);
1782d514b0f3Smrg
1783d514b0f3Smrg		xoff += pDraw->x;
1784d514b0f3Smrg		yoff += pDraw->y;
1785d514b0f3Smrg
1786d514b0f3Smrg		if (uxa_prepare_access(pDraw, NULL, UXA_ACCESS_RW)) {
1787d514b0f3Smrg			PictureScreenPtr ps = GetPictureScreen(screen);
1788d514b0f3Smrg
1789d514b0f3Smrg			for (; ntrap; ntrap--, traps++)
1790d514b0f3Smrg				(*ps->RasterizeTrapezoid) (dst, traps, 0, 0);
1791d514b0f3Smrg			uxa_finish_access(pDraw);
1792d514b0f3Smrg		}
1793d514b0f3Smrg	} else if (maskFormat) {
1794d514b0f3Smrg		PixmapPtr scratch = NULL;
1795d514b0f3Smrg		PicturePtr mask;
1796d514b0f3Smrg		INT16 xDst, yDst;
1797d514b0f3Smrg		INT16 xRel, yRel;
1798d514b0f3Smrg		int width, height;
1799d514b0f3Smrg		pixman_image_t *image;
1800d514b0f3Smrg		pixman_format_code_t format;
1801d514b0f3Smrg
1802d514b0f3Smrg		xDst = traps[0].left.p1.x >> 16;
1803d514b0f3Smrg		yDst = traps[0].left.p1.y >> 16;
1804d514b0f3Smrg
1805d514b0f3Smrg		width  = bounds.x2 - bounds.x1;
1806d514b0f3Smrg		height = bounds.y2 - bounds.y1;
1807d514b0f3Smrg
1808d514b0f3Smrg		format = maskFormat->format |
1809d514b0f3Smrg			(BitsPerPixel(maskFormat->depth) << 24);
1810d514b0f3Smrg		image =
1811d514b0f3Smrg		    pixman_image_create_bits(format, width, height, NULL, 0);
1812d514b0f3Smrg		if (!image)
1813d514b0f3Smrg			return;
1814d514b0f3Smrg
1815d514b0f3Smrg		for (; ntrap; ntrap--, traps++)
1816d514b0f3Smrg			pixman_rasterize_trapezoid(image,
1817d514b0f3Smrg						   (pixman_trapezoid_t *) traps,
1818d514b0f3Smrg						   -bounds.x1, -bounds.y1);
1819d514b0f3Smrg		if (uxa_drawable_is_offscreen(dst->pDrawable)) {
1820d514b0f3Smrg			mask = uxa_picture_from_pixman_image(screen, image, format);
1821d514b0f3Smrg		} else {
1822d514b0f3Smrg			int error;
1823d514b0f3Smrg
1824d514b0f3Smrg			scratch = GetScratchPixmapHeader(screen, width, height,
1825d514b0f3Smrg							PIXMAN_FORMAT_DEPTH(format),
1826d514b0f3Smrg							PIXMAN_FORMAT_BPP(format),
1827d514b0f3Smrg							pixman_image_get_stride(image),
1828d514b0f3Smrg							pixman_image_get_data(image));
1829d514b0f3Smrg			mask = CreatePicture(0, &scratch->drawable,
1830d514b0f3Smrg					     PictureMatchFormat(screen,
1831d514b0f3Smrg								PIXMAN_FORMAT_DEPTH(format),
1832d514b0f3Smrg								format),
1833d514b0f3Smrg					     0, 0, serverClient, &error);
1834d514b0f3Smrg		}
1835d514b0f3Smrg		if (!mask) {
1836d514b0f3Smrg			if (scratch)
1837d514b0f3Smrg				FreeScratchPixmapHeader(scratch);
1838d514b0f3Smrg			pixman_image_unref(image);
1839d514b0f3Smrg			return;
1840d514b0f3Smrg		}
1841d514b0f3Smrg
1842d514b0f3Smrg		xRel = bounds.x1 + xSrc - xDst;
1843d514b0f3Smrg		yRel = bounds.y1 + ySrc - yDst;
1844d514b0f3Smrg		CompositePicture(op, src, mask, dst,
1845d514b0f3Smrg				 xRel, yRel,
1846d514b0f3Smrg				 0, 0,
1847d514b0f3Smrg				 bounds.x1, bounds.y1,
1848d514b0f3Smrg				 width, height);
1849d514b0f3Smrg		FreePicture(mask, 0);
1850d514b0f3Smrg
1851d514b0f3Smrg		if (scratch)
1852d514b0f3Smrg			FreeScratchPixmapHeader(scratch);
1853d514b0f3Smrg		pixman_image_unref(image);
1854d514b0f3Smrg	} else {
1855d514b0f3Smrg		if (dst->polyEdge == PolyEdgeSharp)
1856d514b0f3Smrg			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
1857d514b0f3Smrg		else
1858d514b0f3Smrg			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
1859d514b0f3Smrg		for (; ntrap; ntrap--, traps++)
1860d514b0f3Smrg			uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc,
1861d514b0f3Smrg				       1, traps);
1862d514b0f3Smrg	}
1863d514b0f3Smrg}
1864d514b0f3Smrg
1865d514b0f3Smrg/**
1866d514b0f3Smrg * uxa_triangles is essentially a copy of miTriangles that uses
1867d514b0f3Smrg * uxa_create_alpha_picture instead of miCreateAlphaPicture.
1868d514b0f3Smrg *
1869d514b0f3Smrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1870d514b0f3Smrg * to initialize the contents after creating the pixmap, which
1871d514b0f3Smrg * causes the pixmap to be moved in for acceleration. The subsequent
1872d514b0f3Smrg * call to AddTriangles won't be accelerated however, which forces the pixmap
1873d514b0f3Smrg * to be moved out again.
1874d514b0f3Smrg *
1875d514b0f3Smrg * uxa_create_alpha_picture avoids this roundtrip by using
1876d514b0f3Smrg * uxa_check_poly_fill_rect to initialize the contents.
1877d514b0f3Smrg */
1878d514b0f3Smrgvoid
1879d514b0f3Smrguxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1880d514b0f3Smrg	      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1881d514b0f3Smrg	      int ntri, xTriangle * tris)
1882d514b0f3Smrg{
1883d514b0f3Smrg	ScreenPtr pScreen = pDst->pDrawable->pScreen;
1884d514b0f3Smrg	PictureScreenPtr ps = GetPictureScreen(pScreen);
1885d514b0f3Smrg	BoxRec bounds;
1886d514b0f3Smrg	Bool direct = op == PictOpAdd && miIsSolidAlpha(pSrc);
1887d514b0f3Smrg
1888d514b0f3Smrg	if (maskFormat || direct) {
1889d514b0f3Smrg		miTriangleBounds(ntri, tris, &bounds);
1890d514b0f3Smrg
1891d514b0f3Smrg		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1892d514b0f3Smrg			return;
1893d514b0f3Smrg	}
1894d514b0f3Smrg
1895d514b0f3Smrg	/*
1896d514b0f3Smrg	 * Check for solid alpha add
1897d514b0f3Smrg	 */
1898d514b0f3Smrg	if (direct) {
1899d514b0f3Smrg		DrawablePtr pDraw = pDst->pDrawable;
1900d514b0f3Smrg		if (uxa_prepare_access(pDraw, NULL, UXA_ACCESS_RW)) {
1901d514b0f3Smrg			(*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
1902d514b0f3Smrg			uxa_finish_access(pDraw);
1903d514b0f3Smrg		}
1904d514b0f3Smrg	} else if (maskFormat) {
1905d514b0f3Smrg		PicturePtr pPicture;
1906d514b0f3Smrg		INT16 xDst, yDst;
1907d514b0f3Smrg		INT16 xRel, yRel;
1908d514b0f3Smrg		int width = bounds.x2 - bounds.x1;
1909d514b0f3Smrg		int height = bounds.y2 - bounds.y1;
1910d514b0f3Smrg		GCPtr pGC;
1911d514b0f3Smrg		xRectangle rect;
1912d514b0f3Smrg
1913d514b0f3Smrg		xDst = tris[0].p1.x >> 16;
1914d514b0f3Smrg		yDst = tris[0].p1.y >> 16;
1915d514b0f3Smrg
1916d514b0f3Smrg		pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat,
1917d514b0f3Smrg						    width, height);
1918d514b0f3Smrg		if (!pPicture)
1919d514b0f3Smrg			return;
1920d514b0f3Smrg
1921d514b0f3Smrg		/* Clear the alpha picture to 0. */
1922d514b0f3Smrg		pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen);
1923d514b0f3Smrg		if (!pGC) {
1924d514b0f3Smrg			FreePicture(pPicture, 0);
1925d514b0f3Smrg			return;
1926d514b0f3Smrg		}
1927d514b0f3Smrg		ValidateGC(pPicture->pDrawable, pGC);
1928d514b0f3Smrg		rect.x = 0;
1929d514b0f3Smrg		rect.y = 0;
1930d514b0f3Smrg		rect.width = width;
1931d514b0f3Smrg		rect.height = height;
1932d514b0f3Smrg		uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect);
1933d514b0f3Smrg		FreeScratchGC(pGC);
1934d514b0f3Smrg
1935d514b0f3Smrg		if (uxa_prepare_access(pPicture->pDrawable, NULL, UXA_ACCESS_RW)) {
1936d514b0f3Smrg			(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1,
1937d514b0f3Smrg					     ntri, tris);
1938d514b0f3Smrg			uxa_finish_access(pPicture->pDrawable);
1939d514b0f3Smrg		}
1940d514b0f3Smrg
1941d514b0f3Smrg		xRel = bounds.x1 + xSrc - xDst;
1942d514b0f3Smrg		yRel = bounds.y1 + ySrc - yDst;
1943d514b0f3Smrg		CompositePicture(op, pSrc, pPicture, pDst,
1944d514b0f3Smrg				 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1945d514b0f3Smrg				 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1946d514b0f3Smrg		FreePicture(pPicture, 0);
1947d514b0f3Smrg	} else {
1948d514b0f3Smrg		if (pDst->polyEdge == PolyEdgeSharp)
1949d514b0f3Smrg			maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1950d514b0f3Smrg		else
1951d514b0f3Smrg			maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1952d514b0f3Smrg
1953d514b0f3Smrg		for (; ntri; ntri--, tris++)
1954d514b0f3Smrg			uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1,
1955d514b0f3Smrg				      tris);
1956d514b0f3Smrg	}
1957d514b0f3Smrg}
1958