105b261ecSmrg/*
2f7df2e56Smrg * Copyright © 2001 Keith Packard
305b261ecSmrg *
4f7df2e56Smrg * 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>
26f7df2e56Smrg *    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,
40f7df2e56Smrg             DDXPointPtr ppt, int *pwidth, int fSorted)
4105b261ecSmrg{
42f7df2e56Smrg    ScreenPtr pScreen = pDrawable->pScreen;
43f7df2e56Smrg
44f7df2e56Smrg    ExaScreenPriv(pScreen);
45f7df2e56Smrg    RegionPtr pClip = fbGetCompositeClip(pGC);
46f7df2e56Smrg    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
47f7df2e56Smrg
48f7df2e56Smrg    ExaPixmapPriv(pPixmap);
49f7df2e56Smrg    BoxPtr pextent, pbox;
50f7df2e56Smrg    int nbox;
51f7df2e56Smrg    int extentX1, extentX2, extentY1, extentY2;
52f7df2e56Smrg    int fullX1, fullX2, fullY1;
53f7df2e56Smrg    int partX1, partX2;
54f7df2e56Smrg    int off_x, off_y;
5505b261ecSmrg
564202a189Smrg    if (pExaScr->fallback_counter ||
57f7df2e56Smrg        pExaScr->swappedOut ||
58f7df2e56Smrg        pGC->fillStyle != FillSolid || pExaPixmap->accel_blocked) {
59f7df2e56Smrg        ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted);
60f7df2e56Smrg        return;
614202a189Smrg    }
624202a189Smrg
634202a189Smrg    if (pExaScr->do_migration) {
64f7df2e56Smrg        ExaMigrationRec pixmaps[1];
654202a189Smrg
66f7df2e56Smrg        pixmaps[0].as_dst = TRUE;
67f7df2e56Smrg        pixmaps[0].as_src = FALSE;
68f7df2e56Smrg        pixmaps[0].pPix = pPixmap;
69f7df2e56Smrg        pixmaps[0].pReg = NULL;
704202a189Smrg
71f7df2e56Smrg        exaDoMigration(pixmaps, 1, TRUE);
7205b261ecSmrg    }
7305b261ecSmrg
74f7df2e56Smrg    if (!(pPixmap = exaGetOffscreenPixmap(pDrawable, &off_x, &off_y)) ||
75f7df2e56Smrg        !(*pExaScr->info->PrepareSolid) (pPixmap,
76f7df2e56Smrg                                         pGC->alu,
77f7df2e56Smrg                                         pGC->planemask, pGC->fgPixel)) {
78f7df2e56Smrg        ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted);
79f7df2e56Smrg        return;
8005b261ecSmrg    }
8105b261ecSmrg
824202a189Smrg    pextent = RegionExtents(pClip);
8305b261ecSmrg    extentX1 = pextent->x1;
8405b261ecSmrg    extentY1 = pextent->y1;
8505b261ecSmrg    extentX2 = pextent->x2;
8605b261ecSmrg    extentY2 = pextent->y2;
87f7df2e56Smrg    while (n--) {
88f7df2e56Smrg        fullX1 = ppt->x;
89f7df2e56Smrg        fullY1 = ppt->y;
90f7df2e56Smrg        fullX2 = fullX1 + (int) *pwidth;
91f7df2e56Smrg        ppt++;
92f7df2e56Smrg        pwidth++;
93f7df2e56Smrg
94f7df2e56Smrg        if (fullY1 < extentY1 || extentY2 <= fullY1)
95f7df2e56Smrg            continue;
96f7df2e56Smrg
97f7df2e56Smrg        if (fullX1 < extentX1)
98f7df2e56Smrg            fullX1 = extentX1;
99f7df2e56Smrg
100f7df2e56Smrg        if (fullX2 > extentX2)
101f7df2e56Smrg            fullX2 = extentX2;
102f7df2e56Smrg
103f7df2e56Smrg        if (fullX1 >= fullX2)
104f7df2e56Smrg            continue;
105f7df2e56Smrg
106f7df2e56Smrg        nbox = RegionNumRects(pClip);
107f7df2e56Smrg        if (nbox == 1) {
108f7df2e56Smrg            (*pExaScr->info->Solid) (pPixmap,
109f7df2e56Smrg                                     fullX1 + off_x, fullY1 + off_y,
110f7df2e56Smrg                                     fullX2 + off_x, fullY1 + 1 + off_y);
111f7df2e56Smrg        }
112f7df2e56Smrg        else {
113f7df2e56Smrg            pbox = RegionRects(pClip);
114f7df2e56Smrg            while (nbox--) {
115f7df2e56Smrg                if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) {
116f7df2e56Smrg                    partX1 = pbox->x1;
117f7df2e56Smrg                    if (partX1 < fullX1)
118f7df2e56Smrg                        partX1 = fullX1;
119f7df2e56Smrg                    partX2 = pbox->x2;
120f7df2e56Smrg                    if (partX2 > fullX2)
121f7df2e56Smrg                        partX2 = fullX2;
122f7df2e56Smrg                    if (partX2 > partX1) {
123f7df2e56Smrg                        (*pExaScr->info->Solid) (pPixmap,
124f7df2e56Smrg                                                 partX1 + off_x, fullY1 + off_y,
125f7df2e56Smrg                                                 partX2 + off_x,
126f7df2e56Smrg                                                 fullY1 + 1 + off_y);
127f7df2e56Smrg                    }
128f7df2e56Smrg                }
129f7df2e56Smrg                pbox++;
130f7df2e56Smrg            }
131f7df2e56Smrg        }
13205b261ecSmrg    }
13305b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
13405b261ecSmrg    exaMarkSync(pScreen);
13505b261ecSmrg}
13605b261ecSmrg
1374642e01fSmrgstatic Bool
138f7df2e56SmrgexaDoPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
139f7df2e56Smrg              int w, int h, int format, char *bits, int src_stride)
14005b261ecSmrg{
141f7df2e56Smrg    ExaScreenPriv(pDrawable->pScreen);
142f7df2e56Smrg    PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
143f7df2e56Smrg
1444642e01fSmrg    ExaPixmapPriv(pPix);
14505b261ecSmrg    RegionPtr pClip;
14605b261ecSmrg    BoxPtr pbox;
14705b261ecSmrg    int nbox;
14805b261ecSmrg    int xoff, yoff;
1494642e01fSmrg    int bpp = pDrawable->bitsPerPixel;
1504202a189Smrg    Bool ret = TRUE;
15105b261ecSmrg
152f7df2e56Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
153f7df2e56Smrg        !pExaScr->info->UploadToScreen)
154f7df2e56Smrg        return FALSE;
1554202a189Smrg
1564202a189Smrg    /* If there's a system copy, we want to save the result there */
1574202a189Smrg    if (pExaPixmap->pDamage)
158f7df2e56Smrg        return FALSE;
15905b261ecSmrg
16005b261ecSmrg    /* Don't bother with under 8bpp, XYPixmaps. */
16105b261ecSmrg    if (format != ZPixmap || bpp < 8)
162f7df2e56Smrg        return FALSE;
16305b261ecSmrg
16405b261ecSmrg    /* Only accelerate copies: no rop or planemask. */
16505b261ecSmrg    if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
166f7df2e56Smrg        return FALSE;
16705b261ecSmrg
16805b261ecSmrg    if (pExaScr->swappedOut)
169f7df2e56Smrg        return FALSE;
17005b261ecSmrg
1714202a189Smrg    if (pExaScr->do_migration) {
172f7df2e56Smrg        ExaMigrationRec pixmaps[1];
17305b261ecSmrg
174f7df2e56Smrg        pixmaps[0].as_dst = TRUE;
175f7df2e56Smrg        pixmaps[0].as_src = FALSE;
176f7df2e56Smrg        pixmaps[0].pPix = pPix;
177f7df2e56Smrg        pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
1784642e01fSmrg
179f7df2e56Smrg        exaDoMigration(pixmaps, 1, TRUE);
1804642e01fSmrg    }
18105b261ecSmrg
182f7df2e56Smrg    pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
18305b261ecSmrg
1844202a189Smrg    if (!pPix)
185f7df2e56Smrg        return FALSE;
18605b261ecSmrg
18705b261ecSmrg    x += pDrawable->x;
18805b261ecSmrg    y += pDrawable->y;
18905b261ecSmrg
19005b261ecSmrg    pClip = fbGetCompositeClip(pGC);
1914202a189Smrg    for (nbox = RegionNumRects(pClip),
192f7df2e56Smrg         pbox = RegionRects(pClip); nbox--; pbox++) {
193f7df2e56Smrg        int x1 = x;
194f7df2e56Smrg        int y1 = y;
195f7df2e56Smrg        int x2 = x + w;
196f7df2e56Smrg        int y2 = y + h;
197f7df2e56Smrg        char *src;
198f7df2e56Smrg        Bool ok;
199f7df2e56Smrg
200f7df2e56Smrg        if (x1 < pbox->x1)
201f7df2e56Smrg            x1 = pbox->x1;
202f7df2e56Smrg        if (y1 < pbox->y1)
203f7df2e56Smrg            y1 = pbox->y1;
204f7df2e56Smrg        if (x2 > pbox->x2)
205f7df2e56Smrg            x2 = pbox->x2;
206f7df2e56Smrg        if (y2 > pbox->y2)
207f7df2e56Smrg            y2 = pbox->y2;
208f7df2e56Smrg        if (x1 >= x2 || y1 >= y2)
209f7df2e56Smrg            continue;
210f7df2e56Smrg
211f7df2e56Smrg        src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
212f7df2e56Smrg        ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
213f7df2e56Smrg                                           x2 - x1, y2 - y1, src, src_stride);
214f7df2e56Smrg        /* We have to fall back completely, and ignore what has already been completed.
215f7df2e56Smrg         * Messing with the fb layer directly like we used to is completely unacceptable.
216f7df2e56Smrg         */
217f7df2e56Smrg        if (!ok) {
218f7df2e56Smrg            ret = FALSE;
219f7df2e56Smrg            break;
220f7df2e56Smrg        }
22105b261ecSmrg    }
22205b261ecSmrg
2234202a189Smrg    if (ret)
224f7df2e56Smrg        exaMarkSync(pDrawable->pScreen);
22505b261ecSmrg
2264202a189Smrg    return ret;
2274642e01fSmrg}
22805b261ecSmrg
2294642e01fSmrgstatic void
230f7df2e56SmrgexaPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
231f7df2e56Smrg            int w, int h, int leftPad, int format, char *bits)
2324642e01fSmrg{
2334642e01fSmrg    if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
234f7df2e56Smrg                       PixmapBytePad(w, pDrawable->depth)))
235f7df2e56Smrg        ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
236f7df2e56Smrg                         bits);
23705b261ecSmrg}
23805b261ecSmrg
23905b261ecSmrgstatic Bool inline
240f7df2e56SmrgexaCopyNtoNTwoDir(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
241f7df2e56Smrg                  GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
24205b261ecSmrg{
243f7df2e56Smrg    ExaScreenPriv(pDstDrawable->pScreen);
24405b261ecSmrg    PixmapPtr pSrcPixmap, pDstPixmap;
24505b261ecSmrg    int src_off_x, src_off_y, dst_off_x, dst_off_y;
24605b261ecSmrg    int dirsetup;
24705b261ecSmrg
24805b261ecSmrg    /* Need to get both pixmaps to call the driver routines */
249f7df2e56Smrg    pSrcPixmap = exaGetOffscreenPixmap(pSrcDrawable, &src_off_x, &src_off_y);
250f7df2e56Smrg    pDstPixmap = exaGetOffscreenPixmap(pDstDrawable, &dst_off_x, &dst_off_y);
25105b261ecSmrg    if (!pSrcPixmap || !pDstPixmap)
252f7df2e56Smrg        return FALSE;
25305b261ecSmrg
25405b261ecSmrg    /*
25505b261ecSmrg     * Now the case of a chip that only supports xdir = ydir = 1 or
25605b261ecSmrg     * xdir = ydir = -1, but we have xdir != ydir.
25705b261ecSmrg     */
258f7df2e56Smrg    dirsetup = 0;               /* No direction set up yet. */
25905b261ecSmrg    for (; nbox; pbox++, nbox--) {
260f7df2e56Smrg        if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
261f7df2e56Smrg            /* Do a xdir = ydir = -1 blit instead. */
262f7df2e56Smrg            if (dirsetup != -1) {
263f7df2e56Smrg                if (dirsetup != 0)
264f7df2e56Smrg                    pExaScr->info->DoneCopy(pDstPixmap);
265f7df2e56Smrg                dirsetup = -1;
266f7df2e56Smrg                if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
267f7df2e56Smrg                                                    pDstPixmap,
268f7df2e56Smrg                                                    -1, -1,
269f7df2e56Smrg                                                    pGC ? pGC->alu : GXcopy,
270f7df2e56Smrg                                                    pGC ? pGC->planemask :
271f7df2e56Smrg                                                    FB_ALLONES))
272f7df2e56Smrg                    return FALSE;
273f7df2e56Smrg            }
274f7df2e56Smrg            (*pExaScr->info->Copy) (pDstPixmap,
275f7df2e56Smrg                                    src_off_x + pbox->x1 + dx,
276f7df2e56Smrg                                    src_off_y + pbox->y1 + dy,
277f7df2e56Smrg                                    dst_off_x + pbox->x1,
278f7df2e56Smrg                                    dst_off_y + pbox->y1,
279f7df2e56Smrg                                    pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
280f7df2e56Smrg        }
281f7df2e56Smrg        else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
282f7df2e56Smrg            /* Do a xdir = ydir = 1 blit instead. */
283f7df2e56Smrg            if (dirsetup != 1) {
284f7df2e56Smrg                if (dirsetup != 0)
285f7df2e56Smrg                    pExaScr->info->DoneCopy(pDstPixmap);
286f7df2e56Smrg                dirsetup = 1;
287f7df2e56Smrg                if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
288f7df2e56Smrg                                                    pDstPixmap,
289f7df2e56Smrg                                                    1, 1,
290f7df2e56Smrg                                                    pGC ? pGC->alu : GXcopy,
291f7df2e56Smrg                                                    pGC ? pGC->planemask :
292f7df2e56Smrg                                                    FB_ALLONES))
293f7df2e56Smrg                    return FALSE;
294f7df2e56Smrg            }
295f7df2e56Smrg            (*pExaScr->info->Copy) (pDstPixmap,
296f7df2e56Smrg                                    src_off_x + pbox->x1 + dx,
297f7df2e56Smrg                                    src_off_y + pbox->y1 + dy,
298f7df2e56Smrg                                    dst_off_x + pbox->x1,
299f7df2e56Smrg                                    dst_off_y + pbox->y1,
300f7df2e56Smrg                                    pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
301f7df2e56Smrg        }
302f7df2e56Smrg        else if (dx >= 0) {
303f7df2e56Smrg            /*
304f7df2e56Smrg             * xdir = 1, ydir = -1.
305f7df2e56Smrg             * Perform line-by-line xdir = ydir = 1 blits, going up.
306f7df2e56Smrg             */
307f7df2e56Smrg            int i;
308f7df2e56Smrg
309f7df2e56Smrg            if (dirsetup != 1) {
310f7df2e56Smrg                if (dirsetup != 0)
311f7df2e56Smrg                    pExaScr->info->DoneCopy(pDstPixmap);
312f7df2e56Smrg                dirsetup = 1;
313f7df2e56Smrg                if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
314f7df2e56Smrg                                                    pDstPixmap,
315f7df2e56Smrg                                                    1, 1,
316f7df2e56Smrg                                                    pGC ? pGC->alu : GXcopy,
317f7df2e56Smrg                                                    pGC ? pGC->planemask :
318f7df2e56Smrg                                                    FB_ALLONES))
319f7df2e56Smrg                    return FALSE;
320f7df2e56Smrg            }
321f7df2e56Smrg            for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
322f7df2e56Smrg                (*pExaScr->info->Copy) (pDstPixmap,
323f7df2e56Smrg                                        src_off_x + pbox->x1 + dx,
324f7df2e56Smrg                                        src_off_y + pbox->y1 + dy + i,
325f7df2e56Smrg                                        dst_off_x + pbox->x1,
326f7df2e56Smrg                                        dst_off_y + pbox->y1 + i,
327f7df2e56Smrg                                        pbox->x2 - pbox->x1, 1);
328f7df2e56Smrg        }
329f7df2e56Smrg        else {
330f7df2e56Smrg            /*
331f7df2e56Smrg             * xdir = -1, ydir = 1.
332f7df2e56Smrg             * Perform line-by-line xdir = ydir = -1 blits, going down.
333f7df2e56Smrg             */
334f7df2e56Smrg            int i;
335f7df2e56Smrg
336f7df2e56Smrg            if (dirsetup != -1) {
337f7df2e56Smrg                if (dirsetup != 0)
338f7df2e56Smrg                    pExaScr->info->DoneCopy(pDstPixmap);
339f7df2e56Smrg                dirsetup = -1;
340f7df2e56Smrg                if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
341f7df2e56Smrg                                                    pDstPixmap,
342f7df2e56Smrg                                                    -1, -1,
343f7df2e56Smrg                                                    pGC ? pGC->alu : GXcopy,
344f7df2e56Smrg                                                    pGC ? pGC->planemask :
345f7df2e56Smrg                                                    FB_ALLONES))
346f7df2e56Smrg                    return FALSE;
347f7df2e56Smrg            }
348f7df2e56Smrg            for (i = 0; i < pbox->y2 - pbox->y1; i++)
349f7df2e56Smrg                (*pExaScr->info->Copy) (pDstPixmap,
350f7df2e56Smrg                                        src_off_x + pbox->x1 + dx,
351f7df2e56Smrg                                        src_off_y + pbox->y1 + dy + i,
352f7df2e56Smrg                                        dst_off_x + pbox->x1,
353f7df2e56Smrg                                        dst_off_y + pbox->y1 + i,
354f7df2e56Smrg                                        pbox->x2 - pbox->x1, 1);
355f7df2e56Smrg        }
35605b261ecSmrg    }
35705b261ecSmrg    if (dirsetup != 0)
358f7df2e56Smrg        pExaScr->info->DoneCopy(pDstPixmap);
35905b261ecSmrg    exaMarkSync(pDstDrawable->pScreen);
36005b261ecSmrg    return TRUE;
36105b261ecSmrg}
36205b261ecSmrg
3634202a189SmrgBool
364f7df2e56SmrgexaHWCopyNtoN(DrawablePtr pSrcDrawable,
365f7df2e56Smrg              DrawablePtr pDstDrawable,
366f7df2e56Smrg              GCPtr pGC,
367f7df2e56Smrg              BoxPtr pbox,
368f7df2e56Smrg              int nbox, int dx, int dy, Bool reverse, Bool upsidedown)
36905b261ecSmrg{
370f7df2e56Smrg    ExaScreenPriv(pDstDrawable->pScreen);
37105b261ecSmrg    PixmapPtr pSrcPixmap, pDstPixmap;
3724642e01fSmrg    ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
373f7df2e56Smrg    int src_off_x, src_off_y;
374f7df2e56Smrg    int dst_off_x, dst_off_y;
3754642e01fSmrg    RegionPtr srcregion = NULL, dstregion = NULL;
3764642e01fSmrg    xRectangle *rects;
3774202a189Smrg    Bool ret = TRUE;
3784642e01fSmrg
3794642e01fSmrg    /* avoid doing copy operations if no boxes */
3804642e01fSmrg    if (nbox == 0)
381f7df2e56Smrg        return TRUE;
3824642e01fSmrg
383f7df2e56Smrg    pSrcPixmap = exaGetDrawablePixmap(pSrcDrawable);
384f7df2e56Smrg    pDstPixmap = exaGetDrawablePixmap(pDstDrawable);
3854642e01fSmrg
386f7df2e56Smrg    exaGetDrawableDeltas(pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
387f7df2e56Smrg    exaGetDrawableDeltas(pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
3884642e01fSmrg
389f7df2e56Smrg    rects = xallocarray(nbox, sizeof(xRectangle));
3904642e01fSmrg
3914642e01fSmrg    if (rects) {
392f7df2e56Smrg        int i;
393f7df2e56Smrg        int ordering;
394f7df2e56Smrg
395f7df2e56Smrg        for (i = 0; i < nbox; i++) {
396f7df2e56Smrg            rects[i].x = pbox[i].x1 + dx + src_off_x;
397f7df2e56Smrg            rects[i].y = pbox[i].y1 + dy + src_off_y;
398f7df2e56Smrg            rects[i].width = pbox[i].x2 - pbox[i].x1;
399f7df2e56Smrg            rects[i].height = pbox[i].y2 - pbox[i].y1;
400f7df2e56Smrg        }
40105b261ecSmrg
402f7df2e56Smrg        /* This must match the RegionCopy() logic for reversing rect order */
403f7df2e56Smrg        if (nbox == 1 || (dx > 0 && dy > 0) ||
404f7df2e56Smrg            (pDstDrawable != pSrcDrawable &&
405f7df2e56Smrg             (pDstDrawable->type != DRAWABLE_WINDOW ||
406f7df2e56Smrg              pSrcDrawable->type != DRAWABLE_WINDOW)))
407f7df2e56Smrg            ordering = CT_YXBANDED;
408f7df2e56Smrg        else
409f7df2e56Smrg            ordering = CT_UNSORTED;
410f7df2e56Smrg
411f7df2e56Smrg        srcregion = RegionFromRects(nbox, rects, ordering);
412f7df2e56Smrg        free(rects);
413f7df2e56Smrg
414f7df2e56Smrg        if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
415f7df2e56Smrg                                           pGC->fillStyle, pGC->alu,
416f7df2e56Smrg                                           pGC->clientClip != NULL)) {
417f7df2e56Smrg            dstregion = RegionCreate(NullBox, 0);
418f7df2e56Smrg            RegionCopy(dstregion, srcregion);
419f7df2e56Smrg            RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
420f7df2e56Smrg                            dst_off_y - dy - src_off_y);
421f7df2e56Smrg        }
422f7df2e56Smrg    }
42305b261ecSmrg
424f7df2e56Smrg    pSrcExaPixmap = ExaGetPixmapPriv(pSrcPixmap);
425f7df2e56Smrg    pDstExaPixmap = ExaGetPixmapPriv(pDstPixmap);
4264642e01fSmrg
4274642e01fSmrg    /* Check whether the accelerator can use this pixmap.
4284642e01fSmrg     * If the pitch of the pixmaps is out of range, there's nothing
4294642e01fSmrg     * we can do but fall back to software rendering.
43005b261ecSmrg     */
4314642e01fSmrg    if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
4324642e01fSmrg        pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
433f7df2e56Smrg        goto fallback;
4344642e01fSmrg
4354642e01fSmrg    /* If the width or the height of either of the pixmaps
4364642e01fSmrg     * is out of range, check whether the boxes are actually out of the
4374642e01fSmrg     * addressable range as well. If they aren't, we can still do
4384642e01fSmrg     * the copying in hardware.
4394642e01fSmrg     */
4404642e01fSmrg    if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
4414642e01fSmrg        int i;
4424642e01fSmrg
4434642e01fSmrg        for (i = 0; i < nbox; i++) {
4444642e01fSmrg            /* src */
4454642e01fSmrg            if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
4464642e01fSmrg                (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
4474642e01fSmrg                goto fallback;
4484642e01fSmrg
4494642e01fSmrg            /* dst */
4504642e01fSmrg            if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
4514642e01fSmrg                (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
4524642e01fSmrg                goto fallback;
4534642e01fSmrg        }
45405b261ecSmrg    }
45505b261ecSmrg
4564202a189Smrg    if (pExaScr->do_migration) {
457f7df2e56Smrg        ExaMigrationRec pixmaps[2];
458f7df2e56Smrg
459f7df2e56Smrg        pixmaps[0].as_dst = TRUE;
460f7df2e56Smrg        pixmaps[0].as_src = FALSE;
461f7df2e56Smrg        pixmaps[0].pPix = pDstPixmap;
462f7df2e56Smrg        pixmaps[0].pReg = dstregion;
463f7df2e56Smrg        pixmaps[1].as_dst = FALSE;
464f7df2e56Smrg        pixmaps[1].as_src = TRUE;
465f7df2e56Smrg        pixmaps[1].pPix = pSrcPixmap;
466f7df2e56Smrg        pixmaps[1].pReg = srcregion;
467f7df2e56Smrg
468f7df2e56Smrg        exaDoMigration(pixmaps, 2, TRUE);
4694202a189Smrg    }
4704642e01fSmrg
47105b261ecSmrg    /* Mixed directions must be handled specially if the card is lame */
4724642e01fSmrg    if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
473f7df2e56Smrg        reverse != upsidedown) {
474f7df2e56Smrg        if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
475f7df2e56Smrg                              dx, dy))
476f7df2e56Smrg            goto out;
477f7df2e56Smrg        goto fallback;
47805b261ecSmrg    }
47905b261ecSmrg
4804202a189Smrg    if (exaPixmapHasGpuCopy(pDstPixmap)) {
481f7df2e56Smrg        /* Normal blitting. */
482f7df2e56Smrg        if (exaPixmapHasGpuCopy(pSrcPixmap)) {
483f7df2e56Smrg            if (!(*pExaScr->info->PrepareCopy)
484f7df2e56Smrg                (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, upsidedown ? -1 : 1,
485f7df2e56Smrg                 pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) {
486f7df2e56Smrg                goto fallback;
487f7df2e56Smrg            }
488f7df2e56Smrg
489f7df2e56Smrg            while (nbox--) {
490f7df2e56Smrg                (*pExaScr->info->Copy) (pDstPixmap,
491f7df2e56Smrg                                        pbox->x1 + dx + src_off_x,
492f7df2e56Smrg                                        pbox->y1 + dy + src_off_y,
493f7df2e56Smrg                                        pbox->x1 + dst_off_x,
494f7df2e56Smrg                                        pbox->y1 + dst_off_y,
495f7df2e56Smrg                                        pbox->x2 - pbox->x1,
496f7df2e56Smrg                                        pbox->y2 - pbox->y1);
497f7df2e56Smrg                pbox++;
498f7df2e56Smrg            }
499f7df2e56Smrg
500f7df2e56Smrg            (*pExaScr->info->DoneCopy) (pDstPixmap);
501f7df2e56Smrg            exaMarkSync(pDstDrawable->pScreen);
502f7df2e56Smrg            /* UTS: mainly for SHM PutImage's secondary path.
503f7df2e56Smrg             *
504f7df2e56Smrg             * Only taking this path for directly accessible pixmaps.
505f7df2e56Smrg             */
506f7df2e56Smrg        }
507f7df2e56Smrg        else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
508f7df2e56Smrg            int bpp = pSrcDrawable->bitsPerPixel;
509f7df2e56Smrg            int src_stride = exaGetPixmapPitch(pSrcPixmap);
510f7df2e56Smrg            CARD8 *src = NULL;
511f7df2e56Smrg
512f7df2e56Smrg            if (!pExaScr->info->UploadToScreen)
513f7df2e56Smrg                goto fallback;
514f7df2e56Smrg
515f7df2e56Smrg            if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
516f7df2e56Smrg                goto fallback;
517f7df2e56Smrg
518f7df2e56Smrg            if (pSrcDrawable->bitsPerPixel < 8)
519f7df2e56Smrg                goto fallback;
520f7df2e56Smrg
521f7df2e56Smrg            if (pGC &&
522f7df2e56Smrg                !(pGC->alu == GXcopy &&
523f7df2e56Smrg                  EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask)))
524f7df2e56Smrg                goto fallback;
525f7df2e56Smrg
526f7df2e56Smrg            while (nbox--) {
527f7df2e56Smrg                src =
528f7df2e56Smrg                    pSrcExaPixmap->sys_ptr + (pbox->y1 + dy +
529f7df2e56Smrg                                              src_off_y) * src_stride +
530f7df2e56Smrg                    (pbox->x1 + dx + src_off_x) * (bpp / 8);
531f7df2e56Smrg                if (!pExaScr->info->
532f7df2e56Smrg                    UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
533f7df2e56Smrg                                   pbox->y1 + dst_off_y, pbox->x2 - pbox->x1,
534f7df2e56Smrg                                   pbox->y2 - pbox->y1, (char *) src,
535f7df2e56Smrg                                   src_stride))
536f7df2e56Smrg                    goto fallback;
537f7df2e56Smrg
538f7df2e56Smrg                pbox++;
539f7df2e56Smrg            }
540f7df2e56Smrg        }
541f7df2e56Smrg        else
542f7df2e56Smrg            goto fallback;
543f7df2e56Smrg    }
544f7df2e56Smrg    else
545f7df2e56Smrg        goto fallback;
5464642e01fSmrg
5474642e01fSmrg    goto out;
5484642e01fSmrg
549f7df2e56Smrg fallback:
5504202a189Smrg    ret = FALSE;
5514642e01fSmrg
552f7df2e56Smrg out:
5534642e01fSmrg    if (dstregion) {
554f7df2e56Smrg        RegionUninit(dstregion);
555f7df2e56Smrg        RegionDestroy(dstregion);
5564642e01fSmrg    }
5574642e01fSmrg    if (srcregion) {
558f7df2e56Smrg        RegionUninit(srcregion);
559f7df2e56Smrg        RegionDestroy(srcregion);
5604642e01fSmrg    }
5614202a189Smrg
5624202a189Smrg    return ret;
5634202a189Smrg}
5644202a189Smrg
5654202a189Smrgvoid
566f7df2e56SmrgexaCopyNtoN(DrawablePtr pSrcDrawable,
567f7df2e56Smrg            DrawablePtr pDstDrawable,
568f7df2e56Smrg            GCPtr pGC,
569f7df2e56Smrg            BoxPtr pbox,
570f7df2e56Smrg            int nbox,
571f7df2e56Smrg            int dx,
572f7df2e56Smrg            int dy,
573f7df2e56Smrg            Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
5744202a189Smrg{
5754202a189Smrg    ExaScreenPriv(pDstDrawable->pScreen);
5764202a189Smrg
5774202a189Smrg    if (pExaScr->fallback_counter ||
578f7df2e56Smrg        (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
579f7df2e56Smrg        return;
5804202a189Smrg
581f7df2e56Smrg    if (exaHWCopyNtoN
582f7df2e56Smrg        (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
583f7df2e56Smrg         upsidedown))
584f7df2e56Smrg        return;
5854202a189Smrg
5864202a189Smrg    /* This is a CopyWindow, it's cleaner to fallback at the original call. */
5874202a189Smrg    if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
588f7df2e56Smrg        pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
589f7df2e56Smrg        return;
5904202a189Smrg    }
5914202a189Smrg
5924202a189Smrg    /* fallback */
593f7df2e56Smrg    ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy,
594f7df2e56Smrg                     reverse, upsidedown, bitplane, closure);
59505b261ecSmrg}
59605b261ecSmrg
59705b261ecSmrgRegionPtr
59805b261ecSmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
599f7df2e56Smrg            int srcx, int srcy, int width, int height, int dstx, int dsty)
60005b261ecSmrg{
601f7df2e56Smrg    ExaScreenPriv(pDstDrawable->pScreen);
60205b261ecSmrg
6034202a189Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut) {
604f7df2e56Smrg        return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
605f7df2e56Smrg                                srcx, srcy, width, height, dstx, dsty);
60605b261ecSmrg    }
60705b261ecSmrg
608f7df2e56Smrg    return miDoCopy(pSrcDrawable, pDstDrawable, pGC,
609f7df2e56Smrg                    srcx, srcy, width, height,
610f7df2e56Smrg                    dstx, dsty, exaCopyNtoN, 0, NULL);
61105b261ecSmrg}
61205b261ecSmrg
61305b261ecSmrgstatic void
61405b261ecSmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
615f7df2e56Smrg             DDXPointPtr ppt)
61605b261ecSmrg{
617f7df2e56Smrg    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) {
625f7df2e56Smrg        ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
626f7df2e56Smrg        return;
62705b261ecSmrg    }
62805b261ecSmrg
629f7df2e56Smrg    prect = xallocarray(npt, sizeof(xRectangle));
63005b261ecSmrg    for (i = 0; i < npt; i++) {
631f7df2e56Smrg        prect[i].x = ppt[i].x;
632f7df2e56Smrg        prect[i].y = ppt[i].y;
633f7df2e56Smrg        if (i > 0 && mode == CoordModePrevious) {
634f7df2e56Smrg            prect[i].x += prect[i - 1].x;
635f7df2e56Smrg            prect[i].y += prect[i - 1].y;
636f7df2e56Smrg        }
637f7df2e56Smrg        prect[i].width = 1;
638f7df2e56Smrg        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,
651f7df2e56Smrg             DDXPointPtr ppt)
65205b261ecSmrg{
653f7df2e56Smrg    ExaScreenPriv(pDrawable->pScreen);
65405b261ecSmrg    xRectangle *prect;
65505b261ecSmrg    int x1, x2, y1, y2;
65605b261ecSmrg    int i;
65705b261ecSmrg
6584202a189Smrg    if (pExaScr->fallback_counter) {
659f7df2e56Smrg        ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
660f7df2e56Smrg        return;
6614202a189Smrg    }
6624202a189Smrg
66305b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
66405b261ecSmrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
665f7df2e56Smrg        pGC->fillStyle != FillSolid) {
666f7df2e56Smrg        ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
667f7df2e56Smrg        return;
66805b261ecSmrg    }
66905b261ecSmrg
670f7df2e56Smrg    prect = xallocarray(npt - 1, sizeof(xRectangle));
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++) {
675f7df2e56Smrg        if (mode == CoordModePrevious) {
676f7df2e56Smrg            x2 = x1 + ppt[i + 1].x;
677f7df2e56Smrg            y2 = y1 + ppt[i + 1].y;
678f7df2e56Smrg        }
679f7df2e56Smrg        else {
680f7df2e56Smrg            x2 = ppt[i + 1].x;
681f7df2e56Smrg            y2 = ppt[i + 1].y;
682f7df2e56Smrg        }
683f7df2e56Smrg
684f7df2e56Smrg        if (x1 != x2 && y1 != y2) {
685f7df2e56Smrg            free(prect);
686f7df2e56Smrg            ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
687f7df2e56Smrg            return;
688f7df2e56Smrg        }
689f7df2e56Smrg
690f7df2e56Smrg        if (x1 < x2) {
691f7df2e56Smrg            prect[i].x = x1;
692f7df2e56Smrg            prect[i].width = x2 - x1 + 1;
693f7df2e56Smrg        }
694f7df2e56Smrg        else {
695f7df2e56Smrg            prect[i].x = x2;
696f7df2e56Smrg            prect[i].width = x1 - x2 + 1;
697f7df2e56Smrg        }
698f7df2e56Smrg        if (y1 < y2) {
699f7df2e56Smrg            prect[i].y = y1;
700f7df2e56Smrg            prect[i].height = y2 - y1 + 1;
701f7df2e56Smrg        }
702f7df2e56Smrg        else {
703f7df2e56Smrg            prect[i].y = y2;
704f7df2e56Smrg            prect[i].height = y1 - y2 + 1;
705f7df2e56Smrg        }
706f7df2e56Smrg
707f7df2e56Smrg        x1 = x2;
708f7df2e56Smrg        y1 = y2;
70905b261ecSmrg    }
71005b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
7114202a189Smrg    free(prect);
71205b261ecSmrg}
71305b261ecSmrg
71405b261ecSmrg/**
71505b261ecSmrg * exaPolySegment() checks if it can accelerate the lines as a group of
71605b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
71705b261ecSmrg * acceleration if so.
71805b261ecSmrg */
71905b261ecSmrgstatic void
720f7df2e56SmrgexaPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg)
72105b261ecSmrg{
722f7df2e56Smrg    ExaScreenPriv(pDrawable->pScreen);
72305b261ecSmrg    xRectangle *prect;
72405b261ecSmrg    int i;
72505b261ecSmrg
72605b261ecSmrg    /* Don't try to do wide lines or non-solid fill style. */
7274202a189Smrg    if (pExaScr->fallback_counter || pGC->lineWidth != 0 ||
728f7df2e56Smrg        pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) {
729f7df2e56Smrg        ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
730f7df2e56Smrg        return;
73105b261ecSmrg    }
73205b261ecSmrg
73305b261ecSmrg    /* If we have any non-horizontal/vertical, fall back. */
73405b261ecSmrg    for (i = 0; i < nseg; i++) {
735f7df2e56Smrg        if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
736f7df2e56Smrg            ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
737f7df2e56Smrg            return;
738f7df2e56Smrg        }
73905b261ecSmrg    }
74005b261ecSmrg
7415a112b11Smrg    prect = xallocarray((unsigned int)nseg, sizeof(xRectangle));
74205b261ecSmrg    for (i = 0; i < nseg; i++) {
743f7df2e56Smrg        if (pSeg[i].x1 < pSeg[i].x2) {
744f7df2e56Smrg            prect[i].x = pSeg[i].x1;
745f7df2e56Smrg            prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
746f7df2e56Smrg        }
747f7df2e56Smrg        else {
748f7df2e56Smrg            prect[i].x = pSeg[i].x2;
749f7df2e56Smrg            prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
750f7df2e56Smrg        }
751f7df2e56Smrg        if (pSeg[i].y1 < pSeg[i].y2) {
752f7df2e56Smrg            prect[i].y = pSeg[i].y1;
753f7df2e56Smrg            prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
754f7df2e56Smrg        }
755f7df2e56Smrg        else {
756f7df2e56Smrg            prect[i].y = pSeg[i].y2;
757f7df2e56Smrg            prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
758f7df2e56Smrg        }
759f7df2e56Smrg
760f7df2e56Smrg        /* don't paint last pixel */
761f7df2e56Smrg        if (pGC->capStyle == CapNotLast) {
762f7df2e56Smrg            if (prect[i].width == 1)
763f7df2e56Smrg                prect[i].height--;
764f7df2e56Smrg            else
765f7df2e56Smrg                prect[i].width--;
766f7df2e56Smrg        }
76705b261ecSmrg    }
76805b261ecSmrg    pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
7694202a189Smrg    free(prect);
77005b261ecSmrg}
77105b261ecSmrg
772f7df2e56Smrgstatic Bool exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion,
773f7df2e56Smrg                               Pixel pixel, CARD32 planemask, CARD32 alu,
774f7df2e56Smrg                               Bool hasClientClip);
77505b261ecSmrg
77605b261ecSmrgstatic void
777f7df2e56SmrgexaPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect)
77805b261ecSmrg{
779f7df2e56Smrg    ExaScreenPriv(pDrawable->pScreen);
780f7df2e56Smrg    RegionPtr pClip = fbGetCompositeClip(pGC);
781f7df2e56Smrg    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
782f7df2e56Smrg
783f7df2e56Smrg    ExaPixmapPriv(pPixmap);
78405b261ecSmrg    register BoxPtr pbox;
785f7df2e56Smrg    BoxPtr pextent;
786f7df2e56Smrg    int extentX1, extentX2, extentY1, extentY2;
787f7df2e56Smrg    int fullX1, fullX2, fullY1, fullY2;
788f7df2e56Smrg    int partX1, partX2, partY1, partY2;
789f7df2e56Smrg    int xoff, yoff;
790f7df2e56Smrg    int xorg, yorg;
791f7df2e56Smrg    int n;
7924202a189Smrg    RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
79305b261ecSmrg
79405b261ecSmrg    /* Compute intersection of rects and clip region */
7954202a189Smrg    RegionTranslate(pReg, pDrawable->x, pDrawable->y);
7964202a189Smrg    RegionIntersect(pReg, pClip, pReg);
79705b261ecSmrg
7984202a189Smrg    if (!RegionNumRects(pReg)) {
799f7df2e56Smrg        goto out;
80005b261ecSmrg    }
80105b261ecSmrg
80205b261ecSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
80305b261ecSmrg
8044202a189Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut ||
805f7df2e56Smrg        pExaPixmap->accel_blocked) {
806f7df2e56Smrg        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) &&
813f7df2e56Smrg        (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
814f7df2e56Smrg         pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
815f7df2e56Smrg         pGC->alu == GXset)) {
816f7df2e56Smrg        if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
817f7df2e56Smrg             exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
818f7df2e56Smrg                                pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
819f7df2e56Smrg                                pGC->alu, pGC->clientClip != NULL)) ||
820f7df2e56Smrg            (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
821f7df2e56Smrg             exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
822f7df2e56Smrg                                pGC->planemask, pGC->alu,
823f7df2e56Smrg                                pGC->clientClip != NULL))) {
824f7df2e56Smrg            goto out;
825f7df2e56Smrg        }
82605b261ecSmrg    }
82705b261ecSmrg
82805b261ecSmrg    if (pGC->fillStyle != FillSolid &&
829f7df2e56Smrg        !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) {
830f7df2e56Smrg        goto fallback;
83105b261ecSmrg    }
83205b261ecSmrg
8334202a189Smrg    if (pExaScr->do_migration) {
834f7df2e56Smrg        ExaMigrationRec pixmaps[1];
8354202a189Smrg
836f7df2e56Smrg        pixmaps[0].as_dst = TRUE;
837f7df2e56Smrg        pixmaps[0].as_src = FALSE;
838f7df2e56Smrg        pixmaps[0].pPix = pPixmap;
839f7df2e56Smrg        pixmaps[0].pReg = NULL;
84005b261ecSmrg
841f7df2e56Smrg        exaDoMigration(pixmaps, 1, TRUE);
8424202a189Smrg    }
8434202a189Smrg
844f7df2e56Smrg    if (!exaPixmapHasGpuCopy(pPixmap) ||
845f7df2e56Smrg        !(*pExaScr->info->PrepareSolid) (pPixmap,
846f7df2e56Smrg                                         pGC->alu,
847f7df2e56Smrg                                         pGC->planemask, pGC->fgPixel)) {
848f7df2e56Smrg fallback:
849f7df2e56Smrg        ExaCheckPolyFillRect(pDrawable, pGC, nrect, prect);
850f7df2e56Smrg        goto out;
85105b261ecSmrg    }
85205b261ecSmrg
85305b261ecSmrg    xorg = pDrawable->x;
85405b261ecSmrg    yorg = pDrawable->y;
85505b261ecSmrg
8564202a189Smrg    pextent = RegionExtents(pClip);
85705b261ecSmrg    extentX1 = pextent->x1;
85805b261ecSmrg    extentY1 = pextent->y1;
85905b261ecSmrg    extentX2 = pextent->x2;
86005b261ecSmrg    extentY2 = pextent->y2;
861f7df2e56Smrg    while (nrect--) {
862f7df2e56Smrg        fullX1 = prect->x + xorg;
863f7df2e56Smrg        fullY1 = prect->y + yorg;
864f7df2e56Smrg        fullX2 = fullX1 + (int) prect->width;
865f7df2e56Smrg        fullY2 = fullY1 + (int) prect->height;
866f7df2e56Smrg        prect++;
867f7df2e56Smrg
868f7df2e56Smrg        if (fullX1 < extentX1)
869f7df2e56Smrg            fullX1 = extentX1;
870f7df2e56Smrg
871f7df2e56Smrg        if (fullY1 < extentY1)
872f7df2e56Smrg            fullY1 = extentY1;
873f7df2e56Smrg
874f7df2e56Smrg        if (fullX2 > extentX2)
875f7df2e56Smrg            fullX2 = extentX2;
876f7df2e56Smrg
877f7df2e56Smrg        if (fullY2 > extentY2)
878f7df2e56Smrg            fullY2 = extentY2;
879f7df2e56Smrg
880f7df2e56Smrg        if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
881f7df2e56Smrg            continue;
882f7df2e56Smrg        n = RegionNumRects(pClip);
883f7df2e56Smrg        if (n == 1) {
884f7df2e56Smrg            (*pExaScr->info->Solid) (pPixmap,
885f7df2e56Smrg                                     fullX1 + xoff, fullY1 + yoff,
886f7df2e56Smrg                                     fullX2 + xoff, fullY2 + yoff);
887f7df2e56Smrg        }
888f7df2e56Smrg        else {
889f7df2e56Smrg            pbox = RegionRects(pClip);
890f7df2e56Smrg            /*
891f7df2e56Smrg             * clip the rectangle to each box in the clip region
892f7df2e56Smrg             * this is logically equivalent to calling Intersect(),
893f7df2e56Smrg             * but rectangles may overlap each other here.
894f7df2e56Smrg             */
895f7df2e56Smrg            while (n--) {
896f7df2e56Smrg                partX1 = pbox->x1;
897f7df2e56Smrg                if (partX1 < fullX1)
898f7df2e56Smrg                    partX1 = fullX1;
899f7df2e56Smrg                partY1 = pbox->y1;
900f7df2e56Smrg                if (partY1 < fullY1)
901f7df2e56Smrg                    partY1 = fullY1;
902f7df2e56Smrg                partX2 = pbox->x2;
903f7df2e56Smrg                if (partX2 > fullX2)
904f7df2e56Smrg                    partX2 = fullX2;
905f7df2e56Smrg                partY2 = pbox->y2;
906f7df2e56Smrg                if (partY2 > fullY2)
907f7df2e56Smrg                    partY2 = fullY2;
908f7df2e56Smrg
909f7df2e56Smrg                pbox++;
910f7df2e56Smrg
911f7df2e56Smrg                if (partX1 < partX2 && partY1 < partY2) {
912f7df2e56Smrg                    (*pExaScr->info->Solid) (pPixmap,
913f7df2e56Smrg                                             partX1 + xoff, partY1 + yoff,
914f7df2e56Smrg                                             partX2 + xoff, partY2 + yoff);
915f7df2e56Smrg                }
916f7df2e56Smrg            }
917f7df2e56Smrg        }
91805b261ecSmrg    }
91905b261ecSmrg    (*pExaScr->info->DoneSolid) (pPixmap);
92005b261ecSmrg    exaMarkSync(pDrawable->pScreen);
92105b261ecSmrg
922f7df2e56Smrg out:
9234202a189Smrg    RegionUninit(pReg);
9244202a189Smrg    RegionDestroy(pReg);
92505b261ecSmrg}
92605b261ecSmrg
92705b261ecSmrgconst GCOps exaOps = {
92805b261ecSmrg    exaFillSpans,
92905b261ecSmrg    ExaCheckSetSpans,
93005b261ecSmrg    exaPutImage,
93105b261ecSmrg    exaCopyArea,
93205b261ecSmrg    ExaCheckCopyPlane,
93305b261ecSmrg    exaPolyPoint,
93405b261ecSmrg    exaPolylines,
93505b261ecSmrg    exaPolySegment,
93605b261ecSmrg    miPolyRectangle,
93705b261ecSmrg    ExaCheckPolyArc,
93805b261ecSmrg    miFillPolygon,
93905b261ecSmrg    exaPolyFillRect,
94005b261ecSmrg    miPolyFillArc,
94105b261ecSmrg    miPolyText8,
94205b261ecSmrg    miPolyText16,
94305b261ecSmrg    miImageText8,
94405b261ecSmrg    miImageText16,
9454642e01fSmrg    ExaCheckImageGlyphBlt,
94605b261ecSmrg    ExaCheckPolyGlyphBlt,
94705b261ecSmrg    ExaCheckPushPixels,
94805b261ecSmrg};
94905b261ecSmrg
95005b261ecSmrgvoid
95105b261ecSmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
95205b261ecSmrg{
953f7df2e56Smrg    RegionRec rgnDst;
954f7df2e56Smrg    int dx, dy;
955f7df2e56Smrg    PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
956f7df2e56Smrg
9574202a189Smrg    ExaScreenPriv(pWin->drawable.pScreen);
95805b261ecSmrg
95905b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
96005b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
9614202a189Smrg    RegionTranslate(prgnSrc, -dx, -dy);
96205b261ecSmrg
9634202a189Smrg    RegionInit(&rgnDst, NullBox, 0);
96405b261ecSmrg
9654202a189Smrg    RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
96605b261ecSmrg#ifdef COMPOSITE
96705b261ecSmrg    if (pPixmap->screen_x || pPixmap->screen_y)
968f7df2e56Smrg        RegionTranslate(&rgnDst, -pPixmap->screen_x, -pPixmap->screen_y);
96905b261ecSmrg#endif
97005b261ecSmrg
9714202a189Smrg    if (pExaScr->fallback_counter) {
972f7df2e56Smrg        pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
973f7df2e56Smrg        goto fallback;
9744202a189Smrg    }
9754202a189Smrg
9764202a189Smrg    pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
977f7df2e56Smrg    miCopyRegion(&pPixmap->drawable, &pPixmap->drawable,
978f7df2e56Smrg                 NULL, &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
9794202a189Smrg    pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
98005b261ecSmrg
981f7df2e56Smrg fallback:
9824202a189Smrg    RegionUninit(&rgnDst);
9834202a189Smrg
9844202a189Smrg    if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
985f7df2e56Smrg        pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
986f7df2e56Smrg        RegionTranslate(prgnSrc, dx, dy);
987f7df2e56Smrg        ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
9884202a189Smrg    }
98905b261ecSmrg}
99005b261ecSmrg
99105b261ecSmrgstatic Bool
992f7df2e56SmrgexaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel,
993f7df2e56Smrg                   CARD32 planemask, CARD32 alu, Bool hasClientClip)
99405b261ecSmrg{
99505b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
996f7df2e56Smrg    PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
997f7df2e56Smrg
998f7df2e56Smrg    ExaPixmapPriv(pPixmap);
99905b261ecSmrg    int xoff, yoff;
10004642e01fSmrg    Bool ret = FALSE;
100105b261ecSmrg
10024642e01fSmrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
10034202a189Smrg    RegionTranslate(pRegion, xoff, yoff);
10044642e01fSmrg
10054202a189Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
1006f7df2e56Smrg        goto out;
10074202a189Smrg
10084202a189Smrg    if (pExaScr->do_migration) {
1009f7df2e56Smrg        ExaMigrationRec pixmaps[1];
10104202a189Smrg
1011f7df2e56Smrg        pixmaps[0].as_dst = TRUE;
1012f7df2e56Smrg        pixmaps[0].as_src = FALSE;
1013f7df2e56Smrg        pixmaps[0].pPix = pPixmap;
1014f7df2e56Smrg        pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
1015f7df2e56Smrg                                                alu,
1016f7df2e56Smrg                                                hasClientClip) ? NULL : pRegion;
10174202a189Smrg
1018f7df2e56Smrg        exaDoMigration(pixmaps, 1, TRUE);
101905b261ecSmrg    }
102005b261ecSmrg
1021f7df2e56Smrg    if (exaPixmapHasGpuCopy(pPixmap) &&
1022f7df2e56Smrg        (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) {
1023f7df2e56Smrg        int nbox;
1024f7df2e56Smrg        BoxPtr pBox;
1025f7df2e56Smrg
1026f7df2e56Smrg        nbox = RegionNumRects(pRegion);
1027f7df2e56Smrg        pBox = RegionRects(pRegion);
1028f7df2e56Smrg
1029f7df2e56Smrg        while (nbox--) {
1030f7df2e56Smrg            (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
1031f7df2e56Smrg                                     pBox->y2);
1032f7df2e56Smrg            pBox++;
1033f7df2e56Smrg        }
1034f7df2e56Smrg        (*pExaScr->info->DoneSolid) (pPixmap);
1035f7df2e56Smrg        exaMarkSync(pDrawable->pScreen);
1036f7df2e56Smrg
1037f7df2e56Smrg        if (pExaPixmap->pDamage &&
1038f7df2e56Smrg            pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
1039f7df2e56Smrg            pDrawable->width == 1 && pDrawable->height == 1 &&
1040806e81e9Smrg            pDrawable->bitsPerPixel != 24 && alu == GXcopy) {
1041f7df2e56Smrg            RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
1042f7df2e56Smrg
1043f7df2e56Smrg            switch (pDrawable->bitsPerPixel) {
1044f7df2e56Smrg            case 32:
1045f7df2e56Smrg                *(CARD32 *) pExaPixmap->sys_ptr = pixel;
1046f7df2e56Smrg                break;
1047f7df2e56Smrg            case 16:
1048f7df2e56Smrg                *(CARD16 *) pExaPixmap->sys_ptr = pixel;
1049f7df2e56Smrg                break;
1050f7df2e56Smrg            case 8:
1051f7df2e56Smrg            case 4:
1052f7df2e56Smrg            case 1:
1053f7df2e56Smrg                *(CARD8 *) pExaPixmap->sys_ptr = pixel;
1054f7df2e56Smrg            }
1055f7df2e56Smrg
1056f7df2e56Smrg            RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, pRegion);
1057f7df2e56Smrg            RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, pRegion);
1058f7df2e56Smrg            RegionSubtract(pending_damage, pending_damage, pRegion);
1059f7df2e56Smrg        }
1060f7df2e56Smrg
1061f7df2e56Smrg        ret = TRUE;
106205b261ecSmrg    }
106305b261ecSmrg
1064f7df2e56Smrg out:
10654202a189Smrg    RegionTranslate(pRegion, -xoff, -yoff);
10664642e01fSmrg
10674642e01fSmrg    return ret;
106805b261ecSmrg}
106905b261ecSmrg
107005b261ecSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
107105b261ecSmrg * Based on fbFillRegionTiled(), fbTile().
107205b261ecSmrg */
107305b261ecSmrgBool
1074f7df2e56SmrgexaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
1075f7df2e56Smrg                   DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
1076f7df2e56Smrg                   Bool hasClientClip)
107705b261ecSmrg{
107805b261ecSmrg    ExaScreenPriv(pDrawable->pScreen);
107905b261ecSmrg    PixmapPtr pPixmap;
10804642e01fSmrg    ExaPixmapPrivPtr pExaPixmap;
10814642e01fSmrg    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
10824642e01fSmrg    int xoff, yoff;
108305b261ecSmrg    int tileWidth, tileHeight;
1084f7df2e56Smrg    int nbox = RegionNumRects(pRegion);
1085f7df2e56Smrg    BoxPtr pBox = RegionRects(pRegion);
10864642e01fSmrg    Bool ret = FALSE;
10874642e01fSmrg    int i;
108805b261ecSmrg
108905b261ecSmrg    tileWidth = pTile->drawable.width;
109005b261ecSmrg    tileHeight = pTile->drawable.height;
109105b261ecSmrg
109205b261ecSmrg    /* If we're filling with a solid color, grab it out and go to
109305b261ecSmrg     * FillRegionSolid, saving numerous copies.
109405b261ecSmrg     */
109505b261ecSmrg    if (tileWidth == 1 && tileHeight == 1)
1096f7df2e56Smrg        return exaFillRegionSolid(pDrawable, pRegion,
1097f7df2e56Smrg                                  exaGetPixmapFirstPixel(pTile), planemask,
1098f7df2e56Smrg                                  alu, hasClientClip);
109905b261ecSmrg
1100f7df2e56Smrg    pPixmap = exaGetDrawablePixmap(pDrawable);
1101f7df2e56Smrg    pExaPixmap = ExaGetPixmapPriv(pPixmap);
11024642e01fSmrg
11034202a189Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
1104f7df2e56Smrg        pTileExaPixmap->accel_blocked)
1105f7df2e56Smrg        return FALSE;
11064202a189Smrg
11074202a189Smrg    if (pExaScr->do_migration) {
1108f7df2e56Smrg        ExaMigrationRec pixmaps[2];
1109f7df2e56Smrg
1110f7df2e56Smrg        pixmaps[0].as_dst = TRUE;
1111f7df2e56Smrg        pixmaps[0].as_src = FALSE;
1112f7df2e56Smrg        pixmaps[0].pPix = pPixmap;
1113f7df2e56Smrg        pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
1114f7df2e56Smrg                                                alu,
1115f7df2e56Smrg                                                hasClientClip) ? NULL : pRegion;
1116f7df2e56Smrg        pixmaps[1].as_dst = FALSE;
1117f7df2e56Smrg        pixmaps[1].as_src = TRUE;
1118f7df2e56Smrg        pixmaps[1].pPix = pTile;
1119f7df2e56Smrg        pixmaps[1].pReg = NULL;
1120f7df2e56Smrg
1121f7df2e56Smrg        exaDoMigration(pixmaps, 2, TRUE);
112205b261ecSmrg    }
112305b261ecSmrg
1124f7df2e56Smrg    pPixmap = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
112505b261ecSmrg
11264202a189Smrg    if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
1127f7df2e56Smrg        return FALSE;
1128f7df2e56Smrg
1129f7df2e56Smrg    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) {
1130f7df2e56Smrg        if (xoff || yoff)
1131f7df2e56Smrg            RegionTranslate(pRegion, xoff, yoff);
1132f7df2e56Smrg
1133f7df2e56Smrg        for (i = 0; i < nbox; i++) {
1134f7df2e56Smrg            int height = pBox[i].y2 - pBox[i].y1;
1135f7df2e56Smrg            int dstY = pBox[i].y1;
1136f7df2e56Smrg            int tileY;
1137f7df2e56Smrg
1138f7df2e56Smrg            if (alu == GXcopy)
1139f7df2e56Smrg                height = min(height, tileHeight);
1140f7df2e56Smrg
1141f7df2e56Smrg            modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
1142f7df2e56Smrg
1143f7df2e56Smrg            while (height > 0) {
1144f7df2e56Smrg                int width = pBox[i].x2 - pBox[i].x1;
1145f7df2e56Smrg                int dstX = pBox[i].x1;
1146f7df2e56Smrg                int tileX;
1147f7df2e56Smrg                int h = tileHeight - tileY;
1148f7df2e56Smrg
1149f7df2e56Smrg                if (alu == GXcopy)
1150f7df2e56Smrg                    width = min(width, tileWidth);
1151f7df2e56Smrg
1152f7df2e56Smrg                if (h > height)
1153f7df2e56Smrg                    h = height;
1154f7df2e56Smrg                height -= h;
1155f7df2e56Smrg
1156f7df2e56Smrg                modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
1157f7df2e56Smrg                        tileX);
1158f7df2e56Smrg
1159f7df2e56Smrg                while (width > 0) {
1160f7df2e56Smrg                    int w = tileWidth - tileX;
1161f7df2e56Smrg
1162f7df2e56Smrg                    if (w > width)
1163f7df2e56Smrg                        w = width;
1164f7df2e56Smrg                    width -= w;
1165f7df2e56Smrg
1166f7df2e56Smrg                    (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
1167f7df2e56Smrg                                            w, h);
1168f7df2e56Smrg                    dstX += w;
1169f7df2e56Smrg                    tileX = 0;
1170f7df2e56Smrg                }
1171f7df2e56Smrg                dstY += h;
1172f7df2e56Smrg                tileY = 0;
1173f7df2e56Smrg            }
1174f7df2e56Smrg        }
1175f7df2e56Smrg        (*pExaScr->info->DoneCopy) (pPixmap);
1176f7df2e56Smrg
1177f7df2e56Smrg        /* With GXcopy, we only need to do the basic algorithm up to the tile
1178f7df2e56Smrg         * size; then, we can just keep doubling the destination in each
1179f7df2e56Smrg         * direction until it fills the box. This way, the number of copy
1180f7df2e56Smrg         * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
1181f7df2e56Smrg         * rx/ry is the ratio between box and tile width/height. This can make
1182f7df2e56Smrg         * a big difference if each driver copy incurs a significant constant
1183f7df2e56Smrg         * overhead.
1184f7df2e56Smrg         */
1185f7df2e56Smrg        if (alu != GXcopy)
1186f7df2e56Smrg            ret = TRUE;
1187f7df2e56Smrg        else {
1188f7df2e56Smrg            Bool more_copy = FALSE;
1189f7df2e56Smrg
1190f7df2e56Smrg            for (i = 0; i < nbox; i++) {
1191f7df2e56Smrg                int dstX = pBox[i].x1 + tileWidth;
1192f7df2e56Smrg                int dstY = pBox[i].y1 + tileHeight;
1193f7df2e56Smrg
1194f7df2e56Smrg                if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
1195f7df2e56Smrg                    more_copy = TRUE;
1196f7df2e56Smrg                    break;
1197f7df2e56Smrg                }
1198f7df2e56Smrg            }
1199f7df2e56Smrg
1200f7df2e56Smrg            if (more_copy == FALSE)
1201f7df2e56Smrg                ret = TRUE;
1202f7df2e56Smrg
1203f7df2e56Smrg            if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
1204f7df2e56Smrg                                                            1, 1, alu,
1205f7df2e56Smrg                                                            planemask)) {
1206f7df2e56Smrg                for (i = 0; i < nbox; i++) {
1207f7df2e56Smrg                    int dstX = pBox[i].x1 + tileWidth;
1208f7df2e56Smrg                    int dstY = pBox[i].y1 + tileHeight;
1209f7df2e56Smrg                    int width = min(pBox[i].x2 - dstX, tileWidth);
1210f7df2e56Smrg                    int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
1211f7df2e56Smrg
1212f7df2e56Smrg                    while (dstX < pBox[i].x2) {
1213f7df2e56Smrg                        (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1214f7df2e56Smrg                                                dstX, pBox[i].y1, width,
1215f7df2e56Smrg                                                height);
1216f7df2e56Smrg                        dstX += width;
1217f7df2e56Smrg                        width = min(pBox[i].x2 - dstX, width * 2);
1218f7df2e56Smrg                    }
1219f7df2e56Smrg
1220f7df2e56Smrg                    width = pBox[i].x2 - pBox[i].x1;
1221f7df2e56Smrg                    height = min(pBox[i].y2 - dstY, tileHeight);
1222f7df2e56Smrg
1223f7df2e56Smrg                    while (dstY < pBox[i].y2) {
1224f7df2e56Smrg                        (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1225f7df2e56Smrg                                                pBox[i].x1, dstY, width,
1226f7df2e56Smrg                                                height);
1227f7df2e56Smrg                        dstY += height;
1228f7df2e56Smrg                        height = min(pBox[i].y2 - dstY, height * 2);
1229f7df2e56Smrg                    }
1230f7df2e56Smrg                }
1231f7df2e56Smrg
1232f7df2e56Smrg                (*pExaScr->info->DoneCopy) (pPixmap);
1233f7df2e56Smrg
1234f7df2e56Smrg                ret = TRUE;
1235f7df2e56Smrg            }
1236f7df2e56Smrg        }
1237f7df2e56Smrg
1238f7df2e56Smrg        exaMarkSync(pDrawable->pScreen);
1239f7df2e56Smrg
1240f7df2e56Smrg        if (xoff || yoff)
1241f7df2e56Smrg            RegionTranslate(pRegion, -xoff, -yoff);
124205b261ecSmrg    }
12434642e01fSmrg
12444642e01fSmrg    return ret;
124505b261ecSmrg}
124605b261ecSmrg
124705b261ecSmrg/**
124805b261ecSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
124905b261ecSmrg *
125005b261ecSmrg * This is probably the only case we actually care about.  The rest fall through
12514642e01fSmrg * to migration and fbGetImage, which hopefully will result in migration pushing
12524642e01fSmrg * the pixmap out of framebuffer.
125305b261ecSmrg */
125405b261ecSmrgvoid
1255f7df2e56SmrgexaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
1256f7df2e56Smrg            unsigned int format, unsigned long planeMask, char *d)
125705b261ecSmrg{
1258f7df2e56Smrg    ExaScreenPriv(pDrawable->pScreen);
1259f7df2e56Smrg    PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
1260f7df2e56Smrg
12614202a189Smrg    ExaPixmapPriv(pPix);
126205b261ecSmrg    int xoff, yoff;
126305b261ecSmrg    Bool ok;
126405b261ecSmrg
12654202a189Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut)
1266f7df2e56Smrg        goto fallback;
126705b261ecSmrg
12684202a189Smrg    /* If there's a system copy, we want to save the result there */
12694202a189Smrg    if (pExaPixmap->pDamage)
1270f7df2e56Smrg        goto fallback;
12714642e01fSmrg
1272f7df2e56Smrg    pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
12734642e01fSmrg
12744642e01fSmrg    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
1275f7df2e56Smrg        goto fallback;
127605b261ecSmrg
127705b261ecSmrg    /* Only cover the ZPixmap, solid copy case. */
127805b261ecSmrg    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
1279f7df2e56Smrg        goto fallback;
128005b261ecSmrg
128105b261ecSmrg    /* Only try to handle the 8bpp and up cases, since we don't want to think
128205b261ecSmrg     * about <8bpp.
128305b261ecSmrg     */
128405b261ecSmrg    if (pDrawable->bitsPerPixel < 8)
1285f7df2e56Smrg        goto fallback;
128605b261ecSmrg
12874642e01fSmrg    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
1288f7df2e56Smrg                                           pDrawable->y + y + yoff, w, h, d,
1289f7df2e56Smrg                                           PixmapBytePad(w, pDrawable->depth));
129005b261ecSmrg    if (ok) {
1291f7df2e56Smrg        exaWaitSync(pDrawable->pScreen);
1292f7df2e56Smrg        return;
129305b261ecSmrg    }
129405b261ecSmrg
1295f7df2e56Smrg fallback:
12964202a189Smrg    ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
129705b261ecSmrg}
1298