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/*
27428d7b3dSmrg * This is a slight abuse of the preprocessor to generate repetitive
28428d7b3dSmrg * code, the idea is to generate code for each case of a copy-mode
29428d7b3dSmrg * transparent stipple
30428d7b3dSmrg */
31428d7b3dSmrg#define LaneCases1(c,a) \
32428d7b3dSmrg	case c: while (n--) { FbLaneCase(c,a); a++; } break
33428d7b3dSmrg#define LaneCases2(c,a)	    LaneCases1(c,a); LaneCases1(c+1,a)
34428d7b3dSmrg#define LaneCases4(c,a)	    LaneCases2(c,a); LaneCases2(c+2,a)
35428d7b3dSmrg#define LaneCases8(c,a)	    LaneCases4(c,a); LaneCases4(c+4,a)
36428d7b3dSmrg#define LaneCases16(c,a)    LaneCases8(c,a); LaneCases8(c+8,a)
37428d7b3dSmrg
38428d7b3dSmrg#define LaneCases(a)	    LaneCases16(0,a)
39428d7b3dSmrg
40428d7b3dSmrg/*
41428d7b3dSmrg * Repeat a transparent stipple across a scanline n times
42428d7b3dSmrg */
43428d7b3dSmrg
44428d7b3dSmrgvoid
45428d7b3dSmrgfbTransparentSpan(FbBits * dst, FbBits stip, FbBits fgxor, int n)
46428d7b3dSmrg{
47428d7b3dSmrg	FbStip s;
48428d7b3dSmrg
49428d7b3dSmrg	s = ((FbStip) (stip) & 0x01);
50428d7b3dSmrg	s |= ((FbStip) (stip >> 8) & 0x02);
51428d7b3dSmrg	s |= ((FbStip) (stip >> 16) & 0x04);
52428d7b3dSmrg	s |= ((FbStip) (stip >> 24) & 0x08);
53428d7b3dSmrg	switch (s) {
54428d7b3dSmrg		LaneCases(dst);
55428d7b3dSmrg	}
56428d7b3dSmrg}
57428d7b3dSmrg
58428d7b3dSmrgstatic void
59428d7b3dSmrgfbEvenStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
60428d7b3dSmrg              int width, int height,
61428d7b3dSmrg              FbStip *stip, FbStride stipStride,
62428d7b3dSmrg              int stipHeight,
63428d7b3dSmrg              FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
64428d7b3dSmrg	      int xRot, int yRot)
65428d7b3dSmrg{
66428d7b3dSmrg	FbBits startmask, endmask;
67428d7b3dSmrg	FbBits mask, and, xor;
68428d7b3dSmrg	int nmiddle, n;
69428d7b3dSmrg	FbStip *s, *stipEnd, bits;
70428d7b3dSmrg	int rot, stipX, stipY;
71428d7b3dSmrg	int pixelsPerDst;
72428d7b3dSmrg	const FbBits *fbBits;
73428d7b3dSmrg	Bool transparent;
74428d7b3dSmrg	int startbyte, endbyte;
75428d7b3dSmrg
76428d7b3dSmrg	/*
77428d7b3dSmrg	 * Check for a transparent stipple (stencil)
78428d7b3dSmrg	 */
79428d7b3dSmrg	transparent = FALSE;
80428d7b3dSmrg	if (dstBpp >= 8 && fgand == 0 && bgand == FB_ALLONES && bgxor == 0)
81428d7b3dSmrg		transparent = TRUE;
82428d7b3dSmrg
83428d7b3dSmrg	pixelsPerDst = FB_UNIT / dstBpp;
84428d7b3dSmrg	/*
85428d7b3dSmrg	 * Adjust dest pointers
86428d7b3dSmrg	 */
87428d7b3dSmrg	dst += dstX >> FB_SHIFT;
88428d7b3dSmrg	dstX &= FB_MASK;
89428d7b3dSmrg	FbMaskBitsBytes(dstX, width, fgand == 0 && bgand == 0,
90428d7b3dSmrg			startmask, startbyte, nmiddle, endmask, endbyte);
91428d7b3dSmrg
92428d7b3dSmrg	if (startmask)
93428d7b3dSmrg		dstStride--;
94428d7b3dSmrg	dstStride -= nmiddle;
95428d7b3dSmrg
96428d7b3dSmrg	xRot *= dstBpp;
97428d7b3dSmrg	/*
98428d7b3dSmrg	 * Compute stip start scanline and rotation parameters
99428d7b3dSmrg	 */
100428d7b3dSmrg	stipEnd = stip + stipStride * stipHeight;
101428d7b3dSmrg	modulus(-yRot, stipHeight, stipY);
102428d7b3dSmrg	s = stip + stipStride * stipY;
103428d7b3dSmrg	modulus(-xRot, FB_UNIT, stipX);
104428d7b3dSmrg	rot = stipX;
105428d7b3dSmrg
106428d7b3dSmrg	/*
107428d7b3dSmrg	 * Get pointer to stipple mask array for this depth
108428d7b3dSmrg	 */
109428d7b3dSmrg	/* fbStippleTable covers all valid bpp (4,8,16,32) */
110428d7b3dSmrg	fbBits = fbStippleTable[pixelsPerDst];
111428d7b3dSmrg
112428d7b3dSmrg	while (height--) {
113428d7b3dSmrg		/*
114428d7b3dSmrg		 * Extract stipple bits for this scanline;
115428d7b3dSmrg		 */
116428d7b3dSmrg		bits = READ(s);
117428d7b3dSmrg		s += stipStride;
118428d7b3dSmrg		if (s == stipEnd)
119428d7b3dSmrg			s = stip;
120428d7b3dSmrg		mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
121428d7b3dSmrg		/*
122428d7b3dSmrg		 * Rotate into position and compute reduced rop values
123428d7b3dSmrg		 */
124428d7b3dSmrg		mask = FbRotLeft(mask, rot);
125428d7b3dSmrg		and = (fgand & mask) | (bgand & ~mask);
126428d7b3dSmrg		xor = (fgxor & mask) | (bgxor & ~mask);
127428d7b3dSmrg
128428d7b3dSmrg		if (transparent) {
129428d7b3dSmrg			if (startmask) {
130428d7b3dSmrg				fbTransparentSpan(dst, mask & startmask, fgxor, 1);
131428d7b3dSmrg				dst++;
132428d7b3dSmrg			}
133428d7b3dSmrg			fbTransparentSpan(dst, mask, fgxor, nmiddle);
134428d7b3dSmrg			dst += nmiddle;
135428d7b3dSmrg			if (endmask)
136428d7b3dSmrg				fbTransparentSpan(dst, mask & endmask, fgxor, 1);
137428d7b3dSmrg		} else {
138428d7b3dSmrg			/*
139428d7b3dSmrg			 * Fill scanline
140428d7b3dSmrg			 */
141428d7b3dSmrg			if (startmask) {
142428d7b3dSmrg				FbDoLeftMaskByteRRop(dst, startbyte, startmask, and, xor);
143428d7b3dSmrg				dst++;
144428d7b3dSmrg			}
145428d7b3dSmrg			n = nmiddle;
146428d7b3dSmrg			if (!and)
147428d7b3dSmrg				while (n--)
148428d7b3dSmrg					WRITE(dst++, xor);
149428d7b3dSmrg			else {
150428d7b3dSmrg				while (n--) {
151428d7b3dSmrg					WRITE(dst, FbDoRRop(READ(dst), and, xor));
152428d7b3dSmrg					dst++;
153428d7b3dSmrg				}
154428d7b3dSmrg			}
155428d7b3dSmrg			if (endmask)
156428d7b3dSmrg				FbDoRightMaskByteRRop(dst, endbyte, endmask, and, xor);
157428d7b3dSmrg		}
158428d7b3dSmrg		dst += dstStride;
159428d7b3dSmrg	}
160428d7b3dSmrg}
161428d7b3dSmrg
162428d7b3dSmrgstatic void
163428d7b3dSmrgfbOddStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
164428d7b3dSmrg             int width, int height,
165428d7b3dSmrg             FbStip *stip, FbStride stipStride,
166428d7b3dSmrg             int stipWidth, int stipHeight,
167428d7b3dSmrg             FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
168428d7b3dSmrg	     int xRot, int yRot)
169428d7b3dSmrg{
170428d7b3dSmrg	int stipX, stipY, sx;
171428d7b3dSmrg	int widthTmp;
172428d7b3dSmrg	int h, w;
173428d7b3dSmrg	int x, y;
174428d7b3dSmrg
175428d7b3dSmrg	modulus(-yRot, stipHeight, stipY);
176428d7b3dSmrg	modulus(dstX / dstBpp - xRot, stipWidth, stipX);
177428d7b3dSmrg	y = 0;
178428d7b3dSmrg	while (height) {
179428d7b3dSmrg		h = stipHeight - stipY;
180428d7b3dSmrg		if (h > height)
181428d7b3dSmrg			h = height;
182428d7b3dSmrg		height -= h;
183428d7b3dSmrg		widthTmp = width;
184428d7b3dSmrg		x = dstX;
185428d7b3dSmrg		sx = stipX;
186428d7b3dSmrg		while (widthTmp) {
187428d7b3dSmrg			w = (stipWidth - sx) * dstBpp;
188428d7b3dSmrg			if (w > widthTmp)
189428d7b3dSmrg				w = widthTmp;
190428d7b3dSmrg			widthTmp -= w;
191428d7b3dSmrg			fbBltOne(stip + stipY * stipStride,
192428d7b3dSmrg				 stipStride,
193428d7b3dSmrg				 sx,
194428d7b3dSmrg				 dst + y * dstStride,
195428d7b3dSmrg				 dstStride, x, dstBpp, w, h, fgand, fgxor, bgand, bgxor);
196428d7b3dSmrg			x += w;
197428d7b3dSmrg			sx = 0;
198428d7b3dSmrg		}
199428d7b3dSmrg		y += h;
200428d7b3dSmrg		stipY = 0;
201428d7b3dSmrg	}
202428d7b3dSmrg}
203428d7b3dSmrg
204428d7b3dSmrgvoid
205428d7b3dSmrgfbStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
206428d7b3dSmrg          int width, int height,
207428d7b3dSmrg          FbStip *stip, FbStride stipStride,
208428d7b3dSmrg          int stipWidth, int stipHeight, Bool even,
209428d7b3dSmrg          FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
210428d7b3dSmrg	  int xRot, int yRot)
211428d7b3dSmrg{
212428d7b3dSmrg	DBG(("%s stipple=%dx%d, size=%dx%d\n",
213428d7b3dSmrg	     __FUNCTION__, stipWidth, stipHeight, width, height));
214428d7b3dSmrg
215428d7b3dSmrg	if (even)
216428d7b3dSmrg		fbEvenStipple(dst, dstStride, dstX, dstBpp, width, height,
217428d7b3dSmrg			      stip, stipStride, stipHeight,
218428d7b3dSmrg			      fgand, fgxor, bgand, bgxor, xRot, yRot);
219428d7b3dSmrg	else
220428d7b3dSmrg		fbOddStipple(dst, dstStride, dstX, dstBpp, width, height,
221428d7b3dSmrg			     stip, stipStride, stipWidth, stipHeight,
222428d7b3dSmrg			     fgand, fgxor, bgand, bgxor, xRot, yRot);
223428d7b3dSmrg}
224