exa_accel.c revision 52397711
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;
4184642e01fSmrg
4194642e01fSmrg	for (i = 0; i < nbox; i++) {
4204642e01fSmrg	    rects[i].x = pbox[i].x1 + dx + src_off_x;
4214642e01fSmrg	    rects[i].y = pbox[i].y1 + dy + src_off_y;
4224642e01fSmrg	    rects[i].width = pbox[i].x2 - pbox[i].x1;
4234642e01fSmrg	    rects[i].height = pbox[i].y2 - pbox[i].y1;
4244642e01fSmrg	}
4254642e01fSmrg
4264642e01fSmrg	srcregion  = RECTS_TO_REGION(pScreen, nbox, rects, CT_YXBANDED);
4274642e01fSmrg	xfree(rects);
4284642e01fSmrg
4294642e01fSmrg	if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
43052397711Smrg					   pGC->fillStyle, pGC->alu,
43152397711Smrg					   pGC->clientClipType)) {
4324642e01fSmrg	    dstregion = REGION_CREATE(pScreen, NullBox, 0);
4334642e01fSmrg	    REGION_COPY(pScreen, dstregion, srcregion);
4344642e01fSmrg	    REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x,
4354642e01fSmrg			     dst_off_y - dy - src_off_y);
4364642e01fSmrg	}
4374642e01fSmrg    }
43805b261ecSmrg
43905b261ecSmrg    pixmaps[0].as_dst = TRUE;
44005b261ecSmrg    pixmaps[0].as_src = FALSE;
4414642e01fSmrg    pixmaps[0].pPix = pDstPixmap;
4424642e01fSmrg    pixmaps[0].pReg = dstregion;
44305b261ecSmrg    pixmaps[1].as_dst = FALSE;
44405b261ecSmrg    pixmaps[1].as_src = TRUE;
4454642e01fSmrg    pixmaps[1].pPix = pSrcPixmap;
4464642e01fSmrg    pixmaps[1].pReg = srcregion;
44705b261ecSmrg
4484642e01fSmrg    pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap);
4494642e01fSmrg    pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
4504642e01fSmrg
4514642e01fSmrg    /* Check whether the accelerator can use this pixmap.
4524642e01fSmrg     * If the pitch of the pixmaps is out of range, there's nothing
4534642e01fSmrg     * we can do but fall back to software rendering.
45405b261ecSmrg     */
4554642e01fSmrg    if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
4564642e01fSmrg        pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
4574642e01fSmrg	goto fallback;
4584642e01fSmrg
4594642e01fSmrg    /* If the width or the height of either of the pixmaps
4604642e01fSmrg     * is out of range, check whether the boxes are actually out of the
4614642e01fSmrg     * addressable range as well. If they aren't, we can still do
4624642e01fSmrg     * the copying in hardware.
4634642e01fSmrg     */
4644642e01fSmrg    if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
4654642e01fSmrg        int i;
4664642e01fSmrg
4674642e01fSmrg        for (i = 0; i < nbox; i++) {
4684642e01fSmrg            /* src */
4694642e01fSmrg            if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
4704642e01fSmrg                (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
4714642e01fSmrg                goto fallback;
4724642e01fSmrg
4734642e01fSmrg            /* dst */
4744642e01fSmrg            if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
4754642e01fSmrg                (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
4764642e01fSmrg                goto fallback;
4774642e01fSmrg        }
47805b261ecSmrg    }
47905b261ecSmrg
4804642e01fSmrg    exaDoMigration (pixmaps, 2, TRUE);
4814642e01fSmrg
48205b261ecSmrg    /* Mixed directions must be handled specially if the card is lame */
4834642e01fSmrg    if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
48405b261ecSmrg	reverse != upsidedown) {
48505b261ecSmrg	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
48605b261ecSmrg			       dx, dy))
4874642e01fSmrg	    goto out;
4884642e01fSmrg	goto fallback;
48905b261ecSmrg    }
49005b261ecSmrg
4914642e01fSmrg    if (!exaPixmapIsOffscreen(pSrcPixmap) ||
49205b261ecSmrg	!exaPixmapIsOffscreen(pDstPixmap) ||
49305b261ecSmrg	!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
49405b261ecSmrg					upsidedown ? -1 : 1,
49505b261ecSmrg					pGC ? pGC->alu : GXcopy,
49605b261ecSmrg					pGC ? pGC->planemask : FB_ALLONES)) {
4974642e01fSmrg	goto fallback;
49805b261ecSmrg    }
49905b261ecSmrg
50005b261ecSmrg    while (nbox--)
50105b261ecSmrg    {
5024642e01fSmrg	(*pExaScr->info->Copy) (pDstPixmap,
5034642e01fSmrg				pbox->x1 + dx + src_off_x,
5044642e01fSmrg				pbox->y1 + dy + src_off_y,
5054642e01fSmrg				pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
5064642e01fSmrg				pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
50705b261ecSmrg	pbox++;
50805b261ecSmrg    }
50905b261ecSmrg
51005b261ecSmrg    (*pExaScr->info->DoneCopy) (pDstPixmap);
51105b261ecSmrg    exaMarkSync (pDstDrawable->pScreen);
5124642e01fSmrg
5134642e01fSmrg    goto out;
5144642e01fSmrg
5154642e01fSmrgfallback:
5164642e01fSmrg    EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
5174642e01fSmrg		  exaDrawableLocation(pSrcDrawable),
5184642e01fSmrg		  exaDrawableLocation(pDstDrawable)));
5194642e01fSmrg    exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, dstregion);
5204642e01fSmrg    exaPrepareAccessReg (pSrcDrawable, EXA_PREPARE_SRC, srcregion);
5214642e01fSmrg    fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
5224642e01fSmrg		upsidedown, bitplane, closure);
5234642e01fSmrg    exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
5244642e01fSmrg    exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
5254642e01fSmrg
5264642e01fSmrgout:
5274642e01fSmrg    if (dstregion) {
5284642e01fSmrg	REGION_UNINIT(pScreen, dstregion);
5294642e01fSmrg	REGION_DESTROY(pScreen, dstregion);
5304642e01fSmrg    }
5314642e01fSmrg    if (srcregion) {
5324642e01fSmrg	REGION_UNINIT(pScreen, srcregion);
5334642e01fSmrg	REGION_DESTROY(pScreen, srcregion);
5344642e01fSmrg    }
53505b261ecSmrg}
53605b261ecSmrg
53705b261ecSmrgRegionPtr
53805b261ecSmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
53905b261ecSmrg	    int srcx, int srcy, int width, int height, int dstx, int dsty)
54005b261ecSmrg{
54105b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
54205b261ecSmrg
54305b261ecSmrg    if (pExaScr->swappedOut) {
54405b261ecSmrg        return  ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
54505b261ecSmrg                                 srcx, srcy, width, height, dstx, dsty);
54605b261ecSmrg    }
54705b261ecSmrg
54805b261ecSmrg    return  fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
54905b261ecSmrg                      srcx, srcy, width, height,
55005b261ecSmrg                      dstx, dsty, exaCopyNtoN, 0, NULL);
55105b261ecSmrg}
55205b261ecSmrg
55305b261ecSmrgstatic void
55405b261ecSmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
55505b261ecSmrg	     DDXPointPtr ppt)
55605b261ecSmrg{
55705b261ecSmrg    int i;
55805b261ecSmrg    xRectangle *prect;
55905b261ecSmrg
56005b261ecSmrg    /* If we can't reuse the current GC as is, don't bother accelerating the
56105b261ecSmrg     * points.
56205b261ecSmrg     */
56305b261ecSmrg    if (pGC->fillStyle != FillSolid) {
56405b261ecSmrg	ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
56505b261ecSmrg	return;
56605b261ecSmrg    }
56705b261ecSmrg
5684642e01fSmrg    prect = xalloc(sizeof(xRectangle) * npt);
56905b261ecSmrg    for (i = 0; i < npt; i++) {
57005b261ecSmrg	prect[i].x = ppt[i].x;
57105b261ecSmrg	prect[i].y = ppt[i].y;
57205b261ecSmrg	if (i > 0 && mode == CoordModePrevious) {
57305b261ecSmrg	    prect[i].x += prect[i - 1].x;
57405b261ecSmrg	    prect[i].y += prect[i - 1].y;
57505b261ecSmrg	}
57605b261ecSmrg	prect[i].width = 1;
57705b261ecSmrg	prect[i].height = 1;
57805b261ecSmrg    }
57905b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
5804642e01fSmrg    xfree(prect);
58105b261ecSmrg}
58205b261ecSmrg
58305b261ecSmrg/**
58405b261ecSmrg * exaPolylines() checks if it can accelerate the lines as a group of
58505b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
58605b261ecSmrg * acceleration if so.
58705b261ecSmrg */
58805b261ecSmrgstatic void
58905b261ecSmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
59005b261ecSmrg	     DDXPointPtr ppt)
59105b261ecSmrg{
59205b261ecSmrg    xRectangle *prect;
59305b261ecSmrg    int x1, x2, y1, y2;
59405b261ecSmrg    int i;
59505b261ecSmrg
59605b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
59705b261ecSmrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
59805b261ecSmrg	pGC->fillStyle != FillSolid) {
59905b261ecSmrg	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
60005b261ecSmrg	return;
60105b261ecSmrg    }
60205b261ecSmrg
6034642e01fSmrg    prect = xalloc(sizeof(xRectangle) * (npt - 1));
60405b261ecSmrg    x1 = ppt[0].x;
60505b261ecSmrg    y1 = ppt[0].y;
60605b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
60705b261ecSmrg    for (i = 0; i < npt - 1; i++) {
60805b261ecSmrg	if (mode == CoordModePrevious) {
60905b261ecSmrg	    x2 = x1 + ppt[i + 1].x;
61005b261ecSmrg	    y2 = y1 + ppt[i + 1].y;
61105b261ecSmrg	} else {
61205b261ecSmrg	    x2 = ppt[i + 1].x;
61305b261ecSmrg	    y2 = ppt[i + 1].y;
61405b261ecSmrg	}
61505b261ecSmrg
61605b261ecSmrg	if (x1 != x2 && y1 != y2) {
6174642e01fSmrg	    xfree(prect);
61805b261ecSmrg	    ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
61905b261ecSmrg	    return;
62005b261ecSmrg	}
62105b261ecSmrg
62205b261ecSmrg	if (x1 < x2) {
62305b261ecSmrg	    prect[i].x = x1;
62405b261ecSmrg	    prect[i].width = x2 - x1 + 1;
62505b261ecSmrg	} else {
62605b261ecSmrg	    prect[i].x = x2;
62705b261ecSmrg	    prect[i].width = x1 - x2 + 1;
62805b261ecSmrg	}
62905b261ecSmrg	if (y1 < y2) {
63005b261ecSmrg	    prect[i].y = y1;
63105b261ecSmrg	    prect[i].height = y2 - y1 + 1;
63205b261ecSmrg	} else {
63305b261ecSmrg	    prect[i].y = y2;
63405b261ecSmrg	    prect[i].height = y1 - y2 + 1;
63505b261ecSmrg	}
63605b261ecSmrg
63705b261ecSmrg	x1 = x2;
63805b261ecSmrg	y1 = y2;
63905b261ecSmrg    }
64005b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
6414642e01fSmrg    xfree(prect);
64205b261ecSmrg}
64305b261ecSmrg
64405b261ecSmrg/**
64505b261ecSmrg * exaPolySegment() checks if it can accelerate the lines as a group of
64605b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
64705b261ecSmrg * acceleration if so.
64805b261ecSmrg */
64905b261ecSmrgstatic void
65005b261ecSmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
65105b261ecSmrg		xSegment *pSeg)
65205b261ecSmrg{
65305b261ecSmrg    xRectangle *prect;
65405b261ecSmrg    int i;
65505b261ecSmrg
65605b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
65705b261ecSmrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
65805b261ecSmrg	pGC->fillStyle != FillSolid)
65905b261ecSmrg    {
66005b261ecSmrg	ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
66105b261ecSmrg	return;
66205b261ecSmrg    }
66305b261ecSmrg
66405b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
66505b261ecSmrg    for (i = 0; i < nseg; i++) {
66605b261ecSmrg	if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
66705b261ecSmrg	    ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
66805b261ecSmrg	    return;
66905b261ecSmrg	}
67005b261ecSmrg    }
67105b261ecSmrg
6724642e01fSmrg    prect = xalloc(sizeof(xRectangle) * nseg);
67305b261ecSmrg    for (i = 0; i < nseg; i++) {
67405b261ecSmrg	if (pSeg[i].x1 < pSeg[i].x2) {
67505b261ecSmrg	    prect[i].x = pSeg[i].x1;
67605b261ecSmrg	    prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
67705b261ecSmrg	} else {
67805b261ecSmrg	    prect[i].x = pSeg[i].x2;
67905b261ecSmrg	    prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
68005b261ecSmrg	}
68105b261ecSmrg	if (pSeg[i].y1 < pSeg[i].y2) {
68205b261ecSmrg	    prect[i].y = pSeg[i].y1;
68305b261ecSmrg	    prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
68405b261ecSmrg	} else {
68505b261ecSmrg	    prect[i].y = pSeg[i].y2;
68605b261ecSmrg	    prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
68705b261ecSmrg	}
6884642e01fSmrg
6894642e01fSmrg	/* don't paint last pixel */
6904642e01fSmrg	if (pGC->capStyle == CapNotLast) {
6914642e01fSmrg	    if (prect[i].width == 1)
6924642e01fSmrg		prect[i].height--;
6934642e01fSmrg	    else
6944642e01fSmrg		prect[i].width--;
6954642e01fSmrg	}
69605b261ecSmrg    }
69705b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
6984642e01fSmrg    xfree(prect);
69905b261ecSmrg}
70005b261ecSmrg
70105b261ecSmrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
70252397711Smrg				Pixel pixel, CARD32 planemask, CARD32 alu,
70352397711Smrg				unsigned int clientClipType);
70405b261ecSmrg
70505b261ecSmrgstatic void
70605b261ecSmrgexaPolyFillRect(DrawablePtr pDrawable,
70705b261ecSmrg		GCPtr	    pGC,
70805b261ecSmrg		int	    nrect,
70905b261ecSmrg		xRectangle  *prect)
71005b261ecSmrg{
71105b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
71205b261ecSmrg    RegionPtr	    pClip = fbGetCompositeClip(pGC);
71305b261ecSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
7144642e01fSmrg    ExaPixmapPriv (pPixmap);
71505b261ecSmrg    register BoxPtr pbox;
71605b261ecSmrg    BoxPtr	    pextent;
71705b261ecSmrg    int		    extentX1, extentX2, extentY1, extentY2;
71805b261ecSmrg    int		    fullX1, fullX2, fullY1, fullY2;
71905b261ecSmrg    int		    partX1, partX2, partY1, partY2;
72005b261ecSmrg    int		    xoff, yoff;
72105b261ecSmrg    int		    xorg, yorg;
72205b261ecSmrg    int		    n;
72305b261ecSmrg    ExaMigrationRec pixmaps[2];
72405b261ecSmrg    RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
72505b261ecSmrg
72605b261ecSmrg    /* Compute intersection of rects and clip region */
72705b261ecSmrg    REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
72805b261ecSmrg    REGION_INTERSECT(pScreen, pReg, pClip, pReg);
72905b261ecSmrg
73005b261ecSmrg    if (!REGION_NUM_RECTS(pReg)) {
73105b261ecSmrg	goto out;
73205b261ecSmrg    }
73305b261ecSmrg
73405b261ecSmrg    pixmaps[0].as_dst = TRUE;
73505b261ecSmrg    pixmaps[0].as_src = FALSE;
73605b261ecSmrg    pixmaps[0].pPix = pPixmap;
7374642e01fSmrg    pixmaps[0].pReg = NULL;
7384642e01fSmrg
73905b261ecSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
74005b261ecSmrg
7414642e01fSmrg    if (pExaScr->swappedOut || pExaPixmap->accel_blocked)
74205b261ecSmrg    {
74305b261ecSmrg	goto fallback;
74405b261ecSmrg    }
74505b261ecSmrg
74605b261ecSmrg    /* For ROPs where overlaps don't matter, convert rectangles to region and
74705b261ecSmrg     * call exaFillRegion{Solid,Tiled}.
74805b261ecSmrg     */
74905b261ecSmrg    if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
7504642e01fSmrg	(nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
7514642e01fSmrg	 pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
7524642e01fSmrg	 pGC->alu == GXset)) {
75305b261ecSmrg	if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
75405b261ecSmrg	     exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
75505b261ecSmrg				pGC->fgPixel : pGC->tile.pixel,	pGC->planemask,
75652397711Smrg				pGC->alu, pGC->clientClipType)) ||
75705b261ecSmrg	    (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
75805b261ecSmrg	     exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
75952397711Smrg				pGC->planemask, pGC->alu,
76052397711Smrg				pGC->clientClipType))) {
76105b261ecSmrg	    goto out;
76205b261ecSmrg	}
76305b261ecSmrg    }
76405b261ecSmrg
76505b261ecSmrg    if (pGC->fillStyle != FillSolid &&
76605b261ecSmrg	!(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
76705b261ecSmrg    {
76805b261ecSmrg	goto fallback;
76905b261ecSmrg    }
77005b261ecSmrg
77105b261ecSmrg    exaDoMigration (pixmaps, 1, TRUE);
77205b261ecSmrg
77305b261ecSmrg    if (!exaPixmapIsOffscreen (pPixmap) ||
77405b261ecSmrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
77505b261ecSmrg					 pGC->alu,
77605b261ecSmrg					 pGC->planemask,
77705b261ecSmrg					 pGC->fgPixel))
77805b261ecSmrg    {
77905b261ecSmrgfallback:
78005b261ecSmrg	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
78105b261ecSmrg	goto out;
78205b261ecSmrg    }
78305b261ecSmrg
78405b261ecSmrg    xorg = pDrawable->x;
78505b261ecSmrg    yorg = pDrawable->y;
78605b261ecSmrg
78705b261ecSmrg    pextent = REGION_EXTENTS(pGC->pScreen, pClip);
78805b261ecSmrg    extentX1 = pextent->x1;
78905b261ecSmrg    extentY1 = pextent->y1;
79005b261ecSmrg    extentX2 = pextent->x2;
79105b261ecSmrg    extentY2 = pextent->y2;
79205b261ecSmrg    while (nrect--)
79305b261ecSmrg    {
79405b261ecSmrg	fullX1 = prect->x + xorg;
79505b261ecSmrg	fullY1 = prect->y + yorg;
79605b261ecSmrg	fullX2 = fullX1 + (int) prect->width;
79705b261ecSmrg	fullY2 = fullY1 + (int) prect->height;
79805b261ecSmrg	prect++;
79905b261ecSmrg
80005b261ecSmrg	if (fullX1 < extentX1)
80105b261ecSmrg	    fullX1 = extentX1;
80205b261ecSmrg
80305b261ecSmrg	if (fullY1 < extentY1)
80405b261ecSmrg	    fullY1 = extentY1;
80505b261ecSmrg
80605b261ecSmrg	if (fullX2 > extentX2)
80705b261ecSmrg	    fullX2 = extentX2;
80805b261ecSmrg
80905b261ecSmrg	if (fullY2 > extentY2)
81005b261ecSmrg	    fullY2 = extentY2;
81105b261ecSmrg
81205b261ecSmrg	if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
81305b261ecSmrg	    continue;
81405b261ecSmrg	n = REGION_NUM_RECTS (pClip);
81505b261ecSmrg	if (n == 1)
81605b261ecSmrg	{
81705b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
81805b261ecSmrg				     fullX1 + xoff, fullY1 + yoff,
81905b261ecSmrg				     fullX2 + xoff, fullY2 + yoff);
82005b261ecSmrg	}
82105b261ecSmrg	else
82205b261ecSmrg	{
82305b261ecSmrg	    pbox = REGION_RECTS(pClip);
82405b261ecSmrg	    /*
82505b261ecSmrg	     * clip the rectangle to each box in the clip region
82605b261ecSmrg	     * this is logically equivalent to calling Intersect(),
82705b261ecSmrg	     * but rectangles may overlap each other here.
82805b261ecSmrg	     */
82905b261ecSmrg	    while(n--)
83005b261ecSmrg	    {
83105b261ecSmrg		partX1 = pbox->x1;
83205b261ecSmrg		if (partX1 < fullX1)
83305b261ecSmrg		    partX1 = fullX1;
83405b261ecSmrg		partY1 = pbox->y1;
83505b261ecSmrg		if (partY1 < fullY1)
83605b261ecSmrg		    partY1 = fullY1;
83705b261ecSmrg		partX2 = pbox->x2;
83805b261ecSmrg		if (partX2 > fullX2)
83905b261ecSmrg		    partX2 = fullX2;
84005b261ecSmrg		partY2 = pbox->y2;
84105b261ecSmrg		if (partY2 > fullY2)
84205b261ecSmrg		    partY2 = fullY2;
84305b261ecSmrg
84405b261ecSmrg		pbox++;
84505b261ecSmrg
84605b261ecSmrg		if (partX1 < partX2 && partY1 < partY2) {
84705b261ecSmrg		    (*pExaScr->info->Solid) (pPixmap,
84805b261ecSmrg					     partX1 + xoff, partY1 + yoff,
84905b261ecSmrg					     partX2 + xoff, partY2 + yoff);
85005b261ecSmrg		}
85105b261ecSmrg	    }
85205b261ecSmrg	}
85305b261ecSmrg    }
85405b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
85505b261ecSmrg    exaMarkSync(pDrawable->pScreen);
85605b261ecSmrg
85705b261ecSmrgout:
8584642e01fSmrg    REGION_UNINIT(pScreen, pReg);
85905b261ecSmrg    REGION_DESTROY(pScreen, pReg);
86005b261ecSmrg}
86105b261ecSmrg
86205b261ecSmrgconst GCOps exaOps = {
86305b261ecSmrg    exaFillSpans,
86405b261ecSmrg    ExaCheckSetSpans,
86505b261ecSmrg    exaPutImage,
86605b261ecSmrg    exaCopyArea,
86705b261ecSmrg    ExaCheckCopyPlane,
86805b261ecSmrg    exaPolyPoint,
86905b261ecSmrg    exaPolylines,
87005b261ecSmrg    exaPolySegment,
87105b261ecSmrg    miPolyRectangle,
87205b261ecSmrg    ExaCheckPolyArc,
87305b261ecSmrg    miFillPolygon,
87405b261ecSmrg    exaPolyFillRect,
87505b261ecSmrg    miPolyFillArc,
87605b261ecSmrg    miPolyText8,
87705b261ecSmrg    miPolyText16,
87805b261ecSmrg    miImageText8,
87905b261ecSmrg    miImageText16,
8804642e01fSmrg    ExaCheckImageGlyphBlt,
88105b261ecSmrg    ExaCheckPolyGlyphBlt,
88205b261ecSmrg    ExaCheckPushPixels,
88305b261ecSmrg};
88405b261ecSmrg
88505b261ecSmrgvoid
88605b261ecSmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
88705b261ecSmrg{
88805b261ecSmrg    RegionRec	rgnDst;
88905b261ecSmrg    int		dx, dy;
89005b261ecSmrg    PixmapPtr	pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
89105b261ecSmrg
89205b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
89305b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
89405b261ecSmrg    REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
89505b261ecSmrg
89605b261ecSmrg    REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
89705b261ecSmrg
89805b261ecSmrg    REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
89905b261ecSmrg#ifdef COMPOSITE
90005b261ecSmrg    if (pPixmap->screen_x || pPixmap->screen_y)
90105b261ecSmrg	REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
90205b261ecSmrg			  -pPixmap->screen_x, -pPixmap->screen_y);
90305b261ecSmrg#endif
90405b261ecSmrg
90505b261ecSmrg    fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
90605b261ecSmrg		  NULL,
90705b261ecSmrg		  &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
90805b261ecSmrg
90905b261ecSmrg    REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
91005b261ecSmrg}
91105b261ecSmrg
91205b261ecSmrgstatic Bool
91352397711SmrgexaFillRegionSolid (DrawablePtr	pDrawable, RegionPtr pRegion, Pixel pixel,
91452397711Smrg		    CARD32 planemask, CARD32 alu, unsigned int clientClipType)
91505b261ecSmrg{
91605b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
9174642e01fSmrg    PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
9184642e01fSmrg    ExaPixmapPriv (pPixmap);
91905b261ecSmrg    int xoff, yoff;
92005b261ecSmrg    ExaMigrationRec pixmaps[1];
9214642e01fSmrg    Bool ret = FALSE;
92205b261ecSmrg
92305b261ecSmrg    pixmaps[0].as_dst = TRUE;
92405b261ecSmrg    pixmaps[0].as_src = FALSE;
9254642e01fSmrg    pixmaps[0].pPix = pPixmap;
9264642e01fSmrg    pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
92752397711Smrg					    alu, clientClipType)
92852397711Smrg	? NULL : pRegion;
9294642e01fSmrg
9304642e01fSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
9314642e01fSmrg    REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
9324642e01fSmrg
9334642e01fSmrg    if (pExaPixmap->accel_blocked)
93405b261ecSmrg    {
9354642e01fSmrg	goto out;
93605b261ecSmrg    } else {
93705b261ecSmrg	exaDoMigration (pixmaps, 1, TRUE);
93805b261ecSmrg    }
93905b261ecSmrg
9404642e01fSmrg    if (exaPixmapIsOffscreen (pPixmap) &&
94105b261ecSmrg	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
94205b261ecSmrg    {
9434642e01fSmrg	int nbox;
9444642e01fSmrg	BoxPtr pBox;
9454642e01fSmrg
9464642e01fSmrg	nbox = REGION_NUM_RECTS (pRegion);
9474642e01fSmrg	pBox = REGION_RECTS (pRegion);
9484642e01fSmrg
94905b261ecSmrg	while (nbox--)
95005b261ecSmrg	{
9514642e01fSmrg	    (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
9524642e01fSmrg				     pBox->y2);
95305b261ecSmrg	    pBox++;
95405b261ecSmrg	}
95505b261ecSmrg	(*pExaScr->info->DoneSolid) (pPixmap);
95605b261ecSmrg	exaMarkSync(pDrawable->pScreen);
9574642e01fSmrg
9584642e01fSmrg	if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) &&
9594642e01fSmrg	    pDrawable->width == 1 && pDrawable->height == 1 &&
9604642e01fSmrg	    pDrawable->bitsPerPixel != 24) {
9614642e01fSmrg	    ExaPixmapPriv(pPixmap);
9624642e01fSmrg
9634642e01fSmrg	    switch (pDrawable->bitsPerPixel) {
9644642e01fSmrg	    case 32:
9654642e01fSmrg		*(CARD32*)pExaPixmap->sys_ptr = pixel;
9664642e01fSmrg		break;
9674642e01fSmrg	    case 16:
9684642e01fSmrg		*(CARD16*)pExaPixmap->sys_ptr = pixel;
9694642e01fSmrg		break;
9704642e01fSmrg	    case 8:
9714642e01fSmrg		*(CARD8*)pExaPixmap->sys_ptr = pixel;
9724642e01fSmrg	    }
9734642e01fSmrg
9744642e01fSmrg	    REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
9754642e01fSmrg			 pRegion);
9764642e01fSmrg	}
9774642e01fSmrg
9784642e01fSmrg	ret = TRUE;
97905b261ecSmrg    }
98005b261ecSmrg
9814642e01fSmrgout:
9824642e01fSmrg    REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
9834642e01fSmrg
9844642e01fSmrg    return ret;
98505b261ecSmrg}
98605b261ecSmrg
98705b261ecSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
98805b261ecSmrg * Based on fbFillRegionTiled(), fbTile().
98905b261ecSmrg */
99005b261ecSmrgBool
99152397711SmrgexaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
99252397711Smrg		    DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
99352397711Smrg		    unsigned int clientClipType)
99405b261ecSmrg{
99505b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
99605b261ecSmrg    PixmapPtr pPixmap;
9974642e01fSmrg    ExaPixmapPrivPtr pExaPixmap;
9984642e01fSmrg    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
9994642e01fSmrg    int xoff, yoff;
100005b261ecSmrg    int tileWidth, tileHeight;
100105b261ecSmrg    ExaMigrationRec pixmaps[2];
100205b261ecSmrg    int nbox = REGION_NUM_RECTS (pRegion);
100305b261ecSmrg    BoxPtr pBox = REGION_RECTS (pRegion);
10044642e01fSmrg    Bool ret = FALSE;
10054642e01fSmrg    int i;
100605b261ecSmrg
100705b261ecSmrg    tileWidth = pTile->drawable.width;
100805b261ecSmrg    tileHeight = pTile->drawable.height;
100905b261ecSmrg
101005b261ecSmrg    /* If we're filling with a solid color, grab it out and go to
101105b261ecSmrg     * FillRegionSolid, saving numerous copies.
101205b261ecSmrg     */
101305b261ecSmrg    if (tileWidth == 1 && tileHeight == 1)
101405b261ecSmrg	return exaFillRegionSolid(pDrawable, pRegion,
101505b261ecSmrg				  exaGetPixmapFirstPixel (pTile), planemask,
101652397711Smrg				  alu, clientClipType);
101705b261ecSmrg
101805b261ecSmrg    pixmaps[0].as_dst = TRUE;
101905b261ecSmrg    pixmaps[0].as_src = FALSE;
102005b261ecSmrg    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
10214642e01fSmrg    pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
102252397711Smrg					    alu, clientClipType)
102352397711Smrg	? NULL : pRegion;
102405b261ecSmrg    pixmaps[1].as_dst = FALSE;
102505b261ecSmrg    pixmaps[1].as_src = TRUE;
102605b261ecSmrg    pixmaps[1].pPix = pTile;
10274642e01fSmrg    pixmaps[1].pReg = NULL;
102805b261ecSmrg
10294642e01fSmrg    pExaPixmap = ExaGetPixmapPriv (pPixmap);
10304642e01fSmrg
10314642e01fSmrg    if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked)
103205b261ecSmrg    {
10334642e01fSmrg	return FALSE;
103405b261ecSmrg    } else {
103505b261ecSmrg	exaDoMigration (pixmaps, 2, TRUE);
103605b261ecSmrg    }
103705b261ecSmrg
103805b261ecSmrg    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
103905b261ecSmrg
10404642e01fSmrg    if (!pPixmap || !exaPixmapIsOffscreen(pTile))
10414642e01fSmrg	return FALSE;
104205b261ecSmrg
10434642e01fSmrg    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
104405b261ecSmrg    {
10454642e01fSmrg	if (xoff || yoff)
10464642e01fSmrg	    REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
10474642e01fSmrg
10484642e01fSmrg	for (i = 0; i < nbox; i++)
104905b261ecSmrg	{
10504642e01fSmrg	    int height = pBox[i].y2 - pBox[i].y1;
10514642e01fSmrg	    int dstY = pBox[i].y1;
105205b261ecSmrg	    int tileY;
105305b261ecSmrg
10544642e01fSmrg	    if (alu == GXcopy)
10554642e01fSmrg		height = min(height, tileHeight);
10564642e01fSmrg
10574642e01fSmrg	    modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
105805b261ecSmrg
105905b261ecSmrg	    while (height > 0) {
10604642e01fSmrg		int width = pBox[i].x2 - pBox[i].x1;
10614642e01fSmrg		int dstX = pBox[i].x1;
106205b261ecSmrg		int tileX;
106305b261ecSmrg		int h = tileHeight - tileY;
106405b261ecSmrg
10654642e01fSmrg		if (alu == GXcopy)
10664642e01fSmrg		    width = min(width, tileWidth);
10674642e01fSmrg
106805b261ecSmrg		if (h > height)
106905b261ecSmrg		    h = height;
107005b261ecSmrg		height -= h;
107105b261ecSmrg
10724642e01fSmrg		modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
10734642e01fSmrg			tileX);
107405b261ecSmrg
107505b261ecSmrg		while (width > 0) {
107605b261ecSmrg		    int w = tileWidth - tileX;
107705b261ecSmrg		    if (w > width)
107805b261ecSmrg			w = width;
107905b261ecSmrg		    width -= w;
108005b261ecSmrg
10814642e01fSmrg		    (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
108205b261ecSmrg					    w, h);
108305b261ecSmrg		    dstX += w;
108405b261ecSmrg		    tileX = 0;
108505b261ecSmrg		}
108605b261ecSmrg		dstY += h;
108705b261ecSmrg		tileY = 0;
108805b261ecSmrg	    }
108905b261ecSmrg	}
109005b261ecSmrg	(*pExaScr->info->DoneCopy) (pPixmap);
109105b261ecSmrg
10924642e01fSmrg	/* With GXcopy, we only need to do the basic algorithm up to the tile
10934642e01fSmrg	 * size; then, we can just keep doubling the destination in each
10944642e01fSmrg	 * direction until it fills the box. This way, the number of copy
10954642e01fSmrg	 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
10964642e01fSmrg	 * rx/ry is the ratio between box and tile width/height. This can make
10974642e01fSmrg	 * a big difference if each driver copy incurs a significant constant
10984642e01fSmrg	 * overhead.
10994642e01fSmrg	 */
11004642e01fSmrg	if (alu != GXcopy)
11014642e01fSmrg	    ret = TRUE;
11024642e01fSmrg	else {
11034642e01fSmrg	    Bool more_copy = FALSE;
11044642e01fSmrg
11054642e01fSmrg	    for (i = 0; i < nbox; i++) {
11064642e01fSmrg		int dstX = pBox[i].x1 + tileWidth;
11074642e01fSmrg		int dstY = pBox[i].y1 + tileHeight;
11084642e01fSmrg
11094642e01fSmrg		if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
11104642e01fSmrg		    more_copy = TRUE;
11114642e01fSmrg		    break;
11124642e01fSmrg		}
11134642e01fSmrg	    }
111405b261ecSmrg
11154642e01fSmrg	    if (more_copy == FALSE)
11164642e01fSmrg		ret = TRUE;
111705b261ecSmrg
11184642e01fSmrg	    if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
11194642e01fSmrg							    1, 1, alu, planemask)) {
11204642e01fSmrg		for (i = 0; i < nbox; i++)
11214642e01fSmrg		{
11224642e01fSmrg		    int dstX = pBox[i].x1 + tileWidth;
11234642e01fSmrg		    int dstY = pBox[i].y1 + tileHeight;
11244642e01fSmrg		    int width = min(pBox[i].x2 - dstX, tileWidth);
11254642e01fSmrg		    int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
11264642e01fSmrg
11274642e01fSmrg		    while (dstX < pBox[i].x2) {
11284642e01fSmrg			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
11294642e01fSmrg						dstX, pBox[i].y1, width, height);
11304642e01fSmrg			dstX += width;
11314642e01fSmrg			width = min(pBox[i].x2 - dstX, width * 2);
11324642e01fSmrg		    }
113305b261ecSmrg
11344642e01fSmrg		    width = pBox[i].x2 - pBox[i].x1;
11354642e01fSmrg		    height = min(pBox[i].y2 - dstY, tileHeight);
113605b261ecSmrg
11374642e01fSmrg		    while (dstY < pBox[i].y2) {
11384642e01fSmrg			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
11394642e01fSmrg						pBox[i].x1, dstY, width, height);
11404642e01fSmrg			dstY += height;
11414642e01fSmrg			height = min(pBox[i].y2 - dstY, height * 2);
11424642e01fSmrg		    }
11434642e01fSmrg		}
114405b261ecSmrg
11454642e01fSmrg		(*pExaScr->info->DoneCopy) (pPixmap);
11464642e01fSmrg
11474642e01fSmrg		ret = TRUE;
11484642e01fSmrg	    }
11494642e01fSmrg	}
115005b261ecSmrg
11514642e01fSmrg	exaMarkSync(pDrawable->pScreen);
115205b261ecSmrg
11534642e01fSmrg	if (xoff || yoff)
11544642e01fSmrg	    REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
115505b261ecSmrg    }
11564642e01fSmrg
11574642e01fSmrg    return ret;
115805b261ecSmrg}
115905b261ecSmrg
11604642e01fSmrg
116105b261ecSmrg/**
116205b261ecSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
116305b261ecSmrg *
116405b261ecSmrg * This is probably the only case we actually care about.  The rest fall through
11654642e01fSmrg * to migration and fbGetImage, which hopefully will result in migration pushing
11664642e01fSmrg * the pixmap out of framebuffer.
116705b261ecSmrg */
116805b261ecSmrgvoid
116905b261ecSmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
117005b261ecSmrg	     unsigned int format, unsigned long planeMask, char *d)
117105b261ecSmrg{
117205b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
117305b261ecSmrg    ExaMigrationRec pixmaps[1];
11744642e01fSmrg    BoxRec Box;
11754642e01fSmrg    RegionRec Reg;
117605b261ecSmrg    PixmapPtr pPix;
117705b261ecSmrg    int xoff, yoff;
117805b261ecSmrg    Bool ok;
117905b261ecSmrg
11804642e01fSmrg    pixmaps[0].as_dst = FALSE;
11814642e01fSmrg    pixmaps[0].as_src = TRUE;
11824642e01fSmrg    pixmaps[0].pPix = pPix = exaGetDrawablePixmap (pDrawable);
11834642e01fSmrg    pixmaps[0].pReg = &Reg;
11844642e01fSmrg
11854642e01fSmrg    exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff);
11864642e01fSmrg
11874642e01fSmrg    Box.x1 = pDrawable->y + x + xoff;
11884642e01fSmrg    Box.y1 = pDrawable->y + y + yoff;
11894642e01fSmrg    Box.x2 = Box.x1 + w;
11904642e01fSmrg    Box.y2 = Box.y1 + h;
11914642e01fSmrg
11924642e01fSmrg    REGION_INIT(pScreen, &Reg, &Box, 1);
11934642e01fSmrg
11944642e01fSmrg    if (pExaScr->swappedOut)
119505b261ecSmrg	goto fallback;
119605b261ecSmrg
11974642e01fSmrg    exaDoMigration(pixmaps, 1, FALSE);
11984642e01fSmrg
11994642e01fSmrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
12004642e01fSmrg
12014642e01fSmrg    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
12024642e01fSmrg	goto fallback;
120305b261ecSmrg
120405b261ecSmrg    /* Only cover the ZPixmap, solid copy case. */
120505b261ecSmrg    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
12064642e01fSmrg	goto fallback;
120705b261ecSmrg
120805b261ecSmrg    /* Only try to handle the 8bpp and up cases, since we don't want to think
120905b261ecSmrg     * about <8bpp.
121005b261ecSmrg     */
121105b261ecSmrg    if (pDrawable->bitsPerPixel < 8)
121205b261ecSmrg	goto fallback;
121305b261ecSmrg
12144642e01fSmrg    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
12154642e01fSmrg					   pDrawable->y + y + yoff, w, h, d,
121605b261ecSmrg					   PixmapBytePad(w, pDrawable->depth));
121705b261ecSmrg    if (ok) {
121805b261ecSmrg	exaWaitSync(pDrawable->pScreen);
12194642e01fSmrg	goto out;
122005b261ecSmrg    }
122105b261ecSmrg
122205b261ecSmrgfallback:
12234642e01fSmrg    EXA_FALLBACK(("from %p (%c)\n", pDrawable,
12244642e01fSmrg		  exaDrawableLocation(pDrawable)));
122505b261ecSmrg
12264642e01fSmrg    exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg);
12274642e01fSmrg    fbGetImage (pDrawable, x, y, w, h, format, planeMask, d);
12284642e01fSmrg    exaFinishAccess (pDrawable, EXA_PREPARE_SRC);
122905b261ecSmrg
12304642e01fSmrgout:
12314642e01fSmrg    REGION_UNINIT(pScreen, &Reg);
123205b261ecSmrg}
1233