1/*
2 * Copyright © 1998 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_DIX_CONFIG_H
24#include <dix-config.h>
25#endif
26
27#include "fb.h"
28
29#ifndef FBNOPIXADDR
30/*
31 * This is a slight abuse of the preprocessor to generate repetitive
32 * code, the idea is to generate code for each case of a copy-mode
33 * transparent stipple
34 */
35#define LaneCases1(c,a)	    case c: \
36				while (n--) { FbLaneCase(c,a); a++; } \
37				break
38#define LaneCases2(c,a)	    LaneCases1(c,a); LaneCases1(c+1,a)
39#define LaneCases4(c,a)	    LaneCases2(c,a); LaneCases2(c+2,a)
40#define LaneCases8(c,a)	    LaneCases4(c,a); LaneCases4(c+4,a)
41#define LaneCases16(c,a)    LaneCases8(c,a); LaneCases8(c+8,a)
42#define LaneCases32(c,a)    LaneCases16(c,a); LaneCases16(c+16,a)
43#define LaneCases64(c,a)    LaneCases32(c,a); LaneCases32(c+32,a)
44#define LaneCases128(c,a)   LaneCases64(c,a); LaneCases64(c+64,a)
45#define LaneCases256(c,a)   LaneCases128(c,a); LaneCases128(c+128,a)
46
47#if FB_SHIFT == 6
48#define LaneCases(a)	    LaneCases256(0,a)
49#endif
50
51#if FB_SHIFT == 5
52#define LaneCases(a)	    LaneCases16(0,a)
53#endif
54
55/*
56 * Repeat a transparent stipple across a scanline n times
57 */
58
59void
60fbTransparentSpan (FbBits   *dst,
61		   FbBits   stip,
62		   FbBits   fgxor,
63		   int	    n)
64{
65    FbStip  s;
66
67    s  = ((FbStip) (stip      ) & 0x01);
68    s |= ((FbStip) (stip >>  8) & 0x02);
69    s |= ((FbStip) (stip >> 16) & 0x04);
70    s |= ((FbStip) (stip >> 24) & 0x08);
71#if FB_SHIFT > 5
72    s |= ((FbStip) (stip >> 32) & 0x10);
73    s |= ((FbStip) (stip >> 40) & 0x20);
74    s |= ((FbStip) (stip >> 48) & 0x40);
75    s |= ((FbStip) (stip >> 56) & 0x80);
76#endif
77    switch (s) {
78	LaneCases(dst);
79    }
80}
81#endif
82
83void
84fbEvenStipple (FbBits	*dst,
85	       FbStride	dstStride,
86	       int	dstX,
87	       int	dstBpp,
88
89	       int	width,
90	       int	height,
91
92	       FbStip	*stip,
93	       FbStride	stipStride,
94	       int	stipHeight,
95
96	       FbBits	fgand,
97	       FbBits	fgxor,
98	       FbBits	bgand,
99	       FbBits	bgxor,
100
101	       int	xRot,
102	       int	yRot)
103{
104    FbBits	startmask, endmask;
105    FbBits	mask, and, xor;
106    int		nmiddle, n;
107    FbStip	*s, *stipEnd, bits;
108    int		rot, stipX, stipY;
109    int		pixelsPerDst;
110    const FbBits    *fbBits;
111    Bool	transparent;
112    int		startbyte, endbyte;
113
114    /*
115     * Check for a transparent stipple (stencil)
116     */
117    transparent = FALSE;
118    if (dstBpp >= 8 &&
119	fgand == 0 && bgand == FB_ALLONES && bgxor == 0)
120	transparent = TRUE;
121
122    pixelsPerDst = FB_UNIT / dstBpp;
123    /*
124     * Adjust dest pointers
125     */
126    dst += dstX >> FB_SHIFT;
127    dstX &= FB_MASK;
128    FbMaskBitsBytes (dstX, width, fgand == 0 && bgand == 0,
129		     startmask, startbyte, nmiddle, endmask, endbyte);
130
131    if (startmask)
132	dstStride--;
133    dstStride -= nmiddle;
134
135    xRot *= dstBpp;
136    /*
137     * Compute stip start scanline and rotation parameters
138     */
139    stipEnd = stip + stipStride * stipHeight;
140    modulus (- yRot, stipHeight, stipY);
141    s = stip + stipStride * stipY;
142    modulus (- xRot, FB_UNIT, stipX);
143    rot = stipX;
144
145    /*
146     * Get pointer to stipple mask array for this depth
147     */
148    /* fbStippleTable covers all valid bpp (4,8,16,32) */
149    fbBits = fbStippleTable[pixelsPerDst];
150
151    while (height--)
152    {
153	/*
154	 * Extract stipple bits for this scanline;
155	 */
156	bits = READ(s);
157	s += stipStride;
158	if (s == stipEnd)
159	    s = stip;
160#if FB_UNIT > 32
161	if (pixelsPerDst == 16)
162	    mask = FbStipple16Bits(FbLeftStipBits(bits,16));
163	else
164#endif
165	    mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)];
166	/*
167	 * Rotate into position and compute reduced rop values
168	 */
169	mask = FbRotLeft(mask, rot);
170	and = (fgand & mask) | (bgand & ~mask);
171	xor = (fgxor & mask) | (bgxor & ~mask);
172
173#ifndef FBNOPIXADDR
174	if (transparent)
175	{
176	    if (startmask)
177	    {
178		fbTransparentSpan(dst, mask&startmask, fgxor, 1);
179		dst++;
180	    }
181	    fbTransparentSpan (dst, mask, fgxor, nmiddle);
182	    dst += nmiddle;
183	    if (endmask)
184		fbTransparentSpan(dst, mask&endmask, fgxor, 1);
185	}
186	else
187#endif
188	{
189	    /*
190	     * Fill scanline
191	     */
192	    if (startmask)
193	    {
194		FbDoLeftMaskByteRRop (dst, startbyte, startmask, and, xor);
195		dst++;
196	    }
197	    n = nmiddle;
198	    if (!and)
199		while (n--)
200		    WRITE(dst++, xor);
201	    else
202	    {
203		while (n--)
204		{
205		    WRITE(dst, FbDoRRop (READ(dst), and, xor));
206		    dst++;
207		}
208	    }
209	    if (endmask)
210		FbDoRightMaskByteRRop(dst, endbyte, endmask, and, xor);
211	}
212	dst += dstStride;
213    }
214}
215
216void
217fbOddStipple (FbBits	*dst,
218	      FbStride	dstStride,
219	      int	dstX,
220	      int	dstBpp,
221
222	      int	width,
223	      int	height,
224
225	      FbStip	*stip,
226	      FbStride	stipStride,
227	      int	stipWidth,
228	      int	stipHeight,
229
230	      FbBits	fgand,
231	      FbBits	fgxor,
232	      FbBits	bgand,
233	      FbBits	bgxor,
234
235	      int	xRot,
236	      int	yRot)
237{
238    int		stipX, stipY, sx;
239    int		widthTmp;
240    int		h, w;
241    int		x, y;
242
243    modulus (- yRot, stipHeight, stipY);
244    modulus (dstX / dstBpp - xRot, stipWidth, stipX);
245    y = 0;
246    while (height)
247    {
248	h = stipHeight - stipY;
249	if (h > height)
250	    h = height;
251	height -= h;
252	widthTmp = width;
253	x = dstX;
254	sx = stipX;
255	while (widthTmp)
256	{
257	    w = (stipWidth - sx) * dstBpp;
258	    if (w > widthTmp)
259		w = widthTmp;
260	    widthTmp -= w;
261	    fbBltOne (stip + stipY * stipStride,
262		      stipStride,
263		      sx,
264
265		      dst + y * dstStride,
266		      dstStride,
267		      x,
268		      dstBpp,
269
270		      w, h,
271
272		      fgand, fgxor, bgand, bgxor);
273	    x += w;
274	    sx = 0;
275	}
276	y += h;
277	stipY = 0;
278    }
279}
280
281void
282fbStipple (FbBits	*dst,
283	   FbStride	dstStride,
284	   int		dstX,
285	   int		dstBpp,
286
287	   int		width,
288	   int		height,
289
290	   FbStip	*stip,
291	   FbStride	stipStride,
292	   int		stipWidth,
293	   int		stipHeight,
294	   Bool		even,
295
296	   FbBits	fgand,
297	   FbBits	fgxor,
298	   FbBits	bgand,
299	   FbBits	bgxor,
300
301	   int		xRot,
302	   int		yRot)
303{
304    if (even)
305	fbEvenStipple (dst, dstStride, dstX, dstBpp, width, height,
306		       stip, stipStride, stipHeight,
307		       fgand, fgxor, bgand, bgxor, xRot, yRot);
308    else
309	fbOddStipple (dst, dstStride, dstX, dstBpp, width, height,
310		      stip, stipStride, stipWidth, stipHeight,
311		      fgand, fgxor, bgand, bgxor, xRot, yRot);
312}
313