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