103b705cfSriastradh/*
203b705cfSriastradh * Copyright © 2001 Keith Packard
303b705cfSriastradh *
403b705cfSriastradh * Partly based on code that is Copyright © The XFree86 Project Inc.
503b705cfSriastradh *
603b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its
703b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that
803b705cfSriastradh * the above copyright notice appear in all copies and that both that
903b705cfSriastradh * copyright notice and this permission notice appear in supporting
1003b705cfSriastradh * documentation, and that the name of Keith Packard not be used in
1103b705cfSriastradh * advertising or publicity pertaining to distribution of the software without
1203b705cfSriastradh * specific, written prior permission.  Keith Packard makes no
1303b705cfSriastradh * representations about the suitability of this software for any purpose.  It
1403b705cfSriastradh * is provided "as is" without express or implied warranty.
1503b705cfSriastradh *
1603b705cfSriastradh * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1703b705cfSriastradh * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1803b705cfSriastradh * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1903b705cfSriastradh * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2003b705cfSriastradh * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2103b705cfSriastradh * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2203b705cfSriastradh * PERFORMANCE OF THIS SOFTWARE.
2303b705cfSriastradh */
2403b705cfSriastradh
2503b705cfSriastradh#ifdef HAVE_DIX_CONFIG_H
2603b705cfSriastradh#include <dix-config.h>
2703b705cfSriastradh#endif
2803b705cfSriastradh
2903b705cfSriastradh#include <stdlib.h>
3003b705cfSriastradh
3103b705cfSriastradh#include "uxa-priv.h"
3203b705cfSriastradh
3303b705cfSriastradh#ifdef RENDER
3403b705cfSriastradh#include "mipict.h"
3503b705cfSriastradh
3603b705cfSriastradhstatic void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string,
3703b705cfSriastradh					     int n)
3803b705cfSriastradh{
3903b705cfSriastradh	char format[20];
4003b705cfSriastradh	char size[20];
4103b705cfSriastradh	char loc;
4203b705cfSriastradh
4303b705cfSriastradh	if (!pict) {
4403b705cfSriastradh		snprintf(string, n, "None");
4503b705cfSriastradh		return;
4603b705cfSriastradh	}
4703b705cfSriastradh
4803b705cfSriastradh	if (pict->pDrawable == NULL) {
4903b705cfSriastradh		snprintf(string, n, "source-only");
5003b705cfSriastradh		return;
5103b705cfSriastradh	}
5203b705cfSriastradh
5303b705cfSriastradh	switch (pict->format) {
5403b705cfSriastradh	case PICT_a8r8g8b8:
5503b705cfSriastradh		snprintf(format, 20, "ARGB8888");
5603b705cfSriastradh		break;
5703b705cfSriastradh	case PICT_x8r8g8b8:
5803b705cfSriastradh		snprintf(format, 20, "XRGB8888");
5903b705cfSriastradh		break;
6003b705cfSriastradh	case PICT_r5g6b5:
6103b705cfSriastradh		snprintf(format, 20, "RGB565  ");
6203b705cfSriastradh		break;
6303b705cfSriastradh	case PICT_x1r5g5b5:
6403b705cfSriastradh		snprintf(format, 20, "RGB555  ");
6503b705cfSriastradh		break;
6603b705cfSriastradh	case PICT_a8:
6703b705cfSriastradh		snprintf(format, 20, "A8      ");
6803b705cfSriastradh		break;
6903b705cfSriastradh	case PICT_a1:
7003b705cfSriastradh		snprintf(format, 20, "A1      ");
7103b705cfSriastradh		break;
7203b705cfSriastradh	default:
7303b705cfSriastradh		snprintf(format, 20, "0x%x", (int)pict->format);
7403b705cfSriastradh		break;
7503b705cfSriastradh	}
7603b705cfSriastradh
7703b705cfSriastradh	loc = uxa_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm';
7803b705cfSriastradh
7903b705cfSriastradh	snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
8003b705cfSriastradh		 pict->pDrawable->height, pict->repeat ? " R" : "");
8103b705cfSriastradh
8203b705cfSriastradh	snprintf(string, n, "%p:%c fmt %s (%s)%s",
8303b705cfSriastradh		 pict->pDrawable, loc, format, size,
8403b705cfSriastradh		 pict->alphaMap ? " with alpha map" :"");
8503b705cfSriastradh}
8603b705cfSriastradh
8703b705cfSriastradhstatic const char *
8803b705cfSriastradhop_to_string(CARD8 op)
8903b705cfSriastradh{
9003b705cfSriastradh    switch (op) {
9103b705cfSriastradh#define C(x) case PictOp##x: return #x
9203b705cfSriastradh	C(Clear);
9303b705cfSriastradh	C(Src);
9403b705cfSriastradh	C(Dst);
9503b705cfSriastradh	C(Over);
9603b705cfSriastradh	C(OverReverse);
9703b705cfSriastradh	C(In);
9803b705cfSriastradh	C(InReverse);
9903b705cfSriastradh	C(Out);
10003b705cfSriastradh	C(OutReverse);
10103b705cfSriastradh	C(Atop);
10203b705cfSriastradh	C(AtopReverse);
10303b705cfSriastradh	C(Xor);
10403b705cfSriastradh	C(Add);
10503b705cfSriastradh	C(Saturate);
10603b705cfSriastradh
10703b705cfSriastradh	/*
10803b705cfSriastradh	 * Operators only available in version 0.2
10903b705cfSriastradh	 */
11003b705cfSriastradh#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 2
11103b705cfSriastradh	C(DisjointClear);
11203b705cfSriastradh	C(DisjointSrc);
11303b705cfSriastradh	C(DisjointDst);
11403b705cfSriastradh	C(DisjointOver);
11503b705cfSriastradh	C(DisjointOverReverse);
11603b705cfSriastradh	C(DisjointIn);
11703b705cfSriastradh	C(DisjointInReverse);
11803b705cfSriastradh	C(DisjointOut);
11903b705cfSriastradh	C(DisjointOutReverse);
12003b705cfSriastradh	C(DisjointAtop);
12103b705cfSriastradh	C(DisjointAtopReverse);
12203b705cfSriastradh	C(DisjointXor);
12303b705cfSriastradh
12403b705cfSriastradh	C(ConjointClear);
12503b705cfSriastradh	C(ConjointSrc);
12603b705cfSriastradh	C(ConjointDst);
12703b705cfSriastradh	C(ConjointOver);
12803b705cfSriastradh	C(ConjointOverReverse);
12903b705cfSriastradh	C(ConjointIn);
13003b705cfSriastradh	C(ConjointInReverse);
13103b705cfSriastradh	C(ConjointOut);
13203b705cfSriastradh	C(ConjointOutReverse);
13303b705cfSriastradh	C(ConjointAtop);
13403b705cfSriastradh	C(ConjointAtopReverse);
13503b705cfSriastradh	C(ConjointXor);
13603b705cfSriastradh#endif
13703b705cfSriastradh
13803b705cfSriastradh	/*
13903b705cfSriastradh	 * Operators only available in version 0.11
14003b705cfSriastradh	 */
14103b705cfSriastradh#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 11
14203b705cfSriastradh	C(Multiply);
14303b705cfSriastradh	C(Screen);
14403b705cfSriastradh	C(Overlay);
14503b705cfSriastradh	C(Darken);
14603b705cfSriastradh	C(Lighten);
14703b705cfSriastradh	C(ColorDodge);
14803b705cfSriastradh	C(ColorBurn);
14903b705cfSriastradh	C(HardLight);
15003b705cfSriastradh	C(SoftLight);
15103b705cfSriastradh	C(Difference);
15203b705cfSriastradh	C(Exclusion);
15303b705cfSriastradh	C(HSLHue);
15403b705cfSriastradh	C(HSLSaturation);
15503b705cfSriastradh	C(HSLColor);
15603b705cfSriastradh	C(HSLLuminosity);
15703b705cfSriastradh#endif
15803b705cfSriastradh    default: return "garbage";
15903b705cfSriastradh#undef C
16003b705cfSriastradh    }
16103b705cfSriastradh}
16203b705cfSriastradh
16303b705cfSriastradhstatic void
16403b705cfSriastradhuxa_print_composite_fallback(const char *func, CARD8 op,
16503b705cfSriastradh			     PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
16603b705cfSriastradh{
16703b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
16803b705cfSriastradh	char srcdesc[40], maskdesc[40], dstdesc[40];
16903b705cfSriastradh
17003b705cfSriastradh	if (! uxa_screen->fallback_debug)
17103b705cfSriastradh		return;
17203b705cfSriastradh
17303b705cfSriastradh	/* Limit the noise if fallbacks are expected. */
17403b705cfSriastradh	if (uxa_screen->force_fallback)
17503b705cfSriastradh		return;
17603b705cfSriastradh
17703b705cfSriastradh	uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40);
17803b705cfSriastradh	uxa_composite_fallback_pict_desc(pMask, maskdesc, 40);
17903b705cfSriastradh	uxa_composite_fallback_pict_desc(pDst, dstdesc, 40);
18003b705cfSriastradh
18103b705cfSriastradh	ErrorF("Composite fallback at %s:\n"
18203b705cfSriastradh	       "  op   %s, \n"
18303b705cfSriastradh	       "  src  %s, \n"
18403b705cfSriastradh	       "  mask %s, \n"
18503b705cfSriastradh	       "  dst  %s, \n",
18603b705cfSriastradh	       func, op_to_string (op), srcdesc, maskdesc, dstdesc);
18703b705cfSriastradh}
18803b705cfSriastradh
18903b705cfSriastradhBool uxa_op_reads_destination(CARD8 op)
19003b705cfSriastradh{
19103b705cfSriastradh	/* FALSE (does not read destination) is the list of ops in the protocol
19203b705cfSriastradh	 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
19303b705cfSriastradh	 * That's just Clear and Src.  ReduceCompositeOp() will already have
19403b705cfSriastradh	 * converted con/disjoint clear/src to Clear or Src.
19503b705cfSriastradh	 */
19603b705cfSriastradh	switch (op) {
19703b705cfSriastradh	case PictOpClear:
19803b705cfSriastradh	case PictOpSrc:
19903b705cfSriastradh		return FALSE;
20003b705cfSriastradh	default:
20103b705cfSriastradh		return TRUE;
20203b705cfSriastradh	}
20303b705cfSriastradh}
20403b705cfSriastradh
20503b705cfSriastradhstatic Bool
20603b705cfSriastradhuxa_get_pixel_from_rgba(CARD32 * pixel,
20703b705cfSriastradh			CARD16 red,
20803b705cfSriastradh			CARD16 green,
20903b705cfSriastradh			CARD16 blue,
21003b705cfSriastradh			CARD16 alpha,
21103b705cfSriastradh			CARD32 format)
21203b705cfSriastradh{
21303b705cfSriastradh	int rbits, bbits, gbits, abits;
21403b705cfSriastradh	int rshift, bshift, gshift, ashift;
21503b705cfSriastradh
21603b705cfSriastradh	rbits = PICT_FORMAT_R(format);
21703b705cfSriastradh	gbits = PICT_FORMAT_G(format);
21803b705cfSriastradh	bbits = PICT_FORMAT_B(format);
21903b705cfSriastradh	abits = PICT_FORMAT_A(format);
22003b705cfSriastradh	if (abits == 0)
22103b705cfSriastradh	    abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
22203b705cfSriastradh
22303b705cfSriastradh	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
22403b705cfSriastradh		*pixel = alpha >> (16 - abits);
22503b705cfSriastradh		return TRUE;
22603b705cfSriastradh	}
22703b705cfSriastradh
22803b705cfSriastradh	if (!PICT_FORMAT_COLOR(format))
22903b705cfSriastradh		return FALSE;
23003b705cfSriastradh
23103b705cfSriastradh	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
23203b705cfSriastradh		bshift = 0;
23303b705cfSriastradh		gshift = bbits;
23403b705cfSriastradh		rshift = gshift + gbits;
23503b705cfSriastradh		ashift = rshift + rbits;
23603b705cfSriastradh	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
23703b705cfSriastradh		rshift = 0;
23803b705cfSriastradh		gshift = rbits;
23903b705cfSriastradh		bshift = gshift + gbits;
24003b705cfSriastradh		ashift = bshift + bbits;
24103b705cfSriastradh#if XORG_VERSION_CURRENT >= 10699900
24203b705cfSriastradh	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
24303b705cfSriastradh		ashift = 0;
24403b705cfSriastradh		rshift = abits;
24503b705cfSriastradh		gshift = rshift + rbits;
24603b705cfSriastradh		bshift = gshift + gbits;
24703b705cfSriastradh#endif
24803b705cfSriastradh	} else {
24903b705cfSriastradh		return FALSE;
25003b705cfSriastradh	}
25103b705cfSriastradh
25203b705cfSriastradh	*pixel = 0;
25303b705cfSriastradh	*pixel |= (blue  >> (16 - bbits)) << bshift;
25403b705cfSriastradh	*pixel |= (green >> (16 - gbits)) << gshift;
25503b705cfSriastradh	*pixel |= (red   >> (16 - rbits)) << rshift;
25603b705cfSriastradh	*pixel |= (alpha >> (16 - abits)) << ashift;
25703b705cfSriastradh
25803b705cfSriastradh	return TRUE;
25903b705cfSriastradh}
26003b705cfSriastradh
26103b705cfSriastradhBool
26203b705cfSriastradhuxa_get_rgba_from_pixel(CARD32 pixel,
26303b705cfSriastradh			CARD16 * red,
26403b705cfSriastradh			CARD16 * green,
26503b705cfSriastradh			CARD16 * blue,
26603b705cfSriastradh			CARD16 * alpha,
26703b705cfSriastradh			CARD32 format)
26803b705cfSriastradh{
26903b705cfSriastradh	int rbits, bbits, gbits, abits;
27003b705cfSriastradh	int rshift, bshift, gshift, ashift;
27103b705cfSriastradh
27203b705cfSriastradh	rbits = PICT_FORMAT_R(format);
27303b705cfSriastradh	gbits = PICT_FORMAT_G(format);
27403b705cfSriastradh	bbits = PICT_FORMAT_B(format);
27503b705cfSriastradh	abits = PICT_FORMAT_A(format);
27603b705cfSriastradh
27703b705cfSriastradh	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
27803b705cfSriastradh		rshift = gshift = bshift = ashift = 0;
27903b705cfSriastradh        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
28003b705cfSriastradh		bshift = 0;
28103b705cfSriastradh		gshift = bbits;
28203b705cfSriastradh		rshift = gshift + gbits;
28303b705cfSriastradh		ashift = rshift + rbits;
28403b705cfSriastradh        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
28503b705cfSriastradh		rshift = 0;
28603b705cfSriastradh		gshift = rbits;
28703b705cfSriastradh		bshift = gshift + gbits;
28803b705cfSriastradh		ashift = bshift + bbits;
28903b705cfSriastradh#if XORG_VERSION_CURRENT >= 10699900
29003b705cfSriastradh        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
29103b705cfSriastradh		ashift = 0;
29203b705cfSriastradh		rshift = abits;
29303b705cfSriastradh		if (abits == 0)
29403b705cfSriastradh			rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
29503b705cfSriastradh		gshift = rshift + rbits;
29603b705cfSriastradh		bshift = gshift + gbits;
29703b705cfSriastradh#endif
29803b705cfSriastradh	} else {
29903b705cfSriastradh		return FALSE;
30003b705cfSriastradh	}
30103b705cfSriastradh
30203b705cfSriastradh	if (rbits) {
30303b705cfSriastradh		*red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
30403b705cfSriastradh		while (rbits < 16) {
30503b705cfSriastradh			*red |= *red >> rbits;
30603b705cfSriastradh			rbits <<= 1;
30703b705cfSriastradh		}
30803b705cfSriastradh	} else
30903b705cfSriastradh		*red = 0;
31003b705cfSriastradh
31103b705cfSriastradh	if (gbits) {
31203b705cfSriastradh		*green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
31303b705cfSriastradh		while (gbits < 16) {
31403b705cfSriastradh			*green |= *green >> gbits;
31503b705cfSriastradh			gbits <<= 1;
31603b705cfSriastradh		}
31703b705cfSriastradh	} else
31803b705cfSriastradh		*green = 0;
31903b705cfSriastradh
32003b705cfSriastradh	if (bbits) {
32103b705cfSriastradh		*blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
32203b705cfSriastradh		while (bbits < 16) {
32303b705cfSriastradh			*blue |= *blue >> bbits;
32403b705cfSriastradh			bbits <<= 1;
32503b705cfSriastradh		}
32603b705cfSriastradh	} else
32703b705cfSriastradh		*blue = 0;
32803b705cfSriastradh
32903b705cfSriastradh	if (abits) {
33003b705cfSriastradh		*alpha =
33103b705cfSriastradh		    ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
33203b705cfSriastradh		while (abits < 16) {
33303b705cfSriastradh			*alpha |= *alpha >> abits;
33403b705cfSriastradh			abits <<= 1;
33503b705cfSriastradh		}
33603b705cfSriastradh	} else
33703b705cfSriastradh		*alpha = 0xffff;
33803b705cfSriastradh
33903b705cfSriastradh	return TRUE;
34003b705cfSriastradh}
34103b705cfSriastradh
34203b705cfSriastradhBool
34303b705cfSriastradhuxa_get_color_for_pixmap (PixmapPtr	 pixmap,
34403b705cfSriastradh			  CARD32	 src_format,
34503b705cfSriastradh			  CARD32	 dst_format,
34603b705cfSriastradh			  CARD32	*pixel)
34703b705cfSriastradh{
34803b705cfSriastradh	CARD16 red, green, blue, alpha;
34903b705cfSriastradh
35003b705cfSriastradh	*pixel = uxa_get_pixmap_first_pixel(pixmap);
35103b705cfSriastradh
35203b705cfSriastradh	if (src_format != dst_format) {
35303b705cfSriastradh	    if (!uxa_get_rgba_from_pixel(*pixel,
35403b705cfSriastradh					 &red, &green, &blue, &alpha,
35503b705cfSriastradh					 src_format))
35603b705cfSriastradh		return FALSE;
35703b705cfSriastradh
35803b705cfSriastradh	    if (!uxa_get_pixel_from_rgba(pixel,
35903b705cfSriastradh					 red, green, blue, alpha,
36003b705cfSriastradh					 dst_format))
36103b705cfSriastradh		return FALSE;
36203b705cfSriastradh	}
36303b705cfSriastradh
36403b705cfSriastradh	return TRUE;
36503b705cfSriastradh}
36603b705cfSriastradh
36703b705cfSriastradhstatic int
36803b705cfSriastradhuxa_try_driver_solid_fill(PicturePtr pSrc,
36903b705cfSriastradh			  PicturePtr pDst,
37003b705cfSriastradh			  INT16 xSrc,
37103b705cfSriastradh			  INT16 ySrc,
37203b705cfSriastradh			  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
37303b705cfSriastradh{
37403b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
37503b705cfSriastradh	RegionRec region;
37603b705cfSriastradh	BoxPtr pbox;
37703b705cfSriastradh	int nbox;
37803b705cfSriastradh	int dst_off_x, dst_off_y;
37903b705cfSriastradh	PixmapPtr pSrcPix = NULL, pDstPix;
38003b705cfSriastradh	CARD32 pixel;
38103b705cfSriastradh
38203b705cfSriastradh	if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES))
38303b705cfSriastradh		return -1;
38403b705cfSriastradh
38503b705cfSriastradh	pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
38603b705cfSriastradh	if (!pDstPix)
38703b705cfSriastradh		return -1;
38803b705cfSriastradh
38903b705cfSriastradh	xDst += pDst->pDrawable->x;
39003b705cfSriastradh	yDst += pDst->pDrawable->y;
39103b705cfSriastradh
39203b705cfSriastradh	if (pSrc->pDrawable) {
39303b705cfSriastradh		pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
39403b705cfSriastradh		xSrc += pSrc->pDrawable->x;
39503b705cfSriastradh		ySrc += pSrc->pDrawable->y;
39603b705cfSriastradh	}
39703b705cfSriastradh
39803b705cfSriastradh	if (!miComputeCompositeRegion(&region, pSrc, NULL, pDst,
39903b705cfSriastradh				      xSrc, ySrc, 0, 0, xDst, yDst,
40003b705cfSriastradh				      width, height))
40103b705cfSriastradh		return 1;
40203b705cfSriastradh
40303b705cfSriastradh	if (pSrcPix) {
40403b705cfSriastradh		if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) {
40503b705cfSriastradh			REGION_UNINIT(pDst->pDrawable->pScreen, &region);
40603b705cfSriastradh			return -1;
40703b705cfSriastradh		}
40803b705cfSriastradh	} else {
40903b705cfSriastradh		SourcePict *source = pSrc->pSourcePict;
41003b705cfSriastradh		PictSolidFill *solid = &source->solidFill;
41103b705cfSriastradh
41203b705cfSriastradh		if (source == NULL || source->type != SourcePictTypeSolidFill) {
41303b705cfSriastradh			REGION_UNINIT(pDst->pDrawable->pScreen, &region);
41403b705cfSriastradh			return -1;
41503b705cfSriastradh		}
41603b705cfSriastradh
41703b705cfSriastradh		if (pDst->format == PICT_a8r8g8b8) {
41803b705cfSriastradh			pixel = solid->color;
41903b705cfSriastradh		} else if (pDst->format == PICT_x8r8g8b8) {
42003b705cfSriastradh			pixel = solid->color | 0xff000000;
42103b705cfSriastradh		} else {
42203b705cfSriastradh			CARD16 red, green, blue, alpha;
42303b705cfSriastradh
42403b705cfSriastradh			if (!uxa_get_rgba_from_pixel(solid->color,
42503b705cfSriastradh						     &red, &green, &blue, &alpha,
42603b705cfSriastradh						     PICT_a8r8g8b8) ||
42703b705cfSriastradh			    !uxa_get_pixel_from_rgba(&pixel,
42803b705cfSriastradh						     red, green, blue, alpha,
42903b705cfSriastradh						     pDst->format)) {
43003b705cfSriastradh				REGION_UNINIT(pDst->pDrawable->pScreen, &region);
43103b705cfSriastradh				return -1;
43203b705cfSriastradh			}
43303b705cfSriastradh		}
43403b705cfSriastradh	}
43503b705cfSriastradh
43603b705cfSriastradh	if (!(*uxa_screen->info->prepare_solid)
43703b705cfSriastradh	    (pDstPix, GXcopy, FB_ALLONES, pixel)) {
43803b705cfSriastradh		REGION_UNINIT(pDst->pDrawable->pScreen, &region);
43903b705cfSriastradh		return -1;
44003b705cfSriastradh	}
44103b705cfSriastradh
44203b705cfSriastradh	REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
44303b705cfSriastradh
44403b705cfSriastradh	nbox = REGION_NUM_RECTS(&region);
44503b705cfSriastradh	pbox = REGION_RECTS(&region);
44603b705cfSriastradh
44703b705cfSriastradh	while (nbox--) {
44803b705cfSriastradh		(*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1,
44903b705cfSriastradh					    pbox->x2, pbox->y2);
45003b705cfSriastradh		pbox++;
45103b705cfSriastradh	}
45203b705cfSriastradh
45303b705cfSriastradh	(*uxa_screen->info->done_solid) (pDstPix);
45403b705cfSriastradh
45503b705cfSriastradh	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
45603b705cfSriastradh	return 1;
45703b705cfSriastradh}
45803b705cfSriastradh
45903b705cfSriastradhstatic PicturePtr
46003b705cfSriastradhuxa_picture_for_pixman_format(ScreenPtr screen,
46103b705cfSriastradh			      pixman_format_code_t format,
46203b705cfSriastradh			      int width, int height)
46303b705cfSriastradh{
46403b705cfSriastradh	PicturePtr picture;
46503b705cfSriastradh	PixmapPtr pixmap;
46603b705cfSriastradh	int error;
46703b705cfSriastradh
46803b705cfSriastradh	if (format == PIXMAN_a1)
46903b705cfSriastradh		format = PIXMAN_a8;
47003b705cfSriastradh
47103b705cfSriastradh	/* fill alpha if unset */
47203b705cfSriastradh	if (PIXMAN_FORMAT_A(format) == 0)
47303b705cfSriastradh	    format = PIXMAN_a8r8g8b8;
47403b705cfSriastradh
47503b705cfSriastradh	pixmap = screen->CreatePixmap(screen, width, height,
47603b705cfSriastradh					PIXMAN_FORMAT_DEPTH(format),
47703b705cfSriastradh					UXA_CREATE_PIXMAP_FOR_MAP);
47803b705cfSriastradh	if (!pixmap)
47903b705cfSriastradh		return 0;
48003b705cfSriastradh
48103b705cfSriastradh	if (!uxa_pixmap_is_offscreen(pixmap)) {
48203b705cfSriastradh		screen->DestroyPixmap(pixmap);
48303b705cfSriastradh		return 0;
48403b705cfSriastradh	}
48503b705cfSriastradh
48603b705cfSriastradh	picture = CreatePicture(0, &pixmap->drawable,
48703b705cfSriastradh				PictureMatchFormat(screen,
48803b705cfSriastradh						   PIXMAN_FORMAT_DEPTH(format),
48903b705cfSriastradh						   format),
49003b705cfSriastradh				0, 0, serverClient, &error);
49103b705cfSriastradh	screen->DestroyPixmap(pixmap);
49203b705cfSriastradh	if (!picture)
49303b705cfSriastradh		return 0;
49403b705cfSriastradh
49503b705cfSriastradh	ValidatePicture(picture);
49603b705cfSriastradh
49703b705cfSriastradh	return picture;
49803b705cfSriastradh}
49903b705cfSriastradh
50003b705cfSriastradhstatic PicturePtr
50103b705cfSriastradhuxa_picture_from_pixman_image(ScreenPtr screen,
50203b705cfSriastradh			      pixman_image_t * image,
50303b705cfSriastradh			      pixman_format_code_t format)
50403b705cfSriastradh{
50503b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
50603b705cfSriastradh	PicturePtr picture;
50703b705cfSriastradh	PixmapPtr pixmap;
50803b705cfSriastradh	int width, height;
50903b705cfSriastradh
51003b705cfSriastradh	width = pixman_image_get_width(image);
51103b705cfSriastradh	height = pixman_image_get_height(image);
51203b705cfSriastradh
51303b705cfSriastradh	picture = uxa_picture_for_pixman_format(screen, format,
51403b705cfSriastradh						width, height);
51503b705cfSriastradh	if (!picture)
51603b705cfSriastradh		return 0;
51703b705cfSriastradh
51803b705cfSriastradh	if (uxa_screen->info->put_image &&
51903b705cfSriastradh	    ((picture->pDrawable->depth << 24) | picture->format) == format &&
52003b705cfSriastradh	    uxa_screen->info->put_image((PixmapPtr)picture->pDrawable,
52103b705cfSriastradh					0, 0,
52203b705cfSriastradh					width, height,
52303b705cfSriastradh					(char *)pixman_image_get_data(image),
52403b705cfSriastradh					pixman_image_get_stride(image)))
52503b705cfSriastradh		return picture;
52603b705cfSriastradh
52703b705cfSriastradh	pixmap = GetScratchPixmapHeader(screen, width, height,
52803b705cfSriastradh					PIXMAN_FORMAT_DEPTH(format),
52903b705cfSriastradh					PIXMAN_FORMAT_BPP(format),
53003b705cfSriastradh					pixman_image_get_stride(image),
53103b705cfSriastradh					pixman_image_get_data(image));
53203b705cfSriastradh	if (!pixmap) {
53303b705cfSriastradh		FreePicture(picture, 0);
53403b705cfSriastradh		return 0;
53503b705cfSriastradh	}
53603b705cfSriastradh
53703b705cfSriastradh	if (((picture->pDrawable->depth << 24) | picture->format) == format) {
53803b705cfSriastradh		GCPtr gc;
53903b705cfSriastradh
54003b705cfSriastradh		gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen);
54103b705cfSriastradh		if (!gc) {
54203b705cfSriastradh			FreeScratchPixmapHeader(pixmap);
54303b705cfSriastradh			FreePicture(picture, 0);
54403b705cfSriastradh			return 0;
54503b705cfSriastradh		}
54603b705cfSriastradh		ValidateGC(picture->pDrawable, gc);
54703b705cfSriastradh
54803b705cfSriastradh		(*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable,
54903b705cfSriastradh				      gc, 0, 0, width, height, 0, 0);
55003b705cfSriastradh
55103b705cfSriastradh		FreeScratchGC(gc);
55203b705cfSriastradh	} else {
55303b705cfSriastradh		PicturePtr src;
55403b705cfSriastradh		int error;
55503b705cfSriastradh
55603b705cfSriastradh		src = CreatePicture(0, &pixmap->drawable,
55703b705cfSriastradh				    PictureMatchFormat(screen,
55803b705cfSriastradh						       PIXMAN_FORMAT_DEPTH(format),
55903b705cfSriastradh						       format),
56003b705cfSriastradh				    0, 0, serverClient, &error);
56103b705cfSriastradh		if (!src) {
56203b705cfSriastradh			FreeScratchPixmapHeader(pixmap);
56303b705cfSriastradh			FreePicture(picture, 0);
56403b705cfSriastradh			return 0;
56503b705cfSriastradh		}
56603b705cfSriastradh		ValidatePicture(src);
56703b705cfSriastradh
56803b705cfSriastradh		if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) {
56903b705cfSriastradh			fbComposite(PictOpSrc, src, NULL, picture,
57003b705cfSriastradh				    0, 0, 0, 0, 0, 0, width, height);
57103b705cfSriastradh			uxa_picture_finish_access(picture, UXA_ACCESS_RW);
57203b705cfSriastradh		}
57303b705cfSriastradh
57403b705cfSriastradh		FreePicture(src, 0);
57503b705cfSriastradh	}
57603b705cfSriastradh	FreeScratchPixmapHeader(pixmap);
57703b705cfSriastradh
57803b705cfSriastradh	return picture;
57903b705cfSriastradh}
58003b705cfSriastradh
58103b705cfSriastradhstatic PicturePtr
58203b705cfSriastradhuxa_create_solid(ScreenPtr screen, uint32_t color)
58303b705cfSriastradh{
58403b705cfSriastradh	PixmapPtr pixmap;
58503b705cfSriastradh	PicturePtr picture;
58603b705cfSriastradh	XID repeat = RepeatNormal;
58703b705cfSriastradh	int error = 0;
58803b705cfSriastradh
58903b705cfSriastradh	pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32,
59003b705cfSriastradh					 UXA_CREATE_PIXMAP_FOR_MAP);
59103b705cfSriastradh	if (!pixmap)
59203b705cfSriastradh		return 0;
59303b705cfSriastradh
59403b705cfSriastradh	if (!uxa_prepare_access((DrawablePtr)pixmap, UXA_ACCESS_RW)) {
59503b705cfSriastradh		(*screen->DestroyPixmap)(pixmap);
59603b705cfSriastradh		return 0;
59703b705cfSriastradh	}
59803b705cfSriastradh	*((uint32_t *)pixmap->devPrivate.ptr) = color;
59903b705cfSriastradh	uxa_finish_access((DrawablePtr)pixmap, UXA_ACCESS_RW);
60003b705cfSriastradh
60103b705cfSriastradh	picture = CreatePicture(0, &pixmap->drawable,
60203b705cfSriastradh				PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
60303b705cfSriastradh				CPRepeat, &repeat, serverClient, &error);
60403b705cfSriastradh	(*screen->DestroyPixmap)(pixmap);
60503b705cfSriastradh
60603b705cfSriastradh	return picture;
60703b705cfSriastradh}
60803b705cfSriastradh
60903b705cfSriastradhstatic PicturePtr
61003b705cfSriastradhuxa_solid_clear(ScreenPtr screen)
61103b705cfSriastradh{
61203b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
61303b705cfSriastradh	PicturePtr picture;
61403b705cfSriastradh
61503b705cfSriastradh	if (!uxa_screen->solid_clear) {
61603b705cfSriastradh		uxa_screen->solid_clear = uxa_create_solid(screen, 0);
61703b705cfSriastradh		if (!uxa_screen->solid_clear)
61803b705cfSriastradh			return 0;
61903b705cfSriastradh	}
62003b705cfSriastradh	picture = uxa_screen->solid_clear;
62103b705cfSriastradh	return picture;
62203b705cfSriastradh}
62303b705cfSriastradh
62403b705cfSriastradhPicturePtr
62503b705cfSriastradhuxa_acquire_solid(ScreenPtr screen, SourcePict *source)
62603b705cfSriastradh{
62703b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
62803b705cfSriastradh	PictSolidFill *solid = &source->solidFill;
62903b705cfSriastradh	PicturePtr picture;
63003b705cfSriastradh	int i;
63103b705cfSriastradh
63203b705cfSriastradh	if ((solid->color >> 24) == 0) {
63303b705cfSriastradh		picture = uxa_solid_clear(screen);
63403b705cfSriastradh		if (!picture)
63503b705cfSriastradh		    return 0;
63603b705cfSriastradh
63703b705cfSriastradh		goto DONE;
63803b705cfSriastradh	} else if (solid->color == 0xff000000) {
63903b705cfSriastradh		if (!uxa_screen->solid_black) {
64003b705cfSriastradh			uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000);
64103b705cfSriastradh			if (!uxa_screen->solid_black)
64203b705cfSriastradh				return 0;
64303b705cfSriastradh		}
64403b705cfSriastradh		picture = uxa_screen->solid_black;
64503b705cfSriastradh		goto DONE;
64603b705cfSriastradh	} else if (solid->color == 0xffffffff) {
64703b705cfSriastradh		if (!uxa_screen->solid_white) {
64803b705cfSriastradh			uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff);
64903b705cfSriastradh			if (!uxa_screen->solid_white)
65003b705cfSriastradh				return 0;
65103b705cfSriastradh		}
65203b705cfSriastradh		picture = uxa_screen->solid_white;
65303b705cfSriastradh		goto DONE;
65403b705cfSriastradh	}
65503b705cfSriastradh
65603b705cfSriastradh	for (i = 0; i < uxa_screen->solid_cache_size; i++) {
65703b705cfSriastradh		if (uxa_screen->solid_cache[i].color == solid->color) {
65803b705cfSriastradh			picture = uxa_screen->solid_cache[i].picture;
65903b705cfSriastradh			goto DONE;
66003b705cfSriastradh		}
66103b705cfSriastradh	}
66203b705cfSriastradh
66303b705cfSriastradh	picture = uxa_create_solid(screen, solid->color);
66403b705cfSriastradh	if (!picture)
66503b705cfSriastradh		return 0;
66603b705cfSriastradh
66703b705cfSriastradh	if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) {
66803b705cfSriastradh		i = rand() % UXA_NUM_SOLID_CACHE;
66903b705cfSriastradh		FreePicture(uxa_screen->solid_cache[i].picture, 0);
67003b705cfSriastradh	} else
67103b705cfSriastradh		uxa_screen->solid_cache_size++;
67203b705cfSriastradh
67303b705cfSriastradh	uxa_screen->solid_cache[i].picture = picture;
67403b705cfSriastradh	uxa_screen->solid_cache[i].color = solid->color;
67503b705cfSriastradh
67603b705cfSriastradhDONE:
67703b705cfSriastradh	picture->refcnt++;
67803b705cfSriastradh	return picture;
67903b705cfSriastradh}
68003b705cfSriastradh
68103b705cfSriastradhPicturePtr
68203b705cfSriastradhuxa_acquire_pattern(ScreenPtr pScreen,
68303b705cfSriastradh		    PicturePtr pSrc,
68403b705cfSriastradh		    pixman_format_code_t format,
68503b705cfSriastradh		    INT16 x, INT16 y, CARD16 width, CARD16 height)
68603b705cfSriastradh{
68703b705cfSriastradh	PicturePtr pDst;
68803b705cfSriastradh
68903b705cfSriastradh	if (pSrc->pSourcePict) {
69003b705cfSriastradh		SourcePict *source = pSrc->pSourcePict;
69103b705cfSriastradh		if (source->type == SourcePictTypeSolidFill)
69203b705cfSriastradh			return uxa_acquire_solid (pScreen, source);
69303b705cfSriastradh	}
69403b705cfSriastradh
69503b705cfSriastradh	pDst = uxa_picture_for_pixman_format(pScreen, format, width, height);
69603b705cfSriastradh	if (!pDst)
69703b705cfSriastradh		return 0;
69803b705cfSriastradh
69903b705cfSriastradh	if (uxa_picture_prepare_access(pDst, UXA_ACCESS_RW)) {
70003b705cfSriastradh		fbComposite(PictOpSrc, pSrc, NULL, pDst,
70103b705cfSriastradh			    x, y, 0, 0, 0, 0, width, height);
70203b705cfSriastradh		uxa_picture_finish_access(pDst, UXA_ACCESS_RW);
70303b705cfSriastradh		return pDst;
70403b705cfSriastradh	} else {
70503b705cfSriastradh		FreePicture(pDst, 0);
70603b705cfSriastradh		return 0;
70703b705cfSriastradh	}
70803b705cfSriastradh}
70903b705cfSriastradh
71003b705cfSriastradhstatic Bool
71103b705cfSriastradhtransform_is_integer_translation(PictTransformPtr t, int *tx, int *ty)
71203b705cfSriastradh{
71303b705cfSriastradh	if (t == NULL) {
71403b705cfSriastradh		*tx = *ty = 0;
71503b705cfSriastradh		return TRUE;
71603b705cfSriastradh	}
71703b705cfSriastradh
71803b705cfSriastradh	if (t->matrix[0][0] != IntToxFixed(1) ||
71903b705cfSriastradh	    t->matrix[0][1] != 0 ||
72003b705cfSriastradh	    t->matrix[1][0] != 0 ||
72103b705cfSriastradh	    t->matrix[1][1] != IntToxFixed(1) ||
72203b705cfSriastradh	    t->matrix[2][0] != 0 ||
72303b705cfSriastradh	    t->matrix[2][1] != 0 ||
72403b705cfSriastradh	    t->matrix[2][2] != IntToxFixed(1))
72503b705cfSriastradh		return FALSE;
72603b705cfSriastradh
72703b705cfSriastradh	if (xFixedFrac(t->matrix[0][2]) != 0 ||
72803b705cfSriastradh	    xFixedFrac(t->matrix[1][2]) != 0)
72903b705cfSriastradh		return FALSE;
73003b705cfSriastradh
73103b705cfSriastradh	*tx = xFixedToInt(t->matrix[0][2]);
73203b705cfSriastradh	*ty = xFixedToInt(t->matrix[1][2]);
73303b705cfSriastradh	return TRUE;
73403b705cfSriastradh}
73503b705cfSriastradh
73603b705cfSriastradhstatic PicturePtr
73703b705cfSriastradhuxa_render_picture(ScreenPtr screen,
73803b705cfSriastradh		   PicturePtr src,
73903b705cfSriastradh		   pixman_format_code_t format,
74003b705cfSriastradh		   INT16 x, INT16 y,
74103b705cfSriastradh		   CARD16 width, CARD16 height)
74203b705cfSriastradh{
74303b705cfSriastradh	PicturePtr picture;
74403b705cfSriastradh	int ret = 0;
74503b705cfSriastradh
74603b705cfSriastradh	/* XXX we need a mechanism for the card to choose the fallback format */
74703b705cfSriastradh
74803b705cfSriastradh	/* force alpha channel in case source does not entirely cover the extents */
74903b705cfSriastradh	if (PIXMAN_FORMAT_A(format) == 0)
75003b705cfSriastradh		format = PIXMAN_a8r8g8b8; /* available on all hardware */
75103b705cfSriastradh
75203b705cfSriastradh	picture = uxa_picture_for_pixman_format(screen, format, width, height);
75303b705cfSriastradh	if (!picture)
75403b705cfSriastradh		return 0;
75503b705cfSriastradh
75603b705cfSriastradh	if (uxa_picture_prepare_access(picture, UXA_ACCESS_RW)) {
75703b705cfSriastradh		if (uxa_picture_prepare_access(src, UXA_ACCESS_RO)) {
75803b705cfSriastradh			ret = 1;
75903b705cfSriastradh			fbComposite(PictOpSrc, src, NULL, picture,
76003b705cfSriastradh				    x, y, 0, 0, 0, 0, width, height);
76103b705cfSriastradh			uxa_picture_finish_access(src, UXA_ACCESS_RO);
76203b705cfSriastradh		}
76303b705cfSriastradh		uxa_picture_finish_access(picture, UXA_ACCESS_RW);
76403b705cfSriastradh	}
76503b705cfSriastradh
76603b705cfSriastradh	if (!ret) {
76703b705cfSriastradh		FreePicture(picture, 0);
76803b705cfSriastradh		return 0;
76903b705cfSriastradh	}
77003b705cfSriastradh
77103b705cfSriastradh	return picture;
77203b705cfSriastradh}
77303b705cfSriastradh
77403b705cfSriastradhstatic int
77503b705cfSriastradhdrawable_contains (DrawablePtr drawable, int x, int y, int w, int h)
77603b705cfSriastradh{
77703b705cfSriastradh	if (x < 0 || y < 0)
77803b705cfSriastradh		return FALSE;
77903b705cfSriastradh
78003b705cfSriastradh	if (x + w > drawable->width)
78103b705cfSriastradh		return FALSE;
78203b705cfSriastradh
78303b705cfSriastradh	if (y + h > drawable->height)
78403b705cfSriastradh		return FALSE;
78503b705cfSriastradh
78603b705cfSriastradh	return TRUE;
78703b705cfSriastradh}
78803b705cfSriastradh
78903b705cfSriastradhPicturePtr
79003b705cfSriastradhuxa_acquire_drawable(ScreenPtr pScreen,
79103b705cfSriastradh		     PicturePtr pSrc,
79203b705cfSriastradh		     INT16 x, INT16 y,
79303b705cfSriastradh		     CARD16 width, CARD16 height,
79403b705cfSriastradh		     INT16 * out_x, INT16 * out_y)
79503b705cfSriastradh{
79603b705cfSriastradh	PixmapPtr pPixmap;
79703b705cfSriastradh	PicturePtr pDst;
79803b705cfSriastradh	int depth, error;
79903b705cfSriastradh	int tx, ty;
80003b705cfSriastradh	GCPtr pGC;
80103b705cfSriastradh
80203b705cfSriastradh	depth = pSrc->pDrawable->depth;
80303b705cfSriastradh	if (!transform_is_integer_translation(pSrc->transform, &tx, &ty) ||
80403b705cfSriastradh	    !drawable_contains(pSrc->pDrawable, x + tx, y + ty, width, height) ||
80503b705cfSriastradh	    depth == 1 ||
80603b705cfSriastradh	    pSrc->filter == PictFilterConvolution) {
80703b705cfSriastradh		/* XXX extract the sample extents and do the transformation on the GPU */
80803b705cfSriastradh		pDst = uxa_render_picture(pScreen, pSrc,
80903b705cfSriastradh					  pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24),
81003b705cfSriastradh					  x, y, width, height);
81103b705cfSriastradh		if (!pDst)
81203b705cfSriastradh			return 0;
81303b705cfSriastradh
81403b705cfSriastradh		goto done;
81503b705cfSriastradh	} else {
81603b705cfSriastradh		if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->height) {
81703b705cfSriastradh			*out_x = x + pSrc->pDrawable->x;
81803b705cfSriastradh			*out_y = y + pSrc->pDrawable->y;
81903b705cfSriastradh			return pSrc;
82003b705cfSriastradh		}
82103b705cfSriastradh	}
82203b705cfSriastradh
82303b705cfSriastradh	pPixmap = pScreen->CreatePixmap(pScreen,
82403b705cfSriastradh					width, height, depth,
82503b705cfSriastradh					CREATE_PIXMAP_USAGE_SCRATCH);
82603b705cfSriastradh	if (!pPixmap)
82703b705cfSriastradh		return 0;
82803b705cfSriastradh
82903b705cfSriastradh	/* Skip the copy if the result remains in memory and not a bo */
83003b705cfSriastradh	if (!uxa_pixmap_is_offscreen(pPixmap)) {
83103b705cfSriastradh		pScreen->DestroyPixmap(pPixmap);
83203b705cfSriastradh		return 0;
83303b705cfSriastradh	}
83403b705cfSriastradh
83503b705cfSriastradh	pGC = GetScratchGC(depth, pScreen);
83603b705cfSriastradh	if (!pGC) {
83703b705cfSriastradh		pScreen->DestroyPixmap(pPixmap);
83803b705cfSriastradh		return 0;
83903b705cfSriastradh	}
84003b705cfSriastradh
84103b705cfSriastradh	ValidateGC(&pPixmap->drawable, pGC);
84203b705cfSriastradh	pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC,
84303b705cfSriastradh			   x + tx, y + ty, width, height, 0, 0);
84403b705cfSriastradh	FreeScratchGC(pGC);
84503b705cfSriastradh
84603b705cfSriastradh	pDst = CreatePicture(0, &pPixmap->drawable,
84703b705cfSriastradh			     PictureMatchFormat(pScreen, depth, pSrc->format),
84803b705cfSriastradh			     0, 0, serverClient, &error);
84903b705cfSriastradh	pScreen->DestroyPixmap(pPixmap);
85003b705cfSriastradh	if (!pDst)
85103b705cfSriastradh		return 0;
85203b705cfSriastradh
85303b705cfSriastradh	ValidatePicture(pDst);
85403b705cfSriastradhdone:
85503b705cfSriastradh	pDst->componentAlpha = pSrc->componentAlpha;
85603b705cfSriastradh	*out_x = 0;
85703b705cfSriastradh	*out_y = 0;
85803b705cfSriastradh	return pDst;
85903b705cfSriastradh}
86003b705cfSriastradh
86103b705cfSriastradhstatic PicturePtr
86203b705cfSriastradhuxa_acquire_picture(ScreenPtr screen,
86303b705cfSriastradh		    PicturePtr src,
86403b705cfSriastradh		    pixman_format_code_t format,
86503b705cfSriastradh		    INT16 x, INT16 y,
86603b705cfSriastradh		    CARD16 width, CARD16 height,
86703b705cfSriastradh		    INT16 * out_x, INT16 * out_y)
86803b705cfSriastradh{
86903b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
87003b705cfSriastradh
87103b705cfSriastradh	if (uxa_screen->info->check_composite_texture &&
87203b705cfSriastradh	    uxa_screen->info->check_composite_texture(screen, src)) {
87303b705cfSriastradh		if (src->pDrawable) {
87403b705cfSriastradh			*out_x = x + src->pDrawable->x;
87503b705cfSriastradh			*out_y = y + src->pDrawable->y;
87603b705cfSriastradh		} else {
87703b705cfSriastradh			*out_x = x;
87803b705cfSriastradh			*out_y = y;
87903b705cfSriastradh		}
88003b705cfSriastradh		return src;
88103b705cfSriastradh	}
88203b705cfSriastradh
88303b705cfSriastradh	if (src->pDrawable) {
88403b705cfSriastradh		PicturePtr dst;
88503b705cfSriastradh
88603b705cfSriastradh		dst = uxa_acquire_drawable(screen, src,
88703b705cfSriastradh					   x, y, width, height,
88803b705cfSriastradh					   out_x, out_y);
88903b705cfSriastradh		if (!dst)
89003b705cfSriastradh			return 0;
89103b705cfSriastradh
89203b705cfSriastradh		if (uxa_screen->info->check_composite_texture &&
89303b705cfSriastradh		    !uxa_screen->info->check_composite_texture(screen, dst)) {
89403b705cfSriastradh			if (dst != src)
89503b705cfSriastradh				FreePicture(dst, 0);
89603b705cfSriastradh			return 0;
89703b705cfSriastradh		}
89803b705cfSriastradh
89903b705cfSriastradh		return dst;
90003b705cfSriastradh	}
90103b705cfSriastradh
90203b705cfSriastradh	*out_x = 0;
90303b705cfSriastradh	*out_y = 0;
90403b705cfSriastradh	return uxa_acquire_pattern(screen, src,
90503b705cfSriastradh				   format, x, y, width, height);
90603b705cfSriastradh}
90703b705cfSriastradh
90803b705cfSriastradhstatic PicturePtr
90903b705cfSriastradhuxa_acquire_source(ScreenPtr screen,
91003b705cfSriastradh		   PicturePtr pict,
91103b705cfSriastradh		   INT16 x, INT16 y,
91203b705cfSriastradh		   CARD16 width, CARD16 height,
91303b705cfSriastradh		   INT16 * out_x, INT16 * out_y)
91403b705cfSriastradh{
91503b705cfSriastradh	return uxa_acquire_picture (screen, pict,
91642542f5fSchristos				    PIXMAN_a8r8g8b8,
91703b705cfSriastradh				    x, y,
91803b705cfSriastradh				    width, height,
91903b705cfSriastradh				    out_x, out_y);
92003b705cfSriastradh}
92103b705cfSriastradh
92203b705cfSriastradhstatic PicturePtr
92303b705cfSriastradhuxa_acquire_mask(ScreenPtr screen,
92403b705cfSriastradh		 PicturePtr pict,
92503b705cfSriastradh		 INT16 x, INT16 y,
92603b705cfSriastradh		 INT16 width, INT16 height,
92703b705cfSriastradh		 INT16 * out_x, INT16 * out_y)
92803b705cfSriastradh{
92903b705cfSriastradh	return uxa_acquire_picture (screen, pict,
93042542f5fSchristos				    PIXMAN_a8,
93103b705cfSriastradh				    x, y,
93203b705cfSriastradh				    width, height,
93303b705cfSriastradh				    out_x, out_y);
93403b705cfSriastradh}
93503b705cfSriastradh
93603b705cfSriastradhstatic int
93703b705cfSriastradhuxa_try_driver_composite(CARD8 op,
93803b705cfSriastradh			 PicturePtr pSrc,
93903b705cfSriastradh			 PicturePtr pMask,
94003b705cfSriastradh			 PicturePtr pDst,
94103b705cfSriastradh			 INT16 xSrc, INT16 ySrc,
94203b705cfSriastradh			 INT16 xMask, INT16 yMask,
94303b705cfSriastradh			 INT16 xDst, INT16 yDst,
94403b705cfSriastradh			 CARD16 width, CARD16 height)
94503b705cfSriastradh{
94603b705cfSriastradh	ScreenPtr screen = pDst->pDrawable->pScreen;
94703b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
94803b705cfSriastradh	RegionRec region;
94903b705cfSriastradh	BoxPtr pbox;
95003b705cfSriastradh	int nbox;
95103b705cfSriastradh	int xDst_copy = 0, yDst_copy = 0;
95203b705cfSriastradh	int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
95303b705cfSriastradh	PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
95403b705cfSriastradh	PicturePtr localSrc, localMask = NULL;
95503b705cfSriastradh	PicturePtr localDst = pDst;
95603b705cfSriastradh
95703b705cfSriastradh	if (uxa_screen->info->check_composite &&
95803b705cfSriastradh	    !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height))
95903b705cfSriastradh		return -1;
96003b705cfSriastradh
96103b705cfSriastradh	if (uxa_screen->info->check_composite_target &&
96203b705cfSriastradh	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
96303b705cfSriastradh		int depth = pDst->pDrawable->depth;
96403b705cfSriastradh		PixmapPtr pixmap;
96503b705cfSriastradh		int error;
96603b705cfSriastradh		GCPtr gc;
96703b705cfSriastradh
96803b705cfSriastradh		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
96903b705cfSriastradh		if (uxa_screen->info->check_copy &&
97003b705cfSriastradh		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
97103b705cfSriastradh			return -1;
97203b705cfSriastradh
97303b705cfSriastradh		pixmap = screen->CreatePixmap(screen,
97403b705cfSriastradh					      width, height, depth,
97503b705cfSriastradh					      CREATE_PIXMAP_USAGE_SCRATCH);
97603b705cfSriastradh		if (!pixmap)
97703b705cfSriastradh			return 0;
97803b705cfSriastradh
97903b705cfSriastradh		gc = GetScratchGC(depth, screen);
98003b705cfSriastradh		if (!gc) {
98103b705cfSriastradh			screen->DestroyPixmap(pixmap);
98203b705cfSriastradh			return 0;
98303b705cfSriastradh		}
98403b705cfSriastradh
98503b705cfSriastradh		ValidateGC(&pixmap->drawable, gc);
98603b705cfSriastradh		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
98703b705cfSriastradh				  xDst, yDst, width, height, 0, 0);
98803b705cfSriastradh		FreeScratchGC(gc);
98903b705cfSriastradh
99003b705cfSriastradh		xDst_copy = xDst; xDst = 0;
99103b705cfSriastradh		yDst_copy = yDst; yDst = 0;
99203b705cfSriastradh
99303b705cfSriastradh		localDst = CreatePicture(0, &pixmap->drawable,
99403b705cfSriastradh					 PictureMatchFormat(screen, depth, pDst->format),
99503b705cfSriastradh					 0, 0, serverClient, &error);
99603b705cfSriastradh		screen->DestroyPixmap(pixmap);
99703b705cfSriastradh
99803b705cfSriastradh		if (!localDst)
99903b705cfSriastradh			return 0;
100003b705cfSriastradh
100103b705cfSriastradh		ValidatePicture(localDst);
100203b705cfSriastradh	}
100303b705cfSriastradh
100403b705cfSriastradh	pDstPix =
100503b705cfSriastradh	    uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y);
100603b705cfSriastradh	if (!pDstPix) {
100703b705cfSriastradh		if (localDst != pDst)
100803b705cfSriastradh			FreePicture(localDst, 0);
100903b705cfSriastradh		return -1;
101003b705cfSriastradh	}
101103b705cfSriastradh
101203b705cfSriastradh	xDst += localDst->pDrawable->x;
101303b705cfSriastradh	yDst += localDst->pDrawable->y;
101403b705cfSriastradh
101503b705cfSriastradh	localSrc = uxa_acquire_source(screen, pSrc,
101603b705cfSriastradh				      xSrc, ySrc,
101703b705cfSriastradh				      width, height,
101803b705cfSriastradh				      &xSrc, &ySrc);
101903b705cfSriastradh	if (!localSrc) {
102003b705cfSriastradh		if (localDst != pDst)
102103b705cfSriastradh			FreePicture(localDst, 0);
102203b705cfSriastradh		return 0;
102303b705cfSriastradh	}
102403b705cfSriastradh
102503b705cfSriastradh	if (pMask) {
102603b705cfSriastradh		localMask = uxa_acquire_mask(screen, pMask,
102703b705cfSriastradh					     xMask, yMask,
102803b705cfSriastradh					     width, height,
102903b705cfSriastradh					     &xMask, &yMask);
103003b705cfSriastradh		if (!localMask) {
103103b705cfSriastradh			if (localSrc != pSrc)
103203b705cfSriastradh				FreePicture(localSrc, 0);
103303b705cfSriastradh			if (localDst != pDst)
103403b705cfSriastradh				FreePicture(localDst, 0);
103503b705cfSriastradh
103603b705cfSriastradh			return 0;
103703b705cfSriastradh		}
103803b705cfSriastradh	}
103903b705cfSriastradh
104003b705cfSriastradh	if (!miComputeCompositeRegion(&region, localSrc, localMask, localDst,
104103b705cfSriastradh				      xSrc, ySrc, xMask, yMask, xDst, yDst,
104203b705cfSriastradh				      width, height)) {
104303b705cfSriastradh		if (localSrc != pSrc)
104403b705cfSriastradh			FreePicture(localSrc, 0);
104503b705cfSriastradh		if (localMask && localMask != pMask)
104603b705cfSriastradh			FreePicture(localMask, 0);
104703b705cfSriastradh		if (localDst != pDst)
104803b705cfSriastradh			FreePicture(localDst, 0);
104903b705cfSriastradh
105003b705cfSriastradh		return 1;
105103b705cfSriastradh	}
105203b705cfSriastradh
105303b705cfSriastradh	pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable,
105403b705cfSriastradh					   &src_off_x, &src_off_y);
105503b705cfSriastradh	if (!pSrcPix) {
105603b705cfSriastradh		REGION_UNINIT(screen, &region);
105703b705cfSriastradh
105803b705cfSriastradh		if (localSrc != pSrc)
105903b705cfSriastradh			FreePicture(localSrc, 0);
106003b705cfSriastradh		if (localMask && localMask != pMask)
106103b705cfSriastradh			FreePicture(localMask, 0);
106203b705cfSriastradh		if (localDst != pDst)
106303b705cfSriastradh			FreePicture(localDst, 0);
106403b705cfSriastradh
106503b705cfSriastradh		return 0;
106603b705cfSriastradh	}
106703b705cfSriastradh
106803b705cfSriastradh	if (localMask) {
106903b705cfSriastradh		pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable,
107003b705cfSriastradh						    &mask_off_x, &mask_off_y);
107103b705cfSriastradh		if (!pMaskPix) {
107203b705cfSriastradh			REGION_UNINIT(screen, &region);
107303b705cfSriastradh
107403b705cfSriastradh			if (localSrc != pSrc)
107503b705cfSriastradh				FreePicture(localSrc, 0);
107603b705cfSriastradh			if (localMask && localMask != pMask)
107703b705cfSriastradh				FreePicture(localMask, 0);
107803b705cfSriastradh			if (localDst != pDst)
107903b705cfSriastradh				FreePicture(localDst, 0);
108003b705cfSriastradh
108103b705cfSriastradh			return 0;
108203b705cfSriastradh		}
108303b705cfSriastradh	}
108403b705cfSriastradh
108503b705cfSriastradh	if (!(*uxa_screen->info->prepare_composite)
108603b705cfSriastradh	    (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) {
108703b705cfSriastradh		REGION_UNINIT(screen, &region);
108803b705cfSriastradh
108903b705cfSriastradh		if (localSrc != pSrc)
109003b705cfSriastradh			FreePicture(localSrc, 0);
109103b705cfSriastradh		if (localMask && localMask != pMask)
109203b705cfSriastradh			FreePicture(localMask, 0);
109303b705cfSriastradh		if (localDst != pDst)
109403b705cfSriastradh			FreePicture(localDst, 0);
109503b705cfSriastradh
109603b705cfSriastradh		return -1;
109703b705cfSriastradh	}
109803b705cfSriastradh
109903b705cfSriastradh	if (pMask) {
110003b705cfSriastradh		xMask = xMask + mask_off_x - xDst;
110103b705cfSriastradh		yMask = yMask + mask_off_y - yDst;
110203b705cfSriastradh	}
110303b705cfSriastradh
110403b705cfSriastradh	xSrc = xSrc + src_off_x - xDst;
110503b705cfSriastradh	ySrc = ySrc + src_off_y - yDst;
110603b705cfSriastradh
110703b705cfSriastradh	nbox = REGION_NUM_RECTS(&region);
110803b705cfSriastradh	pbox = REGION_RECTS(&region);
110903b705cfSriastradh	while (nbox--) {
111003b705cfSriastradh		(*uxa_screen->info->composite) (pDstPix,
111103b705cfSriastradh						pbox->x1 + xSrc,
111203b705cfSriastradh						pbox->y1 + ySrc,
111303b705cfSriastradh						pbox->x1 + xMask,
111403b705cfSriastradh						pbox->y1 + yMask,
111503b705cfSriastradh						pbox->x1 + dst_off_x,
111603b705cfSriastradh						pbox->y1 + dst_off_y,
111703b705cfSriastradh						pbox->x2 - pbox->x1,
111803b705cfSriastradh						pbox->y2 - pbox->y1);
111903b705cfSriastradh		pbox++;
112003b705cfSriastradh	}
112103b705cfSriastradh	(*uxa_screen->info->done_composite) (pDstPix);
112203b705cfSriastradh
112303b705cfSriastradh	REGION_UNINIT(screen, &region);
112403b705cfSriastradh
112503b705cfSriastradh	if (localSrc != pSrc)
112603b705cfSriastradh		FreePicture(localSrc, 0);
112703b705cfSriastradh	if (localMask && localMask != pMask)
112803b705cfSriastradh		FreePicture(localMask, 0);
112903b705cfSriastradh
113003b705cfSriastradh	if (localDst != pDst) {
113103b705cfSriastradh		GCPtr gc;
113203b705cfSriastradh
113303b705cfSriastradh		gc = GetScratchGC(pDst->pDrawable->depth, screen);
113403b705cfSriastradh		if (gc) {
113503b705cfSriastradh			ValidateGC(pDst->pDrawable, gc);
113603b705cfSriastradh			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
113703b705cfSriastradh					  0, 0, width, height, xDst_copy, yDst_copy);
113803b705cfSriastradh			FreeScratchGC(gc);
113903b705cfSriastradh		}
114003b705cfSriastradh
114103b705cfSriastradh		FreePicture(localDst, 0);
114203b705cfSriastradh	}
114303b705cfSriastradh
114403b705cfSriastradh	return 1;
114503b705cfSriastradh}
114603b705cfSriastradh
114703b705cfSriastradh/**
114803b705cfSriastradh * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of
114903b705cfSriastradh * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
115003b705cfSriastradh * alpha and limited 1-tmu cards.
115103b705cfSriastradh *
115203b705cfSriastradh * From http://anholt.livejournal.com/32058.html:
115303b705cfSriastradh *
115403b705cfSriastradh * The trouble is that component-alpha rendering requires two different sources
115503b705cfSriastradh * for blending: one for the source value to the blender, which is the
115603b705cfSriastradh * per-channel multiplication of source and mask, and one for the source alpha
115703b705cfSriastradh * for multiplying with the destination channels, which is the multiplication
115803b705cfSriastradh * of the source channels by the mask alpha. So the equation for Over is:
115903b705cfSriastradh *
116003b705cfSriastradh * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
116103b705cfSriastradh * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
116203b705cfSriastradh * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
116303b705cfSriastradh * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
116403b705cfSriastradh *
116503b705cfSriastradh * But we can do some simpler operations, right? How about PictOpOutReverse,
116603b705cfSriastradh * which has a source factor of 0 and dest factor of (1 - source alpha). We
116703b705cfSriastradh * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
116803b705cfSriastradh * blenders pretty easily. So we can do a component-alpha OutReverse, which
116903b705cfSriastradh * gets us:
117003b705cfSriastradh *
117103b705cfSriastradh * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
117203b705cfSriastradh * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
117303b705cfSriastradh * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
117403b705cfSriastradh * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
117503b705cfSriastradh *
117603b705cfSriastradh * OK. And if an op doesn't use the source alpha value for the destination
117703b705cfSriastradh * factor, then we can do the channel multiplication in the texture blenders
117803b705cfSriastradh * to get the source value, and ignore the source alpha that we wouldn't use.
117903b705cfSriastradh * We've supported this in the Radeon driver for a long time. An example would
118003b705cfSriastradh * be PictOpAdd, which does:
118103b705cfSriastradh *
118203b705cfSriastradh * dst.A = src.A * mask.A + dst.A
118303b705cfSriastradh * dst.R = src.R * mask.R + dst.R
118403b705cfSriastradh * dst.G = src.G * mask.G + dst.G
118503b705cfSriastradh * dst.B = src.B * mask.B + dst.B
118603b705cfSriastradh *
118703b705cfSriastradh * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
118803b705cfSriastradh * after it, we get:
118903b705cfSriastradh *
119003b705cfSriastradh * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
119103b705cfSriastradh * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
119203b705cfSriastradh * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
119303b705cfSriastradh * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
119403b705cfSriastradh */
119503b705cfSriastradh
119603b705cfSriastradhstatic int
119703b705cfSriastradhuxa_try_magic_two_pass_composite_helper(CARD8 op,
119803b705cfSriastradh					PicturePtr pSrc,
119903b705cfSriastradh					PicturePtr pMask,
120003b705cfSriastradh					PicturePtr pDst,
120103b705cfSriastradh					INT16 xSrc, INT16 ySrc,
120203b705cfSriastradh					INT16 xMask, INT16 yMask,
120303b705cfSriastradh					INT16 xDst, INT16 yDst,
120403b705cfSriastradh					CARD16 width, CARD16 height)
120503b705cfSriastradh{
120603b705cfSriastradh	ScreenPtr screen = pDst->pDrawable->pScreen;
120703b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
120803b705cfSriastradh	PicturePtr localDst = pDst;
120903b705cfSriastradh	int xDst_copy, yDst_copy;
121003b705cfSriastradh
121103b705cfSriastradh	assert(op == PictOpOver);
121203b705cfSriastradh
121303b705cfSriastradh	if (uxa_screen->info->check_composite &&
121403b705cfSriastradh	    (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc,
121503b705cfSriastradh						    pMask, pDst, width, height)
121603b705cfSriastradh	     || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask,
121703b705cfSriastradh						       pDst, width, height))) {
121803b705cfSriastradh		return -1;
121903b705cfSriastradh	}
122003b705cfSriastradh
122103b705cfSriastradh	if (uxa_screen->info->check_composite_target &&
122203b705cfSriastradh	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
122303b705cfSriastradh		int depth = pDst->pDrawable->depth;
122403b705cfSriastradh		PixmapPtr pixmap;
122503b705cfSriastradh		int error;
122603b705cfSriastradh		GCPtr gc;
122703b705cfSriastradh
122803b705cfSriastradh		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
122903b705cfSriastradh		if (uxa_screen->info->check_copy &&
123003b705cfSriastradh		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
123103b705cfSriastradh			return -1;
123203b705cfSriastradh
123303b705cfSriastradh		pixmap = screen->CreatePixmap(screen,
123403b705cfSriastradh					      width, height, depth,
123503b705cfSriastradh					      CREATE_PIXMAP_USAGE_SCRATCH);
123603b705cfSriastradh		if (!pixmap)
123703b705cfSriastradh			return 0;
123803b705cfSriastradh
123903b705cfSriastradh		gc = GetScratchGC(depth, screen);
124003b705cfSriastradh		if (!gc) {
124103b705cfSriastradh			screen->DestroyPixmap(pixmap);
124203b705cfSriastradh			return 0;
124303b705cfSriastradh		}
124403b705cfSriastradh
124503b705cfSriastradh		ValidateGC(&pixmap->drawable, gc);
124603b705cfSriastradh		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
124703b705cfSriastradh				  xDst, yDst, width, height, 0, 0);
124803b705cfSriastradh		FreeScratchGC(gc);
124903b705cfSriastradh
125003b705cfSriastradh		xDst_copy = xDst; xDst = 0;
125103b705cfSriastradh		yDst_copy = yDst; yDst = 0;
125203b705cfSriastradh
125303b705cfSriastradh		localDst = CreatePicture(0, &pixmap->drawable,
125403b705cfSriastradh					 PictureMatchFormat(screen, depth, pDst->format),
125503b705cfSriastradh					 0, 0, serverClient, &error);
125603b705cfSriastradh		screen->DestroyPixmap(pixmap);
125703b705cfSriastradh
125803b705cfSriastradh		if (!localDst)
125903b705cfSriastradh			return 0;
126003b705cfSriastradh
126103b705cfSriastradh		ValidatePicture(localDst);
126203b705cfSriastradh	}
126303b705cfSriastradh
126403b705cfSriastradh	/* Now, we think we should be able to accelerate this operation. First,
126503b705cfSriastradh	 * composite the destination to be the destination times the source alpha
126603b705cfSriastradh	 * factors.
126703b705cfSriastradh	 */
126803b705cfSriastradh	uxa_composite(PictOpOutReverse, pSrc, pMask, localDst,
126903b705cfSriastradh		      xSrc, ySrc,
127003b705cfSriastradh		      xMask, yMask,
127103b705cfSriastradh		      xDst, yDst,
127203b705cfSriastradh		      width, height);
127303b705cfSriastradh
127403b705cfSriastradh	/* Then, add in the source value times the destination alpha factors (1.0).
127503b705cfSriastradh	 */
127603b705cfSriastradh	uxa_composite(PictOpAdd, pSrc, pMask, localDst,
127703b705cfSriastradh		      xSrc, ySrc,
127803b705cfSriastradh		      xMask, yMask,
127903b705cfSriastradh		      xDst, yDst,
128003b705cfSriastradh		      width, height);
128103b705cfSriastradh
128203b705cfSriastradh	if (localDst != pDst) {
128303b705cfSriastradh		GCPtr gc;
128403b705cfSriastradh
128503b705cfSriastradh		gc = GetScratchGC(pDst->pDrawable->depth, screen);
128603b705cfSriastradh		if (gc) {
128703b705cfSriastradh			ValidateGC(pDst->pDrawable, gc);
128803b705cfSriastradh			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
128903b705cfSriastradh					0, 0, width, height, xDst_copy, yDst_copy);
129003b705cfSriastradh			FreeScratchGC(gc);
129103b705cfSriastradh		}
129203b705cfSriastradh
129303b705cfSriastradh		FreePicture(localDst, 0);
129403b705cfSriastradh	}
129503b705cfSriastradh
129603b705cfSriastradh	return 1;
129703b705cfSriastradh}
129803b705cfSriastradh
129903b705cfSriastradhstatic int
130003b705cfSriastradhcompatible_formats (CARD8 op, PicturePtr dst, PicturePtr src)
130103b705cfSriastradh{
130203b705cfSriastradh	if (op == PictOpSrc) {
130303b705cfSriastradh		if (src->format == dst->format)
130403b705cfSriastradh			return 1;
130503b705cfSriastradh
130603b705cfSriastradh		/* Is the destination an alpha-less version of source? */
130703b705cfSriastradh		if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format),
130803b705cfSriastradh					       PICT_FORMAT_TYPE(src->format),
130903b705cfSriastradh					       0,
131003b705cfSriastradh					       PICT_FORMAT_R(src->format),
131103b705cfSriastradh					       PICT_FORMAT_G(src->format),
131203b705cfSriastradh					       PICT_FORMAT_B(src->format)))
131303b705cfSriastradh			return 1;
131403b705cfSriastradh
131503b705cfSriastradh		/* XXX xrgb is promoted to argb during image upload... */
131603b705cfSriastradh#if 0
131703b705cfSriastradh		if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8)
131803b705cfSriastradh			return 1;
131903b705cfSriastradh#endif
132003b705cfSriastradh	} else if (op == PictOpOver) {
132103b705cfSriastradh		if (PICT_FORMAT_A(src->format))
132203b705cfSriastradh			return 0;
132303b705cfSriastradh
132403b705cfSriastradh		return src->format == dst->format;
132503b705cfSriastradh	}
132603b705cfSriastradh
132703b705cfSriastradh	return 0;
132803b705cfSriastradh}
132903b705cfSriastradh
133003b705cfSriastradhvoid
133103b705cfSriastradhuxa_composite(CARD8 op,
133203b705cfSriastradh	      PicturePtr pSrc,
133303b705cfSriastradh	      PicturePtr pMask,
133403b705cfSriastradh	      PicturePtr pDst,
133503b705cfSriastradh	      INT16 xSrc, INT16 ySrc,
133603b705cfSriastradh	      INT16 xMask, INT16 yMask,
133703b705cfSriastradh	      INT16 xDst, INT16 yDst,
133803b705cfSriastradh	      CARD16 width, CARD16 height)
133903b705cfSriastradh{
134003b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
134103b705cfSriastradh	int ret = -1;
134203b705cfSriastradh	Bool saveSrcRepeat = pSrc->repeat;
134303b705cfSriastradh	Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
134403b705cfSriastradh	RegionRec region;
134503b705cfSriastradh	int tx, ty;
134603b705cfSriastradh
134703b705cfSriastradh	if (uxa_screen->force_fallback)
134803b705cfSriastradh		goto fallback;
134903b705cfSriastradh
135003b705cfSriastradh	if (!uxa_drawable_is_offscreen(pDst->pDrawable))
135103b705cfSriastradh		goto fallback;
135203b705cfSriastradh
135303b705cfSriastradh	if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap))
135403b705cfSriastradh		goto fallback;
135503b705cfSriastradh
135603b705cfSriastradh	/* Remove repeat in source if useless */
135703b705cfSriastradh	if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution &&
135803b705cfSriastradh	    transform_is_integer_translation(pSrc->transform, &tx, &ty) &&
135903b705cfSriastradh	    (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) &&
136003b705cfSriastradh	    drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height))
136103b705cfSriastradh		pSrc->repeat = 0;
136203b705cfSriastradh
136303b705cfSriastradh	if (!pMask) {
136403b705cfSriastradh		if (op == PictOpClear) {
136503b705cfSriastradh			PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen);
136603b705cfSriastradh			if (clear &&
136703b705cfSriastradh			    uxa_try_driver_solid_fill(clear, pDst,
136803b705cfSriastradh						      xSrc, ySrc,
136903b705cfSriastradh						      xDst, yDst,
137003b705cfSriastradh						      width, height) == 1)
137103b705cfSriastradh				goto done;
137203b705cfSriastradh		}
137303b705cfSriastradh
137403b705cfSriastradh		if (pSrc->pDrawable == NULL) {
137503b705cfSriastradh			if (pSrc->pSourcePict) {
137603b705cfSriastradh				SourcePict *source = pSrc->pSourcePict;
137703b705cfSriastradh				if (source->type == SourcePictTypeSolidFill) {
137803b705cfSriastradh					if (op == PictOpSrc ||
137903b705cfSriastradh					    (op == PictOpOver &&
138003b705cfSriastradh					     (source->solidFill.color & 0xff000000) == 0xff000000)) {
138103b705cfSriastradh						ret = uxa_try_driver_solid_fill(pSrc, pDst,
138203b705cfSriastradh										xSrc, ySrc,
138303b705cfSriastradh										xDst, yDst,
138403b705cfSriastradh										width, height);
138503b705cfSriastradh						if (ret == 1)
138603b705cfSriastradh							goto done;
138703b705cfSriastradh					}
138803b705cfSriastradh				}
138903b705cfSriastradh			}
139003b705cfSriastradh		} else if (pSrc->pDrawable->width == 1 &&
139103b705cfSriastradh			   pSrc->pDrawable->height == 1 &&
139203b705cfSriastradh			   pSrc->repeat &&
139303b705cfSriastradh			   (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) {
139403b705cfSriastradh			ret = uxa_try_driver_solid_fill(pSrc, pDst,
139503b705cfSriastradh							xSrc, ySrc,
139603b705cfSriastradh							xDst, yDst,
139703b705cfSriastradh							width, height);
139803b705cfSriastradh			if (ret == 1)
139903b705cfSriastradh				goto done;
140003b705cfSriastradh		} else if (compatible_formats (op, pDst, pSrc) &&
140103b705cfSriastradh			   pSrc->filter != PictFilterConvolution &&
140203b705cfSriastradh			   transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
140303b705cfSriastradh			if (!pSrc->repeat &&
140403b705cfSriastradh			    drawable_contains(pSrc->pDrawable,
140503b705cfSriastradh					     xSrc + tx, ySrc + ty,
140603b705cfSriastradh					     width, height)) {
140703b705cfSriastradh				xDst += pDst->pDrawable->x;
140803b705cfSriastradh				yDst += pDst->pDrawable->y;
140903b705cfSriastradh				xSrc += pSrc->pDrawable->x + tx;
141003b705cfSriastradh				ySrc += pSrc->pDrawable->y + ty;
141103b705cfSriastradh
141203b705cfSriastradh				if (!miComputeCompositeRegion
141303b705cfSriastradh				    (&region, pSrc, pMask, pDst, xSrc, ySrc,
141403b705cfSriastradh				     xMask, yMask, xDst, yDst, width, height))
141503b705cfSriastradh					goto done;
141603b705cfSriastradh
141703b705cfSriastradh				uxa_copy_n_to_n(pSrc->pDrawable,
141803b705cfSriastradh						pDst->pDrawable, NULL,
141903b705cfSriastradh						REGION_RECTS(&region),
142003b705cfSriastradh						REGION_NUM_RECTS(&region),
142103b705cfSriastradh						xSrc - xDst, ySrc - yDst, FALSE,
142203b705cfSriastradh						FALSE, 0, NULL);
142303b705cfSriastradh				REGION_UNINIT(pDst->pDrawable->pScreen,
142403b705cfSriastradh					      &region);
142503b705cfSriastradh				goto done;
142603b705cfSriastradh			} else if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
142703b705cfSriastradh				   pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
142803b705cfSriastradh				DDXPointRec patOrg;
142903b705cfSriastradh
143003b705cfSriastradh				/* Let's see if the driver can do the repeat
143103b705cfSriastradh				 * in one go
143203b705cfSriastradh				 */
143303b705cfSriastradh				if (uxa_screen->info->prepare_composite) {
143403b705cfSriastradh					ret = uxa_try_driver_composite(op, pSrc,
143503b705cfSriastradh								       pMask, pDst,
143603b705cfSriastradh								       xSrc, ySrc,
143703b705cfSriastradh								       xMask, yMask,
143803b705cfSriastradh								       xDst, yDst,
143903b705cfSriastradh								       width, height);
144003b705cfSriastradh					if (ret == 1)
144103b705cfSriastradh						goto done;
144203b705cfSriastradh				}
144303b705cfSriastradh
144403b705cfSriastradh				/* Now see if we can use
144503b705cfSriastradh				 * uxa_fill_region_tiled()
144603b705cfSriastradh				 */
144703b705cfSriastradh				xDst += pDst->pDrawable->x;
144803b705cfSriastradh				yDst += pDst->pDrawable->y;
144903b705cfSriastradh				xSrc += pSrc->pDrawable->x + tx;
145003b705cfSriastradh				ySrc += pSrc->pDrawable->y + ty;
145103b705cfSriastradh
145203b705cfSriastradh				if (!miComputeCompositeRegion
145303b705cfSriastradh				    (&region, pSrc, pMask, pDst, xSrc, ySrc,
145403b705cfSriastradh				     xMask, yMask, xDst, yDst, width, height))
145503b705cfSriastradh					goto done;
145603b705cfSriastradh
145703b705cfSriastradh				/* pattern origin is the point in the
145803b705cfSriastradh				 * destination drawable
145903b705cfSriastradh				 * corresponding to (0,0) in the source */
146003b705cfSriastradh				patOrg.x = xDst - xSrc;
146103b705cfSriastradh				patOrg.y = yDst - ySrc;
146203b705cfSriastradh
146303b705cfSriastradh				ret = uxa_fill_region_tiled(pDst->pDrawable,
146403b705cfSriastradh							    &region,
146503b705cfSriastradh							    (PixmapPtr) pSrc->
146603b705cfSriastradh							    pDrawable, &patOrg,
146703b705cfSriastradh							    FB_ALLONES, GXcopy);
146803b705cfSriastradh
146903b705cfSriastradh				REGION_UNINIT(pDst->pDrawable->pScreen,
147003b705cfSriastradh					      &region);
147103b705cfSriastradh
147203b705cfSriastradh				if (ret)
147303b705cfSriastradh					goto done;
147403b705cfSriastradh			}
147503b705cfSriastradh		}
147603b705cfSriastradh	}
147703b705cfSriastradh
147803b705cfSriastradh	/* Remove repeat in mask if useless */
147903b705cfSriastradh	if (pMask && pMask->pDrawable && pMask->repeat &&
148003b705cfSriastradh	    pMask->filter != PictFilterConvolution &&
148103b705cfSriastradh	    transform_is_integer_translation(pMask->transform, &tx, &ty) &&
148203b705cfSriastradh	    (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) &&
148303b705cfSriastradh	    drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height))
148403b705cfSriastradh		pMask->repeat = 0;
148503b705cfSriastradh
148603b705cfSriastradh	if (uxa_screen->info->prepare_composite) {
148703b705cfSriastradh		Bool isSrcSolid;
148803b705cfSriastradh
148903b705cfSriastradh		ret =
149003b705cfSriastradh		    uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
149103b705cfSriastradh					     xMask, yMask, xDst, yDst, width,
149203b705cfSriastradh					     height);
149303b705cfSriastradh		if (ret == 1)
149403b705cfSriastradh			goto done;
149503b705cfSriastradh
149603b705cfSriastradh		/* For generic masks and solid src pictures, mach64 can do
149703b705cfSriastradh		 * Over in two passes, similar to the component-alpha case.
149803b705cfSriastradh		 */
149903b705cfSriastradh
150003b705cfSriastradh		isSrcSolid =
150103b705cfSriastradh			pSrc->pDrawable ?
150203b705cfSriastradh				pSrc->pDrawable->width == 1 &&
150303b705cfSriastradh				pSrc->pDrawable->height == 1 &&
150403b705cfSriastradh				pSrc->repeat :
150503b705cfSriastradh			pSrc->pSourcePict ?
150603b705cfSriastradh				pSrc->pSourcePict->type == SourcePictTypeSolidFill :
150703b705cfSriastradh			0;
150803b705cfSriastradh
150903b705cfSriastradh		/* If we couldn't do the Composite in a single pass, and it
151003b705cfSriastradh		 * was a component-alpha Over, see if we can do it in two
151103b705cfSriastradh		 * passes with an OutReverse and then an Add.
151203b705cfSriastradh		 */
151303b705cfSriastradh		if (ret == -1 && op == PictOpOver && pMask &&
151403b705cfSriastradh		    (pMask->componentAlpha || isSrcSolid)) {
151503b705cfSriastradh			ret =
151603b705cfSriastradh			    uxa_try_magic_two_pass_composite_helper(op, pSrc,
151703b705cfSriastradh								    pMask, pDst,
151803b705cfSriastradh								    xSrc, ySrc,
151903b705cfSriastradh								    xMask, yMask,
152003b705cfSriastradh								    xDst, yDst,
152103b705cfSriastradh								    width, height);
152203b705cfSriastradh			if (ret == 1)
152303b705cfSriastradh				goto done;
152403b705cfSriastradh		}
152503b705cfSriastradh
152603b705cfSriastradh	}
152703b705cfSriastradh
152803b705cfSriastradhfallback:
152903b705cfSriastradh	uxa_print_composite_fallback("uxa_composite",
153003b705cfSriastradh				     op, pSrc, pMask, pDst);
153103b705cfSriastradh
153203b705cfSriastradh	uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
153303b705cfSriastradh			    xMask, yMask, xDst, yDst, width, height);
153403b705cfSriastradh
153503b705cfSriastradhdone:
153603b705cfSriastradh	pSrc->repeat = saveSrcRepeat;
153703b705cfSriastradh	if (pMask)
153803b705cfSriastradh		pMask->repeat = saveMaskRepeat;
153903b705cfSriastradh}
154003b705cfSriastradh#endif
154103b705cfSriastradh
154203b705cfSriastradh/**
154303b705cfSriastradh * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead
154403b705cfSriastradh * of PolyFillRect to initialize the pixmap after creating it, to prevent
154503b705cfSriastradh * the pixmap from being migrated.
154603b705cfSriastradh *
154703b705cfSriastradh * See the comments about uxa_trapezoids and uxa_triangles.
154803b705cfSriastradh */
154903b705cfSriastradhstatic PicturePtr
155003b705cfSriastradhuxa_create_alpha_picture(ScreenPtr pScreen,
155103b705cfSriastradh			 PicturePtr pDst,
155203b705cfSriastradh			 PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
155303b705cfSriastradh{
155403b705cfSriastradh	PixmapPtr pPixmap;
155503b705cfSriastradh	PicturePtr pPicture;
155603b705cfSriastradh	int error;
155703b705cfSriastradh
155803b705cfSriastradh	if (width > 32767 || height > 32767)
155903b705cfSriastradh		return 0;
156003b705cfSriastradh
156103b705cfSriastradh	if (!pPictFormat) {
156203b705cfSriastradh		if (pDst->polyEdge == PolyEdgeSharp)
156303b705cfSriastradh			pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
156403b705cfSriastradh		else
156503b705cfSriastradh			pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
156603b705cfSriastradh		if (!pPictFormat)
156703b705cfSriastradh			return 0;
156803b705cfSriastradh	}
156903b705cfSriastradh
157003b705cfSriastradh	pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
157103b705cfSriastradh					    pPictFormat->depth,
157203b705cfSriastradh					    UXA_CREATE_PIXMAP_FOR_MAP);
157303b705cfSriastradh	if (!pPixmap)
157403b705cfSriastradh		return 0;
157503b705cfSriastradh	pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
157603b705cfSriastradh				 0, 0, serverClient, &error);
157703b705cfSriastradh	(*pScreen->DestroyPixmap) (pPixmap);
157803b705cfSriastradh	return pPicture;
157903b705cfSriastradh}
158003b705cfSriastradh
158103b705cfSriastradhstatic void
158203b705cfSriastradhuxa_check_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
158303b705cfSriastradh		     PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
158403b705cfSriastradh		     int ntrap, xTrapezoid * traps)
158503b705cfSriastradh{
158603b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
158703b705cfSriastradh
158803b705cfSriastradh	if (maskFormat) {
158903b705cfSriastradh		PixmapPtr scratch = NULL;
159003b705cfSriastradh		PicturePtr mask;
159103b705cfSriastradh		INT16 xDst, yDst;
159203b705cfSriastradh		INT16 xRel, yRel;
159303b705cfSriastradh		BoxRec bounds;
159403b705cfSriastradh		int width, height;
159503b705cfSriastradh		pixman_image_t *image;
159603b705cfSriastradh		pixman_format_code_t format;
159703b705cfSriastradh		int error;
159803b705cfSriastradh
159903b705cfSriastradh		xDst = traps[0].left.p1.x >> 16;
160003b705cfSriastradh		yDst = traps[0].left.p1.y >> 16;
160103b705cfSriastradh
160203b705cfSriastradh		miTrapezoidBounds (ntrap, traps, &bounds);
160303b705cfSriastradh		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
160403b705cfSriastradh			return;
160503b705cfSriastradh
160603b705cfSriastradh		width  = bounds.x2 - bounds.x1;
160703b705cfSriastradh		height = bounds.y2 - bounds.y1;
160803b705cfSriastradh
160903b705cfSriastradh		format = maskFormat->format |
161003b705cfSriastradh			(BitsPerPixel(maskFormat->depth) << 24);
161103b705cfSriastradh		image =
161203b705cfSriastradh		    pixman_image_create_bits(format, width, height, NULL, 0);
161303b705cfSriastradh		if (!image)
161403b705cfSriastradh			return;
161503b705cfSriastradh
161603b705cfSriastradh		for (; ntrap; ntrap--, traps++)
161703b705cfSriastradh			pixman_rasterize_trapezoid(image,
161803b705cfSriastradh						   (pixman_trapezoid_t *) traps,
161903b705cfSriastradh						   -bounds.x1, -bounds.y1);
162003b705cfSriastradh
162103b705cfSriastradh
162203b705cfSriastradh		scratch = GetScratchPixmapHeader(screen, width, height,
162303b705cfSriastradh						 PIXMAN_FORMAT_DEPTH(format),
162403b705cfSriastradh						 PIXMAN_FORMAT_BPP(format),
162503b705cfSriastradh						 pixman_image_get_stride(image),
162603b705cfSriastradh						 pixman_image_get_data(image));
162703b705cfSriastradh		if (!scratch) {
162803b705cfSriastradh			pixman_image_unref(image);
162903b705cfSriastradh			return;
163003b705cfSriastradh		}
163103b705cfSriastradh
163203b705cfSriastradh		mask = CreatePicture(0, &scratch->drawable,
163303b705cfSriastradh				     PictureMatchFormat(screen,
163403b705cfSriastradh							PIXMAN_FORMAT_DEPTH(format),
163503b705cfSriastradh							format),
163603b705cfSriastradh				     0, 0, serverClient, &error);
163703b705cfSriastradh		if (!mask) {
163803b705cfSriastradh			FreeScratchPixmapHeader(scratch);
163903b705cfSriastradh			pixman_image_unref(image);
164003b705cfSriastradh			return;
164103b705cfSriastradh		}
164203b705cfSriastradh
164303b705cfSriastradh		xRel = bounds.x1 + xSrc - xDst;
164403b705cfSriastradh		yRel = bounds.y1 + ySrc - yDst;
164503b705cfSriastradh		CompositePicture(op, src, mask, dst,
164603b705cfSriastradh				 xRel, yRel,
164703b705cfSriastradh				 0, 0,
164803b705cfSriastradh				 bounds.x1, bounds.y1,
164903b705cfSriastradh				 width, height);
165003b705cfSriastradh		FreePicture(mask, 0);
165103b705cfSriastradh
165203b705cfSriastradh		FreeScratchPixmapHeader(scratch);
165303b705cfSriastradh		pixman_image_unref(image);
165403b705cfSriastradh	} else {
165503b705cfSriastradh		if (dst->polyEdge == PolyEdgeSharp)
165603b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
165703b705cfSriastradh		else
165803b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
165903b705cfSriastradh
166003b705cfSriastradh		for (; ntrap; ntrap--, traps++)
166103b705cfSriastradh			uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1, traps);
166203b705cfSriastradh	}
166303b705cfSriastradh}
166403b705cfSriastradh
166503b705cfSriastradh/**
166603b705cfSriastradh * uxa_trapezoids is essentially a copy of miTrapezoids that uses
166703b705cfSriastradh * uxa_create_alpha_picture instead of miCreateAlphaPicture.
166803b705cfSriastradh *
166903b705cfSriastradh * The problem with miCreateAlphaPicture is that it calls PolyFillRect
167003b705cfSriastradh * to initialize the contents after creating the pixmap, which
167103b705cfSriastradh * causes the pixmap to be moved in for acceleration. The subsequent
167203b705cfSriastradh * call to RasterizeTrapezoid won't be accelerated however, which
167303b705cfSriastradh * forces the pixmap to be moved out again.
167403b705cfSriastradh *
167503b705cfSriastradh * uxa_create_alpha_picture avoids this roundtrip by using
167603b705cfSriastradh * uxa_check_poly_fill_rect to initialize the contents.
167703b705cfSriastradh */
167803b705cfSriastradhvoid
167903b705cfSriastradhuxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
168003b705cfSriastradh	       PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
168103b705cfSriastradh	       int ntrap, xTrapezoid * traps)
168203b705cfSriastradh{
168303b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
168403b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
168503b705cfSriastradh	BoxRec bounds;
168603b705cfSriastradh	Bool direct;
168703b705cfSriastradh
168803b705cfSriastradh	if (uxa_screen->force_fallback) {
168903b705cfSriastradh		uxa_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, ntrap, traps);
169003b705cfSriastradh		return;
169103b705cfSriastradh	}
169203b705cfSriastradh
169303b705cfSriastradh	direct = op == PictOpAdd && miIsSolidAlpha(src);
169403b705cfSriastradh	if (maskFormat || direct) {
169503b705cfSriastradh		miTrapezoidBounds(ntrap, traps, &bounds);
169603b705cfSriastradh
169703b705cfSriastradh		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
169803b705cfSriastradh			return;
169903b705cfSriastradh	}
170003b705cfSriastradh
170103b705cfSriastradh	/*
170203b705cfSriastradh	 * Check for solid alpha add
170303b705cfSriastradh	 */
170403b705cfSriastradh	if (direct) {
170503b705cfSriastradh		DrawablePtr pDraw = dst->pDrawable;
170603b705cfSriastradh		PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw);
170703b705cfSriastradh		int xoff, yoff;
170803b705cfSriastradh
170903b705cfSriastradh		uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff);
171003b705cfSriastradh
171103b705cfSriastradh		xoff += pDraw->x;
171203b705cfSriastradh		yoff += pDraw->y;
171303b705cfSriastradh
171403b705cfSriastradh		if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) {
171503b705cfSriastradh			PictureScreenPtr ps = GetPictureScreen(screen);
171603b705cfSriastradh
171703b705cfSriastradh			for (; ntrap; ntrap--, traps++)
171803b705cfSriastradh				(*ps->RasterizeTrapezoid) (dst, traps, 0, 0);
171903b705cfSriastradh			uxa_finish_access(pDraw, UXA_ACCESS_RW);
172003b705cfSriastradh		}
172103b705cfSriastradh	} else if (maskFormat) {
172203b705cfSriastradh		PixmapPtr scratch = NULL;
172303b705cfSriastradh		PicturePtr mask;
172403b705cfSriastradh		INT16 xDst, yDst;
172503b705cfSriastradh		INT16 xRel, yRel;
172603b705cfSriastradh		int width, height;
172703b705cfSriastradh		pixman_image_t *image;
172803b705cfSriastradh		pixman_format_code_t format;
172903b705cfSriastradh
173003b705cfSriastradh		xDst = traps[0].left.p1.x >> 16;
173103b705cfSriastradh		yDst = traps[0].left.p1.y >> 16;
173203b705cfSriastradh
173303b705cfSriastradh		width  = bounds.x2 - bounds.x1;
173403b705cfSriastradh		height = bounds.y2 - bounds.y1;
173503b705cfSriastradh
173603b705cfSriastradh		format = maskFormat->format |
173703b705cfSriastradh			(BitsPerPixel(maskFormat->depth) << 24);
173803b705cfSriastradh		image =
173903b705cfSriastradh		    pixman_image_create_bits(format, width, height, NULL, 0);
174003b705cfSriastradh		if (!image)
174103b705cfSriastradh			return;
174203b705cfSriastradh
174303b705cfSriastradh		for (; ntrap; ntrap--, traps++)
174403b705cfSriastradh			pixman_rasterize_trapezoid(image,
174503b705cfSriastradh						   (pixman_trapezoid_t *) traps,
174603b705cfSriastradh						   -bounds.x1, -bounds.y1);
174703b705cfSriastradh		if (uxa_drawable_is_offscreen(dst->pDrawable)) {
174803b705cfSriastradh			mask = uxa_picture_from_pixman_image(screen, image, format);
174903b705cfSriastradh		} else {
175003b705cfSriastradh			int error;
175103b705cfSriastradh
175203b705cfSriastradh			scratch = GetScratchPixmapHeader(screen, width, height,
175303b705cfSriastradh							PIXMAN_FORMAT_DEPTH(format),
175403b705cfSriastradh							PIXMAN_FORMAT_BPP(format),
175503b705cfSriastradh							pixman_image_get_stride(image),
175603b705cfSriastradh							pixman_image_get_data(image));
175703b705cfSriastradh			mask = CreatePicture(0, &scratch->drawable,
175803b705cfSriastradh					     PictureMatchFormat(screen,
175903b705cfSriastradh								PIXMAN_FORMAT_DEPTH(format),
176003b705cfSriastradh								format),
176103b705cfSriastradh					     0, 0, serverClient, &error);
176203b705cfSriastradh		}
176303b705cfSriastradh		if (!mask) {
176403b705cfSriastradh			if (scratch)
176503b705cfSriastradh				FreeScratchPixmapHeader(scratch);
176603b705cfSriastradh			pixman_image_unref(image);
176703b705cfSriastradh			return;
176803b705cfSriastradh		}
176903b705cfSriastradh
177003b705cfSriastradh		xRel = bounds.x1 + xSrc - xDst;
177103b705cfSriastradh		yRel = bounds.y1 + ySrc - yDst;
177203b705cfSriastradh		CompositePicture(op, src, mask, dst,
177303b705cfSriastradh				 xRel, yRel,
177403b705cfSriastradh				 0, 0,
177503b705cfSriastradh				 bounds.x1, bounds.y1,
177603b705cfSriastradh				 width, height);
177703b705cfSriastradh		FreePicture(mask, 0);
177803b705cfSriastradh
177903b705cfSriastradh		if (scratch)
178003b705cfSriastradh			FreeScratchPixmapHeader(scratch);
178103b705cfSriastradh		pixman_image_unref(image);
178203b705cfSriastradh	} else {
178303b705cfSriastradh		if (dst->polyEdge == PolyEdgeSharp)
178403b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
178503b705cfSriastradh		else
178603b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
178703b705cfSriastradh		for (; ntrap; ntrap--, traps++)
178803b705cfSriastradh			uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc,
178903b705cfSriastradh				       1, traps);
179003b705cfSriastradh	}
179103b705cfSriastradh}
179203b705cfSriastradh
179303b705cfSriastradhstatic void
179403b705cfSriastradhuxa_check_triangles(CARD8 op, PicturePtr src, PicturePtr dst,
179503b705cfSriastradh		    PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
179603b705cfSriastradh		    int ntri, xTriangle *tri)
179703b705cfSriastradh{
179803b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
179903b705cfSriastradh
180003b705cfSriastradh	if (maskFormat) {
180103b705cfSriastradh		PixmapPtr scratch = NULL;
180203b705cfSriastradh		PicturePtr mask;
180303b705cfSriastradh		INT16 xDst, yDst;
180403b705cfSriastradh		INT16 xRel, yRel;
180503b705cfSriastradh		BoxRec bounds;
180603b705cfSriastradh		int width, height;
180703b705cfSriastradh		pixman_image_t *image;
180803b705cfSriastradh		pixman_format_code_t format;
180903b705cfSriastradh		int error;
181003b705cfSriastradh
181103b705cfSriastradh		xDst = pixman_fixed_to_int(tri[0].p1.x);
181203b705cfSriastradh		yDst = pixman_fixed_to_int(tri[0].p1.y);
181303b705cfSriastradh
181403b705cfSriastradh		miTriangleBounds (ntri, tri, &bounds);
181503b705cfSriastradh		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
181603b705cfSriastradh			return;
181703b705cfSriastradh
181803b705cfSriastradh		width  = bounds.x2 - bounds.x1;
181903b705cfSriastradh		height = bounds.y2 - bounds.y1;
182003b705cfSriastradh
182103b705cfSriastradh		format = maskFormat->format |
182203b705cfSriastradh			(BitsPerPixel(maskFormat->depth) << 24);
182303b705cfSriastradh		image =
182403b705cfSriastradh		    pixman_image_create_bits(format, width, height, NULL, 0);
182503b705cfSriastradh		if (!image)
182603b705cfSriastradh			return;
182703b705cfSriastradh
182803b705cfSriastradh		pixman_add_triangles(image,
182903b705cfSriastradh				     -bounds.x1, -bounds.y1,
183003b705cfSriastradh				     ntri, (pixman_triangle_t *)tri);
183103b705cfSriastradh
183203b705cfSriastradh		scratch = GetScratchPixmapHeader(screen, width, height,
183303b705cfSriastradh						 PIXMAN_FORMAT_DEPTH(format),
183403b705cfSriastradh						 PIXMAN_FORMAT_BPP(format),
183503b705cfSriastradh						 pixman_image_get_stride(image),
183603b705cfSriastradh						 pixman_image_get_data(image));
183703b705cfSriastradh		if (!scratch) {
183803b705cfSriastradh			pixman_image_unref(image);
183903b705cfSriastradh			return;
184003b705cfSriastradh		}
184103b705cfSriastradh
184203b705cfSriastradh		mask = CreatePicture(0, &scratch->drawable,
184303b705cfSriastradh				     PictureMatchFormat(screen,
184403b705cfSriastradh							PIXMAN_FORMAT_DEPTH(format),
184503b705cfSriastradh							format),
184603b705cfSriastradh				     0, 0, serverClient, &error);
184703b705cfSriastradh		if (!mask) {
184803b705cfSriastradh			FreeScratchPixmapHeader(scratch);
184903b705cfSriastradh			pixman_image_unref(image);
185003b705cfSriastradh			return;
185103b705cfSriastradh		}
185203b705cfSriastradh
185303b705cfSriastradh		xRel = bounds.x1 + xSrc - xDst;
185403b705cfSriastradh		yRel = bounds.y1 + ySrc - yDst;
185503b705cfSriastradh		CompositePicture(op, src, mask, dst,
185603b705cfSriastradh				 xRel, yRel,
185703b705cfSriastradh				 0, 0,
185803b705cfSriastradh				 bounds.x1, bounds.y1,
185903b705cfSriastradh				 width, height);
186003b705cfSriastradh		FreePicture(mask, 0);
186103b705cfSriastradh
186203b705cfSriastradh		FreeScratchPixmapHeader(scratch);
186303b705cfSriastradh		pixman_image_unref(image);
186403b705cfSriastradh	} else {
186503b705cfSriastradh		if (dst->polyEdge == PolyEdgeSharp)
186603b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
186703b705cfSriastradh		else
186803b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
186903b705cfSriastradh
187003b705cfSriastradh		for (; ntri; ntri--, tri++)
187103b705cfSriastradh			uxa_check_triangles(op, src, dst, maskFormat, xSrc, ySrc, 1, tri);
187203b705cfSriastradh	}
187303b705cfSriastradh}
187403b705cfSriastradh
187503b705cfSriastradh/**
187603b705cfSriastradh * uxa_triangles is essentially a copy of miTriangles that uses
187703b705cfSriastradh * uxa_create_alpha_picture instead of miCreateAlphaPicture.
187803b705cfSriastradh *
187903b705cfSriastradh * The problem with miCreateAlphaPicture is that it calls PolyFillRect
188003b705cfSriastradh * to initialize the contents after creating the pixmap, which
188103b705cfSriastradh * causes the pixmap to be moved in for acceleration. The subsequent
188203b705cfSriastradh * call to AddTriangles won't be accelerated however, which forces the pixmap
188303b705cfSriastradh * to be moved out again.
188403b705cfSriastradh *
188503b705cfSriastradh * uxa_create_alpha_picture avoids this roundtrip by using
188603b705cfSriastradh * uxa_check_poly_fill_rect to initialize the contents.
188703b705cfSriastradh */
188803b705cfSriastradhvoid
188903b705cfSriastradhuxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
189003b705cfSriastradh	      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
189103b705cfSriastradh	      int ntri, xTriangle * tris)
189203b705cfSriastradh{
189303b705cfSriastradh	ScreenPtr pScreen = pDst->pDrawable->pScreen;
189403b705cfSriastradh	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
189503b705cfSriastradh	PictureScreenPtr ps = GetPictureScreen(pScreen);
189603b705cfSriastradh	BoxRec bounds;
189703b705cfSriastradh	Bool direct;
189803b705cfSriastradh
189903b705cfSriastradh	if (uxa_screen->force_fallback) {
190003b705cfSriastradh		uxa_check_triangles(op, pSrc, pDst, maskFormat,
190103b705cfSriastradh				    xSrc, ySrc, ntri, tris);
190203b705cfSriastradh		return;
190303b705cfSriastradh	}
190403b705cfSriastradh
190503b705cfSriastradh	direct = op == PictOpAdd && miIsSolidAlpha(pSrc);
190603b705cfSriastradh	if (maskFormat || direct) {
190703b705cfSriastradh		miTriangleBounds(ntri, tris, &bounds);
190803b705cfSriastradh
190903b705cfSriastradh		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
191003b705cfSriastradh			return;
191103b705cfSriastradh	}
191203b705cfSriastradh
191303b705cfSriastradh	/*
191403b705cfSriastradh	 * Check for solid alpha add
191503b705cfSriastradh	 */
191603b705cfSriastradh	if (direct) {
191703b705cfSriastradh		DrawablePtr pDraw = pDst->pDrawable;
191803b705cfSriastradh		if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) {
191903b705cfSriastradh			(*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
192003b705cfSriastradh			uxa_finish_access(pDraw, UXA_ACCESS_RW);
192103b705cfSriastradh		}
192203b705cfSriastradh	} else if (maskFormat) {
192303b705cfSriastradh		PicturePtr pPicture;
192403b705cfSriastradh		INT16 xDst, yDst;
192503b705cfSriastradh		INT16 xRel, yRel;
192603b705cfSriastradh		int width = bounds.x2 - bounds.x1;
192703b705cfSriastradh		int height = bounds.y2 - bounds.y1;
192803b705cfSriastradh		GCPtr pGC;
192903b705cfSriastradh		xRectangle rect;
193003b705cfSriastradh
193103b705cfSriastradh		xDst = tris[0].p1.x >> 16;
193203b705cfSriastradh		yDst = tris[0].p1.y >> 16;
193303b705cfSriastradh
193403b705cfSriastradh		pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat,
193503b705cfSriastradh						    width, height);
193603b705cfSriastradh		if (!pPicture)
193703b705cfSriastradh			return;
193803b705cfSriastradh
193903b705cfSriastradh		/* Clear the alpha picture to 0. */
194003b705cfSriastradh		pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen);
194103b705cfSriastradh		if (!pGC) {
194203b705cfSriastradh			FreePicture(pPicture, 0);
194303b705cfSriastradh			return;
194403b705cfSriastradh		}
194503b705cfSriastradh		ValidateGC(pPicture->pDrawable, pGC);
194603b705cfSriastradh		rect.x = 0;
194703b705cfSriastradh		rect.y = 0;
194803b705cfSriastradh		rect.width = width;
194903b705cfSriastradh		rect.height = height;
195003b705cfSriastradh		uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect);
195103b705cfSriastradh		FreeScratchGC(pGC);
195203b705cfSriastradh
195303b705cfSriastradh		if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) {
195403b705cfSriastradh			(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1,
195503b705cfSriastradh					     ntri, tris);
195603b705cfSriastradh			uxa_finish_access(pPicture->pDrawable, UXA_ACCESS_RW);
195703b705cfSriastradh		}
195803b705cfSriastradh
195903b705cfSriastradh		xRel = bounds.x1 + xSrc - xDst;
196003b705cfSriastradh		yRel = bounds.y1 + ySrc - yDst;
196103b705cfSriastradh		CompositePicture(op, pSrc, pPicture, pDst,
196203b705cfSriastradh				 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
196303b705cfSriastradh				 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
196403b705cfSriastradh		FreePicture(pPicture, 0);
196503b705cfSriastradh	} else {
196603b705cfSriastradh		if (pDst->polyEdge == PolyEdgeSharp)
196703b705cfSriastradh			maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
196803b705cfSriastradh		else
196903b705cfSriastradh			maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
197003b705cfSriastradh
197103b705cfSriastradh		for (; ntri; ntri--, tris++)
197203b705cfSriastradh			uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1,
197303b705cfSriastradh				      tris);
197403b705cfSriastradh	}
197503b705cfSriastradh}
197603b705cfSriastradh
197703b705cfSriastradhvoid
197803b705cfSriastradhuxa_add_traps(PicturePtr pPicture,
197903b705cfSriastradh	      INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
198003b705cfSriastradh{
198103b705cfSriastradh	uxa_check_add_traps(pPicture, x_off, y_off, ntrap, traps);
198203b705cfSriastradh}
1983