exa_accel.c revision 7b683adc
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
3805b261ecSmrgstatic void
3905b261ecSmrgexaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
4005b261ecSmrg	     DDXPointPtr ppt, int *pwidth, int fSorted)
4105b261ecSmrg{
4205b261ecSmrg    ScreenPtr	    pScreen = pDrawable->pScreen;
4305b261ecSmrg    ExaScreenPriv (pScreen);
4405b261ecSmrg    RegionPtr	    pClip = fbGetCompositeClip(pGC);
454642e01fSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap (pDrawable);
464642e01fSmrg    ExaPixmapPriv (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;
574642e01fSmrg    pixmaps[0].pPix = pPixmap;
584642e01fSmrg    pixmaps[0].pReg = NULL;
5905b261ecSmrg
6005b261ecSmrg    if (pExaScr->swappedOut ||
6105b261ecSmrg	pGC->fillStyle != FillSolid ||
624642e01fSmrg	pExaPixmap->accel_blocked)
6305b261ecSmrg    {
6405b261ecSmrg	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
6505b261ecSmrg	return;
6605b261ecSmrg    } else {
6705b261ecSmrg	exaDoMigration (pixmaps, 1, TRUE);
6805b261ecSmrg    }
6905b261ecSmrg
7005b261ecSmrg    if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
7105b261ecSmrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
7205b261ecSmrg					 pGC->alu,
7305b261ecSmrg					 pGC->planemask,
7405b261ecSmrg					 pGC->fgPixel))
7505b261ecSmrg    {
7605b261ecSmrg	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
7705b261ecSmrg	return;
7805b261ecSmrg    }
7905b261ecSmrg
8005b261ecSmrg    pextent = REGION_EXTENTS(pGC->pScreen, pClip);
8105b261ecSmrg    extentX1 = pextent->x1;
8205b261ecSmrg    extentY1 = pextent->y1;
8305b261ecSmrg    extentX2 = pextent->x2;
8405b261ecSmrg    extentY2 = pextent->y2;
8505b261ecSmrg    while (n--)
8605b261ecSmrg    {
8705b261ecSmrg	fullX1 = ppt->x;
8805b261ecSmrg	fullY1 = ppt->y;
8905b261ecSmrg	fullX2 = fullX1 + (int) *pwidth;
9005b261ecSmrg	ppt++;
9105b261ecSmrg	pwidth++;
9205b261ecSmrg
9305b261ecSmrg	if (fullY1 < extentY1 || extentY2 <= fullY1)
9405b261ecSmrg	    continue;
9505b261ecSmrg
9605b261ecSmrg	if (fullX1 < extentX1)
9705b261ecSmrg	    fullX1 = extentX1;
9805b261ecSmrg
9905b261ecSmrg	if (fullX2 > extentX2)
10005b261ecSmrg	    fullX2 = extentX2;
10105b261ecSmrg
10205b261ecSmrg	if (fullX1 >= fullX2)
10305b261ecSmrg	    continue;
10405b261ecSmrg
10505b261ecSmrg	nbox = REGION_NUM_RECTS (pClip);
10605b261ecSmrg	if (nbox == 1)
10705b261ecSmrg	{
10805b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
10905b261ecSmrg				     fullX1 + off_x, fullY1 + off_y,
11005b261ecSmrg				     fullX2 + off_x, fullY1 + 1 + off_y);
11105b261ecSmrg	}
11205b261ecSmrg	else
11305b261ecSmrg	{
11405b261ecSmrg	    pbox = REGION_RECTS(pClip);
11505b261ecSmrg	    while(nbox--)
11605b261ecSmrg	    {
11705b261ecSmrg		if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
11805b261ecSmrg		{
11905b261ecSmrg		    partX1 = pbox->x1;
12005b261ecSmrg		    if (partX1 < fullX1)
12105b261ecSmrg			partX1 = fullX1;
12205b261ecSmrg		    partX2 = pbox->x2;
12305b261ecSmrg		    if (partX2 > fullX2)
12405b261ecSmrg			partX2 = fullX2;
12505b261ecSmrg		    if (partX2 > partX1) {
12605b261ecSmrg			(*pExaScr->info->Solid) (pPixmap,
12705b261ecSmrg						 partX1 + off_x, fullY1 + off_y,
12805b261ecSmrg						 partX2 + off_x, fullY1 + 1 + off_y);
12905b261ecSmrg		    }
13005b261ecSmrg		}
13105b261ecSmrg		pbox++;
13205b261ecSmrg	    }
13305b261ecSmrg	}
13405b261ecSmrg    }
13505b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
13605b261ecSmrg    exaMarkSync(pScreen);
13705b261ecSmrg}
13805b261ecSmrg
1394642e01fSmrgstatic Bool
1404642e01fSmrgexaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
1414642e01fSmrg	       int w, int h, int format, char *bits, int src_stride)
14205b261ecSmrg{
14305b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
1444642e01fSmrg    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
1454642e01fSmrg    ExaPixmapPriv(pPix);
14605b261ecSmrg    RegionPtr pClip;
14705b261ecSmrg    BoxPtr pbox;
14805b261ecSmrg    int nbox;
14905b261ecSmrg    int xoff, yoff;
1504642e01fSmrg    int bpp = pDrawable->bitsPerPixel;
1514642e01fSmrg    Bool access_prepared = FALSE;
15205b261ecSmrg
1534642e01fSmrg    if (pExaPixmap->accel_blocked)
1544642e01fSmrg	return FALSE;
15505b261ecSmrg
15605b261ecSmrg    /* Don't bother with under 8bpp, XYPixmaps. */
15705b261ecSmrg    if (format != ZPixmap || bpp < 8)
1584642e01fSmrg	return FALSE;
15905b261ecSmrg
16005b261ecSmrg    /* Only accelerate copies: no rop or planemask. */
16105b261ecSmrg    if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
1624642e01fSmrg	return FALSE;
16305b261ecSmrg
16405b261ecSmrg    if (pExaScr->swappedOut)
1654642e01fSmrg	return FALSE;
16605b261ecSmrg
1674642e01fSmrg    if (pExaPixmap->pDamage) {
1684642e01fSmrg	ExaMigrationRec pixmaps[1];
16905b261ecSmrg
1704642e01fSmrg 	pixmaps[0].as_dst = TRUE;
1714642e01fSmrg	pixmaps[0].as_src = FALSE;
1724642e01fSmrg	pixmaps[0].pPix = pPix;
1734642e01fSmrg	pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
1744642e01fSmrg
1754642e01fSmrg	exaDoMigration (pixmaps, 1, TRUE);
1764642e01fSmrg    }
17705b261ecSmrg
17805b261ecSmrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
17905b261ecSmrg
1804642e01fSmrg    if (!pPix || !pExaScr->info->UploadToScreen)
1814642e01fSmrg	return FALSE;
18205b261ecSmrg
18305b261ecSmrg    x += pDrawable->x;
18405b261ecSmrg    y += pDrawable->y;
18505b261ecSmrg
18605b261ecSmrg    pClip = fbGetCompositeClip(pGC);
18705b261ecSmrg    for (nbox = REGION_NUM_RECTS(pClip),
18805b261ecSmrg	 pbox = REGION_RECTS(pClip);
18905b261ecSmrg	 nbox--;
19005b261ecSmrg	 pbox++)
19105b261ecSmrg    {
19205b261ecSmrg	int x1 = x;
19305b261ecSmrg	int y1 = y;
19405b261ecSmrg	int x2 = x + w;
19505b261ecSmrg	int y2 = y + h;
19605b261ecSmrg	char *src;
19705b261ecSmrg	Bool ok;
19805b261ecSmrg
19905b261ecSmrg	if (x1 < pbox->x1)
20005b261ecSmrg	    x1 = pbox->x1;
20105b261ecSmrg	if (y1 < pbox->y1)
20205b261ecSmrg	    y1 = pbox->y1;
20305b261ecSmrg	if (x2 > pbox->x2)
20405b261ecSmrg	    x2 = pbox->x2;
20505b261ecSmrg	if (y2 > pbox->y2)
20605b261ecSmrg	    y2 = pbox->y2;
20705b261ecSmrg	if (x1 >= x2 || y1 >= y2)
20805b261ecSmrg	    continue;
20905b261ecSmrg
21005b261ecSmrg	src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
21105b261ecSmrg	ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
21205b261ecSmrg					   x2 - x1, y2 - y1, src, src_stride);
21305b261ecSmrg	/* If we fail to accelerate the upload, fall back to using unaccelerated
21405b261ecSmrg	 * fb calls.
21505b261ecSmrg	 */
21605b261ecSmrg	if (!ok) {
21705b261ecSmrg	    FbStip *dst;
21805b261ecSmrg	    FbStride dst_stride;
21905b261ecSmrg	    int	dstBpp;
22005b261ecSmrg	    int	dstXoff, dstYoff;
22105b261ecSmrg
2224642e01fSmrg	    if (!access_prepared) {
2234642e01fSmrg		ExaDoPrepareAccess(pDrawable, EXA_PREPARE_DEST);
2244642e01fSmrg
2254642e01fSmrg		access_prepared = TRUE;
2264642e01fSmrg	    }
22705b261ecSmrg
22805b261ecSmrg	    fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp,
22905b261ecSmrg			      dstXoff, dstYoff);
23005b261ecSmrg
23105b261ecSmrg	    fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)),
23205b261ecSmrg		      src_stride / sizeof(FbStip),
23305b261ecSmrg		      (x1 - x) * dstBpp,
23405b261ecSmrg		      dst + (y1 + dstYoff) * dst_stride,
23505b261ecSmrg		      dst_stride,
23605b261ecSmrg		      (x1 + dstXoff) * dstBpp,
23705b261ecSmrg		      (x2 - x1) * dstBpp,
23805b261ecSmrg		      y2 - y1,
23905b261ecSmrg		      GXcopy, FB_ALLONES, dstBpp);
24005b261ecSmrg	}
24105b261ecSmrg    }
24205b261ecSmrg
2434642e01fSmrg    if (access_prepared)
2444642e01fSmrg	exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
2454642e01fSmrg    else
2464642e01fSmrg	exaMarkSync(pDrawable->pScreen);
24705b261ecSmrg
2484642e01fSmrg    return TRUE;
2494642e01fSmrg}
25005b261ecSmrg
2514642e01fSmrgstatic void
2524642e01fSmrgexaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
2534642e01fSmrg	     int w, int h, int leftPad, int format, char *bits)
2544642e01fSmrg{
2554642e01fSmrg    if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
2564642e01fSmrg		       PixmapBytePad(w, pDrawable->depth)))
2574642e01fSmrg	ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
2584642e01fSmrg			 bits);
25905b261ecSmrg}
26005b261ecSmrg
26105b261ecSmrgstatic Bool inline
26205b261ecSmrgexaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
26305b261ecSmrg		   GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
26405b261ecSmrg{
26505b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
26605b261ecSmrg    PixmapPtr pSrcPixmap, pDstPixmap;
26705b261ecSmrg    int src_off_x, src_off_y, dst_off_x, dst_off_y;
26805b261ecSmrg    int dirsetup;
26905b261ecSmrg
27005b261ecSmrg    /* Need to get both pixmaps to call the driver routines */
27105b261ecSmrg    pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
27205b261ecSmrg    pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
27305b261ecSmrg    if (!pSrcPixmap || !pDstPixmap)
27405b261ecSmrg	return FALSE;
27505b261ecSmrg
27605b261ecSmrg    /*
27705b261ecSmrg     * Now the case of a chip that only supports xdir = ydir = 1 or
27805b261ecSmrg     * xdir = ydir = -1, but we have xdir != ydir.
27905b261ecSmrg     */
28005b261ecSmrg    dirsetup = 0;	/* No direction set up yet. */
28105b261ecSmrg    for (; nbox; pbox++, nbox--) {
28205b261ecSmrg	if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
28305b261ecSmrg	    /* Do a xdir = ydir = -1 blit instead. */
28405b261ecSmrg	    if (dirsetup != -1) {
28505b261ecSmrg		if (dirsetup != 0)
28605b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
28705b261ecSmrg		dirsetup = -1;
28805b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
28905b261ecSmrg						   pDstPixmap,
29005b261ecSmrg						   -1, -1,
29105b261ecSmrg						   pGC ? pGC->alu : GXcopy,
29205b261ecSmrg						   pGC ? pGC->planemask :
29305b261ecSmrg							 FB_ALLONES))
29405b261ecSmrg		    return FALSE;
29505b261ecSmrg	    }
29605b261ecSmrg	    (*pExaScr->info->Copy)(pDstPixmap,
29705b261ecSmrg				   src_off_x + pbox->x1 + dx,
29805b261ecSmrg				   src_off_y + pbox->y1 + dy,
29905b261ecSmrg				   dst_off_x + pbox->x1,
30005b261ecSmrg				   dst_off_y + pbox->y1,
30105b261ecSmrg				   pbox->x2 - pbox->x1,
30205b261ecSmrg				   pbox->y2 - pbox->y1);
30305b261ecSmrg	} else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
30405b261ecSmrg	    /* Do a xdir = ydir = 1 blit instead. */
30505b261ecSmrg	    if (dirsetup != 1) {
30605b261ecSmrg		if (dirsetup != 0)
30705b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
30805b261ecSmrg		dirsetup = 1;
30905b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
31005b261ecSmrg						   pDstPixmap,
31105b261ecSmrg						   1, 1,
31205b261ecSmrg						   pGC ? pGC->alu : GXcopy,
31305b261ecSmrg						   pGC ? pGC->planemask :
31405b261ecSmrg							 FB_ALLONES))
31505b261ecSmrg		    return FALSE;
31605b261ecSmrg	    }
31705b261ecSmrg	    (*pExaScr->info->Copy)(pDstPixmap,
31805b261ecSmrg				   src_off_x + pbox->x1 + dx,
31905b261ecSmrg				   src_off_y + pbox->y1 + dy,
32005b261ecSmrg				   dst_off_x + pbox->x1,
32105b261ecSmrg				   dst_off_y + pbox->y1,
32205b261ecSmrg				   pbox->x2 - pbox->x1,
32305b261ecSmrg				   pbox->y2 - pbox->y1);
32405b261ecSmrg	} else if (dx >= 0) {
32505b261ecSmrg	    /*
32605b261ecSmrg	     * xdir = 1, ydir = -1.
32705b261ecSmrg	     * Perform line-by-line xdir = ydir = 1 blits, going up.
32805b261ecSmrg	     */
32905b261ecSmrg	    int i;
33005b261ecSmrg	    if (dirsetup != 1) {
33105b261ecSmrg		if (dirsetup != 0)
33205b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
33305b261ecSmrg		dirsetup = 1;
33405b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
33505b261ecSmrg						   pDstPixmap,
33605b261ecSmrg						   1, 1,
33705b261ecSmrg						   pGC ? pGC->alu : GXcopy,
33805b261ecSmrg						   pGC ? pGC->planemask :
33905b261ecSmrg							 FB_ALLONES))
34005b261ecSmrg		    return FALSE;
34105b261ecSmrg	    }
34205b261ecSmrg	    for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
34305b261ecSmrg		(*pExaScr->info->Copy)(pDstPixmap,
34405b261ecSmrg				       src_off_x + pbox->x1 + dx,
34505b261ecSmrg				       src_off_y + pbox->y1 + dy + i,
34605b261ecSmrg				       dst_off_x + pbox->x1,
34705b261ecSmrg				       dst_off_y + pbox->y1 + i,
34805b261ecSmrg				       pbox->x2 - pbox->x1, 1);
34905b261ecSmrg	} else {
35005b261ecSmrg	    /*
35105b261ecSmrg	     * xdir = -1, ydir = 1.
35205b261ecSmrg	     * Perform line-by-line xdir = ydir = -1 blits, going down.
35305b261ecSmrg	     */
35405b261ecSmrg	    int i;
35505b261ecSmrg	    if (dirsetup != -1) {
35605b261ecSmrg		if (dirsetup != 0)
35705b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
35805b261ecSmrg		dirsetup = -1;
35905b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
36005b261ecSmrg						   pDstPixmap,
36105b261ecSmrg						   -1, -1,
36205b261ecSmrg						   pGC ? pGC->alu : GXcopy,
36305b261ecSmrg						   pGC ? pGC->planemask :
36405b261ecSmrg							 FB_ALLONES))
36505b261ecSmrg		    return FALSE;
36605b261ecSmrg	    }
36705b261ecSmrg	    for (i = 0; i < pbox->y2 - pbox->y1; i++)
36805b261ecSmrg		(*pExaScr->info->Copy)(pDstPixmap,
36905b261ecSmrg				       src_off_x + pbox->x1 + dx,
37005b261ecSmrg				       src_off_y + pbox->y1 + dy + i,
37105b261ecSmrg				       dst_off_x + pbox->x1,
37205b261ecSmrg				       dst_off_y + pbox->y1 + i,
37305b261ecSmrg				       pbox->x2 - pbox->x1, 1);
37405b261ecSmrg	}
37505b261ecSmrg    }
37605b261ecSmrg    if (dirsetup != 0)
37705b261ecSmrg	pExaScr->info->DoneCopy(pDstPixmap);
37805b261ecSmrg    exaMarkSync(pDstDrawable->pScreen);
37905b261ecSmrg    return TRUE;
38005b261ecSmrg}
38105b261ecSmrg
38205b261ecSmrgvoid
38305b261ecSmrgexaCopyNtoN (DrawablePtr    pSrcDrawable,
38405b261ecSmrg	     DrawablePtr    pDstDrawable,
38505b261ecSmrg	     GCPtr	    pGC,
38605b261ecSmrg	     BoxPtr	    pbox,
38705b261ecSmrg	     int	    nbox,
38805b261ecSmrg	     int	    dx,
38905b261ecSmrg	     int	    dy,
39005b261ecSmrg	     Bool	    reverse,
39105b261ecSmrg	     Bool	    upsidedown,
39205b261ecSmrg	     Pixel	    bitplane,
39305b261ecSmrg	     void	    *closure)
39405b261ecSmrg{
39505b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
39605b261ecSmrg    PixmapPtr pSrcPixmap, pDstPixmap;
3974642e01fSmrg    ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
39805b261ecSmrg    int	    src_off_x, src_off_y;
39905b261ecSmrg    int	    dst_off_x, dst_off_y;
40005b261ecSmrg    ExaMigrationRec pixmaps[2];
4014642e01fSmrg    RegionPtr srcregion = NULL, dstregion = NULL;
4024642e01fSmrg    xRectangle *rects;
4034642e01fSmrg
4044642e01fSmrg    /* avoid doing copy operations if no boxes */
4054642e01fSmrg    if (nbox == 0)
4064642e01fSmrg	return;
4074642e01fSmrg
4084642e01fSmrg    pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
4094642e01fSmrg    pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
4104642e01fSmrg
4114642e01fSmrg    exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
4124642e01fSmrg    exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
4134642e01fSmrg
4144642e01fSmrg    rects = xalloc(nbox * sizeof(xRectangle));
4154642e01fSmrg
4164642e01fSmrg    if (rects) {
4174642e01fSmrg	int i;
4187b683adcSmrg	int ordering;
4194642e01fSmrg
4204642e01fSmrg	for (i = 0; i < nbox; i++) {
4214642e01fSmrg	    rects[i].x = pbox[i].x1 + dx + src_off_x;
4224642e01fSmrg	    rects[i].y = pbox[i].y1 + dy + src_off_y;
4234642e01fSmrg	    rects[i].width = pbox[i].x2 - pbox[i].x1;
4244642e01fSmrg	    rects[i].height = pbox[i].y2 - pbox[i].y1;
4254642e01fSmrg	}
4264642e01fSmrg
4277b683adcSmrg	/* This must match the miRegionCopy() logic for reversing rect order */
4287b683adcSmrg	if (nbox == 1 || (dx > 0 && dy > 0) ||
4297b683adcSmrg	    (pDstDrawable != pSrcDrawable &&
4307b683adcSmrg	     (pDstDrawable->type != DRAWABLE_WINDOW ||
4317b683adcSmrg	      pSrcDrawable->type != DRAWABLE_WINDOW)))
4327b683adcSmrg	    ordering = CT_YXBANDED;
4337b683adcSmrg	else
4347b683adcSmrg	    ordering = CT_UNSORTED;
4357b683adcSmrg
4367b683adcSmrg	srcregion  = RECTS_TO_REGION(pScreen, nbox, rects, ordering);
4374642e01fSmrg	xfree(rects);
4384642e01fSmrg
4394642e01fSmrg	if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
44052397711Smrg					   pGC->fillStyle, pGC->alu,
44152397711Smrg					   pGC->clientClipType)) {
4424642e01fSmrg	    dstregion = REGION_CREATE(pScreen, NullBox, 0);
4434642e01fSmrg	    REGION_COPY(pScreen, dstregion, srcregion);
4444642e01fSmrg	    REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x,
4454642e01fSmrg			     dst_off_y - dy - src_off_y);
4464642e01fSmrg	}
4474642e01fSmrg    }
44805b261ecSmrg
44905b261ecSmrg    pixmaps[0].as_dst = TRUE;
45005b261ecSmrg    pixmaps[0].as_src = FALSE;
4514642e01fSmrg    pixmaps[0].pPix = pDstPixmap;
4524642e01fSmrg    pixmaps[0].pReg = dstregion;
45305b261ecSmrg    pixmaps[1].as_dst = FALSE;
45405b261ecSmrg    pixmaps[1].as_src = TRUE;
4554642e01fSmrg    pixmaps[1].pPix = pSrcPixmap;
4564642e01fSmrg    pixmaps[1].pReg = srcregion;
45705b261ecSmrg
4584642e01fSmrg    pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap);
4594642e01fSmrg    pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
4604642e01fSmrg
4614642e01fSmrg    /* Check whether the accelerator can use this pixmap.
4624642e01fSmrg     * If the pitch of the pixmaps is out of range, there's nothing
4634642e01fSmrg     * we can do but fall back to software rendering.
46405b261ecSmrg     */
4654642e01fSmrg    if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
4664642e01fSmrg        pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
4674642e01fSmrg	goto fallback;
4684642e01fSmrg
4694642e01fSmrg    /* If the width or the height of either of the pixmaps
4704642e01fSmrg     * is out of range, check whether the boxes are actually out of the
4714642e01fSmrg     * addressable range as well. If they aren't, we can still do
4724642e01fSmrg     * the copying in hardware.
4734642e01fSmrg     */
4744642e01fSmrg    if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
4754642e01fSmrg        int i;
4764642e01fSmrg
4774642e01fSmrg        for (i = 0; i < nbox; i++) {
4784642e01fSmrg            /* src */
4794642e01fSmrg            if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
4804642e01fSmrg                (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
4814642e01fSmrg                goto fallback;
4824642e01fSmrg
4834642e01fSmrg            /* dst */
4844642e01fSmrg            if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
4854642e01fSmrg                (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
4864642e01fSmrg                goto fallback;
4874642e01fSmrg        }
48805b261ecSmrg    }
48905b261ecSmrg
4904642e01fSmrg    exaDoMigration (pixmaps, 2, TRUE);
4914642e01fSmrg
49205b261ecSmrg    /* Mixed directions must be handled specially if the card is lame */
4934642e01fSmrg    if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
49405b261ecSmrg	reverse != upsidedown) {
49505b261ecSmrg	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
49605b261ecSmrg			       dx, dy))
4974642e01fSmrg	    goto out;
4984642e01fSmrg	goto fallback;
49905b261ecSmrg    }
50005b261ecSmrg
5014642e01fSmrg    if (!exaPixmapIsOffscreen(pSrcPixmap) ||
50205b261ecSmrg	!exaPixmapIsOffscreen(pDstPixmap) ||
50305b261ecSmrg	!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
50405b261ecSmrg					upsidedown ? -1 : 1,
50505b261ecSmrg					pGC ? pGC->alu : GXcopy,
50605b261ecSmrg					pGC ? pGC->planemask : FB_ALLONES)) {
5074642e01fSmrg	goto fallback;
50805b261ecSmrg    }
50905b261ecSmrg
51005b261ecSmrg    while (nbox--)
51105b261ecSmrg    {
5124642e01fSmrg	(*pExaScr->info->Copy) (pDstPixmap,
5134642e01fSmrg				pbox->x1 + dx + src_off_x,
5144642e01fSmrg				pbox->y1 + dy + src_off_y,
5154642e01fSmrg				pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
5164642e01fSmrg				pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
51705b261ecSmrg	pbox++;
51805b261ecSmrg    }
51905b261ecSmrg
52005b261ecSmrg    (*pExaScr->info->DoneCopy) (pDstPixmap);
52105b261ecSmrg    exaMarkSync (pDstDrawable->pScreen);
5224642e01fSmrg
5234642e01fSmrg    goto out;
5244642e01fSmrg
5254642e01fSmrgfallback:
5264642e01fSmrg    EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
5274642e01fSmrg		  exaDrawableLocation(pSrcDrawable),
5284642e01fSmrg		  exaDrawableLocation(pDstDrawable)));
5294642e01fSmrg    exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, dstregion);
5304642e01fSmrg    exaPrepareAccessReg (pSrcDrawable, EXA_PREPARE_SRC, srcregion);
5314642e01fSmrg    fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
5324642e01fSmrg		upsidedown, bitplane, closure);
5334642e01fSmrg    exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
5344642e01fSmrg    exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
5354642e01fSmrg
5364642e01fSmrgout:
5374642e01fSmrg    if (dstregion) {
5384642e01fSmrg	REGION_UNINIT(pScreen, dstregion);
5394642e01fSmrg	REGION_DESTROY(pScreen, dstregion);
5404642e01fSmrg    }
5414642e01fSmrg    if (srcregion) {
5424642e01fSmrg	REGION_UNINIT(pScreen, srcregion);
5434642e01fSmrg	REGION_DESTROY(pScreen, srcregion);
5444642e01fSmrg    }
54505b261ecSmrg}
54605b261ecSmrg
54705b261ecSmrgRegionPtr
54805b261ecSmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
54905b261ecSmrg	    int srcx, int srcy, int width, int height, int dstx, int dsty)
55005b261ecSmrg{
55105b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
55205b261ecSmrg
55305b261ecSmrg    if (pExaScr->swappedOut) {
55405b261ecSmrg        return  ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
55505b261ecSmrg                                 srcx, srcy, width, height, dstx, dsty);
55605b261ecSmrg    }
55705b261ecSmrg
55805b261ecSmrg    return  fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
55905b261ecSmrg                      srcx, srcy, width, height,
56005b261ecSmrg                      dstx, dsty, exaCopyNtoN, 0, NULL);
56105b261ecSmrg}
56205b261ecSmrg
56305b261ecSmrgstatic void
56405b261ecSmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
56505b261ecSmrg	     DDXPointPtr ppt)
56605b261ecSmrg{
56705b261ecSmrg    int i;
56805b261ecSmrg    xRectangle *prect;
56905b261ecSmrg
57005b261ecSmrg    /* If we can't reuse the current GC as is, don't bother accelerating the
57105b261ecSmrg     * points.
57205b261ecSmrg     */
57305b261ecSmrg    if (pGC->fillStyle != FillSolid) {
57405b261ecSmrg	ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
57505b261ecSmrg	return;
57605b261ecSmrg    }
57705b261ecSmrg
5784642e01fSmrg    prect = xalloc(sizeof(xRectangle) * npt);
57905b261ecSmrg    for (i = 0; i < npt; i++) {
58005b261ecSmrg	prect[i].x = ppt[i].x;
58105b261ecSmrg	prect[i].y = ppt[i].y;
58205b261ecSmrg	if (i > 0 && mode == CoordModePrevious) {
58305b261ecSmrg	    prect[i].x += prect[i - 1].x;
58405b261ecSmrg	    prect[i].y += prect[i - 1].y;
58505b261ecSmrg	}
58605b261ecSmrg	prect[i].width = 1;
58705b261ecSmrg	prect[i].height = 1;
58805b261ecSmrg    }
58905b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
5904642e01fSmrg    xfree(prect);
59105b261ecSmrg}
59205b261ecSmrg
59305b261ecSmrg/**
59405b261ecSmrg * exaPolylines() checks if it can accelerate the lines as a group of
59505b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
59605b261ecSmrg * acceleration if so.
59705b261ecSmrg */
59805b261ecSmrgstatic void
59905b261ecSmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
60005b261ecSmrg	     DDXPointPtr ppt)
60105b261ecSmrg{
60205b261ecSmrg    xRectangle *prect;
60305b261ecSmrg    int x1, x2, y1, y2;
60405b261ecSmrg    int i;
60505b261ecSmrg
60605b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
60705b261ecSmrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
60805b261ecSmrg	pGC->fillStyle != FillSolid) {
60905b261ecSmrg	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
61005b261ecSmrg	return;
61105b261ecSmrg    }
61205b261ecSmrg
6134642e01fSmrg    prect = xalloc(sizeof(xRectangle) * (npt - 1));
61405b261ecSmrg    x1 = ppt[0].x;
61505b261ecSmrg    y1 = ppt[0].y;
61605b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
61705b261ecSmrg    for (i = 0; i < npt - 1; i++) {
61805b261ecSmrg	if (mode == CoordModePrevious) {
61905b261ecSmrg	    x2 = x1 + ppt[i + 1].x;
62005b261ecSmrg	    y2 = y1 + ppt[i + 1].y;
62105b261ecSmrg	} else {
62205b261ecSmrg	    x2 = ppt[i + 1].x;
62305b261ecSmrg	    y2 = ppt[i + 1].y;
62405b261ecSmrg	}
62505b261ecSmrg
62605b261ecSmrg	if (x1 != x2 && y1 != y2) {
6274642e01fSmrg	    xfree(prect);
62805b261ecSmrg	    ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
62905b261ecSmrg	    return;
63005b261ecSmrg	}
63105b261ecSmrg
63205b261ecSmrg	if (x1 < x2) {
63305b261ecSmrg	    prect[i].x = x1;
63405b261ecSmrg	    prect[i].width = x2 - x1 + 1;
63505b261ecSmrg	} else {
63605b261ecSmrg	    prect[i].x = x2;
63705b261ecSmrg	    prect[i].width = x1 - x2 + 1;
63805b261ecSmrg	}
63905b261ecSmrg	if (y1 < y2) {
64005b261ecSmrg	    prect[i].y = y1;
64105b261ecSmrg	    prect[i].height = y2 - y1 + 1;
64205b261ecSmrg	} else {
64305b261ecSmrg	    prect[i].y = y2;
64405b261ecSmrg	    prect[i].height = y1 - y2 + 1;
64505b261ecSmrg	}
64605b261ecSmrg
64705b261ecSmrg	x1 = x2;
64805b261ecSmrg	y1 = y2;
64905b261ecSmrg    }
65005b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
6514642e01fSmrg    xfree(prect);
65205b261ecSmrg}
65305b261ecSmrg
65405b261ecSmrg/**
65505b261ecSmrg * exaPolySegment() checks if it can accelerate the lines as a group of
65605b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
65705b261ecSmrg * acceleration if so.
65805b261ecSmrg */
65905b261ecSmrgstatic void
66005b261ecSmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
66105b261ecSmrg		xSegment *pSeg)
66205b261ecSmrg{
66305b261ecSmrg    xRectangle *prect;
66405b261ecSmrg    int i;
66505b261ecSmrg
66605b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
66705b261ecSmrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
66805b261ecSmrg	pGC->fillStyle != FillSolid)
66905b261ecSmrg    {
67005b261ecSmrg	ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
67105b261ecSmrg	return;
67205b261ecSmrg    }
67305b261ecSmrg
67405b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
67505b261ecSmrg    for (i = 0; i < nseg; i++) {
67605b261ecSmrg	if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
67705b261ecSmrg	    ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
67805b261ecSmrg	    return;
67905b261ecSmrg	}
68005b261ecSmrg    }
68105b261ecSmrg
6824642e01fSmrg    prect = xalloc(sizeof(xRectangle) * nseg);
68305b261ecSmrg    for (i = 0; i < nseg; i++) {
68405b261ecSmrg	if (pSeg[i].x1 < pSeg[i].x2) {
68505b261ecSmrg	    prect[i].x = pSeg[i].x1;
68605b261ecSmrg	    prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
68705b261ecSmrg	} else {
68805b261ecSmrg	    prect[i].x = pSeg[i].x2;
68905b261ecSmrg	    prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
69005b261ecSmrg	}
69105b261ecSmrg	if (pSeg[i].y1 < pSeg[i].y2) {
69205b261ecSmrg	    prect[i].y = pSeg[i].y1;
69305b261ecSmrg	    prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
69405b261ecSmrg	} else {
69505b261ecSmrg	    prect[i].y = pSeg[i].y2;
69605b261ecSmrg	    prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
69705b261ecSmrg	}
6984642e01fSmrg
6994642e01fSmrg	/* don't paint last pixel */
7004642e01fSmrg	if (pGC->capStyle == CapNotLast) {
7014642e01fSmrg	    if (prect[i].width == 1)
7024642e01fSmrg		prect[i].height--;
7034642e01fSmrg	    else
7044642e01fSmrg		prect[i].width--;
7054642e01fSmrg	}
70605b261ecSmrg    }
70705b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
7084642e01fSmrg    xfree(prect);
70905b261ecSmrg}
71005b261ecSmrg
71105b261ecSmrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
71252397711Smrg				Pixel pixel, CARD32 planemask, CARD32 alu,
71352397711Smrg				unsigned int clientClipType);
71405b261ecSmrg
71505b261ecSmrgstatic void
71605b261ecSmrgexaPolyFillRect(DrawablePtr pDrawable,
71705b261ecSmrg		GCPtr	    pGC,
71805b261ecSmrg		int	    nrect,
71905b261ecSmrg		xRectangle  *prect)
72005b261ecSmrg{
72105b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
72205b261ecSmrg    RegionPtr	    pClip = fbGetCompositeClip(pGC);
72305b261ecSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
7244642e01fSmrg    ExaPixmapPriv (pPixmap);
72505b261ecSmrg    register BoxPtr pbox;
72605b261ecSmrg    BoxPtr	    pextent;
72705b261ecSmrg    int		    extentX1, extentX2, extentY1, extentY2;
72805b261ecSmrg    int		    fullX1, fullX2, fullY1, fullY2;
72905b261ecSmrg    int		    partX1, partX2, partY1, partY2;
73005b261ecSmrg    int		    xoff, yoff;
73105b261ecSmrg    int		    xorg, yorg;
73205b261ecSmrg    int		    n;
73305b261ecSmrg    ExaMigrationRec pixmaps[2];
73405b261ecSmrg    RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
73505b261ecSmrg
73605b261ecSmrg    /* Compute intersection of rects and clip region */
73705b261ecSmrg    REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
73805b261ecSmrg    REGION_INTERSECT(pScreen, pReg, pClip, pReg);
73905b261ecSmrg
74005b261ecSmrg    if (!REGION_NUM_RECTS(pReg)) {
74105b261ecSmrg	goto out;
74205b261ecSmrg    }
74305b261ecSmrg
74405b261ecSmrg    pixmaps[0].as_dst = TRUE;
74505b261ecSmrg    pixmaps[0].as_src = FALSE;
74605b261ecSmrg    pixmaps[0].pPix = pPixmap;
7474642e01fSmrg    pixmaps[0].pReg = NULL;
7484642e01fSmrg
74905b261ecSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
75005b261ecSmrg
7514642e01fSmrg    if (pExaScr->swappedOut || pExaPixmap->accel_blocked)
75205b261ecSmrg    {
75305b261ecSmrg	goto fallback;
75405b261ecSmrg    }
75505b261ecSmrg
75605b261ecSmrg    /* For ROPs where overlaps don't matter, convert rectangles to region and
75705b261ecSmrg     * call exaFillRegion{Solid,Tiled}.
75805b261ecSmrg     */
75905b261ecSmrg    if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
7604642e01fSmrg	(nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
7614642e01fSmrg	 pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
7624642e01fSmrg	 pGC->alu == GXset)) {
76305b261ecSmrg	if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
76405b261ecSmrg	     exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
76505b261ecSmrg				pGC->fgPixel : pGC->tile.pixel,	pGC->planemask,
76652397711Smrg				pGC->alu, pGC->clientClipType)) ||
76705b261ecSmrg	    (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
76805b261ecSmrg	     exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
76952397711Smrg				pGC->planemask, pGC->alu,
77052397711Smrg				pGC->clientClipType))) {
77105b261ecSmrg	    goto out;
77205b261ecSmrg	}
77305b261ecSmrg    }
77405b261ecSmrg
77505b261ecSmrg    if (pGC->fillStyle != FillSolid &&
77605b261ecSmrg	!(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
77705b261ecSmrg    {
77805b261ecSmrg	goto fallback;
77905b261ecSmrg    }
78005b261ecSmrg
78105b261ecSmrg    exaDoMigration (pixmaps, 1, TRUE);
78205b261ecSmrg
78305b261ecSmrg    if (!exaPixmapIsOffscreen (pPixmap) ||
78405b261ecSmrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
78505b261ecSmrg					 pGC->alu,
78605b261ecSmrg					 pGC->planemask,
78705b261ecSmrg					 pGC->fgPixel))
78805b261ecSmrg    {
78905b261ecSmrgfallback:
79005b261ecSmrg	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
79105b261ecSmrg	goto out;
79205b261ecSmrg    }
79305b261ecSmrg
79405b261ecSmrg    xorg = pDrawable->x;
79505b261ecSmrg    yorg = pDrawable->y;
79605b261ecSmrg
79705b261ecSmrg    pextent = REGION_EXTENTS(pGC->pScreen, pClip);
79805b261ecSmrg    extentX1 = pextent->x1;
79905b261ecSmrg    extentY1 = pextent->y1;
80005b261ecSmrg    extentX2 = pextent->x2;
80105b261ecSmrg    extentY2 = pextent->y2;
80205b261ecSmrg    while (nrect--)
80305b261ecSmrg    {
80405b261ecSmrg	fullX1 = prect->x + xorg;
80505b261ecSmrg	fullY1 = prect->y + yorg;
80605b261ecSmrg	fullX2 = fullX1 + (int) prect->width;
80705b261ecSmrg	fullY2 = fullY1 + (int) prect->height;
80805b261ecSmrg	prect++;
80905b261ecSmrg
81005b261ecSmrg	if (fullX1 < extentX1)
81105b261ecSmrg	    fullX1 = extentX1;
81205b261ecSmrg
81305b261ecSmrg	if (fullY1 < extentY1)
81405b261ecSmrg	    fullY1 = extentY1;
81505b261ecSmrg
81605b261ecSmrg	if (fullX2 > extentX2)
81705b261ecSmrg	    fullX2 = extentX2;
81805b261ecSmrg
81905b261ecSmrg	if (fullY2 > extentY2)
82005b261ecSmrg	    fullY2 = extentY2;
82105b261ecSmrg
82205b261ecSmrg	if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
82305b261ecSmrg	    continue;
82405b261ecSmrg	n = REGION_NUM_RECTS (pClip);
82505b261ecSmrg	if (n == 1)
82605b261ecSmrg	{
82705b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
82805b261ecSmrg				     fullX1 + xoff, fullY1 + yoff,
82905b261ecSmrg				     fullX2 + xoff, fullY2 + yoff);
83005b261ecSmrg	}
83105b261ecSmrg	else
83205b261ecSmrg	{
83305b261ecSmrg	    pbox = REGION_RECTS(pClip);
83405b261ecSmrg	    /*
83505b261ecSmrg	     * clip the rectangle to each box in the clip region
83605b261ecSmrg	     * this is logically equivalent to calling Intersect(),
83705b261ecSmrg	     * but rectangles may overlap each other here.
83805b261ecSmrg	     */
83905b261ecSmrg	    while(n--)
84005b261ecSmrg	    {
84105b261ecSmrg		partX1 = pbox->x1;
84205b261ecSmrg		if (partX1 < fullX1)
84305b261ecSmrg		    partX1 = fullX1;
84405b261ecSmrg		partY1 = pbox->y1;
84505b261ecSmrg		if (partY1 < fullY1)
84605b261ecSmrg		    partY1 = fullY1;
84705b261ecSmrg		partX2 = pbox->x2;
84805b261ecSmrg		if (partX2 > fullX2)
84905b261ecSmrg		    partX2 = fullX2;
85005b261ecSmrg		partY2 = pbox->y2;
85105b261ecSmrg		if (partY2 > fullY2)
85205b261ecSmrg		    partY2 = fullY2;
85305b261ecSmrg
85405b261ecSmrg		pbox++;
85505b261ecSmrg
85605b261ecSmrg		if (partX1 < partX2 && partY1 < partY2) {
85705b261ecSmrg		    (*pExaScr->info->Solid) (pPixmap,
85805b261ecSmrg					     partX1 + xoff, partY1 + yoff,
85905b261ecSmrg					     partX2 + xoff, partY2 + yoff);
86005b261ecSmrg		}
86105b261ecSmrg	    }
86205b261ecSmrg	}
86305b261ecSmrg    }
86405b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
86505b261ecSmrg    exaMarkSync(pDrawable->pScreen);
86605b261ecSmrg
86705b261ecSmrgout:
8684642e01fSmrg    REGION_UNINIT(pScreen, pReg);
86905b261ecSmrg    REGION_DESTROY(pScreen, pReg);
87005b261ecSmrg}
87105b261ecSmrg
87205b261ecSmrgconst GCOps exaOps = {
87305b261ecSmrg    exaFillSpans,
87405b261ecSmrg    ExaCheckSetSpans,
87505b261ecSmrg    exaPutImage,
87605b261ecSmrg    exaCopyArea,
87705b261ecSmrg    ExaCheckCopyPlane,
87805b261ecSmrg    exaPolyPoint,
87905b261ecSmrg    exaPolylines,
88005b261ecSmrg    exaPolySegment,
88105b261ecSmrg    miPolyRectangle,
88205b261ecSmrg    ExaCheckPolyArc,
88305b261ecSmrg    miFillPolygon,
88405b261ecSmrg    exaPolyFillRect,
88505b261ecSmrg    miPolyFillArc,
88605b261ecSmrg    miPolyText8,
88705b261ecSmrg    miPolyText16,
88805b261ecSmrg    miImageText8,
88905b261ecSmrg    miImageText16,
8904642e01fSmrg    ExaCheckImageGlyphBlt,
89105b261ecSmrg    ExaCheckPolyGlyphBlt,
89205b261ecSmrg    ExaCheckPushPixels,
89305b261ecSmrg};
89405b261ecSmrg
89505b261ecSmrgvoid
89605b261ecSmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
89705b261ecSmrg{
89805b261ecSmrg    RegionRec	rgnDst;
89905b261ecSmrg    int		dx, dy;
90005b261ecSmrg    PixmapPtr	pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
90105b261ecSmrg
90205b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
90305b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
90405b261ecSmrg    REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
90505b261ecSmrg
90605b261ecSmrg    REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
90705b261ecSmrg
90805b261ecSmrg    REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
90905b261ecSmrg#ifdef COMPOSITE
91005b261ecSmrg    if (pPixmap->screen_x || pPixmap->screen_y)
91105b261ecSmrg	REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
91205b261ecSmrg			  -pPixmap->screen_x, -pPixmap->screen_y);
91305b261ecSmrg#endif
91405b261ecSmrg
91505b261ecSmrg    fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
91605b261ecSmrg		  NULL,
91705b261ecSmrg		  &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
91805b261ecSmrg
91905b261ecSmrg    REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
92005b261ecSmrg}
92105b261ecSmrg
92205b261ecSmrgstatic Bool
92352397711SmrgexaFillRegionSolid (DrawablePtr	pDrawable, RegionPtr pRegion, Pixel pixel,
92452397711Smrg		    CARD32 planemask, CARD32 alu, unsigned int clientClipType)
92505b261ecSmrg{
92605b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
9274642e01fSmrg    PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
9284642e01fSmrg    ExaPixmapPriv (pPixmap);
92905b261ecSmrg    int xoff, yoff;
93005b261ecSmrg    ExaMigrationRec pixmaps[1];
9314642e01fSmrg    Bool ret = FALSE;
93205b261ecSmrg
93305b261ecSmrg    pixmaps[0].as_dst = TRUE;
93405b261ecSmrg    pixmaps[0].as_src = FALSE;
9354642e01fSmrg    pixmaps[0].pPix = pPixmap;
9364642e01fSmrg    pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
93752397711Smrg					    alu, clientClipType)
93852397711Smrg	? NULL : pRegion;
9394642e01fSmrg
9404642e01fSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
9414642e01fSmrg    REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
9424642e01fSmrg
9434642e01fSmrg    if (pExaPixmap->accel_blocked)
94405b261ecSmrg    {
9454642e01fSmrg	goto out;
94605b261ecSmrg    } else {
94705b261ecSmrg	exaDoMigration (pixmaps, 1, TRUE);
94805b261ecSmrg    }
94905b261ecSmrg
9504642e01fSmrg    if (exaPixmapIsOffscreen (pPixmap) &&
95105b261ecSmrg	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
95205b261ecSmrg    {
9534642e01fSmrg	int nbox;
9544642e01fSmrg	BoxPtr pBox;
9554642e01fSmrg
9564642e01fSmrg	nbox = REGION_NUM_RECTS (pRegion);
9574642e01fSmrg	pBox = REGION_RECTS (pRegion);
9584642e01fSmrg
95905b261ecSmrg	while (nbox--)
96005b261ecSmrg	{
9614642e01fSmrg	    (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
9624642e01fSmrg				     pBox->y2);
96305b261ecSmrg	    pBox++;
96405b261ecSmrg	}
96505b261ecSmrg	(*pExaScr->info->DoneSolid) (pPixmap);
96605b261ecSmrg	exaMarkSync(pDrawable->pScreen);
9674642e01fSmrg
9684642e01fSmrg	if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) &&
9694642e01fSmrg	    pDrawable->width == 1 && pDrawable->height == 1 &&
9704642e01fSmrg	    pDrawable->bitsPerPixel != 24) {
9714642e01fSmrg	    ExaPixmapPriv(pPixmap);
9724642e01fSmrg
9734642e01fSmrg	    switch (pDrawable->bitsPerPixel) {
9744642e01fSmrg	    case 32:
9754642e01fSmrg		*(CARD32*)pExaPixmap->sys_ptr = pixel;
9764642e01fSmrg		break;
9774642e01fSmrg	    case 16:
9784642e01fSmrg		*(CARD16*)pExaPixmap->sys_ptr = pixel;
9794642e01fSmrg		break;
9804642e01fSmrg	    case 8:
9814642e01fSmrg		*(CARD8*)pExaPixmap->sys_ptr = pixel;
9824642e01fSmrg	    }
9834642e01fSmrg
9844642e01fSmrg	    REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
9854642e01fSmrg			 pRegion);
9864642e01fSmrg	}
9874642e01fSmrg
9884642e01fSmrg	ret = TRUE;
98905b261ecSmrg    }
99005b261ecSmrg
9914642e01fSmrgout:
9924642e01fSmrg    REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
9934642e01fSmrg
9944642e01fSmrg    return ret;
99505b261ecSmrg}
99605b261ecSmrg
99705b261ecSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
99805b261ecSmrg * Based on fbFillRegionTiled(), fbTile().
99905b261ecSmrg */
100005b261ecSmrgBool
100152397711SmrgexaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
100252397711Smrg		    DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
100352397711Smrg		    unsigned int clientClipType)
100405b261ecSmrg{
100505b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
100605b261ecSmrg    PixmapPtr pPixmap;
10074642e01fSmrg    ExaPixmapPrivPtr pExaPixmap;
10084642e01fSmrg    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
10094642e01fSmrg    int xoff, yoff;
101005b261ecSmrg    int tileWidth, tileHeight;
101105b261ecSmrg    ExaMigrationRec pixmaps[2];
101205b261ecSmrg    int nbox = REGION_NUM_RECTS (pRegion);
101305b261ecSmrg    BoxPtr pBox = REGION_RECTS (pRegion);
10144642e01fSmrg    Bool ret = FALSE;
10154642e01fSmrg    int i;
101605b261ecSmrg
101705b261ecSmrg    tileWidth = pTile->drawable.width;
101805b261ecSmrg    tileHeight = pTile->drawable.height;
101905b261ecSmrg
102005b261ecSmrg    /* If we're filling with a solid color, grab it out and go to
102105b261ecSmrg     * FillRegionSolid, saving numerous copies.
102205b261ecSmrg     */
102305b261ecSmrg    if (tileWidth == 1 && tileHeight == 1)
102405b261ecSmrg	return exaFillRegionSolid(pDrawable, pRegion,
102505b261ecSmrg				  exaGetPixmapFirstPixel (pTile), planemask,
102652397711Smrg				  alu, clientClipType);
102705b261ecSmrg
102805b261ecSmrg    pixmaps[0].as_dst = TRUE;
102905b261ecSmrg    pixmaps[0].as_src = FALSE;
103005b261ecSmrg    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
10314642e01fSmrg    pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
103252397711Smrg					    alu, clientClipType)
103352397711Smrg	? NULL : pRegion;
103405b261ecSmrg    pixmaps[1].as_dst = FALSE;
103505b261ecSmrg    pixmaps[1].as_src = TRUE;
103605b261ecSmrg    pixmaps[1].pPix = pTile;
10374642e01fSmrg    pixmaps[1].pReg = NULL;
103805b261ecSmrg
10394642e01fSmrg    pExaPixmap = ExaGetPixmapPriv (pPixmap);
10404642e01fSmrg
10414642e01fSmrg    if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked)
104205b261ecSmrg    {
10434642e01fSmrg	return FALSE;
104405b261ecSmrg    } else {
104505b261ecSmrg	exaDoMigration (pixmaps, 2, TRUE);
104605b261ecSmrg    }
104705b261ecSmrg
104805b261ecSmrg    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
104905b261ecSmrg
10504642e01fSmrg    if (!pPixmap || !exaPixmapIsOffscreen(pTile))
10514642e01fSmrg	return FALSE;
105205b261ecSmrg
10534642e01fSmrg    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
105405b261ecSmrg    {
10554642e01fSmrg	if (xoff || yoff)
10564642e01fSmrg	    REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
10574642e01fSmrg
10584642e01fSmrg	for (i = 0; i < nbox; i++)
105905b261ecSmrg	{
10604642e01fSmrg	    int height = pBox[i].y2 - pBox[i].y1;
10614642e01fSmrg	    int dstY = pBox[i].y1;
106205b261ecSmrg	    int tileY;
106305b261ecSmrg
10644642e01fSmrg	    if (alu == GXcopy)
10654642e01fSmrg		height = min(height, tileHeight);
10664642e01fSmrg
10674642e01fSmrg	    modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
106805b261ecSmrg
106905b261ecSmrg	    while (height > 0) {
10704642e01fSmrg		int width = pBox[i].x2 - pBox[i].x1;
10714642e01fSmrg		int dstX = pBox[i].x1;
107205b261ecSmrg		int tileX;
107305b261ecSmrg		int h = tileHeight - tileY;
107405b261ecSmrg
10754642e01fSmrg		if (alu == GXcopy)
10764642e01fSmrg		    width = min(width, tileWidth);
10774642e01fSmrg
107805b261ecSmrg		if (h > height)
107905b261ecSmrg		    h = height;
108005b261ecSmrg		height -= h;
108105b261ecSmrg
10824642e01fSmrg		modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
10834642e01fSmrg			tileX);
108405b261ecSmrg
108505b261ecSmrg		while (width > 0) {
108605b261ecSmrg		    int w = tileWidth - tileX;
108705b261ecSmrg		    if (w > width)
108805b261ecSmrg			w = width;
108905b261ecSmrg		    width -= w;
109005b261ecSmrg
10914642e01fSmrg		    (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
109205b261ecSmrg					    w, h);
109305b261ecSmrg		    dstX += w;
109405b261ecSmrg		    tileX = 0;
109505b261ecSmrg		}
109605b261ecSmrg		dstY += h;
109705b261ecSmrg		tileY = 0;
109805b261ecSmrg	    }
109905b261ecSmrg	}
110005b261ecSmrg	(*pExaScr->info->DoneCopy) (pPixmap);
110105b261ecSmrg
11024642e01fSmrg	/* With GXcopy, we only need to do the basic algorithm up to the tile
11034642e01fSmrg	 * size; then, we can just keep doubling the destination in each
11044642e01fSmrg	 * direction until it fills the box. This way, the number of copy
11054642e01fSmrg	 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
11064642e01fSmrg	 * rx/ry is the ratio between box and tile width/height. This can make
11074642e01fSmrg	 * a big difference if each driver copy incurs a significant constant
11084642e01fSmrg	 * overhead.
11094642e01fSmrg	 */
11104642e01fSmrg	if (alu != GXcopy)
11114642e01fSmrg	    ret = TRUE;
11124642e01fSmrg	else {
11134642e01fSmrg	    Bool more_copy = FALSE;
11144642e01fSmrg
11154642e01fSmrg	    for (i = 0; i < nbox; i++) {
11164642e01fSmrg		int dstX = pBox[i].x1 + tileWidth;
11174642e01fSmrg		int dstY = pBox[i].y1 + tileHeight;
11184642e01fSmrg
11194642e01fSmrg		if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
11204642e01fSmrg		    more_copy = TRUE;
11214642e01fSmrg		    break;
11224642e01fSmrg		}
11234642e01fSmrg	    }
112405b261ecSmrg
11254642e01fSmrg	    if (more_copy == FALSE)
11264642e01fSmrg		ret = TRUE;
112705b261ecSmrg
11284642e01fSmrg	    if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
11294642e01fSmrg							    1, 1, alu, planemask)) {
11304642e01fSmrg		for (i = 0; i < nbox; i++)
11314642e01fSmrg		{
11324642e01fSmrg		    int dstX = pBox[i].x1 + tileWidth;
11334642e01fSmrg		    int dstY = pBox[i].y1 + tileHeight;
11344642e01fSmrg		    int width = min(pBox[i].x2 - dstX, tileWidth);
11354642e01fSmrg		    int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
11364642e01fSmrg
11374642e01fSmrg		    while (dstX < pBox[i].x2) {
11384642e01fSmrg			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
11394642e01fSmrg						dstX, pBox[i].y1, width, height);
11404642e01fSmrg			dstX += width;
11414642e01fSmrg			width = min(pBox[i].x2 - dstX, width * 2);
11424642e01fSmrg		    }
114305b261ecSmrg
11444642e01fSmrg		    width = pBox[i].x2 - pBox[i].x1;
11454642e01fSmrg		    height = min(pBox[i].y2 - dstY, tileHeight);
114605b261ecSmrg
11474642e01fSmrg		    while (dstY < pBox[i].y2) {
11484642e01fSmrg			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
11494642e01fSmrg						pBox[i].x1, dstY, width, height);
11504642e01fSmrg			dstY += height;
11514642e01fSmrg			height = min(pBox[i].y2 - dstY, height * 2);
11524642e01fSmrg		    }
11534642e01fSmrg		}
115405b261ecSmrg
11554642e01fSmrg		(*pExaScr->info->DoneCopy) (pPixmap);
11564642e01fSmrg
11574642e01fSmrg		ret = TRUE;
11584642e01fSmrg	    }
11594642e01fSmrg	}
116005b261ecSmrg
11614642e01fSmrg	exaMarkSync(pDrawable->pScreen);
116205b261ecSmrg
11634642e01fSmrg	if (xoff || yoff)
11644642e01fSmrg	    REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
116505b261ecSmrg    }
11664642e01fSmrg
11674642e01fSmrg    return ret;
116805b261ecSmrg}
116905b261ecSmrg
11704642e01fSmrg
117105b261ecSmrg/**
117205b261ecSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
117305b261ecSmrg *
117405b261ecSmrg * This is probably the only case we actually care about.  The rest fall through
11754642e01fSmrg * to migration and fbGetImage, which hopefully will result in migration pushing
11764642e01fSmrg * the pixmap out of framebuffer.
117705b261ecSmrg */
117805b261ecSmrgvoid
117905b261ecSmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
118005b261ecSmrg	     unsigned int format, unsigned long planeMask, char *d)
118105b261ecSmrg{
118205b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
118305b261ecSmrg    ExaMigrationRec pixmaps[1];
11844642e01fSmrg    BoxRec Box;
11854642e01fSmrg    RegionRec Reg;
118605b261ecSmrg    PixmapPtr pPix;
118705b261ecSmrg    int xoff, yoff;
118805b261ecSmrg    Bool ok;
118905b261ecSmrg
11904642e01fSmrg    pixmaps[0].as_dst = FALSE;
11914642e01fSmrg    pixmaps[0].as_src = TRUE;
11924642e01fSmrg    pixmaps[0].pPix = pPix = exaGetDrawablePixmap (pDrawable);
11934642e01fSmrg    pixmaps[0].pReg = &Reg;
11944642e01fSmrg
11954642e01fSmrg    exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff);
11964642e01fSmrg
11974642e01fSmrg    Box.x1 = pDrawable->y + x + xoff;
11984642e01fSmrg    Box.y1 = pDrawable->y + y + yoff;
11994642e01fSmrg    Box.x2 = Box.x1 + w;
12004642e01fSmrg    Box.y2 = Box.y1 + h;
12014642e01fSmrg
12024642e01fSmrg    REGION_INIT(pScreen, &Reg, &Box, 1);
12034642e01fSmrg
12044642e01fSmrg    if (pExaScr->swappedOut)
120505b261ecSmrg	goto fallback;
120605b261ecSmrg
12074642e01fSmrg    exaDoMigration(pixmaps, 1, FALSE);
12084642e01fSmrg
12094642e01fSmrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
12104642e01fSmrg
12114642e01fSmrg    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
12124642e01fSmrg	goto fallback;
121305b261ecSmrg
121405b261ecSmrg    /* Only cover the ZPixmap, solid copy case. */
121505b261ecSmrg    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
12164642e01fSmrg	goto fallback;
121705b261ecSmrg
121805b261ecSmrg    /* Only try to handle the 8bpp and up cases, since we don't want to think
121905b261ecSmrg     * about <8bpp.
122005b261ecSmrg     */
122105b261ecSmrg    if (pDrawable->bitsPerPixel < 8)
122205b261ecSmrg	goto fallback;
122305b261ecSmrg
12244642e01fSmrg    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
12254642e01fSmrg					   pDrawable->y + y + yoff, w, h, d,
122605b261ecSmrg					   PixmapBytePad(w, pDrawable->depth));
122705b261ecSmrg    if (ok) {
122805b261ecSmrg	exaWaitSync(pDrawable->pScreen);
12294642e01fSmrg	goto out;
123005b261ecSmrg    }
123105b261ecSmrg
123205b261ecSmrgfallback:
12334642e01fSmrg    EXA_FALLBACK(("from %p (%c)\n", pDrawable,
12344642e01fSmrg		  exaDrawableLocation(pDrawable)));
123505b261ecSmrg
12364642e01fSmrg    exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg);
12374642e01fSmrg    fbGetImage (pDrawable, x, y, w, h, format, planeMask, d);
12384642e01fSmrg    exaFinishAccess (pDrawable, EXA_PREPARE_SRC);
123905b261ecSmrg
12404642e01fSmrgout:
12414642e01fSmrg    REGION_UNINIT(pScreen, &Reg);
124205b261ecSmrg}
1243