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