xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

exa_accel.c (42721B)


      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((unsigned int)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 }