1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 1998 Keith Packard
3428d7b3dSmrg * Copyright © 2012 Intel Corporation
4428d7b3dSmrg *
5428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
6428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
7428d7b3dSmrg * the above copyright notice appear in all copies and that both that
8428d7b3dSmrg * copyright notice and this permission notice appear in supporting
9428d7b3dSmrg * documentation, and that the name of Keith Packard not be used in
10428d7b3dSmrg * advertising or publicity pertaining to distribution of the software without
11428d7b3dSmrg * specific, written prior permission.  Keith Packard makes no
12428d7b3dSmrg * representations about the suitability of this software for any purpose.  It
13428d7b3dSmrg * is provided "as is" without express or implied warranty.
14428d7b3dSmrg *
15428d7b3dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16428d7b3dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17428d7b3dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18428d7b3dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19428d7b3dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20428d7b3dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21428d7b3dSmrg * PERFORMANCE OF THIS SOFTWARE.
22428d7b3dSmrg */
23428d7b3dSmrg
24428d7b3dSmrg#include "fb.h"
25428d7b3dSmrg
26428d7b3dSmrg#ifdef __clang__
27428d7b3dSmrg/* shift overflow is intentional */
28428d7b3dSmrg#pragma clang diagnostic ignored "-Wshift-overflow"
29428d7b3dSmrg#endif
30428d7b3dSmrg
31428d7b3dSmrg/*
32428d7b3dSmrg *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
33428d7b3dSmrg *
34428d7b3dSmrg *	**** **** **** **** **** **** **** ****
35428d7b3dSmrg *			^
36428d7b3dSmrg *	********  ********  ********  ********
37428d7b3dSmrg *		  ^
38428d7b3dSmrg *  leftShift = 12
39428d7b3dSmrg *  rightShift = 20
40428d7b3dSmrg *
41428d7b3dSmrg *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
42428d7b3dSmrg *
43428d7b3dSmrg *	**** **** **** **** **** **** **** ****
44428d7b3dSmrg *	^
45428d7b3dSmrg *	********  ********  ********  ********
46428d7b3dSmrg *		  ^
47428d7b3dSmrg *
48428d7b3dSmrg *  leftShift = 24
49428d7b3dSmrg *  rightShift = 8
50428d7b3dSmrg */
51428d7b3dSmrg
52428d7b3dSmrg#define LoadBits {\
53428d7b3dSmrg    if (leftShift) { \
54428d7b3dSmrg	bitsRight = (src < srcEnd ? READ(src++) : 0); \
55428d7b3dSmrg	bits = (FbStipLeft (bitsLeft, leftShift) | \
56428d7b3dSmrg		FbStipRight(bitsRight, rightShift)); \
57428d7b3dSmrg	bitsLeft = bitsRight; \
58428d7b3dSmrg    } else \
59428d7b3dSmrg	bits = (src < srcEnd ? READ(src++) : 0); \
60428d7b3dSmrg}
61428d7b3dSmrg
62428d7b3dSmrg#define LaneCases1(n,a)	    case n: FbLaneCase(n,a); break
63428d7b3dSmrg#define LaneCases2(n,a)	    LaneCases1(n,a); LaneCases1(n+1,a)
64428d7b3dSmrg#define LaneCases4(n,a)	    LaneCases2(n,a); LaneCases2(n+2,a)
65428d7b3dSmrg#define LaneCases8(n,a)	    LaneCases4(n,a); LaneCases4(n+4,a)
66428d7b3dSmrg#define LaneCases16(n,a)    LaneCases8(n,a); LaneCases8(n+8,a)
67428d7b3dSmrg#define LaneCases32(n,a)    LaneCases16(n,a); LaneCases16(n+16,a)
68428d7b3dSmrg#define LaneCases64(n,a)    LaneCases32(n,a); LaneCases32(n+32,a)
69428d7b3dSmrg#define LaneCases128(n,a)   LaneCases64(n,a); LaneCases64(n+64,a)
70428d7b3dSmrg#define LaneCases256(n,a)   LaneCases128(n,a); LaneCases128(n+128,a)
71428d7b3dSmrg
72428d7b3dSmrg#define LaneCases(a)	    LaneCases16(0,a)
73428d7b3dSmrg
74428d7b3dSmrgstatic const CARD8 fb8Lane[16] = {
75428d7b3dSmrg    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
76428d7b3dSmrg};
77428d7b3dSmrg
78428d7b3dSmrgstatic const CARD8 fb16Lane[16] = {
79428d7b3dSmrg    0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80428d7b3dSmrg};
81428d7b3dSmrg
82428d7b3dSmrgstatic const CARD8 fb32Lane[16] = {
83428d7b3dSmrg    0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84428d7b3dSmrg};
85428d7b3dSmrg
86428d7b3dSmrgstatic const CARD8 * const fbLaneTable[33] = {
87428d7b3dSmrg    0, 0, 0, 0, 0, 0, 0, 0,
88428d7b3dSmrg    fb8Lane, 0, 0, 0, 0, 0, 0, 0,
89428d7b3dSmrg    fb16Lane, 0, 0, 0, 0, 0, 0, 0,
90428d7b3dSmrg    0, 0, 0, 0, 0, 0, 0, 0,
91428d7b3dSmrg    fb32Lane
92428d7b3dSmrg};
93428d7b3dSmrg
94428d7b3dSmrgvoid
95428d7b3dSmrgfbBltOne(FbStip * src, FbStride srcStride,      /* FbStip units per scanline */
96428d7b3dSmrg         int srcX,              /* bit position of source */
97428d7b3dSmrg         FbBits * dst, FbStride dstStride,      /* FbBits units per scanline */
98428d7b3dSmrg         int dstX,              /* bit position of dest */
99428d7b3dSmrg         int dstBpp,            /* bits per destination unit */
100428d7b3dSmrg         int width,             /* width in bits of destination */
101428d7b3dSmrg         int height,            /* height in scanlines */
102428d7b3dSmrg         FbBits fgand,          /* rrop values */
103428d7b3dSmrg         FbBits fgxor, FbBits bgand, FbBits bgxor)
104428d7b3dSmrg{
105428d7b3dSmrg	const FbBits *fbBits;
106428d7b3dSmrg	FbBits *srcEnd;
107428d7b3dSmrg	int pixelsPerDst;           /* dst pixels per FbBits */
108428d7b3dSmrg	int unitsPerSrc;            /* src patterns per FbStip */
109428d7b3dSmrg	int leftShift, rightShift;  /* align source with dest */
110428d7b3dSmrg	FbBits startmask, endmask;  /* dest scanline masks */
111428d7b3dSmrg	FbStip bits = 0, bitsLeft, bitsRight;       /* source bits */
112428d7b3dSmrg	FbStip left;
113428d7b3dSmrg	FbBits mask;
114428d7b3dSmrg	int nDst;                   /* dest longwords (w.o. end) */
115428d7b3dSmrg	int w;
116428d7b3dSmrg	int n, nmiddle;
117428d7b3dSmrg	int dstS;                   /* stipple-relative dst X coordinate */
118428d7b3dSmrg	Bool copy;                  /* accelerate dest-invariant */
119428d7b3dSmrg	Bool transparent;           /* accelerate 0 nop */
120428d7b3dSmrg	int srcinc;                 /* source units consumed */
121428d7b3dSmrg	Bool endNeedsLoad = FALSE;  /* need load for endmask */
122428d7b3dSmrg	const CARD8 *fbLane;
123428d7b3dSmrg	int startbyte, endbyte;
124428d7b3dSmrg
125428d7b3dSmrg	/*
126428d7b3dSmrg	 * Do not read past the end of the buffer!
127428d7b3dSmrg	 */
128428d7b3dSmrg	srcEnd = src + height * srcStride;
129428d7b3dSmrg
130428d7b3dSmrg	/*
131428d7b3dSmrg	 * Number of destination units in FbBits == number of stipple pixels
132428d7b3dSmrg	 * used each time
133428d7b3dSmrg	 */
134428d7b3dSmrg	pixelsPerDst = FB_UNIT / dstBpp;
135428d7b3dSmrg
136428d7b3dSmrg	/*
137428d7b3dSmrg	 * Number of source stipple patterns in FbStip
138428d7b3dSmrg	 */
139428d7b3dSmrg	unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
140428d7b3dSmrg
141428d7b3dSmrg	copy = FALSE;
142428d7b3dSmrg	transparent = FALSE;
143428d7b3dSmrg	if (bgand == 0 && fgand == 0)
144428d7b3dSmrg		copy = TRUE;
145428d7b3dSmrg	else if (bgand == FB_ALLONES && bgxor == 0)
146428d7b3dSmrg		transparent = TRUE;
147428d7b3dSmrg
148428d7b3dSmrg	/*
149428d7b3dSmrg	 * Adjust source and dest to nearest FbBits boundary
150428d7b3dSmrg	 */
151428d7b3dSmrg	src += srcX >> FB_STIP_SHIFT;
152428d7b3dSmrg	dst += dstX >> FB_SHIFT;
153428d7b3dSmrg	srcX &= FB_STIP_MASK;
154428d7b3dSmrg	dstX &= FB_MASK;
155428d7b3dSmrg
156428d7b3dSmrg	FbMaskBitsBytes(dstX, width, copy,
157428d7b3dSmrg			startmask, startbyte, nmiddle, endmask, endbyte);
158428d7b3dSmrg
159428d7b3dSmrg	/*
160428d7b3dSmrg	 * Compute effective dest alignment requirement for
161428d7b3dSmrg	 * source -- must align source to dest unit boundary
162428d7b3dSmrg	 */
163428d7b3dSmrg	dstS = dstX / dstBpp;
164428d7b3dSmrg	/*
165428d7b3dSmrg	 * Compute shift constants for effective alignement
166428d7b3dSmrg	 */
167428d7b3dSmrg	if (srcX >= dstS) {
168428d7b3dSmrg		leftShift = srcX - dstS;
169428d7b3dSmrg		rightShift = FB_STIP_UNIT - leftShift;
170428d7b3dSmrg	} else {
171428d7b3dSmrg		rightShift = dstS - srcX;
172428d7b3dSmrg		leftShift = FB_STIP_UNIT - rightShift;
173428d7b3dSmrg	}
174428d7b3dSmrg	/*
175428d7b3dSmrg	 * Get pointer to stipple mask array for this depth
176428d7b3dSmrg	 */
177428d7b3dSmrg	fbBits = 0;                 /* unused */
178428d7b3dSmrg	if (pixelsPerDst <= 8)
179428d7b3dSmrg		fbBits = fbStippleTable[pixelsPerDst];
180428d7b3dSmrg	fbLane = 0;
181428d7b3dSmrg	if (transparent && fgand == 0 && dstBpp >= 8)
182428d7b3dSmrg		fbLane = fbLaneTable[dstBpp];
183428d7b3dSmrg
184428d7b3dSmrg	/*
185428d7b3dSmrg	 * Compute total number of destination words written, but
186428d7b3dSmrg	 * don't count endmask
187428d7b3dSmrg	 */
188428d7b3dSmrg	nDst = nmiddle;
189428d7b3dSmrg	if (startmask)
190428d7b3dSmrg		nDst++;
191428d7b3dSmrg
192428d7b3dSmrg	dstStride -= nDst;
193428d7b3dSmrg
194428d7b3dSmrg	/*
195428d7b3dSmrg	 * Compute total number of source words consumed
196428d7b3dSmrg	 */
197428d7b3dSmrg
198428d7b3dSmrg	srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
199428d7b3dSmrg
200428d7b3dSmrg	if (srcX > dstS)
201428d7b3dSmrg		srcinc++;
202428d7b3dSmrg	if (endmask) {
203428d7b3dSmrg		endNeedsLoad = nDst % unitsPerSrc == 0;
204428d7b3dSmrg		if (endNeedsLoad)
205428d7b3dSmrg			srcinc++;
206428d7b3dSmrg	}
207428d7b3dSmrg
208428d7b3dSmrg	srcStride -= srcinc;
209428d7b3dSmrg
210428d7b3dSmrg	/*
211428d7b3dSmrg	 * Copy rectangle
212428d7b3dSmrg	 */
213428d7b3dSmrg	while (height--) {
214428d7b3dSmrg		w = nDst;               /* total units across scanline */
215428d7b3dSmrg		n = unitsPerSrc;        /* units avail in single stipple */
216428d7b3dSmrg		if (n > w)
217428d7b3dSmrg			n = w;
218428d7b3dSmrg
219428d7b3dSmrg		bitsLeft = 0;
220428d7b3dSmrg		if (srcX > dstS)
221428d7b3dSmrg			bitsLeft = READ(src++);
222428d7b3dSmrg		if (n) {
223428d7b3dSmrg			/*
224428d7b3dSmrg			 * Load first set of stipple bits
225428d7b3dSmrg			 */
226428d7b3dSmrg			LoadBits;
227428d7b3dSmrg
228428d7b3dSmrg			/*
229428d7b3dSmrg			 * Consume stipple bits for startmask
230428d7b3dSmrg			 */
231428d7b3dSmrg			if (startmask) {
232428d7b3dSmrg				mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
233428d7b3dSmrg				if (fbLane) {
234428d7b3dSmrg					fbTransparentSpan(dst, mask & startmask, fgxor, 1);
235428d7b3dSmrg				} else {
236428d7b3dSmrg					if (mask || !transparent)
237428d7b3dSmrg						FbDoLeftMaskByteStippleRRop(dst, mask,
238428d7b3dSmrg									    fgand, fgxor, bgand, bgxor,
239428d7b3dSmrg									    startbyte, startmask);
240428d7b3dSmrg				}
241428d7b3dSmrg				bits = FbStipLeft(bits, pixelsPerDst);
242428d7b3dSmrg				dst++;
243428d7b3dSmrg				n--;
244428d7b3dSmrg				w--;
245428d7b3dSmrg			}
246428d7b3dSmrg			/*
247428d7b3dSmrg			 * Consume stipple bits across scanline
248428d7b3dSmrg			 */
249428d7b3dSmrg			for (;;) {
250428d7b3dSmrg				w -= n;
251428d7b3dSmrg				if (copy) {
252428d7b3dSmrg					while (n--) {
253428d7b3dSmrg#if FB_UNIT > 32
254428d7b3dSmrg						if (pixelsPerDst == 16)
255428d7b3dSmrg							mask = FbStipple16Bits(FbLeftStipBits(bits, 16));
256428d7b3dSmrg						else
257428d7b3dSmrg#endif
258428d7b3dSmrg							mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
259428d7b3dSmrg						WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor));
260428d7b3dSmrg						dst++;
261428d7b3dSmrg						bits = FbStipLeft(bits, pixelsPerDst);
262428d7b3dSmrg					}
263428d7b3dSmrg				}
264428d7b3dSmrg				else {
265428d7b3dSmrg					if (fbLane) {
266428d7b3dSmrg						while (bits && n) {
267428d7b3dSmrg							switch (fbLane[FbLeftStipBits(bits, pixelsPerDst)]) {
268428d7b3dSmrg								LaneCases((CARD8 *) dst);
269428d7b3dSmrg							}
270428d7b3dSmrg							bits = FbStipLeft(bits, pixelsPerDst);
271428d7b3dSmrg							dst++;
272428d7b3dSmrg							n--;
273428d7b3dSmrg						}
274428d7b3dSmrg						dst += n;
275428d7b3dSmrg					} else {
276428d7b3dSmrg						while (n--) {
277428d7b3dSmrg							left = FbLeftStipBits(bits, pixelsPerDst);
278428d7b3dSmrg							if (left || !transparent) {
279428d7b3dSmrg								mask = fbBits[left];
280428d7b3dSmrg								WRITE(dst, FbStippleRRop(READ(dst), mask,
281428d7b3dSmrg											 fgand, fgxor, bgand,
282428d7b3dSmrg											 bgxor));
283428d7b3dSmrg							}
284428d7b3dSmrg							dst++;
285428d7b3dSmrg							bits = FbStipLeft(bits, pixelsPerDst);
286428d7b3dSmrg						}
287428d7b3dSmrg					}
288428d7b3dSmrg				}
289428d7b3dSmrg				if (!w)
290428d7b3dSmrg					break;
291428d7b3dSmrg				/*
292428d7b3dSmrg				 * Load another set and reset number of available units
293428d7b3dSmrg				 */
294428d7b3dSmrg				LoadBits;
295428d7b3dSmrg				n = unitsPerSrc;
296428d7b3dSmrg				if (n > w)
297428d7b3dSmrg					n = w;
298428d7b3dSmrg			}
299428d7b3dSmrg		}
300428d7b3dSmrg		/*
301428d7b3dSmrg		 * Consume stipple bits for endmask
302428d7b3dSmrg		 */
303428d7b3dSmrg		if (endmask) {
304428d7b3dSmrg			if (endNeedsLoad) {
305428d7b3dSmrg				LoadBits;
306428d7b3dSmrg			}
307428d7b3dSmrg			mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
308428d7b3dSmrg			if (fbLane) {
309428d7b3dSmrg				fbTransparentSpan(dst, mask & endmask, fgxor, 1);
310428d7b3dSmrg			} else {
311428d7b3dSmrg				if (mask || !transparent)
312428d7b3dSmrg					FbDoRightMaskByteStippleRRop(dst, mask,
313428d7b3dSmrg								     fgand, fgxor, bgand, bgxor,
314428d7b3dSmrg								     endbyte, endmask);
315428d7b3dSmrg			}
316428d7b3dSmrg		}
317428d7b3dSmrg		dst += dstStride;
318428d7b3dSmrg		src += srcStride;
319428d7b3dSmrg	}
320428d7b3dSmrg}
321428d7b3dSmrg
322428d7b3dSmrg/*
323428d7b3dSmrg * Not very efficient, but simple -- copy a single plane
324428d7b3dSmrg * from an N bit image to a 1 bit image
325428d7b3dSmrg */
326428d7b3dSmrg
327428d7b3dSmrgvoid
328428d7b3dSmrgfbBltPlane(FbBits * src,
329428d7b3dSmrg           FbStride srcStride,
330428d7b3dSmrg           int srcX,
331428d7b3dSmrg           int srcBpp,
332428d7b3dSmrg           FbStip * dst,
333428d7b3dSmrg           FbStride dstStride,
334428d7b3dSmrg           int dstX,
335428d7b3dSmrg           int width,
336428d7b3dSmrg           int height,
337428d7b3dSmrg           FbStip fgand,
338428d7b3dSmrg           FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask)
339428d7b3dSmrg{
340428d7b3dSmrg	FbBits *s;
341428d7b3dSmrg	FbBits pm;
342428d7b3dSmrg	FbBits srcMask;
343428d7b3dSmrg	FbBits srcMaskFirst;
344428d7b3dSmrg	FbBits srcMask0 = 0;
345428d7b3dSmrg	FbBits srcBits;
346428d7b3dSmrg
347428d7b3dSmrg	FbStip dstBits;
348428d7b3dSmrg	FbStip *d;
349428d7b3dSmrg	FbStip dstMask;
350428d7b3dSmrg	FbStip dstMaskFirst;
351428d7b3dSmrg	FbStip dstUnion;
352428d7b3dSmrg	int w;
353428d7b3dSmrg	int wt;
354428d7b3dSmrg
355428d7b3dSmrg	if (!width)
356428d7b3dSmrg		return;
357428d7b3dSmrg
358428d7b3dSmrg	src += srcX >> FB_SHIFT;
359428d7b3dSmrg	srcX &= FB_MASK;
360428d7b3dSmrg
361428d7b3dSmrg	dst += dstX >> FB_STIP_SHIFT;
362428d7b3dSmrg	dstX &= FB_STIP_MASK;
363428d7b3dSmrg
364428d7b3dSmrg	w = width / srcBpp;
365428d7b3dSmrg
366428d7b3dSmrg	pm = fbReplicatePixel(planeMask, srcBpp);
367428d7b3dSmrg	srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
368428d7b3dSmrg	srcMask0 = pm & FbBitsMask(0, srcBpp);
369428d7b3dSmrg
370428d7b3dSmrg	dstMaskFirst = FbStipMask(dstX, 1);
371428d7b3dSmrg	while (height--) {
372428d7b3dSmrg		d = dst;
373428d7b3dSmrg		dst += dstStride;
374428d7b3dSmrg		s = src;
375428d7b3dSmrg		src += srcStride;
376428d7b3dSmrg
377428d7b3dSmrg		srcMask = srcMaskFirst;
378428d7b3dSmrg		srcBits = READ(s++);
379428d7b3dSmrg
380428d7b3dSmrg		dstMask = dstMaskFirst;
381428d7b3dSmrg		dstUnion = 0;
382428d7b3dSmrg		dstBits = 0;
383428d7b3dSmrg
384428d7b3dSmrg		wt = w;
385428d7b3dSmrg
386428d7b3dSmrg		while (wt--) {
387428d7b3dSmrg			if (!srcMask) {
388428d7b3dSmrg				srcBits = READ(s++);
389428d7b3dSmrg				srcMask = srcMask0;
390428d7b3dSmrg			}
391428d7b3dSmrg			if (!dstMask) {
392428d7b3dSmrg				WRITE(d, FbStippleRRopMask(READ(d), dstBits,
393428d7b3dSmrg							   fgand, fgxor, bgand, bgxor,
394428d7b3dSmrg							   dstUnion));
395428d7b3dSmrg				d++;
396428d7b3dSmrg				dstMask = FbStipMask(0, 1);
397428d7b3dSmrg				dstUnion = 0;
398428d7b3dSmrg				dstBits = 0;
399428d7b3dSmrg			}
400428d7b3dSmrg			if (srcBits & srcMask)
401428d7b3dSmrg				dstBits |= dstMask;
402428d7b3dSmrg			dstUnion |= dstMask;
403428d7b3dSmrg			if (srcBpp == FB_UNIT)
404428d7b3dSmrg				srcMask = 0;
405428d7b3dSmrg			else
406428d7b3dSmrg				srcMask = FbScrRight(srcMask, srcBpp);
407428d7b3dSmrg			dstMask = FbStipRight(dstMask, 1);
408428d7b3dSmrg		}
409428d7b3dSmrg		if (dstUnion)
410428d7b3dSmrg			WRITE(d, FbStippleRRopMask(READ(d), dstBits,
411428d7b3dSmrg						   fgand, fgxor, bgand, bgxor, dstUnion));
412428d7b3dSmrg	}
413428d7b3dSmrg}
414