1/*
2 * Copyright © 1998 Keith Packard
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include "fb.h"
25
26#ifdef __clang__
27/* shift overflow is intentional */
28#pragma clang diagnostic ignored "-Wshift-overflow"
29#endif
30
31/*
32 *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
33 *
34 *	**** **** **** **** **** **** **** ****
35 *			^
36 *	********  ********  ********  ********
37 *		  ^
38 *  leftShift = 12
39 *  rightShift = 20
40 *
41 *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
42 *
43 *	**** **** **** **** **** **** **** ****
44 *	^
45 *	********  ********  ********  ********
46 *		  ^
47 *
48 *  leftShift = 24
49 *  rightShift = 8
50 */
51
52#define LoadBits {\
53    if (leftShift) { \
54	bitsRight = (src < srcEnd ? READ(src++) : 0); \
55	bits = (FbStipLeft (bitsLeft, leftShift) | \
56		FbStipRight(bitsRight, rightShift)); \
57	bitsLeft = bitsRight; \
58    } else \
59	bits = (src < srcEnd ? READ(src++) : 0); \
60}
61
62#define LaneCases1(n,a)	    case n: FbLaneCase(n,a); break
63#define LaneCases2(n,a)	    LaneCases1(n,a); LaneCases1(n+1,a)
64#define LaneCases4(n,a)	    LaneCases2(n,a); LaneCases2(n+2,a)
65#define LaneCases8(n,a)	    LaneCases4(n,a); LaneCases4(n+4,a)
66#define LaneCases16(n,a)    LaneCases8(n,a); LaneCases8(n+8,a)
67#define LaneCases32(n,a)    LaneCases16(n,a); LaneCases16(n+16,a)
68#define LaneCases64(n,a)    LaneCases32(n,a); LaneCases32(n+32,a)
69#define LaneCases128(n,a)   LaneCases64(n,a); LaneCases64(n+64,a)
70#define LaneCases256(n,a)   LaneCases128(n,a); LaneCases128(n+128,a)
71
72#define LaneCases(a)	    LaneCases16(0,a)
73
74static const CARD8 fb8Lane[16] = {
75    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
76};
77
78static const CARD8 fb16Lane[16] = {
79    0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80};
81
82static const CARD8 fb32Lane[16] = {
83    0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84};
85
86static const CARD8 * const fbLaneTable[33] = {
87    0, 0, 0, 0, 0, 0, 0, 0,
88    fb8Lane, 0, 0, 0, 0, 0, 0, 0,
89    fb16Lane, 0, 0, 0, 0, 0, 0, 0,
90    0, 0, 0, 0, 0, 0, 0, 0,
91    fb32Lane
92};
93
94void
95fbBltOne(FbStip * src, FbStride srcStride,      /* FbStip units per scanline */
96         int srcX,              /* bit position of source */
97         FbBits * dst, FbStride dstStride,      /* FbBits units per scanline */
98         int dstX,              /* bit position of dest */
99         int dstBpp,            /* bits per destination unit */
100         int width,             /* width in bits of destination */
101         int height,            /* height in scanlines */
102         FbBits fgand,          /* rrop values */
103         FbBits fgxor, FbBits bgand, FbBits bgxor)
104{
105	const FbBits *fbBits;
106	FbBits *srcEnd;
107	int pixelsPerDst;           /* dst pixels per FbBits */
108	int unitsPerSrc;            /* src patterns per FbStip */
109	int leftShift, rightShift;  /* align source with dest */
110	FbBits startmask, endmask;  /* dest scanline masks */
111	FbStip bits = 0, bitsLeft, bitsRight;       /* source bits */
112	FbStip left;
113	FbBits mask;
114	int nDst;                   /* dest longwords (w.o. end) */
115	int w;
116	int n, nmiddle;
117	int dstS;                   /* stipple-relative dst X coordinate */
118	Bool copy;                  /* accelerate dest-invariant */
119	Bool transparent;           /* accelerate 0 nop */
120	int srcinc;                 /* source units consumed */
121	Bool endNeedsLoad = FALSE;  /* need load for endmask */
122	const CARD8 *fbLane;
123	int startbyte, endbyte;
124
125	/*
126	 * Do not read past the end of the buffer!
127	 */
128	srcEnd = src + height * srcStride;
129
130	/*
131	 * Number of destination units in FbBits == number of stipple pixels
132	 * used each time
133	 */
134	pixelsPerDst = FB_UNIT / dstBpp;
135
136	/*
137	 * Number of source stipple patterns in FbStip
138	 */
139	unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
140
141	copy = FALSE;
142	transparent = FALSE;
143	if (bgand == 0 && fgand == 0)
144		copy = TRUE;
145	else if (bgand == FB_ALLONES && bgxor == 0)
146		transparent = TRUE;
147
148	/*
149	 * Adjust source and dest to nearest FbBits boundary
150	 */
151	src += srcX >> FB_STIP_SHIFT;
152	dst += dstX >> FB_SHIFT;
153	srcX &= FB_STIP_MASK;
154	dstX &= FB_MASK;
155
156	FbMaskBitsBytes(dstX, width, copy,
157			startmask, startbyte, nmiddle, endmask, endbyte);
158
159	/*
160	 * Compute effective dest alignment requirement for
161	 * source -- must align source to dest unit boundary
162	 */
163	dstS = dstX / dstBpp;
164	/*
165	 * Compute shift constants for effective alignement
166	 */
167	if (srcX >= dstS) {
168		leftShift = srcX - dstS;
169		rightShift = FB_STIP_UNIT - leftShift;
170	} else {
171		rightShift = dstS - srcX;
172		leftShift = FB_STIP_UNIT - rightShift;
173	}
174	/*
175	 * Get pointer to stipple mask array for this depth
176	 */
177	fbBits = 0;                 /* unused */
178	if (pixelsPerDst <= 8)
179		fbBits = fbStippleTable[pixelsPerDst];
180	fbLane = 0;
181	if (transparent && fgand == 0 && dstBpp >= 8)
182		fbLane = fbLaneTable[dstBpp];
183
184	/*
185	 * Compute total number of destination words written, but
186	 * don't count endmask
187	 */
188	nDst = nmiddle;
189	if (startmask)
190		nDst++;
191
192	dstStride -= nDst;
193
194	/*
195	 * Compute total number of source words consumed
196	 */
197
198	srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
199
200	if (srcX > dstS)
201		srcinc++;
202	if (endmask) {
203		endNeedsLoad = nDst % unitsPerSrc == 0;
204		if (endNeedsLoad)
205			srcinc++;
206	}
207
208	srcStride -= srcinc;
209
210	/*
211	 * Copy rectangle
212	 */
213	while (height--) {
214		w = nDst;               /* total units across scanline */
215		n = unitsPerSrc;        /* units avail in single stipple */
216		if (n > w)
217			n = w;
218
219		bitsLeft = 0;
220		if (srcX > dstS)
221			bitsLeft = READ(src++);
222		if (n) {
223			/*
224			 * Load first set of stipple bits
225			 */
226			LoadBits;
227
228			/*
229			 * Consume stipple bits for startmask
230			 */
231			if (startmask) {
232				mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
233				if (fbLane) {
234					fbTransparentSpan(dst, mask & startmask, fgxor, 1);
235				} else {
236					if (mask || !transparent)
237						FbDoLeftMaskByteStippleRRop(dst, mask,
238									    fgand, fgxor, bgand, bgxor,
239									    startbyte, startmask);
240				}
241				bits = FbStipLeft(bits, pixelsPerDst);
242				dst++;
243				n--;
244				w--;
245			}
246			/*
247			 * Consume stipple bits across scanline
248			 */
249			for (;;) {
250				w -= n;
251				if (copy) {
252					while (n--) {
253#if FB_UNIT > 32
254						if (pixelsPerDst == 16)
255							mask = FbStipple16Bits(FbLeftStipBits(bits, 16));
256						else
257#endif
258							mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
259						WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor));
260						dst++;
261						bits = FbStipLeft(bits, pixelsPerDst);
262					}
263				}
264				else {
265					if (fbLane) {
266						while (bits && n) {
267							switch (fbLane[FbLeftStipBits(bits, pixelsPerDst)]) {
268								LaneCases((CARD8 *) dst);
269							}
270							bits = FbStipLeft(bits, pixelsPerDst);
271							dst++;
272							n--;
273						}
274						dst += n;
275					} else {
276						while (n--) {
277							left = FbLeftStipBits(bits, pixelsPerDst);
278							if (left || !transparent) {
279								mask = fbBits[left];
280								WRITE(dst, FbStippleRRop(READ(dst), mask,
281											 fgand, fgxor, bgand,
282											 bgxor));
283							}
284							dst++;
285							bits = FbStipLeft(bits, pixelsPerDst);
286						}
287					}
288				}
289				if (!w)
290					break;
291				/*
292				 * Load another set and reset number of available units
293				 */
294				LoadBits;
295				n = unitsPerSrc;
296				if (n > w)
297					n = w;
298			}
299		}
300		/*
301		 * Consume stipple bits for endmask
302		 */
303		if (endmask) {
304			if (endNeedsLoad) {
305				LoadBits;
306			}
307			mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
308			if (fbLane) {
309				fbTransparentSpan(dst, mask & endmask, fgxor, 1);
310			} else {
311				if (mask || !transparent)
312					FbDoRightMaskByteStippleRRop(dst, mask,
313								     fgand, fgxor, bgand, bgxor,
314								     endbyte, endmask);
315			}
316		}
317		dst += dstStride;
318		src += srcStride;
319	}
320}
321
322/*
323 * Not very efficient, but simple -- copy a single plane
324 * from an N bit image to a 1 bit image
325 */
326
327void
328fbBltPlane(FbBits * src,
329           FbStride srcStride,
330           int srcX,
331           int srcBpp,
332           FbStip * dst,
333           FbStride dstStride,
334           int dstX,
335           int width,
336           int height,
337           FbStip fgand,
338           FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask)
339{
340	FbBits *s;
341	FbBits pm;
342	FbBits srcMask;
343	FbBits srcMaskFirst;
344	FbBits srcMask0 = 0;
345	FbBits srcBits;
346
347	FbStip dstBits;
348	FbStip *d;
349	FbStip dstMask;
350	FbStip dstMaskFirst;
351	FbStip dstUnion;
352	int w;
353	int wt;
354
355	if (!width)
356		return;
357
358	src += srcX >> FB_SHIFT;
359	srcX &= FB_MASK;
360
361	dst += dstX >> FB_STIP_SHIFT;
362	dstX &= FB_STIP_MASK;
363
364	w = width / srcBpp;
365
366	pm = fbReplicatePixel(planeMask, srcBpp);
367	srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
368	srcMask0 = pm & FbBitsMask(0, srcBpp);
369
370	dstMaskFirst = FbStipMask(dstX, 1);
371	while (height--) {
372		d = dst;
373		dst += dstStride;
374		s = src;
375		src += srcStride;
376
377		srcMask = srcMaskFirst;
378		srcBits = READ(s++);
379
380		dstMask = dstMaskFirst;
381		dstUnion = 0;
382		dstBits = 0;
383
384		wt = w;
385
386		while (wt--) {
387			if (!srcMask) {
388				srcBits = READ(s++);
389				srcMask = srcMask0;
390			}
391			if (!dstMask) {
392				WRITE(d, FbStippleRRopMask(READ(d), dstBits,
393							   fgand, fgxor, bgand, bgxor,
394							   dstUnion));
395				d++;
396				dstMask = FbStipMask(0, 1);
397				dstUnion = 0;
398				dstBits = 0;
399			}
400			if (srcBits & srcMask)
401				dstBits |= dstMask;
402			dstUnion |= dstMask;
403			if (srcBpp == FB_UNIT)
404				srcMask = 0;
405			else
406				srcMask = FbScrRight(srcMask, srcBpp);
407			dstMask = FbStipRight(dstMask, 1);
408		}
409		if (dstUnion)
410			WRITE(d, FbStippleRRopMask(READ(d), dstBits,
411						   fgand, fgxor, bgand, bgxor, dstUnion));
412	}
413}
414