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 <string.h>
25#include "fb.h"
26
27typedef struct _mergeRopBits {
28    FbBits ca1, cx1, ca2, cx2;
29} FbMergeRopRec, *FbMergeRopPtr;
30
31#define O 0
32#define I FB_ALLONES
33
34static const FbMergeRopRec FbMergeRopBits[16] = {
35	{O, O, O, O},               /* clear         0x0         0 */
36	{I, O, O, O},               /* and           0x1         src AND dst */
37	{I, O, I, O},               /* andReverse    0x2         src AND NOT dst */
38	{O, O, I, O},               /* copy          0x3         src */
39	{I, I, O, O},               /* andInverted   0x4         NOT src AND dst */
40	{O, I, O, O},               /* noop          0x5         dst */
41	{O, I, I, O},               /* xor           0x6         src XOR dst */
42	{I, I, I, O},               /* or            0x7         src OR dst */
43	{I, I, I, I},               /* nor           0x8         NOT src AND NOT dst */
44	{O, I, I, I},               /* equiv         0x9         NOT src XOR dst */
45	{O, I, O, I},               /* invert        0xa         NOT dst */
46	{I, I, O, I},               /* orReverse     0xb         src OR NOT dst */
47	{O, O, I, I},               /* copyInverted  0xc         NOT src */
48	{I, O, I, I},               /* orInverted    0xd         NOT src OR dst */
49	{I, O, O, I},               /* nand          0xe         NOT src OR NOT dst */
50	{O, O, O, I},               /* set           0xf         1 */
51};
52
53#undef O
54#undef I
55
56#define FbDeclareMergeRop() FbBits   _ca1, _cx1, _ca2, _cx2;
57#define FbDeclarePrebuiltMergeRop()	FbBits	_cca, _ccx;
58
59#define FbInitializeMergeRop(alu,pm) {\
60    const FbMergeRopRec  *_bits; \
61    _bits = &FbMergeRopBits[alu]; \
62    _ca1 = _bits->ca1 &  pm; \
63    _cx1 = _bits->cx1 | ~pm; \
64    _ca2 = _bits->ca2 &  pm; \
65    _cx2 = _bits->cx2 &  pm; \
66}
67
68#define InitializeShifts(sx,dx,ls,rs) { \
69    if (sx != dx) { \
70	if (sx > dx) { \
71	    ls = sx - dx; \
72	    rs = FB_UNIT - ls; \
73	} else { \
74	    rs = dx - sx; \
75	    ls = FB_UNIT - rs; \
76	} \
77    } \
78}
79
80static void
81fbBlt__rop(FbBits *srcLine, FbStride srcStride, int srcX,
82	   FbBits *dstLine, FbStride dstStride, int dstX,
83	   int width, int height,
84	   int alu, FbBits pm, int bpp,
85	   Bool reverse, Bool upsidedown)
86{
87	FbBits *src, *dst;
88	int leftShift, rightShift;
89	FbBits startmask, endmask;
90	FbBits bits, bits1;
91	int n, nmiddle;
92	Bool destInvarient;
93	int startbyte, endbyte;
94
95	FbDeclareMergeRop();
96
97	FbInitializeMergeRop(alu, pm);
98	destInvarient = FbDestInvarientMergeRop();
99	if (upsidedown) {
100		srcLine += (height - 1) * (srcStride);
101		dstLine += (height - 1) * (dstStride);
102		srcStride = -srcStride;
103		dstStride = -dstStride;
104	}
105	FbMaskBitsBytes(dstX, width, destInvarient, startmask, startbyte,
106			nmiddle, endmask, endbyte);
107	if (reverse) {
108		srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1;
109		dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1;
110		srcX = (srcX + width - 1) & FB_MASK;
111		dstX = (dstX + width - 1) & FB_MASK;
112	} else {
113		srcLine += srcX >> FB_SHIFT;
114		dstLine += dstX >> FB_SHIFT;
115		srcX &= FB_MASK;
116		dstX &= FB_MASK;
117	}
118	if (srcX == dstX) {
119		while (height--) {
120			src = srcLine;
121			srcLine += srcStride;
122			dst = dstLine;
123			dstLine += dstStride;
124			if (reverse) {
125				if (endmask) {
126					bits = READ(--src);
127					--dst;
128					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
129				}
130				n = nmiddle;
131				if (destInvarient) {
132					while (n--)
133						WRITE(--dst, FbDoDestInvarientMergeRop(READ(--src)));
134				} else {
135					while (n--) {
136						bits = READ(--src);
137						--dst;
138						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
139					}
140				}
141				if (startmask) {
142					bits = READ(--src);
143					--dst;
144					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
145				}
146			} else {
147				if (startmask) {
148					bits = READ(src++);
149					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
150					dst++;
151				}
152				n = nmiddle;
153				if (destInvarient) {
154					while (n--)
155						WRITE(dst++, FbDoDestInvarientMergeRop(READ(src++)));
156				} else {
157					while (n--) {
158						bits = READ(src++);
159						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
160						dst++;
161					}
162				}
163				if (endmask) {
164					bits = READ(src);
165					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
166				}
167			}
168		}
169	} else {
170		if (srcX > dstX) {
171			leftShift = srcX - dstX;
172			rightShift = FB_UNIT - leftShift;
173		} else {
174			rightShift = dstX - srcX;
175			leftShift = FB_UNIT - rightShift;
176		}
177		while (height--) {
178			src = srcLine;
179			srcLine += srcStride;
180			dst = dstLine;
181			dstLine += dstStride;
182
183			bits1 = 0;
184			if (reverse) {
185				if (srcX < dstX)
186					bits1 = READ(--src);
187				if (endmask) {
188					bits = FbScrRight(bits1, rightShift);
189					if (FbScrRight(endmask, leftShift)) {
190						bits1 = READ(--src);
191						bits |= FbScrLeft(bits1, leftShift);
192					}
193					--dst;
194					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
195				}
196				n = nmiddle;
197				if (destInvarient) {
198					while (n--) {
199						bits = FbScrRight(bits1, rightShift);
200						bits1 = READ(--src);
201						bits |= FbScrLeft(bits1, leftShift);
202						--dst;
203						WRITE(dst, FbDoDestInvarientMergeRop(bits));
204					}
205				} else {
206					while (n--) {
207						bits = FbScrRight(bits1, rightShift);
208						bits1 = READ(--src);
209						bits |= FbScrLeft(bits1, leftShift);
210						--dst;
211						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
212					}
213				}
214				if (startmask) {
215					bits = FbScrRight(bits1, rightShift);
216					if (FbScrRight(startmask, leftShift)) {
217						bits1 = READ(--src);
218						bits |= FbScrLeft(bits1, leftShift);
219					}
220					--dst;
221					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
222				}
223			} else {
224				if (srcX > dstX)
225					bits1 = READ(src++);
226				if (startmask) {
227					bits = FbScrLeft(bits1, leftShift);
228					if (FbScrLeft(startmask, rightShift)) {
229						bits1 = READ(src++);
230						bits |= FbScrRight(bits1, rightShift);
231					}
232					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
233					dst++;
234				}
235				n = nmiddle;
236				if (destInvarient) {
237					while (n--) {
238						bits = FbScrLeft(bits1, leftShift);
239						bits1 = READ(src++);
240						bits |= FbScrRight(bits1, rightShift);
241						WRITE(dst, FbDoDestInvarientMergeRop(bits));
242						dst++;
243					}
244				} else {
245					while (n--) {
246						bits = FbScrLeft(bits1, leftShift);
247						bits1 = READ(src++);
248						bits |= FbScrRight(bits1, rightShift);
249						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
250						dst++;
251					}
252				}
253				if (endmask) {
254					bits = FbScrLeft(bits1, leftShift);
255					if (FbScrLeft(endmask, rightShift)) {
256						bits1 = READ(src);
257						bits |= FbScrRight(bits1, rightShift);
258					}
259					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
260				}
261			}
262		}
263	}
264}
265
266void
267fbBlt(FbBits *srcLine, FbStride srcStride, int srcX,
268      FbBits *dstLine, FbStride dstStride, int dstX,
269      int width, int height,
270      int alu, FbBits pm, int bpp,
271      Bool reverse, Bool upsidedown)
272{
273	DBG(("%s %dx%d, alu=%d, pm=%x, bpp=%d (reverse=%d, upsidedown=%d)\n",
274	     __FUNCTION__, width, height, alu, pm, bpp, reverse, upsidedown));
275
276	if (alu == GXcopy && pm == FB_ALLONES && ((srcX|dstX|width) & 7) == 0) {
277		CARD8 *s = (CARD8 *) srcLine;
278		CARD8 *d = (CARD8 *) dstLine;
279		void *(*func)(void *, const void *, size_t);
280		int i;
281
282		srcStride *= sizeof(FbBits);
283		dstStride *= sizeof(FbBits);
284		width >>= 3;
285		s += srcX >> 3;
286		d += dstX >> 3;
287
288		DBG(("%s fast blt, src_stride=%d, dst_stride=%d, width=%d (offset=%ld)\n",
289		     __FUNCTION__,
290		     srcStride, dstStride, width, (long)(s - d)));
291
292		if (width == srcStride && width == dstStride) {
293			width *= height;
294			height = 1;
295		}
296
297		if ((s < d && s + width > d) || (d < s && d + width > s))
298			func = memmove;
299		else
300			func = memcpy;
301		if (!upsidedown) {
302			for (i = 0; i < height; i++)
303				func(d + i * dstStride,
304				     s + i * srcStride,
305				     width);
306		} else {
307			for (i = height; i--; )
308				func(d + i * dstStride,
309				     s + i * srcStride,
310				     width);
311		}
312
313		return;
314	}
315
316	fbBlt__rop(srcLine, srcStride, srcX,
317		   dstLine, dstStride, dstX,
318		   width, height,
319		   alu, pm, bpp,
320		   reverse, upsidedown);
321}
322