exa_render.c revision 05b261ec
105b261ecSmrg/*
205b261ecSmrg * Copyright © 2001 Keith Packard
305b261ecSmrg *
405b261ecSmrg * Partly based on code that is Copyright © The XFree86 Project Inc.
505b261ecSmrg *
605b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
705b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
805b261ecSmrg * the above copyright notice appear in all copies and that both that
905b261ecSmrg * copyright notice and this permission notice appear in supporting
1005b261ecSmrg * documentation, and that the name of Keith Packard not be used in
1105b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1205b261ecSmrg * specific, written prior permission.  Keith Packard makes no
1305b261ecSmrg * representations about the suitability of this software for any purpose.  It
1405b261ecSmrg * is provided "as is" without express or implied warranty.
1505b261ecSmrg *
1605b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1705b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1805b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1905b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2005b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2105b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2205b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2305b261ecSmrg */
2405b261ecSmrg
2505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2605b261ecSmrg#include <dix-config.h>
2705b261ecSmrg#endif
2805b261ecSmrg
2905b261ecSmrg#include <stdlib.h>
3005b261ecSmrg
3105b261ecSmrg#include "exa_priv.h"
3205b261ecSmrg
3305b261ecSmrg#ifdef RENDER
3405b261ecSmrg#include "mipict.h"
3505b261ecSmrg
3605b261ecSmrg#if DEBUG_TRACE_FALL
3705b261ecSmrgstatic void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
3805b261ecSmrg{
3905b261ecSmrg    char format[20];
4005b261ecSmrg    char size[20];
4105b261ecSmrg    char loc;
4205b261ecSmrg    int temp;
4305b261ecSmrg
4405b261ecSmrg    if (!pict) {
4505b261ecSmrg	snprintf(string, n, "None");
4605b261ecSmrg	return;
4705b261ecSmrg    }
4805b261ecSmrg
4905b261ecSmrg    switch (pict->format)
5005b261ecSmrg    {
5105b261ecSmrg    case PICT_a8r8g8b8:
5205b261ecSmrg	snprintf(format, 20, "ARGB8888");
5305b261ecSmrg	break;
5405b261ecSmrg    case PICT_r5g6b5:
5505b261ecSmrg	snprintf(format, 20, "RGB565  ");
5605b261ecSmrg	break;
5705b261ecSmrg    case PICT_x1r5g5b5:
5805b261ecSmrg	snprintf(format, 20, "RGB555  ");
5905b261ecSmrg	break;
6005b261ecSmrg    case PICT_a8:
6105b261ecSmrg	snprintf(format, 20, "A8      ");
6205b261ecSmrg	break;
6305b261ecSmrg    case PICT_a1:
6405b261ecSmrg	snprintf(format, 20, "A1      ");
6505b261ecSmrg	break;
6605b261ecSmrg    default:
6705b261ecSmrg	snprintf(format, 20, "0x%x", (int)pict->format);
6805b261ecSmrg	break;
6905b261ecSmrg    }
7005b261ecSmrg
7105b261ecSmrg    loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
7205b261ecSmrg
7305b261ecSmrg    snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
7405b261ecSmrg	     pict->pDrawable->height, pict->repeat ?
7505b261ecSmrg	     " R" : "");
7605b261ecSmrg
7705b261ecSmrg    snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size);
7805b261ecSmrg}
7905b261ecSmrg
8005b261ecSmrgstatic void
8105b261ecSmrgexaPrintCompositeFallback(CARD8 op,
8205b261ecSmrg			  PicturePtr pSrc,
8305b261ecSmrg			  PicturePtr pMask,
8405b261ecSmrg			  PicturePtr pDst)
8505b261ecSmrg{
8605b261ecSmrg    char sop[20];
8705b261ecSmrg    char srcdesc[40], maskdesc[40], dstdesc[40];
8805b261ecSmrg
8905b261ecSmrg    switch(op)
9005b261ecSmrg    {
9105b261ecSmrg    case PictOpSrc:
9205b261ecSmrg	sprintf(sop, "Src");
9305b261ecSmrg	break;
9405b261ecSmrg    case PictOpOver:
9505b261ecSmrg	sprintf(sop, "Over");
9605b261ecSmrg	break;
9705b261ecSmrg    default:
9805b261ecSmrg	sprintf(sop, "0x%x", (int)op);
9905b261ecSmrg	break;
10005b261ecSmrg    }
10105b261ecSmrg
10205b261ecSmrg    exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
10305b261ecSmrg    exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
10405b261ecSmrg    exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
10505b261ecSmrg
10605b261ecSmrg    ErrorF("Composite fallback: op %s, \n"
10705b261ecSmrg	   "                    src  %s, \n"
10805b261ecSmrg	   "                    mask %s, \n"
10905b261ecSmrg	   "                    dst  %s, \n",
11005b261ecSmrg	   sop, srcdesc, maskdesc, dstdesc);
11105b261ecSmrg}
11205b261ecSmrg#endif /* DEBUG_TRACE_FALL */
11305b261ecSmrg
11405b261ecSmrgstatic Bool
11505b261ecSmrgexaOpReadsDestination (CARD8 op)
11605b261ecSmrg{
11705b261ecSmrg    /* FALSE (does not read destination) is the list of ops in the protocol
11805b261ecSmrg     * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
11905b261ecSmrg     * That's just Clear and Src.  ReduceCompositeOp() will already have
12005b261ecSmrg     * converted con/disjoint clear/src to Clear or Src.
12105b261ecSmrg     */
12205b261ecSmrg    switch (op) {
12305b261ecSmrg    case PictOpClear:
12405b261ecSmrg    case PictOpSrc:
12505b261ecSmrg	return FALSE;
12605b261ecSmrg    default:
12705b261ecSmrg	return TRUE;
12805b261ecSmrg    }
12905b261ecSmrg}
13005b261ecSmrg
13105b261ecSmrg
13205b261ecSmrgstatic Bool
13305b261ecSmrgexaGetPixelFromRGBA(CARD32	*pixel,
13405b261ecSmrg		    CARD16	red,
13505b261ecSmrg		    CARD16	green,
13605b261ecSmrg		    CARD16	blue,
13705b261ecSmrg		    CARD16	alpha,
13805b261ecSmrg		    CARD32	format)
13905b261ecSmrg{
14005b261ecSmrg    int rbits, bbits, gbits, abits;
14105b261ecSmrg    int rshift, bshift, gshift, ashift;
14205b261ecSmrg
14305b261ecSmrg    *pixel = 0;
14405b261ecSmrg
14505b261ecSmrg    if (!PICT_FORMAT_COLOR(format))
14605b261ecSmrg	return FALSE;
14705b261ecSmrg
14805b261ecSmrg    rbits = PICT_FORMAT_R(format);
14905b261ecSmrg    gbits = PICT_FORMAT_G(format);
15005b261ecSmrg    bbits = PICT_FORMAT_B(format);
15105b261ecSmrg    abits = PICT_FORMAT_A(format);
15205b261ecSmrg
15305b261ecSmrg    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
15405b261ecSmrg	bshift = 0;
15505b261ecSmrg	gshift = bbits;
15605b261ecSmrg	rshift = gshift + gbits;
15705b261ecSmrg	ashift = rshift + rbits;
15805b261ecSmrg    } else {  /* PICT_TYPE_ABGR */
15905b261ecSmrg	rshift = 0;
16005b261ecSmrg	gshift = rbits;
16105b261ecSmrg	bshift = gshift + gbits;
16205b261ecSmrg	ashift = bshift + bbits;
16305b261ecSmrg    }
16405b261ecSmrg
16505b261ecSmrg    *pixel |=  ( blue >> (16 - bbits)) << bshift;
16605b261ecSmrg    *pixel |=  (  red >> (16 - rbits)) << rshift;
16705b261ecSmrg    *pixel |=  (green >> (16 - gbits)) << gshift;
16805b261ecSmrg    *pixel |=  (alpha >> (16 - abits)) << ashift;
16905b261ecSmrg
17005b261ecSmrg    return TRUE;
17105b261ecSmrg}
17205b261ecSmrg
17305b261ecSmrgstatic Bool
17405b261ecSmrgexaGetRGBAFromPixel(CARD32	pixel,
17505b261ecSmrg		    CARD16	*red,
17605b261ecSmrg		    CARD16	*green,
17705b261ecSmrg		    CARD16	*blue,
17805b261ecSmrg		    CARD16	*alpha,
17905b261ecSmrg		    CARD32	format)
18005b261ecSmrg{
18105b261ecSmrg    int rbits, bbits, gbits, abits;
18205b261ecSmrg    int rshift, bshift, gshift, ashift;
18305b261ecSmrg
18405b261ecSmrg    if (!PICT_FORMAT_COLOR(format))
18505b261ecSmrg	return FALSE;
18605b261ecSmrg
18705b261ecSmrg    rbits = PICT_FORMAT_R(format);
18805b261ecSmrg    gbits = PICT_FORMAT_G(format);
18905b261ecSmrg    bbits = PICT_FORMAT_B(format);
19005b261ecSmrg    abits = PICT_FORMAT_A(format);
19105b261ecSmrg
19205b261ecSmrg    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
19305b261ecSmrg	bshift = 0;
19405b261ecSmrg	gshift = bbits;
19505b261ecSmrg	rshift = gshift + gbits;
19605b261ecSmrg	ashift = rshift + rbits;
19705b261ecSmrg    } else {  /* PICT_TYPE_ABGR */
19805b261ecSmrg	rshift = 0;
19905b261ecSmrg	gshift = rbits;
20005b261ecSmrg	bshift = gshift + gbits;
20105b261ecSmrg	ashift = bshift + bbits;
20205b261ecSmrg    }
20305b261ecSmrg
20405b261ecSmrg    *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
20505b261ecSmrg    while (rbits < 16) {
20605b261ecSmrg	*red |= *red >> rbits;
20705b261ecSmrg	rbits <<= 1;
20805b261ecSmrg    }
20905b261ecSmrg
21005b261ecSmrg    *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
21105b261ecSmrg    while (gbits < 16) {
21205b261ecSmrg	*green |= *green >> gbits;
21305b261ecSmrg	gbits <<= 1;
21405b261ecSmrg    }
21505b261ecSmrg
21605b261ecSmrg    *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
21705b261ecSmrg    while (bbits < 16) {
21805b261ecSmrg	*blue |= *blue >> bbits;
21905b261ecSmrg	bbits <<= 1;
22005b261ecSmrg    }
22105b261ecSmrg
22205b261ecSmrg    if (abits) {
22305b261ecSmrg	*alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
22405b261ecSmrg	while (abits < 16) {
22505b261ecSmrg	    *alpha |= *alpha >> abits;
22605b261ecSmrg	    abits <<= 1;
22705b261ecSmrg	}
22805b261ecSmrg    } else
22905b261ecSmrg	*alpha = 0xffff;
23005b261ecSmrg
23105b261ecSmrg    return TRUE;
23205b261ecSmrg}
23305b261ecSmrg
23405b261ecSmrgstatic int
23505b261ecSmrgexaTryDriverSolidFill(PicturePtr	pSrc,
23605b261ecSmrg		      PicturePtr	pDst,
23705b261ecSmrg		      INT16		xSrc,
23805b261ecSmrg		      INT16		ySrc,
23905b261ecSmrg		      INT16		xDst,
24005b261ecSmrg		      INT16		yDst,
24105b261ecSmrg		      CARD16		width,
24205b261ecSmrg		      CARD16		height)
24305b261ecSmrg{
24405b261ecSmrg    ExaScreenPriv (pDst->pDrawable->pScreen);
24505b261ecSmrg    RegionRec region;
24605b261ecSmrg    BoxPtr pbox;
24705b261ecSmrg    int nbox;
24805b261ecSmrg    int dst_off_x, dst_off_y;
24905b261ecSmrg    PixmapPtr pSrcPix, pDstPix;
25005b261ecSmrg    CARD32 pixel;
25105b261ecSmrg    CARD16 red, green, blue, alpha;
25205b261ecSmrg    ExaMigrationRec pixmaps[1];
25305b261ecSmrg
25405b261ecSmrg    xDst += pDst->pDrawable->x;
25505b261ecSmrg    yDst += pDst->pDrawable->y;
25605b261ecSmrg    xSrc += pSrc->pDrawable->x;
25705b261ecSmrg    ySrc += pSrc->pDrawable->y;
25805b261ecSmrg
25905b261ecSmrg    if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
26005b261ecSmrg				   xSrc, ySrc, 0, 0, xDst, yDst,
26105b261ecSmrg				   width, height))
26205b261ecSmrg	return 1;
26305b261ecSmrg
26405b261ecSmrg    pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
26505b261ecSmrg    pixel = exaGetPixmapFirstPixel (pSrcPix);
26605b261ecSmrg
26705b261ecSmrg    pixmaps[0].as_dst = TRUE;
26805b261ecSmrg    pixmaps[0].as_src = FALSE;
26905b261ecSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
27005b261ecSmrg    exaDoMigration(pixmaps, 1, TRUE);
27105b261ecSmrg
27205b261ecSmrg    pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
27305b261ecSmrg    if (!pDstPix) {
27405b261ecSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
27505b261ecSmrg	return 0;
27605b261ecSmrg    }
27705b261ecSmrg
27805b261ecSmrg    if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
27905b261ecSmrg			 pSrc->format))
28005b261ecSmrg    {
28105b261ecSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
28205b261ecSmrg	return -1;
28305b261ecSmrg    }
28405b261ecSmrg
28505b261ecSmrg    if (!exaGetPixelFromRGBA(&pixel, red, green, blue, alpha,
28605b261ecSmrg			pDst->format))
28705b261ecSmrg    {
28805b261ecSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
28905b261ecSmrg	return -1;
29005b261ecSmrg    }
29105b261ecSmrg
29205b261ecSmrg    if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
29305b261ecSmrg    {
29405b261ecSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
29505b261ecSmrg	return -1;
29605b261ecSmrg    }
29705b261ecSmrg
29805b261ecSmrg    nbox = REGION_NUM_RECTS(&region);
29905b261ecSmrg    pbox = REGION_RECTS(&region);
30005b261ecSmrg
30105b261ecSmrg    while (nbox--)
30205b261ecSmrg    {
30305b261ecSmrg	(*pExaScr->info->Solid) (pDstPix,
30405b261ecSmrg				 pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
30505b261ecSmrg				 pbox->x2 + dst_off_x, pbox->y2 + dst_off_y);
30605b261ecSmrg	pbox++;
30705b261ecSmrg    }
30805b261ecSmrg
30905b261ecSmrg    (*pExaScr->info->DoneSolid) (pDstPix);
31005b261ecSmrg    exaMarkSync(pDst->pDrawable->pScreen);
31105b261ecSmrg
31205b261ecSmrg    REGION_UNINIT(pDst->pDrawable->pScreen, &region);
31305b261ecSmrg    return 1;
31405b261ecSmrg}
31505b261ecSmrg
31605b261ecSmrgstatic int
31705b261ecSmrgexaTryDriverComposite(CARD8		op,
31805b261ecSmrg		      PicturePtr	pSrc,
31905b261ecSmrg		      PicturePtr	pMask,
32005b261ecSmrg		      PicturePtr	pDst,
32105b261ecSmrg		      INT16		xSrc,
32205b261ecSmrg		      INT16		ySrc,
32305b261ecSmrg		      INT16		xMask,
32405b261ecSmrg		      INT16		yMask,
32505b261ecSmrg		      INT16		xDst,
32605b261ecSmrg		      INT16		yDst,
32705b261ecSmrg		      CARD16		width,
32805b261ecSmrg		      CARD16		height)
32905b261ecSmrg{
33005b261ecSmrg    ExaScreenPriv (pDst->pDrawable->pScreen);
33105b261ecSmrg    RegionRec region;
33205b261ecSmrg    BoxPtr pbox;
33305b261ecSmrg    int nbox;
33405b261ecSmrg    int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
33505b261ecSmrg    PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
33605b261ecSmrg    struct _Pixmap scratch;
33705b261ecSmrg    ExaMigrationRec pixmaps[3];
33805b261ecSmrg
33905b261ecSmrg    pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
34005b261ecSmrg    pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
34105b261ecSmrg    if (pMask)
34205b261ecSmrg	pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
34305b261ecSmrg
34405b261ecSmrg    /* Bail if we might exceed coord limits by rendering from/to these.  We
34505b261ecSmrg     * should really be making some scratch pixmaps with offsets and coords
34605b261ecSmrg     * adjusted to deal with this, but it hasn't been done yet.
34705b261ecSmrg     */
34805b261ecSmrg    if (pSrcPix->drawable.width > pExaScr->info->maxX ||
34905b261ecSmrg	pSrcPix->drawable.height > pExaScr->info->maxY ||
35005b261ecSmrg	pDstPix->drawable.width > pExaScr->info->maxX ||
35105b261ecSmrg	pDstPix->drawable.height > pExaScr->info->maxY ||
35205b261ecSmrg	(pMask && (pMaskPix->drawable.width > pExaScr->info->maxX ||
35305b261ecSmrg		   pMaskPix->drawable.height > pExaScr->info->maxY)))
35405b261ecSmrg    {
35505b261ecSmrg	return -1;
35605b261ecSmrg    }
35705b261ecSmrg
35805b261ecSmrg    xDst += pDst->pDrawable->x;
35905b261ecSmrg    yDst += pDst->pDrawable->y;
36005b261ecSmrg
36105b261ecSmrg    if (pMask) {
36205b261ecSmrg	xMask += pMask->pDrawable->x;
36305b261ecSmrg	yMask += pMask->pDrawable->y;
36405b261ecSmrg    }
36505b261ecSmrg
36605b261ecSmrg    xSrc += pSrc->pDrawable->x;
36705b261ecSmrg    ySrc += pSrc->pDrawable->y;
36805b261ecSmrg
36905b261ecSmrg    if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
37005b261ecSmrg				   xSrc, ySrc, xMask, yMask, xDst, yDst,
37105b261ecSmrg				   width, height))
37205b261ecSmrg	return 1;
37305b261ecSmrg
37405b261ecSmrg    if (pExaScr->info->CheckComposite &&
37505b261ecSmrg	!(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
37605b261ecSmrg    {
37705b261ecSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
37805b261ecSmrg	return -1;
37905b261ecSmrg    }
38005b261ecSmrg
38105b261ecSmrg    pixmaps[0].as_dst = TRUE;
38205b261ecSmrg    pixmaps[0].as_src = exaOpReadsDestination(op);
38305b261ecSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
38405b261ecSmrg    pixmaps[1].as_dst = FALSE;
38505b261ecSmrg    pixmaps[1].as_src = TRUE;
38605b261ecSmrg    pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable);
38705b261ecSmrg    if (pMask) {
38805b261ecSmrg	pixmaps[2].as_dst = FALSE;
38905b261ecSmrg	pixmaps[2].as_src = TRUE;
39005b261ecSmrg	pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable);
39105b261ecSmrg	exaDoMigration(pixmaps, 3, TRUE);
39205b261ecSmrg    } else {
39305b261ecSmrg	exaDoMigration(pixmaps, 2, TRUE);
39405b261ecSmrg    }
39505b261ecSmrg
39605b261ecSmrg    pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
39705b261ecSmrg    if (pMask)
39805b261ecSmrg	pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
39905b261ecSmrg					  &mask_off_y);
40005b261ecSmrg    pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
40105b261ecSmrg
40205b261ecSmrg    if (!pDstPix) {
40305b261ecSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
40405b261ecSmrg	return 0;
40505b261ecSmrg    }
40605b261ecSmrg
40705b261ecSmrg    if (!pSrcPix && (!pMask || pMaskPix) && pExaScr->info->UploadToScratch) {
40805b261ecSmrg	pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
40905b261ecSmrg	if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch))
41005b261ecSmrg	    pSrcPix = &scratch;
41105b261ecSmrg    } else if (pSrcPix && pMask && !pMaskPix && pExaScr->info->UploadToScratch) {
41205b261ecSmrg	pMaskPix = exaGetDrawablePixmap (pMask->pDrawable);
41305b261ecSmrg	if ((*pExaScr->info->UploadToScratch) (pMaskPix, &scratch))
41405b261ecSmrg	    pMaskPix = &scratch;
41505b261ecSmrg    }
41605b261ecSmrg
41705b261ecSmrg    if (!pSrcPix || (pMask && !pMaskPix)) {
41805b261ecSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
41905b261ecSmrg	return 0;
42005b261ecSmrg    }
42105b261ecSmrg
42205b261ecSmrg    if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
42305b261ecSmrg					     pMaskPix, pDstPix))
42405b261ecSmrg    {
42505b261ecSmrg	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
42605b261ecSmrg	return -1;
42705b261ecSmrg    }
42805b261ecSmrg
42905b261ecSmrg    nbox = REGION_NUM_RECTS(&region);
43005b261ecSmrg    pbox = REGION_RECTS(&region);
43105b261ecSmrg
43205b261ecSmrg    xMask -= xDst;
43305b261ecSmrg    yMask -= yDst;
43405b261ecSmrg
43505b261ecSmrg    xSrc -= xDst;
43605b261ecSmrg    ySrc -= yDst;
43705b261ecSmrg
43805b261ecSmrg    while (nbox--)
43905b261ecSmrg    {
44005b261ecSmrg	(*pExaScr->info->Composite) (pDstPix,
44105b261ecSmrg				     pbox->x1 + xSrc + src_off_x,
44205b261ecSmrg				     pbox->y1 + ySrc + src_off_y,
44305b261ecSmrg				     pbox->x1 + xMask + mask_off_x,
44405b261ecSmrg				     pbox->y1 + yMask + mask_off_y,
44505b261ecSmrg				     pbox->x1 + dst_off_x,
44605b261ecSmrg				     pbox->y1 + dst_off_y,
44705b261ecSmrg				     pbox->x2 - pbox->x1,
44805b261ecSmrg				     pbox->y2 - pbox->y1);
44905b261ecSmrg	pbox++;
45005b261ecSmrg    }
45105b261ecSmrg    (*pExaScr->info->DoneComposite) (pDstPix);
45205b261ecSmrg    exaMarkSync(pDst->pDrawable->pScreen);
45305b261ecSmrg
45405b261ecSmrg    REGION_UNINIT(pDst->pDrawable->pScreen, &region);
45505b261ecSmrg    return 1;
45605b261ecSmrg}
45705b261ecSmrg
45805b261ecSmrg/**
45905b261ecSmrg * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of
46005b261ecSmrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
46105b261ecSmrg * alpha and limited 1-tmu cards.
46205b261ecSmrg *
46305b261ecSmrg * From http://anholt.livejournal.com/32058.html:
46405b261ecSmrg *
46505b261ecSmrg * The trouble is that component-alpha rendering requires two different sources
46605b261ecSmrg * for blending: one for the source value to the blender, which is the
46705b261ecSmrg * per-channel multiplication of source and mask, and one for the source alpha
46805b261ecSmrg * for multiplying with the destination channels, which is the multiplication
46905b261ecSmrg * of the source channels by the mask alpha. So the equation for Over is:
47005b261ecSmrg *
47105b261ecSmrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
47205b261ecSmrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
47305b261ecSmrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
47405b261ecSmrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
47505b261ecSmrg *
47605b261ecSmrg * But we can do some simpler operations, right? How about PictOpOutReverse,
47705b261ecSmrg * which has a source factor of 0 and dest factor of (1 - source alpha). We
47805b261ecSmrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
47905b261ecSmrg * blenders pretty easily. So we can do a component-alpha OutReverse, which
48005b261ecSmrg * gets us:
48105b261ecSmrg *
48205b261ecSmrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
48305b261ecSmrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
48405b261ecSmrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
48505b261ecSmrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
48605b261ecSmrg *
48705b261ecSmrg * OK. And if an op doesn't use the source alpha value for the destination
48805b261ecSmrg * factor, then we can do the channel multiplication in the texture blenders
48905b261ecSmrg * to get the source value, and ignore the source alpha that we wouldn't use.
49005b261ecSmrg * We've supported this in the Radeon driver for a long time. An example would
49105b261ecSmrg * be PictOpAdd, which does:
49205b261ecSmrg *
49305b261ecSmrg * dst.A = src.A * mask.A + dst.A
49405b261ecSmrg * dst.R = src.R * mask.R + dst.R
49505b261ecSmrg * dst.G = src.G * mask.G + dst.G
49605b261ecSmrg * dst.B = src.B * mask.B + dst.B
49705b261ecSmrg *
49805b261ecSmrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
49905b261ecSmrg * after it, we get:
50005b261ecSmrg *
50105b261ecSmrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
50205b261ecSmrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
50305b261ecSmrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
50405b261ecSmrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
50505b261ecSmrg */
50605b261ecSmrg
50705b261ecSmrgstatic int
50805b261ecSmrgexaTryMagicTwoPassCompositeHelper(CARD8 op,
50905b261ecSmrg				  PicturePtr pSrc,
51005b261ecSmrg				  PicturePtr pMask,
51105b261ecSmrg				  PicturePtr pDst,
51205b261ecSmrg				  INT16 xSrc,
51305b261ecSmrg				  INT16 ySrc,
51405b261ecSmrg				  INT16 xMask,
51505b261ecSmrg				  INT16 yMask,
51605b261ecSmrg				  INT16 xDst,
51705b261ecSmrg				  INT16 yDst,
51805b261ecSmrg				  CARD16 width,
51905b261ecSmrg				  CARD16 height)
52005b261ecSmrg{
52105b261ecSmrg    ExaScreenPriv (pDst->pDrawable->pScreen);
52205b261ecSmrg    DrawablePtr pDstDraw = pDst->pDrawable;
52305b261ecSmrg    PixmapPtr pDstPixmap = exaGetDrawablePixmap(pDstDraw);
52405b261ecSmrg    int xoff, yoff;
52505b261ecSmrg
52605b261ecSmrg    assert(op == PictOpOver);
52705b261ecSmrg
52805b261ecSmrg    if (pExaScr->info->CheckComposite &&
52905b261ecSmrg	(!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
53005b261ecSmrg					   pDst) ||
53105b261ecSmrg	 !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))
53205b261ecSmrg    {
53305b261ecSmrg	return -1;
53405b261ecSmrg    }
53505b261ecSmrg
53605b261ecSmrg    /* Now, we think we should be able to accelerate this operation. First,
53705b261ecSmrg     * composite the destination to be the destination times the source alpha
53805b261ecSmrg     * factors.
53905b261ecSmrg     */
54005b261ecSmrg    exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
54105b261ecSmrg		 xDst, yDst, width, height);
54205b261ecSmrg
54305b261ecSmrg    exaGetDrawableDeltas(pDstDraw, pDstPixmap, &xoff, &yoff);
54405b261ecSmrg    xoff += pDstDraw->x;
54505b261ecSmrg    yoff += pDstDraw->y;
54605b261ecSmrg    exaPixmapDirty(pDstPixmap, xDst + xoff, yDst + yoff, xDst + xoff + width,
54705b261ecSmrg		   yDst + yoff + height);
54805b261ecSmrg
54905b261ecSmrg    /* Then, add in the source value times the destination alpha factors (1.0).
55005b261ecSmrg     */
55105b261ecSmrg    exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
55205b261ecSmrg		 xDst, yDst, width, height);
55305b261ecSmrg
55405b261ecSmrg    return 1;
55505b261ecSmrg}
55605b261ecSmrg
55705b261ecSmrgvoid
55805b261ecSmrgexaComposite(CARD8	op,
55905b261ecSmrg	     PicturePtr pSrc,
56005b261ecSmrg	     PicturePtr pMask,
56105b261ecSmrg	     PicturePtr pDst,
56205b261ecSmrg	     INT16	xSrc,
56305b261ecSmrg	     INT16	ySrc,
56405b261ecSmrg	     INT16	xMask,
56505b261ecSmrg	     INT16	yMask,
56605b261ecSmrg	     INT16	xDst,
56705b261ecSmrg	     INT16	yDst,
56805b261ecSmrg	     CARD16	width,
56905b261ecSmrg	     CARD16	height)
57005b261ecSmrg{
57105b261ecSmrg    ExaScreenPriv (pDst->pDrawable->pScreen);
57205b261ecSmrg    int ret = -1;
57305b261ecSmrg    Bool saveSrcRepeat = pSrc->repeat;
57405b261ecSmrg    Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
57505b261ecSmrg    ExaMigrationRec pixmaps[3];
57605b261ecSmrg    int npixmaps = 1;
57705b261ecSmrg    PixmapPtr pSrcPixmap = NULL;
57805b261ecSmrg
57905b261ecSmrg    pixmaps[0].as_dst = TRUE;
58005b261ecSmrg    pixmaps[0].as_src = exaOpReadsDestination(op);
58105b261ecSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
58205b261ecSmrg
58305b261ecSmrg    if (pSrc->pDrawable) {
58405b261ecSmrg	pSrcPixmap = exaGetDrawablePixmap (pSrc->pDrawable);
58505b261ecSmrg	pixmaps[npixmaps].as_dst = FALSE;
58605b261ecSmrg	pixmaps[npixmaps].as_src = TRUE;
58705b261ecSmrg	pixmaps[npixmaps].pPix = pSrcPixmap;
58805b261ecSmrg	npixmaps++;
58905b261ecSmrg    }
59005b261ecSmrg
59105b261ecSmrg    if (pMask && pMask->pDrawable) {
59205b261ecSmrg	pixmaps[npixmaps].as_dst = FALSE;
59305b261ecSmrg	pixmaps[npixmaps].as_src = TRUE;
59405b261ecSmrg	pixmaps[npixmaps].pPix = exaGetDrawablePixmap (pMask->pDrawable);
59505b261ecSmrg	npixmaps++;
59605b261ecSmrg    }
59705b261ecSmrg
59805b261ecSmrg    /* We currently don't support acceleration of gradients, or other pictures
59905b261ecSmrg     * with a NULL pDrawable.
60005b261ecSmrg     */
60105b261ecSmrg    if (pExaScr->swappedOut ||
60205b261ecSmrg	pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL))
60305b261ecSmrg    {
60405b261ecSmrg	goto fallback;
60505b261ecSmrg    }
60605b261ecSmrg
60705b261ecSmrg    /* Remove repeat in source if useless */
60805b261ecSmrg    if (pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
60905b261ecSmrg	(xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
61005b261ecSmrg	(ySrc + height) <= pSrc->pDrawable->height)
61105b261ecSmrg	    pSrc->repeat = 0;
61205b261ecSmrg
61305b261ecSmrg    if (!pMask)
61405b261ecSmrg    {
61505b261ecSmrg      if ((op == PictOpSrc &&
61605b261ecSmrg	   ((pSrc->format == pDst->format) ||
61705b261ecSmrg	    (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) ||
61805b261ecSmrg	    (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) ||
61905b261ecSmrg	  (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap &&
62005b261ecSmrg	   pSrc->format == pDst->format &&
62105b261ecSmrg	   (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8)))
62205b261ecSmrg	{
62305b261ecSmrg	    if (pSrc->pDrawable->width == 1 &&
62405b261ecSmrg		pSrc->pDrawable->height == 1 &&
62505b261ecSmrg		pSrc->repeat)
62605b261ecSmrg	    {
62705b261ecSmrg		ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
62805b261ecSmrg					    width, height);
62905b261ecSmrg		if (ret == 1)
63005b261ecSmrg		    goto done;
63105b261ecSmrg	    }
63205b261ecSmrg	    else if (pSrcPixmap && !pSrc->repeat && !pSrc->transform)
63305b261ecSmrg	    {
63405b261ecSmrg		RegionRec	region;
63505b261ecSmrg
63605b261ecSmrg		xDst += pDst->pDrawable->x;
63705b261ecSmrg		yDst += pDst->pDrawable->y;
63805b261ecSmrg		xSrc += pSrc->pDrawable->x;
63905b261ecSmrg		ySrc += pSrc->pDrawable->y;
64005b261ecSmrg
64105b261ecSmrg		if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
64205b261ecSmrg					       xSrc, ySrc, xMask, yMask, xDst,
64305b261ecSmrg					       yDst, width, height))
64405b261ecSmrg		    goto done;
64505b261ecSmrg
64605b261ecSmrg
64705b261ecSmrg		exaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, NULL,
64805b261ecSmrg			     REGION_RECTS(&region), REGION_NUM_RECTS(&region),
64905b261ecSmrg			     xSrc - xDst, ySrc - yDst,
65005b261ecSmrg			     FALSE, FALSE, 0, NULL);
65105b261ecSmrg		REGION_UNINIT(pDst->pDrawable->pScreen, &region);
65205b261ecSmrg		goto done;
65305b261ecSmrg	    }
65405b261ecSmrg	    else if (pSrcPixmap && !pSrc->transform &&
65505b261ecSmrg		     pSrc->repeatType == RepeatNormal)
65605b261ecSmrg	    {
65705b261ecSmrg		RegionRec region;
65805b261ecSmrg		DDXPointRec srcOrg;
65905b261ecSmrg
66005b261ecSmrg		/* Let's see if the driver can do the repeat in one go */
66105b261ecSmrg		if (pExaScr->info->PrepareComposite && !pSrc->alphaMap &&
66205b261ecSmrg		    !pDst->alphaMap)
66305b261ecSmrg		{
66405b261ecSmrg		    ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc,
66505b261ecSmrg						ySrc, xMask, yMask, xDst, yDst,
66605b261ecSmrg						width, height);
66705b261ecSmrg		    if (ret == 1)
66805b261ecSmrg			goto done;
66905b261ecSmrg		}
67005b261ecSmrg
67105b261ecSmrg		/* Now see if we can use exaFillRegionTiled() */
67205b261ecSmrg		xDst += pDst->pDrawable->x;
67305b261ecSmrg		yDst += pDst->pDrawable->y;
67405b261ecSmrg		xSrc += pSrc->pDrawable->x;
67505b261ecSmrg		ySrc += pSrc->pDrawable->y;
67605b261ecSmrg
67705b261ecSmrg		if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst, xSrc,
67805b261ecSmrg					       ySrc, xMask, yMask, xDst, yDst,
67905b261ecSmrg					       width, height))
68005b261ecSmrg		    goto done;
68105b261ecSmrg
68205b261ecSmrg		srcOrg.x = (xSrc - xDst) % pSrcPixmap->drawable.width;
68305b261ecSmrg		srcOrg.y = (ySrc - yDst) % pSrcPixmap->drawable.height;
68405b261ecSmrg
68505b261ecSmrg		ret = exaFillRegionTiled(pDst->pDrawable, &region, pSrcPixmap,
68605b261ecSmrg					 &srcOrg, FB_ALLONES, GXcopy);
68705b261ecSmrg
68805b261ecSmrg		REGION_UNINIT(pDst->pDrawable->pScreen, &region);
68905b261ecSmrg
69005b261ecSmrg		if (ret)
69105b261ecSmrg		    goto done;
69205b261ecSmrg	    }
69305b261ecSmrg	}
69405b261ecSmrg    }
69505b261ecSmrg
69605b261ecSmrg    /* Remove repeat in mask if useless */
69705b261ecSmrg    if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 &&
69805b261ecSmrg	(xMask + width) <= pMask->pDrawable->width && yMask >= 0 &&
69905b261ecSmrg	(yMask + height) <= pMask->pDrawable->height)
70005b261ecSmrg	    pMask->repeat = 0;
70105b261ecSmrg
70205b261ecSmrg    if (pExaScr->info->PrepareComposite &&
70305b261ecSmrg	(!pSrc->repeat || pSrc->repeatType == RepeatNormal) &&
70405b261ecSmrg	(!pMask || !pMask->repeat || pMask->repeatType == RepeatNormal) &&
70505b261ecSmrg	!pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
70605b261ecSmrg    {
70705b261ecSmrg	Bool isSrcSolid;
70805b261ecSmrg
70905b261ecSmrg	ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
71005b261ecSmrg				    yMask, xDst, yDst, width, height);
71105b261ecSmrg	if (ret == 1)
71205b261ecSmrg	    goto done;
71305b261ecSmrg
71405b261ecSmrg	/* For generic masks and solid src pictures, mach64 can do Over in two
71505b261ecSmrg	 * passes, similar to the component-alpha case.
71605b261ecSmrg	 */
71705b261ecSmrg	isSrcSolid = pSrc->pDrawable->width == 1 &&
71805b261ecSmrg		     pSrc->pDrawable->height == 1 &&
71905b261ecSmrg		     pSrc->repeat;
72005b261ecSmrg
72105b261ecSmrg	/* If we couldn't do the Composite in a single pass, and it was a
72205b261ecSmrg	 * component-alpha Over, see if we can do it in two passes with
72305b261ecSmrg	 * an OutReverse and then an Add.
72405b261ecSmrg	 */
72505b261ecSmrg	if (ret == -1 && op == PictOpOver && pMask &&
72605b261ecSmrg	    (pMask->componentAlpha || isSrcSolid)) {
72705b261ecSmrg	    ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst,
72805b261ecSmrg						    xSrc, ySrc,
72905b261ecSmrg						    xMask, yMask, xDst, yDst,
73005b261ecSmrg						    width, height);
73105b261ecSmrg	    if (ret == 1)
73205b261ecSmrg		goto done;
73305b261ecSmrg	}
73405b261ecSmrg    }
73505b261ecSmrg
73605b261ecSmrgfallback:
73705b261ecSmrg#if DEBUG_TRACE_FALL
73805b261ecSmrg    exaPrintCompositeFallback (op, pSrc, pMask, pDst);
73905b261ecSmrg#endif
74005b261ecSmrg
74105b261ecSmrg    exaDoMigration(pixmaps, npixmaps, FALSE);
74205b261ecSmrg    ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
74305b261ecSmrg		      xMask, yMask, xDst, yDst, width, height);
74405b261ecSmrg
74505b261ecSmrgdone:
74605b261ecSmrg    pSrc->repeat = saveSrcRepeat;
74705b261ecSmrg    if (pMask)
74805b261ecSmrg	pMask->repeat = saveMaskRepeat;
74905b261ecSmrg}
75005b261ecSmrg#endif
75105b261ecSmrg
75205b261ecSmrg/**
75305b261ecSmrg * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead
75405b261ecSmrg * of PolyFillRect to initialize the pixmap after creating it, to prevent
75505b261ecSmrg * the pixmap from being migrated.
75605b261ecSmrg *
75705b261ecSmrg * See the comments about exaTrapezoids.
75805b261ecSmrg */
75905b261ecSmrgstatic PicturePtr
76005b261ecSmrgexaCreateAlphaPicture (ScreenPtr     pScreen,
76105b261ecSmrg                       PicturePtr    pDst,
76205b261ecSmrg                       PictFormatPtr pPictFormat,
76305b261ecSmrg                       CARD16        width,
76405b261ecSmrg                       CARD16        height)
76505b261ecSmrg{
76605b261ecSmrg    PixmapPtr	    pPixmap;
76705b261ecSmrg    PicturePtr	    pPicture;
76805b261ecSmrg    GCPtr	    pGC;
76905b261ecSmrg    int		    error;
77005b261ecSmrg    xRectangle	    rect;
77105b261ecSmrg
77205b261ecSmrg    if (width > 32767 || height > 32767)
77305b261ecSmrg	return 0;
77405b261ecSmrg
77505b261ecSmrg    if (!pPictFormat)
77605b261ecSmrg    {
77705b261ecSmrg	if (pDst->polyEdge == PolyEdgeSharp)
77805b261ecSmrg	    pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
77905b261ecSmrg	else
78005b261ecSmrg	    pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
78105b261ecSmrg	if (!pPictFormat)
78205b261ecSmrg	    return 0;
78305b261ecSmrg    }
78405b261ecSmrg
78505b261ecSmrg    pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
78605b261ecSmrg					pPictFormat->depth);
78705b261ecSmrg    if (!pPixmap)
78805b261ecSmrg	return 0;
78905b261ecSmrg    pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
79005b261ecSmrg    if (!pGC)
79105b261ecSmrg    {
79205b261ecSmrg	(*pScreen->DestroyPixmap) (pPixmap);
79305b261ecSmrg	return 0;
79405b261ecSmrg    }
79505b261ecSmrg    ValidateGC (&pPixmap->drawable, pGC);
79605b261ecSmrg    rect.x = 0;
79705b261ecSmrg    rect.y = 0;
79805b261ecSmrg    rect.width = width;
79905b261ecSmrg    rect.height = height;
80005b261ecSmrg    ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect);
80105b261ecSmrg    exaPixmapDirty (pPixmap, 0, 0, width, height);
80205b261ecSmrg    FreeScratchGC (pGC);
80305b261ecSmrg    pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat,
80405b261ecSmrg			      0, 0, serverClient, &error);
80505b261ecSmrg    (*pScreen->DestroyPixmap) (pPixmap);
80605b261ecSmrg    return pPicture;
80705b261ecSmrg}
80805b261ecSmrg
80905b261ecSmrg/**
81005b261ecSmrg * exaTrapezoids is essentially a copy of miTrapezoids that uses
81105b261ecSmrg * exaCreateAlphaPicture instead of miCreateAlphaPicture.
81205b261ecSmrg *
81305b261ecSmrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect
81405b261ecSmrg * to initialize the contents after creating the pixmap, which
81505b261ecSmrg * causes the pixmap to be moved in for acceleration. The subsequent
81605b261ecSmrg * call to RasterizeTrapezoid won't be accelerated however, which
81705b261ecSmrg * forces the pixmap to be moved out again.
81805b261ecSmrg *
81905b261ecSmrg * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
82005b261ecSmrg * to initialize the contents.
82105b261ecSmrg */
82205b261ecSmrgvoid
82305b261ecSmrgexaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
82405b261ecSmrg               PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
82505b261ecSmrg               int ntrap, xTrapezoid *traps)
82605b261ecSmrg{
82705b261ecSmrg    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
82805b261ecSmrg    PictureScreenPtr    ps = GetPictureScreen(pScreen);
82905b261ecSmrg
83005b261ecSmrg    /*
83105b261ecSmrg     * Check for solid alpha add
83205b261ecSmrg     */
83305b261ecSmrg    if (op == PictOpAdd && miIsSolidAlpha (pSrc))
83405b261ecSmrg    {
83505b261ecSmrg	for (; ntrap; ntrap--, traps++)
83605b261ecSmrg	    (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
83705b261ecSmrg    }
83805b261ecSmrg    else if (maskFormat)
83905b261ecSmrg    {
84005b261ecSmrg	PicturePtr	pPicture;
84105b261ecSmrg	BoxRec		bounds;
84205b261ecSmrg	INT16		xDst, yDst;
84305b261ecSmrg	INT16		xRel, yRel;
84405b261ecSmrg
84505b261ecSmrg	xDst = traps[0].left.p1.x >> 16;
84605b261ecSmrg	yDst = traps[0].left.p1.y >> 16;
84705b261ecSmrg
84805b261ecSmrg	miTrapezoidBounds (ntrap, traps, &bounds);
84905b261ecSmrg	if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
85005b261ecSmrg	    return;
85105b261ecSmrg	pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat,
85205b261ecSmrg	                                  bounds.x2 - bounds.x1,
85305b261ecSmrg	                                  bounds.y2 - bounds.y1);
85405b261ecSmrg	if (!pPicture)
85505b261ecSmrg	    return;
85605b261ecSmrg	for (; ntrap; ntrap--, traps++)
85705b261ecSmrg	    (*ps->RasterizeTrapezoid) (pPicture, traps,
85805b261ecSmrg				       -bounds.x1, -bounds.y1);
85905b261ecSmrg	xRel = bounds.x1 + xSrc - xDst;
86005b261ecSmrg	yRel = bounds.y1 + ySrc - yDst;
86105b261ecSmrg	CompositePicture (op, pSrc, pPicture, pDst,
86205b261ecSmrg			  xRel, yRel, 0, 0, bounds.x1, bounds.y1,
86305b261ecSmrg			  bounds.x2 - bounds.x1,
86405b261ecSmrg			  bounds.y2 - bounds.y1);
86505b261ecSmrg	FreePicture (pPicture, 0);
86605b261ecSmrg    }
86705b261ecSmrg    else
86805b261ecSmrg    {
86905b261ecSmrg	if (pDst->polyEdge == PolyEdgeSharp)
87005b261ecSmrg	    maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
87105b261ecSmrg	else
87205b261ecSmrg	    maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
87305b261ecSmrg	for (; ntrap; ntrap--, traps++)
87405b261ecSmrg	    exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
87505b261ecSmrg    }
87605b261ecSmrg}
87705b261ecSmrg
87805b261ecSmrg#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
87905b261ecSmrg
88005b261ecSmrg/**
88105b261ecSmrg * exaRasterizeTrapezoid is just a wrapper around the software implementation.
88205b261ecSmrg *
88305b261ecSmrg * The trapezoid specification is basically too hard to be done in hardware (at
88405b261ecSmrg * the very least, without programmability), so we just do the appropriate
88505b261ecSmrg * Prepare/FinishAccess for it before using fbtrap.c.
88605b261ecSmrg */
88705b261ecSmrgvoid
88805b261ecSmrgexaRasterizeTrapezoid (PicturePtr pPicture, xTrapezoid  *trap,
88905b261ecSmrg		       int x_off, int y_off)
89005b261ecSmrg{
89105b261ecSmrg    DrawablePtr pDraw = pPicture->pDrawable;
89205b261ecSmrg    ExaMigrationRec pixmaps[1];
89305b261ecSmrg    int xoff, yoff;
89405b261ecSmrg
89505b261ecSmrg    pixmaps[0].as_dst = TRUE;
89605b261ecSmrg    pixmaps[0].as_src = TRUE;
89705b261ecSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
89805b261ecSmrg    exaDoMigration(pixmaps, 1, FALSE);
89905b261ecSmrg
90005b261ecSmrg    exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
90105b261ecSmrg    fbRasterizeTrapezoid(pPicture, trap, x_off, y_off);
90205b261ecSmrg    exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff);
90305b261ecSmrg    exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff,
90405b261ecSmrg		   pDraw->x + xoff + pDraw->width,
90505b261ecSmrg		   pDraw->y + yoff + pDraw->height);
90605b261ecSmrg    exaFinishAccess(pDraw, EXA_PREPARE_DEST);
90705b261ecSmrg}
90805b261ecSmrg
90905b261ecSmrg/**
91005b261ecSmrg * exaAddTriangles does migration and syncing before dumping down to the
91105b261ecSmrg * software implementation.
91205b261ecSmrg */
91305b261ecSmrgvoid
91405b261ecSmrgexaAddTriangles (PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntri,
91505b261ecSmrg		 xTriangle *tris)
91605b261ecSmrg{
91705b261ecSmrg    DrawablePtr pDraw = pPicture->pDrawable;
91805b261ecSmrg    ExaMigrationRec pixmaps[1];
91905b261ecSmrg    int xoff, yoff;
92005b261ecSmrg
92105b261ecSmrg    pixmaps[0].as_dst = TRUE;
92205b261ecSmrg    pixmaps[0].as_src = TRUE;
92305b261ecSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDraw);
92405b261ecSmrg    exaDoMigration(pixmaps, 1, FALSE);
92505b261ecSmrg
92605b261ecSmrg    exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
92705b261ecSmrg    fbAddTriangles(pPicture, x_off, y_off, ntri, tris);
92805b261ecSmrg    exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff);
92905b261ecSmrg    exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff,
93005b261ecSmrg		   pDraw->x + xoff + pDraw->width,
93105b261ecSmrg		   pDraw->y + yoff + pDraw->height);
93205b261ecSmrg    exaFinishAccess(pDraw, EXA_PREPARE_DEST);
93305b261ecSmrg}
93405b261ecSmrg
93505b261ecSmrg/**
93605b261ecSmrg * Returns TRUE if the glyphs in the lists intersect.  Only checks based on
93705b261ecSmrg * bounding box, which appears to be good enough to catch most cases at least.
93805b261ecSmrg */
93905b261ecSmrgstatic Bool
94005b261ecSmrgexaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs)
94105b261ecSmrg{
94205b261ecSmrg    int x1, x2, y1, y2;
94305b261ecSmrg    int n;
94405b261ecSmrg    GlyphPtr glyph;
94505b261ecSmrg    int x, y;
94605b261ecSmrg    BoxRec extents;
94705b261ecSmrg    Bool first = TRUE;
94805b261ecSmrg
94905b261ecSmrg    x = 0;
95005b261ecSmrg    y = 0;
95105b261ecSmrg    while (nlist--) {
95205b261ecSmrg	x += list->xOff;
95305b261ecSmrg	y += list->yOff;
95405b261ecSmrg	n = list->len;
95505b261ecSmrg	list++;
95605b261ecSmrg	while (n--) {
95705b261ecSmrg	    glyph = *glyphs++;
95805b261ecSmrg
95905b261ecSmrg	    if (glyph->info.width == 0 || glyph->info.height == 0) {
96005b261ecSmrg		x += glyph->info.xOff;
96105b261ecSmrg		y += glyph->info.yOff;
96205b261ecSmrg		continue;
96305b261ecSmrg	    }
96405b261ecSmrg
96505b261ecSmrg	    x1 = x - glyph->info.x;
96605b261ecSmrg	    if (x1 < MINSHORT)
96705b261ecSmrg		x1 = MINSHORT;
96805b261ecSmrg	    y1 = y - glyph->info.y;
96905b261ecSmrg	    if (y1 < MINSHORT)
97005b261ecSmrg		y1 = MINSHORT;
97105b261ecSmrg	    x2 = x1 + glyph->info.width;
97205b261ecSmrg	    if (x2 > MAXSHORT)
97305b261ecSmrg		x2 = MAXSHORT;
97405b261ecSmrg	    y2 = y1 + glyph->info.height;
97505b261ecSmrg	    if (y2 > MAXSHORT)
97605b261ecSmrg		y2 = MAXSHORT;
97705b261ecSmrg
97805b261ecSmrg	    if (first) {
97905b261ecSmrg		extents.x1 = x1;
98005b261ecSmrg		extents.y1 = y1;
98105b261ecSmrg		extents.x2 = x2;
98205b261ecSmrg		extents.y2 = y2;
98305b261ecSmrg		first = FALSE;
98405b261ecSmrg	    } else {
98505b261ecSmrg		if (x1 < extents.x2 && x2 > extents.x1 &&
98605b261ecSmrg		    y1 < extents.y2 && y2 > extents.y1)
98705b261ecSmrg		{
98805b261ecSmrg		    return TRUE;
98905b261ecSmrg		}
99005b261ecSmrg
99105b261ecSmrg		if (x1 < extents.x1)
99205b261ecSmrg		    extents.x1 = x1;
99305b261ecSmrg		if (x2 > extents.x2)
99405b261ecSmrg		    extents.x2 = x2;
99505b261ecSmrg		if (y1 < extents.y1)
99605b261ecSmrg		    extents.y1 = y1;
99705b261ecSmrg		if (y2 > extents.y2)
99805b261ecSmrg		    extents.y2 = y2;
99905b261ecSmrg	    }
100005b261ecSmrg	    x += glyph->info.xOff;
100105b261ecSmrg	    y += glyph->info.yOff;
100205b261ecSmrg	}
100305b261ecSmrg    }
100405b261ecSmrg
100505b261ecSmrg    return FALSE;
100605b261ecSmrg}
100705b261ecSmrg
100805b261ecSmrg/* exaGlyphs is a slight variation on miGlyphs, to support acceleration.  The
100905b261ecSmrg * issue is that miGlyphs' use of ModifyPixmapHeader makes it impossible to
101005b261ecSmrg * migrate these pixmaps.  So, instead we create a pixmap at the beginning of
101105b261ecSmrg * the loop and upload each glyph into the pixmap before compositing.
101205b261ecSmrg */
101305b261ecSmrgvoid
101405b261ecSmrgexaGlyphs (CARD8	op,
101505b261ecSmrg	  PicturePtr	pSrc,
101605b261ecSmrg	  PicturePtr	pDst,
101705b261ecSmrg	  PictFormatPtr	maskFormat,
101805b261ecSmrg	  INT16		xSrc,
101905b261ecSmrg	  INT16		ySrc,
102005b261ecSmrg	  int		nlist,
102105b261ecSmrg	  GlyphListPtr	list,
102205b261ecSmrg	  GlyphPtr	*glyphs)
102305b261ecSmrg{
102405b261ecSmrg    ExaScreenPriv (pDst->pDrawable->pScreen);
102505b261ecSmrg    PixmapPtr	pPixmap = NULL;
102605b261ecSmrg    PicturePtr	pPicture;
102705b261ecSmrg    PixmapPtr   pMaskPixmap = NULL;
102805b261ecSmrg    PixmapPtr   pDstPixmap = exaGetDrawablePixmap(pDst->pDrawable);
102905b261ecSmrg    PicturePtr  pMask;
103005b261ecSmrg    ScreenPtr   pScreen = pDst->pDrawable->pScreen;
103105b261ecSmrg    int		width = 0, height = 0;
103205b261ecSmrg    int		x, y, x1, y1, xoff, yoff;
103305b261ecSmrg    int		xDst = list->xOff, yDst = list->yOff;
103405b261ecSmrg    int		n;
103505b261ecSmrg    int		error;
103605b261ecSmrg    BoxRec	extents;
103705b261ecSmrg    CARD32	component_alpha;
103805b261ecSmrg
103905b261ecSmrg    /* If we have a mask format but it's the same as all the glyphs and
104005b261ecSmrg     * the glyphs don't intersect, we can avoid accumulating the glyphs in the
104105b261ecSmrg     * temporary picture.
104205b261ecSmrg     */
104305b261ecSmrg    if (maskFormat != NULL) {
104405b261ecSmrg	Bool sameFormat = TRUE;
104505b261ecSmrg	int i;
104605b261ecSmrg
104705b261ecSmrg	for (i = 0; i < nlist; i++) {
104805b261ecSmrg	    if (maskFormat->format != list[i].format->format) {
104905b261ecSmrg		sameFormat = FALSE;
105005b261ecSmrg		break;
105105b261ecSmrg	    }
105205b261ecSmrg	}
105305b261ecSmrg	if (sameFormat) {
105405b261ecSmrg	    if (!exaGlyphsIntersect(nlist, list, glyphs)) {
105505b261ecSmrg		maskFormat = NULL;
105605b261ecSmrg	    }
105705b261ecSmrg	}
105805b261ecSmrg    }
105905b261ecSmrg
106005b261ecSmrg    /* If the driver doesn't support accelerated composite, there's no point in
106105b261ecSmrg     * going to this extra work.  Assume that any driver that supports Composite
106205b261ecSmrg     * will be able to support component alpha using the two-pass helper.
106305b261ecSmrg     */
106405b261ecSmrg    if (!pExaScr->info->PrepareComposite)
106505b261ecSmrg    {
106605b261ecSmrg	miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
106705b261ecSmrg	return;
106805b261ecSmrg    }
106905b261ecSmrg
107005b261ecSmrg    if (maskFormat)
107105b261ecSmrg    {
107205b261ecSmrg	GCPtr	    pGC;
107305b261ecSmrg	xRectangle  rect;
107405b261ecSmrg
107505b261ecSmrg	miGlyphExtents (nlist, list, glyphs, &extents);
107605b261ecSmrg
107705b261ecSmrg	extents.x1 = max(extents.x1, 0);
107805b261ecSmrg	extents.y1 = max(extents.y1, 0);
107905b261ecSmrg	extents.x2 = min(extents.x2, pDst->pDrawable->width);
108005b261ecSmrg	extents.y2 = min(extents.y2, pDst->pDrawable->height);
108105b261ecSmrg
108205b261ecSmrg	if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
108305b261ecSmrg	    return;
108405b261ecSmrg	width = extents.x2 - extents.x1;
108505b261ecSmrg	height = extents.y2 - extents.y1;
108605b261ecSmrg	pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
108705b261ecSmrg						maskFormat->depth);
108805b261ecSmrg	if (!pMaskPixmap)
108905b261ecSmrg	    return;
109005b261ecSmrg	component_alpha = NeedsComponent(maskFormat->format);
109105b261ecSmrg	pMask = CreatePicture (0, &pMaskPixmap->drawable,
109205b261ecSmrg			       maskFormat, CPComponentAlpha, &component_alpha,
109305b261ecSmrg			       serverClient, &error);
109405b261ecSmrg	if (!pMask)
109505b261ecSmrg	{
109605b261ecSmrg	    (*pScreen->DestroyPixmap) (pMaskPixmap);
109705b261ecSmrg	    return;
109805b261ecSmrg	}
109905b261ecSmrg	ValidatePicture(pMask);
110005b261ecSmrg	pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
110105b261ecSmrg	ValidateGC (&pMaskPixmap->drawable, pGC);
110205b261ecSmrg	rect.x = 0;
110305b261ecSmrg	rect.y = 0;
110405b261ecSmrg	rect.width = width;
110505b261ecSmrg	rect.height = height;
110605b261ecSmrg	(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
110705b261ecSmrg	exaPixmapDirty(pMaskPixmap, 0, 0, width, height);
110805b261ecSmrg	FreeScratchGC (pGC);
110905b261ecSmrg	x = -extents.x1;
111005b261ecSmrg	y = -extents.y1;
111105b261ecSmrg    }
111205b261ecSmrg    else
111305b261ecSmrg    {
111405b261ecSmrg	pMask = pDst;
111505b261ecSmrg	x = 0;
111605b261ecSmrg	y = 0;
111705b261ecSmrg    }
111805b261ecSmrg
111905b261ecSmrg    exaGetDrawableDeltas(pDst->pDrawable, pDstPixmap, &xoff, &yoff);
112005b261ecSmrg
112105b261ecSmrg    while (nlist--)
112205b261ecSmrg    {
112305b261ecSmrg	GCPtr pGC = NULL;
112405b261ecSmrg	int maxwidth = 0, maxheight = 0, i;
112505b261ecSmrg	ExaMigrationRec pixmaps[1];
112605b261ecSmrg	PixmapPtr pScratchPixmap = NULL;
112705b261ecSmrg
112805b261ecSmrg	x += list->xOff;
112905b261ecSmrg	y += list->yOff;
113005b261ecSmrg	n = list->len;
113105b261ecSmrg	for (i = 0; i < n; i++) {
113205b261ecSmrg	    if (glyphs[i]->info.width > maxwidth)
113305b261ecSmrg		maxwidth = glyphs[i]->info.width;
113405b261ecSmrg	    if (glyphs[i]->info.height > maxheight)
113505b261ecSmrg		maxheight = glyphs[i]->info.height;
113605b261ecSmrg	}
113705b261ecSmrg	if (maxwidth == 0 || maxheight == 0) {
113805b261ecSmrg	    while (n--)
113905b261ecSmrg	    {
114005b261ecSmrg		GlyphPtr glyph;
114105b261ecSmrg
114205b261ecSmrg		glyph = *glyphs++;
114305b261ecSmrg		x += glyph->info.xOff;
114405b261ecSmrg		y += glyph->info.yOff;
114505b261ecSmrg	    }
114605b261ecSmrg	    list++;
114705b261ecSmrg	    continue;
114805b261ecSmrg	}
114905b261ecSmrg
115005b261ecSmrg	/* Create the (real) temporary pixmap to store the current glyph in */
115105b261ecSmrg	pPixmap = (*pScreen->CreatePixmap) (pScreen, maxwidth, maxheight,
115205b261ecSmrg					    list->format->depth);
115305b261ecSmrg	if (!pPixmap)
115405b261ecSmrg	    return;
115505b261ecSmrg
115605b261ecSmrg	/* Create a temporary picture to wrap the temporary pixmap, so it can be
115705b261ecSmrg	 * used as a source for Composite.
115805b261ecSmrg	 */
115905b261ecSmrg	component_alpha = NeedsComponent(list->format->format);
116005b261ecSmrg	pPicture = CreatePicture (0, &pPixmap->drawable, list->format,
116105b261ecSmrg				  CPComponentAlpha, &component_alpha,
116205b261ecSmrg				  serverClient, &error);
116305b261ecSmrg	if (!pPicture) {
116405b261ecSmrg	    (*pScreen->DestroyPixmap) (pPixmap);
116505b261ecSmrg	    return;
116605b261ecSmrg	}
116705b261ecSmrg	ValidatePicture(pPicture);
116805b261ecSmrg
116905b261ecSmrg	/* Give the temporary pixmap an initial kick towards the screen, so
117005b261ecSmrg	 * it'll stick there.
117105b261ecSmrg	 */
117205b261ecSmrg	pixmaps[0].as_dst = TRUE;
117305b261ecSmrg	pixmaps[0].as_src = TRUE;
117405b261ecSmrg	pixmaps[0].pPix = pPixmap;
117505b261ecSmrg	exaDoMigration (pixmaps, 1, pExaScr->info->PrepareComposite != NULL);
117605b261ecSmrg
117705b261ecSmrg	while (n--)
117805b261ecSmrg	{
117905b261ecSmrg	    GlyphPtr glyph = *glyphs++;
118005b261ecSmrg	    pointer glyphdata = (pointer) (glyph + 1);
118105b261ecSmrg	    DrawablePtr pCmpDrw = (maskFormat ? pMask : pDst)->pDrawable;
118205b261ecSmrg
118305b261ecSmrg	    x1 = x - glyph->info.x;
118405b261ecSmrg	    y1 = y - glyph->info.y;
118505b261ecSmrg
118605b261ecSmrg	    if (x1 >= pCmpDrw->width || y1 >= pCmpDrw->height ||
118705b261ecSmrg		glyph->info.width == 0 || glyph->info.height == 0 ||
118805b261ecSmrg		(x1 + glyph->info.width) <= 0 || (y1 + glyph->info.height) <= 0)
118905b261ecSmrg		goto nextglyph;
119005b261ecSmrg
119105b261ecSmrg	    (*pScreen->ModifyPixmapHeader) (pScratchPixmap,
119205b261ecSmrg					    glyph->info.width,
119305b261ecSmrg					    glyph->info.height,
119405b261ecSmrg					    0, 0, -1, glyphdata);
119505b261ecSmrg
119605b261ecSmrg	    /* Copy the glyph data into the proper pixmap instead of a fake.
119705b261ecSmrg	     * First we try to use UploadToScreen, if we can, then we fall back
119805b261ecSmrg	     * to a plain exaCopyArea in case of failure.
119905b261ecSmrg	     */
120005b261ecSmrg	    if (pExaScr->info->UploadToScreen &&
120105b261ecSmrg		exaPixmapIsOffscreen(pPixmap) &&
120205b261ecSmrg		(*pExaScr->info->UploadToScreen) (pPixmap, 0, 0,
120305b261ecSmrg					glyph->info.width,
120405b261ecSmrg					glyph->info.height,
120505b261ecSmrg					glyphdata,
120605b261ecSmrg					PixmapBytePad(glyph->info.width,
120705b261ecSmrg						      list->format->depth)))
120805b261ecSmrg	    {
120905b261ecSmrg		exaMarkSync (pScreen);
121005b261ecSmrg	    } else {
121105b261ecSmrg		/* Set up the scratch pixmap/GC for doing a CopyArea. */
121205b261ecSmrg		if (pScratchPixmap == NULL) {
121305b261ecSmrg		    /* Get a scratch pixmap to wrap the original glyph data */
121405b261ecSmrg		    pScratchPixmap = GetScratchPixmapHeader (pScreen,
121505b261ecSmrg							glyph->info.width,
121605b261ecSmrg							glyph->info.height,
121705b261ecSmrg							list->format->depth,
121805b261ecSmrg							list->format->depth,
121905b261ecSmrg							-1, glyphdata);
122005b261ecSmrg		    if (!pScratchPixmap) {
122105b261ecSmrg			FreePicture(pPicture, 0);
122205b261ecSmrg			(*pScreen->DestroyPixmap) (pPixmap);
122305b261ecSmrg			return;
122405b261ecSmrg		    }
122505b261ecSmrg
122605b261ecSmrg		    /* Get a scratch GC with which to copy the glyph data from
122705b261ecSmrg		     * scratch to temporary
122805b261ecSmrg		     */
122905b261ecSmrg		    pGC = GetScratchGC (list->format->depth, pScreen);
123005b261ecSmrg		    ValidateGC (&pPixmap->drawable, pGC);
123105b261ecSmrg		} else {
123205b261ecSmrg		    (*pScreen->ModifyPixmapHeader) (pScratchPixmap,
123305b261ecSmrg						    glyph->info.width,
123405b261ecSmrg						    glyph->info.height,
123505b261ecSmrg						    0, 0, -1, glyphdata);
123605b261ecSmrg		    pScratchPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
123705b261ecSmrg		}
123805b261ecSmrg
123905b261ecSmrg		exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC,
124005b261ecSmrg			     0, 0, glyph->info.width, glyph->info.height, 0, 0);
124105b261ecSmrg	    }
124205b261ecSmrg
124305b261ecSmrg	    exaPixmapDirty (pPixmap, 0, 0,
124405b261ecSmrg			    glyph->info.width, glyph->info.height);
124505b261ecSmrg
124605b261ecSmrg	    if (maskFormat)
124705b261ecSmrg	    {
124805b261ecSmrg		exaComposite (PictOpAdd, pPicture, NULL, pMask, 0, 0, 0, 0,
124905b261ecSmrg			      x1, y1, glyph->info.width, glyph->info.height);
125005b261ecSmrg		exaPixmapDirty(pMaskPixmap, x1, y1, x1 + glyph->info.width,
125105b261ecSmrg			       y1 + glyph->info.height);
125205b261ecSmrg	    }
125305b261ecSmrg	    else
125405b261ecSmrg	    {
125505b261ecSmrg		exaComposite (op, pSrc, pPicture, pDst,
125605b261ecSmrg			      xSrc + x1 - xDst, ySrc + y1 - yDst,
125705b261ecSmrg			      0, 0, x1, y1, glyph->info.width,
125805b261ecSmrg			      glyph->info.height);
125905b261ecSmrg		x1 += pDst->pDrawable->x + xoff;
126005b261ecSmrg		y1 += pDst->pDrawable->y + yoff;
126105b261ecSmrg		exaPixmapDirty(pDstPixmap, x1, y1, x1 + glyph->info.width,
126205b261ecSmrg			       y1 + glyph->info.height);
126305b261ecSmrg	    }
126405b261ecSmrgnextglyph:
126505b261ecSmrg	    x += glyph->info.xOff;
126605b261ecSmrg	    y += glyph->info.yOff;
126705b261ecSmrg	}
126805b261ecSmrg	list++;
126905b261ecSmrg	if (pGC != NULL)
127005b261ecSmrg	    FreeScratchGC (pGC);
127105b261ecSmrg	FreePicture ((pointer) pPicture, 0);
127205b261ecSmrg	(*pScreen->DestroyPixmap) (pPixmap);
127305b261ecSmrg	if (pScratchPixmap != NULL)
127405b261ecSmrg	    FreeScratchPixmapHeader (pScratchPixmap);
127505b261ecSmrg    }
127605b261ecSmrg    if (maskFormat)
127705b261ecSmrg    {
127805b261ecSmrg	x = extents.x1;
127905b261ecSmrg	y = extents.y1;
128005b261ecSmrg	exaComposite (op, pSrc, pMask, pDst, xSrc + x - xDst, ySrc + y - yDst,
128105b261ecSmrg		      0, 0, x, y, width, height);
128205b261ecSmrg	FreePicture ((pointer) pMask, (XID) 0);
128305b261ecSmrg	(*pScreen->DestroyPixmap) (pMaskPixmap);
128405b261ecSmrg    }
128505b261ecSmrg}
1286