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