"Fossies" - the Fresh Open Source Software Archive

Member "xorg-server-1.20.8/exa/exa_accel.c" (29 Mar 2020, 42707 Bytes) of package /linux/misc/xorg-server-1.20.8.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "exa_accel.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.20.7_vs_1.20.8.

    1 /*
    2  * Copyright © 2001 Keith Packard
    3  *
    4  * Partly based on code that is Copyright © The XFree86 Project Inc.
    5  *
    6  * Permission to use, copy, modify, distribute, and sell this software and its
    7  * documentation for any purpose is hereby granted without fee, provided that
    8  * the above copyright notice appear in all copies and that both that
    9  * copyright notice and this permission notice appear in supporting
   10  * documentation, and that the name of Keith Packard not be used in
   11  * advertising or publicity pertaining to distribution of the software without
   12  * specific, written prior permission.  Keith Packard makes no
   13  * representations about the suitability of this software for any purpose.  It
   14  * is provided "as is" without express or implied warranty.
   15  *
   16  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
   18  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
   19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
   20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
   21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   22  * PERFORMANCE OF THIS SOFTWARE.
   23  *
   24  * Authors:
   25  *    Eric Anholt <eric@anholt.net>
   26  *    Michel Dänzer <michel@tungstengraphics.com>
   27  *
   28  */
   29 
   30 #ifdef HAVE_DIX_CONFIG_H
   31 #include <dix-config.h>
   32 #endif
   33 #include "exa_priv.h"
   34 #include <X11/fonts/fontstruct.h>
   35 #include "dixfontstr.h"
   36 #include "exa.h"
   37 
   38 static void
   39 exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
   40              DDXPointPtr ppt, int *pwidth, int fSorted)
   41 {
   42     ScreenPtr pScreen = pDrawable->pScreen;
   43 
   44     ExaScreenPriv(pScreen);
   45     RegionPtr pClip = fbGetCompositeClip(pGC);
   46     PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
   47 
   48     ExaPixmapPriv(pPixmap);
   49     BoxPtr pextent, pbox;
   50     int nbox;
   51     int extentX1, extentX2, extentY1, extentY2;
   52     int fullX1, fullX2, fullY1;
   53     int partX1, partX2;
   54     int off_x, off_y;
   55 
   56     if (pExaScr->fallback_counter ||
   57         pExaScr->swappedOut ||
   58         pGC->fillStyle != FillSolid || pExaPixmap->accel_blocked) {
   59         ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted);
   60         return;
   61     }
   62 
   63     if (pExaScr->do_migration) {
   64         ExaMigrationRec pixmaps[1];
   65 
   66         pixmaps[0].as_dst = TRUE;
   67         pixmaps[0].as_src = FALSE;
   68         pixmaps[0].pPix = pPixmap;
   69         pixmaps[0].pReg = NULL;
   70 
   71         exaDoMigration(pixmaps, 1, TRUE);
   72     }
   73 
   74     if (!(pPixmap = exaGetOffscreenPixmap(pDrawable, &off_x, &off_y)) ||
   75         !(*pExaScr->info->PrepareSolid) (pPixmap,
   76                                          pGC->alu,
   77                                          pGC->planemask, pGC->fgPixel)) {
   78         ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted);
   79         return;
   80     }
   81 
   82     pextent = RegionExtents(pClip);
   83     extentX1 = pextent->x1;
   84     extentY1 = pextent->y1;
   85     extentX2 = pextent->x2;
   86     extentY2 = pextent->y2;
   87     while (n--) {
   88         fullX1 = ppt->x;
   89         fullY1 = ppt->y;
   90         fullX2 = fullX1 + (int) *pwidth;
   91         ppt++;
   92         pwidth++;
   93 
   94         if (fullY1 < extentY1 || extentY2 <= fullY1)
   95             continue;
   96 
   97         if (fullX1 < extentX1)
   98             fullX1 = extentX1;
   99 
  100         if (fullX2 > extentX2)
  101             fullX2 = extentX2;
  102 
  103         if (fullX1 >= fullX2)
  104             continue;
  105 
  106         nbox = RegionNumRects(pClip);
  107         if (nbox == 1) {
  108             (*pExaScr->info->Solid) (pPixmap,
  109                                      fullX1 + off_x, fullY1 + off_y,
  110                                      fullX2 + off_x, fullY1 + 1 + off_y);
  111         }
  112         else {
  113             pbox = RegionRects(pClip);
  114             while (nbox--) {
  115                 if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) {
  116                     partX1 = pbox->x1;
  117                     if (partX1 < fullX1)
  118                         partX1 = fullX1;
  119                     partX2 = pbox->x2;
  120                     if (partX2 > fullX2)
  121                         partX2 = fullX2;
  122                     if (partX2 > partX1) {
  123                         (*pExaScr->info->Solid) (pPixmap,
  124                                                  partX1 + off_x, fullY1 + off_y,
  125                                                  partX2 + off_x,
  126                                                  fullY1 + 1 + off_y);
  127                     }
  128                 }
  129                 pbox++;
  130             }
  131         }
  132     }
  133     (*pExaScr->info->DoneSolid) (pPixmap);
  134     exaMarkSync(pScreen);
  135 }
  136 
  137 static Bool
  138 exaDoPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
  139               int w, int h, int format, char *bits, int src_stride)
  140 {
  141     ExaScreenPriv(pDrawable->pScreen);
  142     PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
  143 
  144     ExaPixmapPriv(pPix);
  145     RegionPtr pClip;
  146     BoxPtr pbox;
  147     int nbox;
  148     int xoff, yoff;
  149     int bpp = pDrawable->bitsPerPixel;
  150     Bool ret = TRUE;
  151 
  152     if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
  153         !pExaScr->info->UploadToScreen)
  154         return FALSE;
  155 
  156     /* If there's a system copy, we want to save the result there */
  157     if (pExaPixmap->pDamage)
  158         return FALSE;
  159 
  160     /* Don't bother with under 8bpp, XYPixmaps. */
  161     if (format != ZPixmap || bpp < 8)
  162         return FALSE;
  163 
  164     /* Only accelerate copies: no rop or planemask. */
  165     if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
  166         return FALSE;
  167 
  168     if (pExaScr->swappedOut)
  169         return FALSE;
  170 
  171     if (pExaScr->do_migration) {
  172         ExaMigrationRec pixmaps[1];
  173 
  174         pixmaps[0].as_dst = TRUE;
  175         pixmaps[0].as_src = FALSE;
  176         pixmaps[0].pPix = pPix;
  177         pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
  178 
  179         exaDoMigration(pixmaps, 1, TRUE);
  180     }
  181 
  182     pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
  183 
  184     if (!pPix)
  185         return FALSE;
  186 
  187     x += pDrawable->x;
  188     y += pDrawable->y;
  189 
  190     pClip = fbGetCompositeClip(pGC);
  191     for (nbox = RegionNumRects(pClip),
  192          pbox = RegionRects(pClip); nbox--; pbox++) {
  193         int x1 = x;
  194         int y1 = y;
  195         int x2 = x + w;
  196         int y2 = y + h;
  197         char *src;
  198         Bool ok;
  199 
  200         if (x1 < pbox->x1)
  201             x1 = pbox->x1;
  202         if (y1 < pbox->y1)
  203             y1 = pbox->y1;
  204         if (x2 > pbox->x2)
  205             x2 = pbox->x2;
  206         if (y2 > pbox->y2)
  207             y2 = pbox->y2;
  208         if (x1 >= x2 || y1 >= y2)
  209             continue;
  210 
  211         src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
  212         ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
  213                                            x2 - x1, y2 - y1, src, src_stride);
  214         /* We have to fall back completely, and ignore what has already been completed.
  215          * Messing with the fb layer directly like we used to is completely unacceptable.
  216          */
  217         if (!ok) {
  218             ret = FALSE;
  219             break;
  220         }
  221     }
  222 
  223     if (ret)
  224         exaMarkSync(pDrawable->pScreen);
  225 
  226     return ret;
  227 }
  228 
  229 static void
  230 exaPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
  231             int w, int h, int leftPad, int format, char *bits)
  232 {
  233     if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
  234                        PixmapBytePad(w, pDrawable->depth)))
  235         ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
  236                          bits);
  237 }
  238 
  239 static Bool inline
  240 exaCopyNtoNTwoDir(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
  241                   GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
  242 {
  243     ExaScreenPriv(pDstDrawable->pScreen);
  244     PixmapPtr pSrcPixmap, pDstPixmap;
  245     int src_off_x, src_off_y, dst_off_x, dst_off_y;
  246     int dirsetup;
  247 
  248     /* Need to get both pixmaps to call the driver routines */
  249     pSrcPixmap = exaGetOffscreenPixmap(pSrcDrawable, &src_off_x, &src_off_y);
  250     pDstPixmap = exaGetOffscreenPixmap(pDstDrawable, &dst_off_x, &dst_off_y);
  251     if (!pSrcPixmap || !pDstPixmap)
  252         return FALSE;
  253 
  254     /*
  255      * Now the case of a chip that only supports xdir = ydir = 1 or
  256      * xdir = ydir = -1, but we have xdir != ydir.
  257      */
  258     dirsetup = 0;               /* No direction set up yet. */
  259     for (; nbox; pbox++, nbox--) {
  260         if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
  261             /* Do a xdir = ydir = -1 blit instead. */
  262             if (dirsetup != -1) {
  263                 if (dirsetup != 0)
  264                     pExaScr->info->DoneCopy(pDstPixmap);
  265                 dirsetup = -1;
  266                 if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
  267                                                     pDstPixmap,
  268                                                     -1, -1,
  269                                                     pGC ? pGC->alu : GXcopy,
  270                                                     pGC ? pGC->planemask :
  271                                                     FB_ALLONES))
  272                     return FALSE;
  273             }
  274             (*pExaScr->info->Copy) (pDstPixmap,
  275                                     src_off_x + pbox->x1 + dx,
  276                                     src_off_y + pbox->y1 + dy,
  277                                     dst_off_x + pbox->x1,
  278                                     dst_off_y + pbox->y1,
  279                                     pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
  280         }
  281         else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
  282             /* Do a xdir = ydir = 1 blit instead. */
  283             if (dirsetup != 1) {
  284                 if (dirsetup != 0)
  285                     pExaScr->info->DoneCopy(pDstPixmap);
  286                 dirsetup = 1;
  287                 if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
  288                                                     pDstPixmap,
  289                                                     1, 1,
  290                                                     pGC ? pGC->alu : GXcopy,
  291                                                     pGC ? pGC->planemask :
  292                                                     FB_ALLONES))
  293                     return FALSE;
  294             }
  295             (*pExaScr->info->Copy) (pDstPixmap,
  296                                     src_off_x + pbox->x1 + dx,
  297                                     src_off_y + pbox->y1 + dy,
  298                                     dst_off_x + pbox->x1,
  299                                     dst_off_y + pbox->y1,
  300                                     pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
  301         }
  302         else if (dx >= 0) {
  303             /*
  304              * xdir = 1, ydir = -1.
  305              * Perform line-by-line xdir = ydir = 1 blits, going up.
  306              */
  307             int i;
  308 
  309             if (dirsetup != 1) {
  310                 if (dirsetup != 0)
  311                     pExaScr->info->DoneCopy(pDstPixmap);
  312                 dirsetup = 1;
  313                 if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
  314                                                     pDstPixmap,
  315                                                     1, 1,
  316                                                     pGC ? pGC->alu : GXcopy,
  317                                                     pGC ? pGC->planemask :
  318                                                     FB_ALLONES))
  319                     return FALSE;
  320             }
  321             for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
  322                 (*pExaScr->info->Copy) (pDstPixmap,
  323                                         src_off_x + pbox->x1 + dx,
  324                                         src_off_y + pbox->y1 + dy + i,
  325                                         dst_off_x + pbox->x1,
  326                                         dst_off_y + pbox->y1 + i,
  327                                         pbox->x2 - pbox->x1, 1);
  328         }
  329         else {
  330             /*
  331              * xdir = -1, ydir = 1.
  332              * Perform line-by-line xdir = ydir = -1 blits, going down.
  333              */
  334             int i;
  335 
  336             if (dirsetup != -1) {
  337                 if (dirsetup != 0)
  338                     pExaScr->info->DoneCopy(pDstPixmap);
  339                 dirsetup = -1;
  340                 if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
  341                                                     pDstPixmap,
  342                                                     -1, -1,
  343                                                     pGC ? pGC->alu : GXcopy,
  344                                                     pGC ? pGC->planemask :
  345                                                     FB_ALLONES))
  346                     return FALSE;
  347             }
  348             for (i = 0; i < pbox->y2 - pbox->y1; i++)
  349                 (*pExaScr->info->Copy) (pDstPixmap,
  350                                         src_off_x + pbox->x1 + dx,
  351                                         src_off_y + pbox->y1 + dy + i,
  352                                         dst_off_x + pbox->x1,
  353                                         dst_off_y + pbox->y1 + i,
  354                                         pbox->x2 - pbox->x1, 1);
  355         }
  356     }
  357     if (dirsetup != 0)
  358         pExaScr->info->DoneCopy(pDstPixmap);
  359     exaMarkSync(pDstDrawable->pScreen);
  360     return TRUE;
  361 }
  362 
  363 Bool
  364 exaHWCopyNtoN(DrawablePtr pSrcDrawable,
  365               DrawablePtr pDstDrawable,
  366               GCPtr pGC,
  367               BoxPtr pbox,
  368               int nbox, int dx, int dy, Bool reverse, Bool upsidedown)
  369 {
  370     ExaScreenPriv(pDstDrawable->pScreen);
  371     PixmapPtr pSrcPixmap, pDstPixmap;
  372     ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
  373     int src_off_x, src_off_y;
  374     int dst_off_x, dst_off_y;
  375     RegionPtr srcregion = NULL, dstregion = NULL;
  376     xRectangle *rects;
  377     Bool ret = TRUE;
  378 
  379     /* avoid doing copy operations if no boxes */
  380     if (nbox == 0)
  381         return TRUE;
  382 
  383     pSrcPixmap = exaGetDrawablePixmap(pSrcDrawable);
  384     pDstPixmap = exaGetDrawablePixmap(pDstDrawable);
  385 
  386     exaGetDrawableDeltas(pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
  387     exaGetDrawableDeltas(pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
  388 
  389     rects = xallocarray(nbox, sizeof(xRectangle));
  390 
  391     if (rects) {
  392         int i;
  393         int ordering;
  394 
  395         for (i = 0; i < nbox; i++) {
  396             rects[i].x = pbox[i].x1 + dx + src_off_x;
  397             rects[i].y = pbox[i].y1 + dy + src_off_y;
  398             rects[i].width = pbox[i].x2 - pbox[i].x1;
  399             rects[i].height = pbox[i].y2 - pbox[i].y1;
  400         }
  401 
  402         /* This must match the RegionCopy() logic for reversing rect order */
  403         if (nbox == 1 || (dx > 0 && dy > 0) ||
  404             (pDstDrawable != pSrcDrawable &&
  405              (pDstDrawable->type != DRAWABLE_WINDOW ||
  406               pSrcDrawable->type != DRAWABLE_WINDOW)))
  407             ordering = CT_YXBANDED;
  408         else
  409             ordering = CT_UNSORTED;
  410 
  411         srcregion = RegionFromRects(nbox, rects, ordering);
  412         free(rects);
  413 
  414         if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
  415                                            pGC->fillStyle, pGC->alu,
  416                                            pGC->clientClip != NULL)) {
  417             dstregion = RegionCreate(NullBox, 0);
  418             RegionCopy(dstregion, srcregion);
  419             RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
  420                             dst_off_y - dy - src_off_y);
  421         }
  422     }
  423 
  424     pSrcExaPixmap = ExaGetPixmapPriv(pSrcPixmap);
  425     pDstExaPixmap = ExaGetPixmapPriv(pDstPixmap);
  426 
  427     /* Check whether the accelerator can use this pixmap.
  428      * If the pitch of the pixmaps is out of range, there's nothing
  429      * we can do but fall back to software rendering.
  430      */
  431     if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
  432         pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
  433         goto fallback;
  434 
  435     /* If the width or the height of either of the pixmaps
  436      * is out of range, check whether the boxes are actually out of the
  437      * addressable range as well. If they aren't, we can still do
  438      * the copying in hardware.
  439      */
  440     if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
  441         int i;
  442 
  443         for (i = 0; i < nbox; i++) {
  444             /* src */
  445             if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
  446                 (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
  447                 goto fallback;
  448 
  449             /* dst */
  450             if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
  451                 (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
  452                 goto fallback;
  453         }
  454     }
  455 
  456     if (pExaScr->do_migration) {
  457         ExaMigrationRec pixmaps[2];
  458 
  459         pixmaps[0].as_dst = TRUE;
  460         pixmaps[0].as_src = FALSE;
  461         pixmaps[0].pPix = pDstPixmap;
  462         pixmaps[0].pReg = dstregion;
  463         pixmaps[1].as_dst = FALSE;
  464         pixmaps[1].as_src = TRUE;
  465         pixmaps[1].pPix = pSrcPixmap;
  466         pixmaps[1].pReg = srcregion;
  467 
  468         exaDoMigration(pixmaps, 2, TRUE);
  469     }
  470 
  471     /* Mixed directions must be handled specially if the card is lame */
  472     if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
  473         reverse != upsidedown) {
  474         if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
  475                               dx, dy))
  476             goto out;
  477         goto fallback;
  478     }
  479 
  480     if (exaPixmapHasGpuCopy(pDstPixmap)) {
  481         /* Normal blitting. */
  482         if (exaPixmapHasGpuCopy(pSrcPixmap)) {
  483             if (!(*pExaScr->info->PrepareCopy)
  484                 (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, upsidedown ? -1 : 1,
  485                  pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) {
  486                 goto fallback;
  487             }
  488 
  489             while (nbox--) {
  490                 (*pExaScr->info->Copy) (pDstPixmap,
  491                                         pbox->x1 + dx + src_off_x,
  492                                         pbox->y1 + dy + src_off_y,
  493                                         pbox->x1 + dst_off_x,
  494                                         pbox->y1 + dst_off_y,
  495                                         pbox->x2 - pbox->x1,
  496                                         pbox->y2 - pbox->y1);
  497                 pbox++;
  498             }
  499 
  500             (*pExaScr->info->DoneCopy) (pDstPixmap);
  501             exaMarkSync(pDstDrawable->pScreen);
  502             /* UTS: mainly for SHM PutImage's secondary path.
  503              *
  504              * Only taking this path for directly accessible pixmaps.
  505              */
  506         }
  507         else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
  508             int bpp = pSrcDrawable->bitsPerPixel;
  509             int src_stride = exaGetPixmapPitch(pSrcPixmap);
  510             CARD8 *src = NULL;
  511 
  512             if (!pExaScr->info->UploadToScreen)
  513                 goto fallback;
  514 
  515             if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
  516                 goto fallback;
  517 
  518             if (pSrcDrawable->bitsPerPixel < 8)
  519                 goto fallback;
  520 
  521             if (pGC &&
  522                 !(pGC->alu == GXcopy &&
  523                   EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask)))
  524                 goto fallback;
  525 
  526             while (nbox--) {
  527                 src =
  528                     pSrcExaPixmap->sys_ptr + (pbox->y1 + dy +
  529                                               src_off_y) * src_stride +
  530                     (pbox->x1 + dx + src_off_x) * (bpp / 8);
  531                 if (!pExaScr->info->
  532                     UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
  533                                    pbox->y1 + dst_off_y, pbox->x2 - pbox->x1,
  534                                    pbox->y2 - pbox->y1, (char *) src,
  535                                    src_stride))
  536                     goto fallback;
  537 
  538                 pbox++;
  539             }
  540         }
  541         else
  542             goto fallback;
  543     }
  544     else
  545         goto fallback;
  546 
  547     goto out;
  548 
  549  fallback:
  550     ret = FALSE;
  551 
  552  out:
  553     if (dstregion) {
  554         RegionUninit(dstregion);
  555         RegionDestroy(dstregion);
  556     }
  557     if (srcregion) {
  558         RegionUninit(srcregion);
  559         RegionDestroy(srcregion);
  560     }
  561 
  562     return ret;
  563 }
  564 
  565 void
  566 exaCopyNtoN(DrawablePtr pSrcDrawable,
  567             DrawablePtr pDstDrawable,
  568             GCPtr pGC,
  569             BoxPtr pbox,
  570             int nbox,
  571             int dx,
  572             int dy,
  573             Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
  574 {
  575     ExaScreenPriv(pDstDrawable->pScreen);
  576 
  577     if (pExaScr->fallback_counter ||
  578         (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
  579         return;
  580 
  581     if (exaHWCopyNtoN
  582         (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
  583          upsidedown))
  584         return;
  585 
  586     /* This is a CopyWindow, it's cleaner to fallback at the original call. */
  587     if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
  588         pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
  589         return;
  590     }
  591 
  592     /* fallback */
  593     ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy,
  594                      reverse, upsidedown, bitplane, closure);
  595 }
  596 
  597 RegionPtr
  598 exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
  599             int srcx, int srcy, int width, int height, int dstx, int dsty)
  600 {
  601     ExaScreenPriv(pDstDrawable->pScreen);
  602 
  603     if (pExaScr->fallback_counter || pExaScr->swappedOut) {
  604         return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
  605                                 srcx, srcy, width, height, dstx, dsty);
  606     }
  607 
  608     return miDoCopy(pSrcDrawable, pDstDrawable, pGC,
  609                     srcx, srcy, width, height,
  610                     dstx, dsty, exaCopyNtoN, 0, NULL);
  611 }
  612 
  613 static void
  614 exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
  615              DDXPointPtr ppt)
  616 {
  617     ExaScreenPriv(pDrawable->pScreen);
  618     int i;
  619     xRectangle *prect;
  620 
  621     /* If we can't reuse the current GC as is, don't bother accelerating the
  622      * points.
  623      */
  624     if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) {
  625         ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
  626         return;
  627     }
  628 
  629     prect = xallocarray(npt, sizeof(xRectangle));
  630     for (i = 0; i < npt; i++) {
  631         prect[i].x = ppt[i].x;
  632         prect[i].y = ppt[i].y;
  633         if (i > 0 && mode == CoordModePrevious) {
  634             prect[i].x += prect[i - 1].x;
  635             prect[i].y += prect[i - 1].y;
  636         }
  637         prect[i].width = 1;
  638         prect[i].height = 1;
  639     }
  640     pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
  641     free(prect);
  642 }
  643 
  644 /**
  645  * exaPolylines() checks if it can accelerate the lines as a group of
  646  * horizontal or vertical lines (rectangles), and uses existing rectangle fill
  647  * acceleration if so.
  648  */
  649 static void
  650 exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
  651              DDXPointPtr ppt)
  652 {
  653     ExaScreenPriv(pDrawable->pScreen);
  654     xRectangle *prect;
  655     int x1, x2, y1, y2;
  656     int i;
  657 
  658     if (pExaScr->fallback_counter) {
  659         ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
  660         return;
  661     }
  662 
  663     /* Don't try to do wide lines or non-solid fill style. */
  664     if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
  665         pGC->fillStyle != FillSolid) {
  666         ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
  667         return;
  668     }
  669 
  670     prect = xallocarray(npt - 1, sizeof(xRectangle));
  671     x1 = ppt[0].x;
  672     y1 = ppt[0].y;
  673     /* If we have any non-horizontal/vertical, fall back. */
  674     for (i = 0; i < npt - 1; i++) {
  675         if (mode == CoordModePrevious) {
  676             x2 = x1 + ppt[i + 1].x;
  677             y2 = y1 + ppt[i + 1].y;
  678         }
  679         else {
  680             x2 = ppt[i + 1].x;
  681             y2 = ppt[i + 1].y;
  682         }
  683 
  684         if (x1 != x2 && y1 != y2) {
  685             free(prect);
  686             ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
  687             return;
  688         }
  689 
  690         if (x1 < x2) {
  691             prect[i].x = x1;
  692             prect[i].width = x2 - x1 + 1;
  693         }
  694         else {
  695             prect[i].x = x2;
  696             prect[i].width = x1 - x2 + 1;
  697         }
  698         if (y1 < y2) {
  699             prect[i].y = y1;
  700             prect[i].height = y2 - y1 + 1;
  701         }
  702         else {
  703             prect[i].y = y2;
  704             prect[i].height = y1 - y2 + 1;
  705         }
  706 
  707         x1 = x2;
  708         y1 = y2;
  709     }
  710     pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
  711     free(prect);
  712 }
  713 
  714 /**
  715  * exaPolySegment() checks if it can accelerate the lines as a group of
  716  * horizontal or vertical lines (rectangles), and uses existing rectangle fill
  717  * acceleration if so.
  718  */
  719 static void
  720 exaPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg)
  721 {
  722     ExaScreenPriv(pDrawable->pScreen);
  723     xRectangle *prect;
  724     int i;
  725 
  726     /* Don't try to do wide lines or non-solid fill style. */
  727     if (pExaScr->fallback_counter || pGC->lineWidth != 0 ||
  728         pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) {
  729         ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
  730         return;
  731     }
  732 
  733     /* If we have any non-horizontal/vertical, fall back. */
  734     for (i = 0; i < nseg; i++) {
  735         if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
  736             ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
  737             return;
  738         }
  739     }
  740 
  741     prect = xallocarray(nseg, sizeof(xRectangle));
  742     for (i = 0; i < nseg; i++) {
  743         if (pSeg[i].x1 < pSeg[i].x2) {
  744             prect[i].x = pSeg[i].x1;
  745             prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
  746         }
  747         else {
  748             prect[i].x = pSeg[i].x2;
  749             prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
  750         }
  751         if (pSeg[i].y1 < pSeg[i].y2) {
  752             prect[i].y = pSeg[i].y1;
  753             prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
  754         }
  755         else {
  756             prect[i].y = pSeg[i].y2;
  757             prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
  758         }
  759 
  760         /* don't paint last pixel */
  761         if (pGC->capStyle == CapNotLast) {
  762             if (prect[i].width == 1)
  763                 prect[i].height--;
  764             else
  765                 prect[i].width--;
  766         }
  767     }
  768     pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
  769     free(prect);
  770 }
  771 
  772 static Bool exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion,
  773                                Pixel pixel, CARD32 planemask, CARD32 alu,
  774                                Bool hasClientClip);
  775 
  776 static void
  777 exaPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect)
  778 {
  779     ExaScreenPriv(pDrawable->pScreen);
  780     RegionPtr pClip = fbGetCompositeClip(pGC);
  781     PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
  782 
  783     ExaPixmapPriv(pPixmap);
  784     register BoxPtr pbox;
  785     BoxPtr pextent;
  786     int extentX1, extentX2, extentY1, extentY2;
  787     int fullX1, fullX2, fullY1, fullY2;
  788     int partX1, partX2, partY1, partY2;
  789     int xoff, yoff;
  790     int xorg, yorg;
  791     int n;
  792     RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
  793 
  794     /* Compute intersection of rects and clip region */
  795     RegionTranslate(pReg, pDrawable->x, pDrawable->y);
  796     RegionIntersect(pReg, pClip, pReg);
  797 
  798     if (!RegionNumRects(pReg)) {
  799         goto out;
  800     }
  801 
  802     exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
  803 
  804     if (pExaScr->fallback_counter || pExaScr->swappedOut ||
  805         pExaPixmap->accel_blocked) {
  806         goto fallback;
  807     }
  808 
  809     /* For ROPs where overlaps don't matter, convert rectangles to region and
  810      * call exaFillRegion{Solid,Tiled}.
  811      */
  812     if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
  813         (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
  814          pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
  815          pGC->alu == GXset)) {
  816         if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
  817              exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
  818                                 pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
  819                                 pGC->alu, pGC->clientClip != NULL)) ||
  820             (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
  821              exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
  822                                 pGC->planemask, pGC->alu,
  823                                 pGC->clientClip != NULL))) {
  824             goto out;
  825         }
  826     }
  827 
  828     if (pGC->fillStyle != FillSolid &&
  829         !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) {
  830         goto fallback;
  831     }
  832 
  833     if (pExaScr->do_migration) {
  834         ExaMigrationRec pixmaps[1];
  835 
  836         pixmaps[0].as_dst = TRUE;
  837         pixmaps[0].as_src = FALSE;
  838         pixmaps[0].pPix = pPixmap;
  839         pixmaps[0].pReg = NULL;
  840 
  841         exaDoMigration(pixmaps, 1, TRUE);
  842     }
  843 
  844     if (!exaPixmapHasGpuCopy(pPixmap) ||
  845         !(*pExaScr->info->PrepareSolid) (pPixmap,
  846                                          pGC->alu,
  847                                          pGC->planemask, pGC->fgPixel)) {
  848  fallback:
  849         ExaCheckPolyFillRect(pDrawable, pGC, nrect, prect);
  850         goto out;
  851     }
  852 
  853     xorg = pDrawable->x;
  854     yorg = pDrawable->y;
  855 
  856     pextent = RegionExtents(pClip);
  857     extentX1 = pextent->x1;
  858     extentY1 = pextent->y1;
  859     extentX2 = pextent->x2;
  860     extentY2 = pextent->y2;
  861     while (nrect--) {
  862         fullX1 = prect->x + xorg;
  863         fullY1 = prect->y + yorg;
  864         fullX2 = fullX1 + (int) prect->width;
  865         fullY2 = fullY1 + (int) prect->height;
  866         prect++;
  867 
  868         if (fullX1 < extentX1)
  869             fullX1 = extentX1;
  870 
  871         if (fullY1 < extentY1)
  872             fullY1 = extentY1;
  873 
  874         if (fullX2 > extentX2)
  875             fullX2 = extentX2;
  876 
  877         if (fullY2 > extentY2)
  878             fullY2 = extentY2;
  879 
  880         if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
  881             continue;
  882         n = RegionNumRects(pClip);
  883         if (n == 1) {
  884             (*pExaScr->info->Solid) (pPixmap,
  885                                      fullX1 + xoff, fullY1 + yoff,
  886                                      fullX2 + xoff, fullY2 + yoff);
  887         }
  888         else {
  889             pbox = RegionRects(pClip);
  890             /*
  891              * clip the rectangle to each box in the clip region
  892              * this is logically equivalent to calling Intersect(),
  893              * but rectangles may overlap each other here.
  894              */
  895             while (n--) {
  896                 partX1 = pbox->x1;
  897                 if (partX1 < fullX1)
  898                     partX1 = fullX1;
  899                 partY1 = pbox->y1;
  900                 if (partY1 < fullY1)
  901                     partY1 = fullY1;
  902                 partX2 = pbox->x2;
  903                 if (partX2 > fullX2)
  904                     partX2 = fullX2;
  905                 partY2 = pbox->y2;
  906                 if (partY2 > fullY2)
  907                     partY2 = fullY2;
  908 
  909                 pbox++;
  910 
  911                 if (partX1 < partX2 && partY1 < partY2) {
  912                     (*pExaScr->info->Solid) (pPixmap,
  913                                              partX1 + xoff, partY1 + yoff,
  914                                              partX2 + xoff, partY2 + yoff);
  915                 }
  916             }
  917         }
  918     }
  919     (*pExaScr->info->DoneSolid) (pPixmap);
  920     exaMarkSync(pDrawable->pScreen);
  921 
  922  out:
  923     RegionUninit(pReg);
  924     RegionDestroy(pReg);
  925 }
  926 
  927 const GCOps exaOps = {
  928     exaFillSpans,
  929     ExaCheckSetSpans,
  930     exaPutImage,
  931     exaCopyArea,
  932     ExaCheckCopyPlane,
  933     exaPolyPoint,
  934     exaPolylines,
  935     exaPolySegment,
  936     miPolyRectangle,
  937     ExaCheckPolyArc,
  938     miFillPolygon,
  939     exaPolyFillRect,
  940     miPolyFillArc,
  941     miPolyText8,
  942     miPolyText16,
  943     miImageText8,
  944     miImageText16,
  945     ExaCheckImageGlyphBlt,
  946     ExaCheckPolyGlyphBlt,
  947     ExaCheckPushPixels,
  948 };
  949 
  950 void
  951 exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
  952 {
  953     RegionRec rgnDst;
  954     int dx, dy;
  955     PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
  956 
  957     ExaScreenPriv(pWin->drawable.pScreen);
  958 
  959     dx = ptOldOrg.x - pWin->drawable.x;
  960     dy = ptOldOrg.y - pWin->drawable.y;
  961     RegionTranslate(prgnSrc, -dx, -dy);
  962 
  963     RegionInit(&rgnDst, NullBox, 0);
  964 
  965     RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
  966 #ifdef COMPOSITE
  967     if (pPixmap->screen_x || pPixmap->screen_y)
  968         RegionTranslate(&rgnDst, -pPixmap->screen_x, -pPixmap->screen_y);
  969 #endif
  970 
  971     if (pExaScr->fallback_counter) {
  972         pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
  973         goto fallback;
  974     }
  975 
  976     pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
  977     miCopyRegion(&pPixmap->drawable, &pPixmap->drawable,
  978                  NULL, &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
  979     pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
  980 
  981  fallback:
  982     RegionUninit(&rgnDst);
  983 
  984     if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
  985         pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
  986         RegionTranslate(prgnSrc, dx, dy);
  987         ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
  988     }
  989 }
  990 
  991 static Bool
  992 exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel,
  993                    CARD32 planemask, CARD32 alu, Bool hasClientClip)
  994 {
  995     ExaScreenPriv(pDrawable->pScreen);
  996     PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
  997 
  998     ExaPixmapPriv(pPixmap);
  999     int xoff, yoff;
 1000     Bool ret = FALSE;
 1001 
 1002     exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
 1003     RegionTranslate(pRegion, xoff, yoff);
 1004 
 1005     if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
 1006         goto out;
 1007 
 1008     if (pExaScr->do_migration) {
 1009         ExaMigrationRec pixmaps[1];
 1010 
 1011         pixmaps[0].as_dst = TRUE;
 1012         pixmaps[0].as_src = FALSE;
 1013         pixmaps[0].pPix = pPixmap;
 1014         pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
 1015                                                 alu,
 1016                                                 hasClientClip) ? NULL : pRegion;
 1017 
 1018         exaDoMigration(pixmaps, 1, TRUE);
 1019     }
 1020 
 1021     if (exaPixmapHasGpuCopy(pPixmap) &&
 1022         (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) {
 1023         int nbox;
 1024         BoxPtr pBox;
 1025 
 1026         nbox = RegionNumRects(pRegion);
 1027         pBox = RegionRects(pRegion);
 1028 
 1029         while (nbox--) {
 1030             (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
 1031                                      pBox->y2);
 1032             pBox++;
 1033         }
 1034         (*pExaScr->info->DoneSolid) (pPixmap);
 1035         exaMarkSync(pDrawable->pScreen);
 1036 
 1037         if (pExaPixmap->pDamage &&
 1038             pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
 1039             pDrawable->width == 1 && pDrawable->height == 1 &&
 1040             pDrawable->bitsPerPixel != 24 && alu == GXcopy) {
 1041             RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
 1042 
 1043             switch (pDrawable->bitsPerPixel) {
 1044             case 32:
 1045                 *(CARD32 *) pExaPixmap->sys_ptr = pixel;
 1046                 break;
 1047             case 16:
 1048                 *(CARD16 *) pExaPixmap->sys_ptr = pixel;
 1049                 break;
 1050             case 8:
 1051             case 4:
 1052             case 1:
 1053                 *(CARD8 *) pExaPixmap->sys_ptr = pixel;
 1054             }
 1055 
 1056             RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, pRegion);
 1057             RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, pRegion);
 1058             RegionSubtract(pending_damage, pending_damage, pRegion);
 1059         }
 1060 
 1061         ret = TRUE;
 1062     }
 1063 
 1064  out:
 1065     RegionTranslate(pRegion, -xoff, -yoff);
 1066 
 1067     return ret;
 1068 }
 1069 
 1070 /* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
 1071  * Based on fbFillRegionTiled(), fbTile().
 1072  */
 1073 Bool
 1074 exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
 1075                    DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
 1076                    Bool hasClientClip)
 1077 {
 1078     ExaScreenPriv(pDrawable->pScreen);
 1079     PixmapPtr pPixmap;
 1080     ExaPixmapPrivPtr pExaPixmap;
 1081     ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
 1082     int xoff, yoff;
 1083     int tileWidth, tileHeight;
 1084     int nbox = RegionNumRects(pRegion);
 1085     BoxPtr pBox = RegionRects(pRegion);
 1086     Bool ret = FALSE;
 1087     int i;
 1088 
 1089     tileWidth = pTile->drawable.width;
 1090     tileHeight = pTile->drawable.height;
 1091 
 1092     /* If we're filling with a solid color, grab it out and go to
 1093      * FillRegionSolid, saving numerous copies.
 1094      */
 1095     if (tileWidth == 1 && tileHeight == 1)
 1096         return exaFillRegionSolid(pDrawable, pRegion,
 1097                                   exaGetPixmapFirstPixel(pTile), planemask,
 1098                                   alu, hasClientClip);
 1099 
 1100     pPixmap = exaGetDrawablePixmap(pDrawable);
 1101     pExaPixmap = ExaGetPixmapPriv(pPixmap);
 1102 
 1103     if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
 1104         pTileExaPixmap->accel_blocked)
 1105         return FALSE;
 1106 
 1107     if (pExaScr->do_migration) {
 1108         ExaMigrationRec pixmaps[2];
 1109 
 1110         pixmaps[0].as_dst = TRUE;
 1111         pixmaps[0].as_src = FALSE;
 1112         pixmaps[0].pPix = pPixmap;
 1113         pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
 1114                                                 alu,
 1115                                                 hasClientClip) ? NULL : pRegion;
 1116         pixmaps[1].as_dst = FALSE;
 1117         pixmaps[1].as_src = TRUE;
 1118         pixmaps[1].pPix = pTile;
 1119         pixmaps[1].pReg = NULL;
 1120 
 1121         exaDoMigration(pixmaps, 2, TRUE);
 1122     }
 1123 
 1124     pPixmap = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
 1125 
 1126     if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
 1127         return FALSE;
 1128 
 1129     if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) {
 1130         if (xoff || yoff)
 1131             RegionTranslate(pRegion, xoff, yoff);
 1132 
 1133         for (i = 0; i < nbox; i++) {
 1134             int height = pBox[i].y2 - pBox[i].y1;
 1135             int dstY = pBox[i].y1;
 1136             int tileY;
 1137 
 1138             if (alu == GXcopy)
 1139                 height = min(height, tileHeight);
 1140 
 1141             modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
 1142 
 1143             while (height > 0) {
 1144                 int width = pBox[i].x2 - pBox[i].x1;
 1145                 int dstX = pBox[i].x1;
 1146                 int tileX;
 1147                 int h = tileHeight - tileY;
 1148 
 1149                 if (alu == GXcopy)
 1150                     width = min(width, tileWidth);
 1151 
 1152                 if (h > height)
 1153                     h = height;
 1154                 height -= h;
 1155 
 1156                 modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
 1157                         tileX);
 1158 
 1159                 while (width > 0) {
 1160                     int w = tileWidth - tileX;
 1161 
 1162                     if (w > width)
 1163                         w = width;
 1164                     width -= w;
 1165 
 1166                     (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
 1167                                             w, h);
 1168                     dstX += w;
 1169                     tileX = 0;
 1170                 }
 1171                 dstY += h;
 1172                 tileY = 0;
 1173             }
 1174         }
 1175         (*pExaScr->info->DoneCopy) (pPixmap);
 1176 
 1177         /* With GXcopy, we only need to do the basic algorithm up to the tile
 1178          * size; then, we can just keep doubling the destination in each
 1179          * direction until it fills the box. This way, the number of copy
 1180          * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
 1181          * rx/ry is the ratio between box and tile width/height. This can make
 1182          * a big difference if each driver copy incurs a significant constant
 1183          * overhead.
 1184          */
 1185         if (alu != GXcopy)
 1186             ret = TRUE;
 1187         else {
 1188             Bool more_copy = FALSE;
 1189 
 1190             for (i = 0; i < nbox; i++) {
 1191                 int dstX = pBox[i].x1 + tileWidth;
 1192                 int dstY = pBox[i].y1 + tileHeight;
 1193 
 1194                 if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
 1195                     more_copy = TRUE;
 1196                     break;
 1197                 }
 1198             }
 1199 
 1200             if (more_copy == FALSE)
 1201                 ret = TRUE;
 1202 
 1203             if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
 1204                                                             1, 1, alu,
 1205                                                             planemask)) {
 1206                 for (i = 0; i < nbox; i++) {
 1207                     int dstX = pBox[i].x1 + tileWidth;
 1208                     int dstY = pBox[i].y1 + tileHeight;
 1209                     int width = min(pBox[i].x2 - dstX, tileWidth);
 1210                     int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
 1211 
 1212                     while (dstX < pBox[i].x2) {
 1213                         (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
 1214                                                 dstX, pBox[i].y1, width,
 1215                                                 height);
 1216                         dstX += width;
 1217                         width = min(pBox[i].x2 - dstX, width * 2);
 1218                     }
 1219 
 1220                     width = pBox[i].x2 - pBox[i].x1;
 1221                     height = min(pBox[i].y2 - dstY, tileHeight);
 1222 
 1223                     while (dstY < pBox[i].y2) {
 1224                         (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
 1225                                                 pBox[i].x1, dstY, width,
 1226                                                 height);
 1227                         dstY += height;
 1228                         height = min(pBox[i].y2 - dstY, height * 2);
 1229                     }
 1230                 }
 1231 
 1232                 (*pExaScr->info->DoneCopy) (pPixmap);
 1233 
 1234                 ret = TRUE;
 1235             }
 1236         }
 1237 
 1238         exaMarkSync(pDrawable->pScreen);
 1239 
 1240         if (xoff || yoff)
 1241             RegionTranslate(pRegion, -xoff, -yoff);
 1242     }
 1243 
 1244     return ret;
 1245 }
 1246 
 1247 /**
 1248  * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
 1249  *
 1250  * This is probably the only case we actually care about.  The rest fall through
 1251  * to migration and fbGetImage, which hopefully will result in migration pushing
 1252  * the pixmap out of framebuffer.
 1253  */
 1254 void
 1255 exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
 1256             unsigned int format, unsigned long planeMask, char *d)
 1257 {
 1258     ExaScreenPriv(pDrawable->pScreen);
 1259     PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
 1260 
 1261     ExaPixmapPriv(pPix);
 1262     int xoff, yoff;
 1263     Bool ok;
 1264 
 1265     if (pExaScr->fallback_counter || pExaScr->swappedOut)
 1266         goto fallback;
 1267 
 1268     /* If there's a system copy, we want to save the result there */
 1269     if (pExaPixmap->pDamage)
 1270         goto fallback;
 1271 
 1272     pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
 1273 
 1274     if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
 1275         goto fallback;
 1276 
 1277     /* Only cover the ZPixmap, solid copy case. */
 1278     if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
 1279         goto fallback;
 1280 
 1281     /* Only try to handle the 8bpp and up cases, since we don't want to think
 1282      * about <8bpp.
 1283      */
 1284     if (pDrawable->bitsPerPixel < 8)
 1285         goto fallback;
 1286 
 1287     ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
 1288                                            pDrawable->y + y + yoff, w, h, d,
 1289                                            PixmapBytePad(w, pDrawable->depth));
 1290     if (ok) {
 1291         exaWaitSync(pDrawable->pScreen);
 1292         return;
 1293     }
 1294 
 1295  fallback:
 1296     ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
 1297 }