fbcopy.c revision 4642e01f
1/* 2 * Copyright © 1998 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Keith Packard not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Keith Packard makes no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_DIX_CONFIG_H 24#include <dix-config.h> 25#endif 26 27#include <stdlib.h> 28 29#include "fb.h" 30 31void 32fbCopyNtoN (DrawablePtr pSrcDrawable, 33 DrawablePtr pDstDrawable, 34 GCPtr pGC, 35 BoxPtr pbox, 36 int nbox, 37 int dx, 38 int dy, 39 Bool reverse, 40 Bool upsidedown, 41 Pixel bitplane, 42 void *closure) 43{ 44 CARD8 alu = pGC ? pGC->alu : GXcopy; 45 FbBits pm = pGC ? fbGetGCPrivate(pGC)->pm : FB_ALLONES; 46 FbBits *src; 47 FbStride srcStride; 48 int srcBpp; 49 int srcXoff, srcYoff; 50 FbBits *dst; 51 FbStride dstStride; 52 int dstBpp; 53 int dstXoff, dstYoff; 54 55 fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); 56 fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 57 58 while (nbox--) 59 { 60#ifndef FB_ACCESS_WRAPPER /* pixman_blt() doesn't support accessors yet */ 61 if (pm == FB_ALLONES && alu == GXcopy && !reverse && 62 !upsidedown) 63 { 64 if (!pixman_blt ((uint32_t *)src, (uint32_t *)dst, srcStride, dstStride, srcBpp, dstBpp, 65 (pbox->x1 + dx + srcXoff), 66 (pbox->y1 + dy + srcYoff), 67 (pbox->x1 + dstXoff), 68 (pbox->y1 + dstYoff), 69 (pbox->x2 - pbox->x1), 70 (pbox->y2 - pbox->y1))) 71 goto fallback; 72 else 73 goto next; 74 } 75 fallback: 76#endif 77 fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride, 78 srcStride, 79 (pbox->x1 + dx + srcXoff) * srcBpp, 80 81 dst + (pbox->y1 + dstYoff) * dstStride, 82 dstStride, 83 (pbox->x1 + dstXoff) * dstBpp, 84 85 (pbox->x2 - pbox->x1) * dstBpp, 86 (pbox->y2 - pbox->y1), 87 88 alu, 89 pm, 90 dstBpp, 91 92 reverse, 93 upsidedown); 94#ifndef FB_ACCESS_WRAPPER 95 next: 96#endif 97 pbox++; 98 } 99 fbFinishAccess (pDstDrawable); 100 fbFinishAccess (pSrcDrawable); 101} 102 103void 104fbCopy1toN (DrawablePtr pSrcDrawable, 105 DrawablePtr pDstDrawable, 106 GCPtr pGC, 107 BoxPtr pbox, 108 int nbox, 109 int dx, 110 int dy, 111 Bool reverse, 112 Bool upsidedown, 113 Pixel bitplane, 114 void *closure) 115{ 116 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 117 FbBits *src; 118 FbStride srcStride; 119 int srcBpp; 120 int srcXoff, srcYoff; 121 FbBits *dst; 122 FbStride dstStride; 123 int dstBpp; 124 int dstXoff, dstYoff; 125 126 fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); 127 fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 128 129 while (nbox--) 130 { 131 if (dstBpp == 1) 132 { 133 fbBlt (src + (pbox->y1 + dy + srcYoff) * srcStride, 134 srcStride, 135 (pbox->x1 + dx + srcXoff) * srcBpp, 136 137 dst + (pbox->y1 + dstYoff) * dstStride, 138 dstStride, 139 (pbox->x1 + dstXoff) * dstBpp, 140 141 (pbox->x2 - pbox->x1) * dstBpp, 142 (pbox->y2 - pbox->y1), 143 144 FbOpaqueStipple1Rop(pGC->alu, 145 pGC->fgPixel,pGC->bgPixel), 146 pPriv->pm, 147 dstBpp, 148 149 reverse, 150 upsidedown); 151 } 152 else 153 { 154 fbBltOne ((FbStip *) (src + (pbox->y1 + dy + srcYoff) * srcStride), 155 srcStride*(FB_UNIT/FB_STIP_UNIT), 156 (pbox->x1 + dx + srcXoff), 157 158 dst + (pbox->y1 + dstYoff) * dstStride, 159 dstStride, 160 (pbox->x1 + dstXoff) * dstBpp, 161 dstBpp, 162 163 (pbox->x2 - pbox->x1) * dstBpp, 164 (pbox->y2 - pbox->y1), 165 166 pPriv->and, pPriv->xor, 167 pPriv->bgand, pPriv->bgxor); 168 } 169 pbox++; 170 } 171 172 fbFinishAccess (pDstDrawable); 173 fbFinishAccess (pSrcDrawable); 174} 175 176void 177fbCopyNto1 (DrawablePtr pSrcDrawable, 178 DrawablePtr pDstDrawable, 179 GCPtr pGC, 180 BoxPtr pbox, 181 int nbox, 182 int dx, 183 int dy, 184 Bool reverse, 185 Bool upsidedown, 186 Pixel bitplane, 187 void *closure) 188{ 189 FbGCPrivPtr pPriv = fbGetGCPrivate (pGC); 190 191 while (nbox--) 192 { 193 if (pDstDrawable->bitsPerPixel == 1) 194 { 195 FbBits *src; 196 FbStride srcStride; 197 int srcBpp; 198 int srcXoff, srcYoff; 199 200 FbStip *dst; 201 FbStride dstStride; 202 int dstBpp; 203 int dstXoff, dstYoff; 204 205 fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); 206 fbGetStipDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 207 fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride, 208 srcStride, 209 (pbox->x1 + dx + srcXoff) * srcBpp, 210 srcBpp, 211 212 dst + (pbox->y1 + dstYoff) * dstStride, 213 dstStride, 214 (pbox->x1 + dstXoff) * dstBpp, 215 216 (pbox->x2 - pbox->x1) * srcBpp, 217 (pbox->y2 - pbox->y1), 218 219 (FbStip) pPriv->and, (FbStip) pPriv->xor, 220 (FbStip) pPriv->bgand, (FbStip) pPriv->bgxor, 221 bitplane); 222 fbFinishAccess (pDstDrawable); 223 fbFinishAccess (pSrcDrawable); 224 } 225 else 226 { 227 FbBits *src; 228 FbStride srcStride; 229 int srcBpp; 230 int srcXoff, srcYoff; 231 232 FbBits *dst; 233 FbStride dstStride; 234 int dstBpp; 235 int dstXoff, dstYoff; 236 237 FbStip *tmp; 238 FbStride tmpStride; 239 int width, height; 240 241 width = pbox->x2 - pbox->x1; 242 height = pbox->y2 - pbox->y1; 243 244 tmpStride = ((width + FB_STIP_MASK) >> FB_STIP_SHIFT); 245 tmp = xalloc (tmpStride * height * sizeof (FbStip)); 246 if (!tmp) 247 return; 248 249 fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); 250 fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); 251 252 fbBltPlane (src + (pbox->y1+ dy + srcYoff) * srcStride, 253 srcStride, 254 (pbox->x1 + dx + srcXoff) * srcBpp, 255 srcBpp, 256 257 tmp, 258 tmpStride, 259 0, 260 261 width * srcBpp, 262 height, 263 264 fbAndStip(GXcopy,FB_ALLONES,FB_ALLONES), 265 fbXorStip(GXcopy,FB_ALLONES,FB_ALLONES), 266 fbAndStip(GXcopy,0,FB_ALLONES), 267 fbXorStip(GXcopy,0,FB_ALLONES), 268 bitplane); 269 fbBltOne (tmp, 270 tmpStride, 271 0, 272 273 dst + (pbox->y1 + dstYoff) * dstStride, 274 dstStride, 275 (pbox->x1 + dstXoff) * dstBpp, 276 dstBpp, 277 278 width * dstBpp, 279 height, 280 281 pPriv->and, pPriv->xor, 282 pPriv->bgand, pPriv->bgxor); 283 xfree (tmp); 284 285 fbFinishAccess (pDstDrawable); 286 fbFinishAccess (pSrcDrawable); 287 } 288 pbox++; 289 } 290} 291 292void 293fbCopyRegion (DrawablePtr pSrcDrawable, 294 DrawablePtr pDstDrawable, 295 GCPtr pGC, 296 RegionPtr pDstRegion, 297 int dx, 298 int dy, 299 fbCopyProc copyProc, 300 Pixel bitPlane, 301 void *closure) 302{ 303 int careful; 304 Bool reverse; 305 Bool upsidedown; 306 BoxPtr pbox; 307 int nbox; 308 BoxPtr pboxNew1, pboxNew2, pboxBase, pboxNext, pboxTmp; 309 310 pbox = REGION_RECTS(pDstRegion); 311 nbox = REGION_NUM_RECTS(pDstRegion); 312 313 /* XXX we have to err on the side of safety when both are windows, 314 * because we don't know if IncludeInferiors is being used. 315 */ 316 careful = ((pSrcDrawable == pDstDrawable) || 317 ((pSrcDrawable->type == DRAWABLE_WINDOW) && 318 (pDstDrawable->type == DRAWABLE_WINDOW))); 319 320 pboxNew1 = NULL; 321 pboxNew2 = NULL; 322 if (careful && dy < 0) 323 { 324 upsidedown = TRUE; 325 326 if (nbox > 1) 327 { 328 /* keep ordering in each band, reverse order of bands */ 329 pboxNew1 = (BoxPtr)xalloc(sizeof(BoxRec) * nbox); 330 if(!pboxNew1) 331 return; 332 pboxBase = pboxNext = pbox+nbox-1; 333 while (pboxBase >= pbox) 334 { 335 while ((pboxNext >= pbox) && 336 (pboxBase->y1 == pboxNext->y1)) 337 pboxNext--; 338 pboxTmp = pboxNext+1; 339 while (pboxTmp <= pboxBase) 340 { 341 *pboxNew1++ = *pboxTmp++; 342 } 343 pboxBase = pboxNext; 344 } 345 pboxNew1 -= nbox; 346 pbox = pboxNew1; 347 } 348 } 349 else 350 { 351 /* walk source top to bottom */ 352 upsidedown = FALSE; 353 } 354 355 if (careful && dx < 0) 356 { 357 /* walk source right to left */ 358 if (dy <= 0) 359 reverse = TRUE; 360 else 361 reverse = FALSE; 362 363 if (nbox > 1) 364 { 365 /* reverse order of rects in each band */ 366 pboxNew2 = (BoxPtr)xalloc(sizeof(BoxRec) * nbox); 367 if(!pboxNew2) 368 { 369 if (pboxNew1) 370 xfree(pboxNew1); 371 return; 372 } 373 pboxBase = pboxNext = pbox; 374 while (pboxBase < pbox+nbox) 375 { 376 while ((pboxNext < pbox+nbox) && 377 (pboxNext->y1 == pboxBase->y1)) 378 pboxNext++; 379 pboxTmp = pboxNext; 380 while (pboxTmp != pboxBase) 381 { 382 *pboxNew2++ = *--pboxTmp; 383 } 384 pboxBase = pboxNext; 385 } 386 pboxNew2 -= nbox; 387 pbox = pboxNew2; 388 } 389 } 390 else 391 { 392 /* walk source left to right */ 393 reverse = FALSE; 394 } 395 396 (*copyProc) (pSrcDrawable, 397 pDstDrawable, 398 pGC, 399 pbox, 400 nbox, 401 dx, dy, 402 reverse, upsidedown, bitPlane, closure); 403 404 if (pboxNew1) 405 xfree (pboxNew1); 406 if (pboxNew2) 407 xfree (pboxNew2); 408} 409 410RegionPtr 411fbDoCopy (DrawablePtr pSrcDrawable, 412 DrawablePtr pDstDrawable, 413 GCPtr pGC, 414 int xIn, 415 int yIn, 416 int widthSrc, 417 int heightSrc, 418 int xOut, 419 int yOut, 420 fbCopyProc copyProc, 421 Pixel bitPlane, 422 void *closure) 423{ 424 RegionPtr prgnSrcClip = NULL; /* may be a new region, or just a copy */ 425 Bool freeSrcClip = FALSE; 426 RegionPtr prgnExposed = NULL; 427 RegionRec rgnDst; 428 int dx; 429 int dy; 430 int numRects; 431 int box_x1; 432 int box_y1; 433 int box_x2; 434 int box_y2; 435 Bool fastSrc = FALSE; /* for fast clipping with pixmap source */ 436 Bool fastDst = FALSE; /* for fast clipping with one rect dest */ 437 Bool fastExpose = FALSE; /* for fast exposures with pixmap source */ 438 439 /* Short cut for unmapped windows */ 440 441 if (pDstDrawable->type == DRAWABLE_WINDOW && 442 !((WindowPtr)pDstDrawable)->realized) 443 { 444 return NULL; 445 } 446 447 if ((pSrcDrawable != pDstDrawable) && 448 pSrcDrawable->pScreen->SourceValidate) 449 { 450 (*pSrcDrawable->pScreen->SourceValidate) (pSrcDrawable, xIn, yIn, widthSrc, heightSrc); 451 } 452 453 /* Compute source clip region */ 454 if (pSrcDrawable->type == DRAWABLE_PIXMAP) 455 { 456 if ((pSrcDrawable == pDstDrawable) && (pGC->clientClipType == CT_NONE)) 457 prgnSrcClip = fbGetCompositeClip(pGC); 458 else 459 fastSrc = TRUE; 460 } 461 else 462 { 463 if (pGC->subWindowMode == IncludeInferiors) 464 { 465 /* 466 * XFree86 DDX empties the border clip when the 467 * VT is inactive, make sure the region isn't empty 468 */ 469 if (!((WindowPtr) pSrcDrawable)->parent && 470 REGION_NOTEMPTY (pSrcDrawable->pScreen, 471 &((WindowPtr) pSrcDrawable)->borderClip)) 472 { 473 /* 474 * special case bitblt from root window in 475 * IncludeInferiors mode; just like from a pixmap 476 */ 477 fastSrc = TRUE; 478 } 479 else if ((pSrcDrawable == pDstDrawable) && 480 (pGC->clientClipType == CT_NONE)) 481 { 482 prgnSrcClip = fbGetCompositeClip(pGC); 483 } 484 else 485 { 486 prgnSrcClip = NotClippedByChildren((WindowPtr)pSrcDrawable); 487 freeSrcClip = TRUE; 488 } 489 } 490 else 491 { 492 prgnSrcClip = &((WindowPtr)pSrcDrawable)->clipList; 493 } 494 } 495 496 xIn += pSrcDrawable->x; 497 yIn += pSrcDrawable->y; 498 499 xOut += pDstDrawable->x; 500 yOut += pDstDrawable->y; 501 502 box_x1 = xIn; 503 box_y1 = yIn; 504 box_x2 = xIn + widthSrc; 505 box_y2 = yIn + heightSrc; 506 507 dx = xIn - xOut; 508 dy = yIn - yOut; 509 510 /* Don't create a source region if we are doing a fast clip */ 511 if (fastSrc) 512 { 513 RegionPtr cclip; 514 515 fastExpose = TRUE; 516 /* 517 * clip the source; if regions extend beyond the source size, 518 * make sure exposure events get sent 519 */ 520 if (box_x1 < pSrcDrawable->x) 521 { 522 box_x1 = pSrcDrawable->x; 523 fastExpose = FALSE; 524 } 525 if (box_y1 < pSrcDrawable->y) 526 { 527 box_y1 = pSrcDrawable->y; 528 fastExpose = FALSE; 529 } 530 if (box_x2 > pSrcDrawable->x + (int) pSrcDrawable->width) 531 { 532 box_x2 = pSrcDrawable->x + (int) pSrcDrawable->width; 533 fastExpose = FALSE; 534 } 535 if (box_y2 > pSrcDrawable->y + (int) pSrcDrawable->height) 536 { 537 box_y2 = pSrcDrawable->y + (int) pSrcDrawable->height; 538 fastExpose = FALSE; 539 } 540 541 /* Translate and clip the dst to the destination composite clip */ 542 box_x1 -= dx; 543 box_x2 -= dx; 544 box_y1 -= dy; 545 box_y2 -= dy; 546 547 /* If the destination composite clip is one rectangle we can 548 do the clip directly. Otherwise we have to create a full 549 blown region and call intersect */ 550 551 cclip = fbGetCompositeClip(pGC); 552 if (REGION_NUM_RECTS(cclip) == 1) 553 { 554 BoxPtr pBox = REGION_RECTS(cclip); 555 556 if (box_x1 < pBox->x1) box_x1 = pBox->x1; 557 if (box_x2 > pBox->x2) box_x2 = pBox->x2; 558 if (box_y1 < pBox->y1) box_y1 = pBox->y1; 559 if (box_y2 > pBox->y2) box_y2 = pBox->y2; 560 fastDst = TRUE; 561 } 562 } 563 564 /* Check to see if the region is empty */ 565 if (box_x1 >= box_x2 || box_y1 >= box_y2) 566 { 567 REGION_NULL(pGC->pScreen, &rgnDst); 568 } 569 else 570 { 571 BoxRec box; 572 box.x1 = box_x1; 573 box.y1 = box_y1; 574 box.x2 = box_x2; 575 box.y2 = box_y2; 576 REGION_INIT(pGC->pScreen, &rgnDst, &box, 1); 577 } 578 579 /* Clip against complex source if needed */ 580 if (!fastSrc) 581 { 582 REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, prgnSrcClip); 583 REGION_TRANSLATE(pGC->pScreen, &rgnDst, -dx, -dy); 584 } 585 586 /* Clip against complex dest if needed */ 587 if (!fastDst) 588 { 589 REGION_INTERSECT(pGC->pScreen, &rgnDst, &rgnDst, 590 fbGetCompositeClip(pGC)); 591 } 592 593 /* Do bit blitting */ 594 numRects = REGION_NUM_RECTS(&rgnDst); 595 if (numRects && widthSrc && heightSrc) 596 fbCopyRegion (pSrcDrawable, pDstDrawable, pGC, 597 &rgnDst, dx, dy, copyProc, bitPlane, closure); 598 599 /* Pixmap sources generate a NoExposed (we return NULL to do this) */ 600 if (!fastExpose && pGC->fExpose) 601 prgnExposed = miHandleExposures(pSrcDrawable, pDstDrawable, pGC, 602 xIn - pSrcDrawable->x, 603 yIn - pSrcDrawable->y, 604 widthSrc, heightSrc, 605 xOut - pDstDrawable->x, 606 yOut - pDstDrawable->y, 607 (unsigned long) bitPlane); 608 REGION_UNINIT(pGC->pScreen, &rgnDst); 609 if (freeSrcClip) 610 REGION_DESTROY(pGC->pScreen, prgnSrcClip); 611 fbValidateDrawable (pDstDrawable); 612 return prgnExposed; 613} 614 615RegionPtr 616fbCopyArea (DrawablePtr pSrcDrawable, 617 DrawablePtr pDstDrawable, 618 GCPtr pGC, 619 int xIn, 620 int yIn, 621 int widthSrc, 622 int heightSrc, 623 int xOut, 624 int yOut) 625{ 626 fbCopyProc copy; 627 628#ifdef FB_24_32BIT 629 if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) 630 copy = fb24_32CopyMtoN; 631 else 632#endif 633 copy = fbCopyNtoN; 634 return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn, 635 widthSrc, heightSrc, xOut, yOut, copy, 0, 0); 636} 637 638RegionPtr 639fbCopyPlane (DrawablePtr pSrcDrawable, 640 DrawablePtr pDstDrawable, 641 GCPtr pGC, 642 int xIn, 643 int yIn, 644 int widthSrc, 645 int heightSrc, 646 int xOut, 647 int yOut, 648 unsigned long bitplane) 649{ 650 if (pSrcDrawable->bitsPerPixel > 1) 651 return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, 652 xIn, yIn, widthSrc, heightSrc, 653 xOut, yOut, fbCopyNto1, (Pixel) bitplane, 0); 654 else if (bitplane & 1) 655 return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn, 656 widthSrc, heightSrc, xOut, yOut, fbCopy1toN, 657 (Pixel) bitplane, 0); 658 else 659 return miHandleExposures(pSrcDrawable, pDstDrawable, pGC, 660 xIn, yIn, 661 widthSrc, 662 heightSrc, 663 xOut, yOut, bitplane); 664} 665