exa_accel.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 * Authors:
2505b261ecSmrg *    Eric Anholt <eric@anholt.net>
2605b261ecSmrg *    Michel D�nzer <michel@tungstengraphics.com>
2705b261ecSmrg *
2805b261ecSmrg */
2905b261ecSmrg
3005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3105b261ecSmrg#include <dix-config.h>
3205b261ecSmrg#endif
3305b261ecSmrg#include "exa_priv.h"
3405b261ecSmrg#include <X11/fonts/fontstruct.h>
3505b261ecSmrg#include "dixfontstr.h"
3605b261ecSmrg#include "exa.h"
3705b261ecSmrg#include "cw.h"
3805b261ecSmrg
3905b261ecSmrgstatic void
4005b261ecSmrgexaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
4105b261ecSmrg	     DDXPointPtr ppt, int *pwidth, int fSorted)
4205b261ecSmrg{
4305b261ecSmrg    ScreenPtr	    pScreen = pDrawable->pScreen;
4405b261ecSmrg    ExaScreenPriv (pScreen);
4505b261ecSmrg    RegionPtr	    pClip = fbGetCompositeClip(pGC);
4605b261ecSmrg    PixmapPtr	    pPixmap;
4705b261ecSmrg    BoxPtr	    pextent, pbox;
4805b261ecSmrg    int		    nbox;
4905b261ecSmrg    int		    extentX1, extentX2, extentY1, extentY2;
5005b261ecSmrg    int		    fullX1, fullX2, fullY1;
5105b261ecSmrg    int		    partX1, partX2;
5205b261ecSmrg    int		    off_x, off_y;
5305b261ecSmrg    ExaMigrationRec pixmaps[1];
5405b261ecSmrg
5505b261ecSmrg    pixmaps[0].as_dst = TRUE;
5605b261ecSmrg    pixmaps[0].as_src = FALSE;
5705b261ecSmrg    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
5805b261ecSmrg
5905b261ecSmrg    if (pExaScr->swappedOut ||
6005b261ecSmrg	pGC->fillStyle != FillSolid ||
6105b261ecSmrg	pPixmap->drawable.width > pExaScr->info->maxX ||
6205b261ecSmrg	pPixmap->drawable.height > pExaScr->info->maxY)
6305b261ecSmrg    {
6405b261ecSmrg	exaDoMigration (pixmaps, 1, FALSE);
6505b261ecSmrg	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
6605b261ecSmrg	return;
6705b261ecSmrg    } else {
6805b261ecSmrg	exaDoMigration (pixmaps, 1, TRUE);
6905b261ecSmrg    }
7005b261ecSmrg
7105b261ecSmrg    if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
7205b261ecSmrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
7305b261ecSmrg					 pGC->alu,
7405b261ecSmrg					 pGC->planemask,
7505b261ecSmrg					 pGC->fgPixel))
7605b261ecSmrg    {
7705b261ecSmrg	exaDoMigration (pixmaps, 1, FALSE);
7805b261ecSmrg	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
7905b261ecSmrg	return;
8005b261ecSmrg    }
8105b261ecSmrg
8205b261ecSmrg    pextent = REGION_EXTENTS(pGC->pScreen, pClip);
8305b261ecSmrg    extentX1 = pextent->x1;
8405b261ecSmrg    extentY1 = pextent->y1;
8505b261ecSmrg    extentX2 = pextent->x2;
8605b261ecSmrg    extentY2 = pextent->y2;
8705b261ecSmrg    while (n--)
8805b261ecSmrg    {
8905b261ecSmrg	fullX1 = ppt->x;
9005b261ecSmrg	fullY1 = ppt->y;
9105b261ecSmrg	fullX2 = fullX1 + (int) *pwidth;
9205b261ecSmrg	ppt++;
9305b261ecSmrg	pwidth++;
9405b261ecSmrg
9505b261ecSmrg	if (fullY1 < extentY1 || extentY2 <= fullY1)
9605b261ecSmrg	    continue;
9705b261ecSmrg
9805b261ecSmrg	if (fullX1 < extentX1)
9905b261ecSmrg	    fullX1 = extentX1;
10005b261ecSmrg
10105b261ecSmrg	if (fullX2 > extentX2)
10205b261ecSmrg	    fullX2 = extentX2;
10305b261ecSmrg
10405b261ecSmrg	if (fullX1 >= fullX2)
10505b261ecSmrg	    continue;
10605b261ecSmrg
10705b261ecSmrg	nbox = REGION_NUM_RECTS (pClip);
10805b261ecSmrg	if (nbox == 1)
10905b261ecSmrg	{
11005b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
11105b261ecSmrg				     fullX1 + off_x, fullY1 + off_y,
11205b261ecSmrg				     fullX2 + off_x, fullY1 + 1 + off_y);
11305b261ecSmrg	}
11405b261ecSmrg	else
11505b261ecSmrg	{
11605b261ecSmrg	    pbox = REGION_RECTS(pClip);
11705b261ecSmrg	    while(nbox--)
11805b261ecSmrg	    {
11905b261ecSmrg		if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
12005b261ecSmrg		{
12105b261ecSmrg		    partX1 = pbox->x1;
12205b261ecSmrg		    if (partX1 < fullX1)
12305b261ecSmrg			partX1 = fullX1;
12405b261ecSmrg		    partX2 = pbox->x2;
12505b261ecSmrg		    if (partX2 > fullX2)
12605b261ecSmrg			partX2 = fullX2;
12705b261ecSmrg		    if (partX2 > partX1) {
12805b261ecSmrg			(*pExaScr->info->Solid) (pPixmap,
12905b261ecSmrg						 partX1 + off_x, fullY1 + off_y,
13005b261ecSmrg						 partX2 + off_x, fullY1 + 1 + off_y);
13105b261ecSmrg		    }
13205b261ecSmrg		}
13305b261ecSmrg		pbox++;
13405b261ecSmrg	    }
13505b261ecSmrg	}
13605b261ecSmrg    }
13705b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
13805b261ecSmrg    exaMarkSync(pScreen);
13905b261ecSmrg}
14005b261ecSmrg
14105b261ecSmrgstatic void
14205b261ecSmrgexaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
14305b261ecSmrg	     int w, int h, int leftPad, int format, char *bits)
14405b261ecSmrg{
14505b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
14605b261ecSmrg    PixmapPtr pPix;
14705b261ecSmrg    ExaMigrationRec pixmaps[1];
14805b261ecSmrg    RegionPtr pClip;
14905b261ecSmrg    BoxPtr pbox;
15005b261ecSmrg    int nbox;
15105b261ecSmrg    int xoff, yoff;
15205b261ecSmrg    int src_stride, bpp = pDrawable->bitsPerPixel;
15305b261ecSmrg
15405b261ecSmrg    pixmaps[0].as_dst = TRUE;
15505b261ecSmrg    pixmaps[0].as_src = FALSE;
15605b261ecSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
15705b261ecSmrg
15805b261ecSmrg    /* Don't bother with under 8bpp, XYPixmaps. */
15905b261ecSmrg    if (format != ZPixmap || bpp < 8)
16005b261ecSmrg	goto migrate_and_fallback;
16105b261ecSmrg
16205b261ecSmrg    /* Only accelerate copies: no rop or planemask. */
16305b261ecSmrg    if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
16405b261ecSmrg	goto migrate_and_fallback;
16505b261ecSmrg
16605b261ecSmrg    if (pExaScr->swappedOut)
16705b261ecSmrg	goto fallback;
16805b261ecSmrg
16905b261ecSmrg    exaDoMigration (pixmaps, 1, TRUE);
17005b261ecSmrg
17105b261ecSmrg    if (pExaScr->info->UploadToScreen == NULL)
17205b261ecSmrg	goto fallback;
17305b261ecSmrg
17405b261ecSmrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
17505b261ecSmrg
17605b261ecSmrg    if (pPix == NULL)
17705b261ecSmrg	goto fallback;
17805b261ecSmrg
17905b261ecSmrg    x += pDrawable->x;
18005b261ecSmrg    y += pDrawable->y;
18105b261ecSmrg
18205b261ecSmrg    pClip = fbGetCompositeClip(pGC);
18305b261ecSmrg    src_stride = PixmapBytePad(w, pDrawable->depth);
18405b261ecSmrg    for (nbox = REGION_NUM_RECTS(pClip),
18505b261ecSmrg	 pbox = REGION_RECTS(pClip);
18605b261ecSmrg	 nbox--;
18705b261ecSmrg	 pbox++)
18805b261ecSmrg    {
18905b261ecSmrg	int x1 = x;
19005b261ecSmrg	int y1 = y;
19105b261ecSmrg	int x2 = x + w;
19205b261ecSmrg	int y2 = y + h;
19305b261ecSmrg	char *src;
19405b261ecSmrg	Bool ok;
19505b261ecSmrg
19605b261ecSmrg	if (x1 < pbox->x1)
19705b261ecSmrg	    x1 = pbox->x1;
19805b261ecSmrg	if (y1 < pbox->y1)
19905b261ecSmrg	    y1 = pbox->y1;
20005b261ecSmrg	if (x2 > pbox->x2)
20105b261ecSmrg	    x2 = pbox->x2;
20205b261ecSmrg	if (y2 > pbox->y2)
20305b261ecSmrg	    y2 = pbox->y2;
20405b261ecSmrg	if (x1 >= x2 || y1 >= y2)
20505b261ecSmrg	    continue;
20605b261ecSmrg
20705b261ecSmrg	src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
20805b261ecSmrg	ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
20905b261ecSmrg					   x2 - x1, y2 - y1, src, src_stride);
21005b261ecSmrg	/* If we fail to accelerate the upload, fall back to using unaccelerated
21105b261ecSmrg	 * fb calls.
21205b261ecSmrg	 */
21305b261ecSmrg	if (!ok) {
21405b261ecSmrg	    FbStip *dst;
21505b261ecSmrg	    FbStride dst_stride;
21605b261ecSmrg	    int	dstBpp;
21705b261ecSmrg	    int	dstXoff, dstYoff;
21805b261ecSmrg
21905b261ecSmrg	    exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
22005b261ecSmrg
22105b261ecSmrg	    fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp,
22205b261ecSmrg			      dstXoff, dstYoff);
22305b261ecSmrg
22405b261ecSmrg	    fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)),
22505b261ecSmrg		      src_stride / sizeof(FbStip),
22605b261ecSmrg		      (x1 - x) * dstBpp,
22705b261ecSmrg		      dst + (y1 + dstYoff) * dst_stride,
22805b261ecSmrg		      dst_stride,
22905b261ecSmrg		      (x1 + dstXoff) * dstBpp,
23005b261ecSmrg		      (x2 - x1) * dstBpp,
23105b261ecSmrg		      y2 - y1,
23205b261ecSmrg		      GXcopy, FB_ALLONES, dstBpp);
23305b261ecSmrg
23405b261ecSmrg	    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
23505b261ecSmrg	}
23605b261ecSmrg
23705b261ecSmrg	exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
23805b261ecSmrg    }
23905b261ecSmrg
24005b261ecSmrg    return;
24105b261ecSmrg
24205b261ecSmrgmigrate_and_fallback:
24305b261ecSmrg    exaDoMigration (pixmaps, 1, FALSE);
24405b261ecSmrg
24505b261ecSmrgfallback:
24605b261ecSmrg    ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
24705b261ecSmrg}
24805b261ecSmrg
24905b261ecSmrgstatic Bool inline
25005b261ecSmrgexaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
25105b261ecSmrg		   GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
25205b261ecSmrg{
25305b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
25405b261ecSmrg    PixmapPtr pSrcPixmap, pDstPixmap;
25505b261ecSmrg    int src_off_x, src_off_y, dst_off_x, dst_off_y;
25605b261ecSmrg    int dirsetup;
25705b261ecSmrg
25805b261ecSmrg    /* Need to get both pixmaps to call the driver routines */
25905b261ecSmrg    pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
26005b261ecSmrg    pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
26105b261ecSmrg    if (!pSrcPixmap || !pDstPixmap)
26205b261ecSmrg	return FALSE;
26305b261ecSmrg
26405b261ecSmrg    /*
26505b261ecSmrg     * Now the case of a chip that only supports xdir = ydir = 1 or
26605b261ecSmrg     * xdir = ydir = -1, but we have xdir != ydir.
26705b261ecSmrg     */
26805b261ecSmrg    dirsetup = 0;	/* No direction set up yet. */
26905b261ecSmrg    for (; nbox; pbox++, nbox--) {
27005b261ecSmrg	if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
27105b261ecSmrg	    /* Do a xdir = ydir = -1 blit instead. */
27205b261ecSmrg	    if (dirsetup != -1) {
27305b261ecSmrg		if (dirsetup != 0)
27405b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
27505b261ecSmrg		dirsetup = -1;
27605b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
27705b261ecSmrg						   pDstPixmap,
27805b261ecSmrg						   -1, -1,
27905b261ecSmrg						   pGC ? pGC->alu : GXcopy,
28005b261ecSmrg						   pGC ? pGC->planemask :
28105b261ecSmrg							 FB_ALLONES))
28205b261ecSmrg		    return FALSE;
28305b261ecSmrg	    }
28405b261ecSmrg	    (*pExaScr->info->Copy)(pDstPixmap,
28505b261ecSmrg				   src_off_x + pbox->x1 + dx,
28605b261ecSmrg				   src_off_y + pbox->y1 + dy,
28705b261ecSmrg				   dst_off_x + pbox->x1,
28805b261ecSmrg				   dst_off_y + pbox->y1,
28905b261ecSmrg				   pbox->x2 - pbox->x1,
29005b261ecSmrg				   pbox->y2 - pbox->y1);
29105b261ecSmrg	} else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
29205b261ecSmrg	    /* Do a xdir = ydir = 1 blit instead. */
29305b261ecSmrg	    if (dirsetup != 1) {
29405b261ecSmrg		if (dirsetup != 0)
29505b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
29605b261ecSmrg		dirsetup = 1;
29705b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
29805b261ecSmrg						   pDstPixmap,
29905b261ecSmrg						   1, 1,
30005b261ecSmrg						   pGC ? pGC->alu : GXcopy,
30105b261ecSmrg						   pGC ? pGC->planemask :
30205b261ecSmrg							 FB_ALLONES))
30305b261ecSmrg		    return FALSE;
30405b261ecSmrg	    }
30505b261ecSmrg	    (*pExaScr->info->Copy)(pDstPixmap,
30605b261ecSmrg				   src_off_x + pbox->x1 + dx,
30705b261ecSmrg				   src_off_y + pbox->y1 + dy,
30805b261ecSmrg				   dst_off_x + pbox->x1,
30905b261ecSmrg				   dst_off_y + pbox->y1,
31005b261ecSmrg				   pbox->x2 - pbox->x1,
31105b261ecSmrg				   pbox->y2 - pbox->y1);
31205b261ecSmrg	} else if (dx >= 0) {
31305b261ecSmrg	    /*
31405b261ecSmrg	     * xdir = 1, ydir = -1.
31505b261ecSmrg	     * Perform line-by-line xdir = ydir = 1 blits, going up.
31605b261ecSmrg	     */
31705b261ecSmrg	    int i;
31805b261ecSmrg	    if (dirsetup != 1) {
31905b261ecSmrg		if (dirsetup != 0)
32005b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
32105b261ecSmrg		dirsetup = 1;
32205b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
32305b261ecSmrg						   pDstPixmap,
32405b261ecSmrg						   1, 1,
32505b261ecSmrg						   pGC ? pGC->alu : GXcopy,
32605b261ecSmrg						   pGC ? pGC->planemask :
32705b261ecSmrg							 FB_ALLONES))
32805b261ecSmrg		    return FALSE;
32905b261ecSmrg	    }
33005b261ecSmrg	    for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
33105b261ecSmrg		(*pExaScr->info->Copy)(pDstPixmap,
33205b261ecSmrg				       src_off_x + pbox->x1 + dx,
33305b261ecSmrg				       src_off_y + pbox->y1 + dy + i,
33405b261ecSmrg				       dst_off_x + pbox->x1,
33505b261ecSmrg				       dst_off_y + pbox->y1 + i,
33605b261ecSmrg				       pbox->x2 - pbox->x1, 1);
33705b261ecSmrg	} else {
33805b261ecSmrg	    /*
33905b261ecSmrg	     * xdir = -1, ydir = 1.
34005b261ecSmrg	     * Perform line-by-line xdir = ydir = -1 blits, going down.
34105b261ecSmrg	     */
34205b261ecSmrg	    int i;
34305b261ecSmrg	    if (dirsetup != -1) {
34405b261ecSmrg		if (dirsetup != 0)
34505b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
34605b261ecSmrg		dirsetup = -1;
34705b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
34805b261ecSmrg						   pDstPixmap,
34905b261ecSmrg						   -1, -1,
35005b261ecSmrg						   pGC ? pGC->alu : GXcopy,
35105b261ecSmrg						   pGC ? pGC->planemask :
35205b261ecSmrg							 FB_ALLONES))
35305b261ecSmrg		    return FALSE;
35405b261ecSmrg	    }
35505b261ecSmrg	    for (i = 0; i < pbox->y2 - pbox->y1; i++)
35605b261ecSmrg		(*pExaScr->info->Copy)(pDstPixmap,
35705b261ecSmrg				       src_off_x + pbox->x1 + dx,
35805b261ecSmrg				       src_off_y + pbox->y1 + dy + i,
35905b261ecSmrg				       dst_off_x + pbox->x1,
36005b261ecSmrg				       dst_off_y + pbox->y1 + i,
36105b261ecSmrg				       pbox->x2 - pbox->x1, 1);
36205b261ecSmrg	}
36305b261ecSmrg	exaPixmapDirty(pDstPixmap, dst_off_x + pbox->x1, dst_off_y + pbox->y1,
36405b261ecSmrg		       dst_off_x + pbox->x2, dst_off_y + pbox->y2);
36505b261ecSmrg    }
36605b261ecSmrg    if (dirsetup != 0)
36705b261ecSmrg	pExaScr->info->DoneCopy(pDstPixmap);
36805b261ecSmrg    exaMarkSync(pDstDrawable->pScreen);
36905b261ecSmrg    return TRUE;
37005b261ecSmrg}
37105b261ecSmrg
37205b261ecSmrgvoid
37305b261ecSmrgexaCopyNtoN (DrawablePtr    pSrcDrawable,
37405b261ecSmrg	     DrawablePtr    pDstDrawable,
37505b261ecSmrg	     GCPtr	    pGC,
37605b261ecSmrg	     BoxPtr	    pbox,
37705b261ecSmrg	     int	    nbox,
37805b261ecSmrg	     int	    dx,
37905b261ecSmrg	     int	    dy,
38005b261ecSmrg	     Bool	    reverse,
38105b261ecSmrg	     Bool	    upsidedown,
38205b261ecSmrg	     Pixel	    bitplane,
38305b261ecSmrg	     void	    *closure)
38405b261ecSmrg{
38505b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
38605b261ecSmrg    PixmapPtr pSrcPixmap, pDstPixmap;
38705b261ecSmrg    int	    src_off_x, src_off_y;
38805b261ecSmrg    int	    dst_off_x, dst_off_y;
38905b261ecSmrg    ExaMigrationRec pixmaps[2];
39005b261ecSmrg    Bool fallback = FALSE;
39105b261ecSmrg
39205b261ecSmrg    pixmaps[0].as_dst = TRUE;
39305b261ecSmrg    pixmaps[0].as_src = FALSE;
39405b261ecSmrg    pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
39505b261ecSmrg    pixmaps[1].as_dst = FALSE;
39605b261ecSmrg    pixmaps[1].as_src = TRUE;
39705b261ecSmrg    pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
39805b261ecSmrg
39905b261ecSmrg    /* Respect maxX/maxY in a trivial way: don't set up drawing when we might
40005b261ecSmrg     * violate the limits.  The proper solution would be a temporary pixmap
40105b261ecSmrg     * adjusted so that the drawing happened within limits.
40205b261ecSmrg     */
40305b261ecSmrg    if (pSrcPixmap->drawable.width > pExaScr->info->maxX ||
40405b261ecSmrg	pSrcPixmap->drawable.height > pExaScr->info->maxY ||
40505b261ecSmrg	pDstPixmap->drawable.width > pExaScr->info->maxX ||
40605b261ecSmrg	pDstPixmap->drawable.height > pExaScr->info->maxY)
40705b261ecSmrg    {
40805b261ecSmrg	fallback = TRUE;
40905b261ecSmrg    } else {
41005b261ecSmrg	exaDoMigration (pixmaps, 2, TRUE);
41105b261ecSmrg    }
41205b261ecSmrg
41305b261ecSmrg    /* Mixed directions must be handled specially if the card is lame */
41405b261ecSmrg    if (!fallback && (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
41505b261ecSmrg	reverse != upsidedown) {
41605b261ecSmrg	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
41705b261ecSmrg			       dx, dy))
41805b261ecSmrg	    return;
41905b261ecSmrg	fallback = TRUE;
42005b261ecSmrg    }
42105b261ecSmrg
42205b261ecSmrg    pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
42305b261ecSmrg    pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
42405b261ecSmrg
42505b261ecSmrg    exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
42605b261ecSmrg    exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
42705b261ecSmrg
42805b261ecSmrg    if (fallback || !exaPixmapIsOffscreen(pSrcPixmap) ||
42905b261ecSmrg	!exaPixmapIsOffscreen(pDstPixmap) ||
43005b261ecSmrg	!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
43105b261ecSmrg					upsidedown ? -1 : 1,
43205b261ecSmrg					pGC ? pGC->alu : GXcopy,
43305b261ecSmrg					pGC ? pGC->planemask : FB_ALLONES)) {
43405b261ecSmrg	fallback = TRUE;
43505b261ecSmrg	EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
43605b261ecSmrg		      exaDrawableLocation(pSrcDrawable),
43705b261ecSmrg		      exaDrawableLocation(pDstDrawable)));
43805b261ecSmrg	exaDoMigration (pixmaps, 2, FALSE);
43905b261ecSmrg	exaPrepareAccess (pDstDrawable, EXA_PREPARE_DEST);
44005b261ecSmrg	exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
44105b261ecSmrg	fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
44205b261ecSmrg		    pbox, nbox, dx, dy, reverse, upsidedown,
44305b261ecSmrg		    bitplane, closure);
44405b261ecSmrg	exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
44505b261ecSmrg	exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
44605b261ecSmrg    }
44705b261ecSmrg
44805b261ecSmrg    while (nbox--)
44905b261ecSmrg    {
45005b261ecSmrg	if (!fallback)
45105b261ecSmrg	    (*pExaScr->info->Copy) (pDstPixmap,
45205b261ecSmrg				    pbox->x1 + dx + src_off_x,
45305b261ecSmrg				    pbox->y1 + dy + src_off_y,
45405b261ecSmrg				    pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
45505b261ecSmrg				    pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
45605b261ecSmrg	exaPixmapDirty (pDstPixmap, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
45705b261ecSmrg			pbox->x2  + dst_off_x, pbox->y2 + dst_off_y);
45805b261ecSmrg	pbox++;
45905b261ecSmrg    }
46005b261ecSmrg
46105b261ecSmrg    if (fallback)
46205b261ecSmrg	return;
46305b261ecSmrg
46405b261ecSmrg    (*pExaScr->info->DoneCopy) (pDstPixmap);
46505b261ecSmrg    exaMarkSync (pDstDrawable->pScreen);
46605b261ecSmrg}
46705b261ecSmrg
46805b261ecSmrgRegionPtr
46905b261ecSmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
47005b261ecSmrg	    int srcx, int srcy, int width, int height, int dstx, int dsty)
47105b261ecSmrg{
47205b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
47305b261ecSmrg
47405b261ecSmrg    if (pExaScr->swappedOut) {
47505b261ecSmrg        return  ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
47605b261ecSmrg                                 srcx, srcy, width, height, dstx, dsty);
47705b261ecSmrg    }
47805b261ecSmrg
47905b261ecSmrg    return  fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
48005b261ecSmrg                      srcx, srcy, width, height,
48105b261ecSmrg                      dstx, dsty, exaCopyNtoN, 0, NULL);
48205b261ecSmrg}
48305b261ecSmrg
48405b261ecSmrgstatic void
48505b261ecSmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
48605b261ecSmrg	     DDXPointPtr ppt)
48705b261ecSmrg{
48805b261ecSmrg    int i;
48905b261ecSmrg    xRectangle *prect;
49005b261ecSmrg
49105b261ecSmrg    /* If we can't reuse the current GC as is, don't bother accelerating the
49205b261ecSmrg     * points.
49305b261ecSmrg     */
49405b261ecSmrg    if (pGC->fillStyle != FillSolid) {
49505b261ecSmrg	ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
49605b261ecSmrg	return;
49705b261ecSmrg    }
49805b261ecSmrg
49905b261ecSmrg    prect = ALLOCATE_LOCAL(sizeof(xRectangle) * npt);
50005b261ecSmrg    for (i = 0; i < npt; i++) {
50105b261ecSmrg	prect[i].x = ppt[i].x;
50205b261ecSmrg	prect[i].y = ppt[i].y;
50305b261ecSmrg	if (i > 0 && mode == CoordModePrevious) {
50405b261ecSmrg	    prect[i].x += prect[i - 1].x;
50505b261ecSmrg	    prect[i].y += prect[i - 1].y;
50605b261ecSmrg	}
50705b261ecSmrg	prect[i].width = 1;
50805b261ecSmrg	prect[i].height = 1;
50905b261ecSmrg    }
51005b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
51105b261ecSmrg    DEALLOCATE_LOCAL(prect);
51205b261ecSmrg}
51305b261ecSmrg
51405b261ecSmrg/**
51505b261ecSmrg * exaPolylines() checks if it can accelerate the lines as a group of
51605b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
51705b261ecSmrg * acceleration if so.
51805b261ecSmrg */
51905b261ecSmrgstatic void
52005b261ecSmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
52105b261ecSmrg	     DDXPointPtr ppt)
52205b261ecSmrg{
52305b261ecSmrg    xRectangle *prect;
52405b261ecSmrg    int x1, x2, y1, y2;
52505b261ecSmrg    int i;
52605b261ecSmrg
52705b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
52805b261ecSmrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
52905b261ecSmrg	pGC->fillStyle != FillSolid) {
53005b261ecSmrg	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
53105b261ecSmrg	return;
53205b261ecSmrg    }
53305b261ecSmrg
53405b261ecSmrg    prect = ALLOCATE_LOCAL(sizeof(xRectangle) * (npt - 1));
53505b261ecSmrg    x1 = ppt[0].x;
53605b261ecSmrg    y1 = ppt[0].y;
53705b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
53805b261ecSmrg    for (i = 0; i < npt - 1; i++) {
53905b261ecSmrg	if (mode == CoordModePrevious) {
54005b261ecSmrg	    x2 = x1 + ppt[i + 1].x;
54105b261ecSmrg	    y2 = y1 + ppt[i + 1].y;
54205b261ecSmrg	} else {
54305b261ecSmrg	    x2 = ppt[i + 1].x;
54405b261ecSmrg	    y2 = ppt[i + 1].y;
54505b261ecSmrg	}
54605b261ecSmrg
54705b261ecSmrg	if (x1 != x2 && y1 != y2) {
54805b261ecSmrg	    DEALLOCATE_LOCAL(prect);
54905b261ecSmrg	    ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
55005b261ecSmrg	    return;
55105b261ecSmrg	}
55205b261ecSmrg
55305b261ecSmrg	if (x1 < x2) {
55405b261ecSmrg	    prect[i].x = x1;
55505b261ecSmrg	    prect[i].width = x2 - x1 + 1;
55605b261ecSmrg	} else {
55705b261ecSmrg	    prect[i].x = x2;
55805b261ecSmrg	    prect[i].width = x1 - x2 + 1;
55905b261ecSmrg	}
56005b261ecSmrg	if (y1 < y2) {
56105b261ecSmrg	    prect[i].y = y1;
56205b261ecSmrg	    prect[i].height = y2 - y1 + 1;
56305b261ecSmrg	} else {
56405b261ecSmrg	    prect[i].y = y2;
56505b261ecSmrg	    prect[i].height = y1 - y2 + 1;
56605b261ecSmrg	}
56705b261ecSmrg
56805b261ecSmrg	x1 = x2;
56905b261ecSmrg	y1 = y2;
57005b261ecSmrg    }
57105b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
57205b261ecSmrg    DEALLOCATE_LOCAL(prect);
57305b261ecSmrg}
57405b261ecSmrg
57505b261ecSmrg/**
57605b261ecSmrg * exaPolySegment() checks if it can accelerate the lines as a group of
57705b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
57805b261ecSmrg * acceleration if so.
57905b261ecSmrg */
58005b261ecSmrgstatic void
58105b261ecSmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
58205b261ecSmrg		xSegment *pSeg)
58305b261ecSmrg{
58405b261ecSmrg    xRectangle *prect;
58505b261ecSmrg    int i;
58605b261ecSmrg
58705b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
58805b261ecSmrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
58905b261ecSmrg	pGC->fillStyle != FillSolid)
59005b261ecSmrg    {
59105b261ecSmrg	ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
59205b261ecSmrg	return;
59305b261ecSmrg    }
59405b261ecSmrg
59505b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
59605b261ecSmrg    for (i = 0; i < nseg; i++) {
59705b261ecSmrg	if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
59805b261ecSmrg	    ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
59905b261ecSmrg	    return;
60005b261ecSmrg	}
60105b261ecSmrg    }
60205b261ecSmrg
60305b261ecSmrg    prect = ALLOCATE_LOCAL(sizeof(xRectangle) * nseg);
60405b261ecSmrg    for (i = 0; i < nseg; i++) {
60505b261ecSmrg	if (pSeg[i].x1 < pSeg[i].x2) {
60605b261ecSmrg	    prect[i].x = pSeg[i].x1;
60705b261ecSmrg	    prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
60805b261ecSmrg	} else {
60905b261ecSmrg	    prect[i].x = pSeg[i].x2;
61005b261ecSmrg	    prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
61105b261ecSmrg	}
61205b261ecSmrg	if (pSeg[i].y1 < pSeg[i].y2) {
61305b261ecSmrg	    prect[i].y = pSeg[i].y1;
61405b261ecSmrg	    prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
61505b261ecSmrg	} else {
61605b261ecSmrg	    prect[i].y = pSeg[i].y2;
61705b261ecSmrg	    prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
61805b261ecSmrg	}
61905b261ecSmrg    }
62005b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
62105b261ecSmrg    DEALLOCATE_LOCAL(prect);
62205b261ecSmrg}
62305b261ecSmrg
62405b261ecSmrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
62505b261ecSmrg				Pixel pixel, CARD32 planemask, CARD32 alu);
62605b261ecSmrg
62705b261ecSmrgstatic void
62805b261ecSmrgexaPolyFillRect(DrawablePtr pDrawable,
62905b261ecSmrg		GCPtr	    pGC,
63005b261ecSmrg		int	    nrect,
63105b261ecSmrg		xRectangle  *prect)
63205b261ecSmrg{
63305b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
63405b261ecSmrg    RegionPtr	    pClip = fbGetCompositeClip(pGC);
63505b261ecSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
63605b261ecSmrg    register BoxPtr pbox;
63705b261ecSmrg    BoxPtr	    pextent;
63805b261ecSmrg    int		    extentX1, extentX2, extentY1, extentY2;
63905b261ecSmrg    int		    fullX1, fullX2, fullY1, fullY2;
64005b261ecSmrg    int		    partX1, partX2, partY1, partY2;
64105b261ecSmrg    int		    xoff, yoff;
64205b261ecSmrg    int		    xorg, yorg;
64305b261ecSmrg    int		    n;
64405b261ecSmrg    ExaMigrationRec pixmaps[2];
64505b261ecSmrg    RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
64605b261ecSmrg
64705b261ecSmrg    /* Compute intersection of rects and clip region */
64805b261ecSmrg    REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
64905b261ecSmrg    REGION_INTERSECT(pScreen, pReg, pClip, pReg);
65005b261ecSmrg
65105b261ecSmrg    if (!REGION_NUM_RECTS(pReg)) {
65205b261ecSmrg	goto out;
65305b261ecSmrg    }
65405b261ecSmrg
65505b261ecSmrg    pixmaps[0].as_dst = TRUE;
65605b261ecSmrg    pixmaps[0].as_src = FALSE;
65705b261ecSmrg    pixmaps[0].pPix = pPixmap;
65805b261ecSmrg
65905b261ecSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
66005b261ecSmrg
66105b261ecSmrg    if (pExaScr->swappedOut ||
66205b261ecSmrg	pPixmap->drawable.width > pExaScr->info->maxX ||
66305b261ecSmrg	pPixmap->drawable.height > pExaScr->info->maxY)
66405b261ecSmrg    {
66505b261ecSmrg	goto fallback;
66605b261ecSmrg    }
66705b261ecSmrg
66805b261ecSmrg    /* For ROPs where overlaps don't matter, convert rectangles to region and
66905b261ecSmrg     * call exaFillRegion{Solid,Tiled}.
67005b261ecSmrg     */
67105b261ecSmrg    if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
67205b261ecSmrg	(pGC->alu == GXcopy || pGC->alu == GXclear || pGC->alu == GXnoop ||
67305b261ecSmrg	 pGC->alu == GXcopyInverted || pGC->alu == GXset)) {
67405b261ecSmrg	if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
67505b261ecSmrg	     exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
67605b261ecSmrg				pGC->fgPixel : pGC->tile.pixel,	pGC->planemask,
67705b261ecSmrg				pGC->alu)) ||
67805b261ecSmrg	    (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
67905b261ecSmrg	     exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
68005b261ecSmrg				pGC->planemask, pGC->alu))) {
68105b261ecSmrg	    goto out;
68205b261ecSmrg	}
68305b261ecSmrg    }
68405b261ecSmrg
68505b261ecSmrg    if (pGC->fillStyle != FillSolid &&
68605b261ecSmrg	!(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
68705b261ecSmrg    {
68805b261ecSmrg	goto fallback;
68905b261ecSmrg    }
69005b261ecSmrg
69105b261ecSmrg    exaDoMigration (pixmaps, 1, TRUE);
69205b261ecSmrg
69305b261ecSmrg    if (!exaPixmapIsOffscreen (pPixmap) ||
69405b261ecSmrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
69505b261ecSmrg					 pGC->alu,
69605b261ecSmrg					 pGC->planemask,
69705b261ecSmrg					 pGC->fgPixel))
69805b261ecSmrg    {
69905b261ecSmrgfallback:
70005b261ecSmrg	if (pGC->fillStyle == FillTiled && !pGC->tileIsPixel) {
70105b261ecSmrg	    pixmaps[1].as_dst = FALSE;
70205b261ecSmrg	    pixmaps[1].as_src = TRUE;
70305b261ecSmrg	    pixmaps[1].pPix = pGC->tile.pixmap;
70405b261ecSmrg	    exaDoMigration (pixmaps, 2, FALSE);
70505b261ecSmrg	} else {
70605b261ecSmrg	    exaDoMigration (pixmaps, 1, FALSE);
70705b261ecSmrg	}
70805b261ecSmrg
70905b261ecSmrg	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
71005b261ecSmrg	goto out;
71105b261ecSmrg    }
71205b261ecSmrg
71305b261ecSmrg    xorg = pDrawable->x;
71405b261ecSmrg    yorg = pDrawable->y;
71505b261ecSmrg
71605b261ecSmrg    pextent = REGION_EXTENTS(pGC->pScreen, pClip);
71705b261ecSmrg    extentX1 = pextent->x1;
71805b261ecSmrg    extentY1 = pextent->y1;
71905b261ecSmrg    extentX2 = pextent->x2;
72005b261ecSmrg    extentY2 = pextent->y2;
72105b261ecSmrg    while (nrect--)
72205b261ecSmrg    {
72305b261ecSmrg	fullX1 = prect->x + xorg;
72405b261ecSmrg	fullY1 = prect->y + yorg;
72505b261ecSmrg	fullX2 = fullX1 + (int) prect->width;
72605b261ecSmrg	fullY2 = fullY1 + (int) prect->height;
72705b261ecSmrg	prect++;
72805b261ecSmrg
72905b261ecSmrg	if (fullX1 < extentX1)
73005b261ecSmrg	    fullX1 = extentX1;
73105b261ecSmrg
73205b261ecSmrg	if (fullY1 < extentY1)
73305b261ecSmrg	    fullY1 = extentY1;
73405b261ecSmrg
73505b261ecSmrg	if (fullX2 > extentX2)
73605b261ecSmrg	    fullX2 = extentX2;
73705b261ecSmrg
73805b261ecSmrg	if (fullY2 > extentY2)
73905b261ecSmrg	    fullY2 = extentY2;
74005b261ecSmrg
74105b261ecSmrg	if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
74205b261ecSmrg	    continue;
74305b261ecSmrg	n = REGION_NUM_RECTS (pClip);
74405b261ecSmrg	if (n == 1)
74505b261ecSmrg	{
74605b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
74705b261ecSmrg				     fullX1 + xoff, fullY1 + yoff,
74805b261ecSmrg				     fullX2 + xoff, fullY2 + yoff);
74905b261ecSmrg	}
75005b261ecSmrg	else
75105b261ecSmrg	{
75205b261ecSmrg	    pbox = REGION_RECTS(pClip);
75305b261ecSmrg	    /*
75405b261ecSmrg	     * clip the rectangle to each box in the clip region
75505b261ecSmrg	     * this is logically equivalent to calling Intersect(),
75605b261ecSmrg	     * but rectangles may overlap each other here.
75705b261ecSmrg	     */
75805b261ecSmrg	    while(n--)
75905b261ecSmrg	    {
76005b261ecSmrg		partX1 = pbox->x1;
76105b261ecSmrg		if (partX1 < fullX1)
76205b261ecSmrg		    partX1 = fullX1;
76305b261ecSmrg		partY1 = pbox->y1;
76405b261ecSmrg		if (partY1 < fullY1)
76505b261ecSmrg		    partY1 = fullY1;
76605b261ecSmrg		partX2 = pbox->x2;
76705b261ecSmrg		if (partX2 > fullX2)
76805b261ecSmrg		    partX2 = fullX2;
76905b261ecSmrg		partY2 = pbox->y2;
77005b261ecSmrg		if (partY2 > fullY2)
77105b261ecSmrg		    partY2 = fullY2;
77205b261ecSmrg
77305b261ecSmrg		pbox++;
77405b261ecSmrg
77505b261ecSmrg		if (partX1 < partX2 && partY1 < partY2) {
77605b261ecSmrg		    (*pExaScr->info->Solid) (pPixmap,
77705b261ecSmrg					     partX1 + xoff, partY1 + yoff,
77805b261ecSmrg					     partX2 + xoff, partY2 + yoff);
77905b261ecSmrg		}
78005b261ecSmrg	    }
78105b261ecSmrg	}
78205b261ecSmrg    }
78305b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
78405b261ecSmrg    exaMarkSync(pDrawable->pScreen);
78505b261ecSmrg
78605b261ecSmrgout:
78705b261ecSmrg    REGION_DESTROY(pScreen, pReg);
78805b261ecSmrg}
78905b261ecSmrg
79005b261ecSmrgstatic void
79105b261ecSmrgexaSolidBoxClipped (DrawablePtr	pDrawable,
79205b261ecSmrg		    RegionPtr	pClip,
79305b261ecSmrg		    FbBits	pm,
79405b261ecSmrg		    FbBits	fg,
79505b261ecSmrg		    int		x1,
79605b261ecSmrg		    int		y1,
79705b261ecSmrg		    int		x2,
79805b261ecSmrg		    int		y2)
79905b261ecSmrg{
80005b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
80105b261ecSmrg    PixmapPtr   pPixmap;
80205b261ecSmrg    BoxPtr	pbox;
80305b261ecSmrg    int		nbox;
80405b261ecSmrg    int		xoff, yoff;
80505b261ecSmrg    int		partX1, partX2, partY1, partY2;
80605b261ecSmrg    ExaMigrationRec pixmaps[1];
80705b261ecSmrg    Bool	fallback = FALSE;
80805b261ecSmrg
80905b261ecSmrg    pixmaps[0].as_dst = TRUE;
81005b261ecSmrg    pixmaps[0].as_src = FALSE;
81105b261ecSmrg    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
81205b261ecSmrg
81305b261ecSmrg    if (pExaScr->swappedOut ||
81405b261ecSmrg	pPixmap->drawable.width > pExaScr->info->maxX ||
81505b261ecSmrg	pPixmap->drawable.height > pExaScr->info->maxY)
81605b261ecSmrg    {
81705b261ecSmrg	fallback = TRUE;
81805b261ecSmrg    } else {
81905b261ecSmrg	exaDoMigration (pixmaps, 1, TRUE);
82005b261ecSmrg    }
82105b261ecSmrg
82205b261ecSmrg    exaGetDrawableDeltas (pDrawable, pPixmap, &xoff, &yoff);
82305b261ecSmrg
82405b261ecSmrg    if (fallback || !exaPixmapIsOffscreen(pPixmap) ||
82505b261ecSmrg	!(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, pm, fg))
82605b261ecSmrg    {
82705b261ecSmrg	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
82805b261ecSmrg		      exaDrawableLocation(pDrawable)));
82905b261ecSmrg	exaDoMigration (pixmaps, 1, FALSE);
83005b261ecSmrg	fallback = TRUE;
83105b261ecSmrg	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
83205b261ecSmrg	fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
83305b261ecSmrg	fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
83405b261ecSmrg			   fbAnd (GXcopy, fg, pm),
83505b261ecSmrg			   fbXor (GXcopy, fg, pm));
83605b261ecSmrg	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
83705b261ecSmrg    }
83805b261ecSmrg    for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
83905b261ecSmrg	 nbox--;
84005b261ecSmrg	 pbox++)
84105b261ecSmrg    {
84205b261ecSmrg	partX1 = pbox->x1;
84305b261ecSmrg	if (partX1 < x1)
84405b261ecSmrg	    partX1 = x1;
84505b261ecSmrg
84605b261ecSmrg	partX2 = pbox->x2;
84705b261ecSmrg	if (partX2 > x2)
84805b261ecSmrg	    partX2 = x2;
84905b261ecSmrg
85005b261ecSmrg	if (partX2 <= partX1)
85105b261ecSmrg	    continue;
85205b261ecSmrg
85305b261ecSmrg	partY1 = pbox->y1;
85405b261ecSmrg	if (partY1 < y1)
85505b261ecSmrg	    partY1 = y1;
85605b261ecSmrg
85705b261ecSmrg	partY2 = pbox->y2;
85805b261ecSmrg	if (partY2 > y2)
85905b261ecSmrg	    partY2 = y2;
86005b261ecSmrg
86105b261ecSmrg	if (partY2 <= partY1)
86205b261ecSmrg	    continue;
86305b261ecSmrg
86405b261ecSmrg	if (!fallback) {
86505b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
86605b261ecSmrg				     partX1 + xoff, partY1 + yoff,
86705b261ecSmrg				     partX2 + xoff, partY2 + yoff);
86805b261ecSmrg	}
86905b261ecSmrg
87005b261ecSmrg	exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff, partX2 + xoff,
87105b261ecSmrg			partY2 + yoff);
87205b261ecSmrg    }
87305b261ecSmrg
87405b261ecSmrg    if (fallback)
87505b261ecSmrg	return;
87605b261ecSmrg
87705b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
87805b261ecSmrg    exaMarkSync(pDrawable->pScreen);
87905b261ecSmrg}
88005b261ecSmrg
88105b261ecSmrgstatic void
88205b261ecSmrgexaImageGlyphBlt (DrawablePtr	pDrawable,
88305b261ecSmrg		  GCPtr		pGC,
88405b261ecSmrg		  int		x,
88505b261ecSmrg		  int		y,
88605b261ecSmrg		  unsigned int	nglyph,
88705b261ecSmrg		  CharInfoPtr	*ppciInit,
88805b261ecSmrg		  pointer	pglyphBase)
88905b261ecSmrg{
89005b261ecSmrg    FbGCPrivPtr	    pPriv = fbGetGCPrivate(pGC);
89105b261ecSmrg    CharInfoPtr	    *ppci;
89205b261ecSmrg    CharInfoPtr	    pci;
89305b261ecSmrg    unsigned char   *pglyph;		/* pointer bits in glyph */
89405b261ecSmrg    int		    gWidth, gHeight;	/* width and height of glyph */
89505b261ecSmrg    FbStride	    gStride;		/* stride of glyph */
89605b261ecSmrg    Bool	    opaque;
89705b261ecSmrg    int		    n;
89805b261ecSmrg    int		    gx, gy;
89905b261ecSmrg    void	    (*glyph) (FbBits *,
90005b261ecSmrg			      FbStride,
90105b261ecSmrg			      int,
90205b261ecSmrg			      FbStip *,
90305b261ecSmrg			      FbBits,
90405b261ecSmrg			      int,
90505b261ecSmrg			      int);
90605b261ecSmrg    FbBits	    *dst;
90705b261ecSmrg    FbStride	    dstStride;
90805b261ecSmrg    int		    dstBpp;
90905b261ecSmrg    int		    dstXoff, dstYoff;
91005b261ecSmrg    FbBits	    depthMask;
91105b261ecSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
91205b261ecSmrg    ExaMigrationRec pixmaps[1];
91305b261ecSmrg    int		    xBack, widthBack, yBack, heightBack;
91405b261ecSmrg
91505b261ecSmrg    for (ppci = ppciInit, n = nglyph, widthBack = 0; n; n--)
91605b261ecSmrg	widthBack += (*ppci++)->metrics.characterWidth;
91705b261ecSmrg
91805b261ecSmrg    xBack = x;
91905b261ecSmrg    if (widthBack < 0)
92005b261ecSmrg    {
92105b261ecSmrg	xBack += widthBack;
92205b261ecSmrg	widthBack = -widthBack;
92305b261ecSmrg    }
92405b261ecSmrg    yBack = y - FONTASCENT(pGC->font);
92505b261ecSmrg    heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
92605b261ecSmrg
92705b261ecSmrg    if (xBack >= pDrawable->width || yBack >= pDrawable->height ||
92805b261ecSmrg	(xBack + widthBack) <= 0 || (yBack + heightBack) <= 0)
92905b261ecSmrg	return;
93005b261ecSmrg
93105b261ecSmrg    pixmaps[0].as_dst = TRUE;
93205b261ecSmrg    pixmaps[0].as_src = TRUE;
93305b261ecSmrg    pixmaps[0].pPix = pPixmap;
93405b261ecSmrg
93505b261ecSmrg    depthMask = FbFullMask(pDrawable->depth);
93605b261ecSmrg    if ((pGC->planemask & depthMask) != depthMask)
93705b261ecSmrg    {
93805b261ecSmrg	exaDoMigration(pixmaps, 1, FALSE);
93905b261ecSmrg	ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
94005b261ecSmrg	goto damage;
94105b261ecSmrg    }
94205b261ecSmrg    glyph = NULL;
94305b261ecSmrg    switch (pDrawable->bitsPerPixel) {
94405b261ecSmrg    case 8:	glyph = fbGlyph8; break;
94505b261ecSmrg    case 16:    glyph = fbGlyph16; break;
94605b261ecSmrg    case 24:    glyph = fbGlyph24; break;
94705b261ecSmrg    case 32:    glyph = fbGlyph32; break;
94805b261ecSmrg    }
94905b261ecSmrg
95005b261ecSmrg    x += pDrawable->x;
95105b261ecSmrg    y += pDrawable->y;
95205b261ecSmrg    xBack += pDrawable->x;
95305b261ecSmrg    yBack += pDrawable->y;
95405b261ecSmrg
95505b261ecSmrg    if (TERMINALFONT (pGC->font) && !glyph)
95605b261ecSmrg    {
95705b261ecSmrg	opaque = TRUE;
95805b261ecSmrg    }
95905b261ecSmrg    else
96005b261ecSmrg    {
96105b261ecSmrg        exaSolidBoxClipped (pDrawable,
96205b261ecSmrg			    fbGetCompositeClip(pGC),
96305b261ecSmrg			    pGC->planemask,
96405b261ecSmrg			    pGC->bgPixel,
96505b261ecSmrg			    xBack,
96605b261ecSmrg			    yBack,
96705b261ecSmrg			    xBack + widthBack,
96805b261ecSmrg			    yBack + heightBack);
96905b261ecSmrg	opaque = FALSE;
97005b261ecSmrg    }
97105b261ecSmrg
97205b261ecSmrg    EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
97305b261ecSmrg    exaDoMigration(pixmaps, 1, FALSE);
97405b261ecSmrg    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
97505b261ecSmrg    exaPrepareAccessGC (pGC);
97605b261ecSmrg
97705b261ecSmrg    fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
97805b261ecSmrg
97905b261ecSmrg    for (ppci = ppciInit; nglyph; nglyph--, x += pci->metrics.characterWidth)
98005b261ecSmrg    {
98105b261ecSmrg	pci = *ppci++;
98205b261ecSmrg	gWidth = GLYPHWIDTHPIXELS(pci);
98305b261ecSmrg	gHeight = GLYPHHEIGHTPIXELS(pci);
98405b261ecSmrg	gx = x + pci->metrics.leftSideBearing;
98505b261ecSmrg	gy = y - pci->metrics.ascent;
98605b261ecSmrg
98705b261ecSmrg	if (!gWidth || !gHeight || (gx + gWidth) <= xBack ||
98805b261ecSmrg	    (gy + gHeight) <= yBack || gx >= (xBack + widthBack) ||
98905b261ecSmrg	    gy >= (yBack + heightBack))
99005b261ecSmrg	    continue;
99105b261ecSmrg
99205b261ecSmrg	pglyph = FONTGLYPHBITS(pglyphBase, pci);
99305b261ecSmrg
99405b261ecSmrg	if (glyph && gWidth <= sizeof (FbStip) * 8 &&
99505b261ecSmrg	    fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
99605b261ecSmrg	{
99705b261ecSmrg	    (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
99805b261ecSmrg		      (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight);
99905b261ecSmrg	}
100005b261ecSmrg	else
100105b261ecSmrg	{
100205b261ecSmrg	    RegionPtr pClip = fbGetCompositeClip(pGC);
100305b261ecSmrg
100405b261ecSmrg	    gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
100505b261ecSmrg	    fbPutXYImage (pDrawable, pClip, pPriv->fg, pPriv->bg, pPriv->pm,
100605b261ecSmrg			  GXcopy, opaque, gx, gy, gWidth, gHeight,
100705b261ecSmrg			  (FbStip *) pglyph, gStride, 0);
100805b261ecSmrg	}
100905b261ecSmrg    }
101005b261ecSmrg    exaFinishAccessGC (pGC);
101105b261ecSmrg    exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
101205b261ecSmrg
101305b261ecSmrgdamage:
101405b261ecSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &dstXoff, &dstYoff);
101505b261ecSmrg    exaPixmapDirty(pPixmap, xBack + dstXoff, yBack + dstYoff,
101605b261ecSmrg		   xBack + dstXoff + widthBack, yBack + dstYoff + heightBack);
101705b261ecSmrg}
101805b261ecSmrg
101905b261ecSmrgconst GCOps exaOps = {
102005b261ecSmrg    exaFillSpans,
102105b261ecSmrg    ExaCheckSetSpans,
102205b261ecSmrg    exaPutImage,
102305b261ecSmrg    exaCopyArea,
102405b261ecSmrg    ExaCheckCopyPlane,
102505b261ecSmrg    exaPolyPoint,
102605b261ecSmrg    exaPolylines,
102705b261ecSmrg    exaPolySegment,
102805b261ecSmrg    miPolyRectangle,
102905b261ecSmrg    ExaCheckPolyArc,
103005b261ecSmrg    miFillPolygon,
103105b261ecSmrg    exaPolyFillRect,
103205b261ecSmrg    miPolyFillArc,
103305b261ecSmrg    miPolyText8,
103405b261ecSmrg    miPolyText16,
103505b261ecSmrg    miImageText8,
103605b261ecSmrg    miImageText16,
103705b261ecSmrg    exaImageGlyphBlt,
103805b261ecSmrg    ExaCheckPolyGlyphBlt,
103905b261ecSmrg    ExaCheckPushPixels,
104005b261ecSmrg};
104105b261ecSmrg
104205b261ecSmrgvoid
104305b261ecSmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
104405b261ecSmrg{
104505b261ecSmrg    RegionRec	rgnDst;
104605b261ecSmrg    int		dx, dy;
104705b261ecSmrg    PixmapPtr	pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
104805b261ecSmrg
104905b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
105005b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
105105b261ecSmrg    REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
105205b261ecSmrg
105305b261ecSmrg    REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
105405b261ecSmrg
105505b261ecSmrg    REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
105605b261ecSmrg#ifdef COMPOSITE
105705b261ecSmrg    if (pPixmap->screen_x || pPixmap->screen_y)
105805b261ecSmrg	REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
105905b261ecSmrg			  -pPixmap->screen_x, -pPixmap->screen_y);
106005b261ecSmrg#endif
106105b261ecSmrg
106205b261ecSmrg    fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
106305b261ecSmrg		  NULL,
106405b261ecSmrg		  &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
106505b261ecSmrg
106605b261ecSmrg    REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
106705b261ecSmrg}
106805b261ecSmrg
106905b261ecSmrgstatic Bool
107005b261ecSmrgexaFillRegionSolid (DrawablePtr	pDrawable,
107105b261ecSmrg		    RegionPtr	pRegion,
107205b261ecSmrg		    Pixel	pixel,
107305b261ecSmrg		    CARD32	planemask,
107405b261ecSmrg		    CARD32	alu)
107505b261ecSmrg{
107605b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
107705b261ecSmrg    PixmapPtr pPixmap;
107805b261ecSmrg    int xoff, yoff;
107905b261ecSmrg    ExaMigrationRec pixmaps[1];
108005b261ecSmrg    int nbox = REGION_NUM_RECTS (pRegion);
108105b261ecSmrg    BoxPtr pBox = REGION_RECTS (pRegion);
108205b261ecSmrg
108305b261ecSmrg    pixmaps[0].as_dst = TRUE;
108405b261ecSmrg    pixmaps[0].as_src = FALSE;
108505b261ecSmrg    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
108605b261ecSmrg
108705b261ecSmrg    if (pPixmap->drawable.width > pExaScr->info->maxX ||
108805b261ecSmrg	pPixmap->drawable.height > pExaScr->info->maxY)
108905b261ecSmrg    {
109005b261ecSmrg	goto fallback;
109105b261ecSmrg    } else {
109205b261ecSmrg	exaDoMigration (pixmaps, 1, TRUE);
109305b261ecSmrg    }
109405b261ecSmrg
109505b261ecSmrg    if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
109605b261ecSmrg	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
109705b261ecSmrg    {
109805b261ecSmrg	while (nbox--)
109905b261ecSmrg	{
110005b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
110105b261ecSmrg				     pBox->x1 + xoff, pBox->y1 + yoff,
110205b261ecSmrg				     pBox->x2 + xoff, pBox->y2 + yoff);
110305b261ecSmrg	    pBox++;
110405b261ecSmrg	}
110505b261ecSmrg	(*pExaScr->info->DoneSolid) (pPixmap);
110605b261ecSmrg	exaMarkSync(pDrawable->pScreen);
110705b261ecSmrg    }
110805b261ecSmrg    else
110905b261ecSmrg    {
111005b261ecSmrgfallback:
111105b261ecSmrg	if (alu != GXcopy || planemask != FB_ALLONES)
111205b261ecSmrg	    return FALSE;
111305b261ecSmrg	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
111405b261ecSmrg		      exaDrawableLocation(pDrawable)));
111505b261ecSmrg	exaDoMigration (pixmaps, 1, FALSE);
111605b261ecSmrg	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
111705b261ecSmrg	fbFillRegionSolid (pDrawable, pRegion, 0,
111805b261ecSmrg			   fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
111905b261ecSmrg	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
112005b261ecSmrg    }
112105b261ecSmrg
112205b261ecSmrg    return TRUE;
112305b261ecSmrg}
112405b261ecSmrg
112505b261ecSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
112605b261ecSmrg * Based on fbFillRegionTiled(), fbTile().
112705b261ecSmrg */
112805b261ecSmrgBool
112905b261ecSmrgexaFillRegionTiled (DrawablePtr	pDrawable,
113005b261ecSmrg		    RegionPtr	pRegion,
113105b261ecSmrg		    PixmapPtr	pTile,
113205b261ecSmrg		    DDXPointPtr pPatOrg,
113305b261ecSmrg		    CARD32	planemask,
113405b261ecSmrg		    CARD32	alu)
113505b261ecSmrg{
113605b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
113705b261ecSmrg    PixmapPtr pPixmap;
113805b261ecSmrg    int xoff, yoff, tileXoff, tileYoff;
113905b261ecSmrg    int tileWidth, tileHeight;
114005b261ecSmrg    ExaMigrationRec pixmaps[2];
114105b261ecSmrg    int nbox = REGION_NUM_RECTS (pRegion);
114205b261ecSmrg    BoxPtr pBox = REGION_RECTS (pRegion);
114305b261ecSmrg
114405b261ecSmrg    tileWidth = pTile->drawable.width;
114505b261ecSmrg    tileHeight = pTile->drawable.height;
114605b261ecSmrg
114705b261ecSmrg    /* If we're filling with a solid color, grab it out and go to
114805b261ecSmrg     * FillRegionSolid, saving numerous copies.
114905b261ecSmrg     */
115005b261ecSmrg    if (tileWidth == 1 && tileHeight == 1)
115105b261ecSmrg	return exaFillRegionSolid(pDrawable, pRegion,
115205b261ecSmrg				  exaGetPixmapFirstPixel (pTile), planemask,
115305b261ecSmrg				  alu);
115405b261ecSmrg
115505b261ecSmrg    pixmaps[0].as_dst = TRUE;
115605b261ecSmrg    pixmaps[0].as_src = FALSE;
115705b261ecSmrg    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
115805b261ecSmrg    pixmaps[1].as_dst = FALSE;
115905b261ecSmrg    pixmaps[1].as_src = TRUE;
116005b261ecSmrg    pixmaps[1].pPix = pTile;
116105b261ecSmrg
116205b261ecSmrg    if (pPixmap->drawable.width > pExaScr->info->maxX ||
116305b261ecSmrg	pPixmap->drawable.height > pExaScr->info->maxY ||
116405b261ecSmrg	tileWidth > pExaScr->info->maxX ||
116505b261ecSmrg	tileHeight > pExaScr->info->maxY)
116605b261ecSmrg    {
116705b261ecSmrg	goto fallback;
116805b261ecSmrg    } else {
116905b261ecSmrg	exaDoMigration (pixmaps, 2, TRUE);
117005b261ecSmrg    }
117105b261ecSmrg
117205b261ecSmrg    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
117305b261ecSmrg
117405b261ecSmrg    if (!pPixmap)
117505b261ecSmrg	goto fallback;
117605b261ecSmrg
117705b261ecSmrg    if (!exaPixmapIsOffscreen(pTile))
117805b261ecSmrg	goto fallback;
117905b261ecSmrg
118005b261ecSmrg    if ((*pExaScr->info->PrepareCopy) (exaGetOffscreenPixmap((DrawablePtr)pTile,
118105b261ecSmrg							     &tileXoff, &tileYoff),
118205b261ecSmrg				       pPixmap, 0, 0, alu, planemask))
118305b261ecSmrg    {
118405b261ecSmrg	while (nbox--)
118505b261ecSmrg	{
118605b261ecSmrg	    int height = pBox->y2 - pBox->y1;
118705b261ecSmrg	    int dstY = pBox->y1;
118805b261ecSmrg	    int tileY;
118905b261ecSmrg
119005b261ecSmrg	    modulus(dstY - pDrawable->y - pPatOrg->y, tileHeight, tileY);
119105b261ecSmrg
119205b261ecSmrg	    while (height > 0) {
119305b261ecSmrg		int width = pBox->x2 - pBox->x1;
119405b261ecSmrg		int dstX = pBox->x1;
119505b261ecSmrg		int tileX;
119605b261ecSmrg		int h = tileHeight - tileY;
119705b261ecSmrg
119805b261ecSmrg		if (h > height)
119905b261ecSmrg		    h = height;
120005b261ecSmrg		height -= h;
120105b261ecSmrg
120205b261ecSmrg		modulus(dstX - pDrawable->x - pPatOrg->x, tileWidth, tileX);
120305b261ecSmrg
120405b261ecSmrg		while (width > 0) {
120505b261ecSmrg		    int w = tileWidth - tileX;
120605b261ecSmrg		    if (w > width)
120705b261ecSmrg			w = width;
120805b261ecSmrg		    width -= w;
120905b261ecSmrg
121005b261ecSmrg		    (*pExaScr->info->Copy) (pPixmap,
121105b261ecSmrg					    tileX + tileXoff, tileY + tileYoff,
121205b261ecSmrg					    dstX + xoff, dstY + yoff,
121305b261ecSmrg					    w, h);
121405b261ecSmrg		    dstX += w;
121505b261ecSmrg		    tileX = 0;
121605b261ecSmrg		}
121705b261ecSmrg		dstY += h;
121805b261ecSmrg		tileY = 0;
121905b261ecSmrg	    }
122005b261ecSmrg	    pBox++;
122105b261ecSmrg	}
122205b261ecSmrg	(*pExaScr->info->DoneCopy) (pPixmap);
122305b261ecSmrg	exaMarkSync(pDrawable->pScreen);
122405b261ecSmrg	return TRUE;
122505b261ecSmrg    }
122605b261ecSmrg
122705b261ecSmrgfallback:
122805b261ecSmrg    if (alu != GXcopy || planemask != FB_ALLONES || pPatOrg->x != 0 ||
122905b261ecSmrg	pPatOrg->y != 0)
123005b261ecSmrg	return FALSE;
123105b261ecSmrg    EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable,
123205b261ecSmrg		  exaDrawableLocation(&pTile->drawable),
123305b261ecSmrg		  exaDrawableLocation(pDrawable)));
123405b261ecSmrg    exaDoMigration (pixmaps, 2, FALSE);
123505b261ecSmrg    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
123605b261ecSmrg    exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
123705b261ecSmrg    fbFillRegionTiled (pDrawable, pRegion, pTile);
123805b261ecSmrg    exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
123905b261ecSmrg    exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
124005b261ecSmrg
124105b261ecSmrg    return TRUE;
124205b261ecSmrg}
124305b261ecSmrg
124405b261ecSmrgvoid
124505b261ecSmrgexaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
124605b261ecSmrg{
124705b261ecSmrg    ExaScreenPriv (pWin->drawable.pScreen);
124805b261ecSmrg    PixmapPtr pPixmap = exaGetDrawablePixmap((DrawablePtr)pWin);
124905b261ecSmrg    int xoff, yoff;
125005b261ecSmrg    BoxPtr pBox;
125105b261ecSmrg    int nbox = REGION_NUM_RECTS(pRegion);
125205b261ecSmrg
125305b261ecSmrg    if (!nbox)
125405b261ecSmrg	return;
125505b261ecSmrg
125605b261ecSmrg    if (!pExaScr->swappedOut) {
125705b261ecSmrg	DDXPointRec zeros = { 0, 0 };
125805b261ecSmrg
125905b261ecSmrg        switch (what) {
126005b261ecSmrg        case PW_BACKGROUND:
126105b261ecSmrg            switch (pWin->backgroundState) {
126205b261ecSmrg            case None:
126305b261ecSmrg                return;
126405b261ecSmrg            case ParentRelative:
126505b261ecSmrg                do {
126605b261ecSmrg                    pWin = pWin->parent;
126705b261ecSmrg                } while (pWin->backgroundState == ParentRelative);
126805b261ecSmrg                (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
126905b261ecSmrg                                                                 what);
127005b261ecSmrg                return;
127105b261ecSmrg            case BackgroundPixel:
127205b261ecSmrg		exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->background.pixel,
127305b261ecSmrg				   FB_ALLONES, GXcopy);
127405b261ecSmrg                goto damage;
127505b261ecSmrg            case BackgroundPixmap:
127605b261ecSmrg                exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->background.pixmap,
127705b261ecSmrg				   &zeros, FB_ALLONES, GXcopy);
127805b261ecSmrg                goto damage;
127905b261ecSmrg            }
128005b261ecSmrg            break;
128105b261ecSmrg        case PW_BORDER:
128205b261ecSmrg            if (pWin->borderIsPixel) {
128305b261ecSmrg                exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->border.pixel,
128405b261ecSmrg				   FB_ALLONES, GXcopy);
128505b261ecSmrg                goto damage;
128605b261ecSmrg            } else {
128705b261ecSmrg                exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->border.pixmap,
128805b261ecSmrg				   &zeros, FB_ALLONES, GXcopy);
128905b261ecSmrg                goto damage;
129005b261ecSmrg            }
129105b261ecSmrg            break;
129205b261ecSmrg        }
129305b261ecSmrg    }
129405b261ecSmrg    ExaCheckPaintWindow (pWin, pRegion, what);
129505b261ecSmrg
129605b261ecSmrgdamage:
129705b261ecSmrg    exaGetDrawableDeltas((DrawablePtr)pWin, pPixmap, &xoff, &yoff);
129805b261ecSmrg
129905b261ecSmrg    pBox = REGION_RECTS(pRegion);
130005b261ecSmrg
130105b261ecSmrg    while (nbox--)
130205b261ecSmrg    {
130305b261ecSmrg	exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff,
130405b261ecSmrg			pBox->x2 + xoff, pBox->y2 + yoff);
130505b261ecSmrg	pBox++;
130605b261ecSmrg    }
130705b261ecSmrg}
130805b261ecSmrg
130905b261ecSmrg/**
131005b261ecSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
131105b261ecSmrg *
131205b261ecSmrg * This is probably the only case we actually care about.  The rest fall through
131305b261ecSmrg * to migration and ExaCheckGetImage, which hopefully will result in migration
131405b261ecSmrg * pushing the pixmap out of framebuffer.
131505b261ecSmrg */
131605b261ecSmrgvoid
131705b261ecSmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
131805b261ecSmrg	     unsigned int format, unsigned long planeMask, char *d)
131905b261ecSmrg{
132005b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
132105b261ecSmrg    ExaMigrationRec pixmaps[1];
132205b261ecSmrg    PixmapPtr pPix;
132305b261ecSmrg    int xoff, yoff;
132405b261ecSmrg    Bool ok;
132505b261ecSmrg
132605b261ecSmrg    if (pExaScr->swappedOut || (w == 1 && h == 1))
132705b261ecSmrg	goto fallback;
132805b261ecSmrg
132905b261ecSmrg    if (pExaScr->info->DownloadFromScreen == NULL)
133005b261ecSmrg	goto migrate_and_fallback;
133105b261ecSmrg
133205b261ecSmrg    /* Only cover the ZPixmap, solid copy case. */
133305b261ecSmrg    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
133405b261ecSmrg	goto migrate_and_fallback;
133505b261ecSmrg
133605b261ecSmrg    /* Only try to handle the 8bpp and up cases, since we don't want to think
133705b261ecSmrg     * about <8bpp.
133805b261ecSmrg     */
133905b261ecSmrg    if (pDrawable->bitsPerPixel < 8)
134005b261ecSmrg	goto migrate_and_fallback;
134105b261ecSmrg
134205b261ecSmrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
134305b261ecSmrg    if (pPix == NULL)
134405b261ecSmrg	goto fallback;
134505b261ecSmrg
134605b261ecSmrg    xoff += pDrawable->x;
134705b261ecSmrg    yoff += pDrawable->y;
134805b261ecSmrg
134905b261ecSmrg    ok = pExaScr->info->DownloadFromScreen(pPix, x + xoff, y + yoff, w, h, d,
135005b261ecSmrg					   PixmapBytePad(w, pDrawable->depth));
135105b261ecSmrg    if (ok) {
135205b261ecSmrg	exaWaitSync(pDrawable->pScreen);
135305b261ecSmrg	return;
135405b261ecSmrg    }
135505b261ecSmrg
135605b261ecSmrgmigrate_and_fallback:
135705b261ecSmrg    pixmaps[0].as_dst = FALSE;
135805b261ecSmrg    pixmaps[0].as_src = TRUE;
135905b261ecSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
136005b261ecSmrg    exaDoMigration (pixmaps, 1, FALSE);
136105b261ecSmrgfallback:
136205b261ecSmrg    ExaCheckGetImage (pDrawable, x, y, w, h, format, planeMask, d);
136305b261ecSmrg}
136405b261ecSmrg
136505b261ecSmrg/**
136605b261ecSmrg * GetSpans isn't accelerated yet, but performs migration so that we'll
136705b261ecSmrg * hopefully avoid the read-from-framebuffer cost.
136805b261ecSmrg */
136905b261ecSmrgvoid
137005b261ecSmrgexaGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth,
137105b261ecSmrg	     int nspans, char *pdstStart)
137205b261ecSmrg{
137305b261ecSmrg    ExaMigrationRec pixmaps[1];
137405b261ecSmrg
137505b261ecSmrg    pixmaps[0].as_dst = FALSE;
137605b261ecSmrg    pixmaps[0].as_src = TRUE;
137705b261ecSmrg    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
137805b261ecSmrg    exaDoMigration (pixmaps, 1, FALSE);
137905b261ecSmrg
138005b261ecSmrg    ExaCheckGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
138105b261ecSmrg}
1382