exa_accel.c revision 5a112b11
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 38static void 39exaFillSpans(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 137static Bool 138exaDoPutImage(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 229static void 230exaPutImage(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 239static Bool inline 240exaCopyNtoNTwoDir(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 363Bool 364exaHWCopyNtoN(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 565void 566exaCopyNtoN(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 597RegionPtr 598exaCopyArea(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 613static void 614exaPolyPoint(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 */ 649static void 650exaPolylines(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 */ 719static void 720exaPolySegment(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 772static Bool exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion, 773 Pixel pixel, CARD32 planemask, CARD32 alu, 774 Bool hasClientClip); 775 776static void 777exaPolyFillRect(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 927const 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 950void 951exaCopyWindow(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 991static Bool 992exaFillRegionSolid(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 */ 1073Bool 1074exaFillRegionTiled(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 */ 1254void 1255exaGetImage(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} 1298