103b705cfSriastradh/* 203b705cfSriastradh * Copyright © 1998 Keith Packard 303b705cfSriastradh * Copyright © 2012 Intel Corporation 403b705cfSriastradh * 503b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its 603b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that 703b705cfSriastradh * the above copyright notice appear in all copies and that both that 803b705cfSriastradh * copyright notice and this permission notice appear in supporting 903b705cfSriastradh * documentation, and that the name of Keith Packard not be used in 1003b705cfSriastradh * advertising or publicity pertaining to distribution of the software without 1103b705cfSriastradh * specific, written prior permission. Keith Packard makes no 1203b705cfSriastradh * representations about the suitability of this software for any purpose. It 1303b705cfSriastradh * is provided "as is" without express or implied warranty. 1403b705cfSriastradh * 1503b705cfSriastradh * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1603b705cfSriastradh * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1703b705cfSriastradh * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1803b705cfSriastradh * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1903b705cfSriastradh * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2003b705cfSriastradh * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2103b705cfSriastradh * PERFORMANCE OF THIS SOFTWARE. 2203b705cfSriastradh */ 2303b705cfSriastradh 2403b705cfSriastradh#include "fb.h" 2503b705cfSriastradh 2603b705cfSriastradh#ifdef __clang__ 2703b705cfSriastradh/* shift overflow is intentional */ 2803b705cfSriastradh#pragma clang diagnostic ignored "-Wshift-overflow" 2903b705cfSriastradh#endif 3003b705cfSriastradh 3103b705cfSriastradh/* 3203b705cfSriastradh * Example: srcX = 13 dstX = 8 (FB unit 32 dstBpp 8) 3303b705cfSriastradh * 3403b705cfSriastradh * **** **** **** **** **** **** **** **** 3503b705cfSriastradh * ^ 3603b705cfSriastradh * ******** ******** ******** ******** 3703b705cfSriastradh * ^ 3803b705cfSriastradh * leftShift = 12 3903b705cfSriastradh * rightShift = 20 4003b705cfSriastradh * 4103b705cfSriastradh * Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8) 4203b705cfSriastradh * 4303b705cfSriastradh * **** **** **** **** **** **** **** **** 4403b705cfSriastradh * ^ 4503b705cfSriastradh * ******** ******** ******** ******** 4603b705cfSriastradh * ^ 4703b705cfSriastradh * 4803b705cfSriastradh * leftShift = 24 4903b705cfSriastradh * rightShift = 8 5003b705cfSriastradh */ 5103b705cfSriastradh 5203b705cfSriastradh#define LoadBits {\ 5303b705cfSriastradh if (leftShift) { \ 5403b705cfSriastradh bitsRight = (src < srcEnd ? READ(src++) : 0); \ 5503b705cfSriastradh bits = (FbStipLeft (bitsLeft, leftShift) | \ 5603b705cfSriastradh FbStipRight(bitsRight, rightShift)); \ 5703b705cfSriastradh bitsLeft = bitsRight; \ 5803b705cfSriastradh } else \ 5903b705cfSriastradh bits = (src < srcEnd ? READ(src++) : 0); \ 6003b705cfSriastradh} 6103b705cfSriastradh 6203b705cfSriastradh#define LaneCases1(n,a) case n: FbLaneCase(n,a); break 6303b705cfSriastradh#define LaneCases2(n,a) LaneCases1(n,a); LaneCases1(n+1,a) 6403b705cfSriastradh#define LaneCases4(n,a) LaneCases2(n,a); LaneCases2(n+2,a) 6503b705cfSriastradh#define LaneCases8(n,a) LaneCases4(n,a); LaneCases4(n+4,a) 6603b705cfSriastradh#define LaneCases16(n,a) LaneCases8(n,a); LaneCases8(n+8,a) 6703b705cfSriastradh#define LaneCases32(n,a) LaneCases16(n,a); LaneCases16(n+16,a) 6803b705cfSriastradh#define LaneCases64(n,a) LaneCases32(n,a); LaneCases32(n+32,a) 6903b705cfSriastradh#define LaneCases128(n,a) LaneCases64(n,a); LaneCases64(n+64,a) 7003b705cfSriastradh#define LaneCases256(n,a) LaneCases128(n,a); LaneCases128(n+128,a) 7103b705cfSriastradh 7203b705cfSriastradh#define LaneCases(a) LaneCases16(0,a) 7303b705cfSriastradh 7403b705cfSriastradhstatic const CARD8 fb8Lane[16] = { 7503b705cfSriastradh 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 7603b705cfSriastradh}; 7703b705cfSriastradh 7803b705cfSriastradhstatic const CARD8 fb16Lane[16] = { 7903b705cfSriastradh 0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8003b705cfSriastradh}; 8103b705cfSriastradh 8203b705cfSriastradhstatic const CARD8 fb32Lane[16] = { 8303b705cfSriastradh 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8403b705cfSriastradh}; 8503b705cfSriastradh 8603b705cfSriastradhstatic const CARD8 * const fbLaneTable[33] = { 8703b705cfSriastradh 0, 0, 0, 0, 0, 0, 0, 0, 8803b705cfSriastradh fb8Lane, 0, 0, 0, 0, 0, 0, 0, 8903b705cfSriastradh fb16Lane, 0, 0, 0, 0, 0, 0, 0, 9003b705cfSriastradh 0, 0, 0, 0, 0, 0, 0, 0, 9103b705cfSriastradh fb32Lane 9203b705cfSriastradh}; 9303b705cfSriastradh 9403b705cfSriastradhvoid 9503b705cfSriastradhfbBltOne(FbStip * src, FbStride srcStride, /* FbStip units per scanline */ 9603b705cfSriastradh int srcX, /* bit position of source */ 9703b705cfSriastradh FbBits * dst, FbStride dstStride, /* FbBits units per scanline */ 9803b705cfSriastradh int dstX, /* bit position of dest */ 9903b705cfSriastradh int dstBpp, /* bits per destination unit */ 10003b705cfSriastradh int width, /* width in bits of destination */ 10103b705cfSriastradh int height, /* height in scanlines */ 10203b705cfSriastradh FbBits fgand, /* rrop values */ 10303b705cfSriastradh FbBits fgxor, FbBits bgand, FbBits bgxor) 10403b705cfSriastradh{ 10503b705cfSriastradh const FbBits *fbBits; 10603b705cfSriastradh FbBits *srcEnd; 10703b705cfSriastradh int pixelsPerDst; /* dst pixels per FbBits */ 10803b705cfSriastradh int unitsPerSrc; /* src patterns per FbStip */ 10903b705cfSriastradh int leftShift, rightShift; /* align source with dest */ 11003b705cfSriastradh FbBits startmask, endmask; /* dest scanline masks */ 11103b705cfSriastradh FbStip bits = 0, bitsLeft, bitsRight; /* source bits */ 11203b705cfSriastradh FbStip left; 11303b705cfSriastradh FbBits mask; 11403b705cfSriastradh int nDst; /* dest longwords (w.o. end) */ 11503b705cfSriastradh int w; 11603b705cfSriastradh int n, nmiddle; 11703b705cfSriastradh int dstS; /* stipple-relative dst X coordinate */ 11803b705cfSriastradh Bool copy; /* accelerate dest-invariant */ 11903b705cfSriastradh Bool transparent; /* accelerate 0 nop */ 12003b705cfSriastradh int srcinc; /* source units consumed */ 12103b705cfSriastradh Bool endNeedsLoad = FALSE; /* need load for endmask */ 12203b705cfSriastradh const CARD8 *fbLane; 12303b705cfSriastradh int startbyte, endbyte; 12403b705cfSriastradh 12503b705cfSriastradh /* 12603b705cfSriastradh * Do not read past the end of the buffer! 12703b705cfSriastradh */ 12803b705cfSriastradh srcEnd = src + height * srcStride; 12903b705cfSriastradh 13003b705cfSriastradh /* 13103b705cfSriastradh * Number of destination units in FbBits == number of stipple pixels 13203b705cfSriastradh * used each time 13303b705cfSriastradh */ 13403b705cfSriastradh pixelsPerDst = FB_UNIT / dstBpp; 13503b705cfSriastradh 13603b705cfSriastradh /* 13703b705cfSriastradh * Number of source stipple patterns in FbStip 13803b705cfSriastradh */ 13903b705cfSriastradh unitsPerSrc = FB_STIP_UNIT / pixelsPerDst; 14003b705cfSriastradh 14103b705cfSriastradh copy = FALSE; 14203b705cfSriastradh transparent = FALSE; 14303b705cfSriastradh if (bgand == 0 && fgand == 0) 14403b705cfSriastradh copy = TRUE; 14503b705cfSriastradh else if (bgand == FB_ALLONES && bgxor == 0) 14603b705cfSriastradh transparent = TRUE; 14703b705cfSriastradh 14803b705cfSriastradh /* 14903b705cfSriastradh * Adjust source and dest to nearest FbBits boundary 15003b705cfSriastradh */ 15103b705cfSriastradh src += srcX >> FB_STIP_SHIFT; 15203b705cfSriastradh dst += dstX >> FB_SHIFT; 15303b705cfSriastradh srcX &= FB_STIP_MASK; 15403b705cfSriastradh dstX &= FB_MASK; 15503b705cfSriastradh 15603b705cfSriastradh FbMaskBitsBytes(dstX, width, copy, 15703b705cfSriastradh startmask, startbyte, nmiddle, endmask, endbyte); 15803b705cfSriastradh 15903b705cfSriastradh /* 16003b705cfSriastradh * Compute effective dest alignment requirement for 16103b705cfSriastradh * source -- must align source to dest unit boundary 16203b705cfSriastradh */ 16303b705cfSriastradh dstS = dstX / dstBpp; 16403b705cfSriastradh /* 16503b705cfSriastradh * Compute shift constants for effective alignement 16603b705cfSriastradh */ 16703b705cfSriastradh if (srcX >= dstS) { 16803b705cfSriastradh leftShift = srcX - dstS; 16903b705cfSriastradh rightShift = FB_STIP_UNIT - leftShift; 17003b705cfSriastradh } else { 17103b705cfSriastradh rightShift = dstS - srcX; 17203b705cfSriastradh leftShift = FB_STIP_UNIT - rightShift; 17303b705cfSriastradh } 17403b705cfSriastradh /* 17503b705cfSriastradh * Get pointer to stipple mask array for this depth 17603b705cfSriastradh */ 17703b705cfSriastradh fbBits = 0; /* unused */ 17803b705cfSriastradh if (pixelsPerDst <= 8) 17903b705cfSriastradh fbBits = fbStippleTable[pixelsPerDst]; 18003b705cfSriastradh fbLane = 0; 18103b705cfSriastradh if (transparent && fgand == 0 && dstBpp >= 8) 18203b705cfSriastradh fbLane = fbLaneTable[dstBpp]; 18303b705cfSriastradh 18403b705cfSriastradh /* 18503b705cfSriastradh * Compute total number of destination words written, but 18603b705cfSriastradh * don't count endmask 18703b705cfSriastradh */ 18803b705cfSriastradh nDst = nmiddle; 18903b705cfSriastradh if (startmask) 19003b705cfSriastradh nDst++; 19103b705cfSriastradh 19203b705cfSriastradh dstStride -= nDst; 19303b705cfSriastradh 19403b705cfSriastradh /* 19503b705cfSriastradh * Compute total number of source words consumed 19603b705cfSriastradh */ 19703b705cfSriastradh 19803b705cfSriastradh srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc; 19903b705cfSriastradh 20003b705cfSriastradh if (srcX > dstS) 20103b705cfSriastradh srcinc++; 20203b705cfSriastradh if (endmask) { 20303b705cfSriastradh endNeedsLoad = nDst % unitsPerSrc == 0; 20403b705cfSriastradh if (endNeedsLoad) 20503b705cfSriastradh srcinc++; 20603b705cfSriastradh } 20703b705cfSriastradh 20803b705cfSriastradh srcStride -= srcinc; 20903b705cfSriastradh 21003b705cfSriastradh /* 21103b705cfSriastradh * Copy rectangle 21203b705cfSriastradh */ 21303b705cfSriastradh while (height--) { 21403b705cfSriastradh w = nDst; /* total units across scanline */ 21503b705cfSriastradh n = unitsPerSrc; /* units avail in single stipple */ 21603b705cfSriastradh if (n > w) 21703b705cfSriastradh n = w; 21803b705cfSriastradh 21903b705cfSriastradh bitsLeft = 0; 22003b705cfSriastradh if (srcX > dstS) 22103b705cfSriastradh bitsLeft = READ(src++); 22203b705cfSriastradh if (n) { 22303b705cfSriastradh /* 22403b705cfSriastradh * Load first set of stipple bits 22503b705cfSriastradh */ 22603b705cfSriastradh LoadBits; 22703b705cfSriastradh 22803b705cfSriastradh /* 22903b705cfSriastradh * Consume stipple bits for startmask 23003b705cfSriastradh */ 23103b705cfSriastradh if (startmask) { 23203b705cfSriastradh mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 23303b705cfSriastradh if (fbLane) { 23403b705cfSriastradh fbTransparentSpan(dst, mask & startmask, fgxor, 1); 23503b705cfSriastradh } else { 23603b705cfSriastradh if (mask || !transparent) 23703b705cfSriastradh FbDoLeftMaskByteStippleRRop(dst, mask, 23803b705cfSriastradh fgand, fgxor, bgand, bgxor, 23903b705cfSriastradh startbyte, startmask); 24003b705cfSriastradh } 24103b705cfSriastradh bits = FbStipLeft(bits, pixelsPerDst); 24203b705cfSriastradh dst++; 24303b705cfSriastradh n--; 24403b705cfSriastradh w--; 24503b705cfSriastradh } 24603b705cfSriastradh /* 24703b705cfSriastradh * Consume stipple bits across scanline 24803b705cfSriastradh */ 24903b705cfSriastradh for (;;) { 25003b705cfSriastradh w -= n; 25103b705cfSriastradh if (copy) { 25203b705cfSriastradh while (n--) { 25303b705cfSriastradh#if FB_UNIT > 32 25403b705cfSriastradh if (pixelsPerDst == 16) 25503b705cfSriastradh mask = FbStipple16Bits(FbLeftStipBits(bits, 16)); 25603b705cfSriastradh else 25703b705cfSriastradh#endif 25803b705cfSriastradh mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 25903b705cfSriastradh WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor)); 26003b705cfSriastradh dst++; 26103b705cfSriastradh bits = FbStipLeft(bits, pixelsPerDst); 26203b705cfSriastradh } 26303b705cfSriastradh } 26403b705cfSriastradh else { 26503b705cfSriastradh if (fbLane) { 26603b705cfSriastradh while (bits && n) { 26703b705cfSriastradh switch (fbLane[FbLeftStipBits(bits, pixelsPerDst)]) { 26803b705cfSriastradh LaneCases((CARD8 *) dst); 26903b705cfSriastradh } 27003b705cfSriastradh bits = FbStipLeft(bits, pixelsPerDst); 27103b705cfSriastradh dst++; 27203b705cfSriastradh n--; 27303b705cfSriastradh } 27403b705cfSriastradh dst += n; 27503b705cfSriastradh } else { 27603b705cfSriastradh while (n--) { 27703b705cfSriastradh left = FbLeftStipBits(bits, pixelsPerDst); 27803b705cfSriastradh if (left || !transparent) { 27903b705cfSriastradh mask = fbBits[left]; 28003b705cfSriastradh WRITE(dst, FbStippleRRop(READ(dst), mask, 28103b705cfSriastradh fgand, fgxor, bgand, 28203b705cfSriastradh bgxor)); 28303b705cfSriastradh } 28403b705cfSriastradh dst++; 28503b705cfSriastradh bits = FbStipLeft(bits, pixelsPerDst); 28603b705cfSriastradh } 28703b705cfSriastradh } 28803b705cfSriastradh } 28903b705cfSriastradh if (!w) 29003b705cfSriastradh break; 29103b705cfSriastradh /* 29203b705cfSriastradh * Load another set and reset number of available units 29303b705cfSriastradh */ 29403b705cfSriastradh LoadBits; 29503b705cfSriastradh n = unitsPerSrc; 29603b705cfSriastradh if (n > w) 29703b705cfSriastradh n = w; 29803b705cfSriastradh } 29903b705cfSriastradh } 30003b705cfSriastradh /* 30103b705cfSriastradh * Consume stipple bits for endmask 30203b705cfSriastradh */ 30303b705cfSriastradh if (endmask) { 30403b705cfSriastradh if (endNeedsLoad) { 30503b705cfSriastradh LoadBits; 30603b705cfSriastradh } 30703b705cfSriastradh mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)]; 30803b705cfSriastradh if (fbLane) { 30903b705cfSriastradh fbTransparentSpan(dst, mask & endmask, fgxor, 1); 31003b705cfSriastradh } else { 31103b705cfSriastradh if (mask || !transparent) 31203b705cfSriastradh FbDoRightMaskByteStippleRRop(dst, mask, 31303b705cfSriastradh fgand, fgxor, bgand, bgxor, 31403b705cfSriastradh endbyte, endmask); 31503b705cfSriastradh } 31603b705cfSriastradh } 31703b705cfSriastradh dst += dstStride; 31803b705cfSriastradh src += srcStride; 31903b705cfSriastradh } 32003b705cfSriastradh} 32103b705cfSriastradh 32203b705cfSriastradh/* 32303b705cfSriastradh * Not very efficient, but simple -- copy a single plane 32403b705cfSriastradh * from an N bit image to a 1 bit image 32503b705cfSriastradh */ 32603b705cfSriastradh 32703b705cfSriastradhvoid 32803b705cfSriastradhfbBltPlane(FbBits * src, 32903b705cfSriastradh FbStride srcStride, 33003b705cfSriastradh int srcX, 33103b705cfSriastradh int srcBpp, 33203b705cfSriastradh FbStip * dst, 33303b705cfSriastradh FbStride dstStride, 33403b705cfSriastradh int dstX, 33503b705cfSriastradh int width, 33603b705cfSriastradh int height, 33703b705cfSriastradh FbStip fgand, 33803b705cfSriastradh FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask) 33903b705cfSriastradh{ 34003b705cfSriastradh FbBits *s; 34103b705cfSriastradh FbBits pm; 34203b705cfSriastradh FbBits srcMask; 34303b705cfSriastradh FbBits srcMaskFirst; 34403b705cfSriastradh FbBits srcMask0 = 0; 34503b705cfSriastradh FbBits srcBits; 34603b705cfSriastradh 34703b705cfSriastradh FbStip dstBits; 34803b705cfSriastradh FbStip *d; 34903b705cfSriastradh FbStip dstMask; 35003b705cfSriastradh FbStip dstMaskFirst; 35103b705cfSriastradh FbStip dstUnion; 35203b705cfSriastradh int w; 35303b705cfSriastradh int wt; 35403b705cfSriastradh 35503b705cfSriastradh if (!width) 35603b705cfSriastradh return; 35703b705cfSriastradh 35803b705cfSriastradh src += srcX >> FB_SHIFT; 35903b705cfSriastradh srcX &= FB_MASK; 36003b705cfSriastradh 36103b705cfSriastradh dst += dstX >> FB_STIP_SHIFT; 36203b705cfSriastradh dstX &= FB_STIP_MASK; 36303b705cfSriastradh 36403b705cfSriastradh w = width / srcBpp; 36503b705cfSriastradh 36603b705cfSriastradh pm = fbReplicatePixel(planeMask, srcBpp); 36703b705cfSriastradh srcMaskFirst = pm & FbBitsMask(srcX, srcBpp); 36803b705cfSriastradh srcMask0 = pm & FbBitsMask(0, srcBpp); 36903b705cfSriastradh 37003b705cfSriastradh dstMaskFirst = FbStipMask(dstX, 1); 37103b705cfSriastradh while (height--) { 37203b705cfSriastradh d = dst; 37303b705cfSriastradh dst += dstStride; 37403b705cfSriastradh s = src; 37503b705cfSriastradh src += srcStride; 37603b705cfSriastradh 37703b705cfSriastradh srcMask = srcMaskFirst; 37803b705cfSriastradh srcBits = READ(s++); 37903b705cfSriastradh 38003b705cfSriastradh dstMask = dstMaskFirst; 38103b705cfSriastradh dstUnion = 0; 38203b705cfSriastradh dstBits = 0; 38303b705cfSriastradh 38403b705cfSriastradh wt = w; 38503b705cfSriastradh 38603b705cfSriastradh while (wt--) { 38703b705cfSriastradh if (!srcMask) { 38803b705cfSriastradh srcBits = READ(s++); 38903b705cfSriastradh srcMask = srcMask0; 39003b705cfSriastradh } 39103b705cfSriastradh if (!dstMask) { 39203b705cfSriastradh WRITE(d, FbStippleRRopMask(READ(d), dstBits, 39303b705cfSriastradh fgand, fgxor, bgand, bgxor, 39403b705cfSriastradh dstUnion)); 39503b705cfSriastradh d++; 39603b705cfSriastradh dstMask = FbStipMask(0, 1); 39703b705cfSriastradh dstUnion = 0; 39803b705cfSriastradh dstBits = 0; 39903b705cfSriastradh } 40003b705cfSriastradh if (srcBits & srcMask) 40103b705cfSriastradh dstBits |= dstMask; 40203b705cfSriastradh dstUnion |= dstMask; 40303b705cfSriastradh if (srcBpp == FB_UNIT) 40403b705cfSriastradh srcMask = 0; 40503b705cfSriastradh else 40603b705cfSriastradh srcMask = FbScrRight(srcMask, srcBpp); 40703b705cfSriastradh dstMask = FbStipRight(dstMask, 1); 40803b705cfSriastradh } 40903b705cfSriastradh if (dstUnion) 41003b705cfSriastradh WRITE(d, FbStippleRRopMask(READ(d), dstBits, 41103b705cfSriastradh fgand, fgxor, bgand, bgxor, dstUnion)); 41203b705cfSriastradh } 41303b705cfSriastradh} 414