1 /* 2 * cfb copy area 3 */ 4 5 /* 6 7 Copyright (c) 1989 X Consortium 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 26 Except as contained in this notice, the name of the X Consortium shall not be 27 used in advertising or otherwise to promote the sale, use or other dealings 28 in this Software without prior written authorization from the X Consortium. 29 30 Author: Keith Packard 31 32 */ 33 /* $XConsortium: cfbblt.c,v 1.13 94/04/17 20:28:44 dpw Exp $ */ 34 /* $XFree86: xc/programs/Xserver/cfb/cfbblt.c,v 3.1 1996/12/09 11:50:52 dawes Exp $ */ 35 36 #include "X.h" 37 #include "Xmd.h" 38 #include "Xproto.h" 39 #include "gcstruct.h" 40 #include "windowstr.h" 41 #include "scrnintstr.h" 42 #include "pixmapstr.h" 43 #include "regionstr.h" 44 #include "cfb.h" 45 #include "cfbmskbits.h" 46 #include "cfb8bit.h" 47 #include "fastblt.h" 48 #include "mergerop.h" 49 50 #ifdef notdef /* XXX fails right now, walks off end of pixmaps */ 51 #if defined (FAST_UNALIGNED_READS) && PSZ == 8 52 #define DO_UNALIGNED_BITBLT 53 #endif 54 #endif 55 56 #if defined(FAST_MEMCPY) && (MROP == Mcopy) && PSZ == 8 57 #define DO_MEMCPY 58 #endif 59 60 void 61 MROP_NAME(cfbDoBitblt)(pSrc, pDst, alu, prgnDst, pptSrc, planemask) 62 DrawablePtr pSrc, pDst; 63 int alu; 64 RegionPtr prgnDst; 65 DDXPointPtr pptSrc; 66 unsigned long planemask; 67 { 68 unsigned long *psrcBase, *pdstBase; 69 /* start of src and dst bitmaps */ 70 int widthSrc, widthDst; /* add to get to same position in next line */ 71 72 BoxPtr pbox; 73 int nbox; 74 75 BoxPtr pboxTmp, pboxNext, pboxBase, pboxNew1, pboxNew2; 76 /* temporaries for shuffling rectangles */ 77 DDXPointPtr pptTmp, pptNew1, pptNew2; 78 /* shuffling boxes entails shuffling the 79 source points too */ 80 int w, h; 81 int xdir; /* 1 = left right, -1 = right left/ */ 82 int ydir; /* 1 = top down, -1 = bottom up */ 83 84 unsigned long *psrcLine, *pdstLine; 85 /* pointers to line with current src and dst */ 86 register unsigned long *psrc;/* pointer to current src longword */ 87 register unsigned long *pdst;/* pointer to current dst longword */ 88 89 MROP_DECLARE_REG() 90 91 /* following used for looping through a line */ 92 unsigned long startmask, endmask; /* masks for writing ends of dst */ 93 int nlMiddle; /* whole longwords in dst */ 94 int xoffSrc, xoffDst; 95 register int leftShift, rightShift; 96 register unsigned long bits; 97 register unsigned long bits1; 98 register int nl; /* temp copy of nlMiddle */ 99 100 /* place to store full source word */ 101 int nstart; /* number of ragged bits at start of dst */ 102 int nend; /* number of ragged bits at end of dst */ 103 int srcStartOver; /* pulling nstart bits from src 104 overflows into the next word? */ 105 int careful; 106 int tmpSrc; 107 #if PSZ == 24 108 #ifdef DO_MEMCPY 109 int w2; 110 #endif 111 #endif 112 113 MROP_INITIALIZE(alu,planemask); 114 115 cfbGetLongWidthAndPointer (pSrc, widthSrc, psrcBase) 116 117 cfbGetLongWidthAndPointer (pDst, widthDst, pdstBase) 118 119 /* XXX we have to err on the side of safety when both are windows, 120 * because we don't know if IncludeInferiors is being used. 121 */ 122 careful = ((pSrc == pDst) || 123 ((pSrc->type == DRAWABLE_WINDOW) && 124 (pDst->type == DRAWABLE_WINDOW))); 125 126 pbox = REGION_RECTS(prgnDst); 127 nbox = REGION_NUM_RECTS(prgnDst); 128 129 pboxNew1 = NULL; 130 pptNew1 = NULL; 131 pboxNew2 = NULL; 132 pptNew2 = NULL; 133 if (careful && (pptSrc->y < pbox->y1)) 134 { 135 /* walk source botttom to top */ 136 ydir = -1; 137 widthSrc = -widthSrc; 138 widthDst = -widthDst; 139 140 if (nbox > 1) 141 { 142 /* keep ordering in each band, reverse order of bands */ 143 pboxNew1 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); 144 if(!pboxNew1) 145 return; 146 pptNew1 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); 147 if(!pptNew1) 148 { 149 DEALLOCATE_LOCAL(pboxNew1); 150 return; 151 } 152 pboxBase = pboxNext = pbox+nbox-1; 153 while (pboxBase >= pbox) 154 { 155 while ((pboxNext >= pbox) && 156 (pboxBase->y1 == pboxNext->y1)) 157 pboxNext--; 158 pboxTmp = pboxNext+1; 159 pptTmp = pptSrc + (pboxTmp - pbox); 160 while (pboxTmp <= pboxBase) 161 { 162 *pboxNew1++ = *pboxTmp++; 163 *pptNew1++ = *pptTmp++; 164 } 165 pboxBase = pboxNext; 166 } 167 pboxNew1 -= nbox; 168 pbox = pboxNew1; 169 pptNew1 -= nbox; 170 pptSrc = pptNew1; 171 } 172 } 173 else 174 { 175 /* walk source top to bottom */ 176 ydir = 1; 177 } 178 179 if (careful && (pptSrc->x < pbox->x1)) 180 { 181 /* walk source right to left */ 182 xdir = -1; 183 184 if (nbox > 1) 185 { 186 /* reverse order of rects in each band */ 187 pboxNew2 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); 188 pptNew2 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); 189 if(!pboxNew2 || !pptNew2) 190 { 191 if (pptNew2) DEALLOCATE_LOCAL(pptNew2); 192 if (pboxNew2) DEALLOCATE_LOCAL(pboxNew2); 193 if (pboxNew1) 194 { 195 DEALLOCATE_LOCAL(pptNew1); 196 DEALLOCATE_LOCAL(pboxNew1); 197 } 198 return; 199 } 200 pboxBase = pboxNext = pbox; 201 while (pboxBase < pbox+nbox) 202 { 203 while ((pboxNext < pbox+nbox) && 204 (pboxNext->y1 == pboxBase->y1)) 205 pboxNext++; 206 pboxTmp = pboxNext; 207 pptTmp = pptSrc + (pboxTmp - pbox); 208 while (pboxTmp != pboxBase) 209 { 210 *pboxNew2++ = *--pboxTmp; 211 *pptNew2++ = *--pptTmp; 212 } 213 pboxBase = pboxNext; 214 } 215 pboxNew2 -= nbox; 216 pbox = pboxNew2; 217 pptNew2 -= nbox; 218 pptSrc = pptNew2; 219 } 220 } 221 else 222 { 223 /* walk source left to right */ 224 xdir = 1; 225 } 226 227 while(nbox--) 228 { 229 w = pbox->x2 - pbox->x1; 230 h = pbox->y2 - pbox->y1; 231 232 #if PSZ == 24 233 #ifdef DO_MEMCPY 234 w2 = w * 3; 235 #endif 236 #endif 237 if (ydir == -1) /* start at last scanline of rectangle */ 238 { 239 psrcLine = psrcBase + ((pptSrc->y+h-1) * -widthSrc); 240 pdstLine = pdstBase + ((pbox->y2-1) * -widthDst); 241 } 242 else /* start at first scanline */ 243 { 244 psrcLine = psrcBase + (pptSrc->y * widthSrc); 245 pdstLine = pdstBase + (pbox->y1 * widthDst); 246 } 247 #if PSZ == 24 248 if (w == 1 && ((pbox->x1 & 3) == 0 || (pbox->x1 & 3) == 3)) 249 #else 250 if ((pbox->x1 & PIM) + w <= PPW) 251 #endif 252 { 253 maskpartialbits (pbox->x1, w, endmask); 254 startmask = 0; 255 nlMiddle = 0; 256 } 257 else 258 { 259 maskbits(pbox->x1, w, startmask, endmask, nlMiddle); 260 } 261 262 #ifdef DO_MEMCPY 263 /* If the src and dst scanline don't overlap, do forward case. */ 264 265 if ((xdir == 1) || (pptSrc->y != pbox->y1) 266 || (pptSrc->x + w <= pbox->x1)) 267 { 268 #if PSZ == 24 269 char *psrc = (char *) psrcLine + (pptSrc->x * 3); 270 char *pdst = (char *) pdstLine + (pbox->x1 * 3); 271 #else 272 char *psrc = (char *) psrcLine + pptSrc->x; 273 char *pdst = (char *) pdstLine + pbox->x1; 274 #endif 275 while (h--) 276 { 277 #if PSZ == 24 278 memcpy(pdst, psrc, w2); 279 #else 280 memcpy(pdst, psrc, w); 281 #endif 282 pdst += widthDst << PWSH; 283 psrc += widthSrc << PWSH; 284 } 285 } 286 #else /* ! DO_MEMCPY */ 287 if (xdir == 1) 288 { 289 #if PSZ == 24 290 xoffSrc = (4 - pptSrc->x) & 3; 291 xoffDst = (4 - pbox->x1) & 3; 292 pdstLine += (pbox->x1 * 3) >> 2; 293 psrcLine += (pptSrc->x * 3) >> 2; 294 #else 295 xoffSrc = pptSrc->x & PIM; 296 xoffDst = pbox->x1 & PIM; 297 pdstLine += (pbox->x1 >> PWSH); 298 psrcLine += (pptSrc->x >> PWSH); 299 #endif 300 #ifdef DO_UNALIGNED_BITBLT 301 nl = xoffSrc - xoffDst; 302 psrcLine = (unsigned long *) 303 (((unsigned char *) psrcLine) + nl); 304 #else 305 if (xoffSrc == xoffDst) 306 #endif 307 { 308 while (h--) 309 { 310 psrc = psrcLine; 311 pdst = pdstLine; 312 pdstLine += widthDst; 313 psrcLine += widthSrc; 314 if (startmask) 315 { 316 *pdst = MROP_MASK(*psrc, *pdst, startmask); 317 psrc++; 318 pdst++; 319 } 320 nl = nlMiddle; 321 322 #ifdef LARGE_INSTRUCTION_CACHE 323 #ifdef FAST_CONSTANT_OFFSET_MODE 324 325 psrc += nl & (UNROLL-1); 326 pdst += nl & (UNROLL-1); 327 328 #define BodyOdd(n) pdst[-n] = MROP_SOLID (psrc[-n], pdst[-n]); 329 #define BodyEven(n) pdst[-n] = MROP_SOLID (psrc[-n], pdst[-n]); 330 331 #define LoopReset \ 332 pdst += UNROLL; \ 333 psrc += UNROLL; 334 335 #else 336 337 #define BodyOdd(n) *pdst = MROP_SOLID (*psrc, *pdst); pdst++; psrc++; 338 #define BodyEven(n) BodyOdd(n) 339 340 #define LoopReset ; 341 342 #endif 343 PackedLoop 344 345 #undef BodyOdd 346 #undef BodyEven 347 #undef LoopReset 348 349 #else 350 #ifdef NOTDEF 351 /* you'd think this would be faster -- 352 * a single instruction instead of 6 353 * but measurements show it to be ~15% slower 354 */ 355 while ((nl -= 6) >= 0) 356 { 357 asm ("moveml %1+,#0x0c0f;moveml#0x0c0f,%0" 358 : "=m" (*(char *)pdst) 359 : "m" (*(char *)psrc) 360 : "d0", "d1", "d2", "d3", 361 "a2", "a3"); 362 pdst += 6; 363 } 364 nl += 6; 365 while (nl--) 366 *pdst++ = *psrc++; 367 #endif 368 DuffL(nl, label1, 369 *pdst = MROP_SOLID (*psrc, *pdst); 370 pdst++; psrc++;) 371 #endif 372 373 if (endmask) 374 *pdst = MROP_MASK(*psrc, *pdst, endmask); 375 } 376 } 377 #ifndef DO_UNALIGNED_BITBLT 378 else 379 { 380 if (xoffSrc > xoffDst) 381 { 382 #if PSZ == 24 383 leftShift = (xoffSrc - xoffDst) << 3; 384 #else 385 #if PGSZ == 32 386 leftShift = (xoffSrc - xoffDst) << (5 - PWSH); 387 #else /* PGSZ == 64 */ 388 leftShift = (xoffSrc - xoffDst) << (6 - PWSH); 389 #endif /* PGSZ */ 390 #endif 391 rightShift = PGSZ - leftShift; 392 } 393 else 394 { 395 #if PSZ == 24 396 rightShift = (xoffDst - xoffSrc) << 3; 397 #else 398 #if PGSZ == 32 399 rightShift = (xoffDst - xoffSrc) << (5 - PWSH); 400 #else /* PGSZ == 64 */ 401 rightShift = (xoffDst - xoffSrc) << (6 - PWSH); 402 #endif /* PGSZ */ 403 #endif 404 leftShift = PGSZ - rightShift; 405 } 406 while (h--) 407 { 408 psrc = psrcLine; 409 pdst = pdstLine; 410 pdstLine += widthDst; 411 psrcLine += widthSrc; 412 bits = 0; 413 if (xoffSrc > xoffDst) 414 bits = *psrc++; 415 if (startmask) 416 { 417 bits1 = BitLeft(bits,leftShift); 418 bits = *psrc++; 419 bits1 |= BitRight(bits,rightShift); 420 *pdst = MROP_MASK(bits1, *pdst, startmask); 421 pdst++; 422 } 423 nl = nlMiddle; 424 425 #ifdef LARGE_INSTRUCTION_CACHE 426 bits1 = bits; 427 428 #ifdef FAST_CONSTANT_OFFSET_MODE 429 430 psrc += nl & (UNROLL-1); 431 pdst += nl & (UNROLL-1); 432 433 #define BodyOdd(n) \ 434 bits = psrc[-n]; \ 435 pdst[-n] = MROP_SOLID(BitLeft(bits1, leftShift) | BitRight(bits, rightShift), pdst[-n]); 436 437 #define BodyEven(n) \ 438 bits1 = psrc[-n]; \ 439 pdst[-n] = MROP_SOLID(BitLeft(bits, leftShift) | BitRight(bits1, rightShift), pdst[-n]); 440 441 #define LoopReset \ 442 pdst += UNROLL; \ 443 psrc += UNROLL; 444 445 #else 446 447 #define BodyOdd(n) \ 448 bits = *psrc++; \ 449 *pdst = MROP_SOLID(BitLeft(bits1, leftShift) | BitRight(bits, rightShift), *pdst); \ 450 pdst++; 451 452 #define BodyEven(n) \ 453 bits1 = *psrc++; \ 454 *pdst = MROP_SOLID(BitLeft(bits, leftShift) | BitRight(bits1, rightShift), *pdst); \ 455 pdst++; 456 457 #define LoopReset ; 458 459 #endif /* !FAST_CONSTANT_OFFSET_MODE */ 460 461 PackedLoop 462 463 #undef BodyOdd 464 #undef BodyEven 465 #undef LoopReset 466 467 #else 468 DuffL (nl,label2, 469 bits1 = BitLeft(bits, leftShift); 470 bits = *psrc++; 471 *pdst = MROP_SOLID (bits1 | BitRight(bits, rightShift), *pdst); 472 pdst++; 473 ) 474 #endif 475 476 if (endmask) 477 { 478 bits1 = BitLeft(bits, leftShift); 479 if (BitLeft(endmask, rightShift)) 480 { 481 bits = *psrc; 482 bits1 |= BitRight(bits, rightShift); 483 } 484 *pdst = MROP_MASK (bits1, *pdst, endmask); 485 } 486 } 487 } 488 #endif /* DO_UNALIGNED_BITBLT */ 489 } 490 #endif /* ! DO_MEMCPY */ 491 else /* xdir == -1 */ 492 { 493 #if PSZ == 24 494 xoffSrc = (pptSrc->x + w) & 3; 495 xoffDst = pbox->x2 & 3; 496 pdstLine += ((pbox->x2 * 3 - 1) >> 2) + 1; 497 psrcLine += (((pptSrc->x+w) * 3 - 1) >> 2) + 1; 498 #else 499 xoffSrc = (pptSrc->x + w - 1) & PIM; 500 xoffDst = (pbox->x2 - 1) & PIM; 501 pdstLine += ((pbox->x2-1) >> PWSH) + 1; 502 psrcLine += ((pptSrc->x+w - 1) >> PWSH) + 1; 503 #endif 504 #ifdef DO_UNALIGNED_BITBLT 505 #if PSZ == 24 506 nl = xoffDst - xoffSrc; 507 #else 508 nl = xoffSrc - xoffDst; 509 #endif 510 psrcLine = (unsigned long *) 511 (((unsigned char *) psrcLine) + nl); 512 #else 513 if (xoffSrc == xoffDst) 514 #endif 515 { 516 while (h--) 517 { 518 psrc = psrcLine; 519 pdst = pdstLine; 520 pdstLine += widthDst; 521 psrcLine += widthSrc; 522 if (endmask) 523 { 524 pdst--; 525 psrc--; 526 *pdst = MROP_MASK (*psrc, *pdst, endmask); 527 } 528 nl = nlMiddle; 529 530 #ifdef LARGE_INSTRUCTION_CACHE 531 #ifdef FAST_CONSTANT_OFFSET_MODE 532 psrc -= nl & (UNROLL - 1); 533 pdst -= nl & (UNROLL - 1); 534 535 #define BodyOdd(n) pdst[n-1] = MROP_SOLID (psrc[n-1], pdst[n-1]); 536 537 #define BodyEven(n) BodyOdd(n) 538 539 #define LoopReset \ 540 pdst -= UNROLL;\ 541 psrc -= UNROLL; 542 543 #else 544 545 #define BodyOdd(n) --pdst; --psrc; *pdst = MROP_SOLID(*psrc, *pdst); 546 #define BodyEven(n) BodyOdd(n) 547 #define LoopReset ; 548 549 #endif 550 PackedLoop 551 552 #undef BodyOdd 553 #undef BodyEven 554 #undef LoopReset 555 556 #else 557 DuffL(nl,label3, 558 --pdst; --psrc; *pdst = MROP_SOLID (*psrc, *pdst);) 559 #endif 560 561 if (startmask) 562 { 563 --pdst; 564 --psrc; 565 *pdst = MROP_MASK(*psrc, *pdst, startmask); 566 } 567 } 568 } 569 #ifndef DO_UNALIGNED_BITBLT 570 else 571 { 572 if (xoffDst > xoffSrc) 573 { 574 #if PSZ == 24 575 leftShift = (xoffDst - xoffSrc) << 3; 576 rightShift = PGSZ - leftShift; 577 #else 578 #if PGSZ == 32 579 rightShift = (xoffDst - xoffSrc) << (5 - PWSH); 580 #else /* PGSZ == 64 */ 581 rightShift = (xoffDst - xoffSrc) << (6 - PWSH); 582 #endif /* PGSZ */ 583 leftShift = PGSZ - rightShift; 584 #endif 585 } 586 else 587 { 588 #if PSZ == 24 589 rightShift = (xoffSrc - xoffDst) << 3; 590 leftShift = PGSZ - rightShift; 591 #else 592 #if PGSZ == 32 593 leftShift = (xoffSrc - xoffDst) << (5 - PWSH); 594 #else /* PGSZ == 64 */ 595 leftShift = (xoffSrc - xoffDst) << (6 - PWSH); 596 #endif /* PGSZ */ 597 rightShift = PGSZ - leftShift; 598 #endif 599 } 600 while (h--) 601 { 602 psrc = psrcLine; 603 pdst = pdstLine; 604 pdstLine += widthDst; 605 psrcLine += widthSrc; 606 bits = 0; 607 #if PSZ == 24 608 if (xoffSrc > xoffDst) 609 #else 610 if (xoffDst > xoffSrc) 611 #endif 612 bits = *--psrc; 613 if (endmask) 614 { 615 bits1 = BitRight(bits, rightShift); 616 bits = *--psrc; 617 bits1 |= BitLeft(bits, leftShift); 618 pdst--; 619 *pdst = MROP_MASK(bits1, *pdst, endmask); 620 } 621 nl = nlMiddle; 622 623 #ifdef LARGE_INSTRUCTION_CACHE 624 bits1 = bits; 625 #ifdef FAST_CONSTANT_OFFSET_MODE 626 psrc -= nl & (UNROLL - 1); 627 pdst -= nl & (UNROLL - 1); 628 629 #define BodyOdd(n) \ 630 bits = psrc[n-1]; \ 631 pdst[n-1] = MROP_SOLID(BitRight(bits1, rightShift) | BitLeft(bits, leftShift),pdst[n-1]); 632 633 #define BodyEven(n) \ 634 bits1 = psrc[n-1]; \ 635 pdst[n-1] = MROP_SOLID(BitRight(bits, rightShift) | BitLeft(bits1, leftShift),pdst[n-1]); 636 637 #define LoopReset \ 638 pdst -= UNROLL; \ 639 psrc -= UNROLL; 640 641 #else 642 643 #define BodyOdd(n) \ 644 bits = *--psrc; --pdst; \ 645 *pdst = MROP_SOLID(BitRight(bits1, rightShift) | BitLeft(bits, leftShift),*pdst); 646 647 #define BodyEven(n) \ 648 bits1 = *--psrc; --pdst; \ 649 *pdst = MROP_SOLID(BitRight(bits, rightShift) | BitLeft(bits1, leftShift),*pdst); 650 651 #define LoopReset ; 652 653 #endif 654 655 PackedLoop 656 657 #undef BodyOdd 658 #undef BodyEven 659 #undef LoopReset 660 661 #else 662 DuffL (nl, label4, 663 bits1 = BitRight(bits, rightShift); 664 bits = *--psrc; 665 --pdst; 666 *pdst = MROP_SOLID(bits1 | BitLeft(bits, leftShift),*pdst); 667 ) 668 #endif 669 670 if (startmask) 671 { 672 bits1 = BitRight(bits, rightShift); 673 if (BitRight (startmask, leftShift)) 674 { 675 bits = *--psrc; 676 bits1 |= BitLeft(bits, leftShift); 677 } 678 --pdst; 679 *pdst = MROP_MASK(bits1, *pdst, startmask); 680 } 681 } 682 } 683 #endif 684 } 685 pbox++; 686 pptSrc++; 687 } 688 if (pboxNew2) 689 { 690 DEALLOCATE_LOCAL(pptNew2); 691 DEALLOCATE_LOCAL(pboxNew2); 692 } 693 if (pboxNew1) 694 { 695 DEALLOCATE_LOCAL(pptNew1); 696 DEALLOCATE_LOCAL(pboxNew1); 697 } 698 } 699