exa_accel.c revision 4202a189
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
544202a189Smrg    if (pExaScr->fallback_counter ||
554202a189Smrg	pExaScr->swappedOut ||
5605b261ecSmrg	pGC->fillStyle != FillSolid ||
574642e01fSmrg	pExaPixmap->accel_blocked)
5805b261ecSmrg    {
5905b261ecSmrg	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
6005b261ecSmrg	return;
614202a189Smrg    }
624202a189Smrg
634202a189Smrg    if (pExaScr->do_migration) {
644202a189Smrg	ExaMigrationRec pixmaps[1];
654202a189Smrg
664202a189Smrg	pixmaps[0].as_dst = TRUE;
674202a189Smrg	pixmaps[0].as_src = FALSE;
684202a189Smrg	pixmaps[0].pPix = pPixmap;
694202a189Smrg	pixmaps[0].pReg = NULL;
704202a189Smrg
7105b261ecSmrg	exaDoMigration (pixmaps, 1, TRUE);
7205b261ecSmrg    }
7305b261ecSmrg
7405b261ecSmrg    if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
7505b261ecSmrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
7605b261ecSmrg					 pGC->alu,
7705b261ecSmrg					 pGC->planemask,
7805b261ecSmrg					 pGC->fgPixel))
7905b261ecSmrg    {
8005b261ecSmrg	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
8105b261ecSmrg	return;
8205b261ecSmrg    }
8305b261ecSmrg
844202a189Smrg    pextent = RegionExtents(pClip);
8505b261ecSmrg    extentX1 = pextent->x1;
8605b261ecSmrg    extentY1 = pextent->y1;
8705b261ecSmrg    extentX2 = pextent->x2;
8805b261ecSmrg    extentY2 = pextent->y2;
8905b261ecSmrg    while (n--)
9005b261ecSmrg    {
9105b261ecSmrg	fullX1 = ppt->x;
9205b261ecSmrg	fullY1 = ppt->y;
9305b261ecSmrg	fullX2 = fullX1 + (int) *pwidth;
9405b261ecSmrg	ppt++;
9505b261ecSmrg	pwidth++;
9605b261ecSmrg
9705b261ecSmrg	if (fullY1 < extentY1 || extentY2 <= fullY1)
9805b261ecSmrg	    continue;
9905b261ecSmrg
10005b261ecSmrg	if (fullX1 < extentX1)
10105b261ecSmrg	    fullX1 = extentX1;
10205b261ecSmrg
10305b261ecSmrg	if (fullX2 > extentX2)
10405b261ecSmrg	    fullX2 = extentX2;
10505b261ecSmrg
10605b261ecSmrg	if (fullX1 >= fullX2)
10705b261ecSmrg	    continue;
10805b261ecSmrg
1094202a189Smrg	nbox = RegionNumRects (pClip);
11005b261ecSmrg	if (nbox == 1)
11105b261ecSmrg	{
11205b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
11305b261ecSmrg				     fullX1 + off_x, fullY1 + off_y,
11405b261ecSmrg				     fullX2 + off_x, fullY1 + 1 + off_y);
11505b261ecSmrg	}
11605b261ecSmrg	else
11705b261ecSmrg	{
1184202a189Smrg	    pbox = RegionRects(pClip);
11905b261ecSmrg	    while(nbox--)
12005b261ecSmrg	    {
12105b261ecSmrg		if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
12205b261ecSmrg		{
12305b261ecSmrg		    partX1 = pbox->x1;
12405b261ecSmrg		    if (partX1 < fullX1)
12505b261ecSmrg			partX1 = fullX1;
12605b261ecSmrg		    partX2 = pbox->x2;
12705b261ecSmrg		    if (partX2 > fullX2)
12805b261ecSmrg			partX2 = fullX2;
12905b261ecSmrg		    if (partX2 > partX1) {
13005b261ecSmrg			(*pExaScr->info->Solid) (pPixmap,
13105b261ecSmrg						 partX1 + off_x, fullY1 + off_y,
13205b261ecSmrg						 partX2 + off_x, fullY1 + 1 + off_y);
13305b261ecSmrg		    }
13405b261ecSmrg		}
13505b261ecSmrg		pbox++;
13605b261ecSmrg	    }
13705b261ecSmrg	}
13805b261ecSmrg    }
13905b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
14005b261ecSmrg    exaMarkSync(pScreen);
14105b261ecSmrg}
14205b261ecSmrg
1434642e01fSmrgstatic Bool
1444642e01fSmrgexaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
1454642e01fSmrg	       int w, int h, int format, char *bits, int src_stride)
14605b261ecSmrg{
14705b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
1484642e01fSmrg    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
1494642e01fSmrg    ExaPixmapPriv(pPix);
15005b261ecSmrg    RegionPtr pClip;
15105b261ecSmrg    BoxPtr pbox;
15205b261ecSmrg    int nbox;
15305b261ecSmrg    int xoff, yoff;
1544642e01fSmrg    int bpp = pDrawable->bitsPerPixel;
1554202a189Smrg    Bool ret = TRUE;
15605b261ecSmrg
1574202a189Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen)
1584202a189Smrg	return FALSE;
1594202a189Smrg
1604202a189Smrg    /* If there's a system copy, we want to save the result there */
1614202a189Smrg    if (pExaPixmap->pDamage)
1624642e01fSmrg	return FALSE;
16305b261ecSmrg
16405b261ecSmrg    /* Don't bother with under 8bpp, XYPixmaps. */
16505b261ecSmrg    if (format != ZPixmap || bpp < 8)
1664642e01fSmrg	return FALSE;
16705b261ecSmrg
16805b261ecSmrg    /* Only accelerate copies: no rop or planemask. */
16905b261ecSmrg    if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
1704642e01fSmrg	return FALSE;
17105b261ecSmrg
17205b261ecSmrg    if (pExaScr->swappedOut)
1734642e01fSmrg	return FALSE;
17405b261ecSmrg
1754202a189Smrg    if (pExaScr->do_migration) {
1764642e01fSmrg	ExaMigrationRec pixmaps[1];
17705b261ecSmrg
1784202a189Smrg	pixmaps[0].as_dst = TRUE;
1794642e01fSmrg	pixmaps[0].as_src = FALSE;
1804642e01fSmrg	pixmaps[0].pPix = pPix;
1814642e01fSmrg	pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
1824642e01fSmrg
1834642e01fSmrg	exaDoMigration (pixmaps, 1, TRUE);
1844642e01fSmrg    }
18505b261ecSmrg
18605b261ecSmrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
18705b261ecSmrg
1884202a189Smrg    if (!pPix)
1894642e01fSmrg	return FALSE;
19005b261ecSmrg
19105b261ecSmrg    x += pDrawable->x;
19205b261ecSmrg    y += pDrawable->y;
19305b261ecSmrg
19405b261ecSmrg    pClip = fbGetCompositeClip(pGC);
1954202a189Smrg    for (nbox = RegionNumRects(pClip),
1964202a189Smrg	 pbox = RegionRects(pClip);
19705b261ecSmrg	 nbox--;
19805b261ecSmrg	 pbox++)
19905b261ecSmrg    {
20005b261ecSmrg	int x1 = x;
20105b261ecSmrg	int y1 = y;
20205b261ecSmrg	int x2 = x + w;
20305b261ecSmrg	int y2 = y + h;
20405b261ecSmrg	char *src;
20505b261ecSmrg	Bool ok;
20605b261ecSmrg
20705b261ecSmrg	if (x1 < pbox->x1)
20805b261ecSmrg	    x1 = pbox->x1;
20905b261ecSmrg	if (y1 < pbox->y1)
21005b261ecSmrg	    y1 = pbox->y1;
21105b261ecSmrg	if (x2 > pbox->x2)
21205b261ecSmrg	    x2 = pbox->x2;
21305b261ecSmrg	if (y2 > pbox->y2)
21405b261ecSmrg	    y2 = pbox->y2;
21505b261ecSmrg	if (x1 >= x2 || y1 >= y2)
21605b261ecSmrg	    continue;
21705b261ecSmrg
21805b261ecSmrg	src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
21905b261ecSmrg	ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
22005b261ecSmrg					   x2 - x1, y2 - y1, src, src_stride);
2214202a189Smrg	/* We have to fall back completely, and ignore what has already been completed.
2224202a189Smrg	 * Messing with the fb layer directly like we used to is completely unacceptable.
22305b261ecSmrg	 */
22405b261ecSmrg	if (!ok) {
2254202a189Smrg	    ret = FALSE;
2264202a189Smrg	    break;
22705b261ecSmrg	}
22805b261ecSmrg    }
22905b261ecSmrg
2304202a189Smrg    if (ret)
2314642e01fSmrg	exaMarkSync(pDrawable->pScreen);
23205b261ecSmrg
2334202a189Smrg    return ret;
2344642e01fSmrg}
23505b261ecSmrg
2364642e01fSmrgstatic void
2374642e01fSmrgexaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
2384642e01fSmrg	     int w, int h, int leftPad, int format, char *bits)
2394642e01fSmrg{
2404642e01fSmrg    if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
2414642e01fSmrg		       PixmapBytePad(w, pDrawable->depth)))
2424642e01fSmrg	ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
2434642e01fSmrg			 bits);
24405b261ecSmrg}
24505b261ecSmrg
24605b261ecSmrgstatic Bool inline
24705b261ecSmrgexaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
24805b261ecSmrg		   GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
24905b261ecSmrg{
25005b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
25105b261ecSmrg    PixmapPtr pSrcPixmap, pDstPixmap;
25205b261ecSmrg    int src_off_x, src_off_y, dst_off_x, dst_off_y;
25305b261ecSmrg    int dirsetup;
25405b261ecSmrg
25505b261ecSmrg    /* Need to get both pixmaps to call the driver routines */
25605b261ecSmrg    pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
25705b261ecSmrg    pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
25805b261ecSmrg    if (!pSrcPixmap || !pDstPixmap)
25905b261ecSmrg	return FALSE;
26005b261ecSmrg
26105b261ecSmrg    /*
26205b261ecSmrg     * Now the case of a chip that only supports xdir = ydir = 1 or
26305b261ecSmrg     * xdir = ydir = -1, but we have xdir != ydir.
26405b261ecSmrg     */
26505b261ecSmrg    dirsetup = 0;	/* No direction set up yet. */
26605b261ecSmrg    for (; nbox; pbox++, nbox--) {
26705b261ecSmrg	if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
26805b261ecSmrg	    /* Do a xdir = ydir = -1 blit instead. */
26905b261ecSmrg	    if (dirsetup != -1) {
27005b261ecSmrg		if (dirsetup != 0)
27105b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
27205b261ecSmrg		dirsetup = -1;
27305b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
27405b261ecSmrg						   pDstPixmap,
27505b261ecSmrg						   -1, -1,
27605b261ecSmrg						   pGC ? pGC->alu : GXcopy,
27705b261ecSmrg						   pGC ? pGC->planemask :
27805b261ecSmrg							 FB_ALLONES))
27905b261ecSmrg		    return FALSE;
28005b261ecSmrg	    }
28105b261ecSmrg	    (*pExaScr->info->Copy)(pDstPixmap,
28205b261ecSmrg				   src_off_x + pbox->x1 + dx,
28305b261ecSmrg				   src_off_y + pbox->y1 + dy,
28405b261ecSmrg				   dst_off_x + pbox->x1,
28505b261ecSmrg				   dst_off_y + pbox->y1,
28605b261ecSmrg				   pbox->x2 - pbox->x1,
28705b261ecSmrg				   pbox->y2 - pbox->y1);
28805b261ecSmrg	} else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
28905b261ecSmrg	    /* Do a xdir = ydir = 1 blit instead. */
29005b261ecSmrg	    if (dirsetup != 1) {
29105b261ecSmrg		if (dirsetup != 0)
29205b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
29305b261ecSmrg		dirsetup = 1;
29405b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
29505b261ecSmrg						   pDstPixmap,
29605b261ecSmrg						   1, 1,
29705b261ecSmrg						   pGC ? pGC->alu : GXcopy,
29805b261ecSmrg						   pGC ? pGC->planemask :
29905b261ecSmrg							 FB_ALLONES))
30005b261ecSmrg		    return FALSE;
30105b261ecSmrg	    }
30205b261ecSmrg	    (*pExaScr->info->Copy)(pDstPixmap,
30305b261ecSmrg				   src_off_x + pbox->x1 + dx,
30405b261ecSmrg				   src_off_y + pbox->y1 + dy,
30505b261ecSmrg				   dst_off_x + pbox->x1,
30605b261ecSmrg				   dst_off_y + pbox->y1,
30705b261ecSmrg				   pbox->x2 - pbox->x1,
30805b261ecSmrg				   pbox->y2 - pbox->y1);
30905b261ecSmrg	} else if (dx >= 0) {
31005b261ecSmrg	    /*
31105b261ecSmrg	     * xdir = 1, ydir = -1.
31205b261ecSmrg	     * Perform line-by-line xdir = ydir = 1 blits, going up.
31305b261ecSmrg	     */
31405b261ecSmrg	    int i;
31505b261ecSmrg	    if (dirsetup != 1) {
31605b261ecSmrg		if (dirsetup != 0)
31705b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
31805b261ecSmrg		dirsetup = 1;
31905b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
32005b261ecSmrg						   pDstPixmap,
32105b261ecSmrg						   1, 1,
32205b261ecSmrg						   pGC ? pGC->alu : GXcopy,
32305b261ecSmrg						   pGC ? pGC->planemask :
32405b261ecSmrg							 FB_ALLONES))
32505b261ecSmrg		    return FALSE;
32605b261ecSmrg	    }
32705b261ecSmrg	    for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
32805b261ecSmrg		(*pExaScr->info->Copy)(pDstPixmap,
32905b261ecSmrg				       src_off_x + pbox->x1 + dx,
33005b261ecSmrg				       src_off_y + pbox->y1 + dy + i,
33105b261ecSmrg				       dst_off_x + pbox->x1,
33205b261ecSmrg				       dst_off_y + pbox->y1 + i,
33305b261ecSmrg				       pbox->x2 - pbox->x1, 1);
33405b261ecSmrg	} else {
33505b261ecSmrg	    /*
33605b261ecSmrg	     * xdir = -1, ydir = 1.
33705b261ecSmrg	     * Perform line-by-line xdir = ydir = -1 blits, going down.
33805b261ecSmrg	     */
33905b261ecSmrg	    int i;
34005b261ecSmrg	    if (dirsetup != -1) {
34105b261ecSmrg		if (dirsetup != 0)
34205b261ecSmrg		    pExaScr->info->DoneCopy(pDstPixmap);
34305b261ecSmrg		dirsetup = -1;
34405b261ecSmrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
34505b261ecSmrg						   pDstPixmap,
34605b261ecSmrg						   -1, -1,
34705b261ecSmrg						   pGC ? pGC->alu : GXcopy,
34805b261ecSmrg						   pGC ? pGC->planemask :
34905b261ecSmrg							 FB_ALLONES))
35005b261ecSmrg		    return FALSE;
35105b261ecSmrg	    }
35205b261ecSmrg	    for (i = 0; i < pbox->y2 - pbox->y1; i++)
35305b261ecSmrg		(*pExaScr->info->Copy)(pDstPixmap,
35405b261ecSmrg				       src_off_x + pbox->x1 + dx,
35505b261ecSmrg				       src_off_y + pbox->y1 + dy + i,
35605b261ecSmrg				       dst_off_x + pbox->x1,
35705b261ecSmrg				       dst_off_y + pbox->y1 + i,
35805b261ecSmrg				       pbox->x2 - pbox->x1, 1);
35905b261ecSmrg	}
36005b261ecSmrg    }
36105b261ecSmrg    if (dirsetup != 0)
36205b261ecSmrg	pExaScr->info->DoneCopy(pDstPixmap);
36305b261ecSmrg    exaMarkSync(pDstDrawable->pScreen);
36405b261ecSmrg    return TRUE;
36505b261ecSmrg}
36605b261ecSmrg
3674202a189SmrgBool
3684202a189SmrgexaHWCopyNtoN (DrawablePtr    pSrcDrawable,
36905b261ecSmrg	     DrawablePtr    pDstDrawable,
37005b261ecSmrg	     GCPtr	    pGC,
37105b261ecSmrg	     BoxPtr	    pbox,
37205b261ecSmrg	     int	    nbox,
37305b261ecSmrg	     int	    dx,
37405b261ecSmrg	     int	    dy,
37505b261ecSmrg	     Bool	    reverse,
3764202a189Smrg	     Bool	    upsidedown)
37705b261ecSmrg{
37805b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
37905b261ecSmrg    PixmapPtr pSrcPixmap, pDstPixmap;
3804642e01fSmrg    ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
38105b261ecSmrg    int	    src_off_x, src_off_y;
38205b261ecSmrg    int	    dst_off_x, dst_off_y;
3834642e01fSmrg    RegionPtr srcregion = NULL, dstregion = NULL;
3844642e01fSmrg    xRectangle *rects;
3854202a189Smrg    Bool ret = TRUE;
3864642e01fSmrg
3874642e01fSmrg    /* avoid doing copy operations if no boxes */
3884642e01fSmrg    if (nbox == 0)
3894202a189Smrg	return TRUE;
3904642e01fSmrg
3914642e01fSmrg    pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
3924642e01fSmrg    pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
3934642e01fSmrg
3944642e01fSmrg    exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
3954642e01fSmrg    exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
3964642e01fSmrg
3974202a189Smrg    rects = malloc(nbox * sizeof(xRectangle));
3984642e01fSmrg
3994642e01fSmrg    if (rects) {
4004642e01fSmrg	int i;
4017b683adcSmrg	int ordering;
4024642e01fSmrg
4034642e01fSmrg	for (i = 0; i < nbox; i++) {
4044642e01fSmrg	    rects[i].x = pbox[i].x1 + dx + src_off_x;
4054642e01fSmrg	    rects[i].y = pbox[i].y1 + dy + src_off_y;
4064642e01fSmrg	    rects[i].width = pbox[i].x2 - pbox[i].x1;
4074642e01fSmrg	    rects[i].height = pbox[i].y2 - pbox[i].y1;
4084642e01fSmrg	}
4094642e01fSmrg
4104202a189Smrg	/* This must match the RegionCopy() logic for reversing rect order */
4117b683adcSmrg	if (nbox == 1 || (dx > 0 && dy > 0) ||
4127b683adcSmrg	    (pDstDrawable != pSrcDrawable &&
4137b683adcSmrg	     (pDstDrawable->type != DRAWABLE_WINDOW ||
4147b683adcSmrg	      pSrcDrawable->type != DRAWABLE_WINDOW)))
4157b683adcSmrg	    ordering = CT_YXBANDED;
4167b683adcSmrg	else
4177b683adcSmrg	    ordering = CT_UNSORTED;
4187b683adcSmrg
4194202a189Smrg	srcregion  = RegionFromRects(nbox, rects, ordering);
4204202a189Smrg	free(rects);
4214642e01fSmrg
4224642e01fSmrg	if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
42352397711Smrg					   pGC->fillStyle, pGC->alu,
42452397711Smrg					   pGC->clientClipType)) {
4254202a189Smrg	    dstregion = RegionCreate(NullBox, 0);
4264202a189Smrg	    RegionCopy(dstregion, srcregion);
4274202a189Smrg	    RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
4284642e01fSmrg			     dst_off_y - dy - src_off_y);
4294642e01fSmrg	}
4304642e01fSmrg    }
43105b261ecSmrg
43205b261ecSmrg
4334642e01fSmrg    pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap);
4344642e01fSmrg    pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
4354642e01fSmrg
4364642e01fSmrg    /* Check whether the accelerator can use this pixmap.
4374642e01fSmrg     * If the pitch of the pixmaps is out of range, there's nothing
4384642e01fSmrg     * we can do but fall back to software rendering.
43905b261ecSmrg     */
4404642e01fSmrg    if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
4414642e01fSmrg        pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
4424642e01fSmrg	goto fallback;
4434642e01fSmrg
4444642e01fSmrg    /* If the width or the height of either of the pixmaps
4454642e01fSmrg     * is out of range, check whether the boxes are actually out of the
4464642e01fSmrg     * addressable range as well. If they aren't, we can still do
4474642e01fSmrg     * the copying in hardware.
4484642e01fSmrg     */
4494642e01fSmrg    if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
4504642e01fSmrg        int i;
4514642e01fSmrg
4524642e01fSmrg        for (i = 0; i < nbox; i++) {
4534642e01fSmrg            /* src */
4544642e01fSmrg            if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
4554642e01fSmrg                (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
4564642e01fSmrg                goto fallback;
4574642e01fSmrg
4584642e01fSmrg            /* dst */
4594642e01fSmrg            if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
4604642e01fSmrg                (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
4614642e01fSmrg                goto fallback;
4624642e01fSmrg        }
46305b261ecSmrg    }
46405b261ecSmrg
4654202a189Smrg    if (pExaScr->do_migration) {
4664202a189Smrg	ExaMigrationRec pixmaps[2];
4674202a189Smrg
4684202a189Smrg	pixmaps[0].as_dst = TRUE;
4694202a189Smrg	pixmaps[0].as_src = FALSE;
4704202a189Smrg	pixmaps[0].pPix = pDstPixmap;
4714202a189Smrg	pixmaps[0].pReg = dstregion;
4724202a189Smrg	pixmaps[1].as_dst = FALSE;
4734202a189Smrg	pixmaps[1].as_src = TRUE;
4744202a189Smrg	pixmaps[1].pPix = pSrcPixmap;
4754202a189Smrg	pixmaps[1].pReg = srcregion;
4764202a189Smrg
4774202a189Smrg	exaDoMigration (pixmaps, 2, TRUE);
4784202a189Smrg    }
4794642e01fSmrg
48005b261ecSmrg    /* Mixed directions must be handled specially if the card is lame */
4814642e01fSmrg    if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
48205b261ecSmrg	reverse != upsidedown) {
48305b261ecSmrg	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
48405b261ecSmrg			       dx, dy))
4854642e01fSmrg	    goto out;
4864642e01fSmrg	goto fallback;
48705b261ecSmrg    }
48805b261ecSmrg
4894202a189Smrg    if (exaPixmapHasGpuCopy(pDstPixmap)) {
4904202a189Smrg	/* Normal blitting. */
4914202a189Smrg	if (exaPixmapHasGpuCopy(pSrcPixmap)) {
4924202a189Smrg	    if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
4934202a189Smrg						upsidedown ? -1 : 1,
4944202a189Smrg						pGC ? pGC->alu : GXcopy,
4954202a189Smrg						pGC ? pGC->planemask : FB_ALLONES)) {
4964202a189Smrg		goto fallback;
4974202a189Smrg	    }
49805b261ecSmrg
4994202a189Smrg	    while (nbox--)
5004202a189Smrg	    {
5014202a189Smrg		(*pExaScr->info->Copy) (pDstPixmap,
5024202a189Smrg					pbox->x1 + dx + src_off_x,
5034202a189Smrg					pbox->y1 + dy + src_off_y,
5044202a189Smrg					pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
5054202a189Smrg					pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
5064202a189Smrg		pbox++;
5074202a189Smrg	    }
5084202a189Smrg
5094202a189Smrg	    (*pExaScr->info->DoneCopy) (pDstPixmap);
5104202a189Smrg	    exaMarkSync (pDstDrawable->pScreen);
5114202a189Smrg	/* UTS: mainly for SHM PutImage's secondary path.
5124202a189Smrg	 *
5134202a189Smrg	 * Only taking this path for directly accessible pixmaps.
5144202a189Smrg	 */
5154202a189Smrg	} else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
5164202a189Smrg	    int bpp = pSrcDrawable->bitsPerPixel;
5174202a189Smrg	    int src_stride = exaGetPixmapPitch(pSrcPixmap);
5184202a189Smrg	    CARD8 *src = NULL;
5194202a189Smrg
5204202a189Smrg	    if (!pExaScr->info->UploadToScreen)
5214202a189Smrg		goto fallback;
52205b261ecSmrg
5234202a189Smrg	    if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
5244202a189Smrg		goto fallback;
5254202a189Smrg
5264202a189Smrg	    if (pSrcDrawable->bitsPerPixel < 8)
5274202a189Smrg		goto fallback;
5284202a189Smrg
5294202a189Smrg	    if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable,  pGC->planemask)))
5304202a189Smrg		goto fallback;
5314202a189Smrg
5324202a189Smrg	    while (nbox--)
5334202a189Smrg	    {
5344202a189Smrg		src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8);
5354202a189Smrg		if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
5364202a189Smrg				pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
5374202a189Smrg				(char *) src, src_stride))
5384202a189Smrg		    goto fallback;
5394202a189Smrg
5404202a189Smrg		pbox++;
5414202a189Smrg	    }
5424202a189Smrg	} else
5434202a189Smrg	    goto fallback;
5444202a189Smrg    } else
5454202a189Smrg	goto fallback;
5464642e01fSmrg
5474642e01fSmrg    goto out;
5484642e01fSmrg
5494642e01fSmrgfallback:
5504202a189Smrg    ret = FALSE;
5514642e01fSmrg
5524642e01fSmrgout:
5534642e01fSmrg    if (dstregion) {
5544202a189Smrg	RegionUninit(dstregion);
5554202a189Smrg	RegionDestroy(dstregion);
5564642e01fSmrg    }
5574642e01fSmrg    if (srcregion) {
5584202a189Smrg	RegionUninit(srcregion);
5594202a189Smrg	RegionDestroy(srcregion);
5604642e01fSmrg    }
5614202a189Smrg
5624202a189Smrg    return ret;
5634202a189Smrg}
5644202a189Smrg
5654202a189Smrgvoid
5664202a189SmrgexaCopyNtoN (DrawablePtr    pSrcDrawable,
5674202a189Smrg	     DrawablePtr    pDstDrawable,
5684202a189Smrg	     GCPtr	    pGC,
5694202a189Smrg	     BoxPtr	    pbox,
5704202a189Smrg	     int	    nbox,
5714202a189Smrg	     int	    dx,
5724202a189Smrg	     int	    dy,
5734202a189Smrg	     Bool	    reverse,
5744202a189Smrg	     Bool	    upsidedown,
5754202a189Smrg	     Pixel	    bitplane,
5764202a189Smrg	     void	    *closure)
5774202a189Smrg{
5784202a189Smrg    ExaScreenPriv(pDstDrawable->pScreen);
5794202a189Smrg
5804202a189Smrg    if (pExaScr->fallback_counter ||
5814202a189Smrg	    (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
5824202a189Smrg	return;
5834202a189Smrg
5844202a189Smrg    if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown))
5854202a189Smrg	return;
5864202a189Smrg
5874202a189Smrg    /* This is a CopyWindow, it's cleaner to fallback at the original call. */
5884202a189Smrg    if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
5894202a189Smrg	pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
5904202a189Smrg	return;
5914202a189Smrg    }
5924202a189Smrg
5934202a189Smrg    /* fallback */
5944202a189Smrg    ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
59505b261ecSmrg}
59605b261ecSmrg
59705b261ecSmrgRegionPtr
59805b261ecSmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
59905b261ecSmrg	    int srcx, int srcy, int width, int height, int dstx, int dsty)
60005b261ecSmrg{
60105b261ecSmrg    ExaScreenPriv (pDstDrawable->pScreen);
60205b261ecSmrg
6034202a189Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut) {
60405b261ecSmrg        return  ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
60505b261ecSmrg                                 srcx, srcy, width, height, dstx, dsty);
60605b261ecSmrg    }
60705b261ecSmrg
6084202a189Smrg    return  miDoCopy (pSrcDrawable, pDstDrawable, pGC,
60905b261ecSmrg                      srcx, srcy, width, height,
61005b261ecSmrg                      dstx, dsty, exaCopyNtoN, 0, NULL);
61105b261ecSmrg}
61205b261ecSmrg
61305b261ecSmrgstatic void
61405b261ecSmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
61505b261ecSmrg	     DDXPointPtr ppt)
61605b261ecSmrg{
6174202a189Smrg    ExaScreenPriv (pDrawable->pScreen);
61805b261ecSmrg    int i;
61905b261ecSmrg    xRectangle *prect;
62005b261ecSmrg
62105b261ecSmrg    /* If we can't reuse the current GC as is, don't bother accelerating the
62205b261ecSmrg     * points.
62305b261ecSmrg     */
6244202a189Smrg    if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) {
62505b261ecSmrg	ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
62605b261ecSmrg	return;
62705b261ecSmrg    }
62805b261ecSmrg
6294202a189Smrg    prect = malloc(sizeof(xRectangle) * npt);
63005b261ecSmrg    for (i = 0; i < npt; i++) {
63105b261ecSmrg	prect[i].x = ppt[i].x;
63205b261ecSmrg	prect[i].y = ppt[i].y;
63305b261ecSmrg	if (i > 0 && mode == CoordModePrevious) {
63405b261ecSmrg	    prect[i].x += prect[i - 1].x;
63505b261ecSmrg	    prect[i].y += prect[i - 1].y;
63605b261ecSmrg	}
63705b261ecSmrg	prect[i].width = 1;
63805b261ecSmrg	prect[i].height = 1;
63905b261ecSmrg    }
64005b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
6414202a189Smrg    free(prect);
64205b261ecSmrg}
64305b261ecSmrg
64405b261ecSmrg/**
64505b261ecSmrg * exaPolylines() 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
65005b261ecSmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
65105b261ecSmrg	     DDXPointPtr ppt)
65205b261ecSmrg{
6534202a189Smrg    ExaScreenPriv (pDrawable->pScreen);
65405b261ecSmrg    xRectangle *prect;
65505b261ecSmrg    int x1, x2, y1, y2;
65605b261ecSmrg    int i;
65705b261ecSmrg
6584202a189Smrg    if (pExaScr->fallback_counter) {
6594202a189Smrg	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
6604202a189Smrg	return;
6614202a189Smrg    }
6624202a189Smrg
66305b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
66405b261ecSmrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
66505b261ecSmrg	pGC->fillStyle != FillSolid) {
66605b261ecSmrg	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
66705b261ecSmrg	return;
66805b261ecSmrg    }
66905b261ecSmrg
6704202a189Smrg    prect = malloc(sizeof(xRectangle) * (npt - 1));
67105b261ecSmrg    x1 = ppt[0].x;
67205b261ecSmrg    y1 = ppt[0].y;
67305b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
67405b261ecSmrg    for (i = 0; i < npt - 1; i++) {
67505b261ecSmrg	if (mode == CoordModePrevious) {
67605b261ecSmrg	    x2 = x1 + ppt[i + 1].x;
67705b261ecSmrg	    y2 = y1 + ppt[i + 1].y;
67805b261ecSmrg	} else {
67905b261ecSmrg	    x2 = ppt[i + 1].x;
68005b261ecSmrg	    y2 = ppt[i + 1].y;
68105b261ecSmrg	}
68205b261ecSmrg
68305b261ecSmrg	if (x1 != x2 && y1 != y2) {
6844202a189Smrg	    free(prect);
68505b261ecSmrg	    ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
68605b261ecSmrg	    return;
68705b261ecSmrg	}
68805b261ecSmrg
68905b261ecSmrg	if (x1 < x2) {
69005b261ecSmrg	    prect[i].x = x1;
69105b261ecSmrg	    prect[i].width = x2 - x1 + 1;
69205b261ecSmrg	} else {
69305b261ecSmrg	    prect[i].x = x2;
69405b261ecSmrg	    prect[i].width = x1 - x2 + 1;
69505b261ecSmrg	}
69605b261ecSmrg	if (y1 < y2) {
69705b261ecSmrg	    prect[i].y = y1;
69805b261ecSmrg	    prect[i].height = y2 - y1 + 1;
69905b261ecSmrg	} else {
70005b261ecSmrg	    prect[i].y = y2;
70105b261ecSmrg	    prect[i].height = y1 - y2 + 1;
70205b261ecSmrg	}
70305b261ecSmrg
70405b261ecSmrg	x1 = x2;
70505b261ecSmrg	y1 = y2;
70605b261ecSmrg    }
70705b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
7084202a189Smrg    free(prect);
70905b261ecSmrg}
71005b261ecSmrg
71105b261ecSmrg/**
71205b261ecSmrg * exaPolySegment() checks if it can accelerate the lines as a group of
71305b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
71405b261ecSmrg * acceleration if so.
71505b261ecSmrg */
71605b261ecSmrgstatic void
71705b261ecSmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
71805b261ecSmrg		xSegment *pSeg)
71905b261ecSmrg{
7204202a189Smrg    ExaScreenPriv (pDrawable->pScreen);
72105b261ecSmrg    xRectangle *prect;
72205b261ecSmrg    int i;
72305b261ecSmrg
72405b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
7254202a189Smrg    if (pExaScr->fallback_counter || pGC->lineWidth != 0 ||
7264202a189Smrg	pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid)
72705b261ecSmrg    {
72805b261ecSmrg	ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
72905b261ecSmrg	return;
73005b261ecSmrg    }
73105b261ecSmrg
73205b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
73305b261ecSmrg    for (i = 0; i < nseg; i++) {
73405b261ecSmrg	if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
73505b261ecSmrg	    ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
73605b261ecSmrg	    return;
73705b261ecSmrg	}
73805b261ecSmrg    }
73905b261ecSmrg
7404202a189Smrg    prect = malloc(sizeof(xRectangle) * nseg);
74105b261ecSmrg    for (i = 0; i < nseg; i++) {
74205b261ecSmrg	if (pSeg[i].x1 < pSeg[i].x2) {
74305b261ecSmrg	    prect[i].x = pSeg[i].x1;
74405b261ecSmrg	    prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
74505b261ecSmrg	} else {
74605b261ecSmrg	    prect[i].x = pSeg[i].x2;
74705b261ecSmrg	    prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
74805b261ecSmrg	}
74905b261ecSmrg	if (pSeg[i].y1 < pSeg[i].y2) {
75005b261ecSmrg	    prect[i].y = pSeg[i].y1;
75105b261ecSmrg	    prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
75205b261ecSmrg	} else {
75305b261ecSmrg	    prect[i].y = pSeg[i].y2;
75405b261ecSmrg	    prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
75505b261ecSmrg	}
7564642e01fSmrg
7574642e01fSmrg	/* don't paint last pixel */
7584642e01fSmrg	if (pGC->capStyle == CapNotLast) {
7594642e01fSmrg	    if (prect[i].width == 1)
7604642e01fSmrg		prect[i].height--;
7614642e01fSmrg	    else
7624642e01fSmrg		prect[i].width--;
7634642e01fSmrg	}
76405b261ecSmrg    }
76505b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
7664202a189Smrg    free(prect);
76705b261ecSmrg}
76805b261ecSmrg
76905b261ecSmrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
77052397711Smrg				Pixel pixel, CARD32 planemask, CARD32 alu,
77152397711Smrg				unsigned int clientClipType);
77205b261ecSmrg
77305b261ecSmrgstatic void
77405b261ecSmrgexaPolyFillRect(DrawablePtr pDrawable,
77505b261ecSmrg		GCPtr	    pGC,
77605b261ecSmrg		int	    nrect,
77705b261ecSmrg		xRectangle  *prect)
77805b261ecSmrg{
77905b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
78005b261ecSmrg    RegionPtr	    pClip = fbGetCompositeClip(pGC);
78105b261ecSmrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
7824642e01fSmrg    ExaPixmapPriv (pPixmap);
78305b261ecSmrg    register BoxPtr pbox;
78405b261ecSmrg    BoxPtr	    pextent;
78505b261ecSmrg    int		    extentX1, extentX2, extentY1, extentY2;
78605b261ecSmrg    int		    fullX1, fullX2, fullY1, fullY2;
78705b261ecSmrg    int		    partX1, partX2, partY1, partY2;
78805b261ecSmrg    int		    xoff, yoff;
78905b261ecSmrg    int		    xorg, yorg;
79005b261ecSmrg    int		    n;
7914202a189Smrg    RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
79205b261ecSmrg
79305b261ecSmrg    /* Compute intersection of rects and clip region */
7944202a189Smrg    RegionTranslate(pReg, pDrawable->x, pDrawable->y);
7954202a189Smrg    RegionIntersect(pReg, pClip, pReg);
79605b261ecSmrg
7974202a189Smrg    if (!RegionNumRects(pReg)) {
79805b261ecSmrg	goto out;
79905b261ecSmrg    }
80005b261ecSmrg
80105b261ecSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
80205b261ecSmrg
8034202a189Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut ||
8044202a189Smrg	    pExaPixmap->accel_blocked)
80505b261ecSmrg    {
80605b261ecSmrg	goto fallback;
80705b261ecSmrg    }
80805b261ecSmrg
80905b261ecSmrg    /* For ROPs where overlaps don't matter, convert rectangles to region and
81005b261ecSmrg     * call exaFillRegion{Solid,Tiled}.
81105b261ecSmrg     */
81205b261ecSmrg    if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
8134642e01fSmrg	(nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
8144642e01fSmrg	 pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
8154642e01fSmrg	 pGC->alu == GXset)) {
81605b261ecSmrg	if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
81705b261ecSmrg	     exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
81805b261ecSmrg				pGC->fgPixel : pGC->tile.pixel,	pGC->planemask,
81952397711Smrg				pGC->alu, pGC->clientClipType)) ||
82005b261ecSmrg	    (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
82105b261ecSmrg	     exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
82252397711Smrg				pGC->planemask, pGC->alu,
82352397711Smrg				pGC->clientClipType))) {
82405b261ecSmrg	    goto out;
82505b261ecSmrg	}
82605b261ecSmrg    }
82705b261ecSmrg
82805b261ecSmrg    if (pGC->fillStyle != FillSolid &&
82905b261ecSmrg	!(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
83005b261ecSmrg    {
83105b261ecSmrg	goto fallback;
83205b261ecSmrg    }
83305b261ecSmrg
8344202a189Smrg    if (pExaScr->do_migration) {
8354202a189Smrg	ExaMigrationRec pixmaps[1];
8364202a189Smrg
8374202a189Smrg	pixmaps[0].as_dst = TRUE;
8384202a189Smrg	pixmaps[0].as_src = FALSE;
8394202a189Smrg	pixmaps[0].pPix = pPixmap;
8404202a189Smrg	pixmaps[0].pReg = NULL;
84105b261ecSmrg
8424202a189Smrg	exaDoMigration (pixmaps, 1, TRUE);
8434202a189Smrg    }
8444202a189Smrg
8454202a189Smrg    if (!exaPixmapHasGpuCopy (pPixmap) ||
84605b261ecSmrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
84705b261ecSmrg					 pGC->alu,
84805b261ecSmrg					 pGC->planemask,
84905b261ecSmrg					 pGC->fgPixel))
85005b261ecSmrg    {
85105b261ecSmrgfallback:
85205b261ecSmrg	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
85305b261ecSmrg	goto out;
85405b261ecSmrg    }
85505b261ecSmrg
85605b261ecSmrg    xorg = pDrawable->x;
85705b261ecSmrg    yorg = pDrawable->y;
85805b261ecSmrg
8594202a189Smrg    pextent = RegionExtents(pClip);
86005b261ecSmrg    extentX1 = pextent->x1;
86105b261ecSmrg    extentY1 = pextent->y1;
86205b261ecSmrg    extentX2 = pextent->x2;
86305b261ecSmrg    extentY2 = pextent->y2;
86405b261ecSmrg    while (nrect--)
86505b261ecSmrg    {
86605b261ecSmrg	fullX1 = prect->x + xorg;
86705b261ecSmrg	fullY1 = prect->y + yorg;
86805b261ecSmrg	fullX2 = fullX1 + (int) prect->width;
86905b261ecSmrg	fullY2 = fullY1 + (int) prect->height;
87005b261ecSmrg	prect++;
87105b261ecSmrg
87205b261ecSmrg	if (fullX1 < extentX1)
87305b261ecSmrg	    fullX1 = extentX1;
87405b261ecSmrg
87505b261ecSmrg	if (fullY1 < extentY1)
87605b261ecSmrg	    fullY1 = extentY1;
87705b261ecSmrg
87805b261ecSmrg	if (fullX2 > extentX2)
87905b261ecSmrg	    fullX2 = extentX2;
88005b261ecSmrg
88105b261ecSmrg	if (fullY2 > extentY2)
88205b261ecSmrg	    fullY2 = extentY2;
88305b261ecSmrg
88405b261ecSmrg	if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
88505b261ecSmrg	    continue;
8864202a189Smrg	n = RegionNumRects (pClip);
88705b261ecSmrg	if (n == 1)
88805b261ecSmrg	{
88905b261ecSmrg	    (*pExaScr->info->Solid) (pPixmap,
89005b261ecSmrg				     fullX1 + xoff, fullY1 + yoff,
89105b261ecSmrg				     fullX2 + xoff, fullY2 + yoff);
89205b261ecSmrg	}
89305b261ecSmrg	else
89405b261ecSmrg	{
8954202a189Smrg	    pbox = RegionRects(pClip);
89605b261ecSmrg	    /*
89705b261ecSmrg	     * clip the rectangle to each box in the clip region
89805b261ecSmrg	     * this is logically equivalent to calling Intersect(),
89905b261ecSmrg	     * but rectangles may overlap each other here.
90005b261ecSmrg	     */
90105b261ecSmrg	    while(n--)
90205b261ecSmrg	    {
90305b261ecSmrg		partX1 = pbox->x1;
90405b261ecSmrg		if (partX1 < fullX1)
90505b261ecSmrg		    partX1 = fullX1;
90605b261ecSmrg		partY1 = pbox->y1;
90705b261ecSmrg		if (partY1 < fullY1)
90805b261ecSmrg		    partY1 = fullY1;
90905b261ecSmrg		partX2 = pbox->x2;
91005b261ecSmrg		if (partX2 > fullX2)
91105b261ecSmrg		    partX2 = fullX2;
91205b261ecSmrg		partY2 = pbox->y2;
91305b261ecSmrg		if (partY2 > fullY2)
91405b261ecSmrg		    partY2 = fullY2;
91505b261ecSmrg
91605b261ecSmrg		pbox++;
91705b261ecSmrg
91805b261ecSmrg		if (partX1 < partX2 && partY1 < partY2) {
91905b261ecSmrg		    (*pExaScr->info->Solid) (pPixmap,
92005b261ecSmrg					     partX1 + xoff, partY1 + yoff,
92105b261ecSmrg					     partX2 + xoff, partY2 + yoff);
92205b261ecSmrg		}
92305b261ecSmrg	    }
92405b261ecSmrg	}
92505b261ecSmrg    }
92605b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
92705b261ecSmrg    exaMarkSync(pDrawable->pScreen);
92805b261ecSmrg
92905b261ecSmrgout:
9304202a189Smrg    RegionUninit(pReg);
9314202a189Smrg    RegionDestroy(pReg);
93205b261ecSmrg}
93305b261ecSmrg
93405b261ecSmrgconst GCOps exaOps = {
93505b261ecSmrg    exaFillSpans,
93605b261ecSmrg    ExaCheckSetSpans,
93705b261ecSmrg    exaPutImage,
93805b261ecSmrg    exaCopyArea,
93905b261ecSmrg    ExaCheckCopyPlane,
94005b261ecSmrg    exaPolyPoint,
94105b261ecSmrg    exaPolylines,
94205b261ecSmrg    exaPolySegment,
94305b261ecSmrg    miPolyRectangle,
94405b261ecSmrg    ExaCheckPolyArc,
94505b261ecSmrg    miFillPolygon,
94605b261ecSmrg    exaPolyFillRect,
94705b261ecSmrg    miPolyFillArc,
94805b261ecSmrg    miPolyText8,
94905b261ecSmrg    miPolyText16,
95005b261ecSmrg    miImageText8,
95105b261ecSmrg    miImageText16,
9524642e01fSmrg    ExaCheckImageGlyphBlt,
95305b261ecSmrg    ExaCheckPolyGlyphBlt,
95405b261ecSmrg    ExaCheckPushPixels,
95505b261ecSmrg};
95605b261ecSmrg
95705b261ecSmrgvoid
95805b261ecSmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
95905b261ecSmrg{
96005b261ecSmrg    RegionRec	rgnDst;
96105b261ecSmrg    int		dx, dy;
96205b261ecSmrg    PixmapPtr	pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
9634202a189Smrg    ExaScreenPriv(pWin->drawable.pScreen);
96405b261ecSmrg
96505b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
96605b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
9674202a189Smrg    RegionTranslate(prgnSrc, -dx, -dy);
96805b261ecSmrg
9694202a189Smrg    RegionInit(&rgnDst, NullBox, 0);
97005b261ecSmrg
9714202a189Smrg    RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
97205b261ecSmrg#ifdef COMPOSITE
97305b261ecSmrg    if (pPixmap->screen_x || pPixmap->screen_y)
9744202a189Smrg	RegionTranslate(&rgnDst,
97505b261ecSmrg			  -pPixmap->screen_x, -pPixmap->screen_y);
97605b261ecSmrg#endif
97705b261ecSmrg
9784202a189Smrg    if (pExaScr->fallback_counter) {
9794202a189Smrg	pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
9804202a189Smrg	goto fallback;
9814202a189Smrg    }
9824202a189Smrg
9834202a189Smrg    pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
9844202a189Smrg    miCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
98505b261ecSmrg		  NULL,
98605b261ecSmrg		  &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
9874202a189Smrg    pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
98805b261ecSmrg
9894202a189Smrgfallback:
9904202a189Smrg    RegionUninit(&rgnDst);
9914202a189Smrg
9924202a189Smrg    if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
9934202a189Smrg	pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
9944202a189Smrg	RegionTranslate(prgnSrc, dx, dy);
9954202a189Smrg	ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
9964202a189Smrg    }
99705b261ecSmrg}
99805b261ecSmrg
99905b261ecSmrgstatic Bool
100052397711SmrgexaFillRegionSolid (DrawablePtr	pDrawable, RegionPtr pRegion, Pixel pixel,
100152397711Smrg		    CARD32 planemask, CARD32 alu, unsigned int clientClipType)
100205b261ecSmrg{
100305b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
10044642e01fSmrg    PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
10054642e01fSmrg    ExaPixmapPriv (pPixmap);
100605b261ecSmrg    int xoff, yoff;
10074642e01fSmrg    Bool ret = FALSE;
100805b261ecSmrg
10094642e01fSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
10104202a189Smrg    RegionTranslate(pRegion, xoff, yoff);
10114642e01fSmrg
10124202a189Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
10134642e01fSmrg	goto out;
10144202a189Smrg
10154202a189Smrg    if (pExaScr->do_migration) {
10164202a189Smrg	ExaMigrationRec pixmaps[1];
10174202a189Smrg
10184202a189Smrg	pixmaps[0].as_dst = TRUE;
10194202a189Smrg	pixmaps[0].as_src = FALSE;
10204202a189Smrg	pixmaps[0].pPix = pPixmap;
10214202a189Smrg	pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
10224202a189Smrg						alu, clientClipType) ? NULL : pRegion;
10234202a189Smrg
102405b261ecSmrg	exaDoMigration (pixmaps, 1, TRUE);
102505b261ecSmrg    }
102605b261ecSmrg
10274202a189Smrg    if (exaPixmapHasGpuCopy (pPixmap) &&
102805b261ecSmrg	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
102905b261ecSmrg    {
10304642e01fSmrg	int nbox;
10314642e01fSmrg	BoxPtr pBox;
10324642e01fSmrg
10334202a189Smrg	nbox = RegionNumRects (pRegion);
10344202a189Smrg	pBox = RegionRects (pRegion);
10354642e01fSmrg
103605b261ecSmrg	while (nbox--)
103705b261ecSmrg	{
10384642e01fSmrg	    (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
10394642e01fSmrg				     pBox->y2);
104005b261ecSmrg	    pBox++;
104105b261ecSmrg	}
104205b261ecSmrg	(*pExaScr->info->DoneSolid) (pPixmap);
104305b261ecSmrg	exaMarkSync(pDrawable->pScreen);
10444642e01fSmrg
10454202a189Smrg	if (pExaPixmap->pDamage &&
10464202a189Smrg	    pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
10474642e01fSmrg	    pDrawable->width == 1 && pDrawable->height == 1 &&
10484642e01fSmrg	    pDrawable->bitsPerPixel != 24) {
10494642e01fSmrg	    ExaPixmapPriv(pPixmap);
10504202a189Smrg	    RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
10514642e01fSmrg
10524642e01fSmrg	    switch (pDrawable->bitsPerPixel) {
10534642e01fSmrg	    case 32:
10544642e01fSmrg		*(CARD32*)pExaPixmap->sys_ptr = pixel;
10554642e01fSmrg		break;
10564642e01fSmrg	    case 16:
10574642e01fSmrg		*(CARD16*)pExaPixmap->sys_ptr = pixel;
10584642e01fSmrg		break;
10594642e01fSmrg	    case 8:
10604642e01fSmrg		*(CARD8*)pExaPixmap->sys_ptr = pixel;
10614642e01fSmrg	    }
10624642e01fSmrg
10634202a189Smrg	    RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys,
10644202a189Smrg			 pRegion);
10654202a189Smrg	    RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB,
10664642e01fSmrg			 pRegion);
10674202a189Smrg	    RegionSubtract(pending_damage, pending_damage, pRegion);
10684642e01fSmrg	}
10694642e01fSmrg
10704642e01fSmrg	ret = TRUE;
107105b261ecSmrg    }
107205b261ecSmrg
10734642e01fSmrgout:
10744202a189Smrg    RegionTranslate(pRegion, -xoff, -yoff);
10754642e01fSmrg
10764642e01fSmrg    return ret;
107705b261ecSmrg}
107805b261ecSmrg
107905b261ecSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
108005b261ecSmrg * Based on fbFillRegionTiled(), fbTile().
108105b261ecSmrg */
108205b261ecSmrgBool
108352397711SmrgexaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
108452397711Smrg		    DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
108552397711Smrg		    unsigned int clientClipType)
108605b261ecSmrg{
108705b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
108805b261ecSmrg    PixmapPtr pPixmap;
10894642e01fSmrg    ExaPixmapPrivPtr pExaPixmap;
10904642e01fSmrg    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
10914642e01fSmrg    int xoff, yoff;
109205b261ecSmrg    int tileWidth, tileHeight;
10934202a189Smrg    int nbox = RegionNumRects (pRegion);
10944202a189Smrg    BoxPtr pBox = RegionRects (pRegion);
10954642e01fSmrg    Bool ret = FALSE;
10964642e01fSmrg    int i;
109705b261ecSmrg
109805b261ecSmrg    tileWidth = pTile->drawable.width;
109905b261ecSmrg    tileHeight = pTile->drawable.height;
110005b261ecSmrg
110105b261ecSmrg    /* If we're filling with a solid color, grab it out and go to
110205b261ecSmrg     * FillRegionSolid, saving numerous copies.
110305b261ecSmrg     */
110405b261ecSmrg    if (tileWidth == 1 && tileHeight == 1)
110505b261ecSmrg	return exaFillRegionSolid(pDrawable, pRegion,
110605b261ecSmrg				  exaGetPixmapFirstPixel (pTile), planemask,
110752397711Smrg				  alu, clientClipType);
110805b261ecSmrg
11094202a189Smrg    pPixmap = exaGetDrawablePixmap (pDrawable);
11104642e01fSmrg    pExaPixmap = ExaGetPixmapPriv (pPixmap);
11114642e01fSmrg
11124202a189Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
11134202a189Smrg	    pTileExaPixmap->accel_blocked)
11144642e01fSmrg	return FALSE;
11154202a189Smrg
11164202a189Smrg    if (pExaScr->do_migration) {
11174202a189Smrg	ExaMigrationRec pixmaps[2];
11184202a189Smrg
11194202a189Smrg	pixmaps[0].as_dst = TRUE;
11204202a189Smrg	pixmaps[0].as_src = FALSE;
11214202a189Smrg	pixmaps[0].pPix = pPixmap;
11224202a189Smrg	pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
11234202a189Smrg						alu, clientClipType) ? NULL : pRegion;
11244202a189Smrg	pixmaps[1].as_dst = FALSE;
11254202a189Smrg	pixmaps[1].as_src = TRUE;
11264202a189Smrg	pixmaps[1].pPix = pTile;
11274202a189Smrg	pixmaps[1].pReg = NULL;
11284202a189Smrg
112905b261ecSmrg	exaDoMigration (pixmaps, 2, TRUE);
113005b261ecSmrg    }
113105b261ecSmrg
113205b261ecSmrg    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
113305b261ecSmrg
11344202a189Smrg    if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
11354642e01fSmrg	return FALSE;
113605b261ecSmrg
11374642e01fSmrg    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
113805b261ecSmrg    {
11394642e01fSmrg	if (xoff || yoff)
11404202a189Smrg	    RegionTranslate(pRegion, xoff, yoff);
11414642e01fSmrg
11424642e01fSmrg	for (i = 0; i < nbox; i++)
114305b261ecSmrg	{
11444642e01fSmrg	    int height = pBox[i].y2 - pBox[i].y1;
11454642e01fSmrg	    int dstY = pBox[i].y1;
114605b261ecSmrg	    int tileY;
114705b261ecSmrg
11484642e01fSmrg	    if (alu == GXcopy)
11494642e01fSmrg		height = min(height, tileHeight);
11504642e01fSmrg
11514642e01fSmrg	    modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
115205b261ecSmrg
115305b261ecSmrg	    while (height > 0) {
11544642e01fSmrg		int width = pBox[i].x2 - pBox[i].x1;
11554642e01fSmrg		int dstX = pBox[i].x1;
115605b261ecSmrg		int tileX;
115705b261ecSmrg		int h = tileHeight - tileY;
115805b261ecSmrg
11594642e01fSmrg		if (alu == GXcopy)
11604642e01fSmrg		    width = min(width, tileWidth);
11614642e01fSmrg
116205b261ecSmrg		if (h > height)
116305b261ecSmrg		    h = height;
116405b261ecSmrg		height -= h;
116505b261ecSmrg
11664642e01fSmrg		modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
11674642e01fSmrg			tileX);
116805b261ecSmrg
116905b261ecSmrg		while (width > 0) {
117005b261ecSmrg		    int w = tileWidth - tileX;
117105b261ecSmrg		    if (w > width)
117205b261ecSmrg			w = width;
117305b261ecSmrg		    width -= w;
117405b261ecSmrg
11754642e01fSmrg		    (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
117605b261ecSmrg					    w, h);
117705b261ecSmrg		    dstX += w;
117805b261ecSmrg		    tileX = 0;
117905b261ecSmrg		}
118005b261ecSmrg		dstY += h;
118105b261ecSmrg		tileY = 0;
118205b261ecSmrg	    }
118305b261ecSmrg	}
118405b261ecSmrg	(*pExaScr->info->DoneCopy) (pPixmap);
118505b261ecSmrg
11864642e01fSmrg	/* With GXcopy, we only need to do the basic algorithm up to the tile
11874642e01fSmrg	 * size; then, we can just keep doubling the destination in each
11884642e01fSmrg	 * direction until it fills the box. This way, the number of copy
11894642e01fSmrg	 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
11904642e01fSmrg	 * rx/ry is the ratio between box and tile width/height. This can make
11914642e01fSmrg	 * a big difference if each driver copy incurs a significant constant
11924642e01fSmrg	 * overhead.
11934642e01fSmrg	 */
11944642e01fSmrg	if (alu != GXcopy)
11954642e01fSmrg	    ret = TRUE;
11964642e01fSmrg	else {
11974642e01fSmrg	    Bool more_copy = FALSE;
11984642e01fSmrg
11994642e01fSmrg	    for (i = 0; i < nbox; i++) {
12004642e01fSmrg		int dstX = pBox[i].x1 + tileWidth;
12014642e01fSmrg		int dstY = pBox[i].y1 + tileHeight;
12024642e01fSmrg
12034642e01fSmrg		if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
12044642e01fSmrg		    more_copy = TRUE;
12054642e01fSmrg		    break;
12064642e01fSmrg		}
12074642e01fSmrg	    }
120805b261ecSmrg
12094642e01fSmrg	    if (more_copy == FALSE)
12104642e01fSmrg		ret = TRUE;
121105b261ecSmrg
12124642e01fSmrg	    if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
12134642e01fSmrg							    1, 1, alu, planemask)) {
12144642e01fSmrg		for (i = 0; i < nbox; i++)
12154642e01fSmrg		{
12164642e01fSmrg		    int dstX = pBox[i].x1 + tileWidth;
12174642e01fSmrg		    int dstY = pBox[i].y1 + tileHeight;
12184642e01fSmrg		    int width = min(pBox[i].x2 - dstX, tileWidth);
12194642e01fSmrg		    int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
12204642e01fSmrg
12214642e01fSmrg		    while (dstX < pBox[i].x2) {
12224642e01fSmrg			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
12234642e01fSmrg						dstX, pBox[i].y1, width, height);
12244642e01fSmrg			dstX += width;
12254642e01fSmrg			width = min(pBox[i].x2 - dstX, width * 2);
12264642e01fSmrg		    }
122705b261ecSmrg
12284642e01fSmrg		    width = pBox[i].x2 - pBox[i].x1;
12294642e01fSmrg		    height = min(pBox[i].y2 - dstY, tileHeight);
123005b261ecSmrg
12314642e01fSmrg		    while (dstY < pBox[i].y2) {
12324642e01fSmrg			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
12334642e01fSmrg						pBox[i].x1, dstY, width, height);
12344642e01fSmrg			dstY += height;
12354642e01fSmrg			height = min(pBox[i].y2 - dstY, height * 2);
12364642e01fSmrg		    }
12374642e01fSmrg		}
123805b261ecSmrg
12394642e01fSmrg		(*pExaScr->info->DoneCopy) (pPixmap);
12404642e01fSmrg
12414642e01fSmrg		ret = TRUE;
12424642e01fSmrg	    }
12434642e01fSmrg	}
124405b261ecSmrg
12454642e01fSmrg	exaMarkSync(pDrawable->pScreen);
124605b261ecSmrg
12474642e01fSmrg	if (xoff || yoff)
12484202a189Smrg	    RegionTranslate(pRegion, -xoff, -yoff);
124905b261ecSmrg    }
12504642e01fSmrg
12514642e01fSmrg    return ret;
125205b261ecSmrg}
125305b261ecSmrg
12544642e01fSmrg
125505b261ecSmrg/**
125605b261ecSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
125705b261ecSmrg *
125805b261ecSmrg * This is probably the only case we actually care about.  The rest fall through
12594642e01fSmrg * to migration and fbGetImage, which hopefully will result in migration pushing
12604642e01fSmrg * the pixmap out of framebuffer.
126105b261ecSmrg */
126205b261ecSmrgvoid
126305b261ecSmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
126405b261ecSmrg	     unsigned int format, unsigned long planeMask, char *d)
126505b261ecSmrg{
126605b261ecSmrg    ExaScreenPriv (pDrawable->pScreen);
12674202a189Smrg    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
12684202a189Smrg    ExaPixmapPriv(pPix);
126905b261ecSmrg    int xoff, yoff;
127005b261ecSmrg    Bool ok;
127105b261ecSmrg
12724202a189Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut)
127305b261ecSmrg	goto fallback;
127405b261ecSmrg
12754202a189Smrg    /* If there's a system copy, we want to save the result there */
12764202a189Smrg    if (pExaPixmap->pDamage)
12774202a189Smrg	goto fallback;
12784642e01fSmrg
12794642e01fSmrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
12804642e01fSmrg
12814642e01fSmrg    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
12824642e01fSmrg	goto fallback;
128305b261ecSmrg
128405b261ecSmrg    /* Only cover the ZPixmap, solid copy case. */
128505b261ecSmrg    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
12864642e01fSmrg	goto fallback;
128705b261ecSmrg
128805b261ecSmrg    /* Only try to handle the 8bpp and up cases, since we don't want to think
128905b261ecSmrg     * about <8bpp.
129005b261ecSmrg     */
129105b261ecSmrg    if (pDrawable->bitsPerPixel < 8)
129205b261ecSmrg	goto fallback;
129305b261ecSmrg
12944642e01fSmrg    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
12954642e01fSmrg					   pDrawable->y + y + yoff, w, h, d,
129605b261ecSmrg					   PixmapBytePad(w, pDrawable->depth));
129705b261ecSmrg    if (ok) {
129805b261ecSmrg	exaWaitSync(pDrawable->pScreen);
12994202a189Smrg	return;
130005b261ecSmrg    }
130105b261ecSmrg
130205b261ecSmrgfallback:
13034202a189Smrg    ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
130405b261ecSmrg}
1305