exa_accel.c revision 05b261ec
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#include "cw.h" 38 39static void 40exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, 41 DDXPointPtr ppt, int *pwidth, int fSorted) 42{ 43 ScreenPtr pScreen = pDrawable->pScreen; 44 ExaScreenPriv (pScreen); 45 RegionPtr pClip = fbGetCompositeClip(pGC); 46 PixmapPtr 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 ExaMigrationRec pixmaps[1]; 54 55 pixmaps[0].as_dst = TRUE; 56 pixmaps[0].as_src = FALSE; 57 pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); 58 59 if (pExaScr->swappedOut || 60 pGC->fillStyle != FillSolid || 61 pPixmap->drawable.width > pExaScr->info->maxX || 62 pPixmap->drawable.height > pExaScr->info->maxY) 63 { 64 exaDoMigration (pixmaps, 1, FALSE); 65 ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); 66 return; 67 } else { 68 exaDoMigration (pixmaps, 1, TRUE); 69 } 70 71 if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) || 72 !(*pExaScr->info->PrepareSolid) (pPixmap, 73 pGC->alu, 74 pGC->planemask, 75 pGC->fgPixel)) 76 { 77 exaDoMigration (pixmaps, 1, FALSE); 78 ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); 79 return; 80 } 81 82 pextent = REGION_EXTENTS(pGC->pScreen, pClip); 83 extentX1 = pextent->x1; 84 extentY1 = pextent->y1; 85 extentX2 = pextent->x2; 86 extentY2 = pextent->y2; 87 while (n--) 88 { 89 fullX1 = ppt->x; 90 fullY1 = ppt->y; 91 fullX2 = fullX1 + (int) *pwidth; 92 ppt++; 93 pwidth++; 94 95 if (fullY1 < extentY1 || extentY2 <= fullY1) 96 continue; 97 98 if (fullX1 < extentX1) 99 fullX1 = extentX1; 100 101 if (fullX2 > extentX2) 102 fullX2 = extentX2; 103 104 if (fullX1 >= fullX2) 105 continue; 106 107 nbox = REGION_NUM_RECTS (pClip); 108 if (nbox == 1) 109 { 110 (*pExaScr->info->Solid) (pPixmap, 111 fullX1 + off_x, fullY1 + off_y, 112 fullX2 + off_x, fullY1 + 1 + off_y); 113 } 114 else 115 { 116 pbox = REGION_RECTS(pClip); 117 while(nbox--) 118 { 119 if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) 120 { 121 partX1 = pbox->x1; 122 if (partX1 < fullX1) 123 partX1 = fullX1; 124 partX2 = pbox->x2; 125 if (partX2 > fullX2) 126 partX2 = fullX2; 127 if (partX2 > partX1) { 128 (*pExaScr->info->Solid) (pPixmap, 129 partX1 + off_x, fullY1 + off_y, 130 partX2 + off_x, fullY1 + 1 + off_y); 131 } 132 } 133 pbox++; 134 } 135 } 136 } 137 (*pExaScr->info->DoneSolid) (pPixmap); 138 exaMarkSync(pScreen); 139} 140 141static void 142exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 143 int w, int h, int leftPad, int format, char *bits) 144{ 145 ExaScreenPriv (pDrawable->pScreen); 146 PixmapPtr pPix; 147 ExaMigrationRec pixmaps[1]; 148 RegionPtr pClip; 149 BoxPtr pbox; 150 int nbox; 151 int xoff, yoff; 152 int src_stride, bpp = pDrawable->bitsPerPixel; 153 154 pixmaps[0].as_dst = TRUE; 155 pixmaps[0].as_src = FALSE; 156 pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); 157 158 /* Don't bother with under 8bpp, XYPixmaps. */ 159 if (format != ZPixmap || bpp < 8) 160 goto migrate_and_fallback; 161 162 /* Only accelerate copies: no rop or planemask. */ 163 if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) 164 goto migrate_and_fallback; 165 166 if (pExaScr->swappedOut) 167 goto fallback; 168 169 exaDoMigration (pixmaps, 1, TRUE); 170 171 if (pExaScr->info->UploadToScreen == NULL) 172 goto fallback; 173 174 pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 175 176 if (pPix == NULL) 177 goto fallback; 178 179 x += pDrawable->x; 180 y += pDrawable->y; 181 182 pClip = fbGetCompositeClip(pGC); 183 src_stride = PixmapBytePad(w, pDrawable->depth); 184 for (nbox = REGION_NUM_RECTS(pClip), 185 pbox = REGION_RECTS(pClip); 186 nbox--; 187 pbox++) 188 { 189 int x1 = x; 190 int y1 = y; 191 int x2 = x + w; 192 int y2 = y + h; 193 char *src; 194 Bool ok; 195 196 if (x1 < pbox->x1) 197 x1 = pbox->x1; 198 if (y1 < pbox->y1) 199 y1 = pbox->y1; 200 if (x2 > pbox->x2) 201 x2 = pbox->x2; 202 if (y2 > pbox->y2) 203 y2 = pbox->y2; 204 if (x1 >= x2 || y1 >= y2) 205 continue; 206 207 src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); 208 ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, 209 x2 - x1, y2 - y1, src, src_stride); 210 /* If we fail to accelerate the upload, fall back to using unaccelerated 211 * fb calls. 212 */ 213 if (!ok) { 214 FbStip *dst; 215 FbStride dst_stride; 216 int dstBpp; 217 int dstXoff, dstYoff; 218 219 exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); 220 221 fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp, 222 dstXoff, dstYoff); 223 224 fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)), 225 src_stride / sizeof(FbStip), 226 (x1 - x) * dstBpp, 227 dst + (y1 + dstYoff) * dst_stride, 228 dst_stride, 229 (x1 + dstXoff) * dstBpp, 230 (x2 - x1) * dstBpp, 231 y2 - y1, 232 GXcopy, FB_ALLONES, dstBpp); 233 234 exaFinishAccess(pDrawable, EXA_PREPARE_DEST); 235 } 236 237 exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff); 238 } 239 240 return; 241 242migrate_and_fallback: 243 exaDoMigration (pixmaps, 1, FALSE); 244 245fallback: 246 ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); 247} 248 249static Bool inline 250exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, 251 GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) 252{ 253 ExaScreenPriv (pDstDrawable->pScreen); 254 PixmapPtr pSrcPixmap, pDstPixmap; 255 int src_off_x, src_off_y, dst_off_x, dst_off_y; 256 int dirsetup; 257 258 /* Need to get both pixmaps to call the driver routines */ 259 pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y); 260 pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y); 261 if (!pSrcPixmap || !pDstPixmap) 262 return FALSE; 263 264 /* 265 * Now the case of a chip that only supports xdir = ydir = 1 or 266 * xdir = ydir = -1, but we have xdir != ydir. 267 */ 268 dirsetup = 0; /* No direction set up yet. */ 269 for (; nbox; pbox++, nbox--) { 270 if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 271 /* Do a xdir = ydir = -1 blit instead. */ 272 if (dirsetup != -1) { 273 if (dirsetup != 0) 274 pExaScr->info->DoneCopy(pDstPixmap); 275 dirsetup = -1; 276 if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 277 pDstPixmap, 278 -1, -1, 279 pGC ? pGC->alu : GXcopy, 280 pGC ? pGC->planemask : 281 FB_ALLONES)) 282 return FALSE; 283 } 284 (*pExaScr->info->Copy)(pDstPixmap, 285 src_off_x + pbox->x1 + dx, 286 src_off_y + pbox->y1 + dy, 287 dst_off_x + pbox->x1, 288 dst_off_y + pbox->y1, 289 pbox->x2 - pbox->x1, 290 pbox->y2 - pbox->y1); 291 } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 292 /* Do a xdir = ydir = 1 blit instead. */ 293 if (dirsetup != 1) { 294 if (dirsetup != 0) 295 pExaScr->info->DoneCopy(pDstPixmap); 296 dirsetup = 1; 297 if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 298 pDstPixmap, 299 1, 1, 300 pGC ? pGC->alu : GXcopy, 301 pGC ? pGC->planemask : 302 FB_ALLONES)) 303 return FALSE; 304 } 305 (*pExaScr->info->Copy)(pDstPixmap, 306 src_off_x + pbox->x1 + dx, 307 src_off_y + pbox->y1 + dy, 308 dst_off_x + pbox->x1, 309 dst_off_y + pbox->y1, 310 pbox->x2 - pbox->x1, 311 pbox->y2 - pbox->y1); 312 } else if (dx >= 0) { 313 /* 314 * xdir = 1, ydir = -1. 315 * Perform line-by-line xdir = ydir = 1 blits, going up. 316 */ 317 int i; 318 if (dirsetup != 1) { 319 if (dirsetup != 0) 320 pExaScr->info->DoneCopy(pDstPixmap); 321 dirsetup = 1; 322 if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 323 pDstPixmap, 324 1, 1, 325 pGC ? pGC->alu : GXcopy, 326 pGC ? pGC->planemask : 327 FB_ALLONES)) 328 return FALSE; 329 } 330 for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) 331 (*pExaScr->info->Copy)(pDstPixmap, 332 src_off_x + pbox->x1 + dx, 333 src_off_y + pbox->y1 + dy + i, 334 dst_off_x + pbox->x1, 335 dst_off_y + pbox->y1 + i, 336 pbox->x2 - pbox->x1, 1); 337 } else { 338 /* 339 * xdir = -1, ydir = 1. 340 * Perform line-by-line xdir = ydir = -1 blits, going down. 341 */ 342 int i; 343 if (dirsetup != -1) { 344 if (dirsetup != 0) 345 pExaScr->info->DoneCopy(pDstPixmap); 346 dirsetup = -1; 347 if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 348 pDstPixmap, 349 -1, -1, 350 pGC ? pGC->alu : GXcopy, 351 pGC ? pGC->planemask : 352 FB_ALLONES)) 353 return FALSE; 354 } 355 for (i = 0; i < pbox->y2 - pbox->y1; i++) 356 (*pExaScr->info->Copy)(pDstPixmap, 357 src_off_x + pbox->x1 + dx, 358 src_off_y + pbox->y1 + dy + i, 359 dst_off_x + pbox->x1, 360 dst_off_y + pbox->y1 + i, 361 pbox->x2 - pbox->x1, 1); 362 } 363 exaPixmapDirty(pDstPixmap, dst_off_x + pbox->x1, dst_off_y + pbox->y1, 364 dst_off_x + pbox->x2, dst_off_y + pbox->y2); 365 } 366 if (dirsetup != 0) 367 pExaScr->info->DoneCopy(pDstPixmap); 368 exaMarkSync(pDstDrawable->pScreen); 369 return TRUE; 370} 371 372void 373exaCopyNtoN (DrawablePtr pSrcDrawable, 374 DrawablePtr pDstDrawable, 375 GCPtr pGC, 376 BoxPtr pbox, 377 int nbox, 378 int dx, 379 int dy, 380 Bool reverse, 381 Bool upsidedown, 382 Pixel bitplane, 383 void *closure) 384{ 385 ExaScreenPriv (pDstDrawable->pScreen); 386 PixmapPtr pSrcPixmap, pDstPixmap; 387 int src_off_x, src_off_y; 388 int dst_off_x, dst_off_y; 389 ExaMigrationRec pixmaps[2]; 390 Bool fallback = FALSE; 391 392 pixmaps[0].as_dst = TRUE; 393 pixmaps[0].as_src = FALSE; 394 pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable); 395 pixmaps[1].as_dst = FALSE; 396 pixmaps[1].as_src = TRUE; 397 pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); 398 399 /* Respect maxX/maxY in a trivial way: don't set up drawing when we might 400 * violate the limits. The proper solution would be a temporary pixmap 401 * adjusted so that the drawing happened within limits. 402 */ 403 if (pSrcPixmap->drawable.width > pExaScr->info->maxX || 404 pSrcPixmap->drawable.height > pExaScr->info->maxY || 405 pDstPixmap->drawable.width > pExaScr->info->maxX || 406 pDstPixmap->drawable.height > pExaScr->info->maxY) 407 { 408 fallback = TRUE; 409 } else { 410 exaDoMigration (pixmaps, 2, TRUE); 411 } 412 413 /* Mixed directions must be handled specially if the card is lame */ 414 if (!fallback && (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && 415 reverse != upsidedown) { 416 if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, 417 dx, dy)) 418 return; 419 fallback = TRUE; 420 } 421 422 pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); 423 pDstPixmap = exaGetDrawablePixmap (pDstDrawable); 424 425 exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); 426 exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); 427 428 if (fallback || !exaPixmapIsOffscreen(pSrcPixmap) || 429 !exaPixmapIsOffscreen(pDstPixmap) || 430 !(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, 431 upsidedown ? -1 : 1, 432 pGC ? pGC->alu : GXcopy, 433 pGC ? pGC->planemask : FB_ALLONES)) { 434 fallback = TRUE; 435 EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, 436 exaDrawableLocation(pSrcDrawable), 437 exaDrawableLocation(pDstDrawable))); 438 exaDoMigration (pixmaps, 2, FALSE); 439 exaPrepareAccess (pDstDrawable, EXA_PREPARE_DEST); 440 exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC); 441 fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, 442 pbox, nbox, dx, dy, reverse, upsidedown, 443 bitplane, closure); 444 exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC); 445 exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST); 446 } 447 448 while (nbox--) 449 { 450 if (!fallback) 451 (*pExaScr->info->Copy) (pDstPixmap, 452 pbox->x1 + dx + src_off_x, 453 pbox->y1 + dy + src_off_y, 454 pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, 455 pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); 456 exaPixmapDirty (pDstPixmap, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, 457 pbox->x2 + dst_off_x, pbox->y2 + dst_off_y); 458 pbox++; 459 } 460 461 if (fallback) 462 return; 463 464 (*pExaScr->info->DoneCopy) (pDstPixmap); 465 exaMarkSync (pDstDrawable->pScreen); 466} 467 468RegionPtr 469exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, 470 int srcx, int srcy, int width, int height, int dstx, int dsty) 471{ 472 ExaScreenPriv (pDstDrawable->pScreen); 473 474 if (pExaScr->swappedOut) { 475 return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, 476 srcx, srcy, width, height, dstx, dsty); 477 } 478 479 return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, 480 srcx, srcy, width, height, 481 dstx, dsty, exaCopyNtoN, 0, NULL); 482} 483 484static void 485exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 486 DDXPointPtr ppt) 487{ 488 int i; 489 xRectangle *prect; 490 491 /* If we can't reuse the current GC as is, don't bother accelerating the 492 * points. 493 */ 494 if (pGC->fillStyle != FillSolid) { 495 ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); 496 return; 497 } 498 499 prect = ALLOCATE_LOCAL(sizeof(xRectangle) * npt); 500 for (i = 0; i < npt; i++) { 501 prect[i].x = ppt[i].x; 502 prect[i].y = ppt[i].y; 503 if (i > 0 && mode == CoordModePrevious) { 504 prect[i].x += prect[i - 1].x; 505 prect[i].y += prect[i - 1].y; 506 } 507 prect[i].width = 1; 508 prect[i].height = 1; 509 } 510 pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); 511 DEALLOCATE_LOCAL(prect); 512} 513 514/** 515 * exaPolylines() checks if it can accelerate the lines as a group of 516 * horizontal or vertical lines (rectangles), and uses existing rectangle fill 517 * acceleration if so. 518 */ 519static void 520exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 521 DDXPointPtr ppt) 522{ 523 xRectangle *prect; 524 int x1, x2, y1, y2; 525 int i; 526 527 /* Don't try to do wide lines or non-solid fill style. */ 528 if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 529 pGC->fillStyle != FillSolid) { 530 ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 531 return; 532 } 533 534 prect = ALLOCATE_LOCAL(sizeof(xRectangle) * (npt - 1)); 535 x1 = ppt[0].x; 536 y1 = ppt[0].y; 537 /* If we have any non-horizontal/vertical, fall back. */ 538 for (i = 0; i < npt - 1; i++) { 539 if (mode == CoordModePrevious) { 540 x2 = x1 + ppt[i + 1].x; 541 y2 = y1 + ppt[i + 1].y; 542 } else { 543 x2 = ppt[i + 1].x; 544 y2 = ppt[i + 1].y; 545 } 546 547 if (x1 != x2 && y1 != y2) { 548 DEALLOCATE_LOCAL(prect); 549 ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 550 return; 551 } 552 553 if (x1 < x2) { 554 prect[i].x = x1; 555 prect[i].width = x2 - x1 + 1; 556 } else { 557 prect[i].x = x2; 558 prect[i].width = x1 - x2 + 1; 559 } 560 if (y1 < y2) { 561 prect[i].y = y1; 562 prect[i].height = y2 - y1 + 1; 563 } else { 564 prect[i].y = y2; 565 prect[i].height = y1 - y2 + 1; 566 } 567 568 x1 = x2; 569 y1 = y2; 570 } 571 pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); 572 DEALLOCATE_LOCAL(prect); 573} 574 575/** 576 * exaPolySegment() checks if it can accelerate the lines as a group of 577 * horizontal or vertical lines (rectangles), and uses existing rectangle fill 578 * acceleration if so. 579 */ 580static void 581exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, 582 xSegment *pSeg) 583{ 584 xRectangle *prect; 585 int i; 586 587 /* Don't try to do wide lines or non-solid fill style. */ 588 if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 589 pGC->fillStyle != FillSolid) 590 { 591 ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 592 return; 593 } 594 595 /* If we have any non-horizontal/vertical, fall back. */ 596 for (i = 0; i < nseg; i++) { 597 if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { 598 ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 599 return; 600 } 601 } 602 603 prect = ALLOCATE_LOCAL(sizeof(xRectangle) * nseg); 604 for (i = 0; i < nseg; i++) { 605 if (pSeg[i].x1 < pSeg[i].x2) { 606 prect[i].x = pSeg[i].x1; 607 prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; 608 } else { 609 prect[i].x = pSeg[i].x2; 610 prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; 611 } 612 if (pSeg[i].y1 < pSeg[i].y2) { 613 prect[i].y = pSeg[i].y1; 614 prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; 615 } else { 616 prect[i].y = pSeg[i].y2; 617 prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; 618 } 619 } 620 pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); 621 DEALLOCATE_LOCAL(prect); 622} 623 624static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, 625 Pixel pixel, CARD32 planemask, CARD32 alu); 626 627static void 628exaPolyFillRect(DrawablePtr pDrawable, 629 GCPtr pGC, 630 int nrect, 631 xRectangle *prect) 632{ 633 ExaScreenPriv (pDrawable->pScreen); 634 RegionPtr pClip = fbGetCompositeClip(pGC); 635 PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); 636 register BoxPtr pbox; 637 BoxPtr pextent; 638 int extentX1, extentX2, extentY1, extentY2; 639 int fullX1, fullX2, fullY1, fullY2; 640 int partX1, partX2, partY1, partY2; 641 int xoff, yoff; 642 int xorg, yorg; 643 int n; 644 ExaMigrationRec pixmaps[2]; 645 RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); 646 647 /* Compute intersection of rects and clip region */ 648 REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); 649 REGION_INTERSECT(pScreen, pReg, pClip, pReg); 650 651 if (!REGION_NUM_RECTS(pReg)) { 652 goto out; 653 } 654 655 pixmaps[0].as_dst = TRUE; 656 pixmaps[0].as_src = FALSE; 657 pixmaps[0].pPix = pPixmap; 658 659 exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 660 661 if (pExaScr->swappedOut || 662 pPixmap->drawable.width > pExaScr->info->maxX || 663 pPixmap->drawable.height > pExaScr->info->maxY) 664 { 665 goto fallback; 666 } 667 668 /* For ROPs where overlaps don't matter, convert rectangles to region and 669 * call exaFillRegion{Solid,Tiled}. 670 */ 671 if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && 672 (pGC->alu == GXcopy || pGC->alu == GXclear || pGC->alu == GXnoop || 673 pGC->alu == GXcopyInverted || pGC->alu == GXset)) { 674 if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && 675 exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? 676 pGC->fgPixel : pGC->tile.pixel, pGC->planemask, 677 pGC->alu)) || 678 (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && 679 exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, 680 pGC->planemask, pGC->alu))) { 681 goto out; 682 } 683 } 684 685 if (pGC->fillStyle != FillSolid && 686 !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) 687 { 688 goto fallback; 689 } 690 691 exaDoMigration (pixmaps, 1, TRUE); 692 693 if (!exaPixmapIsOffscreen (pPixmap) || 694 !(*pExaScr->info->PrepareSolid) (pPixmap, 695 pGC->alu, 696 pGC->planemask, 697 pGC->fgPixel)) 698 { 699fallback: 700 if (pGC->fillStyle == FillTiled && !pGC->tileIsPixel) { 701 pixmaps[1].as_dst = FALSE; 702 pixmaps[1].as_src = TRUE; 703 pixmaps[1].pPix = pGC->tile.pixmap; 704 exaDoMigration (pixmaps, 2, FALSE); 705 } else { 706 exaDoMigration (pixmaps, 1, FALSE); 707 } 708 709 ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); 710 goto out; 711 } 712 713 xorg = pDrawable->x; 714 yorg = pDrawable->y; 715 716 pextent = REGION_EXTENTS(pGC->pScreen, pClip); 717 extentX1 = pextent->x1; 718 extentY1 = pextent->y1; 719 extentX2 = pextent->x2; 720 extentY2 = pextent->y2; 721 while (nrect--) 722 { 723 fullX1 = prect->x + xorg; 724 fullY1 = prect->y + yorg; 725 fullX2 = fullX1 + (int) prect->width; 726 fullY2 = fullY1 + (int) prect->height; 727 prect++; 728 729 if (fullX1 < extentX1) 730 fullX1 = extentX1; 731 732 if (fullY1 < extentY1) 733 fullY1 = extentY1; 734 735 if (fullX2 > extentX2) 736 fullX2 = extentX2; 737 738 if (fullY2 > extentY2) 739 fullY2 = extentY2; 740 741 if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) 742 continue; 743 n = REGION_NUM_RECTS (pClip); 744 if (n == 1) 745 { 746 (*pExaScr->info->Solid) (pPixmap, 747 fullX1 + xoff, fullY1 + yoff, 748 fullX2 + xoff, fullY2 + yoff); 749 } 750 else 751 { 752 pbox = REGION_RECTS(pClip); 753 /* 754 * clip the rectangle to each box in the clip region 755 * this is logically equivalent to calling Intersect(), 756 * but rectangles may overlap each other here. 757 */ 758 while(n--) 759 { 760 partX1 = pbox->x1; 761 if (partX1 < fullX1) 762 partX1 = fullX1; 763 partY1 = pbox->y1; 764 if (partY1 < fullY1) 765 partY1 = fullY1; 766 partX2 = pbox->x2; 767 if (partX2 > fullX2) 768 partX2 = fullX2; 769 partY2 = pbox->y2; 770 if (partY2 > fullY2) 771 partY2 = fullY2; 772 773 pbox++; 774 775 if (partX1 < partX2 && partY1 < partY2) { 776 (*pExaScr->info->Solid) (pPixmap, 777 partX1 + xoff, partY1 + yoff, 778 partX2 + xoff, partY2 + yoff); 779 } 780 } 781 } 782 } 783 (*pExaScr->info->DoneSolid) (pPixmap); 784 exaMarkSync(pDrawable->pScreen); 785 786out: 787 REGION_DESTROY(pScreen, pReg); 788} 789 790static void 791exaSolidBoxClipped (DrawablePtr pDrawable, 792 RegionPtr pClip, 793 FbBits pm, 794 FbBits fg, 795 int x1, 796 int y1, 797 int x2, 798 int y2) 799{ 800 ExaScreenPriv (pDrawable->pScreen); 801 PixmapPtr pPixmap; 802 BoxPtr pbox; 803 int nbox; 804 int xoff, yoff; 805 int partX1, partX2, partY1, partY2; 806 ExaMigrationRec pixmaps[1]; 807 Bool fallback = FALSE; 808 809 pixmaps[0].as_dst = TRUE; 810 pixmaps[0].as_src = FALSE; 811 pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); 812 813 if (pExaScr->swappedOut || 814 pPixmap->drawable.width > pExaScr->info->maxX || 815 pPixmap->drawable.height > pExaScr->info->maxY) 816 { 817 fallback = TRUE; 818 } else { 819 exaDoMigration (pixmaps, 1, TRUE); 820 } 821 822 exaGetDrawableDeltas (pDrawable, pPixmap, &xoff, &yoff); 823 824 if (fallback || !exaPixmapIsOffscreen(pPixmap) || 825 !(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, pm, fg)) 826 { 827 EXA_FALLBACK(("to %p (%c)\n", pDrawable, 828 exaDrawableLocation(pDrawable))); 829 exaDoMigration (pixmaps, 1, FALSE); 830 fallback = TRUE; 831 exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); 832 fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel); 833 fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2, 834 fbAnd (GXcopy, fg, pm), 835 fbXor (GXcopy, fg, pm)); 836 exaFinishAccess (pDrawable, EXA_PREPARE_DEST); 837 } 838 for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip); 839 nbox--; 840 pbox++) 841 { 842 partX1 = pbox->x1; 843 if (partX1 < x1) 844 partX1 = x1; 845 846 partX2 = pbox->x2; 847 if (partX2 > x2) 848 partX2 = x2; 849 850 if (partX2 <= partX1) 851 continue; 852 853 partY1 = pbox->y1; 854 if (partY1 < y1) 855 partY1 = y1; 856 857 partY2 = pbox->y2; 858 if (partY2 > y2) 859 partY2 = y2; 860 861 if (partY2 <= partY1) 862 continue; 863 864 if (!fallback) { 865 (*pExaScr->info->Solid) (pPixmap, 866 partX1 + xoff, partY1 + yoff, 867 partX2 + xoff, partY2 + yoff); 868 } 869 870 exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff, partX2 + xoff, 871 partY2 + yoff); 872 } 873 874 if (fallback) 875 return; 876 877 (*pExaScr->info->DoneSolid) (pPixmap); 878 exaMarkSync(pDrawable->pScreen); 879} 880 881static void 882exaImageGlyphBlt (DrawablePtr pDrawable, 883 GCPtr pGC, 884 int x, 885 int y, 886 unsigned int nglyph, 887 CharInfoPtr *ppciInit, 888 pointer pglyphBase) 889{ 890 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 891 CharInfoPtr *ppci; 892 CharInfoPtr pci; 893 unsigned char *pglyph; /* pointer bits in glyph */ 894 int gWidth, gHeight; /* width and height of glyph */ 895 FbStride gStride; /* stride of glyph */ 896 Bool opaque; 897 int n; 898 int gx, gy; 899 void (*glyph) (FbBits *, 900 FbStride, 901 int, 902 FbStip *, 903 FbBits, 904 int, 905 int); 906 FbBits *dst; 907 FbStride dstStride; 908 int dstBpp; 909 int dstXoff, dstYoff; 910 FbBits depthMask; 911 PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); 912 ExaMigrationRec pixmaps[1]; 913 int xBack, widthBack, yBack, heightBack; 914 915 for (ppci = ppciInit, n = nglyph, widthBack = 0; n; n--) 916 widthBack += (*ppci++)->metrics.characterWidth; 917 918 xBack = x; 919 if (widthBack < 0) 920 { 921 xBack += widthBack; 922 widthBack = -widthBack; 923 } 924 yBack = y - FONTASCENT(pGC->font); 925 heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); 926 927 if (xBack >= pDrawable->width || yBack >= pDrawable->height || 928 (xBack + widthBack) <= 0 || (yBack + heightBack) <= 0) 929 return; 930 931 pixmaps[0].as_dst = TRUE; 932 pixmaps[0].as_src = TRUE; 933 pixmaps[0].pPix = pPixmap; 934 935 depthMask = FbFullMask(pDrawable->depth); 936 if ((pGC->planemask & depthMask) != depthMask) 937 { 938 exaDoMigration(pixmaps, 1, FALSE); 939 ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase); 940 goto damage; 941 } 942 glyph = NULL; 943 switch (pDrawable->bitsPerPixel) { 944 case 8: glyph = fbGlyph8; break; 945 case 16: glyph = fbGlyph16; break; 946 case 24: glyph = fbGlyph24; break; 947 case 32: glyph = fbGlyph32; break; 948 } 949 950 x += pDrawable->x; 951 y += pDrawable->y; 952 xBack += pDrawable->x; 953 yBack += pDrawable->y; 954 955 if (TERMINALFONT (pGC->font) && !glyph) 956 { 957 opaque = TRUE; 958 } 959 else 960 { 961 exaSolidBoxClipped (pDrawable, 962 fbGetCompositeClip(pGC), 963 pGC->planemask, 964 pGC->bgPixel, 965 xBack, 966 yBack, 967 xBack + widthBack, 968 yBack + heightBack); 969 opaque = FALSE; 970 } 971 972 EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); 973 exaDoMigration(pixmaps, 1, FALSE); 974 exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); 975 exaPrepareAccessGC (pGC); 976 977 fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 978 979 for (ppci = ppciInit; nglyph; nglyph--, x += pci->metrics.characterWidth) 980 { 981 pci = *ppci++; 982 gWidth = GLYPHWIDTHPIXELS(pci); 983 gHeight = GLYPHHEIGHTPIXELS(pci); 984 gx = x + pci->metrics.leftSideBearing; 985 gy = y - pci->metrics.ascent; 986 987 if (!gWidth || !gHeight || (gx + gWidth) <= xBack || 988 (gy + gHeight) <= yBack || gx >= (xBack + widthBack) || 989 gy >= (yBack + heightBack)) 990 continue; 991 992 pglyph = FONTGLYPHBITS(pglyphBase, pci); 993 994 if (glyph && gWidth <= sizeof (FbStip) * 8 && 995 fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) 996 { 997 (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp, 998 (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight); 999 } 1000 else 1001 { 1002 RegionPtr pClip = fbGetCompositeClip(pGC); 1003 1004 gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip); 1005 fbPutXYImage (pDrawable, pClip, pPriv->fg, pPriv->bg, pPriv->pm, 1006 GXcopy, opaque, gx, gy, gWidth, gHeight, 1007 (FbStip *) pglyph, gStride, 0); 1008 } 1009 } 1010 exaFinishAccessGC (pGC); 1011 exaFinishAccess (pDrawable, EXA_PREPARE_DEST); 1012 1013damage: 1014 exaGetDrawableDeltas(pDrawable, pPixmap, &dstXoff, &dstYoff); 1015 exaPixmapDirty(pPixmap, xBack + dstXoff, yBack + dstYoff, 1016 xBack + dstXoff + widthBack, yBack + dstYoff + heightBack); 1017} 1018 1019const GCOps exaOps = { 1020 exaFillSpans, 1021 ExaCheckSetSpans, 1022 exaPutImage, 1023 exaCopyArea, 1024 ExaCheckCopyPlane, 1025 exaPolyPoint, 1026 exaPolylines, 1027 exaPolySegment, 1028 miPolyRectangle, 1029 ExaCheckPolyArc, 1030 miFillPolygon, 1031 exaPolyFillRect, 1032 miPolyFillArc, 1033 miPolyText8, 1034 miPolyText16, 1035 miImageText8, 1036 miImageText16, 1037 exaImageGlyphBlt, 1038 ExaCheckPolyGlyphBlt, 1039 ExaCheckPushPixels, 1040}; 1041 1042void 1043exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 1044{ 1045 RegionRec rgnDst; 1046 int dx, dy; 1047 PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); 1048 1049 dx = ptOldOrg.x - pWin->drawable.x; 1050 dy = ptOldOrg.y - pWin->drawable.y; 1051 REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); 1052 1053 REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); 1054 1055 REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); 1056#ifdef COMPOSITE 1057 if (pPixmap->screen_x || pPixmap->screen_y) 1058 REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, 1059 -pPixmap->screen_x, -pPixmap->screen_y); 1060#endif 1061 1062 fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable, 1063 NULL, 1064 &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); 1065 1066 REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); 1067} 1068 1069static Bool 1070exaFillRegionSolid (DrawablePtr pDrawable, 1071 RegionPtr pRegion, 1072 Pixel pixel, 1073 CARD32 planemask, 1074 CARD32 alu) 1075{ 1076 ExaScreenPriv(pDrawable->pScreen); 1077 PixmapPtr pPixmap; 1078 int xoff, yoff; 1079 ExaMigrationRec pixmaps[1]; 1080 int nbox = REGION_NUM_RECTS (pRegion); 1081 BoxPtr pBox = REGION_RECTS (pRegion); 1082 1083 pixmaps[0].as_dst = TRUE; 1084 pixmaps[0].as_src = FALSE; 1085 pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); 1086 1087 if (pPixmap->drawable.width > pExaScr->info->maxX || 1088 pPixmap->drawable.height > pExaScr->info->maxY) 1089 { 1090 goto fallback; 1091 } else { 1092 exaDoMigration (pixmaps, 1, TRUE); 1093 } 1094 1095 if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) && 1096 (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) 1097 { 1098 while (nbox--) 1099 { 1100 (*pExaScr->info->Solid) (pPixmap, 1101 pBox->x1 + xoff, pBox->y1 + yoff, 1102 pBox->x2 + xoff, pBox->y2 + yoff); 1103 pBox++; 1104 } 1105 (*pExaScr->info->DoneSolid) (pPixmap); 1106 exaMarkSync(pDrawable->pScreen); 1107 } 1108 else 1109 { 1110fallback: 1111 if (alu != GXcopy || planemask != FB_ALLONES) 1112 return FALSE; 1113 EXA_FALLBACK(("to %p (%c)\n", pDrawable, 1114 exaDrawableLocation(pDrawable))); 1115 exaDoMigration (pixmaps, 1, FALSE); 1116 exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); 1117 fbFillRegionSolid (pDrawable, pRegion, 0, 1118 fbReplicatePixel (pixel, pDrawable->bitsPerPixel)); 1119 exaFinishAccess (pDrawable, EXA_PREPARE_DEST); 1120 } 1121 1122 return TRUE; 1123} 1124 1125/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. 1126 * Based on fbFillRegionTiled(), fbTile(). 1127 */ 1128Bool 1129exaFillRegionTiled (DrawablePtr pDrawable, 1130 RegionPtr pRegion, 1131 PixmapPtr pTile, 1132 DDXPointPtr pPatOrg, 1133 CARD32 planemask, 1134 CARD32 alu) 1135{ 1136 ExaScreenPriv(pDrawable->pScreen); 1137 PixmapPtr pPixmap; 1138 int xoff, yoff, tileXoff, tileYoff; 1139 int tileWidth, tileHeight; 1140 ExaMigrationRec pixmaps[2]; 1141 int nbox = REGION_NUM_RECTS (pRegion); 1142 BoxPtr pBox = REGION_RECTS (pRegion); 1143 1144 tileWidth = pTile->drawable.width; 1145 tileHeight = pTile->drawable.height; 1146 1147 /* If we're filling with a solid color, grab it out and go to 1148 * FillRegionSolid, saving numerous copies. 1149 */ 1150 if (tileWidth == 1 && tileHeight == 1) 1151 return exaFillRegionSolid(pDrawable, pRegion, 1152 exaGetPixmapFirstPixel (pTile), planemask, 1153 alu); 1154 1155 pixmaps[0].as_dst = TRUE; 1156 pixmaps[0].as_src = FALSE; 1157 pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); 1158 pixmaps[1].as_dst = FALSE; 1159 pixmaps[1].as_src = TRUE; 1160 pixmaps[1].pPix = pTile; 1161 1162 if (pPixmap->drawable.width > pExaScr->info->maxX || 1163 pPixmap->drawable.height > pExaScr->info->maxY || 1164 tileWidth > pExaScr->info->maxX || 1165 tileHeight > pExaScr->info->maxY) 1166 { 1167 goto fallback; 1168 } else { 1169 exaDoMigration (pixmaps, 2, TRUE); 1170 } 1171 1172 pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 1173 1174 if (!pPixmap) 1175 goto fallback; 1176 1177 if (!exaPixmapIsOffscreen(pTile)) 1178 goto fallback; 1179 1180 if ((*pExaScr->info->PrepareCopy) (exaGetOffscreenPixmap((DrawablePtr)pTile, 1181 &tileXoff, &tileYoff), 1182 pPixmap, 0, 0, alu, planemask)) 1183 { 1184 while (nbox--) 1185 { 1186 int height = pBox->y2 - pBox->y1; 1187 int dstY = pBox->y1; 1188 int tileY; 1189 1190 modulus(dstY - pDrawable->y - pPatOrg->y, tileHeight, tileY); 1191 1192 while (height > 0) { 1193 int width = pBox->x2 - pBox->x1; 1194 int dstX = pBox->x1; 1195 int tileX; 1196 int h = tileHeight - tileY; 1197 1198 if (h > height) 1199 h = height; 1200 height -= h; 1201 1202 modulus(dstX - pDrawable->x - pPatOrg->x, tileWidth, tileX); 1203 1204 while (width > 0) { 1205 int w = tileWidth - tileX; 1206 if (w > width) 1207 w = width; 1208 width -= w; 1209 1210 (*pExaScr->info->Copy) (pPixmap, 1211 tileX + tileXoff, tileY + tileYoff, 1212 dstX + xoff, dstY + yoff, 1213 w, h); 1214 dstX += w; 1215 tileX = 0; 1216 } 1217 dstY += h; 1218 tileY = 0; 1219 } 1220 pBox++; 1221 } 1222 (*pExaScr->info->DoneCopy) (pPixmap); 1223 exaMarkSync(pDrawable->pScreen); 1224 return TRUE; 1225 } 1226 1227fallback: 1228 if (alu != GXcopy || planemask != FB_ALLONES || pPatOrg->x != 0 || 1229 pPatOrg->y != 0) 1230 return FALSE; 1231 EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable, 1232 exaDrawableLocation(&pTile->drawable), 1233 exaDrawableLocation(pDrawable))); 1234 exaDoMigration (pixmaps, 2, FALSE); 1235 exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); 1236 exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC); 1237 fbFillRegionTiled (pDrawable, pRegion, pTile); 1238 exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC); 1239 exaFinishAccess (pDrawable, EXA_PREPARE_DEST); 1240 1241 return TRUE; 1242} 1243 1244void 1245exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what) 1246{ 1247 ExaScreenPriv (pWin->drawable.pScreen); 1248 PixmapPtr pPixmap = exaGetDrawablePixmap((DrawablePtr)pWin); 1249 int xoff, yoff; 1250 BoxPtr pBox; 1251 int nbox = REGION_NUM_RECTS(pRegion); 1252 1253 if (!nbox) 1254 return; 1255 1256 if (!pExaScr->swappedOut) { 1257 DDXPointRec zeros = { 0, 0 }; 1258 1259 switch (what) { 1260 case PW_BACKGROUND: 1261 switch (pWin->backgroundState) { 1262 case None: 1263 return; 1264 case ParentRelative: 1265 do { 1266 pWin = pWin->parent; 1267 } while (pWin->backgroundState == ParentRelative); 1268 (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion, 1269 what); 1270 return; 1271 case BackgroundPixel: 1272 exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->background.pixel, 1273 FB_ALLONES, GXcopy); 1274 goto damage; 1275 case BackgroundPixmap: 1276 exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->background.pixmap, 1277 &zeros, FB_ALLONES, GXcopy); 1278 goto damage; 1279 } 1280 break; 1281 case PW_BORDER: 1282 if (pWin->borderIsPixel) { 1283 exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->border.pixel, 1284 FB_ALLONES, GXcopy); 1285 goto damage; 1286 } else { 1287 exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->border.pixmap, 1288 &zeros, FB_ALLONES, GXcopy); 1289 goto damage; 1290 } 1291 break; 1292 } 1293 } 1294 ExaCheckPaintWindow (pWin, pRegion, what); 1295 1296damage: 1297 exaGetDrawableDeltas((DrawablePtr)pWin, pPixmap, &xoff, &yoff); 1298 1299 pBox = REGION_RECTS(pRegion); 1300 1301 while (nbox--) 1302 { 1303 exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff, 1304 pBox->x2 + xoff, pBox->y2 + yoff); 1305 pBox++; 1306 } 1307} 1308 1309/** 1310 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. 1311 * 1312 * This is probably the only case we actually care about. The rest fall through 1313 * to migration and ExaCheckGetImage, which hopefully will result in migration 1314 * pushing the pixmap out of framebuffer. 1315 */ 1316void 1317exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, 1318 unsigned int format, unsigned long planeMask, char *d) 1319{ 1320 ExaScreenPriv (pDrawable->pScreen); 1321 ExaMigrationRec pixmaps[1]; 1322 PixmapPtr pPix; 1323 int xoff, yoff; 1324 Bool ok; 1325 1326 if (pExaScr->swappedOut || (w == 1 && h == 1)) 1327 goto fallback; 1328 1329 if (pExaScr->info->DownloadFromScreen == NULL) 1330 goto migrate_and_fallback; 1331 1332 /* Only cover the ZPixmap, solid copy case. */ 1333 if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) 1334 goto migrate_and_fallback; 1335 1336 /* Only try to handle the 8bpp and up cases, since we don't want to think 1337 * about <8bpp. 1338 */ 1339 if (pDrawable->bitsPerPixel < 8) 1340 goto migrate_and_fallback; 1341 1342 pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 1343 if (pPix == NULL) 1344 goto fallback; 1345 1346 xoff += pDrawable->x; 1347 yoff += pDrawable->y; 1348 1349 ok = pExaScr->info->DownloadFromScreen(pPix, x + xoff, y + yoff, w, h, d, 1350 PixmapBytePad(w, pDrawable->depth)); 1351 if (ok) { 1352 exaWaitSync(pDrawable->pScreen); 1353 return; 1354 } 1355 1356migrate_and_fallback: 1357 pixmaps[0].as_dst = FALSE; 1358 pixmaps[0].as_src = TRUE; 1359 pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); 1360 exaDoMigration (pixmaps, 1, FALSE); 1361fallback: 1362 ExaCheckGetImage (pDrawable, x, y, w, h, format, planeMask, d); 1363} 1364 1365/** 1366 * GetSpans isn't accelerated yet, but performs migration so that we'll 1367 * hopefully avoid the read-from-framebuffer cost. 1368 */ 1369void 1370exaGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth, 1371 int nspans, char *pdstStart) 1372{ 1373 ExaMigrationRec pixmaps[1]; 1374 1375 pixmaps[0].as_dst = FALSE; 1376 pixmaps[0].as_src = TRUE; 1377 pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); 1378 exaDoMigration (pixmaps, 1, FALSE); 1379 1380 ExaCheckGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); 1381} 1382