xserver

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

exa_migration_classic.c (24398B)


      1 /*
      2  * Copyright © 2006 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  *
     23  * Authors:
     24  *    Eric Anholt <eric@anholt.net>
     25  *    Michel Dänzer <michel@tungstengraphics.com>
     26  *
     27  */
     28 
     29 #ifdef HAVE_DIX_CONFIG_H
     30 #include <dix-config.h>
     31 #endif
     32 
     33 #include <string.h>
     34 
     35 #include "exa_priv.h"
     36 #include "exa.h"
     37 
     38 #if DEBUG_MIGRATE
     39 #define DBG_MIGRATE(a) ErrorF a
     40 #else
     41 #define DBG_MIGRATE(a)
     42 #endif
     43 
     44 /**
     45  * The fallback path for UTS/DFS failing is to just memcpy.  exaCopyDirtyToSys
     46  * and exaCopyDirtyToFb both needed to do this loop.
     47  */
     48 static void
     49 exaMemcpyBox(PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
     50              CARD8 *dst, int dst_pitch)
     51 {
     52     int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
     53     int bytes = (pbox->x2 - pbox->x1) * cpp;
     54 
     55     src += pbox->y1 * src_pitch + pbox->x1 * cpp;
     56     dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
     57 
     58     for (i = pbox->y2 - pbox->y1; i; i--) {
     59         memcpy(dst, src, bytes);
     60         src += src_pitch;
     61         dst += dst_pitch;
     62     }
     63 }
     64 
     65 /**
     66  * Returns TRUE if the pixmap is dirty (has been modified in its current
     67  * location compared to the other), or lacks a private for tracking
     68  * dirtiness.
     69  */
     70 static Bool
     71 exaPixmapIsDirty(PixmapPtr pPix)
     72 {
     73     ExaPixmapPriv(pPix);
     74 
     75     if (pExaPixmap == NULL)
     76         EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
     77 
     78     if (!pExaPixmap->pDamage)
     79         return FALSE;
     80 
     81     return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) ||
     82         !RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB);
     83 }
     84 
     85 /**
     86  * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
     87  * to be considered "should be in framebuffer".  That's just anything that has
     88  * had more acceleration than fallbacks, or has no score yet.
     89  *
     90  * Only valid if using a migration scheme that tracks score.
     91  */
     92 static Bool
     93 exaPixmapShouldBeInFB(PixmapPtr pPix)
     94 {
     95     ExaPixmapPriv(pPix);
     96 
     97     if (exaPixmapIsPinned(pPix))
     98         return TRUE;
     99 
    100     return pExaPixmap->score >= 0;
    101 }
    102 
    103 /**
    104  * If the pixmap is currently dirty, this copies at least the dirty area from
    105  * FB to system or vice versa.  Both areas must be allocated.
    106  */
    107 static void
    108 exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
    109              Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
    110                                char *sys, int sys_pitch), int fallback_index,
    111              void (*sync) (ScreenPtr pScreen))
    112 {
    113     PixmapPtr pPixmap = migrate->pPix;
    114 
    115     ExaPixmapPriv(pPixmap);
    116     RegionPtr damage = DamageRegion(pExaPixmap->pDamage);
    117     RegionRec CopyReg;
    118     Bool save_use_gpu_copy;
    119     int save_pitch;
    120     BoxPtr pBox;
    121     int nbox;
    122     Bool access_prepared = FALSE;
    123     Bool need_sync = FALSE;
    124 
    125     /* Damaged bits are valid in current copy but invalid in other one */
    126     if (pExaPixmap->use_gpu_copy) {
    127         RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
    128         RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
    129     }
    130     else {
    131         RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
    132         RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
    133     }
    134 
    135     RegionEmpty(damage);
    136 
    137     /* Copy bits valid in source but not in destination */
    138     RegionNull(&CopyReg);
    139     RegionSubtract(&CopyReg, pValidSrc, pValidDst);
    140 
    141     if (migrate->as_dst) {
    142         ExaScreenPriv(pPixmap->drawable.pScreen);
    143 
    144         /* XXX: The pending damage region will be marked as damaged after the
    145          * operation, so it should serve as an upper bound for the region that
    146          * needs to be synchronized for the operation. Unfortunately, this
    147          * causes corruption in some cases, e.g. when starting compiz. See
    148          * https://bugs.freedesktop.org/show_bug.cgi?id=12916 .
    149          */
    150         if (pExaScr->optimize_migration) {
    151             RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
    152 
    153 #if DEBUG_MIGRATE
    154             if (RegionNil(pending_damage)) {
    155                 static Bool firsttime = TRUE;
    156 
    157                 if (firsttime) {
    158                     ErrorF("%s: Pending damage region empty!\n", __func__);
    159                     firsttime = FALSE;
    160                 }
    161             }
    162 #endif
    163 
    164             /* Try to prevent destination valid region from growing too many
    165              * rects by filling it up to the extents of the union of the
    166              * destination valid region and the pending damage region.
    167              */
    168             if (RegionNumRects(pValidDst) > 10) {
    169                 BoxRec box;
    170                 BoxPtr pValidExt, pDamageExt;
    171                 RegionRec closure;
    172 
    173                 pValidExt = RegionExtents(pValidDst);
    174                 pDamageExt = RegionExtents(pending_damage);
    175 
    176                 box.x1 = min(pValidExt->x1, pDamageExt->x1);
    177                 box.y1 = min(pValidExt->y1, pDamageExt->y1);
    178                 box.x2 = max(pValidExt->x2, pDamageExt->x2);
    179                 box.y2 = max(pValidExt->y2, pDamageExt->y2);
    180 
    181                 RegionInit(&closure, &box, 0);
    182                 RegionIntersect(&CopyReg, &CopyReg, &closure);
    183             }
    184             else
    185                 RegionIntersect(&CopyReg, &CopyReg, pending_damage);
    186         }
    187 
    188         /* The caller may provide a region to be subtracted from the calculated
    189          * dirty region. This is to avoid migration of bits that don't
    190          * contribute to the result of the operation.
    191          */
    192         if (migrate->pReg)
    193             RegionSubtract(&CopyReg, &CopyReg, migrate->pReg);
    194     }
    195     else {
    196         /* The caller may restrict the region to be migrated for source pixmaps
    197          * to what's relevant for the operation.
    198          */
    199         if (migrate->pReg)
    200             RegionIntersect(&CopyReg, &CopyReg, migrate->pReg);
    201     }
    202 
    203     pBox = RegionRects(&CopyReg);
    204     nbox = RegionNumRects(&CopyReg);
    205 
    206     save_use_gpu_copy = pExaPixmap->use_gpu_copy;
    207     save_pitch = pPixmap->devKind;
    208     pExaPixmap->use_gpu_copy = TRUE;
    209     pPixmap->devKind = pExaPixmap->fb_pitch;
    210 
    211     while (nbox--) {
    212         pBox->x1 = max(pBox->x1, 0);
    213         pBox->y1 = max(pBox->y1, 0);
    214         pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
    215         pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
    216 
    217         if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
    218             continue;
    219 
    220         if (!transfer || !transfer(pPixmap,
    221                                    pBox->x1, pBox->y1,
    222                                    pBox->x2 - pBox->x1,
    223                                    pBox->y2 - pBox->y1,
    224                                    (char *) (pExaPixmap->sys_ptr
    225                                              + pBox->y1 * pExaPixmap->sys_pitch
    226                                              +
    227                                              pBox->x1 *
    228                                              pPixmap->drawable.bitsPerPixel /
    229                                              8), pExaPixmap->sys_pitch)) {
    230             if (!access_prepared) {
    231                 ExaDoPrepareAccess(pPixmap, fallback_index);
    232                 access_prepared = TRUE;
    233             }
    234             if (fallback_index == EXA_PREPARE_DEST) {
    235                 exaMemcpyBox(pPixmap, pBox,
    236                              pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
    237                              pPixmap->devPrivate.ptr, pPixmap->devKind);
    238             }
    239             else {
    240                 exaMemcpyBox(pPixmap, pBox,
    241                              pPixmap->devPrivate.ptr, pPixmap->devKind,
    242                              pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
    243             }
    244         }
    245         else
    246             need_sync = TRUE;
    247 
    248         pBox++;
    249     }
    250 
    251     pExaPixmap->use_gpu_copy = save_use_gpu_copy;
    252     pPixmap->devKind = save_pitch;
    253 
    254     /* Try to prevent source valid region from growing too many rects by
    255      * removing parts of it which are also in the destination valid region.
    256      * Removing anything beyond that would lead to data loss.
    257      */
    258     if (RegionNumRects(pValidSrc) > 20)
    259         RegionSubtract(pValidSrc, pValidSrc, pValidDst);
    260 
    261     /* The copied bits are now valid in destination */
    262     RegionUnion(pValidDst, pValidDst, &CopyReg);
    263 
    264     RegionUninit(&CopyReg);
    265 
    266     if (access_prepared)
    267         exaFinishAccess(&pPixmap->drawable, fallback_index);
    268     else if (need_sync && sync)
    269         sync(pPixmap->drawable.pScreen);
    270 }
    271 
    272 /**
    273  * If the pixmap is currently dirty, this copies at least the dirty area from
    274  * the framebuffer  memory copy to the system memory copy.  Both areas must be
    275  * allocated.
    276  */
    277 void
    278 exaCopyDirtyToSys(ExaMigrationPtr migrate)
    279 {
    280     PixmapPtr pPixmap = migrate->pPix;
    281 
    282     ExaScreenPriv(pPixmap->drawable.pScreen);
    283     ExaPixmapPriv(pPixmap);
    284 
    285     exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
    286                  pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC,
    287                  exaWaitSync);
    288 }
    289 
    290 /**
    291  * If the pixmap is currently dirty, this copies at least the dirty area from
    292  * the system memory copy to the framebuffer memory copy.  Both areas must be
    293  * allocated.
    294  */
    295 void
    296 exaCopyDirtyToFb(ExaMigrationPtr migrate)
    297 {
    298     PixmapPtr pPixmap = migrate->pPix;
    299 
    300     ExaScreenPriv(pPixmap->drawable.pScreen);
    301     ExaPixmapPriv(pPixmap);
    302 
    303     exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
    304                  pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL);
    305 }
    306 
    307 /**
    308  * Allocates a framebuffer copy of the pixmap if necessary, and then copies
    309  * any necessary pixmap data into the framebuffer copy and points the pixmap at
    310  * it.
    311  *
    312  * Note that when first allocated, a pixmap will have FALSE dirty flag.
    313  * This is intentional because pixmap data starts out undefined.  So if we move
    314  * it in due to the first operation against it being accelerated, it will have
    315  * undefined framebuffer contents that we didn't have to upload.  If we do
    316  * moveouts (and moveins) after the first movein, then we will only have to copy
    317  * back and forth if the pixmap was written to after the last synchronization of
    318  * the two copies.  Then, at exaPixmapSave (when the framebuffer copy goes away)
    319  * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
    320  * all the data, since it's almost surely all valid now.
    321  */
    322 static void
    323 exaDoMoveInPixmap(ExaMigrationPtr migrate)
    324 {
    325     PixmapPtr pPixmap = migrate->pPix;
    326     ScreenPtr pScreen = pPixmap->drawable.pScreen;
    327 
    328     ExaScreenPriv(pScreen);
    329     ExaPixmapPriv(pPixmap);
    330 
    331     /* If we're VT-switched away, no touching card memory allowed. */
    332     if (pExaScr->swappedOut)
    333         return;
    334 
    335     /* If we're not allowed to move, then fail. */
    336     if (exaPixmapIsPinned(pPixmap))
    337         return;
    338 
    339     /* Don't migrate in pixmaps which are less than 8bpp.  This avoids a lot of
    340      * fragility in EXA, and <8bpp is probably not used enough any more to care
    341      * (at least, not in acceleratd paths).
    342      */
    343     if (pPixmap->drawable.bitsPerPixel < 8)
    344         return;
    345 
    346     if (pExaPixmap->accel_blocked)
    347         return;
    348 
    349     if (pExaPixmap->area == NULL) {
    350         pExaPixmap->area =
    351             exaOffscreenAlloc(pScreen, pExaPixmap->fb_size,
    352                               pExaScr->info->pixmapOffsetAlign, FALSE,
    353                               exaPixmapSave, (void *) pPixmap);
    354         if (pExaPixmap->area == NULL)
    355             return;
    356 
    357         pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
    358             pExaPixmap->area->offset;
    359     }
    360 
    361     exaCopyDirtyToFb(migrate);
    362 
    363     if (exaPixmapHasGpuCopy(pPixmap))
    364         return;
    365 
    366     DBG_MIGRATE(("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
    367                  (ExaGetPixmapPriv(pPixmap)->area ?
    368                   ExaGetPixmapPriv(pPixmap)->area->offset : 0),
    369                  pPixmap->drawable.width,
    370                  pPixmap->drawable.height,
    371                  exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
    372 
    373     pExaPixmap->use_gpu_copy = TRUE;
    374 
    375     pPixmap->devKind = pExaPixmap->fb_pitch;
    376     pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
    377 }
    378 
    379 void
    380 exaMoveInPixmap_classic(PixmapPtr pPixmap)
    381 {
    382     static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
    383         .pReg = NULL
    384     };
    385 
    386     migrate.pPix = pPixmap;
    387     exaDoMoveInPixmap(&migrate);
    388 }
    389 
    390 /**
    391  * Switches the current active location of the pixmap to system memory, copying
    392  * updated data out if necessary.
    393  */
    394 static void
    395 exaDoMoveOutPixmap(ExaMigrationPtr migrate)
    396 {
    397     PixmapPtr pPixmap = migrate->pPix;
    398 
    399     ExaPixmapPriv(pPixmap);
    400 
    401     if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
    402         return;
    403 
    404     exaCopyDirtyToSys(migrate);
    405 
    406     if (exaPixmapHasGpuCopy(pPixmap)) {
    407 
    408         DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
    409                      (void *) (ExaGetPixmapPriv(pPixmap)->area ?
    410                                ExaGetPixmapPriv(pPixmap)->area->offset : 0),
    411                      pPixmap->drawable.width,
    412                      pPixmap->drawable.height,
    413                      exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
    414 
    415         pExaPixmap->use_gpu_copy = FALSE;
    416 
    417         pPixmap->devKind = pExaPixmap->sys_pitch;
    418         pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
    419     }
    420 }
    421 
    422 void
    423 exaMoveOutPixmap_classic(PixmapPtr pPixmap)
    424 {
    425     static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
    426         .pReg = NULL
    427     };
    428 
    429     migrate.pPix = pPixmap;
    430     exaDoMoveOutPixmap(&migrate);
    431 }
    432 
    433 /**
    434  * Copies out important pixmap data and removes references to framebuffer area.
    435  * Called when the memory manager decides it's time to kick the pixmap out of
    436  * framebuffer entirely.
    437  */
    438 void
    439 exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area)
    440 {
    441     PixmapPtr pPixmap = area->privData;
    442 
    443     ExaPixmapPriv(pPixmap);
    444 
    445     exaMoveOutPixmap(pPixmap);
    446 
    447     pExaPixmap->fb_ptr = NULL;
    448     pExaPixmap->area = NULL;
    449 
    450     /* Mark all FB bits as invalid, so all valid system bits get copied to FB
    451      * next time */
    452     RegionEmpty(&pExaPixmap->validFB);
    453 }
    454 
    455 /**
    456  * For the "greedy" migration scheme, pushes the pixmap toward being located in
    457  * framebuffer memory.
    458  */
    459 static void
    460 exaMigrateTowardFb(ExaMigrationPtr migrate)
    461 {
    462     PixmapPtr pPixmap = migrate->pPix;
    463 
    464     ExaPixmapPriv(pPixmap);
    465 
    466     if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
    467         DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
    468                      (void *) pPixmap));
    469         return;
    470     }
    471 
    472     DBG_MIGRATE(("UseScreen %p score %d\n",
    473                  (void *) pPixmap, pExaPixmap->score));
    474 
    475     if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
    476         exaDoMoveInPixmap(migrate);
    477         pExaPixmap->score = 0;
    478     }
    479 
    480     if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
    481         pExaPixmap->score++;
    482 
    483     if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
    484         !exaPixmapHasGpuCopy(pPixmap)) {
    485         exaDoMoveInPixmap(migrate);
    486     }
    487 
    488     if (exaPixmapHasGpuCopy(pPixmap)) {
    489         exaCopyDirtyToFb(migrate);
    490         ExaOffscreenMarkUsed(pPixmap);
    491     }
    492     else
    493         exaCopyDirtyToSys(migrate);
    494 }
    495 
    496 /**
    497  * For the "greedy" migration scheme, pushes the pixmap toward being located in
    498  * system memory.
    499  */
    500 static void
    501 exaMigrateTowardSys(ExaMigrationPtr migrate)
    502 {
    503     PixmapPtr pPixmap = migrate->pPix;
    504 
    505     ExaPixmapPriv(pPixmap);
    506 
    507     DBG_MIGRATE(("UseMem: %p score %d\n", (void *) pPixmap,
    508                  pExaPixmap->score));
    509 
    510     if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
    511         return;
    512 
    513     if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
    514         pExaPixmap->score = 0;
    515 
    516     if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
    517         pExaPixmap->score--;
    518 
    519     if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
    520         exaDoMoveOutPixmap(migrate);
    521 
    522     if (exaPixmapHasGpuCopy(pPixmap)) {
    523         exaCopyDirtyToFb(migrate);
    524         ExaOffscreenMarkUsed(pPixmap);
    525     }
    526     else
    527         exaCopyDirtyToSys(migrate);
    528 }
    529 
    530 /**
    531  * If the pixmap has both a framebuffer and system memory copy, this function
    532  * asserts that both of them are the same.
    533  */
    534 static Bool
    535 exaAssertNotDirty(PixmapPtr pPixmap)
    536 {
    537     ExaPixmapPriv(pPixmap);
    538     CARD8 *dst, *src;
    539     RegionRec ValidReg;
    540     int dst_pitch, src_pitch, cpp, y, nbox, save_pitch;
    541     BoxPtr pBox;
    542     Bool ret = TRUE, save_use_gpu_copy;
    543 
    544     if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
    545         return ret;
    546 
    547     RegionNull(&ValidReg);
    548     RegionIntersect(&ValidReg, &pExaPixmap->validFB, &pExaPixmap->validSys);
    549     nbox = RegionNumRects(&ValidReg);
    550 
    551     if (!nbox)
    552         goto out;
    553 
    554     pBox = RegionRects(&ValidReg);
    555 
    556     dst_pitch = pExaPixmap->sys_pitch;
    557     src_pitch = pExaPixmap->fb_pitch;
    558     cpp = pPixmap->drawable.bitsPerPixel / 8;
    559 
    560     save_use_gpu_copy = pExaPixmap->use_gpu_copy;
    561     save_pitch = pPixmap->devKind;
    562     pExaPixmap->use_gpu_copy = TRUE;
    563     pPixmap->devKind = pExaPixmap->fb_pitch;
    564 
    565     if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
    566         goto skip;
    567 
    568     while (nbox--) {
    569         int rowbytes;
    570 
    571         pBox->x1 = max(pBox->x1, 0);
    572         pBox->y1 = max(pBox->y1, 0);
    573         pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
    574         pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
    575 
    576         if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
    577             continue;
    578 
    579         rowbytes = (pBox->x2 - pBox->x1) * cpp;
    580         src =
    581             (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch +
    582             pBox->x1 * cpp;
    583         dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
    584 
    585         for (y = pBox->y1; y < pBox->y2;
    586              y++, src += src_pitch, dst += dst_pitch) {
    587             if (memcmp(dst, src, rowbytes) != 0) {
    588                 ret = FALSE;
    589                 exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
    590                 break;
    591             }
    592         }
    593     }
    594 
    595  skip:
    596     exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
    597 
    598     pExaPixmap->use_gpu_copy = save_use_gpu_copy;
    599     pPixmap->devKind = save_pitch;
    600 
    601  out:
    602     RegionUninit(&ValidReg);
    603     return ret;
    604 }
    605 
    606 /**
    607  * Performs migration of the pixmaps according to the operation information
    608  * provided in pixmaps and can_accel and the migration scheme chosen in the
    609  * config file.
    610  */
    611 void
    612 exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
    613 {
    614     ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
    615 
    616     ExaScreenPriv(pScreen);
    617     int i, j;
    618 
    619     /* If this debugging flag is set, check each pixmap for whether it is marked
    620      * as clean, and if so, actually check if that's the case.  This should help
    621      * catch issues with failing to mark a drawable as dirty.  While it will
    622      * catch them late (after the operation happened), it at least explains what
    623      * went wrong, and instrumenting the code to find what operation happened
    624      * to the pixmap last shouldn't be hard.
    625      */
    626     if (pExaScr->checkDirtyCorrectness) {
    627         for (i = 0; i < npixmaps; i++) {
    628             if (!exaPixmapIsDirty(pixmaps[i].pPix) &&
    629                 !exaAssertNotDirty(pixmaps[i].pPix))
    630                 ErrorF("%s: Pixmap %d dirty but not marked as such!\n",
    631                        __func__, i);
    632         }
    633     }
    634     /* If anything is pinned in system memory, we won't be able to
    635      * accelerate.
    636      */
    637     for (i = 0; i < npixmaps; i++) {
    638         if (exaPixmapIsPinned(pixmaps[i].pPix) &&
    639             !exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
    640             EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
    641                           pixmaps[i].pPix->drawable.width,
    642                           pixmaps[i].pPix->drawable.height));
    643             can_accel = FALSE;
    644             break;
    645         }
    646     }
    647 
    648     if (pExaScr->migration == ExaMigrationSmart) {
    649         /* If we've got something as a destination that we shouldn't cause to
    650          * become newly dirtied, take the unaccelerated route.
    651          */
    652         for (i = 0; i < npixmaps; i++) {
    653             if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB(pixmaps[i].pPix) &&
    654                 !exaPixmapIsDirty(pixmaps[i].pPix)) {
    655                 for (i = 0; i < npixmaps; i++) {
    656                     if (!exaPixmapIsDirty(pixmaps[i].pPix))
    657                         exaDoMoveOutPixmap(pixmaps + i);
    658                 }
    659                 return;
    660             }
    661         }
    662 
    663         /* If we aren't going to accelerate, then we migrate everybody toward
    664          * system memory, and kick out if it's free.
    665          */
    666         if (!can_accel) {
    667             for (i = 0; i < npixmaps; i++) {
    668                 exaMigrateTowardSys(pixmaps + i);
    669                 if (!exaPixmapIsDirty(pixmaps[i].pPix))
    670                     exaDoMoveOutPixmap(pixmaps + i);
    671             }
    672             return;
    673         }
    674 
    675         /* Finally, the acceleration path.  Move them all in. */
    676         for (i = 0; i < npixmaps; i++) {
    677             exaMigrateTowardFb(pixmaps + i);
    678             exaDoMoveInPixmap(pixmaps + i);
    679         }
    680     }
    681     else if (pExaScr->migration == ExaMigrationGreedy) {
    682         /* If we can't accelerate, either because the driver can't or because one of
    683          * the pixmaps is pinned in system memory, then we migrate everybody toward
    684          * system memory.
    685          *
    686          * We also migrate toward system if all pixmaps involved are currently in
    687          * system memory -- this can mitigate thrashing when there are significantly
    688          * more pixmaps active than would fit in memory.
    689          *
    690          * If not, then we migrate toward FB so that hopefully acceleration can
    691          * happen.
    692          */
    693         if (!can_accel) {
    694             for (i = 0; i < npixmaps; i++)
    695                 exaMigrateTowardSys(pixmaps + i);
    696             return;
    697         }
    698 
    699         for (i = 0; i < npixmaps; i++) {
    700             if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
    701                 /* Found one in FB, so move all to FB. */
    702                 for (j = 0; j < npixmaps; j++)
    703                     exaMigrateTowardFb(pixmaps + i);
    704                 return;
    705             }
    706         }
    707 
    708         /* Nobody's in FB, so move all away from FB. */
    709         for (i = 0; i < npixmaps; i++)
    710             exaMigrateTowardSys(pixmaps + i);
    711     }
    712     else if (pExaScr->migration == ExaMigrationAlways) {
    713         /* Always move the pixmaps out if we can't accelerate.  If we can
    714          * accelerate, try to move them all in.  If that fails, then move them
    715          * back out.
    716          */
    717         if (!can_accel) {
    718             for (i = 0; i < npixmaps; i++)
    719                 exaDoMoveOutPixmap(pixmaps + i);
    720             return;
    721         }
    722 
    723         /* Now, try to move them all into FB */
    724         for (i = 0; i < npixmaps; i++) {
    725             exaDoMoveInPixmap(pixmaps + i);
    726         }
    727 
    728         /* If we couldn't fit everything in, abort */
    729         for (i = 0; i < npixmaps; i++) {
    730             if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
    731                 return;
    732             }
    733         }
    734 
    735         /* Yay, everything has a gpu copy, mark memory as used */
    736         for (i = 0; i < npixmaps; i++) {
    737             ExaOffscreenMarkUsed(pixmaps[i].pPix);
    738         }
    739     }
    740 }
    741 
    742 void
    743 exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg)
    744 {
    745     ExaMigrationRec pixmaps[1];
    746 
    747     if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
    748         pixmaps[0].as_dst = TRUE;
    749         pixmaps[0].as_src = FALSE;
    750     }
    751     else {
    752         pixmaps[0].as_dst = FALSE;
    753         pixmaps[0].as_src = TRUE;
    754     }
    755     pixmaps[0].pPix = pPixmap;
    756     pixmaps[0].pReg = pReg;
    757 
    758     exaDoMigration(pixmaps, 1, FALSE);
    759 
    760     (void) ExaDoPrepareAccess(pPixmap, index);
    761 }