1706f2543Smrg/*
2706f2543Smrg * Copyright © 1998 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that
7706f2543Smrg * copyright notice and this permission notice appear in supporting
8706f2543Smrg * documentation, and that the name of Keith Packard not be used in
9706f2543Smrg * advertising or publicity pertaining to distribution of the software without
10706f2543Smrg * specific, written prior permission.  Keith Packard makes no
11706f2543Smrg * representations about the suitability of this software for any purpose.  It
12706f2543Smrg * is provided "as is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
24706f2543Smrg#include <dix-config.h>
25706f2543Smrg#endif
26706f2543Smrg
27706f2543Smrg#include "fb.h"
28706f2543Smrg
29706f2543Smrg/*
30706f2543Smrg *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
31706f2543Smrg *
32706f2543Smrg *	**** **** **** **** **** **** **** ****
33706f2543Smrg *			^
34706f2543Smrg *	********  ********  ********  ********
35706f2543Smrg *		  ^
36706f2543Smrg *  leftShift = 12
37706f2543Smrg *  rightShift = 20
38706f2543Smrg *
39706f2543Smrg *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
40706f2543Smrg *
41706f2543Smrg *	**** **** **** **** **** **** **** ****
42706f2543Smrg *	^
43706f2543Smrg *	********  ********  ********  ********
44706f2543Smrg *		  ^
45706f2543Smrg *
46706f2543Smrg *  leftShift = 24
47706f2543Smrg *  rightShift = 8
48706f2543Smrg */
49706f2543Smrg
50706f2543Smrg#define LoadBits {\
51706f2543Smrg    if (leftShift) { \
52706f2543Smrg	bitsRight = (src < srcEnd ? READ(src++) : 0); \
53706f2543Smrg	bits = (FbStipLeft (bitsLeft, leftShift) | \
54706f2543Smrg		FbStipRight(bitsRight, rightShift)); \
55706f2543Smrg	bitsLeft = bitsRight; \
56706f2543Smrg    } else \
57706f2543Smrg	bits = (src < srcEnd ? READ(src++) : 0); \
58706f2543Smrg}
59706f2543Smrg
60706f2543Smrg#ifndef FBNOPIXADDR
61706f2543Smrg
62706f2543Smrg#define LaneCases1(n,a)	    case n: FbLaneCase(n,a); break
63706f2543Smrg#define LaneCases2(n,a)	    LaneCases1(n,a); LaneCases1(n+1,a)
64706f2543Smrg#define LaneCases4(n,a)	    LaneCases2(n,a); LaneCases2(n+2,a)
65706f2543Smrg#define LaneCases8(n,a)	    LaneCases4(n,a); LaneCases4(n+4,a)
66706f2543Smrg#define LaneCases16(n,a)    LaneCases8(n,a); LaneCases8(n+8,a)
67706f2543Smrg#define LaneCases32(n,a)    LaneCases16(n,a); LaneCases16(n+16,a)
68706f2543Smrg#define LaneCases64(n,a)    LaneCases32(n,a); LaneCases32(n+32,a)
69706f2543Smrg#define LaneCases128(n,a)   LaneCases64(n,a); LaneCases64(n+64,a)
70706f2543Smrg#define LaneCases256(n,a)   LaneCases128(n,a); LaneCases128(n+128,a)
71706f2543Smrg
72706f2543Smrg#if FB_SHIFT == 6
73706f2543Smrg#define LaneCases(a)	    LaneCases256(0,a)
74706f2543Smrg#endif
75706f2543Smrg
76706f2543Smrg#if FB_SHIFT == 5
77706f2543Smrg#define LaneCases(a)	    LaneCases16(0,a)
78706f2543Smrg#endif
79706f2543Smrg
80706f2543Smrg#if FB_SHIFT == 6
81706f2543SmrgCARD8	fb8Lane[256] = {
82706f2543Smrg0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
83706f2543Smrg22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
84706f2543Smrg41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
85706f2543Smrg60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
86706f2543Smrg79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
87706f2543Smrg98, 99, 100, 101, 102,103,104,105,106,107,108,109,110,111,112,113,114,115,
88706f2543Smrg116, 117, 118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,
89706f2543Smrg134, 135, 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,
90706f2543Smrg152, 153, 154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,
91706f2543Smrg170, 171, 172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,
92706f2543Smrg188, 189, 190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,
93706f2543Smrg206, 207, 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
94706f2543Smrg224, 225, 226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,
95706f2543Smrg242, 243, 244,245,246,247,248,249,250,251,252,253,254,255,
96706f2543Smrg};
97706f2543Smrg
98706f2543SmrgCARD8	fb16Lane[256] = {
99706f2543Smrg    0x00, 0x03, 0x0c, 0x0f,
100706f2543Smrg    0x30, 0x33, 0x3c, 0x3f,
101706f2543Smrg    0xc0, 0xc3, 0xcc, 0xcf,
102706f2543Smrg    0xf0, 0xf3, 0xfc, 0xff,
103706f2543Smrg};
104706f2543Smrg
105706f2543SmrgCARD8	fb32Lane[16] = {
106706f2543Smrg    0x00, 0x0f, 0xf0, 0xff,
107706f2543Smrg};
108706f2543Smrg#endif
109706f2543Smrg
110706f2543Smrg#if FB_SHIFT == 5
111706f2543SmrgCARD8	fb8Lane[16] = {
112706f2543Smrg    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
113706f2543Smrg};
114706f2543Smrg
115706f2543SmrgCARD8	fb16Lane[16] = {
116706f2543Smrg    0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117706f2543Smrg};
118706f2543Smrg
119706f2543SmrgCARD8	fb32Lane[16] = {
120706f2543Smrg    0, 15,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121706f2543Smrg};
122706f2543Smrg#endif
123706f2543Smrg
124706f2543SmrgCARD8	*fbLaneTable[33] = {
125706f2543Smrg    0, 0, 0, 0, 0, 0, 0, 0,
126706f2543Smrg    fb8Lane,  0, 0, 0, 0, 0, 0, 0,
127706f2543Smrg    fb16Lane, 0, 0, 0, 0, 0, 0, 0,
128706f2543Smrg    0, 0, 0, 0, 0, 0, 0, 0,
129706f2543Smrg    fb32Lane
130706f2543Smrg};
131706f2543Smrg#endif
132706f2543Smrg
133706f2543Smrgvoid
134706f2543SmrgfbBltOne (FbStip    *src,
135706f2543Smrg	  FbStride  srcStride,	    /* FbStip units per scanline */
136706f2543Smrg	  int	    srcX,	    /* bit position of source */
137706f2543Smrg	  FbBits    *dst,
138706f2543Smrg	  FbStride  dstStride,	    /* FbBits units per scanline */
139706f2543Smrg	  int	    dstX,	    /* bit position of dest */
140706f2543Smrg	  int	    dstBpp,	    /* bits per destination unit */
141706f2543Smrg
142706f2543Smrg	  int	    width,	    /* width in bits of destination */
143706f2543Smrg	  int	    height,	    /* height in scanlines */
144706f2543Smrg
145706f2543Smrg	  FbBits    fgand,	    /* rrop values */
146706f2543Smrg	  FbBits    fgxor,
147706f2543Smrg	  FbBits    bgand,
148706f2543Smrg	  FbBits    bgxor)
149706f2543Smrg{
150706f2543Smrg    const FbBits    *fbBits;
151706f2543Smrg    FbBits	    *srcEnd;
152706f2543Smrg    int		    pixelsPerDst;		/* dst pixels per FbBits */
153706f2543Smrg    int		    unitsPerSrc;		/* src patterns per FbStip */
154706f2543Smrg    int		    leftShift, rightShift;	/* align source with dest */
155706f2543Smrg    FbBits	    startmask, endmask;		/* dest scanline masks */
156706f2543Smrg    FbStip	    bits=0, bitsLeft, bitsRight;/* source bits */
157706f2543Smrg    FbStip	    left;
158706f2543Smrg    FbBits	    mask;
159706f2543Smrg    int		    nDst;			/* dest longwords (w.o. end) */
160706f2543Smrg    int		    w;
161706f2543Smrg    int		    n, nmiddle;
162706f2543Smrg    int		    dstS;			/* stipple-relative dst X coordinate */
163706f2543Smrg    Bool	    copy;			/* accelerate dest-invariant */
164706f2543Smrg    Bool	    transparent;		/* accelerate 0 nop */
165706f2543Smrg    int		    srcinc;			/* source units consumed */
166706f2543Smrg    Bool	    endNeedsLoad = FALSE;	/* need load for endmask */
167706f2543Smrg#ifndef FBNOPIXADDR
168706f2543Smrg    CARD8	    *fbLane;
169706f2543Smrg#endif
170706f2543Smrg    int		    startbyte, endbyte;
171706f2543Smrg
172706f2543Smrg#ifdef FB_24BIT
173706f2543Smrg    if (dstBpp == 24)
174706f2543Smrg    {
175706f2543Smrg	fbBltOne24 (src, srcStride, srcX,
176706f2543Smrg		    dst, dstStride, dstX, dstBpp,
177706f2543Smrg		    width, height,
178706f2543Smrg		    fgand, fgxor, bgand, bgxor);
179706f2543Smrg	return;
180706f2543Smrg    }
181706f2543Smrg#endif
182706f2543Smrg
183706f2543Smrg    /*
184706f2543Smrg     * Do not read past the end of the buffer!
185706f2543Smrg     */
186706f2543Smrg    srcEnd = src + height * srcStride;
187706f2543Smrg
188706f2543Smrg    /*
189706f2543Smrg     * Number of destination units in FbBits == number of stipple pixels
190706f2543Smrg     * used each time
191706f2543Smrg     */
192706f2543Smrg    pixelsPerDst = FB_UNIT / dstBpp;
193706f2543Smrg
194706f2543Smrg    /*
195706f2543Smrg     * Number of source stipple patterns in FbStip
196706f2543Smrg     */
197706f2543Smrg    unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
198706f2543Smrg
199706f2543Smrg    copy = FALSE;
200706f2543Smrg    transparent = FALSE;
201706f2543Smrg    if (bgand == 0 && fgand == 0)
202706f2543Smrg	copy = TRUE;
203706f2543Smrg    else if (bgand == FB_ALLONES && bgxor == 0)
204706f2543Smrg	transparent = TRUE;
205706f2543Smrg
206706f2543Smrg    /*
207706f2543Smrg     * Adjust source and dest to nearest FbBits boundary
208706f2543Smrg     */
209706f2543Smrg    src += srcX >> FB_STIP_SHIFT;
210706f2543Smrg    dst += dstX >> FB_SHIFT;
211706f2543Smrg    srcX &= FB_STIP_MASK;
212706f2543Smrg    dstX &= FB_MASK;
213706f2543Smrg
214706f2543Smrg    FbMaskBitsBytes(dstX, width, copy,
215706f2543Smrg		    startmask, startbyte, nmiddle, endmask, endbyte);
216706f2543Smrg
217706f2543Smrg    /*
218706f2543Smrg     * Compute effective dest alignment requirement for
219706f2543Smrg     * source -- must align source to dest unit boundary
220706f2543Smrg     */
221706f2543Smrg    dstS = dstX / dstBpp;
222706f2543Smrg    /*
223706f2543Smrg     * Compute shift constants for effective alignement
224706f2543Smrg     */
225706f2543Smrg    if (srcX >= dstS)
226706f2543Smrg    {
227706f2543Smrg	leftShift = srcX - dstS;
228706f2543Smrg	rightShift = FB_STIP_UNIT - leftShift;
229706f2543Smrg    }
230706f2543Smrg    else
231706f2543Smrg    {
232706f2543Smrg	rightShift = dstS - srcX;
233706f2543Smrg	leftShift = FB_STIP_UNIT - rightShift;
234706f2543Smrg    }
235706f2543Smrg    /*
236706f2543Smrg     * Get pointer to stipple mask array for this depth
237706f2543Smrg     */
238706f2543Smrg    fbBits = 0;	/* unused */
239706f2543Smrg    if (pixelsPerDst <= 8)
240706f2543Smrg	fbBits = fbStippleTable[pixelsPerDst];
241706f2543Smrg#ifndef FBNOPIXADDR
242706f2543Smrg    fbLane = 0;
243706f2543Smrg    if (transparent && fgand == 0 && dstBpp >= 8)
244706f2543Smrg	fbLane = fbLaneTable[dstBpp];
245706f2543Smrg#endif
246706f2543Smrg
247706f2543Smrg    /*
248706f2543Smrg     * Compute total number of destination words written, but
249706f2543Smrg     * don't count endmask
250706f2543Smrg     */
251706f2543Smrg    nDst = nmiddle;
252706f2543Smrg    if (startmask)
253706f2543Smrg	nDst++;
254706f2543Smrg
255706f2543Smrg    dstStride -= nDst;
256706f2543Smrg
257706f2543Smrg    /*
258706f2543Smrg     * Compute total number of source words consumed
259706f2543Smrg     */
260706f2543Smrg
261706f2543Smrg    srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
262706f2543Smrg
263706f2543Smrg    if (srcX > dstS)
264706f2543Smrg	srcinc++;
265706f2543Smrg    if (endmask)
266706f2543Smrg    {
267706f2543Smrg	endNeedsLoad = nDst % unitsPerSrc == 0;
268706f2543Smrg	if (endNeedsLoad)
269706f2543Smrg	    srcinc++;
270706f2543Smrg    }
271706f2543Smrg
272706f2543Smrg    srcStride -= srcinc;
273706f2543Smrg
274706f2543Smrg    /*
275706f2543Smrg     * Copy rectangle
276706f2543Smrg     */
277706f2543Smrg    while (height--)
278706f2543Smrg    {
279706f2543Smrg	w = nDst;	    /* total units across scanline */
280706f2543Smrg	n = unitsPerSrc;    /* units avail in single stipple */
281706f2543Smrg	if (n > w)
282706f2543Smrg	    n = w;
283706f2543Smrg
284706f2543Smrg	bitsLeft = 0;
285706f2543Smrg	if (srcX > dstS)
286706f2543Smrg	    bitsLeft = READ(src++);
287706f2543Smrg	if (n)
288706f2543Smrg	{
289706f2543Smrg	    /*
290706f2543Smrg	     * Load first set of stipple bits
291706f2543Smrg	     */
292706f2543Smrg	    LoadBits;
293706f2543Smrg
294706f2543Smrg	    /*
295706f2543Smrg	     * Consume stipple bits for startmask
296706f2543Smrg	     */
297706f2543Smrg	    if (startmask)
298706f2543Smrg	    {
299706f2543Smrg#if FB_UNIT > 32
300706f2543Smrg		if (pixelsPerDst == 16)
301706f2543Smrg		    mask = FbStipple16Bits(FbLeftStipBits(bits,16));
302706f2543Smrg		else
303706f2543Smrg#endif
304706f2543Smrg		    mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)];
305706f2543Smrg#ifndef FBNOPIXADDR
306706f2543Smrg		if (fbLane)
307706f2543Smrg		{
308706f2543Smrg		    fbTransparentSpan (dst, mask & startmask, fgxor, 1);
309706f2543Smrg		}
310706f2543Smrg		else
311706f2543Smrg#endif
312706f2543Smrg		{
313706f2543Smrg		    if (mask || !transparent)
314706f2543Smrg			FbDoLeftMaskByteStippleRRop (dst, mask,
315706f2543Smrg						     fgand, fgxor, bgand, bgxor,
316706f2543Smrg						     startbyte, startmask);
317706f2543Smrg		}
318706f2543Smrg		bits = FbStipLeft (bits, pixelsPerDst);
319706f2543Smrg		dst++;
320706f2543Smrg		n--;
321706f2543Smrg		w--;
322706f2543Smrg	    }
323706f2543Smrg	    /*
324706f2543Smrg	     * Consume stipple bits across scanline
325706f2543Smrg	     */
326706f2543Smrg	    for (;;)
327706f2543Smrg	    {
328706f2543Smrg		w -= n;
329706f2543Smrg		if (copy)
330706f2543Smrg		{
331706f2543Smrg		    while (n--)
332706f2543Smrg		    {
333706f2543Smrg#if FB_UNIT > 32
334706f2543Smrg			if (pixelsPerDst == 16)
335706f2543Smrg			    mask = FbStipple16Bits(FbLeftStipBits(bits,16));
336706f2543Smrg			else
337706f2543Smrg#endif
338706f2543Smrg			    mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)];
339706f2543Smrg			WRITE(dst, FbOpaqueStipple (mask, fgxor, bgxor));
340706f2543Smrg			dst++;
341706f2543Smrg			bits = FbStipLeft(bits, pixelsPerDst);
342706f2543Smrg		    }
343706f2543Smrg		}
344706f2543Smrg		else
345706f2543Smrg		{
346706f2543Smrg#ifndef FBNOPIXADDR
347706f2543Smrg		    if (fbLane)
348706f2543Smrg		    {
349706f2543Smrg			while (bits && n)
350706f2543Smrg			{
351706f2543Smrg			    switch (fbLane[FbLeftStipBits(bits,pixelsPerDst)]) {
352706f2543Smrg				LaneCases((CARD8 *) dst);
353706f2543Smrg			    }
354706f2543Smrg			    bits = FbStipLeft(bits,pixelsPerDst);
355706f2543Smrg			    dst++;
356706f2543Smrg			    n--;
357706f2543Smrg			}
358706f2543Smrg			dst += n;
359706f2543Smrg		    }
360706f2543Smrg		    else
361706f2543Smrg#endif
362706f2543Smrg		    {
363706f2543Smrg			while (n--)
364706f2543Smrg			{
365706f2543Smrg			    left = FbLeftStipBits(bits,pixelsPerDst);
366706f2543Smrg			    if (left || !transparent)
367706f2543Smrg			    {
368706f2543Smrg				mask = fbBits[left];
369706f2543Smrg				WRITE(dst, FbStippleRRop (READ(dst), mask,
370706f2543Smrg						          fgand, fgxor, bgand, bgxor));
371706f2543Smrg			    }
372706f2543Smrg			    dst++;
373706f2543Smrg			    bits = FbStipLeft(bits, pixelsPerDst);
374706f2543Smrg			}
375706f2543Smrg		    }
376706f2543Smrg		}
377706f2543Smrg		if (!w)
378706f2543Smrg		    break;
379706f2543Smrg		/*
380706f2543Smrg		 * Load another set and reset number of available units
381706f2543Smrg		 */
382706f2543Smrg		LoadBits;
383706f2543Smrg		n = unitsPerSrc;
384706f2543Smrg		if (n > w)
385706f2543Smrg		    n = w;
386706f2543Smrg	    }
387706f2543Smrg	}
388706f2543Smrg	/*
389706f2543Smrg	 * Consume stipple bits for endmask
390706f2543Smrg	 */
391706f2543Smrg	if (endmask)
392706f2543Smrg	{
393706f2543Smrg	    if (endNeedsLoad)
394706f2543Smrg	    {
395706f2543Smrg		LoadBits;
396706f2543Smrg	    }
397706f2543Smrg#if FB_UNIT > 32
398706f2543Smrg	    if (pixelsPerDst == 16)
399706f2543Smrg		mask = FbStipple16Bits(FbLeftStipBits(bits,16));
400706f2543Smrg	    else
401706f2543Smrg#endif
402706f2543Smrg		mask = fbBits[FbLeftStipBits(bits,pixelsPerDst)];
403706f2543Smrg#ifndef FBNOPIXADDR
404706f2543Smrg	    if (fbLane)
405706f2543Smrg	    {
406706f2543Smrg		fbTransparentSpan (dst, mask & endmask, fgxor, 1);
407706f2543Smrg	    }
408706f2543Smrg	    else
409706f2543Smrg#endif
410706f2543Smrg	    {
411706f2543Smrg		if (mask || !transparent)
412706f2543Smrg		    FbDoRightMaskByteStippleRRop (dst, mask,
413706f2543Smrg						  fgand, fgxor, bgand, bgxor,
414706f2543Smrg						  endbyte, endmask);
415706f2543Smrg	    }
416706f2543Smrg	}
417706f2543Smrg	dst += dstStride;
418706f2543Smrg	src += srcStride;
419706f2543Smrg    }
420706f2543Smrg}
421706f2543Smrg
422706f2543Smrg#ifdef FB_24BIT
423706f2543Smrg
424706f2543Smrg/*
425706f2543Smrg * Crufty macros to initialize the mask array, most of this
426706f2543Smrg * is to avoid compile-time warnings about shift overflow
427706f2543Smrg */
428706f2543Smrg
429706f2543Smrg#if BITMAP_BIT_ORDER == MSBFirst
430706f2543Smrg#define Mask24Pos(x,r) ((x)*24-(r))
431706f2543Smrg#else
432706f2543Smrg#define Mask24Pos(x,r) ((x)*24-((r) ? 24 - (r) : 0))
433706f2543Smrg#endif
434706f2543Smrg
435706f2543Smrg#define Mask24Neg(x,r)	(Mask24Pos(x,r) < 0 ? -Mask24Pos(x,r) : 0)
436706f2543Smrg#define Mask24Check(x,r)    (Mask24Pos(x,r) < 0 ? 0 : \
437706f2543Smrg			     Mask24Pos(x,r) >= FB_UNIT ? 0 : Mask24Pos(x,r))
438706f2543Smrg
439706f2543Smrg#define Mask24(x,r) (Mask24Pos(x,r) < FB_UNIT ? \
440706f2543Smrg		     (Mask24Pos(x,r) < 0 ? \
441706f2543Smrg		      0xffffffU >> Mask24Neg (x,r) : \
442706f2543Smrg		      0xffffffU << Mask24Check(x,r)) : 0)
443706f2543Smrg
444706f2543Smrg#define SelMask24(b,n,r)	((((b) >> n) & 1) * Mask24(n,r))
445706f2543Smrg
446706f2543Smrg/*
447706f2543Smrg * Untested for MSBFirst or FB_UNIT == 32
448706f2543Smrg */
449706f2543Smrg
450706f2543Smrg#if FB_UNIT == 64
451706f2543Smrg#define C4_24(b,r) \
452706f2543Smrg    (SelMask24(b,0,r) | \
453706f2543Smrg     SelMask24(b,1,r) | \
454706f2543Smrg     SelMask24(b,2,r) | \
455706f2543Smrg     SelMask24(b,3,r))
456706f2543Smrg
457706f2543Smrg#define FbStip24New(rot)    (2 + (rot != 0))
458706f2543Smrg#define FbStip24Len	    4
459706f2543Smrg
460706f2543Smrgconst FbBits	fbStipple24Bits[3][1 << FbStip24Len] = {
461706f2543Smrg    /* rotate 0 */
462706f2543Smrg    {
463706f2543Smrg	C4_24( 0, 0), C4_24( 1, 0), C4_24( 2, 0), C4_24( 3, 0),
464706f2543Smrg	C4_24( 4, 0), C4_24( 5, 0), C4_24( 6, 0), C4_24( 7, 0),
465706f2543Smrg	C4_24( 8, 0), C4_24( 9, 0), C4_24(10, 0), C4_24(11, 0),
466706f2543Smrg	C4_24(12, 0), C4_24(13, 0), C4_24(14, 0), C4_24(15, 0),
467706f2543Smrg    },
468706f2543Smrg    /* rotate 8 */
469706f2543Smrg    {
470706f2543Smrg	C4_24( 0, 8), C4_24( 1, 8), C4_24( 2, 8), C4_24( 3, 8),
471706f2543Smrg	C4_24( 4, 8), C4_24( 5, 8), C4_24( 6, 8), C4_24( 7, 8),
472706f2543Smrg	C4_24( 8, 8), C4_24( 9, 8), C4_24(10, 8), C4_24(11, 8),
473706f2543Smrg	C4_24(12, 8), C4_24(13, 8), C4_24(14, 8), C4_24(15, 8),
474706f2543Smrg    },
475706f2543Smrg    /* rotate 16 */
476706f2543Smrg    {
477706f2543Smrg	C4_24( 0,16), C4_24( 1,16), C4_24( 2,16), C4_24( 3,16),
478706f2543Smrg	C4_24( 4,16), C4_24( 5,16), C4_24( 6,16), C4_24( 7,16),
479706f2543Smrg	C4_24( 8,16), C4_24( 9,16), C4_24(10,16), C4_24(11,16),
480706f2543Smrg	C4_24(12,16), C4_24(13,16), C4_24(14,16), C4_24(15,16),
481706f2543Smrg    }
482706f2543Smrg};
483706f2543Smrg
484706f2543Smrg#endif
485706f2543Smrg
486706f2543Smrg#if FB_UNIT == 32
487706f2543Smrg#define C2_24(b,r)  \
488706f2543Smrg    (SelMask24(b,0,r) | \
489706f2543Smrg     SelMask24(b,1,r))
490706f2543Smrg
491706f2543Smrg#define FbStip24Len	    2
492706f2543Smrg#if BITMAP_BIT_ORDER == MSBFirst
493706f2543Smrg#define FbStip24New(rot)    (1 + (rot == 0))
494706f2543Smrg#else
495706f2543Smrg#define FbStip24New(rot)    (1 + (rot == 8))
496706f2543Smrg#endif
497706f2543Smrg
498706f2543Smrgconst FbBits	fbStipple24Bits[3][1 << FbStip24Len] = {
499706f2543Smrg    /* rotate 0 */
500706f2543Smrg    {
501706f2543Smrg	C2_24( 0, 0), C2_24 ( 1, 0), C2_24 ( 2, 0), C2_24 ( 3, 0),
502706f2543Smrg    },
503706f2543Smrg    /* rotate 8 */
504706f2543Smrg    {
505706f2543Smrg	C2_24( 0, 8), C2_24 ( 1, 8), C2_24 ( 2, 8), C2_24 ( 3, 8),
506706f2543Smrg    },
507706f2543Smrg    /* rotate 16 */
508706f2543Smrg    {
509706f2543Smrg	C2_24( 0,16), C2_24 ( 1,16), C2_24 ( 2,16), C2_24 ( 3,16),
510706f2543Smrg    }
511706f2543Smrg};
512706f2543Smrg#endif
513706f2543Smrg
514706f2543Smrg#if BITMAP_BIT_ORDER == LSBFirst
515706f2543Smrg
516706f2543Smrg#define FbMergeStip24Bits(left, right, new) \
517706f2543Smrg	(FbStipLeft (left, new) | FbStipRight ((right), (FbStip24Len - (new))))
518706f2543Smrg
519706f2543Smrg#define FbMergePartStip24Bits(left, right, llen, rlen) \
520706f2543Smrg	(left | FbStipRight(right, llen))
521706f2543Smrg
522706f2543Smrg#else
523706f2543Smrg
524706f2543Smrg#define FbMergeStip24Bits(left, right, new) \
525706f2543Smrg	((FbStipLeft (left, new) & ((1 << FbStip24Len) - 1)) | right)
526706f2543Smrg
527706f2543Smrg#define FbMergePartStip24Bits(left, right, llen, rlen) \
528706f2543Smrg	(FbStipLeft(left, rlen) | right)
529706f2543Smrg
530706f2543Smrg#endif
531706f2543Smrg
532706f2543Smrg#define fbFirstStipBits(len,stip) {\
533706f2543Smrg    int	__len = (len); \
534706f2543Smrg    if (len <= remain) { \
535706f2543Smrg	stip = FbLeftStipBits(bits, len); \
536706f2543Smrg    } else { \
537706f2543Smrg	stip = FbLeftStipBits(bits, remain); \
538706f2543Smrg	bits = (src < srcEnd ? READ(src++) : 0); \
539706f2543Smrg	__len = (len) - remain; \
540706f2543Smrg	stip = FbMergePartStip24Bits(stip, FbLeftStipBits(bits, __len), \
541706f2543Smrg				     remain, __len); \
542706f2543Smrg	remain = FB_STIP_UNIT; \
543706f2543Smrg    } \
544706f2543Smrg    bits = FbStipLeft (bits, __len); \
545706f2543Smrg    remain -= __len; \
546706f2543Smrg}
547706f2543Smrg
548706f2543Smrg#define fbInitStipBits(offset,len,stip) {\
549706f2543Smrg    bits = FbStipLeft (READ(src++),offset); \
550706f2543Smrg    remain = FB_STIP_UNIT - offset; \
551706f2543Smrg    fbFirstStipBits(len,stip); \
552706f2543Smrg    stip = FbMergeStip24Bits (0, stip, len); \
553706f2543Smrg}
554706f2543Smrg
555706f2543Smrg#define fbNextStipBits(rot,stip) {\
556706f2543Smrg    int	    __new = FbStip24New(rot); \
557706f2543Smrg    FbStip  __right; \
558706f2543Smrg    fbFirstStipBits(__new, __right); \
559706f2543Smrg    stip = FbMergeStip24Bits (stip, __right, __new); \
560706f2543Smrg    rot = FbNext24Rot (rot); \
561706f2543Smrg}
562706f2543Smrg
563706f2543Smrg/*
564706f2543Smrg * Use deep mask tables that incorporate rotation, pull
565706f2543Smrg * a variable number of bits out of the stipple and
566706f2543Smrg * reuse the right bits as needed for the next write
567706f2543Smrg *
568706f2543Smrg * Yes, this is probably too much code, but most 24-bpp screens
569706f2543Smrg * have no acceleration so this code is used for stipples, copyplane
570706f2543Smrg * and text
571706f2543Smrg */
572706f2543Smrgvoid
573706f2543SmrgfbBltOne24 (FbStip	*srcLine,
574706f2543Smrg	    FbStride	srcStride,  /* FbStip units per scanline */
575706f2543Smrg	    int		srcX,	    /* bit position of source */
576706f2543Smrg	    FbBits	*dst,
577706f2543Smrg	    FbStride	dstStride,  /* FbBits units per scanline */
578706f2543Smrg	    int		dstX,	    /* bit position of dest */
579706f2543Smrg	    int		dstBpp,	    /* bits per destination unit */
580706f2543Smrg
581706f2543Smrg	    int		width,	    /* width in bits of destination */
582706f2543Smrg	    int		height,	    /* height in scanlines */
583706f2543Smrg
584706f2543Smrg	    FbBits	fgand,	    /* rrop values */
585706f2543Smrg	    FbBits	fgxor,
586706f2543Smrg	    FbBits	bgand,
587706f2543Smrg	    FbBits	bgxor)
588706f2543Smrg{
589706f2543Smrg    FbStip	*src, *srcEnd;
590706f2543Smrg    FbBits	leftMask, rightMask, mask;
591706f2543Smrg    int		nlMiddle, nl;
592706f2543Smrg    FbStip	stip, bits;
593706f2543Smrg    int		remain;
594706f2543Smrg    int		dstS;
595706f2543Smrg    int		firstlen;
596706f2543Smrg    int		rot0, rot;
597706f2543Smrg    int		nDst;
598706f2543Smrg
599706f2543Smrg    /*
600706f2543Smrg     * Do not read past the end of the buffer!
601706f2543Smrg     */
602706f2543Smrg    srcEnd = srcLine + height * srcStride;
603706f2543Smrg
604706f2543Smrg    srcLine += srcX >> FB_STIP_SHIFT;
605706f2543Smrg    dst += dstX >> FB_SHIFT;
606706f2543Smrg    srcX &= FB_STIP_MASK;
607706f2543Smrg    dstX &= FB_MASK;
608706f2543Smrg    rot0 = FbFirst24Rot (dstX);
609706f2543Smrg
610706f2543Smrg    FbMaskBits (dstX, width, leftMask, nlMiddle, rightMask);
611706f2543Smrg
612706f2543Smrg    dstS = (dstX + 23) / 24;
613706f2543Smrg    firstlen = FbStip24Len - dstS;
614706f2543Smrg
615706f2543Smrg    nDst = nlMiddle;
616706f2543Smrg    if (leftMask)
617706f2543Smrg	nDst++;
618706f2543Smrg    dstStride -= nDst;
619706f2543Smrg
620706f2543Smrg    /* opaque copy */
621706f2543Smrg    if (bgand == 0 && fgand == 0)
622706f2543Smrg    {
623706f2543Smrg	while (height--)
624706f2543Smrg	{
625706f2543Smrg	    rot = rot0;
626706f2543Smrg	    src = srcLine;
627706f2543Smrg	    srcLine += srcStride;
628706f2543Smrg	    fbInitStipBits (srcX,firstlen, stip);
629706f2543Smrg	    if (leftMask)
630706f2543Smrg	    {
631706f2543Smrg		mask = fbStipple24Bits[rot >> 3][stip];
632706f2543Smrg		WRITE(dst, (READ(dst) & ~leftMask) |
633706f2543Smrg			    (FbOpaqueStipple (mask,
634706f2543Smrg					      FbRot24(fgxor, rot),
635706f2543Smrg					      FbRot24(bgxor, rot))
636706f2543Smrg			     & leftMask));
637706f2543Smrg		dst++;
638706f2543Smrg		fbNextStipBits(rot,stip);
639706f2543Smrg	    }
640706f2543Smrg	    nl = nlMiddle;
641706f2543Smrg	    while (nl--)
642706f2543Smrg	    {
643706f2543Smrg		mask = fbStipple24Bits[rot>>3][stip];
644706f2543Smrg		WRITE(dst, FbOpaqueStipple (mask,
645706f2543Smrg					    FbRot24(fgxor, rot),
646706f2543Smrg					    FbRot24(bgxor, rot)));
647706f2543Smrg		dst++;
648706f2543Smrg		fbNextStipBits(rot,stip);
649706f2543Smrg	    }
650706f2543Smrg	    if (rightMask)
651706f2543Smrg	    {
652706f2543Smrg		mask = fbStipple24Bits[rot >> 3][stip];
653706f2543Smrg		WRITE(dst, (READ(dst) & ~rightMask) |
654706f2543Smrg			    (FbOpaqueStipple (mask,
655706f2543Smrg					      FbRot24(fgxor, rot),
656706f2543Smrg					      FbRot24(bgxor, rot))
657706f2543Smrg			     & rightMask));
658706f2543Smrg	    }
659706f2543Smrg	    dst += dstStride;
660706f2543Smrg	    src += srcStride;
661706f2543Smrg	}
662706f2543Smrg    }
663706f2543Smrg    /* transparent copy */
664706f2543Smrg    else if (bgand == FB_ALLONES && bgxor == 0 && fgand == 0)
665706f2543Smrg    {
666706f2543Smrg	while (height--)
667706f2543Smrg	{
668706f2543Smrg	    rot = rot0;
669706f2543Smrg	    src = srcLine;
670706f2543Smrg	    srcLine += srcStride;
671706f2543Smrg	    fbInitStipBits (srcX, firstlen, stip);
672706f2543Smrg	    if (leftMask)
673706f2543Smrg	    {
674706f2543Smrg		if (stip)
675706f2543Smrg		{
676706f2543Smrg		    mask = fbStipple24Bits[rot >> 3][stip] & leftMask;
677706f2543Smrg		    WRITE(dst, (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
678706f2543Smrg		}
679706f2543Smrg		dst++;
680706f2543Smrg		fbNextStipBits (rot, stip);
681706f2543Smrg	    }
682706f2543Smrg	    nl = nlMiddle;
683706f2543Smrg	    while (nl--)
684706f2543Smrg	    {
685706f2543Smrg		if (stip)
686706f2543Smrg		{
687706f2543Smrg		    mask = fbStipple24Bits[rot>>3][stip];
688706f2543Smrg		    WRITE(dst, (READ(dst) & ~mask) | (FbRot24(fgxor,rot) & mask));
689706f2543Smrg		}
690706f2543Smrg		dst++;
691706f2543Smrg		fbNextStipBits (rot, stip);
692706f2543Smrg	    }
693706f2543Smrg	    if (rightMask)
694706f2543Smrg	    {
695706f2543Smrg		if (stip)
696706f2543Smrg		{
697706f2543Smrg		    mask = fbStipple24Bits[rot >> 3][stip] & rightMask;
698706f2543Smrg		    WRITE(dst, (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
699706f2543Smrg		}
700706f2543Smrg	    }
701706f2543Smrg	    dst += dstStride;
702706f2543Smrg	}
703706f2543Smrg    }
704706f2543Smrg    else
705706f2543Smrg    {
706706f2543Smrg	while (height--)
707706f2543Smrg	{
708706f2543Smrg	    rot = rot0;
709706f2543Smrg	    src = srcLine;
710706f2543Smrg	    srcLine += srcStride;
711706f2543Smrg	    fbInitStipBits (srcX, firstlen, stip);
712706f2543Smrg	    if (leftMask)
713706f2543Smrg	    {
714706f2543Smrg		mask = fbStipple24Bits[rot >> 3][stip];
715706f2543Smrg		WRITE(dst, FbStippleRRopMask (READ(dst), mask,
716706f2543Smrg					      FbRot24(fgand, rot),
717706f2543Smrg					      FbRot24(fgxor, rot),
718706f2543Smrg					      FbRot24(bgand, rot),
719706f2543Smrg					      FbRot24(bgxor, rot),
720706f2543Smrg					      leftMask));
721706f2543Smrg		dst++;
722706f2543Smrg		fbNextStipBits(rot,stip);
723706f2543Smrg	    }
724706f2543Smrg	    nl = nlMiddle;
725706f2543Smrg	    while (nl--)
726706f2543Smrg	    {
727706f2543Smrg		mask = fbStipple24Bits[rot >> 3][stip];
728706f2543Smrg		WRITE(dst, FbStippleRRop (READ(dst), mask,
729706f2543Smrg					  FbRot24(fgand, rot),
730706f2543Smrg					  FbRot24(fgxor, rot),
731706f2543Smrg					  FbRot24(bgand, rot),
732706f2543Smrg					  FbRot24(bgxor, rot)));
733706f2543Smrg		dst++;
734706f2543Smrg		fbNextStipBits(rot,stip);
735706f2543Smrg	    }
736706f2543Smrg	    if (rightMask)
737706f2543Smrg	    {
738706f2543Smrg		mask = fbStipple24Bits[rot >> 3][stip];
739706f2543Smrg		WRITE(dst, FbStippleRRopMask (READ(dst), mask,
740706f2543Smrg					      FbRot24(fgand, rot),
741706f2543Smrg					      FbRot24(fgxor, rot),
742706f2543Smrg					      FbRot24(bgand, rot),
743706f2543Smrg					      FbRot24(bgxor, rot),
744706f2543Smrg					      rightMask));
745706f2543Smrg	    }
746706f2543Smrg	    dst += dstStride;
747706f2543Smrg	}
748706f2543Smrg    }
749706f2543Smrg}
750706f2543Smrg#endif
751706f2543Smrg
752706f2543Smrg/*
753706f2543Smrg * Not very efficient, but simple -- copy a single plane
754706f2543Smrg * from an N bit image to a 1 bit image
755706f2543Smrg */
756706f2543Smrg
757706f2543Smrgvoid
758706f2543SmrgfbBltPlane (FbBits	    *src,
759706f2543Smrg	    FbStride	    srcStride,
760706f2543Smrg	    int		    srcX,
761706f2543Smrg	    int		    srcBpp,
762706f2543Smrg
763706f2543Smrg	    FbStip	    *dst,
764706f2543Smrg	    FbStride	    dstStride,
765706f2543Smrg	    int		    dstX,
766706f2543Smrg
767706f2543Smrg	    int		    width,
768706f2543Smrg	    int		    height,
769706f2543Smrg
770706f2543Smrg	    FbStip	    fgand,
771706f2543Smrg	    FbStip	    fgxor,
772706f2543Smrg	    FbStip	    bgand,
773706f2543Smrg	    FbStip	    bgxor,
774706f2543Smrg	    Pixel	    planeMask)
775706f2543Smrg{
776706f2543Smrg    FbBits	*s;
777706f2543Smrg    FbBits	pm;
778706f2543Smrg    FbBits	srcMask;
779706f2543Smrg    FbBits	srcMaskFirst;
780706f2543Smrg    FbBits	srcMask0 = 0;
781706f2543Smrg    FbBits	srcBits;
782706f2543Smrg
783706f2543Smrg    FbStip	dstBits;
784706f2543Smrg    FbStip	*d;
785706f2543Smrg    FbStip	dstMask;
786706f2543Smrg    FbStip	dstMaskFirst;
787706f2543Smrg    FbStip	dstUnion;
788706f2543Smrg    int		w;
789706f2543Smrg    int		wt;
790706f2543Smrg    int		rot0;
791706f2543Smrg
792706f2543Smrg    if (!width)
793706f2543Smrg	return;
794706f2543Smrg
795706f2543Smrg    src += srcX >> FB_SHIFT;
796706f2543Smrg    srcX &= FB_MASK;
797706f2543Smrg
798706f2543Smrg    dst += dstX >> FB_STIP_SHIFT;
799706f2543Smrg    dstX &= FB_STIP_MASK;
800706f2543Smrg
801706f2543Smrg    w = width / srcBpp;
802706f2543Smrg
803706f2543Smrg    pm = fbReplicatePixel (planeMask, srcBpp);
804706f2543Smrg#ifdef FB_24BIT
805706f2543Smrg    if (srcBpp == 24)
806706f2543Smrg    {
807706f2543Smrg	int w = 24;
808706f2543Smrg
809706f2543Smrg	rot0 = FbFirst24Rot (srcX);
810706f2543Smrg	if (srcX + w > FB_UNIT)
811706f2543Smrg	    w = FB_UNIT - srcX;
812706f2543Smrg	srcMaskFirst = FbRot24(pm,rot0) & FbBitsMask(srcX,w);
813706f2543Smrg    }
814706f2543Smrg    else
815706f2543Smrg#endif
816706f2543Smrg    {
817706f2543Smrg	rot0 = 0;
818706f2543Smrg	srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
819706f2543Smrg	srcMask0 = pm & FbBitsMask(0, srcBpp);
820706f2543Smrg    }
821706f2543Smrg
822706f2543Smrg    dstMaskFirst = FbStipMask(dstX,1);
823706f2543Smrg    while (height--)
824706f2543Smrg    {
825706f2543Smrg	d = dst;
826706f2543Smrg	dst += dstStride;
827706f2543Smrg	s = src;
828706f2543Smrg	src += srcStride;
829706f2543Smrg
830706f2543Smrg	srcMask = srcMaskFirst;
831706f2543Smrg#ifdef FB_24BIT
832706f2543Smrg	if (srcBpp == 24)
833706f2543Smrg	    srcMask0 = FbRot24(pm,rot0) & FbBitsMask(0, srcBpp);
834706f2543Smrg#endif
835706f2543Smrg    	srcBits = READ(s++);
836706f2543Smrg
837706f2543Smrg	dstMask = dstMaskFirst;
838706f2543Smrg	dstUnion = 0;
839706f2543Smrg	dstBits = 0;
840706f2543Smrg
841706f2543Smrg	wt = w;
842706f2543Smrg
843706f2543Smrg	while (wt--)
844706f2543Smrg	{
845706f2543Smrg	    if (!srcMask)
846706f2543Smrg	    {
847706f2543Smrg		srcBits = READ(s++);
848706f2543Smrg#ifdef FB_24BIT
849706f2543Smrg		if (srcBpp == 24)
850706f2543Smrg		    srcMask0 = FbNext24Pix(srcMask0) & FbBitsMask(0,24);
851706f2543Smrg#endif
852706f2543Smrg		srcMask = srcMask0;
853706f2543Smrg	    }
854706f2543Smrg	    if (!dstMask)
855706f2543Smrg	    {
856706f2543Smrg		WRITE(d, FbStippleRRopMask(READ(d), dstBits,
857706f2543Smrg					   fgand, fgxor, bgand, bgxor,
858706f2543Smrg					   dstUnion));
859706f2543Smrg		d++;
860706f2543Smrg		dstMask = FbStipMask(0,1);
861706f2543Smrg		dstUnion = 0;
862706f2543Smrg		dstBits = 0;
863706f2543Smrg	    }
864706f2543Smrg	    if (srcBits & srcMask)
865706f2543Smrg		dstBits |= dstMask;
866706f2543Smrg	    dstUnion |= dstMask;
867706f2543Smrg	    if (srcBpp == FB_UNIT)
868706f2543Smrg		srcMask = 0;
869706f2543Smrg	    else
870706f2543Smrg		srcMask = FbScrRight(srcMask,srcBpp);
871706f2543Smrg	    dstMask = FbStipRight(dstMask,1);
872706f2543Smrg	}
873706f2543Smrg	if (dstUnion)
874706f2543Smrg	    WRITE(d, FbStippleRRopMask(READ(d),dstBits,
875706f2543Smrg				       fgand, fgxor, bgand, bgxor,
876706f2543Smrg				       dstUnion));
877706f2543Smrg    }
878706f2543Smrg}
879706f2543Smrg
880