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 <string.h>
25428d7b3dSmrg#include "fb.h"
26428d7b3dSmrg
27428d7b3dSmrgtypedef struct _mergeRopBits {
28428d7b3dSmrg    FbBits ca1, cx1, ca2, cx2;
29428d7b3dSmrg} FbMergeRopRec, *FbMergeRopPtr;
30428d7b3dSmrg
31428d7b3dSmrg#define O 0
32428d7b3dSmrg#define I FB_ALLONES
33428d7b3dSmrg
34428d7b3dSmrgstatic const FbMergeRopRec FbMergeRopBits[16] = {
35428d7b3dSmrg	{O, O, O, O},               /* clear         0x0         0 */
36428d7b3dSmrg	{I, O, O, O},               /* and           0x1         src AND dst */
37428d7b3dSmrg	{I, O, I, O},               /* andReverse    0x2         src AND NOT dst */
38428d7b3dSmrg	{O, O, I, O},               /* copy          0x3         src */
39428d7b3dSmrg	{I, I, O, O},               /* andInverted   0x4         NOT src AND dst */
40428d7b3dSmrg	{O, I, O, O},               /* noop          0x5         dst */
41428d7b3dSmrg	{O, I, I, O},               /* xor           0x6         src XOR dst */
42428d7b3dSmrg	{I, I, I, O},               /* or            0x7         src OR dst */
43428d7b3dSmrg	{I, I, I, I},               /* nor           0x8         NOT src AND NOT dst */
44428d7b3dSmrg	{O, I, I, I},               /* equiv         0x9         NOT src XOR dst */
45428d7b3dSmrg	{O, I, O, I},               /* invert        0xa         NOT dst */
46428d7b3dSmrg	{I, I, O, I},               /* orReverse     0xb         src OR NOT dst */
47428d7b3dSmrg	{O, O, I, I},               /* copyInverted  0xc         NOT src */
48428d7b3dSmrg	{I, O, I, I},               /* orInverted    0xd         NOT src OR dst */
49428d7b3dSmrg	{I, O, O, I},               /* nand          0xe         NOT src OR NOT dst */
50428d7b3dSmrg	{O, O, O, I},               /* set           0xf         1 */
51428d7b3dSmrg};
52428d7b3dSmrg
53428d7b3dSmrg#undef O
54428d7b3dSmrg#undef I
55428d7b3dSmrg
56428d7b3dSmrg#define FbDeclareMergeRop() FbBits   _ca1, _cx1, _ca2, _cx2;
57428d7b3dSmrg#define FbDeclarePrebuiltMergeRop()	FbBits	_cca, _ccx;
58428d7b3dSmrg
59428d7b3dSmrg#define FbInitializeMergeRop(alu,pm) {\
60428d7b3dSmrg    const FbMergeRopRec  *_bits; \
61428d7b3dSmrg    _bits = &FbMergeRopBits[alu]; \
62428d7b3dSmrg    _ca1 = _bits->ca1 &  pm; \
63428d7b3dSmrg    _cx1 = _bits->cx1 | ~pm; \
64428d7b3dSmrg    _ca2 = _bits->ca2 &  pm; \
65428d7b3dSmrg    _cx2 = _bits->cx2 &  pm; \
66428d7b3dSmrg}
67428d7b3dSmrg
68428d7b3dSmrg#define InitializeShifts(sx,dx,ls,rs) { \
69428d7b3dSmrg    if (sx != dx) { \
70428d7b3dSmrg	if (sx > dx) { \
71428d7b3dSmrg	    ls = sx - dx; \
72428d7b3dSmrg	    rs = FB_UNIT - ls; \
73428d7b3dSmrg	} else { \
74428d7b3dSmrg	    rs = dx - sx; \
75428d7b3dSmrg	    ls = FB_UNIT - rs; \
76428d7b3dSmrg	} \
77428d7b3dSmrg    } \
78428d7b3dSmrg}
79428d7b3dSmrg
80428d7b3dSmrgstatic void
81428d7b3dSmrgfbBlt__rop(FbBits *srcLine, FbStride srcStride, int srcX,
82428d7b3dSmrg	   FbBits *dstLine, FbStride dstStride, int dstX,
83428d7b3dSmrg	   int width, int height,
84428d7b3dSmrg	   int alu, FbBits pm, int bpp,
85428d7b3dSmrg	   Bool reverse, Bool upsidedown)
86428d7b3dSmrg{
87428d7b3dSmrg	FbBits *src, *dst;
88428d7b3dSmrg	int leftShift, rightShift;
89428d7b3dSmrg	FbBits startmask, endmask;
90428d7b3dSmrg	FbBits bits, bits1;
91428d7b3dSmrg	int n, nmiddle;
92428d7b3dSmrg	Bool destInvarient;
93428d7b3dSmrg	int startbyte, endbyte;
94428d7b3dSmrg
95428d7b3dSmrg	FbDeclareMergeRop();
96428d7b3dSmrg
97428d7b3dSmrg	FbInitializeMergeRop(alu, pm);
98428d7b3dSmrg	destInvarient = FbDestInvarientMergeRop();
99428d7b3dSmrg	if (upsidedown) {
100428d7b3dSmrg		srcLine += (height - 1) * (srcStride);
101428d7b3dSmrg		dstLine += (height - 1) * (dstStride);
102428d7b3dSmrg		srcStride = -srcStride;
103428d7b3dSmrg		dstStride = -dstStride;
104428d7b3dSmrg	}
105428d7b3dSmrg	FbMaskBitsBytes(dstX, width, destInvarient, startmask, startbyte,
106428d7b3dSmrg			nmiddle, endmask, endbyte);
107428d7b3dSmrg	if (reverse) {
108428d7b3dSmrg		srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1;
109428d7b3dSmrg		dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1;
110428d7b3dSmrg		srcX = (srcX + width - 1) & FB_MASK;
111428d7b3dSmrg		dstX = (dstX + width - 1) & FB_MASK;
112428d7b3dSmrg	} else {
113428d7b3dSmrg		srcLine += srcX >> FB_SHIFT;
114428d7b3dSmrg		dstLine += dstX >> FB_SHIFT;
115428d7b3dSmrg		srcX &= FB_MASK;
116428d7b3dSmrg		dstX &= FB_MASK;
117428d7b3dSmrg	}
118428d7b3dSmrg	if (srcX == dstX) {
119428d7b3dSmrg		while (height--) {
120428d7b3dSmrg			src = srcLine;
121428d7b3dSmrg			srcLine += srcStride;
122428d7b3dSmrg			dst = dstLine;
123428d7b3dSmrg			dstLine += dstStride;
124428d7b3dSmrg			if (reverse) {
125428d7b3dSmrg				if (endmask) {
126428d7b3dSmrg					bits = READ(--src);
127428d7b3dSmrg					--dst;
128428d7b3dSmrg					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
129428d7b3dSmrg				}
130428d7b3dSmrg				n = nmiddle;
131428d7b3dSmrg				if (destInvarient) {
132428d7b3dSmrg					while (n--)
133428d7b3dSmrg						WRITE(--dst, FbDoDestInvarientMergeRop(READ(--src)));
134428d7b3dSmrg				} else {
135428d7b3dSmrg					while (n--) {
136428d7b3dSmrg						bits = READ(--src);
137428d7b3dSmrg						--dst;
138428d7b3dSmrg						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
139428d7b3dSmrg					}
140428d7b3dSmrg				}
141428d7b3dSmrg				if (startmask) {
142428d7b3dSmrg					bits = READ(--src);
143428d7b3dSmrg					--dst;
144428d7b3dSmrg					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
145428d7b3dSmrg				}
146428d7b3dSmrg			} else {
147428d7b3dSmrg				if (startmask) {
148428d7b3dSmrg					bits = READ(src++);
149428d7b3dSmrg					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
150428d7b3dSmrg					dst++;
151428d7b3dSmrg				}
152428d7b3dSmrg				n = nmiddle;
153428d7b3dSmrg				if (destInvarient) {
154428d7b3dSmrg					while (n--)
155428d7b3dSmrg						WRITE(dst++, FbDoDestInvarientMergeRop(READ(src++)));
156428d7b3dSmrg				} else {
157428d7b3dSmrg					while (n--) {
158428d7b3dSmrg						bits = READ(src++);
159428d7b3dSmrg						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
160428d7b3dSmrg						dst++;
161428d7b3dSmrg					}
162428d7b3dSmrg				}
163428d7b3dSmrg				if (endmask) {
164428d7b3dSmrg					bits = READ(src);
165428d7b3dSmrg					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
166428d7b3dSmrg				}
167428d7b3dSmrg			}
168428d7b3dSmrg		}
169428d7b3dSmrg	} else {
170428d7b3dSmrg		if (srcX > dstX) {
171428d7b3dSmrg			leftShift = srcX - dstX;
172428d7b3dSmrg			rightShift = FB_UNIT - leftShift;
173428d7b3dSmrg		} else {
174428d7b3dSmrg			rightShift = dstX - srcX;
175428d7b3dSmrg			leftShift = FB_UNIT - rightShift;
176428d7b3dSmrg		}
177428d7b3dSmrg		while (height--) {
178428d7b3dSmrg			src = srcLine;
179428d7b3dSmrg			srcLine += srcStride;
180428d7b3dSmrg			dst = dstLine;
181428d7b3dSmrg			dstLine += dstStride;
182428d7b3dSmrg
183428d7b3dSmrg			bits1 = 0;
184428d7b3dSmrg			if (reverse) {
185428d7b3dSmrg				if (srcX < dstX)
186428d7b3dSmrg					bits1 = READ(--src);
187428d7b3dSmrg				if (endmask) {
188428d7b3dSmrg					bits = FbScrRight(bits1, rightShift);
189428d7b3dSmrg					if (FbScrRight(endmask, leftShift)) {
190428d7b3dSmrg						bits1 = READ(--src);
191428d7b3dSmrg						bits |= FbScrLeft(bits1, leftShift);
192428d7b3dSmrg					}
193428d7b3dSmrg					--dst;
194428d7b3dSmrg					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
195428d7b3dSmrg				}
196428d7b3dSmrg				n = nmiddle;
197428d7b3dSmrg				if (destInvarient) {
198428d7b3dSmrg					while (n--) {
199428d7b3dSmrg						bits = FbScrRight(bits1, rightShift);
200428d7b3dSmrg						bits1 = READ(--src);
201428d7b3dSmrg						bits |= FbScrLeft(bits1, leftShift);
202428d7b3dSmrg						--dst;
203428d7b3dSmrg						WRITE(dst, FbDoDestInvarientMergeRop(bits));
204428d7b3dSmrg					}
205428d7b3dSmrg				} else {
206428d7b3dSmrg					while (n--) {
207428d7b3dSmrg						bits = FbScrRight(bits1, rightShift);
208428d7b3dSmrg						bits1 = READ(--src);
209428d7b3dSmrg						bits |= FbScrLeft(bits1, leftShift);
210428d7b3dSmrg						--dst;
211428d7b3dSmrg						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
212428d7b3dSmrg					}
213428d7b3dSmrg				}
214428d7b3dSmrg				if (startmask) {
215428d7b3dSmrg					bits = FbScrRight(bits1, rightShift);
216428d7b3dSmrg					if (FbScrRight(startmask, leftShift)) {
217428d7b3dSmrg						bits1 = READ(--src);
218428d7b3dSmrg						bits |= FbScrLeft(bits1, leftShift);
219428d7b3dSmrg					}
220428d7b3dSmrg					--dst;
221428d7b3dSmrg					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
222428d7b3dSmrg				}
223428d7b3dSmrg			} else {
224428d7b3dSmrg				if (srcX > dstX)
225428d7b3dSmrg					bits1 = READ(src++);
226428d7b3dSmrg				if (startmask) {
227428d7b3dSmrg					bits = FbScrLeft(bits1, leftShift);
228428d7b3dSmrg					if (FbScrLeft(startmask, rightShift)) {
229428d7b3dSmrg						bits1 = READ(src++);
230428d7b3dSmrg						bits |= FbScrRight(bits1, rightShift);
231428d7b3dSmrg					}
232428d7b3dSmrg					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
233428d7b3dSmrg					dst++;
234428d7b3dSmrg				}
235428d7b3dSmrg				n = nmiddle;
236428d7b3dSmrg				if (destInvarient) {
237428d7b3dSmrg					while (n--) {
238428d7b3dSmrg						bits = FbScrLeft(bits1, leftShift);
239428d7b3dSmrg						bits1 = READ(src++);
240428d7b3dSmrg						bits |= FbScrRight(bits1, rightShift);
241428d7b3dSmrg						WRITE(dst, FbDoDestInvarientMergeRop(bits));
242428d7b3dSmrg						dst++;
243428d7b3dSmrg					}
244428d7b3dSmrg				} else {
245428d7b3dSmrg					while (n--) {
246428d7b3dSmrg						bits = FbScrLeft(bits1, leftShift);
247428d7b3dSmrg						bits1 = READ(src++);
248428d7b3dSmrg						bits |= FbScrRight(bits1, rightShift);
249428d7b3dSmrg						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
250428d7b3dSmrg						dst++;
251428d7b3dSmrg					}
252428d7b3dSmrg				}
253428d7b3dSmrg				if (endmask) {
254428d7b3dSmrg					bits = FbScrLeft(bits1, leftShift);
255428d7b3dSmrg					if (FbScrLeft(endmask, rightShift)) {
256428d7b3dSmrg						bits1 = READ(src);
257428d7b3dSmrg						bits |= FbScrRight(bits1, rightShift);
258428d7b3dSmrg					}
259428d7b3dSmrg					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
260428d7b3dSmrg				}
261428d7b3dSmrg			}
262428d7b3dSmrg		}
263428d7b3dSmrg	}
264428d7b3dSmrg}
265428d7b3dSmrg
266428d7b3dSmrgvoid
267428d7b3dSmrgfbBlt(FbBits *srcLine, FbStride srcStride, int srcX,
268428d7b3dSmrg      FbBits *dstLine, FbStride dstStride, int dstX,
269428d7b3dSmrg      int width, int height,
270428d7b3dSmrg      int alu, FbBits pm, int bpp,
271428d7b3dSmrg      Bool reverse, Bool upsidedown)
272428d7b3dSmrg{
273428d7b3dSmrg	DBG(("%s %dx%d, alu=%d, pm=%x, bpp=%d (reverse=%d, upsidedown=%d)\n",
274428d7b3dSmrg	     __FUNCTION__, width, height, alu, pm, bpp, reverse, upsidedown));
275428d7b3dSmrg
276428d7b3dSmrg	if (alu == GXcopy && pm == FB_ALLONES && ((srcX|dstX|width) & 7) == 0) {
277428d7b3dSmrg		CARD8 *s = (CARD8 *) srcLine;
278428d7b3dSmrg		CARD8 *d = (CARD8 *) dstLine;
279428d7b3dSmrg		void *(*func)(void *, const void *, size_t);
280428d7b3dSmrg		int i;
281428d7b3dSmrg
282428d7b3dSmrg		srcStride *= sizeof(FbBits);
283428d7b3dSmrg		dstStride *= sizeof(FbBits);
284428d7b3dSmrg		width >>= 3;
285428d7b3dSmrg		s += srcX >> 3;
286428d7b3dSmrg		d += dstX >> 3;
287428d7b3dSmrg
288428d7b3dSmrg		DBG(("%s fast blt, src_stride=%d, dst_stride=%d, width=%d (offset=%ld)\n",
289428d7b3dSmrg		     __FUNCTION__,
290428d7b3dSmrg		     srcStride, dstStride, width, (long)(s - d)));
291428d7b3dSmrg
292428d7b3dSmrg		if (width == srcStride && width == dstStride) {
293428d7b3dSmrg			width *= height;
294428d7b3dSmrg			height = 1;
295428d7b3dSmrg		}
296428d7b3dSmrg
297428d7b3dSmrg		if ((s < d && s + width > d) || (d < s && d + width > s))
298428d7b3dSmrg			func = memmove;
299428d7b3dSmrg		else
300428d7b3dSmrg			func = memcpy;
301428d7b3dSmrg		if (!upsidedown) {
302428d7b3dSmrg			for (i = 0; i < height; i++)
303428d7b3dSmrg				func(d + i * dstStride,
304428d7b3dSmrg				     s + i * srcStride,
305428d7b3dSmrg				     width);
306428d7b3dSmrg		} else {
307428d7b3dSmrg			for (i = height; i--; )
308428d7b3dSmrg				func(d + i * dstStride,
309428d7b3dSmrg				     s + i * srcStride,
310428d7b3dSmrg				     width);
311428d7b3dSmrg		}
312428d7b3dSmrg
313428d7b3dSmrg		return;
314428d7b3dSmrg	}
315428d7b3dSmrg
316428d7b3dSmrg	fbBlt__rop(srcLine, srcStride, srcX,
317428d7b3dSmrg		   dstLine, dstStride, dstX,
318428d7b3dSmrg		   width, height,
319428d7b3dSmrg		   alu, pm, bpp,
320428d7b3dSmrg		   reverse, upsidedown);
321428d7b3dSmrg}
322