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 */ 48static void 49exaMemcpyBox(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 */ 70static Bool 71exaPixmapIsDirty(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 */ 92static Bool 93exaPixmapShouldBeInFB(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 */ 107static void 108exaCopyDirty(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 */ 277void 278exaCopyDirtyToSys(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 */ 295void 296exaCopyDirtyToFb(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 */ 322static void 323exaDoMoveInPixmap(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 379void 380exaMoveInPixmap_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 */ 394static void 395exaDoMoveOutPixmap(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 422void 423exaMoveOutPixmap_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 */ 438void 439exaPixmapSave(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 */ 459static void 460exaMigrateTowardFb(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 */ 500static void 501exaMigrateTowardSys(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 */ 534static Bool 535exaAssertNotDirty(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 */ 611void 612exaDoMigration_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 742void 743exaPrepareAccessReg_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} 762