exa_accel.c revision 4642e01f
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 dstregion = REGION_CREATE(pScreen, NullBox, 0); 432 REGION_COPY(pScreen, dstregion, srcregion); 433 REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x, 434 dst_off_y - dy - src_off_y); 435 } 436 } 437 438 pixmaps[0].as_dst = TRUE; 439 pixmaps[0].as_src = FALSE; 440 pixmaps[0].pPix = pDstPixmap; 441 pixmaps[0].pReg = dstregion; 442 pixmaps[1].as_dst = FALSE; 443 pixmaps[1].as_src = TRUE; 444 pixmaps[1].pPix = pSrcPixmap; 445 pixmaps[1].pReg = srcregion; 446 447 pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); 448 pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); 449 450 /* Check whether the accelerator can use this pixmap. 451 * If the pitch of the pixmaps is out of range, there's nothing 452 * we can do but fall back to software rendering. 453 */ 454 if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || 455 pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) 456 goto fallback; 457 458 /* If the width or the height of either of the pixmaps 459 * is out of range, check whether the boxes are actually out of the 460 * addressable range as well. If they aren't, we can still do 461 * the copying in hardware. 462 */ 463 if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { 464 int i; 465 466 for (i = 0; i < nbox; i++) { 467 /* src */ 468 if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || 469 (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) 470 goto fallback; 471 472 /* dst */ 473 if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || 474 (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) 475 goto fallback; 476 } 477 } 478 479 exaDoMigration (pixmaps, 2, TRUE); 480 481 /* Mixed directions must be handled specially if the card is lame */ 482 if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && 483 reverse != upsidedown) { 484 if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, 485 dx, dy)) 486 goto out; 487 goto fallback; 488 } 489 490 if (!exaPixmapIsOffscreen(pSrcPixmap) || 491 !exaPixmapIsOffscreen(pDstPixmap) || 492 !(*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 512 goto out; 513 514fallback: 515 EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, 516 exaDrawableLocation(pSrcDrawable), 517 exaDrawableLocation(pDstDrawable))); 518 exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, dstregion); 519 exaPrepareAccessReg (pSrcDrawable, EXA_PREPARE_SRC, srcregion); 520 fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, 521 upsidedown, bitplane, closure); 522 exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC); 523 exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST); 524 525out: 526 if (dstregion) { 527 REGION_UNINIT(pScreen, dstregion); 528 REGION_DESTROY(pScreen, dstregion); 529 } 530 if (srcregion) { 531 REGION_UNINIT(pScreen, srcregion); 532 REGION_DESTROY(pScreen, srcregion); 533 } 534} 535 536RegionPtr 537exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, 538 int srcx, int srcy, int width, int height, int dstx, int dsty) 539{ 540 ExaScreenPriv (pDstDrawable->pScreen); 541 542 if (pExaScr->swappedOut) { 543 return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, 544 srcx, srcy, width, height, dstx, dsty); 545 } 546 547 return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, 548 srcx, srcy, width, height, 549 dstx, dsty, exaCopyNtoN, 0, NULL); 550} 551 552static void 553exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 554 DDXPointPtr ppt) 555{ 556 int i; 557 xRectangle *prect; 558 559 /* If we can't reuse the current GC as is, don't bother accelerating the 560 * points. 561 */ 562 if (pGC->fillStyle != FillSolid) { 563 ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); 564 return; 565 } 566 567 prect = xalloc(sizeof(xRectangle) * npt); 568 for (i = 0; i < npt; i++) { 569 prect[i].x = ppt[i].x; 570 prect[i].y = ppt[i].y; 571 if (i > 0 && mode == CoordModePrevious) { 572 prect[i].x += prect[i - 1].x; 573 prect[i].y += prect[i - 1].y; 574 } 575 prect[i].width = 1; 576 prect[i].height = 1; 577 } 578 pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); 579 xfree(prect); 580} 581 582/** 583 * exaPolylines() checks if it can accelerate the lines as a group of 584 * horizontal or vertical lines (rectangles), and uses existing rectangle fill 585 * acceleration if so. 586 */ 587static void 588exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 589 DDXPointPtr ppt) 590{ 591 xRectangle *prect; 592 int x1, x2, y1, y2; 593 int i; 594 595 /* Don't try to do wide lines or non-solid fill style. */ 596 if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 597 pGC->fillStyle != FillSolid) { 598 ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 599 return; 600 } 601 602 prect = xalloc(sizeof(xRectangle) * (npt - 1)); 603 x1 = ppt[0].x; 604 y1 = ppt[0].y; 605 /* If we have any non-horizontal/vertical, fall back. */ 606 for (i = 0; i < npt - 1; i++) { 607 if (mode == CoordModePrevious) { 608 x2 = x1 + ppt[i + 1].x; 609 y2 = y1 + ppt[i + 1].y; 610 } else { 611 x2 = ppt[i + 1].x; 612 y2 = ppt[i + 1].y; 613 } 614 615 if (x1 != x2 && y1 != y2) { 616 xfree(prect); 617 ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 618 return; 619 } 620 621 if (x1 < x2) { 622 prect[i].x = x1; 623 prect[i].width = x2 - x1 + 1; 624 } else { 625 prect[i].x = x2; 626 prect[i].width = x1 - x2 + 1; 627 } 628 if (y1 < y2) { 629 prect[i].y = y1; 630 prect[i].height = y2 - y1 + 1; 631 } else { 632 prect[i].y = y2; 633 prect[i].height = y1 - y2 + 1; 634 } 635 636 x1 = x2; 637 y1 = y2; 638 } 639 pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); 640 xfree(prect); 641} 642 643/** 644 * exaPolySegment() checks if it can accelerate the lines as a group of 645 * horizontal or vertical lines (rectangles), and uses existing rectangle fill 646 * acceleration if so. 647 */ 648static void 649exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, 650 xSegment *pSeg) 651{ 652 xRectangle *prect; 653 int i; 654 655 /* Don't try to do wide lines or non-solid fill style. */ 656 if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 657 pGC->fillStyle != FillSolid) 658 { 659 ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 660 return; 661 } 662 663 /* If we have any non-horizontal/vertical, fall back. */ 664 for (i = 0; i < nseg; i++) { 665 if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { 666 ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 667 return; 668 } 669 } 670 671 prect = xalloc(sizeof(xRectangle) * nseg); 672 for (i = 0; i < nseg; i++) { 673 if (pSeg[i].x1 < pSeg[i].x2) { 674 prect[i].x = pSeg[i].x1; 675 prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; 676 } else { 677 prect[i].x = pSeg[i].x2; 678 prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; 679 } 680 if (pSeg[i].y1 < pSeg[i].y2) { 681 prect[i].y = pSeg[i].y1; 682 prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; 683 } else { 684 prect[i].y = pSeg[i].y2; 685 prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; 686 } 687 688 /* don't paint last pixel */ 689 if (pGC->capStyle == CapNotLast) { 690 if (prect[i].width == 1) 691 prect[i].height--; 692 else 693 prect[i].width--; 694 } 695 } 696 pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); 697 xfree(prect); 698} 699 700static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, 701 Pixel pixel, CARD32 planemask, CARD32 alu); 702 703static void 704exaPolyFillRect(DrawablePtr pDrawable, 705 GCPtr pGC, 706 int nrect, 707 xRectangle *prect) 708{ 709 ExaScreenPriv (pDrawable->pScreen); 710 RegionPtr pClip = fbGetCompositeClip(pGC); 711 PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); 712 ExaPixmapPriv (pPixmap); 713 register BoxPtr pbox; 714 BoxPtr pextent; 715 int extentX1, extentX2, extentY1, extentY2; 716 int fullX1, fullX2, fullY1, fullY2; 717 int partX1, partX2, partY1, partY2; 718 int xoff, yoff; 719 int xorg, yorg; 720 int n; 721 ExaMigrationRec pixmaps[2]; 722 RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); 723 724 /* Compute intersection of rects and clip region */ 725 REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); 726 REGION_INTERSECT(pScreen, pReg, pClip, pReg); 727 728 if (!REGION_NUM_RECTS(pReg)) { 729 goto out; 730 } 731 732 pixmaps[0].as_dst = TRUE; 733 pixmaps[0].as_src = FALSE; 734 pixmaps[0].pPix = pPixmap; 735 pixmaps[0].pReg = NULL; 736 737 exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 738 739 if (pExaScr->swappedOut || pExaPixmap->accel_blocked) 740 { 741 goto fallback; 742 } 743 744 /* For ROPs where overlaps don't matter, convert rectangles to region and 745 * call exaFillRegion{Solid,Tiled}. 746 */ 747 if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && 748 (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || 749 pGC->alu == GXnoop || pGC->alu == GXcopyInverted || 750 pGC->alu == GXset)) { 751 if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && 752 exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? 753 pGC->fgPixel : pGC->tile.pixel, pGC->planemask, 754 pGC->alu)) || 755 (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && 756 exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, 757 pGC->planemask, pGC->alu))) { 758 goto out; 759 } 760 } 761 762 if (pGC->fillStyle != FillSolid && 763 !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) 764 { 765 goto fallback; 766 } 767 768 exaDoMigration (pixmaps, 1, TRUE); 769 770 if (!exaPixmapIsOffscreen (pPixmap) || 771 !(*pExaScr->info->PrepareSolid) (pPixmap, 772 pGC->alu, 773 pGC->planemask, 774 pGC->fgPixel)) 775 { 776fallback: 777 ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); 778 goto out; 779 } 780 781 xorg = pDrawable->x; 782 yorg = pDrawable->y; 783 784 pextent = REGION_EXTENTS(pGC->pScreen, pClip); 785 extentX1 = pextent->x1; 786 extentY1 = pextent->y1; 787 extentX2 = pextent->x2; 788 extentY2 = pextent->y2; 789 while (nrect--) 790 { 791 fullX1 = prect->x + xorg; 792 fullY1 = prect->y + yorg; 793 fullX2 = fullX1 + (int) prect->width; 794 fullY2 = fullY1 + (int) prect->height; 795 prect++; 796 797 if (fullX1 < extentX1) 798 fullX1 = extentX1; 799 800 if (fullY1 < extentY1) 801 fullY1 = extentY1; 802 803 if (fullX2 > extentX2) 804 fullX2 = extentX2; 805 806 if (fullY2 > extentY2) 807 fullY2 = extentY2; 808 809 if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) 810 continue; 811 n = REGION_NUM_RECTS (pClip); 812 if (n == 1) 813 { 814 (*pExaScr->info->Solid) (pPixmap, 815 fullX1 + xoff, fullY1 + yoff, 816 fullX2 + xoff, fullY2 + yoff); 817 } 818 else 819 { 820 pbox = REGION_RECTS(pClip); 821 /* 822 * clip the rectangle to each box in the clip region 823 * this is logically equivalent to calling Intersect(), 824 * but rectangles may overlap each other here. 825 */ 826 while(n--) 827 { 828 partX1 = pbox->x1; 829 if (partX1 < fullX1) 830 partX1 = fullX1; 831 partY1 = pbox->y1; 832 if (partY1 < fullY1) 833 partY1 = fullY1; 834 partX2 = pbox->x2; 835 if (partX2 > fullX2) 836 partX2 = fullX2; 837 partY2 = pbox->y2; 838 if (partY2 > fullY2) 839 partY2 = fullY2; 840 841 pbox++; 842 843 if (partX1 < partX2 && partY1 < partY2) { 844 (*pExaScr->info->Solid) (pPixmap, 845 partX1 + xoff, partY1 + yoff, 846 partX2 + xoff, partY2 + yoff); 847 } 848 } 849 } 850 } 851 (*pExaScr->info->DoneSolid) (pPixmap); 852 exaMarkSync(pDrawable->pScreen); 853 854out: 855 REGION_UNINIT(pScreen, pReg); 856 REGION_DESTROY(pScreen, pReg); 857} 858 859const GCOps exaOps = { 860 exaFillSpans, 861 ExaCheckSetSpans, 862 exaPutImage, 863 exaCopyArea, 864 ExaCheckCopyPlane, 865 exaPolyPoint, 866 exaPolylines, 867 exaPolySegment, 868 miPolyRectangle, 869 ExaCheckPolyArc, 870 miFillPolygon, 871 exaPolyFillRect, 872 miPolyFillArc, 873 miPolyText8, 874 miPolyText16, 875 miImageText8, 876 miImageText16, 877 ExaCheckImageGlyphBlt, 878 ExaCheckPolyGlyphBlt, 879 ExaCheckPushPixels, 880}; 881 882void 883exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 884{ 885 RegionRec rgnDst; 886 int dx, dy; 887 PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); 888 889 dx = ptOldOrg.x - pWin->drawable.x; 890 dy = ptOldOrg.y - pWin->drawable.y; 891 REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); 892 893 REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); 894 895 REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); 896#ifdef COMPOSITE 897 if (pPixmap->screen_x || pPixmap->screen_y) 898 REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, 899 -pPixmap->screen_x, -pPixmap->screen_y); 900#endif 901 902 fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable, 903 NULL, 904 &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); 905 906 REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); 907} 908 909static Bool 910exaFillRegionSolid (DrawablePtr pDrawable, 911 RegionPtr pRegion, 912 Pixel pixel, 913 CARD32 planemask, 914 CARD32 alu) 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) ? NULL : pRegion; 928 929 exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 930 REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); 931 932 if (pExaPixmap->accel_blocked) 933 { 934 goto out; 935 } else { 936 exaDoMigration (pixmaps, 1, TRUE); 937 } 938 939 if (exaPixmapIsOffscreen (pPixmap) && 940 (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) 941 { 942 int nbox; 943 BoxPtr pBox; 944 945 nbox = REGION_NUM_RECTS (pRegion); 946 pBox = REGION_RECTS (pRegion); 947 948 while (nbox--) 949 { 950 (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, 951 pBox->y2); 952 pBox++; 953 } 954 (*pExaScr->info->DoneSolid) (pPixmap); 955 exaMarkSync(pDrawable->pScreen); 956 957 if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && 958 pDrawable->width == 1 && pDrawable->height == 1 && 959 pDrawable->bitsPerPixel != 24) { 960 ExaPixmapPriv(pPixmap); 961 962 switch (pDrawable->bitsPerPixel) { 963 case 32: 964 *(CARD32*)pExaPixmap->sys_ptr = pixel; 965 break; 966 case 16: 967 *(CARD16*)pExaPixmap->sys_ptr = pixel; 968 break; 969 case 8: 970 *(CARD8*)pExaPixmap->sys_ptr = pixel; 971 } 972 973 REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, 974 pRegion); 975 } 976 977 ret = TRUE; 978 } 979 980out: 981 REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); 982 983 return ret; 984} 985 986/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. 987 * Based on fbFillRegionTiled(), fbTile(). 988 */ 989Bool 990exaFillRegionTiled (DrawablePtr pDrawable, 991 RegionPtr pRegion, 992 PixmapPtr pTile, 993 DDXPointPtr pPatOrg, 994 CARD32 planemask, 995 CARD32 alu) 996{ 997 ExaScreenPriv(pDrawable->pScreen); 998 PixmapPtr pPixmap; 999 ExaPixmapPrivPtr pExaPixmap; 1000 ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); 1001 int xoff, yoff; 1002 int tileWidth, tileHeight; 1003 ExaMigrationRec pixmaps[2]; 1004 int nbox = REGION_NUM_RECTS (pRegion); 1005 BoxPtr pBox = REGION_RECTS (pRegion); 1006 Bool ret = FALSE; 1007 int i; 1008 1009 tileWidth = pTile->drawable.width; 1010 tileHeight = pTile->drawable.height; 1011 1012 /* If we're filling with a solid color, grab it out and go to 1013 * FillRegionSolid, saving numerous copies. 1014 */ 1015 if (tileWidth == 1 && tileHeight == 1) 1016 return exaFillRegionSolid(pDrawable, pRegion, 1017 exaGetPixmapFirstPixel (pTile), planemask, 1018 alu); 1019 1020 pixmaps[0].as_dst = TRUE; 1021 pixmaps[0].as_src = FALSE; 1022 pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); 1023 pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, 1024 alu) ? NULL : pRegion; 1025 pixmaps[1].as_dst = FALSE; 1026 pixmaps[1].as_src = TRUE; 1027 pixmaps[1].pPix = pTile; 1028 pixmaps[1].pReg = NULL; 1029 1030 pExaPixmap = ExaGetPixmapPriv (pPixmap); 1031 1032 if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked) 1033 { 1034 return FALSE; 1035 } else { 1036 exaDoMigration (pixmaps, 2, TRUE); 1037 } 1038 1039 pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 1040 1041 if (!pPixmap || !exaPixmapIsOffscreen(pTile)) 1042 return FALSE; 1043 1044 if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) 1045 { 1046 if (xoff || yoff) 1047 REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); 1048 1049 for (i = 0; i < nbox; i++) 1050 { 1051 int height = pBox[i].y2 - pBox[i].y1; 1052 int dstY = pBox[i].y1; 1053 int tileY; 1054 1055 if (alu == GXcopy) 1056 height = min(height, tileHeight); 1057 1058 modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); 1059 1060 while (height > 0) { 1061 int width = pBox[i].x2 - pBox[i].x1; 1062 int dstX = pBox[i].x1; 1063 int tileX; 1064 int h = tileHeight - tileY; 1065 1066 if (alu == GXcopy) 1067 width = min(width, tileWidth); 1068 1069 if (h > height) 1070 h = height; 1071 height -= h; 1072 1073 modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, 1074 tileX); 1075 1076 while (width > 0) { 1077 int w = tileWidth - tileX; 1078 if (w > width) 1079 w = width; 1080 width -= w; 1081 1082 (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, 1083 w, h); 1084 dstX += w; 1085 tileX = 0; 1086 } 1087 dstY += h; 1088 tileY = 0; 1089 } 1090 } 1091 (*pExaScr->info->DoneCopy) (pPixmap); 1092 1093 /* With GXcopy, we only need to do the basic algorithm up to the tile 1094 * size; then, we can just keep doubling the destination in each 1095 * direction until it fills the box. This way, the number of copy 1096 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where 1097 * rx/ry is the ratio between box and tile width/height. This can make 1098 * a big difference if each driver copy incurs a significant constant 1099 * overhead. 1100 */ 1101 if (alu != GXcopy) 1102 ret = TRUE; 1103 else { 1104 Bool more_copy = FALSE; 1105 1106 for (i = 0; i < nbox; i++) { 1107 int dstX = pBox[i].x1 + tileWidth; 1108 int dstY = pBox[i].y1 + tileHeight; 1109 1110 if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { 1111 more_copy = TRUE; 1112 break; 1113 } 1114 } 1115 1116 if (more_copy == FALSE) 1117 ret = TRUE; 1118 1119 if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, 1120 1, 1, alu, planemask)) { 1121 for (i = 0; i < nbox; i++) 1122 { 1123 int dstX = pBox[i].x1 + tileWidth; 1124 int dstY = pBox[i].y1 + tileHeight; 1125 int width = min(pBox[i].x2 - dstX, tileWidth); 1126 int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); 1127 1128 while (dstX < pBox[i].x2) { 1129 (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 1130 dstX, pBox[i].y1, width, height); 1131 dstX += width; 1132 width = min(pBox[i].x2 - dstX, width * 2); 1133 } 1134 1135 width = pBox[i].x2 - pBox[i].x1; 1136 height = min(pBox[i].y2 - dstY, tileHeight); 1137 1138 while (dstY < pBox[i].y2) { 1139 (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 1140 pBox[i].x1, dstY, width, height); 1141 dstY += height; 1142 height = min(pBox[i].y2 - dstY, height * 2); 1143 } 1144 } 1145 1146 (*pExaScr->info->DoneCopy) (pPixmap); 1147 1148 ret = TRUE; 1149 } 1150 } 1151 1152 exaMarkSync(pDrawable->pScreen); 1153 1154 if (xoff || yoff) 1155 REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); 1156 } 1157 1158 return ret; 1159} 1160 1161 1162/** 1163 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. 1164 * 1165 * This is probably the only case we actually care about. The rest fall through 1166 * to migration and fbGetImage, which hopefully will result in migration pushing 1167 * the pixmap out of framebuffer. 1168 */ 1169void 1170exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, 1171 unsigned int format, unsigned long planeMask, char *d) 1172{ 1173 ExaScreenPriv (pDrawable->pScreen); 1174 ExaMigrationRec pixmaps[1]; 1175 BoxRec Box; 1176 RegionRec Reg; 1177 PixmapPtr pPix; 1178 int xoff, yoff; 1179 Bool ok; 1180 1181 pixmaps[0].as_dst = FALSE; 1182 pixmaps[0].as_src = TRUE; 1183 pixmaps[0].pPix = pPix = exaGetDrawablePixmap (pDrawable); 1184 pixmaps[0].pReg = &Reg; 1185 1186 exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff); 1187 1188 Box.x1 = pDrawable->y + x + xoff; 1189 Box.y1 = pDrawable->y + y + yoff; 1190 Box.x2 = Box.x1 + w; 1191 Box.y2 = Box.y1 + h; 1192 1193 REGION_INIT(pScreen, &Reg, &Box, 1); 1194 1195 if (pExaScr->swappedOut) 1196 goto fallback; 1197 1198 exaDoMigration(pixmaps, 1, FALSE); 1199 1200 pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 1201 1202 if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) 1203 goto fallback; 1204 1205 /* Only cover the ZPixmap, solid copy case. */ 1206 if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) 1207 goto fallback; 1208 1209 /* Only try to handle the 8bpp and up cases, since we don't want to think 1210 * about <8bpp. 1211 */ 1212 if (pDrawable->bitsPerPixel < 8) 1213 goto fallback; 1214 1215 ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, 1216 pDrawable->y + y + yoff, w, h, d, 1217 PixmapBytePad(w, pDrawable->depth)); 1218 if (ok) { 1219 exaWaitSync(pDrawable->pScreen); 1220 goto out; 1221 } 1222 1223fallback: 1224 EXA_FALLBACK(("from %p (%c)\n", pDrawable, 1225 exaDrawableLocation(pDrawable))); 1226 1227 exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg); 1228 fbGetImage (pDrawable, x, y, w, h, format, planeMask, d); 1229 exaFinishAccess (pDrawable, EXA_PREPARE_SRC); 1230 1231out: 1232 REGION_UNINIT(pScreen, &Reg); 1233} 1234