1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2001 Keith Packard
3428d7b3dSmrg *
4428d7b3dSmrg * Partly based on code that is Copyright © The XFree86 Project Inc.
5428d7b3dSmrg *
6428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
7428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
8428d7b3dSmrg * the above copyright notice appear in all copies and that both that
9428d7b3dSmrg * copyright notice and this permission notice appear in supporting
10428d7b3dSmrg * documentation, and that the name of Keith Packard not be used in
11428d7b3dSmrg * advertising or publicity pertaining to distribution of the software without
12428d7b3dSmrg * specific, written prior permission.  Keith Packard makes no
13428d7b3dSmrg * representations about the suitability of this software for any purpose.  It
14428d7b3dSmrg * is provided "as is" without express or implied warranty.
15428d7b3dSmrg *
16428d7b3dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17428d7b3dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18428d7b3dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19428d7b3dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20428d7b3dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21428d7b3dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22428d7b3dSmrg * PERFORMANCE OF THIS SOFTWARE.
23428d7b3dSmrg */
24428d7b3dSmrg
25428d7b3dSmrg#ifdef HAVE_DIX_CONFIG_H
26428d7b3dSmrg#include <dix-config.h>
27428d7b3dSmrg#endif
28428d7b3dSmrg
29428d7b3dSmrg#include <stdlib.h>
30428d7b3dSmrg
31428d7b3dSmrg#include "uxa-priv.h"
32428d7b3dSmrg
33428d7b3dSmrg#ifdef RENDER
34428d7b3dSmrg#include "mipict.h"
35428d7b3dSmrg
36428d7b3dSmrgstatic void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string,
37428d7b3dSmrg					     int n)
38428d7b3dSmrg{
39428d7b3dSmrg	char format[20];
40428d7b3dSmrg	char size[20];
41428d7b3dSmrg	char loc;
42428d7b3dSmrg
43428d7b3dSmrg	if (!pict) {
44428d7b3dSmrg		snprintf(string, n, "None");
45428d7b3dSmrg		return;
46428d7b3dSmrg	}
47428d7b3dSmrg
48428d7b3dSmrg	if (pict->pDrawable == NULL) {
49428d7b3dSmrg		snprintf(string, n, "source-only");
50428d7b3dSmrg		return;
51428d7b3dSmrg	}
52428d7b3dSmrg
53428d7b3dSmrg	switch (pict->format) {
54428d7b3dSmrg	case PICT_a8r8g8b8:
55428d7b3dSmrg		snprintf(format, 20, "ARGB8888");
56428d7b3dSmrg		break;
57428d7b3dSmrg	case PICT_x8r8g8b8:
58428d7b3dSmrg		snprintf(format, 20, "XRGB8888");
59428d7b3dSmrg		break;
60428d7b3dSmrg	case PICT_r5g6b5:
61428d7b3dSmrg		snprintf(format, 20, "RGB565  ");
62428d7b3dSmrg		break;
63428d7b3dSmrg	case PICT_x1r5g5b5:
64428d7b3dSmrg		snprintf(format, 20, "RGB555  ");
65428d7b3dSmrg		break;
66428d7b3dSmrg	case PICT_a8:
67428d7b3dSmrg		snprintf(format, 20, "A8      ");
68428d7b3dSmrg		break;
69428d7b3dSmrg	case PICT_a1:
70428d7b3dSmrg		snprintf(format, 20, "A1      ");
71428d7b3dSmrg		break;
72428d7b3dSmrg	default:
73428d7b3dSmrg		snprintf(format, 20, "0x%x", (int)pict->format);
74428d7b3dSmrg		break;
75428d7b3dSmrg	}
76428d7b3dSmrg
77428d7b3dSmrg	loc = uxa_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm';
78428d7b3dSmrg
79428d7b3dSmrg	snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
80428d7b3dSmrg		 pict->pDrawable->height, pict->repeat ? " R" : "");
81428d7b3dSmrg
82428d7b3dSmrg	snprintf(string, n, "%p:%c fmt %s (%s)%s",
83428d7b3dSmrg		 pict->pDrawable, loc, format, size,
84428d7b3dSmrg		 pict->alphaMap ? " with alpha map" :"");
85428d7b3dSmrg}
86428d7b3dSmrg
87428d7b3dSmrgstatic const char *
88428d7b3dSmrgop_to_string(CARD8 op)
89428d7b3dSmrg{
90428d7b3dSmrg    switch (op) {
91428d7b3dSmrg#define C(x) case PictOp##x: return #x
92428d7b3dSmrg	C(Clear);
93428d7b3dSmrg	C(Src);
94428d7b3dSmrg	C(Dst);
95428d7b3dSmrg	C(Over);
96428d7b3dSmrg	C(OverReverse);
97428d7b3dSmrg	C(In);
98428d7b3dSmrg	C(InReverse);
99428d7b3dSmrg	C(Out);
100428d7b3dSmrg	C(OutReverse);
101428d7b3dSmrg	C(Atop);
102428d7b3dSmrg	C(AtopReverse);
103428d7b3dSmrg	C(Xor);
104428d7b3dSmrg	C(Add);
105428d7b3dSmrg	C(Saturate);
106428d7b3dSmrg
107428d7b3dSmrg	/*
108428d7b3dSmrg	 * Operators only available in version 0.2
109428d7b3dSmrg	 */
110428d7b3dSmrg#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 2
111428d7b3dSmrg	C(DisjointClear);
112428d7b3dSmrg	C(DisjointSrc);
113428d7b3dSmrg	C(DisjointDst);
114428d7b3dSmrg	C(DisjointOver);
115428d7b3dSmrg	C(DisjointOverReverse);
116428d7b3dSmrg	C(DisjointIn);
117428d7b3dSmrg	C(DisjointInReverse);
118428d7b3dSmrg	C(DisjointOut);
119428d7b3dSmrg	C(DisjointOutReverse);
120428d7b3dSmrg	C(DisjointAtop);
121428d7b3dSmrg	C(DisjointAtopReverse);
122428d7b3dSmrg	C(DisjointXor);
123428d7b3dSmrg
124428d7b3dSmrg	C(ConjointClear);
125428d7b3dSmrg	C(ConjointSrc);
126428d7b3dSmrg	C(ConjointDst);
127428d7b3dSmrg	C(ConjointOver);
128428d7b3dSmrg	C(ConjointOverReverse);
129428d7b3dSmrg	C(ConjointIn);
130428d7b3dSmrg	C(ConjointInReverse);
131428d7b3dSmrg	C(ConjointOut);
132428d7b3dSmrg	C(ConjointOutReverse);
133428d7b3dSmrg	C(ConjointAtop);
134428d7b3dSmrg	C(ConjointAtopReverse);
135428d7b3dSmrg	C(ConjointXor);
136428d7b3dSmrg#endif
137428d7b3dSmrg
138428d7b3dSmrg	/*
139428d7b3dSmrg	 * Operators only available in version 0.11
140428d7b3dSmrg	 */
141428d7b3dSmrg#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 11
142428d7b3dSmrg	C(Multiply);
143428d7b3dSmrg	C(Screen);
144428d7b3dSmrg	C(Overlay);
145428d7b3dSmrg	C(Darken);
146428d7b3dSmrg	C(Lighten);
147428d7b3dSmrg	C(ColorDodge);
148428d7b3dSmrg	C(ColorBurn);
149428d7b3dSmrg	C(HardLight);
150428d7b3dSmrg	C(SoftLight);
151428d7b3dSmrg	C(Difference);
152428d7b3dSmrg	C(Exclusion);
153428d7b3dSmrg	C(HSLHue);
154428d7b3dSmrg	C(HSLSaturation);
155428d7b3dSmrg	C(HSLColor);
156428d7b3dSmrg	C(HSLLuminosity);
157428d7b3dSmrg#endif
158428d7b3dSmrg    default: return "garbage";
159428d7b3dSmrg#undef C
160428d7b3dSmrg    }
161428d7b3dSmrg}
162428d7b3dSmrg
163428d7b3dSmrgstatic void
164428d7b3dSmrguxa_print_composite_fallback(const char *func, CARD8 op,
165428d7b3dSmrg			     PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
166428d7b3dSmrg{
167428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
168428d7b3dSmrg	char srcdesc[40], maskdesc[40], dstdesc[40];
169428d7b3dSmrg
170428d7b3dSmrg	if (! uxa_screen->fallback_debug)
171428d7b3dSmrg		return;
172428d7b3dSmrg
173428d7b3dSmrg	/* Limit the noise if fallbacks are expected. */
174428d7b3dSmrg	if (uxa_screen->force_fallback)
175428d7b3dSmrg		return;
176428d7b3dSmrg
177428d7b3dSmrg	uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40);
178428d7b3dSmrg	uxa_composite_fallback_pict_desc(pMask, maskdesc, 40);
179428d7b3dSmrg	uxa_composite_fallback_pict_desc(pDst, dstdesc, 40);
180428d7b3dSmrg
181428d7b3dSmrg	ErrorF("Composite fallback at %s:\n"
182428d7b3dSmrg	       "  op   %s, \n"
183428d7b3dSmrg	       "  src  %s, \n"
184428d7b3dSmrg	       "  mask %s, \n"
185428d7b3dSmrg	       "  dst  %s, \n",
186428d7b3dSmrg	       func, op_to_string (op), srcdesc, maskdesc, dstdesc);
187428d7b3dSmrg}
188428d7b3dSmrg
189428d7b3dSmrgBool uxa_op_reads_destination(CARD8 op)
190428d7b3dSmrg{
191428d7b3dSmrg	/* FALSE (does not read destination) is the list of ops in the protocol
192428d7b3dSmrg	 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
193428d7b3dSmrg	 * That's just Clear and Src.  ReduceCompositeOp() will already have
194428d7b3dSmrg	 * converted con/disjoint clear/src to Clear or Src.
195428d7b3dSmrg	 */
196428d7b3dSmrg	switch (op) {
197428d7b3dSmrg	case PictOpClear:
198428d7b3dSmrg	case PictOpSrc:
199428d7b3dSmrg		return FALSE;
200428d7b3dSmrg	default:
201428d7b3dSmrg		return TRUE;
202428d7b3dSmrg	}
203428d7b3dSmrg}
204428d7b3dSmrg
205428d7b3dSmrgstatic Bool
206428d7b3dSmrguxa_get_pixel_from_rgba(CARD32 * pixel,
207428d7b3dSmrg			CARD16 red,
208428d7b3dSmrg			CARD16 green,
209428d7b3dSmrg			CARD16 blue,
210428d7b3dSmrg			CARD16 alpha,
211428d7b3dSmrg			CARD32 format)
212428d7b3dSmrg{
213428d7b3dSmrg	int rbits, bbits, gbits, abits;
214428d7b3dSmrg	int rshift, bshift, gshift, ashift;
215428d7b3dSmrg
216428d7b3dSmrg	rbits = PICT_FORMAT_R(format);
217428d7b3dSmrg	gbits = PICT_FORMAT_G(format);
218428d7b3dSmrg	bbits = PICT_FORMAT_B(format);
219428d7b3dSmrg	abits = PICT_FORMAT_A(format);
220428d7b3dSmrg	if (abits == 0)
221428d7b3dSmrg	    abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
222428d7b3dSmrg
223428d7b3dSmrg	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
224428d7b3dSmrg		*pixel = alpha >> (16 - abits);
225428d7b3dSmrg		return TRUE;
226428d7b3dSmrg	}
227428d7b3dSmrg
228428d7b3dSmrg	if (!PICT_FORMAT_COLOR(format))
229428d7b3dSmrg		return FALSE;
230428d7b3dSmrg
231428d7b3dSmrg	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
232428d7b3dSmrg		bshift = 0;
233428d7b3dSmrg		gshift = bbits;
234428d7b3dSmrg		rshift = gshift + gbits;
235428d7b3dSmrg		ashift = rshift + rbits;
236428d7b3dSmrg	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
237428d7b3dSmrg		rshift = 0;
238428d7b3dSmrg		gshift = rbits;
239428d7b3dSmrg		bshift = gshift + gbits;
240428d7b3dSmrg		ashift = bshift + bbits;
241428d7b3dSmrg#if XORG_VERSION_CURRENT >= 10699900
242428d7b3dSmrg	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
243428d7b3dSmrg		ashift = 0;
244428d7b3dSmrg		rshift = abits;
245428d7b3dSmrg		gshift = rshift + rbits;
246428d7b3dSmrg		bshift = gshift + gbits;
247428d7b3dSmrg#endif
248428d7b3dSmrg	} else {
249428d7b3dSmrg		return FALSE;
250428d7b3dSmrg	}
251428d7b3dSmrg
252428d7b3dSmrg	*pixel = 0;
253428d7b3dSmrg	*pixel |= (blue  >> (16 - bbits)) << bshift;
254428d7b3dSmrg	*pixel |= (green >> (16 - gbits)) << gshift;
255428d7b3dSmrg	*pixel |= (red   >> (16 - rbits)) << rshift;
256428d7b3dSmrg	*pixel |= (alpha >> (16 - abits)) << ashift;
257428d7b3dSmrg
258428d7b3dSmrg	return TRUE;
259428d7b3dSmrg}
260428d7b3dSmrg
261428d7b3dSmrgBool
262428d7b3dSmrguxa_get_rgba_from_pixel(CARD32 pixel,
263428d7b3dSmrg			CARD16 * red,
264428d7b3dSmrg			CARD16 * green,
265428d7b3dSmrg			CARD16 * blue,
266428d7b3dSmrg			CARD16 * alpha,
267428d7b3dSmrg			CARD32 format)
268428d7b3dSmrg{
269428d7b3dSmrg	int rbits, bbits, gbits, abits;
270428d7b3dSmrg	int rshift, bshift, gshift, ashift;
271428d7b3dSmrg
272428d7b3dSmrg	rbits = PICT_FORMAT_R(format);
273428d7b3dSmrg	gbits = PICT_FORMAT_G(format);
274428d7b3dSmrg	bbits = PICT_FORMAT_B(format);
275428d7b3dSmrg	abits = PICT_FORMAT_A(format);
276428d7b3dSmrg
277428d7b3dSmrg	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
278428d7b3dSmrg		rshift = gshift = bshift = ashift = 0;
279428d7b3dSmrg        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
280428d7b3dSmrg		bshift = 0;
281428d7b3dSmrg		gshift = bbits;
282428d7b3dSmrg		rshift = gshift + gbits;
283428d7b3dSmrg		ashift = rshift + rbits;
284428d7b3dSmrg        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
285428d7b3dSmrg		rshift = 0;
286428d7b3dSmrg		gshift = rbits;
287428d7b3dSmrg		bshift = gshift + gbits;
288428d7b3dSmrg		ashift = bshift + bbits;
289428d7b3dSmrg#if XORG_VERSION_CURRENT >= 10699900
290428d7b3dSmrg        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
291428d7b3dSmrg		ashift = 0;
292428d7b3dSmrg		rshift = abits;
293428d7b3dSmrg		if (abits == 0)
294428d7b3dSmrg			rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
295428d7b3dSmrg		gshift = rshift + rbits;
296428d7b3dSmrg		bshift = gshift + gbits;
297428d7b3dSmrg#endif
298428d7b3dSmrg	} else {
299428d7b3dSmrg		return FALSE;
300428d7b3dSmrg	}
301428d7b3dSmrg
302428d7b3dSmrg	if (rbits) {
303428d7b3dSmrg		*red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
304428d7b3dSmrg		while (rbits < 16) {
305428d7b3dSmrg			*red |= *red >> rbits;
306428d7b3dSmrg			rbits <<= 1;
307428d7b3dSmrg		}
308428d7b3dSmrg	} else
309428d7b3dSmrg		*red = 0;
310428d7b3dSmrg
311428d7b3dSmrg	if (gbits) {
312428d7b3dSmrg		*green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
313428d7b3dSmrg		while (gbits < 16) {
314428d7b3dSmrg			*green |= *green >> gbits;
315428d7b3dSmrg			gbits <<= 1;
316428d7b3dSmrg		}
317428d7b3dSmrg	} else
318428d7b3dSmrg		*green = 0;
319428d7b3dSmrg
320428d7b3dSmrg	if (bbits) {
321428d7b3dSmrg		*blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
322428d7b3dSmrg		while (bbits < 16) {
323428d7b3dSmrg			*blue |= *blue >> bbits;
324428d7b3dSmrg			bbits <<= 1;
325428d7b3dSmrg		}
326428d7b3dSmrg	} else
327428d7b3dSmrg		*blue = 0;
328428d7b3dSmrg
329428d7b3dSmrg	if (abits) {
330428d7b3dSmrg		*alpha =
331428d7b3dSmrg		    ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
332428d7b3dSmrg		while (abits < 16) {
333428d7b3dSmrg			*alpha |= *alpha >> abits;
334428d7b3dSmrg			abits <<= 1;
335428d7b3dSmrg		}
336428d7b3dSmrg	} else
337428d7b3dSmrg		*alpha = 0xffff;
338428d7b3dSmrg
339428d7b3dSmrg	return TRUE;
340428d7b3dSmrg}
341428d7b3dSmrg
342428d7b3dSmrgBool
343428d7b3dSmrguxa_get_color_for_pixmap (PixmapPtr	 pixmap,
344428d7b3dSmrg			  CARD32	 src_format,
345428d7b3dSmrg			  CARD32	 dst_format,
346428d7b3dSmrg			  CARD32	*pixel)
347428d7b3dSmrg{
348428d7b3dSmrg	CARD16 red, green, blue, alpha;
349428d7b3dSmrg
350428d7b3dSmrg	*pixel = uxa_get_pixmap_first_pixel(pixmap);
351428d7b3dSmrg
352428d7b3dSmrg	if (src_format != dst_format) {
353428d7b3dSmrg	    if (!uxa_get_rgba_from_pixel(*pixel,
354428d7b3dSmrg					 &red, &green, &blue, &alpha,
355428d7b3dSmrg					 src_format))
356428d7b3dSmrg		return FALSE;
357428d7b3dSmrg
358428d7b3dSmrg	    if (!uxa_get_pixel_from_rgba(pixel,
359428d7b3dSmrg					 red, green, blue, alpha,
360428d7b3dSmrg					 dst_format))
361428d7b3dSmrg		return FALSE;
362428d7b3dSmrg	}
363428d7b3dSmrg
364428d7b3dSmrg	return TRUE;
365428d7b3dSmrg}
366428d7b3dSmrg
367428d7b3dSmrgstatic int
368428d7b3dSmrguxa_try_driver_solid_fill(PicturePtr pSrc,
369428d7b3dSmrg			  PicturePtr pDst,
370428d7b3dSmrg			  INT16 xSrc,
371428d7b3dSmrg			  INT16 ySrc,
372428d7b3dSmrg			  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
373428d7b3dSmrg{
374428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
375428d7b3dSmrg	RegionRec region;
376428d7b3dSmrg	BoxPtr pbox;
377428d7b3dSmrg	int nbox;
378428d7b3dSmrg	int dst_off_x, dst_off_y;
379428d7b3dSmrg	PixmapPtr pSrcPix = NULL, pDstPix;
380428d7b3dSmrg	CARD32 pixel;
381428d7b3dSmrg
382428d7b3dSmrg	if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES))
383428d7b3dSmrg		return -1;
384428d7b3dSmrg
385428d7b3dSmrg	pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
386428d7b3dSmrg	if (!pDstPix)
387428d7b3dSmrg		return -1;
388428d7b3dSmrg
389428d7b3dSmrg	xDst += pDst->pDrawable->x;
390428d7b3dSmrg	yDst += pDst->pDrawable->y;
391428d7b3dSmrg
392428d7b3dSmrg	if (pSrc->pDrawable) {
393428d7b3dSmrg		pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
394428d7b3dSmrg		xSrc += pSrc->pDrawable->x;
395428d7b3dSmrg		ySrc += pSrc->pDrawable->y;
396428d7b3dSmrg	}
397428d7b3dSmrg
398428d7b3dSmrg	if (!miComputeCompositeRegion(&region, pSrc, NULL, pDst,
399428d7b3dSmrg				      xSrc, ySrc, 0, 0, xDst, yDst,
400428d7b3dSmrg				      width, height))
401428d7b3dSmrg		return 1;
402428d7b3dSmrg
403428d7b3dSmrg	if (pSrcPix) {
404428d7b3dSmrg		if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) {
405428d7b3dSmrg			REGION_UNINIT(pDst->pDrawable->pScreen, &region);
406428d7b3dSmrg			return -1;
407428d7b3dSmrg		}
408428d7b3dSmrg	} else {
409428d7b3dSmrg		SourcePict *source = pSrc->pSourcePict;
410428d7b3dSmrg		PictSolidFill *solid = &source->solidFill;
411428d7b3dSmrg
412428d7b3dSmrg		if (source == NULL || source->type != SourcePictTypeSolidFill) {
413428d7b3dSmrg			REGION_UNINIT(pDst->pDrawable->pScreen, &region);
414428d7b3dSmrg			return -1;
415428d7b3dSmrg		}
416428d7b3dSmrg
417428d7b3dSmrg		if (pDst->format == PICT_a8r8g8b8) {
418428d7b3dSmrg			pixel = solid->color;
419428d7b3dSmrg		} else if (pDst->format == PICT_x8r8g8b8) {
420428d7b3dSmrg			pixel = solid->color | 0xff000000;
421428d7b3dSmrg		} else {
422428d7b3dSmrg			CARD16 red, green, blue, alpha;
423428d7b3dSmrg
424428d7b3dSmrg			if (!uxa_get_rgba_from_pixel(solid->color,
425428d7b3dSmrg						     &red, &green, &blue, &alpha,
426428d7b3dSmrg						     PICT_a8r8g8b8) ||
427428d7b3dSmrg			    !uxa_get_pixel_from_rgba(&pixel,
428428d7b3dSmrg						     red, green, blue, alpha,
429428d7b3dSmrg						     pDst->format)) {
430428d7b3dSmrg				REGION_UNINIT(pDst->pDrawable->pScreen, &region);
431428d7b3dSmrg				return -1;
432428d7b3dSmrg			}
433428d7b3dSmrg		}
434428d7b3dSmrg	}
435428d7b3dSmrg
436428d7b3dSmrg	if (!(*uxa_screen->info->prepare_solid)
437428d7b3dSmrg	    (pDstPix, GXcopy, FB_ALLONES, pixel)) {
438428d7b3dSmrg		REGION_UNINIT(pDst->pDrawable->pScreen, &region);
439428d7b3dSmrg		return -1;
440428d7b3dSmrg	}
441428d7b3dSmrg
442428d7b3dSmrg	REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
443428d7b3dSmrg
444428d7b3dSmrg	nbox = REGION_NUM_RECTS(&region);
445428d7b3dSmrg	pbox = REGION_RECTS(&region);
446428d7b3dSmrg
447428d7b3dSmrg	while (nbox--) {
448428d7b3dSmrg		(*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1,
449428d7b3dSmrg					    pbox->x2, pbox->y2);
450428d7b3dSmrg		pbox++;
451428d7b3dSmrg	}
452428d7b3dSmrg
453428d7b3dSmrg	(*uxa_screen->info->done_solid) (pDstPix);
454428d7b3dSmrg
455428d7b3dSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
456428d7b3dSmrg	return 1;
457428d7b3dSmrg}
458428d7b3dSmrg
459428d7b3dSmrgstatic PicturePtr
460428d7b3dSmrguxa_picture_for_pixman_format(ScreenPtr screen,
461428d7b3dSmrg			      pixman_format_code_t format,
462428d7b3dSmrg			      int width, int height)
463428d7b3dSmrg{
464428d7b3dSmrg	PicturePtr picture;
465428d7b3dSmrg	PixmapPtr pixmap;
466428d7b3dSmrg	int error;
467428d7b3dSmrg
468428d7b3dSmrg	if (format == PIXMAN_a1)
469428d7b3dSmrg		format = PIXMAN_a8;
470428d7b3dSmrg
471428d7b3dSmrg	/* fill alpha if unset */
472428d7b3dSmrg	if (PIXMAN_FORMAT_A(format) == 0)
473428d7b3dSmrg	    format = PIXMAN_a8r8g8b8;
474428d7b3dSmrg
475428d7b3dSmrg	pixmap = screen->CreatePixmap(screen, width, height,
476428d7b3dSmrg					PIXMAN_FORMAT_DEPTH(format),
477428d7b3dSmrg					UXA_CREATE_PIXMAP_FOR_MAP);
478428d7b3dSmrg	if (!pixmap)
479428d7b3dSmrg		return 0;
480428d7b3dSmrg
481428d7b3dSmrg	if (!uxa_pixmap_is_offscreen(pixmap)) {
482428d7b3dSmrg		screen->DestroyPixmap(pixmap);
483428d7b3dSmrg		return 0;
484428d7b3dSmrg	}
485428d7b3dSmrg
486428d7b3dSmrg	picture = CreatePicture(0, &pixmap->drawable,
487428d7b3dSmrg				PictureMatchFormat(screen,
488428d7b3dSmrg						   PIXMAN_FORMAT_DEPTH(format),
489428d7b3dSmrg						   format),
490428d7b3dSmrg				0, 0, serverClient, &error);
491428d7b3dSmrg	screen->DestroyPixmap(pixmap);
492428d7b3dSmrg	if (!picture)
493428d7b3dSmrg		return 0;
494428d7b3dSmrg
495428d7b3dSmrg	ValidatePicture(picture);
496428d7b3dSmrg
497428d7b3dSmrg	return picture;
498428d7b3dSmrg}
499428d7b3dSmrg
500428d7b3dSmrgstatic PicturePtr
501428d7b3dSmrguxa_picture_from_pixman_image(ScreenPtr screen,
502428d7b3dSmrg			      pixman_image_t * image,
503428d7b3dSmrg			      pixman_format_code_t format)
504428d7b3dSmrg{
505428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
506428d7b3dSmrg	PicturePtr picture;
507428d7b3dSmrg	PixmapPtr pixmap;
508428d7b3dSmrg	int width, height;
509428d7b3dSmrg
510428d7b3dSmrg	width = pixman_image_get_width(image);
511428d7b3dSmrg	height = pixman_image_get_height(image);
512428d7b3dSmrg
513428d7b3dSmrg	picture = uxa_picture_for_pixman_format(screen, format,
514428d7b3dSmrg						width, height);
515428d7b3dSmrg	if (!picture)
516428d7b3dSmrg		return 0;
517428d7b3dSmrg
518428d7b3dSmrg	if (uxa_screen->info->put_image &&
519428d7b3dSmrg	    ((picture->pDrawable->depth << 24) | picture->format) == format &&
520428d7b3dSmrg	    uxa_screen->info->put_image((PixmapPtr)picture->pDrawable,
521428d7b3dSmrg					0, 0,
522428d7b3dSmrg					width, height,
523428d7b3dSmrg					(char *)pixman_image_get_data(image),
524428d7b3dSmrg					pixman_image_get_stride(image)))
525428d7b3dSmrg		return picture;
526428d7b3dSmrg
527428d7b3dSmrg	pixmap = GetScratchPixmapHeader(screen, width, height,
528428d7b3dSmrg					PIXMAN_FORMAT_DEPTH(format),
529428d7b3dSmrg					PIXMAN_FORMAT_BPP(format),
530428d7b3dSmrg					pixman_image_get_stride(image),
531428d7b3dSmrg					pixman_image_get_data(image));
532428d7b3dSmrg	if (!pixmap) {
533428d7b3dSmrg		FreePicture(picture, 0);
534428d7b3dSmrg		return 0;
535428d7b3dSmrg	}
536428d7b3dSmrg
537428d7b3dSmrg	if (((picture->pDrawable->depth << 24) | picture->format) == format) {
538428d7b3dSmrg		GCPtr gc;
539428d7b3dSmrg
540428d7b3dSmrg		gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen);
541428d7b3dSmrg		if (!gc) {
542428d7b3dSmrg			FreeScratchPixmapHeader(pixmap);
543428d7b3dSmrg			FreePicture(picture, 0);
544428d7b3dSmrg			return 0;
545428d7b3dSmrg		}
546428d7b3dSmrg		ValidateGC(picture->pDrawable, gc);
547428d7b3dSmrg
548428d7b3dSmrg		(*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable,
549428d7b3dSmrg				      gc, 0, 0, width, height, 0, 0);
550428d7b3dSmrg
551428d7b3dSmrg		FreeScratchGC(gc);
552428d7b3dSmrg	} else {
553428d7b3dSmrg		PicturePtr src;
554428d7b3dSmrg		int error;
555428d7b3dSmrg
556428d7b3dSmrg		src = CreatePicture(0, &pixmap->drawable,
557428d7b3dSmrg				    PictureMatchFormat(screen,
558428d7b3dSmrg						       PIXMAN_FORMAT_DEPTH(format),
559428d7b3dSmrg						       format),
560428d7b3dSmrg				    0, 0, serverClient, &error);
561428d7b3dSmrg		if (!src) {
562428d7b3dSmrg			FreeScratchPixmapHeader(pixmap);
563428d7b3dSmrg			FreePicture(picture, 0);
564428d7b3dSmrg			return 0;
565428d7b3dSmrg		}
566428d7b3dSmrg		ValidatePicture(src);
567428d7b3dSmrg
568428d7b3dSmrg		if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) {
569428d7b3dSmrg			fbComposite(PictOpSrc, src, NULL, picture,
570428d7b3dSmrg				    0, 0, 0, 0, 0, 0, width, height);
571428d7b3dSmrg			uxa_picture_finish_access(picture, UXA_ACCESS_RW);
572428d7b3dSmrg		}
573428d7b3dSmrg
574428d7b3dSmrg		FreePicture(src, 0);
575428d7b3dSmrg	}
576428d7b3dSmrg	FreeScratchPixmapHeader(pixmap);
577428d7b3dSmrg
578428d7b3dSmrg	return picture;
579428d7b3dSmrg}
580428d7b3dSmrg
581428d7b3dSmrgstatic PicturePtr
582428d7b3dSmrguxa_create_solid(ScreenPtr screen, uint32_t color)
583428d7b3dSmrg{
584428d7b3dSmrg	PixmapPtr pixmap;
585428d7b3dSmrg	PicturePtr picture;
586428d7b3dSmrg	XID repeat = RepeatNormal;
587428d7b3dSmrg	int error = 0;
588428d7b3dSmrg
589428d7b3dSmrg	pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32,
590428d7b3dSmrg					 UXA_CREATE_PIXMAP_FOR_MAP);
591428d7b3dSmrg	if (!pixmap)
592428d7b3dSmrg		return 0;
593428d7b3dSmrg
594428d7b3dSmrg	if (!uxa_prepare_access((DrawablePtr)pixmap, UXA_ACCESS_RW)) {
595428d7b3dSmrg		(*screen->DestroyPixmap)(pixmap);
596428d7b3dSmrg		return 0;
597428d7b3dSmrg	}
598428d7b3dSmrg	*((uint32_t *)pixmap->devPrivate.ptr) = color;
599428d7b3dSmrg	uxa_finish_access((DrawablePtr)pixmap, UXA_ACCESS_RW);
600428d7b3dSmrg
601428d7b3dSmrg	picture = CreatePicture(0, &pixmap->drawable,
602428d7b3dSmrg				PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
603428d7b3dSmrg				CPRepeat, &repeat, serverClient, &error);
604428d7b3dSmrg	(*screen->DestroyPixmap)(pixmap);
605428d7b3dSmrg
606428d7b3dSmrg	return picture;
607428d7b3dSmrg}
608428d7b3dSmrg
609428d7b3dSmrgstatic PicturePtr
610428d7b3dSmrguxa_solid_clear(ScreenPtr screen)
611428d7b3dSmrg{
612428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
613428d7b3dSmrg	PicturePtr picture;
614428d7b3dSmrg
615428d7b3dSmrg	if (!uxa_screen->solid_clear) {
616428d7b3dSmrg		uxa_screen->solid_clear = uxa_create_solid(screen, 0);
617428d7b3dSmrg		if (!uxa_screen->solid_clear)
618428d7b3dSmrg			return 0;
619428d7b3dSmrg	}
620428d7b3dSmrg	picture = uxa_screen->solid_clear;
621428d7b3dSmrg	return picture;
622428d7b3dSmrg}
623428d7b3dSmrg
624428d7b3dSmrgPicturePtr
625428d7b3dSmrguxa_acquire_solid(ScreenPtr screen, SourcePict *source)
626428d7b3dSmrg{
627428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
628428d7b3dSmrg	PictSolidFill *solid = &source->solidFill;
629428d7b3dSmrg	PicturePtr picture;
630428d7b3dSmrg	int i;
631428d7b3dSmrg
632428d7b3dSmrg	if ((solid->color >> 24) == 0) {
633428d7b3dSmrg		picture = uxa_solid_clear(screen);
634428d7b3dSmrg		if (!picture)
635428d7b3dSmrg		    return 0;
636428d7b3dSmrg
637428d7b3dSmrg		goto DONE;
638428d7b3dSmrg	} else if (solid->color == 0xff000000) {
639428d7b3dSmrg		if (!uxa_screen->solid_black) {
640428d7b3dSmrg			uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000);
641428d7b3dSmrg			if (!uxa_screen->solid_black)
642428d7b3dSmrg				return 0;
643428d7b3dSmrg		}
644428d7b3dSmrg		picture = uxa_screen->solid_black;
645428d7b3dSmrg		goto DONE;
646428d7b3dSmrg	} else if (solid->color == 0xffffffff) {
647428d7b3dSmrg		if (!uxa_screen->solid_white) {
648428d7b3dSmrg			uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff);
649428d7b3dSmrg			if (!uxa_screen->solid_white)
650428d7b3dSmrg				return 0;
651428d7b3dSmrg		}
652428d7b3dSmrg		picture = uxa_screen->solid_white;
653428d7b3dSmrg		goto DONE;
654428d7b3dSmrg	}
655428d7b3dSmrg
656428d7b3dSmrg	for (i = 0; i < uxa_screen->solid_cache_size; i++) {
657428d7b3dSmrg		if (uxa_screen->solid_cache[i].color == solid->color) {
658428d7b3dSmrg			picture = uxa_screen->solid_cache[i].picture;
659428d7b3dSmrg			goto DONE;
660428d7b3dSmrg		}
661428d7b3dSmrg	}
662428d7b3dSmrg
663428d7b3dSmrg	picture = uxa_create_solid(screen, solid->color);
664428d7b3dSmrg	if (!picture)
665428d7b3dSmrg		return 0;
666428d7b3dSmrg
667428d7b3dSmrg	if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) {
668428d7b3dSmrg		i = rand() % UXA_NUM_SOLID_CACHE;
669428d7b3dSmrg		FreePicture(uxa_screen->solid_cache[i].picture, 0);
670428d7b3dSmrg	} else
671428d7b3dSmrg		uxa_screen->solid_cache_size++;
672428d7b3dSmrg
673428d7b3dSmrg	uxa_screen->solid_cache[i].picture = picture;
674428d7b3dSmrg	uxa_screen->solid_cache[i].color = solid->color;
675428d7b3dSmrg
676428d7b3dSmrgDONE:
677428d7b3dSmrg	picture->refcnt++;
678428d7b3dSmrg	return picture;
679428d7b3dSmrg}
680428d7b3dSmrg
681428d7b3dSmrgPicturePtr
682428d7b3dSmrguxa_acquire_pattern(ScreenPtr pScreen,
683428d7b3dSmrg		    PicturePtr pSrc,
684428d7b3dSmrg		    pixman_format_code_t format,
685428d7b3dSmrg		    INT16 x, INT16 y, CARD16 width, CARD16 height)
686428d7b3dSmrg{
687428d7b3dSmrg	PicturePtr pDst;
688428d7b3dSmrg
689428d7b3dSmrg	if (pSrc->pSourcePict) {
690428d7b3dSmrg		SourcePict *source = pSrc->pSourcePict;
691428d7b3dSmrg		if (source->type == SourcePictTypeSolidFill)
692428d7b3dSmrg			return uxa_acquire_solid (pScreen, source);
693428d7b3dSmrg	}
694428d7b3dSmrg
695428d7b3dSmrg	pDst = uxa_picture_for_pixman_format(pScreen, format, width, height);
696428d7b3dSmrg	if (!pDst)
697428d7b3dSmrg		return 0;
698428d7b3dSmrg
699428d7b3dSmrg	if (uxa_picture_prepare_access(pDst, UXA_ACCESS_RW)) {
700428d7b3dSmrg		fbComposite(PictOpSrc, pSrc, NULL, pDst,
701428d7b3dSmrg			    x, y, 0, 0, 0, 0, width, height);
702428d7b3dSmrg		uxa_picture_finish_access(pDst, UXA_ACCESS_RW);
703428d7b3dSmrg		return pDst;
704428d7b3dSmrg	} else {
705428d7b3dSmrg		FreePicture(pDst, 0);
706428d7b3dSmrg		return 0;
707428d7b3dSmrg	}
708428d7b3dSmrg}
709428d7b3dSmrg
710428d7b3dSmrgstatic Bool
711428d7b3dSmrgtransform_is_integer_translation(PictTransformPtr t, int *tx, int *ty)
712428d7b3dSmrg{
713428d7b3dSmrg	if (t == NULL) {
714428d7b3dSmrg		*tx = *ty = 0;
715428d7b3dSmrg		return TRUE;
716428d7b3dSmrg	}
717428d7b3dSmrg
718428d7b3dSmrg	if (t->matrix[0][0] != IntToxFixed(1) ||
719428d7b3dSmrg	    t->matrix[0][1] != 0 ||
720428d7b3dSmrg	    t->matrix[1][0] != 0 ||
721428d7b3dSmrg	    t->matrix[1][1] != IntToxFixed(1) ||
722428d7b3dSmrg	    t->matrix[2][0] != 0 ||
723428d7b3dSmrg	    t->matrix[2][1] != 0 ||
724428d7b3dSmrg	    t->matrix[2][2] != IntToxFixed(1))
725428d7b3dSmrg		return FALSE;
726428d7b3dSmrg
727428d7b3dSmrg	if (xFixedFrac(t->matrix[0][2]) != 0 ||
728428d7b3dSmrg	    xFixedFrac(t->matrix[1][2]) != 0)
729428d7b3dSmrg		return FALSE;
730428d7b3dSmrg
731428d7b3dSmrg	*tx = xFixedToInt(t->matrix[0][2]);
732428d7b3dSmrg	*ty = xFixedToInt(t->matrix[1][2]);
733428d7b3dSmrg	return TRUE;
734428d7b3dSmrg}
735428d7b3dSmrg
736428d7b3dSmrgstatic PicturePtr
737428d7b3dSmrguxa_render_picture(ScreenPtr screen,
738428d7b3dSmrg		   PicturePtr src,
739428d7b3dSmrg		   pixman_format_code_t format,
740428d7b3dSmrg		   INT16 x, INT16 y,
741428d7b3dSmrg		   CARD16 width, CARD16 height)
742428d7b3dSmrg{
743428d7b3dSmrg	PicturePtr picture;
744428d7b3dSmrg	int ret = 0;
745428d7b3dSmrg
746428d7b3dSmrg	/* XXX we need a mechanism for the card to choose the fallback format */
747428d7b3dSmrg
748428d7b3dSmrg	/* force alpha channel in case source does not entirely cover the extents */
749428d7b3dSmrg	if (PIXMAN_FORMAT_A(format) == 0)
750428d7b3dSmrg		format = PIXMAN_a8r8g8b8; /* available on all hardware */
751428d7b3dSmrg
752428d7b3dSmrg	picture = uxa_picture_for_pixman_format(screen, format, width, height);
753428d7b3dSmrg	if (!picture)
754428d7b3dSmrg		return 0;
755428d7b3dSmrg
756428d7b3dSmrg	if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) {
757428d7b3dSmrg		if (uxa_picture_prepare_access(src, UXA_ACCESS_RO)) {
758428d7b3dSmrg			ret = 1;
759428d7b3dSmrg			fbComposite(PictOpSrc, src, NULL, picture,
760428d7b3dSmrg				    x, y, 0, 0, 0, 0, width, height);
761428d7b3dSmrg			uxa_picture_finish_access(src, UXA_ACCESS_RO);
762428d7b3dSmrg		}
763428d7b3dSmrg		uxa_picture_finish_access(picture, UXA_ACCESS_RW);
764428d7b3dSmrg	}
765428d7b3dSmrg
766428d7b3dSmrg	if (!ret) {
767428d7b3dSmrg		FreePicture(picture, 0);
768428d7b3dSmrg		return 0;
769428d7b3dSmrg	}
770428d7b3dSmrg
771428d7b3dSmrg	return picture;
772428d7b3dSmrg}
773428d7b3dSmrg
774428d7b3dSmrgstatic int
775428d7b3dSmrgdrawable_contains (DrawablePtr drawable, int x, int y, int w, int h)
776428d7b3dSmrg{
777428d7b3dSmrg	if (x < 0 || y < 0)
778428d7b3dSmrg		return FALSE;
779428d7b3dSmrg
780428d7b3dSmrg	if (x + w > drawable->width)
781428d7b3dSmrg		return FALSE;
782428d7b3dSmrg
783428d7b3dSmrg	if (y + h > drawable->height)
784428d7b3dSmrg		return FALSE;
785428d7b3dSmrg
786428d7b3dSmrg	return TRUE;
787428d7b3dSmrg}
788428d7b3dSmrg
789428d7b3dSmrgPicturePtr
790428d7b3dSmrguxa_acquire_drawable(ScreenPtr pScreen,
791428d7b3dSmrg		     PicturePtr pSrc,
792428d7b3dSmrg		     INT16 x, INT16 y,
793428d7b3dSmrg		     CARD16 width, CARD16 height,
794428d7b3dSmrg		     INT16 * out_x, INT16 * out_y)
795428d7b3dSmrg{
796428d7b3dSmrg	PixmapPtr pPixmap;
797428d7b3dSmrg	PicturePtr pDst;
798428d7b3dSmrg	int depth, error;
799428d7b3dSmrg	int tx, ty;
800428d7b3dSmrg	GCPtr pGC;
801428d7b3dSmrg
802428d7b3dSmrg	depth = pSrc->pDrawable->depth;
803428d7b3dSmrg	if (!transform_is_integer_translation(pSrc->transform, &tx, &ty) ||
804428d7b3dSmrg	    !drawable_contains(pSrc->pDrawable, x + tx, y + ty, width, height) ||
805428d7b3dSmrg	    depth == 1 ||
806428d7b3dSmrg	    pSrc->filter == PictFilterConvolution) {
807428d7b3dSmrg		/* XXX extract the sample extents and do the transformation on the GPU */
808428d7b3dSmrg		pDst = uxa_render_picture(pScreen, pSrc,
809428d7b3dSmrg					  pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24),
810428d7b3dSmrg					  x, y, width, height);
811428d7b3dSmrg		if (!pDst)
812428d7b3dSmrg			return 0;
813428d7b3dSmrg
814428d7b3dSmrg		goto done;
815428d7b3dSmrg	} else {
816428d7b3dSmrg		if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->height) {
817428d7b3dSmrg			*out_x = x + pSrc->pDrawable->x;
818428d7b3dSmrg			*out_y = y + pSrc->pDrawable->y;
819428d7b3dSmrg			return pSrc;
820428d7b3dSmrg		}
821428d7b3dSmrg	}
822428d7b3dSmrg
823428d7b3dSmrg	pPixmap = pScreen->CreatePixmap(pScreen,
824428d7b3dSmrg					width, height, depth,
825428d7b3dSmrg					CREATE_PIXMAP_USAGE_SCRATCH);
826428d7b3dSmrg	if (!pPixmap)
827428d7b3dSmrg		return 0;
828428d7b3dSmrg
829428d7b3dSmrg	/* Skip the copy if the result remains in memory and not a bo */
830428d7b3dSmrg	if (!uxa_pixmap_is_offscreen(pPixmap)) {
831428d7b3dSmrg		pScreen->DestroyPixmap(pPixmap);
832428d7b3dSmrg		return 0;
833428d7b3dSmrg	}
834428d7b3dSmrg
835428d7b3dSmrg	pGC = GetScratchGC(depth, pScreen);
836428d7b3dSmrg	if (!pGC) {
837428d7b3dSmrg		pScreen->DestroyPixmap(pPixmap);
838428d7b3dSmrg		return 0;
839428d7b3dSmrg	}
840428d7b3dSmrg
841428d7b3dSmrg	ValidateGC(&pPixmap->drawable, pGC);
842428d7b3dSmrg	pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC,
843428d7b3dSmrg			   x + tx, y + ty, width, height, 0, 0);
844428d7b3dSmrg	FreeScratchGC(pGC);
845428d7b3dSmrg
846428d7b3dSmrg	pDst = CreatePicture(0, &pPixmap->drawable,
847428d7b3dSmrg			     PictureMatchFormat(pScreen, depth, pSrc->format),
848428d7b3dSmrg			     0, 0, serverClient, &error);
849428d7b3dSmrg	pScreen->DestroyPixmap(pPixmap);
850428d7b3dSmrg	if (!pDst)
851428d7b3dSmrg		return 0;
852428d7b3dSmrg
853428d7b3dSmrg	ValidatePicture(pDst);
854428d7b3dSmrgdone:
855428d7b3dSmrg	pDst->componentAlpha = pSrc->componentAlpha;
856428d7b3dSmrg	*out_x = 0;
857428d7b3dSmrg	*out_y = 0;
858428d7b3dSmrg	return pDst;
859428d7b3dSmrg}
860428d7b3dSmrg
861428d7b3dSmrgstatic PicturePtr
862428d7b3dSmrguxa_acquire_picture(ScreenPtr screen,
863428d7b3dSmrg		    PicturePtr src,
864428d7b3dSmrg		    pixman_format_code_t format,
865428d7b3dSmrg		    INT16 x, INT16 y,
866428d7b3dSmrg		    CARD16 width, CARD16 height,
867428d7b3dSmrg		    INT16 * out_x, INT16 * out_y)
868428d7b3dSmrg{
869428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
870428d7b3dSmrg
871428d7b3dSmrg	if (uxa_screen->info->check_composite_texture &&
872428d7b3dSmrg	    uxa_screen->info->check_composite_texture(screen, src)) {
873428d7b3dSmrg		if (src->pDrawable) {
874428d7b3dSmrg			*out_x = x + src->pDrawable->x;
875428d7b3dSmrg			*out_y = y + src->pDrawable->y;
876428d7b3dSmrg		} else {
877428d7b3dSmrg			*out_x = x;
878428d7b3dSmrg			*out_y = y;
879428d7b3dSmrg		}
880428d7b3dSmrg		return src;
881428d7b3dSmrg	}
882428d7b3dSmrg
883428d7b3dSmrg	if (src->pDrawable) {
884428d7b3dSmrg		PicturePtr dst;
885428d7b3dSmrg
886428d7b3dSmrg		dst = uxa_acquire_drawable(screen, src,
887428d7b3dSmrg					   x, y, width, height,
888428d7b3dSmrg					   out_x, out_y);
889428d7b3dSmrg		if (!dst)
890428d7b3dSmrg			return 0;
891428d7b3dSmrg
892428d7b3dSmrg		if (uxa_screen->info->check_composite_texture &&
893428d7b3dSmrg		    !uxa_screen->info->check_composite_texture(screen, dst)) {
894428d7b3dSmrg			if (dst != src)
895428d7b3dSmrg				FreePicture(dst, 0);
896428d7b3dSmrg			return 0;
897428d7b3dSmrg		}
898428d7b3dSmrg
899428d7b3dSmrg		return dst;
900428d7b3dSmrg	}
901428d7b3dSmrg
902428d7b3dSmrg	*out_x = 0;
903428d7b3dSmrg	*out_y = 0;
904428d7b3dSmrg	return uxa_acquire_pattern(screen, src,
905428d7b3dSmrg				   format, x, y, width, height);
906428d7b3dSmrg}
907428d7b3dSmrg
908428d7b3dSmrgstatic PicturePtr
909428d7b3dSmrguxa_acquire_source(ScreenPtr screen,
910428d7b3dSmrg		   PicturePtr pict,
911428d7b3dSmrg		   INT16 x, INT16 y,
912428d7b3dSmrg		   CARD16 width, CARD16 height,
913428d7b3dSmrg		   INT16 * out_x, INT16 * out_y)
914428d7b3dSmrg{
915428d7b3dSmrg	return uxa_acquire_picture (screen, pict,
916428d7b3dSmrg				    PIXMAN_a8r8g8b8,
917428d7b3dSmrg				    x, y,
918428d7b3dSmrg				    width, height,
919428d7b3dSmrg				    out_x, out_y);
920428d7b3dSmrg}
921428d7b3dSmrg
922428d7b3dSmrgstatic PicturePtr
923428d7b3dSmrguxa_acquire_mask(ScreenPtr screen,
924428d7b3dSmrg		 PicturePtr pict,
925428d7b3dSmrg		 INT16 x, INT16 y,
926428d7b3dSmrg		 INT16 width, INT16 height,
927428d7b3dSmrg		 INT16 * out_x, INT16 * out_y)
928428d7b3dSmrg{
929428d7b3dSmrg	return uxa_acquire_picture (screen, pict,
930428d7b3dSmrg				    PIXMAN_a8,
931428d7b3dSmrg				    x, y,
932428d7b3dSmrg				    width, height,
933428d7b3dSmrg				    out_x, out_y);
934428d7b3dSmrg}
935428d7b3dSmrg
936428d7b3dSmrgstatic int
937428d7b3dSmrguxa_try_driver_composite(CARD8 op,
938428d7b3dSmrg			 PicturePtr pSrc,
939428d7b3dSmrg			 PicturePtr pMask,
940428d7b3dSmrg			 PicturePtr pDst,
941428d7b3dSmrg			 INT16 xSrc, INT16 ySrc,
942428d7b3dSmrg			 INT16 xMask, INT16 yMask,
943428d7b3dSmrg			 INT16 xDst, INT16 yDst,
944428d7b3dSmrg			 CARD16 width, CARD16 height)
945428d7b3dSmrg{
946428d7b3dSmrg	ScreenPtr screen = pDst->pDrawable->pScreen;
947428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
948428d7b3dSmrg	RegionRec region;
949428d7b3dSmrg	BoxPtr pbox;
950428d7b3dSmrg	int nbox;
951428d7b3dSmrg	int xDst_copy = 0, yDst_copy = 0;
952428d7b3dSmrg	int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
953428d7b3dSmrg	PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
954428d7b3dSmrg	PicturePtr localSrc, localMask = NULL;
955428d7b3dSmrg	PicturePtr localDst = pDst;
956428d7b3dSmrg
957428d7b3dSmrg	if (uxa_screen->info->check_composite &&
958428d7b3dSmrg	    !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height))
959428d7b3dSmrg		return -1;
960428d7b3dSmrg
961428d7b3dSmrg	if (uxa_screen->info->check_composite_target &&
962428d7b3dSmrg	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
963428d7b3dSmrg		int depth = pDst->pDrawable->depth;
964428d7b3dSmrg		PixmapPtr pixmap;
965428d7b3dSmrg		int error;
966428d7b3dSmrg		GCPtr gc;
967428d7b3dSmrg
968428d7b3dSmrg		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
969428d7b3dSmrg		if (uxa_screen->info->check_copy &&
970428d7b3dSmrg		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
971428d7b3dSmrg			return -1;
972428d7b3dSmrg
973428d7b3dSmrg		pixmap = screen->CreatePixmap(screen,
974428d7b3dSmrg					      width, height, depth,
975428d7b3dSmrg					      CREATE_PIXMAP_USAGE_SCRATCH);
976428d7b3dSmrg		if (!pixmap)
977428d7b3dSmrg			return 0;
978428d7b3dSmrg
979428d7b3dSmrg		gc = GetScratchGC(depth, screen);
980428d7b3dSmrg		if (!gc) {
981428d7b3dSmrg			screen->DestroyPixmap(pixmap);
982428d7b3dSmrg			return 0;
983428d7b3dSmrg		}
984428d7b3dSmrg
985428d7b3dSmrg		ValidateGC(&pixmap->drawable, gc);
986428d7b3dSmrg		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
987428d7b3dSmrg				  xDst, yDst, width, height, 0, 0);
988428d7b3dSmrg		FreeScratchGC(gc);
989428d7b3dSmrg
990428d7b3dSmrg		xDst_copy = xDst; xDst = 0;
991428d7b3dSmrg		yDst_copy = yDst; yDst = 0;
992428d7b3dSmrg
993428d7b3dSmrg		localDst = CreatePicture(0, &pixmap->drawable,
994428d7b3dSmrg					 PictureMatchFormat(screen, depth, pDst->format),
995428d7b3dSmrg					 0, 0, serverClient, &error);
996428d7b3dSmrg		screen->DestroyPixmap(pixmap);
997428d7b3dSmrg
998428d7b3dSmrg		if (!localDst)
999428d7b3dSmrg			return 0;
1000428d7b3dSmrg
1001428d7b3dSmrg		ValidatePicture(localDst);
1002428d7b3dSmrg	}
1003428d7b3dSmrg
1004428d7b3dSmrg	pDstPix =
1005428d7b3dSmrg	    uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y);
1006428d7b3dSmrg	if (!pDstPix) {
1007428d7b3dSmrg		if (localDst != pDst)
1008428d7b3dSmrg			FreePicture(localDst, 0);
1009428d7b3dSmrg		return -1;
1010428d7b3dSmrg	}
1011428d7b3dSmrg
1012428d7b3dSmrg	xDst += localDst->pDrawable->x;
1013428d7b3dSmrg	yDst += localDst->pDrawable->y;
1014428d7b3dSmrg
1015428d7b3dSmrg	localSrc = uxa_acquire_source(screen, pSrc,
1016428d7b3dSmrg				      xSrc, ySrc,
1017428d7b3dSmrg				      width, height,
1018428d7b3dSmrg				      &xSrc, &ySrc);
1019428d7b3dSmrg	if (!localSrc) {
1020428d7b3dSmrg		if (localDst != pDst)
1021428d7b3dSmrg			FreePicture(localDst, 0);
1022428d7b3dSmrg		return 0;
1023428d7b3dSmrg	}
1024428d7b3dSmrg
1025428d7b3dSmrg	if (pMask) {
1026428d7b3dSmrg		localMask = uxa_acquire_mask(screen, pMask,
1027428d7b3dSmrg					     xMask, yMask,
1028428d7b3dSmrg					     width, height,
1029428d7b3dSmrg					     &xMask, &yMask);
1030428d7b3dSmrg		if (!localMask) {
1031428d7b3dSmrg			if (localSrc != pSrc)
1032428d7b3dSmrg				FreePicture(localSrc, 0);
1033428d7b3dSmrg			if (localDst != pDst)
1034428d7b3dSmrg				FreePicture(localDst, 0);
1035428d7b3dSmrg
1036428d7b3dSmrg			return 0;
1037428d7b3dSmrg		}
1038428d7b3dSmrg	}
1039428d7b3dSmrg
1040428d7b3dSmrg	if (!miComputeCompositeRegion(&region, localSrc, localMask, localDst,
1041428d7b3dSmrg				      xSrc, ySrc, xMask, yMask, xDst, yDst,
1042428d7b3dSmrg				      width, height)) {
1043428d7b3dSmrg		if (localSrc != pSrc)
1044428d7b3dSmrg			FreePicture(localSrc, 0);
1045428d7b3dSmrg		if (localMask && localMask != pMask)
1046428d7b3dSmrg			FreePicture(localMask, 0);
1047428d7b3dSmrg		if (localDst != pDst)
1048428d7b3dSmrg			FreePicture(localDst, 0);
1049428d7b3dSmrg
1050428d7b3dSmrg		return 1;
1051428d7b3dSmrg	}
1052428d7b3dSmrg
1053428d7b3dSmrg	pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable,
1054428d7b3dSmrg					   &src_off_x, &src_off_y);
1055428d7b3dSmrg	if (!pSrcPix) {
1056428d7b3dSmrg		REGION_UNINIT(screen, &region);
1057428d7b3dSmrg
1058428d7b3dSmrg		if (localSrc != pSrc)
1059428d7b3dSmrg			FreePicture(localSrc, 0);
1060428d7b3dSmrg		if (localMask && localMask != pMask)
1061428d7b3dSmrg			FreePicture(localMask, 0);
1062428d7b3dSmrg		if (localDst != pDst)
1063428d7b3dSmrg			FreePicture(localDst, 0);
1064428d7b3dSmrg
1065428d7b3dSmrg		return 0;
1066428d7b3dSmrg	}
1067428d7b3dSmrg
1068428d7b3dSmrg	if (localMask) {
1069428d7b3dSmrg		pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable,
1070428d7b3dSmrg						    &mask_off_x, &mask_off_y);
1071428d7b3dSmrg		if (!pMaskPix) {
1072428d7b3dSmrg			REGION_UNINIT(screen, &region);
1073428d7b3dSmrg
1074428d7b3dSmrg			if (localSrc != pSrc)
1075428d7b3dSmrg				FreePicture(localSrc, 0);
1076428d7b3dSmrg			if (localMask && localMask != pMask)
1077428d7b3dSmrg				FreePicture(localMask, 0);
1078428d7b3dSmrg			if (localDst != pDst)
1079428d7b3dSmrg				FreePicture(localDst, 0);
1080428d7b3dSmrg
1081428d7b3dSmrg			return 0;
1082428d7b3dSmrg		}
1083428d7b3dSmrg	}
1084428d7b3dSmrg
1085428d7b3dSmrg	if (!(*uxa_screen->info->prepare_composite)
1086428d7b3dSmrg	    (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) {
1087428d7b3dSmrg		REGION_UNINIT(screen, &region);
1088428d7b3dSmrg
1089428d7b3dSmrg		if (localSrc != pSrc)
1090428d7b3dSmrg			FreePicture(localSrc, 0);
1091428d7b3dSmrg		if (localMask && localMask != pMask)
1092428d7b3dSmrg			FreePicture(localMask, 0);
1093428d7b3dSmrg		if (localDst != pDst)
1094428d7b3dSmrg			FreePicture(localDst, 0);
1095428d7b3dSmrg
1096428d7b3dSmrg		return -1;
1097428d7b3dSmrg	}
1098428d7b3dSmrg
1099428d7b3dSmrg	if (pMask) {
1100428d7b3dSmrg		xMask = xMask + mask_off_x - xDst;
1101428d7b3dSmrg		yMask = yMask + mask_off_y - yDst;
1102428d7b3dSmrg	}
1103428d7b3dSmrg
1104428d7b3dSmrg	xSrc = xSrc + src_off_x - xDst;
1105428d7b3dSmrg	ySrc = ySrc + src_off_y - yDst;
1106428d7b3dSmrg
1107428d7b3dSmrg	nbox = REGION_NUM_RECTS(&region);
1108428d7b3dSmrg	pbox = REGION_RECTS(&region);
1109428d7b3dSmrg	while (nbox--) {
1110428d7b3dSmrg		(*uxa_screen->info->composite) (pDstPix,
1111428d7b3dSmrg						pbox->x1 + xSrc,
1112428d7b3dSmrg						pbox->y1 + ySrc,
1113428d7b3dSmrg						pbox->x1 + xMask,
1114428d7b3dSmrg						pbox->y1 + yMask,
1115428d7b3dSmrg						pbox->x1 + dst_off_x,
1116428d7b3dSmrg						pbox->y1 + dst_off_y,
1117428d7b3dSmrg						pbox->x2 - pbox->x1,
1118428d7b3dSmrg						pbox->y2 - pbox->y1);
1119428d7b3dSmrg		pbox++;
1120428d7b3dSmrg	}
1121428d7b3dSmrg	(*uxa_screen->info->done_composite) (pDstPix);
1122428d7b3dSmrg
1123428d7b3dSmrg	REGION_UNINIT(screen, &region);
1124428d7b3dSmrg
1125428d7b3dSmrg	if (localSrc != pSrc)
1126428d7b3dSmrg		FreePicture(localSrc, 0);
1127428d7b3dSmrg	if (localMask && localMask != pMask)
1128428d7b3dSmrg		FreePicture(localMask, 0);
1129428d7b3dSmrg
1130428d7b3dSmrg	if (localDst != pDst) {
1131428d7b3dSmrg		GCPtr gc;
1132428d7b3dSmrg
1133428d7b3dSmrg		gc = GetScratchGC(pDst->pDrawable->depth, screen);
1134428d7b3dSmrg		if (gc) {
1135428d7b3dSmrg			ValidateGC(pDst->pDrawable, gc);
1136428d7b3dSmrg			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
1137428d7b3dSmrg					  0, 0, width, height, xDst_copy, yDst_copy);
1138428d7b3dSmrg			FreeScratchGC(gc);
1139428d7b3dSmrg		}
1140428d7b3dSmrg
1141428d7b3dSmrg		FreePicture(localDst, 0);
1142428d7b3dSmrg	}
1143428d7b3dSmrg
1144428d7b3dSmrg	return 1;
1145428d7b3dSmrg}
1146428d7b3dSmrg
1147428d7b3dSmrg/**
1148428d7b3dSmrg * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of
1149428d7b3dSmrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
1150428d7b3dSmrg * alpha and limited 1-tmu cards.
1151428d7b3dSmrg *
1152428d7b3dSmrg * From http://anholt.livejournal.com/32058.html:
1153428d7b3dSmrg *
1154428d7b3dSmrg * The trouble is that component-alpha rendering requires two different sources
1155428d7b3dSmrg * for blending: one for the source value to the blender, which is the
1156428d7b3dSmrg * per-channel multiplication of source and mask, and one for the source alpha
1157428d7b3dSmrg * for multiplying with the destination channels, which is the multiplication
1158428d7b3dSmrg * of the source channels by the mask alpha. So the equation for Over is:
1159428d7b3dSmrg *
1160428d7b3dSmrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
1161428d7b3dSmrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
1162428d7b3dSmrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
1163428d7b3dSmrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
1164428d7b3dSmrg *
1165428d7b3dSmrg * But we can do some simpler operations, right? How about PictOpOutReverse,
1166428d7b3dSmrg * which has a source factor of 0 and dest factor of (1 - source alpha). We
1167428d7b3dSmrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
1168428d7b3dSmrg * blenders pretty easily. So we can do a component-alpha OutReverse, which
1169428d7b3dSmrg * gets us:
1170428d7b3dSmrg *
1171428d7b3dSmrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
1172428d7b3dSmrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
1173428d7b3dSmrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
1174428d7b3dSmrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
1175428d7b3dSmrg *
1176428d7b3dSmrg * OK. And if an op doesn't use the source alpha value for the destination
1177428d7b3dSmrg * factor, then we can do the channel multiplication in the texture blenders
1178428d7b3dSmrg * to get the source value, and ignore the source alpha that we wouldn't use.
1179428d7b3dSmrg * We've supported this in the Radeon driver for a long time. An example would
1180428d7b3dSmrg * be PictOpAdd, which does:
1181428d7b3dSmrg *
1182428d7b3dSmrg * dst.A = src.A * mask.A + dst.A
1183428d7b3dSmrg * dst.R = src.R * mask.R + dst.R
1184428d7b3dSmrg * dst.G = src.G * mask.G + dst.G
1185428d7b3dSmrg * dst.B = src.B * mask.B + dst.B
1186428d7b3dSmrg *
1187428d7b3dSmrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
1188428d7b3dSmrg * after it, we get:
1189428d7b3dSmrg *
1190428d7b3dSmrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
1191428d7b3dSmrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
1192428d7b3dSmrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
1193428d7b3dSmrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
1194428d7b3dSmrg */
1195428d7b3dSmrg
1196428d7b3dSmrgstatic int
1197428d7b3dSmrguxa_try_magic_two_pass_composite_helper(CARD8 op,
1198428d7b3dSmrg					PicturePtr pSrc,
1199428d7b3dSmrg					PicturePtr pMask,
1200428d7b3dSmrg					PicturePtr pDst,
1201428d7b3dSmrg					INT16 xSrc, INT16 ySrc,
1202428d7b3dSmrg					INT16 xMask, INT16 yMask,
1203428d7b3dSmrg					INT16 xDst, INT16 yDst,
1204428d7b3dSmrg					CARD16 width, CARD16 height)
1205428d7b3dSmrg{
1206428d7b3dSmrg	ScreenPtr screen = pDst->pDrawable->pScreen;
1207428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1208428d7b3dSmrg	PicturePtr localDst = pDst;
1209428d7b3dSmrg	int xDst_copy, yDst_copy;
1210428d7b3dSmrg
1211428d7b3dSmrg	assert(op == PictOpOver);
1212428d7b3dSmrg
1213428d7b3dSmrg	if (uxa_screen->info->check_composite &&
1214428d7b3dSmrg	    (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc,
1215428d7b3dSmrg						    pMask, pDst, width, height)
1216428d7b3dSmrg	     || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask,
1217428d7b3dSmrg						       pDst, width, height))) {
1218428d7b3dSmrg		return -1;
1219428d7b3dSmrg	}
1220428d7b3dSmrg
1221428d7b3dSmrg	if (uxa_screen->info->check_composite_target &&
1222428d7b3dSmrg	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
1223428d7b3dSmrg		int depth = pDst->pDrawable->depth;
1224428d7b3dSmrg		PixmapPtr pixmap;
1225428d7b3dSmrg		int error;
1226428d7b3dSmrg		GCPtr gc;
1227428d7b3dSmrg
1228428d7b3dSmrg		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
1229428d7b3dSmrg		if (uxa_screen->info->check_copy &&
1230428d7b3dSmrg		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
1231428d7b3dSmrg			return -1;
1232428d7b3dSmrg
1233428d7b3dSmrg		pixmap = screen->CreatePixmap(screen,
1234428d7b3dSmrg					      width, height, depth,
1235428d7b3dSmrg					      CREATE_PIXMAP_USAGE_SCRATCH);
1236428d7b3dSmrg		if (!pixmap)
1237428d7b3dSmrg			return 0;
1238428d7b3dSmrg
1239428d7b3dSmrg		gc = GetScratchGC(depth, screen);
1240428d7b3dSmrg		if (!gc) {
1241428d7b3dSmrg			screen->DestroyPixmap(pixmap);
1242428d7b3dSmrg			return 0;
1243428d7b3dSmrg		}
1244428d7b3dSmrg
1245428d7b3dSmrg		ValidateGC(&pixmap->drawable, gc);
1246428d7b3dSmrg		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
1247428d7b3dSmrg				  xDst, yDst, width, height, 0, 0);
1248428d7b3dSmrg		FreeScratchGC(gc);
1249428d7b3dSmrg
1250428d7b3dSmrg		xDst_copy = xDst; xDst = 0;
1251428d7b3dSmrg		yDst_copy = yDst; yDst = 0;
1252428d7b3dSmrg
1253428d7b3dSmrg		localDst = CreatePicture(0, &pixmap->drawable,
1254428d7b3dSmrg					 PictureMatchFormat(screen, depth, pDst->format),
1255428d7b3dSmrg					 0, 0, serverClient, &error);
1256428d7b3dSmrg		screen->DestroyPixmap(pixmap);
1257428d7b3dSmrg
1258428d7b3dSmrg		if (!localDst)
1259428d7b3dSmrg			return 0;
1260428d7b3dSmrg
1261428d7b3dSmrg		ValidatePicture(localDst);
1262428d7b3dSmrg	}
1263428d7b3dSmrg
1264428d7b3dSmrg	/* Now, we think we should be able to accelerate this operation. First,
1265428d7b3dSmrg	 * composite the destination to be the destination times the source alpha
1266428d7b3dSmrg	 * factors.
1267428d7b3dSmrg	 */
1268428d7b3dSmrg	uxa_composite(PictOpOutReverse, pSrc, pMask, localDst,
1269428d7b3dSmrg		      xSrc, ySrc,
1270428d7b3dSmrg		      xMask, yMask,
1271428d7b3dSmrg		      xDst, yDst,
1272428d7b3dSmrg		      width, height);
1273428d7b3dSmrg
1274428d7b3dSmrg	/* Then, add in the source value times the destination alpha factors (1.0).
1275428d7b3dSmrg	 */
1276428d7b3dSmrg	uxa_composite(PictOpAdd, pSrc, pMask, localDst,
1277428d7b3dSmrg		      xSrc, ySrc,
1278428d7b3dSmrg		      xMask, yMask,
1279428d7b3dSmrg		      xDst, yDst,
1280428d7b3dSmrg		      width, height);
1281428d7b3dSmrg
1282428d7b3dSmrg	if (localDst != pDst) {
1283428d7b3dSmrg		GCPtr gc;
1284428d7b3dSmrg
1285428d7b3dSmrg		gc = GetScratchGC(pDst->pDrawable->depth, screen);
1286428d7b3dSmrg		if (gc) {
1287428d7b3dSmrg			ValidateGC(pDst->pDrawable, gc);
1288428d7b3dSmrg			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
1289428d7b3dSmrg					0, 0, width, height, xDst_copy, yDst_copy);
1290428d7b3dSmrg			FreeScratchGC(gc);
1291428d7b3dSmrg		}
1292428d7b3dSmrg
1293428d7b3dSmrg		FreePicture(localDst, 0);
1294428d7b3dSmrg	}
1295428d7b3dSmrg
1296428d7b3dSmrg	return 1;
1297428d7b3dSmrg}
1298428d7b3dSmrg
1299428d7b3dSmrgstatic int
1300428d7b3dSmrgcompatible_formats (CARD8 op, PicturePtr dst, PicturePtr src)
1301428d7b3dSmrg{
1302428d7b3dSmrg	if (op == PictOpSrc) {
1303428d7b3dSmrg		if (src->format == dst->format)
1304428d7b3dSmrg			return 1;
1305428d7b3dSmrg
1306428d7b3dSmrg		/* Is the destination an alpha-less version of source? */
1307428d7b3dSmrg		if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format),
1308428d7b3dSmrg					       PICT_FORMAT_TYPE(src->format),
1309428d7b3dSmrg					       0,
1310428d7b3dSmrg					       PICT_FORMAT_R(src->format),
1311428d7b3dSmrg					       PICT_FORMAT_G(src->format),
1312428d7b3dSmrg					       PICT_FORMAT_B(src->format)))
1313428d7b3dSmrg			return 1;
1314428d7b3dSmrg
1315428d7b3dSmrg		/* XXX xrgb is promoted to argb during image upload... */
1316428d7b3dSmrg#if 0
1317428d7b3dSmrg		if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8)
1318428d7b3dSmrg			return 1;
1319428d7b3dSmrg#endif
1320428d7b3dSmrg	} else if (op == PictOpOver) {
1321428d7b3dSmrg		if (PICT_FORMAT_A(src->format))
1322428d7b3dSmrg			return 0;
1323428d7b3dSmrg
1324428d7b3dSmrg		return src->format == dst->format;
1325428d7b3dSmrg	}
1326428d7b3dSmrg
1327428d7b3dSmrg	return 0;
1328428d7b3dSmrg}
1329428d7b3dSmrg
1330428d7b3dSmrgvoid
1331428d7b3dSmrguxa_composite(CARD8 op,
1332428d7b3dSmrg	      PicturePtr pSrc,
1333428d7b3dSmrg	      PicturePtr pMask,
1334428d7b3dSmrg	      PicturePtr pDst,
1335428d7b3dSmrg	      INT16 xSrc, INT16 ySrc,
1336428d7b3dSmrg	      INT16 xMask, INT16 yMask,
1337428d7b3dSmrg	      INT16 xDst, INT16 yDst,
1338428d7b3dSmrg	      CARD16 width, CARD16 height)
1339428d7b3dSmrg{
1340428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
1341428d7b3dSmrg	int ret = -1;
1342428d7b3dSmrg	Bool saveSrcRepeat = pSrc->repeat;
1343428d7b3dSmrg	Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
1344428d7b3dSmrg	RegionRec region;
1345428d7b3dSmrg	int tx, ty;
1346428d7b3dSmrg
1347428d7b3dSmrg	if (uxa_screen->force_fallback)
1348428d7b3dSmrg		goto fallback;
1349428d7b3dSmrg
1350428d7b3dSmrg	if (!uxa_drawable_is_offscreen(pDst->pDrawable))
1351428d7b3dSmrg		goto fallback;
1352428d7b3dSmrg
1353428d7b3dSmrg	if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap))
1354428d7b3dSmrg		goto fallback;
1355428d7b3dSmrg
1356428d7b3dSmrg	/* Remove repeat in source if useless */
1357428d7b3dSmrg	if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution &&
1358428d7b3dSmrg	    transform_is_integer_translation(pSrc->transform, &tx, &ty) &&
1359428d7b3dSmrg	    (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) &&
1360428d7b3dSmrg	    drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height))
1361428d7b3dSmrg		pSrc->repeat = 0;
1362428d7b3dSmrg
1363428d7b3dSmrg	if (!pMask) {
1364428d7b3dSmrg		if (op == PictOpClear) {
1365428d7b3dSmrg			PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen);
1366428d7b3dSmrg			if (clear &&
1367428d7b3dSmrg			    uxa_try_driver_solid_fill(clear, pDst,
1368428d7b3dSmrg						      xSrc, ySrc,
1369428d7b3dSmrg						      xDst, yDst,
1370428d7b3dSmrg						      width, height) == 1)
1371428d7b3dSmrg				goto done;
1372428d7b3dSmrg		}
1373428d7b3dSmrg
1374428d7b3dSmrg		if (pSrc->pDrawable == NULL) {
1375428d7b3dSmrg			if (pSrc->pSourcePict) {
1376428d7b3dSmrg				SourcePict *source = pSrc->pSourcePict;
1377428d7b3dSmrg				if (source->type == SourcePictTypeSolidFill) {
1378428d7b3dSmrg					if (op == PictOpSrc ||
1379428d7b3dSmrg					    (op == PictOpOver &&
1380428d7b3dSmrg					     (source->solidFill.color & 0xff000000) == 0xff000000)) {
1381428d7b3dSmrg						ret = uxa_try_driver_solid_fill(pSrc, pDst,
1382428d7b3dSmrg										xSrc, ySrc,
1383428d7b3dSmrg										xDst, yDst,
1384428d7b3dSmrg										width, height);
1385428d7b3dSmrg						if (ret == 1)
1386428d7b3dSmrg							goto done;
1387428d7b3dSmrg					}
1388428d7b3dSmrg				}
1389428d7b3dSmrg			}
1390428d7b3dSmrg		} else if (pSrc->pDrawable->width == 1 &&
1391428d7b3dSmrg			   pSrc->pDrawable->height == 1 &&
1392428d7b3dSmrg			   pSrc->repeat &&
1393428d7b3dSmrg			   (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) {
1394428d7b3dSmrg			ret = uxa_try_driver_solid_fill(pSrc, pDst,
1395428d7b3dSmrg							xSrc, ySrc,
1396428d7b3dSmrg							xDst, yDst,
1397428d7b3dSmrg							width, height);
1398428d7b3dSmrg			if (ret == 1)
1399428d7b3dSmrg				goto done;
1400428d7b3dSmrg		} else if (compatible_formats (op, pDst, pSrc) &&
1401428d7b3dSmrg			   pSrc->filter != PictFilterConvolution &&
1402428d7b3dSmrg			   transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
1403428d7b3dSmrg			if (!pSrc->repeat &&
1404428d7b3dSmrg			    drawable_contains(pSrc->pDrawable,
1405428d7b3dSmrg					     xSrc + tx, ySrc + ty,
1406428d7b3dSmrg					     width, height)) {
1407428d7b3dSmrg				xDst += pDst->pDrawable->x;
1408428d7b3dSmrg				yDst += pDst->pDrawable->y;
1409428d7b3dSmrg				xSrc += pSrc->pDrawable->x + tx;
1410428d7b3dSmrg				ySrc += pSrc->pDrawable->y + ty;
1411428d7b3dSmrg
1412428d7b3dSmrg				if (!miComputeCompositeRegion
1413428d7b3dSmrg				    (&region, pSrc, pMask, pDst, xSrc, ySrc,
1414428d7b3dSmrg				     xMask, yMask, xDst, yDst, width, height))
1415428d7b3dSmrg					goto done;
1416428d7b3dSmrg
1417428d7b3dSmrg				uxa_copy_n_to_n(pSrc->pDrawable,
1418428d7b3dSmrg						pDst->pDrawable, NULL,
1419428d7b3dSmrg						REGION_RECTS(&region),
1420428d7b3dSmrg						REGION_NUM_RECTS(&region),
1421428d7b3dSmrg						xSrc - xDst, ySrc - yDst, FALSE,
1422428d7b3dSmrg						FALSE, 0, NULL);
1423428d7b3dSmrg				REGION_UNINIT(pDst->pDrawable->pScreen,
1424428d7b3dSmrg					      &region);
1425428d7b3dSmrg				goto done;
1426428d7b3dSmrg			} else if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
1427428d7b3dSmrg				   pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
1428428d7b3dSmrg				DDXPointRec patOrg;
1429428d7b3dSmrg
1430428d7b3dSmrg				/* Let's see if the driver can do the repeat
1431428d7b3dSmrg				 * in one go
1432428d7b3dSmrg				 */
1433428d7b3dSmrg				if (uxa_screen->info->prepare_composite) {
1434428d7b3dSmrg					ret = uxa_try_driver_composite(op, pSrc,
1435428d7b3dSmrg								       pMask, pDst,
1436428d7b3dSmrg								       xSrc, ySrc,
1437428d7b3dSmrg								       xMask, yMask,
1438428d7b3dSmrg								       xDst, yDst,
1439428d7b3dSmrg								       width, height);
1440428d7b3dSmrg					if (ret == 1)
1441428d7b3dSmrg						goto done;
1442428d7b3dSmrg				}
1443428d7b3dSmrg
1444428d7b3dSmrg				/* Now see if we can use
1445428d7b3dSmrg				 * uxa_fill_region_tiled()
1446428d7b3dSmrg				 */
1447428d7b3dSmrg				xDst += pDst->pDrawable->x;
1448428d7b3dSmrg				yDst += pDst->pDrawable->y;
1449428d7b3dSmrg				xSrc += pSrc->pDrawable->x + tx;
1450428d7b3dSmrg				ySrc += pSrc->pDrawable->y + ty;
1451428d7b3dSmrg
1452428d7b3dSmrg				if (!miComputeCompositeRegion
1453428d7b3dSmrg				    (&region, pSrc, pMask, pDst, xSrc, ySrc,
1454428d7b3dSmrg				     xMask, yMask, xDst, yDst, width, height))
1455428d7b3dSmrg					goto done;
1456428d7b3dSmrg
1457428d7b3dSmrg				/* pattern origin is the point in the
1458428d7b3dSmrg				 * destination drawable
1459428d7b3dSmrg				 * corresponding to (0,0) in the source */
1460428d7b3dSmrg				patOrg.x = xDst - xSrc;
1461428d7b3dSmrg				patOrg.y = yDst - ySrc;
1462428d7b3dSmrg
1463428d7b3dSmrg				ret = uxa_fill_region_tiled(pDst->pDrawable,
1464428d7b3dSmrg							    &region,
1465428d7b3dSmrg							    (PixmapPtr) pSrc->
1466428d7b3dSmrg							    pDrawable, &patOrg,
1467428d7b3dSmrg							    FB_ALLONES, GXcopy);
1468428d7b3dSmrg
1469428d7b3dSmrg				REGION_UNINIT(pDst->pDrawable->pScreen,
1470428d7b3dSmrg					      &region);
1471428d7b3dSmrg
1472428d7b3dSmrg				if (ret)
1473428d7b3dSmrg					goto done;
1474428d7b3dSmrg			}
1475428d7b3dSmrg		}
1476428d7b3dSmrg	}
1477428d7b3dSmrg
1478428d7b3dSmrg	/* Remove repeat in mask if useless */
1479428d7b3dSmrg	if (pMask && pMask->pDrawable && pMask->repeat &&
1480428d7b3dSmrg	    pMask->filter != PictFilterConvolution &&
1481428d7b3dSmrg	    transform_is_integer_translation(pMask->transform, &tx, &ty) &&
1482428d7b3dSmrg	    (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) &&
1483428d7b3dSmrg	    drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height))
1484428d7b3dSmrg		pMask->repeat = 0;
1485428d7b3dSmrg
1486428d7b3dSmrg	if (uxa_screen->info->prepare_composite) {
1487428d7b3dSmrg		Bool isSrcSolid;
1488428d7b3dSmrg
1489428d7b3dSmrg		ret =
1490428d7b3dSmrg		    uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
1491428d7b3dSmrg					     xMask, yMask, xDst, yDst, width,
1492428d7b3dSmrg					     height);
1493428d7b3dSmrg		if (ret == 1)
1494428d7b3dSmrg			goto done;
1495428d7b3dSmrg
1496428d7b3dSmrg		/* For generic masks and solid src pictures, mach64 can do
1497428d7b3dSmrg		 * Over in two passes, similar to the component-alpha case.
1498428d7b3dSmrg		 */
1499428d7b3dSmrg
1500428d7b3dSmrg		isSrcSolid =
1501428d7b3dSmrg			pSrc->pDrawable ?
1502428d7b3dSmrg				pSrc->pDrawable->width == 1 &&
1503428d7b3dSmrg				pSrc->pDrawable->height == 1 &&
1504428d7b3dSmrg				pSrc->repeat :
1505428d7b3dSmrg			pSrc->pSourcePict ?
1506428d7b3dSmrg				pSrc->pSourcePict->type == SourcePictTypeSolidFill :
1507428d7b3dSmrg			0;
1508428d7b3dSmrg
1509428d7b3dSmrg		/* If we couldn't do the Composite in a single pass, and it
1510428d7b3dSmrg		 * was a component-alpha Over, see if we can do it in two
1511428d7b3dSmrg		 * passes with an OutReverse and then an Add.
1512428d7b3dSmrg		 */
1513428d7b3dSmrg		if (ret == -1 && op == PictOpOver && pMask &&
1514428d7b3dSmrg		    (pMask->componentAlpha || isSrcSolid)) {
1515428d7b3dSmrg			ret =
1516428d7b3dSmrg			    uxa_try_magic_two_pass_composite_helper(op, pSrc,
1517428d7b3dSmrg								    pMask, pDst,
1518428d7b3dSmrg								    xSrc, ySrc,
1519428d7b3dSmrg								    xMask, yMask,
1520428d7b3dSmrg								    xDst, yDst,
1521428d7b3dSmrg								    width, height);
1522428d7b3dSmrg			if (ret == 1)
1523428d7b3dSmrg				goto done;
1524428d7b3dSmrg		}
1525428d7b3dSmrg
1526428d7b3dSmrg	}
1527428d7b3dSmrg
1528428d7b3dSmrgfallback:
1529428d7b3dSmrg	uxa_print_composite_fallback("uxa_composite",
1530428d7b3dSmrg				     op, pSrc, pMask, pDst);
1531428d7b3dSmrg
1532428d7b3dSmrg	uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
1533428d7b3dSmrg			    xMask, yMask, xDst, yDst, width, height);
1534428d7b3dSmrg
1535428d7b3dSmrgdone:
1536428d7b3dSmrg	pSrc->repeat = saveSrcRepeat;
1537428d7b3dSmrg	if (pMask)
1538428d7b3dSmrg		pMask->repeat = saveMaskRepeat;
1539428d7b3dSmrg}
1540428d7b3dSmrg#endif
1541428d7b3dSmrg
1542428d7b3dSmrg/**
1543428d7b3dSmrg * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead
1544428d7b3dSmrg * of PolyFillRect to initialize the pixmap after creating it, to prevent
1545428d7b3dSmrg * the pixmap from being migrated.
1546428d7b3dSmrg *
1547428d7b3dSmrg * See the comments about uxa_trapezoids and uxa_triangles.
1548428d7b3dSmrg */
1549428d7b3dSmrgstatic PicturePtr
1550428d7b3dSmrguxa_create_alpha_picture(ScreenPtr pScreen,
1551428d7b3dSmrg			 PicturePtr pDst,
1552428d7b3dSmrg			 PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
1553428d7b3dSmrg{
1554428d7b3dSmrg	PixmapPtr pPixmap;
1555428d7b3dSmrg	PicturePtr pPicture;
1556428d7b3dSmrg	int error;
1557428d7b3dSmrg
1558428d7b3dSmrg	if (width > 32767 || height > 32767)
1559428d7b3dSmrg		return 0;
1560428d7b3dSmrg
1561428d7b3dSmrg	if (!pPictFormat) {
1562428d7b3dSmrg		if (pDst->polyEdge == PolyEdgeSharp)
1563428d7b3dSmrg			pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1564428d7b3dSmrg		else
1565428d7b3dSmrg			pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1566428d7b3dSmrg		if (!pPictFormat)
1567428d7b3dSmrg			return 0;
1568428d7b3dSmrg	}
1569428d7b3dSmrg
1570428d7b3dSmrg	pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1571428d7b3dSmrg					    pPictFormat->depth,
1572428d7b3dSmrg					    UXA_CREATE_PIXMAP_FOR_MAP);
1573428d7b3dSmrg	if (!pPixmap)
1574428d7b3dSmrg		return 0;
1575428d7b3dSmrg	pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
1576428d7b3dSmrg				 0, 0, serverClient, &error);
1577428d7b3dSmrg	(*pScreen->DestroyPixmap) (pPixmap);
1578428d7b3dSmrg	return pPicture;
1579428d7b3dSmrg}
1580428d7b3dSmrg
1581428d7b3dSmrgstatic void
1582428d7b3dSmrguxa_check_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
1583428d7b3dSmrg		     PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1584428d7b3dSmrg		     int ntrap, xTrapezoid * traps)
1585428d7b3dSmrg{
1586428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
1587428d7b3dSmrg
1588428d7b3dSmrg	if (maskFormat) {
1589428d7b3dSmrg		PixmapPtr scratch = NULL;
1590428d7b3dSmrg		PicturePtr mask;
1591428d7b3dSmrg		INT16 xDst, yDst;
1592428d7b3dSmrg		INT16 xRel, yRel;
1593428d7b3dSmrg		BoxRec bounds;
1594428d7b3dSmrg		int width, height;
1595428d7b3dSmrg		pixman_image_t *image;
1596428d7b3dSmrg		pixman_format_code_t format;
1597428d7b3dSmrg		int error;
1598428d7b3dSmrg
1599428d7b3dSmrg		xDst = traps[0].left.p1.x >> 16;
1600428d7b3dSmrg		yDst = traps[0].left.p1.y >> 16;
1601428d7b3dSmrg
1602428d7b3dSmrg		miTrapezoidBounds (ntrap, traps, &bounds);
1603428d7b3dSmrg		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1604428d7b3dSmrg			return;
1605428d7b3dSmrg
1606428d7b3dSmrg		width  = bounds.x2 - bounds.x1;
1607428d7b3dSmrg		height = bounds.y2 - bounds.y1;
1608428d7b3dSmrg
1609428d7b3dSmrg		format = maskFormat->format |
1610428d7b3dSmrg			(BitsPerPixel(maskFormat->depth) << 24);
1611428d7b3dSmrg		image =
1612428d7b3dSmrg		    pixman_image_create_bits(format, width, height, NULL, 0);
1613428d7b3dSmrg		if (!image)
1614428d7b3dSmrg			return;
1615428d7b3dSmrg
1616428d7b3dSmrg		for (; ntrap; ntrap--, traps++)
1617428d7b3dSmrg			pixman_rasterize_trapezoid(image,
1618428d7b3dSmrg						   (pixman_trapezoid_t *) traps,
1619428d7b3dSmrg						   -bounds.x1, -bounds.y1);
1620428d7b3dSmrg
1621428d7b3dSmrg
1622428d7b3dSmrg		scratch = GetScratchPixmapHeader(screen, width, height,
1623428d7b3dSmrg						 PIXMAN_FORMAT_DEPTH(format),
1624428d7b3dSmrg						 PIXMAN_FORMAT_BPP(format),
1625428d7b3dSmrg						 pixman_image_get_stride(image),
1626428d7b3dSmrg						 pixman_image_get_data(image));
1627428d7b3dSmrg		if (!scratch) {
1628428d7b3dSmrg			pixman_image_unref(image);
1629428d7b3dSmrg			return;
1630428d7b3dSmrg		}
1631428d7b3dSmrg
1632428d7b3dSmrg		mask = CreatePicture(0, &scratch->drawable,
1633428d7b3dSmrg				     PictureMatchFormat(screen,
1634428d7b3dSmrg							PIXMAN_FORMAT_DEPTH(format),
1635428d7b3dSmrg							format),
1636428d7b3dSmrg				     0, 0, serverClient, &error);
1637428d7b3dSmrg		if (!mask) {
1638428d7b3dSmrg			FreeScratchPixmapHeader(scratch);
1639428d7b3dSmrg			pixman_image_unref(image);
1640428d7b3dSmrg			return;
1641428d7b3dSmrg		}
1642428d7b3dSmrg
1643428d7b3dSmrg		xRel = bounds.x1 + xSrc - xDst;
1644428d7b3dSmrg		yRel = bounds.y1 + ySrc - yDst;
1645428d7b3dSmrg		CompositePicture(op, src, mask, dst,
1646428d7b3dSmrg				 xRel, yRel,
1647428d7b3dSmrg				 0, 0,
1648428d7b3dSmrg				 bounds.x1, bounds.y1,
1649428d7b3dSmrg				 width, height);
1650428d7b3dSmrg		FreePicture(mask, 0);
1651428d7b3dSmrg
1652428d7b3dSmrg		FreeScratchPixmapHeader(scratch);
1653428d7b3dSmrg		pixman_image_unref(image);
1654428d7b3dSmrg	} else {
1655428d7b3dSmrg		if (dst->polyEdge == PolyEdgeSharp)
1656428d7b3dSmrg			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
1657428d7b3dSmrg		else
1658428d7b3dSmrg			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
1659428d7b3dSmrg
1660428d7b3dSmrg		for (; ntrap; ntrap--, traps++)
1661428d7b3dSmrg			uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1, traps);
1662428d7b3dSmrg	}
1663428d7b3dSmrg}
1664428d7b3dSmrg
1665428d7b3dSmrg/**
1666428d7b3dSmrg * uxa_trapezoids is essentially a copy of miTrapezoids that uses
1667428d7b3dSmrg * uxa_create_alpha_picture instead of miCreateAlphaPicture.
1668428d7b3dSmrg *
1669428d7b3dSmrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1670428d7b3dSmrg * to initialize the contents after creating the pixmap, which
1671428d7b3dSmrg * causes the pixmap to be moved in for acceleration. The subsequent
1672428d7b3dSmrg * call to RasterizeTrapezoid won't be accelerated however, which
1673428d7b3dSmrg * forces the pixmap to be moved out again.
1674428d7b3dSmrg *
1675428d7b3dSmrg * uxa_create_alpha_picture avoids this roundtrip by using
1676428d7b3dSmrg * uxa_check_poly_fill_rect to initialize the contents.
1677428d7b3dSmrg */
1678428d7b3dSmrgvoid
1679428d7b3dSmrguxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
1680428d7b3dSmrg	       PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1681428d7b3dSmrg	       int ntrap, xTrapezoid * traps)
1682428d7b3dSmrg{
1683428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
1684428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1685428d7b3dSmrg	BoxRec bounds;
1686428d7b3dSmrg	Bool direct;
1687428d7b3dSmrg
1688428d7b3dSmrg	if (uxa_screen->force_fallback) {
1689428d7b3dSmrg		uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, ntrap, traps);
1690428d7b3dSmrg		return;
1691428d7b3dSmrg	}
1692428d7b3dSmrg
1693428d7b3dSmrg	direct = op == PictOpAdd && miIsSolidAlpha(src);
1694428d7b3dSmrg	if (maskFormat || direct) {
1695428d7b3dSmrg		miTrapezoidBounds(ntrap, traps, &bounds);
1696428d7b3dSmrg
1697428d7b3dSmrg		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1698428d7b3dSmrg			return;
1699428d7b3dSmrg	}
1700428d7b3dSmrg
1701428d7b3dSmrg	/*
1702428d7b3dSmrg	 * Check for solid alpha add
1703428d7b3dSmrg	 */
1704428d7b3dSmrg	if (direct) {
1705428d7b3dSmrg		DrawablePtr pDraw = dst->pDrawable;
1706428d7b3dSmrg		PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw);
1707428d7b3dSmrg		int xoff, yoff;
1708428d7b3dSmrg
1709428d7b3dSmrg		uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff);
1710428d7b3dSmrg
1711428d7b3dSmrg		xoff += pDraw->x;
1712428d7b3dSmrg		yoff += pDraw->y;
1713428d7b3dSmrg
1714428d7b3dSmrg		if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) {
1715428d7b3dSmrg			PictureScreenPtr ps = GetPictureScreen(screen);
1716428d7b3dSmrg
1717428d7b3dSmrg			for (; ntrap; ntrap--, traps++)
1718428d7b3dSmrg				(*ps->RasterizeTrapezoid) (dst, traps, 0, 0);
1719428d7b3dSmrg			uxa_finish_access(pDraw, UXA_ACCESS_RW);
1720428d7b3dSmrg		}
1721428d7b3dSmrg	} else if (maskFormat) {
1722428d7b3dSmrg		PixmapPtr scratch = NULL;
1723428d7b3dSmrg		PicturePtr mask;
1724428d7b3dSmrg		INT16 xDst, yDst;
1725428d7b3dSmrg		INT16 xRel, yRel;
1726428d7b3dSmrg		int width, height;
1727428d7b3dSmrg		pixman_image_t *image;
1728428d7b3dSmrg		pixman_format_code_t format;
1729428d7b3dSmrg
1730428d7b3dSmrg		xDst = traps[0].left.p1.x >> 16;
1731428d7b3dSmrg		yDst = traps[0].left.p1.y >> 16;
1732428d7b3dSmrg
1733428d7b3dSmrg		width  = bounds.x2 - bounds.x1;
1734428d7b3dSmrg		height = bounds.y2 - bounds.y1;
1735428d7b3dSmrg
1736428d7b3dSmrg		format = maskFormat->format |
1737428d7b3dSmrg			(BitsPerPixel(maskFormat->depth) << 24);
1738428d7b3dSmrg		image =
1739428d7b3dSmrg		    pixman_image_create_bits(format, width, height, NULL, 0);
1740428d7b3dSmrg		if (!image)
1741428d7b3dSmrg			return;
1742428d7b3dSmrg
1743428d7b3dSmrg		for (; ntrap; ntrap--, traps++)
1744428d7b3dSmrg			pixman_rasterize_trapezoid(image,
1745428d7b3dSmrg						   (pixman_trapezoid_t *) traps,
1746428d7b3dSmrg						   -bounds.x1, -bounds.y1);
1747428d7b3dSmrg		if (uxa_drawable_is_offscreen(dst->pDrawable)) {
1748428d7b3dSmrg			mask = uxa_picture_from_pixman_image(screen, image, format);
1749428d7b3dSmrg		} else {
1750428d7b3dSmrg			int error;
1751428d7b3dSmrg
1752428d7b3dSmrg			scratch = GetScratchPixmapHeader(screen, width, height,
1753428d7b3dSmrg							PIXMAN_FORMAT_DEPTH(format),
1754428d7b3dSmrg							PIXMAN_FORMAT_BPP(format),
1755428d7b3dSmrg							pixman_image_get_stride(image),
1756428d7b3dSmrg							pixman_image_get_data(image));
1757428d7b3dSmrg			mask = CreatePicture(0, &scratch->drawable,
1758428d7b3dSmrg					     PictureMatchFormat(screen,
1759428d7b3dSmrg								PIXMAN_FORMAT_DEPTH(format),
1760428d7b3dSmrg								format),
1761428d7b3dSmrg					     0, 0, serverClient, &error);
1762428d7b3dSmrg		}
1763428d7b3dSmrg		if (!mask) {
1764428d7b3dSmrg			if (scratch)
1765428d7b3dSmrg				FreeScratchPixmapHeader(scratch);
1766428d7b3dSmrg			pixman_image_unref(image);
1767428d7b3dSmrg			return;
1768428d7b3dSmrg		}
1769428d7b3dSmrg
1770428d7b3dSmrg		xRel = bounds.x1 + xSrc - xDst;
1771428d7b3dSmrg		yRel = bounds.y1 + ySrc - yDst;
1772428d7b3dSmrg		CompositePicture(op, src, mask, dst,
1773428d7b3dSmrg				 xRel, yRel,
1774428d7b3dSmrg				 0, 0,
1775428d7b3dSmrg				 bounds.x1, bounds.y1,
1776428d7b3dSmrg				 width, height);
1777428d7b3dSmrg		FreePicture(mask, 0);
1778428d7b3dSmrg
1779428d7b3dSmrg		if (scratch)
1780428d7b3dSmrg			FreeScratchPixmapHeader(scratch);
1781428d7b3dSmrg		pixman_image_unref(image);
1782428d7b3dSmrg	} else {
1783428d7b3dSmrg		if (dst->polyEdge == PolyEdgeSharp)
1784428d7b3dSmrg			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
1785428d7b3dSmrg		else
1786428d7b3dSmrg			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
1787428d7b3dSmrg		for (; ntrap; ntrap--, traps++)
1788428d7b3dSmrg			uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc,
1789428d7b3dSmrg				       1, traps);
1790428d7b3dSmrg	}
1791428d7b3dSmrg}
1792428d7b3dSmrg
1793428d7b3dSmrgstatic void
1794428d7b3dSmrguxa_check_triangles(CARD8 op, PicturePtr src, PicturePtr dst,
1795428d7b3dSmrg		    PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1796428d7b3dSmrg		    int ntri, xTriangle *tri)
1797428d7b3dSmrg{
1798428d7b3dSmrg	ScreenPtr screen = dst->pDrawable->pScreen;
1799428d7b3dSmrg
1800428d7b3dSmrg	if (maskFormat) {
1801428d7b3dSmrg		PixmapPtr scratch = NULL;
1802428d7b3dSmrg		PicturePtr mask;
1803428d7b3dSmrg		INT16 xDst, yDst;
1804428d7b3dSmrg		INT16 xRel, yRel;
1805428d7b3dSmrg		BoxRec bounds;
1806428d7b3dSmrg		int width, height;
1807428d7b3dSmrg		pixman_image_t *image;
1808428d7b3dSmrg		pixman_format_code_t format;
1809428d7b3dSmrg		int error;
1810428d7b3dSmrg
1811428d7b3dSmrg		xDst = pixman_fixed_to_int(tri[0].p1.x);
1812428d7b3dSmrg		yDst = pixman_fixed_to_int(tri[0].p1.y);
1813428d7b3dSmrg
1814428d7b3dSmrg		miTriangleBounds (ntri, tri, &bounds);
1815428d7b3dSmrg		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1816428d7b3dSmrg			return;
1817428d7b3dSmrg
1818428d7b3dSmrg		width  = bounds.x2 - bounds.x1;
1819428d7b3dSmrg		height = bounds.y2 - bounds.y1;
1820428d7b3dSmrg
1821428d7b3dSmrg		format = maskFormat->format |
1822428d7b3dSmrg			(BitsPerPixel(maskFormat->depth) << 24);
1823428d7b3dSmrg		image =
1824428d7b3dSmrg		    pixman_image_create_bits(format, width, height, NULL, 0);
1825428d7b3dSmrg		if (!image)
1826428d7b3dSmrg			return;
1827428d7b3dSmrg
1828428d7b3dSmrg		pixman_add_triangles(image,
1829428d7b3dSmrg				     -bounds.x1, -bounds.y1,
1830428d7b3dSmrg				     ntri, (pixman_triangle_t *)tri);
1831428d7b3dSmrg
1832428d7b3dSmrg		scratch = GetScratchPixmapHeader(screen, width, height,
1833428d7b3dSmrg						 PIXMAN_FORMAT_DEPTH(format),
1834428d7b3dSmrg						 PIXMAN_FORMAT_BPP(format),
1835428d7b3dSmrg						 pixman_image_get_stride(image),
1836428d7b3dSmrg						 pixman_image_get_data(image));
1837428d7b3dSmrg		if (!scratch) {
1838428d7b3dSmrg			pixman_image_unref(image);
1839428d7b3dSmrg			return;
1840428d7b3dSmrg		}
1841428d7b3dSmrg
1842428d7b3dSmrg		mask = CreatePicture(0, &scratch->drawable,
1843428d7b3dSmrg				     PictureMatchFormat(screen,
1844428d7b3dSmrg							PIXMAN_FORMAT_DEPTH(format),
1845428d7b3dSmrg							format),
1846428d7b3dSmrg				     0, 0, serverClient, &error);
1847428d7b3dSmrg		if (!mask) {
1848428d7b3dSmrg			FreeScratchPixmapHeader(scratch);
1849428d7b3dSmrg			pixman_image_unref(image);
1850428d7b3dSmrg			return;
1851428d7b3dSmrg		}
1852428d7b3dSmrg
1853428d7b3dSmrg		xRel = bounds.x1 + xSrc - xDst;
1854428d7b3dSmrg		yRel = bounds.y1 + ySrc - yDst;
1855428d7b3dSmrg		CompositePicture(op, src, mask, dst,
1856428d7b3dSmrg				 xRel, yRel,
1857428d7b3dSmrg				 0, 0,
1858428d7b3dSmrg				 bounds.x1, bounds.y1,
1859428d7b3dSmrg				 width, height);
1860428d7b3dSmrg		FreePicture(mask, 0);
1861428d7b3dSmrg
1862428d7b3dSmrg		FreeScratchPixmapHeader(scratch);
1863428d7b3dSmrg		pixman_image_unref(image);
1864428d7b3dSmrg	} else {
1865428d7b3dSmrg		if (dst->polyEdge == PolyEdgeSharp)
1866428d7b3dSmrg			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
1867428d7b3dSmrg		else
1868428d7b3dSmrg			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
1869428d7b3dSmrg
1870428d7b3dSmrg		for (; ntri; ntri--, tri++)
1871428d7b3dSmrg			uxa_check_triangles(op, src, dst, maskFormat, xSrc, ySrc, 1, tri);
1872428d7b3dSmrg	}
1873428d7b3dSmrg}
1874428d7b3dSmrg
1875428d7b3dSmrg/**
1876428d7b3dSmrg * uxa_triangles is essentially a copy of miTriangles that uses
1877428d7b3dSmrg * uxa_create_alpha_picture instead of miCreateAlphaPicture.
1878428d7b3dSmrg *
1879428d7b3dSmrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1880428d7b3dSmrg * to initialize the contents after creating the pixmap, which
1881428d7b3dSmrg * causes the pixmap to be moved in for acceleration. The subsequent
1882428d7b3dSmrg * call to AddTriangles won't be accelerated however, which forces the pixmap
1883428d7b3dSmrg * to be moved out again.
1884428d7b3dSmrg *
1885428d7b3dSmrg * uxa_create_alpha_picture avoids this roundtrip by using
1886428d7b3dSmrg * uxa_check_poly_fill_rect to initialize the contents.
1887428d7b3dSmrg */
1888428d7b3dSmrgvoid
1889428d7b3dSmrguxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1890428d7b3dSmrg	      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1891428d7b3dSmrg	      int ntri, xTriangle * tris)
1892428d7b3dSmrg{
1893428d7b3dSmrg	ScreenPtr pScreen = pDst->pDrawable->pScreen;
1894428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
1895428d7b3dSmrg	PictureScreenPtr ps = GetPictureScreen(pScreen);
1896428d7b3dSmrg	BoxRec bounds;
1897428d7b3dSmrg	Bool direct;
1898428d7b3dSmrg
1899428d7b3dSmrg	if (uxa_screen->force_fallback) {
1900428d7b3dSmrg		uxa_check_triangles(op, pSrc, pDst, maskFormat,
1901428d7b3dSmrg				    xSrc, ySrc, ntri, tris);
1902428d7b3dSmrg		return;
1903428d7b3dSmrg	}
1904428d7b3dSmrg
1905428d7b3dSmrg	direct = op == PictOpAdd && miIsSolidAlpha(pSrc);
1906428d7b3dSmrg	if (maskFormat || direct) {
1907428d7b3dSmrg		miTriangleBounds(ntri, tris, &bounds);
1908428d7b3dSmrg
1909428d7b3dSmrg		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1910428d7b3dSmrg			return;
1911428d7b3dSmrg	}
1912428d7b3dSmrg
1913428d7b3dSmrg	/*
1914428d7b3dSmrg	 * Check for solid alpha add
1915428d7b3dSmrg	 */
1916428d7b3dSmrg	if (direct) {
1917428d7b3dSmrg		DrawablePtr pDraw = pDst->pDrawable;
1918428d7b3dSmrg		if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) {
1919428d7b3dSmrg			(*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
1920428d7b3dSmrg			uxa_finish_access(pDraw, UXA_ACCESS_RW);
1921428d7b3dSmrg		}
1922428d7b3dSmrg	} else if (maskFormat) {
1923428d7b3dSmrg		PicturePtr pPicture;
1924428d7b3dSmrg		INT16 xDst, yDst;
1925428d7b3dSmrg		INT16 xRel, yRel;
1926428d7b3dSmrg		int width = bounds.x2 - bounds.x1;
1927428d7b3dSmrg		int height = bounds.y2 - bounds.y1;
1928428d7b3dSmrg		GCPtr pGC;
1929428d7b3dSmrg		xRectangle rect;
1930428d7b3dSmrg
1931428d7b3dSmrg		xDst = tris[0].p1.x >> 16;
1932428d7b3dSmrg		yDst = tris[0].p1.y >> 16;
1933428d7b3dSmrg
1934428d7b3dSmrg		pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat,
1935428d7b3dSmrg						    width, height);
1936428d7b3dSmrg		if (!pPicture)
1937428d7b3dSmrg			return;
1938428d7b3dSmrg
1939428d7b3dSmrg		/* Clear the alpha picture to 0. */
1940428d7b3dSmrg		pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen);
1941428d7b3dSmrg		if (!pGC) {
1942428d7b3dSmrg			FreePicture(pPicture, 0);
1943428d7b3dSmrg			return;
1944428d7b3dSmrg		}
1945428d7b3dSmrg		ValidateGC(pPicture->pDrawable, pGC);
1946428d7b3dSmrg		rect.x = 0;
1947428d7b3dSmrg		rect.y = 0;
1948428d7b3dSmrg		rect.width = width;
1949428d7b3dSmrg		rect.height = height;
1950428d7b3dSmrg		uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect);
1951428d7b3dSmrg		FreeScratchGC(pGC);
1952428d7b3dSmrg
1953428d7b3dSmrg		if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) {
1954428d7b3dSmrg			(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1,
1955428d7b3dSmrg					     ntri, tris);
1956428d7b3dSmrg			uxa_finish_access(pPicture->pDrawable, UXA_ACCESS_RW);
1957428d7b3dSmrg		}
1958428d7b3dSmrg
1959428d7b3dSmrg		xRel = bounds.x1 + xSrc - xDst;
1960428d7b3dSmrg		yRel = bounds.y1 + ySrc - yDst;
1961428d7b3dSmrg		CompositePicture(op, pSrc, pPicture, pDst,
1962428d7b3dSmrg				 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1963428d7b3dSmrg				 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1964428d7b3dSmrg		FreePicture(pPicture, 0);
1965428d7b3dSmrg	} else {
1966428d7b3dSmrg		if (pDst->polyEdge == PolyEdgeSharp)
1967428d7b3dSmrg			maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1968428d7b3dSmrg		else
1969428d7b3dSmrg			maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1970428d7b3dSmrg
1971428d7b3dSmrg		for (; ntri; ntri--, tris++)
1972428d7b3dSmrg			uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1,
1973428d7b3dSmrg				      tris);
1974428d7b3dSmrg	}
1975428d7b3dSmrg}
1976428d7b3dSmrg
1977428d7b3dSmrgvoid
1978428d7b3dSmrguxa_add_traps(PicturePtr pPicture,
1979428d7b3dSmrg	      INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
1980428d7b3dSmrg{
1981428d7b3dSmrg	uxa_check_add_traps(pPicture, x_off, y_off, ntrap, traps);
1982428d7b3dSmrg}
1983