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 <string.h>
28#include "fb.h"
29
30#define InitializeShifts(sx,dx,ls,rs) { \
31    if (sx != dx) { \
32	if (sx > dx) { \
33	    ls = sx - dx; \
34	    rs = FB_UNIT - ls; \
35	} else { \
36	    rs = dx - sx; \
37	    ls = FB_UNIT - rs; \
38	} \
39    } \
40}
41
42void
43fbBlt (FbBits   *srcLine,
44       FbStride	srcStride,
45       int	srcX,
46
47       FbBits   *dstLine,
48       FbStride dstStride,
49       int	dstX,
50
51       int	width,
52       int	height,
53
54       int	alu,
55       FbBits	pm,
56       int	bpp,
57
58       Bool	reverse,
59       Bool	upsidedown)
60{
61    FbBits  *src, *dst;
62    int	    leftShift, rightShift;
63    FbBits  startmask, endmask;
64    FbBits  bits, bits1;
65    int	    n, nmiddle;
66    Bool    destInvarient;
67    int	    startbyte, endbyte;
68    int     careful;
69    FbDeclareMergeRop ();
70
71#ifdef FB_24BIT
72    if (bpp == 24 && !FbCheck24Pix (pm))
73    {
74	fbBlt24 (srcLine, srcStride, srcX, dstLine, dstStride, dstX,
75		 width, height, alu, pm, reverse, upsidedown);
76	return;
77    }
78#endif
79
80    careful = !((srcLine < dstLine && srcLine + width * (bpp>>3) > dstLine) ||
81                (dstLine < srcLine && dstLine + width * (bpp>>3) > srcLine)) ||
82              (bpp & 7);
83
84    if (alu == GXcopy && pm == FB_ALLONES && !careful &&
85            !(srcX & 7) && !(dstX & 7) && !(width & 7)) {
86        int i;
87        CARD8 *src = (CARD8 *) srcLine;
88        CARD8 *dst = (CARD8 *) dstLine;
89
90        srcStride *= sizeof(FbBits);
91        dstStride *= sizeof(FbBits);
92        width >>= 3;
93        src += (srcX >> 3);
94        dst += (dstX >> 3);
95
96        if (!upsidedown)
97            for (i = 0; i < height; i++)
98                MEMCPY_WRAPPED(dst + i * dstStride, src + i * srcStride, width);
99        else
100            for (i = height - 1; i >= 0; i--)
101                MEMCPY_WRAPPED(dst + i * dstStride, src + i * srcStride, width);
102
103        return;
104    }
105
106    FbInitializeMergeRop(alu, pm);
107    destInvarient = FbDestInvarientMergeRop();
108    if (upsidedown)
109    {
110	srcLine += (height - 1) * (srcStride);
111	dstLine += (height - 1) * (dstStride);
112	srcStride = -srcStride;
113	dstStride = -dstStride;
114    }
115    FbMaskBitsBytes (dstX, width, destInvarient, startmask, startbyte,
116		     nmiddle, endmask, endbyte);
117    if (reverse)
118    {
119	srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1;
120	dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1;
121	srcX = (srcX + width - 1) & FB_MASK;
122	dstX = (dstX + width - 1) & FB_MASK;
123    }
124    else
125    {
126	srcLine += srcX >> FB_SHIFT;
127	dstLine += dstX >> FB_SHIFT;
128	srcX &= FB_MASK;
129	dstX &= FB_MASK;
130    }
131    if (srcX == dstX)
132    {
133	while (height--)
134	{
135	    src = srcLine;
136	    srcLine += srcStride;
137	    dst = dstLine;
138	    dstLine += dstStride;
139	    if (reverse)
140	    {
141		if (endmask)
142		{
143		    bits = READ(--src);
144		    --dst;
145		    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
146		}
147		n = nmiddle;
148		if (destInvarient)
149		{
150		    while (n--)
151			WRITE(--dst, FbDoDestInvarientMergeRop(READ(--src)));
152		}
153		else
154		{
155		    while (n--)
156		    {
157			bits = READ(--src);
158			--dst;
159			WRITE(dst, FbDoMergeRop (bits, READ(dst)));
160		    }
161		}
162		if (startmask)
163		{
164		    bits = READ(--src);
165		    --dst;
166		    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
167		}
168	    }
169	    else
170	    {
171		if (startmask)
172		{
173		    bits = READ(src++);
174		    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
175		    dst++;
176		}
177		n = nmiddle;
178		if (destInvarient)
179		{
180#if 0
181		    /*
182		     * This provides some speedup on screen->screen blts
183		     * over the PCI bus, usually about 10%.  But fb
184		     * isn't usually used for this operation...
185		     */
186		    if (_ca2 + 1 == 0 && _cx2 == 0)
187		    {
188			FbBits	t1, t2, t3, t4;
189			while (n >= 4)
190			{
191			    t1 = *src++;
192			    t2 = *src++;
193			    t3 = *src++;
194			    t4 = *src++;
195			    *dst++ = t1;
196			    *dst++ = t2;
197			    *dst++ = t3;
198			    *dst++ = t4;
199			    n -= 4;
200			}
201		    }
202#endif
203		    while (n--)
204			WRITE(dst++, FbDoDestInvarientMergeRop(READ(src++)));
205		}
206		else
207		{
208		    while (n--)
209		    {
210			bits = READ(src++);
211			WRITE(dst, FbDoMergeRop (bits, READ(dst)));
212			dst++;
213		    }
214		}
215		if (endmask)
216		{
217		    bits = READ(src);
218		    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
219		}
220	    }
221	}
222    }
223    else
224    {
225	if (srcX > dstX)
226	{
227	    leftShift = srcX - dstX;
228	    rightShift = FB_UNIT - leftShift;
229	}
230	else
231	{
232	    rightShift = dstX - srcX;
233	    leftShift = FB_UNIT - rightShift;
234	}
235	while (height--)
236	{
237	    src = srcLine;
238	    srcLine += srcStride;
239	    dst = dstLine;
240	    dstLine += dstStride;
241
242	    bits1 = 0;
243	    if (reverse)
244	    {
245		if (srcX < dstX)
246		    bits1 = READ(--src);
247		if (endmask)
248		{
249		    bits = FbScrRight(bits1, rightShift);
250		    if (FbScrRight(endmask, leftShift))
251		    {
252			bits1 = READ(--src);
253			bits |= FbScrLeft(bits1, leftShift);
254		    }
255		    --dst;
256		    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
257		}
258		n = nmiddle;
259		if (destInvarient)
260		{
261		    while (n--)
262		    {
263			bits = FbScrRight(bits1, rightShift);
264			bits1 = READ(--src);
265			bits |= FbScrLeft(bits1, leftShift);
266			--dst;
267			WRITE(dst, FbDoDestInvarientMergeRop(bits));
268		    }
269		}
270		else
271		{
272		    while (n--)
273		    {
274			bits = FbScrRight(bits1, rightShift);
275			bits1 = READ(--src);
276			bits |= FbScrLeft(bits1, leftShift);
277			--dst;
278			WRITE(dst, FbDoMergeRop(bits, READ(dst)));
279		    }
280		}
281		if (startmask)
282		{
283		    bits = FbScrRight(bits1, rightShift);
284		    if (FbScrRight(startmask, leftShift))
285		    {
286			bits1 = READ(--src);
287			bits |= FbScrLeft(bits1, leftShift);
288		    }
289		    --dst;
290		    FbDoLeftMaskByteMergeRop (dst, bits, startbyte, startmask);
291		}
292	    }
293	    else
294	    {
295		if (srcX > dstX)
296		    bits1 = READ(src++);
297		if (startmask)
298		{
299		    bits = FbScrLeft(bits1, leftShift);
300		    if (FbScrLeft(startmask, rightShift))
301		    {
302			bits1 = READ(src++);
303			bits |= FbScrRight(bits1, rightShift);
304		    }
305		    FbDoLeftMaskByteMergeRop (dst, bits, startbyte, startmask);
306		    dst++;
307		}
308		n = nmiddle;
309		if (destInvarient)
310		{
311		    while (n--)
312		    {
313			bits = FbScrLeft(bits1, leftShift);
314			bits1 = READ(src++);
315			bits |= FbScrRight(bits1, rightShift);
316			WRITE(dst, FbDoDestInvarientMergeRop(bits));
317			dst++;
318		    }
319		}
320		else
321		{
322		    while (n--)
323		    {
324			bits = FbScrLeft(bits1, leftShift);
325			bits1 = READ(src++);
326			bits |= FbScrRight(bits1, rightShift);
327			WRITE(dst, FbDoMergeRop(bits, READ(dst)));
328			dst++;
329		    }
330		}
331		if (endmask)
332		{
333		    bits = FbScrLeft(bits1, leftShift);
334		    if (FbScrLeft(endmask, rightShift))
335		    {
336			bits1 = READ(src);
337			bits |= FbScrRight(bits1, rightShift);
338		    }
339		    FbDoRightMaskByteMergeRop (dst, bits, endbyte, endmask);
340		}
341	    }
342	}
343    }
344}
345
346#ifdef FB_24BIT
347
348#undef DEBUG_BLT24
349#ifdef DEBUG_BLT24
350
351static unsigned long
352getPixel (char *src, int x)
353{
354    unsigned long   l;
355
356    l = 0;
357    memcpy (&l, src + x * 3, 3);
358    return l;
359}
360#endif
361
362static void
363fbBlt24Line (FbBits	    *src,
364	     int	    srcX,
365
366	     FbBits	    *dst,
367	     int	    dstX,
368
369	     int	    width,
370
371	     int	    alu,
372	     FbBits	    pm,
373
374	     Bool	    reverse)
375{
376#ifdef DEBUG_BLT24
377    char    *origDst = (char *) dst;
378    FbBits  *origLine = dst + ((dstX >> FB_SHIFT) - 1);
379    int	    origNlw = ((width + FB_MASK) >> FB_SHIFT) + 3;
380    int	    origX = dstX / 24;
381#endif
382
383    int	    leftShift, rightShift;
384    FbBits  startmask, endmask;
385    int	    n;
386
387    FbBits  bits, bits1;
388    FbBits  mask;
389
390    int	    rot;
391    FbDeclareMergeRop ();
392
393    FbInitializeMergeRop (alu, FB_ALLONES);
394    FbMaskBits(dstX, width, startmask, n, endmask);
395#ifdef DEBUG_BLT24
396    ErrorF ("dstX %d width %d reverse %d\n", dstX, width, reverse);
397#endif
398    if (reverse)
399    {
400	src += ((srcX + width - 1) >> FB_SHIFT) + 1;
401	dst += ((dstX + width - 1) >> FB_SHIFT) + 1;
402	rot = FbFirst24Rot (((dstX + width - 8) & FB_MASK));
403	rot = FbPrev24Rot(rot);
404#ifdef DEBUG_BLT24
405	ErrorF ("dstX + width - 8: %d rot: %d\n", (dstX + width - 8) & FB_MASK, rot);
406#endif
407	srcX = (srcX + width - 1) & FB_MASK;
408	dstX = (dstX + width - 1) & FB_MASK;
409    }
410    else
411    {
412	src += srcX >> FB_SHIFT;
413	dst += dstX >> FB_SHIFT;
414	srcX &= FB_MASK;
415	dstX &= FB_MASK;
416	rot = FbFirst24Rot (dstX);
417#ifdef DEBUG_BLT24
418	ErrorF ("dstX: %d rot: %d\n", dstX, rot);
419#endif
420    }
421    mask = FbRot24(pm,rot);
422#ifdef DEBUG_BLT24
423    ErrorF ("pm 0x%x mask 0x%x\n", pm, mask);
424#endif
425    if (srcX == dstX)
426    {
427	if (reverse)
428	{
429	    if (endmask)
430	    {
431		bits = READ(--src);
432		--dst;
433		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), mask & endmask));
434		mask = FbPrev24Pix (mask);
435	    }
436	    while (n--)
437	    {
438		bits = READ(--src);
439		--dst;
440		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), mask));
441		mask = FbPrev24Pix (mask);
442	    }
443	    if (startmask)
444	    {
445		bits = READ(--src);
446		--dst;
447		WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & startmask));
448	    }
449	}
450	else
451	{
452	    if (startmask)
453	    {
454		bits = READ(src++);
455		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), mask & startmask));
456		dst++;
457		mask = FbNext24Pix(mask);
458	    }
459	    while (n--)
460	    {
461		bits = READ(src++);
462		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), mask));
463		dst++;
464		mask = FbNext24Pix(mask);
465	    }
466	    if (endmask)
467	    {
468		bits = READ(src);
469		WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & endmask));
470	    }
471	}
472    }
473    else
474    {
475	if (srcX > dstX)
476	{
477	    leftShift = srcX - dstX;
478	    rightShift = FB_UNIT - leftShift;
479	}
480	else
481	{
482	    rightShift = dstX - srcX;
483	    leftShift = FB_UNIT - rightShift;
484	}
485
486	bits1 = 0;
487	if (reverse)
488	{
489	    if (srcX < dstX)
490		bits1 = READ(--src);
491	    if (endmask)
492	    {
493		bits = FbScrRight(bits1, rightShift);
494		if (FbScrRight(endmask, leftShift))
495		{
496		    bits1 = READ(--src);
497		    bits |= FbScrLeft(bits1, leftShift);
498		}
499		--dst;
500		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), mask & endmask));
501		mask = FbPrev24Pix(mask);
502	    }
503	    while (n--)
504	    {
505		bits = FbScrRight(bits1, rightShift);
506		bits1 = READ(--src);
507		bits |= FbScrLeft(bits1, leftShift);
508		--dst;
509		WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask));
510		mask = FbPrev24Pix(mask);
511	    }
512	    if (startmask)
513	    {
514		bits = FbScrRight(bits1, rightShift);
515		if (FbScrRight(startmask, leftShift))
516		{
517		    bits1 = READ(--src);
518		    bits |= FbScrLeft(bits1, leftShift);
519		}
520		--dst;
521		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), mask & startmask));
522	    }
523	}
524	else
525	{
526	    if (srcX > dstX)
527		bits1 = READ(src++);
528	    if (startmask)
529	    {
530		bits = FbScrLeft(bits1, leftShift);
531		bits1 = READ(src++);
532		bits |= FbScrRight(bits1, rightShift);
533		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), mask & startmask));
534		dst++;
535		mask = FbNext24Pix(mask);
536	    }
537	    while (n--)
538	    {
539		bits = FbScrLeft(bits1, leftShift);
540		bits1 = READ(src++);
541		bits |= FbScrRight(bits1, rightShift);
542		WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask));
543		dst++;
544		mask = FbNext24Pix(mask);
545	    }
546	    if (endmask)
547	    {
548		bits = FbScrLeft(bits1, leftShift);
549		if (FbScrLeft(endmask, rightShift))
550		{
551		    bits1 = READ(src);
552		    bits |= FbScrRight(bits1, rightShift);
553		}
554		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), mask & endmask));
555	    }
556	}
557    }
558#ifdef DEBUG_BLT24
559    {
560	int firstx, lastx, x;
561
562	firstx = origX;
563	if (firstx)
564	    firstx--;
565	lastx = origX + width/24 + 1;
566	for (x = firstx; x <= lastx; x++)
567	    ErrorF ("%06x ", getPixel (origDst, x));
568	ErrorF ("\n");
569	while (origNlw--)
570	    ErrorF ("%08x ", *origLine++);
571	ErrorF ("\n");
572    }
573#endif
574}
575
576void
577fbBlt24 (FbBits	    *srcLine,
578	 FbStride   srcStride,
579	 int	    srcX,
580
581	 FbBits	    *dstLine,
582	 FbStride   dstStride,
583	 int	    dstX,
584
585	 int	    width,
586	 int	    height,
587
588	 int	    alu,
589	 FbBits	    pm,
590
591	 Bool	    reverse,
592	 Bool	    upsidedown)
593{
594    if (upsidedown)
595    {
596	srcLine += (height-1) * srcStride;
597	dstLine += (height-1) * dstStride;
598	srcStride = -srcStride;
599	dstStride = -dstStride;
600    }
601    while (height--)
602    {
603	fbBlt24Line (srcLine, srcX, dstLine, dstX, width, alu, pm, reverse);
604	srcLine += srcStride;
605	dstLine += dstStride;
606    }
607#ifdef DEBUG_BLT24
608    ErrorF ("\n");
609#endif
610}
611#endif /* FB_24BIT */
612
613#if FB_SHIFT == FB_STIP_SHIFT + 1
614
615/*
616 * Could be generalized to FB_SHIFT > FB_STIP_SHIFT + 1 by
617 * creating an ring of values stepped through for each line
618 */
619
620void
621fbBltOdd (FbBits    *srcLine,
622	  FbStride  srcStrideEven,
623	  FbStride  srcStrideOdd,
624	  int	    srcXEven,
625	  int	    srcXOdd,
626
627	  FbBits    *dstLine,
628	  FbStride  dstStrideEven,
629	  FbStride  dstStrideOdd,
630	  int	    dstXEven,
631	  int	    dstXOdd,
632
633	  int	    width,
634	  int	    height,
635
636	  int	    alu,
637	  FbBits    pm,
638	  int	    bpp)
639{
640    FbBits  *src;
641    int	    leftShiftEven, rightShiftEven;
642    FbBits  startmaskEven, endmaskEven;
643    int	    nmiddleEven;
644
645    FbBits  *dst;
646    int	    leftShiftOdd, rightShiftOdd;
647    FbBits  startmaskOdd, endmaskOdd;
648    int	    nmiddleOdd;
649
650    int	    leftShift, rightShift;
651    FbBits  startmask, endmask;
652    int	    nmiddle;
653
654    int	    srcX, dstX;
655
656    FbBits  bits, bits1;
657    int	    n;
658
659    Bool    destInvarient;
660    Bool    even;
661    FbDeclareMergeRop ();
662
663    FbInitializeMergeRop (alu, pm);
664    destInvarient = FbDestInvarientMergeRop();
665
666    srcLine += srcXEven >> FB_SHIFT;
667    dstLine += dstXEven >> FB_SHIFT;
668    srcXEven &= FB_MASK;
669    dstXEven &= FB_MASK;
670    srcXOdd &= FB_MASK;
671    dstXOdd &= FB_MASK;
672
673    FbMaskBits(dstXEven, width, startmaskEven, nmiddleEven, endmaskEven);
674    FbMaskBits(dstXOdd, width, startmaskOdd, nmiddleOdd, endmaskOdd);
675
676    even = TRUE;
677    InitializeShifts(srcXEven, dstXEven, leftShiftEven, rightShiftEven);
678    InitializeShifts(srcXOdd, dstXOdd, leftShiftOdd, rightShiftOdd);
679    while (height--)
680    {
681	src = srcLine;
682	dst = dstLine;
683	if (even)
684	{
685	    srcX = srcXEven;
686	    dstX = dstXEven;
687	    startmask = startmaskEven;
688	    endmask = endmaskEven;
689	    nmiddle = nmiddleEven;
690	    leftShift = leftShiftEven;
691	    rightShift = rightShiftEven;
692	    srcLine += srcStrideEven;
693	    dstLine += dstStrideEven;
694	    even = FALSE;
695	}
696	else
697	{
698	    srcX = srcXOdd;
699	    dstX = dstXOdd;
700	    startmask = startmaskOdd;
701	    endmask = endmaskOdd;
702	    nmiddle = nmiddleOdd;
703	    leftShift = leftShiftOdd;
704	    rightShift = rightShiftOdd;
705	    srcLine += srcStrideOdd;
706	    dstLine += dstStrideOdd;
707	    even = TRUE;
708	}
709	if (srcX == dstX)
710	{
711	    if (startmask)
712	    {
713		bits = READ(src++);
714		WRITE(dst, FbDoMaskMergeRop (bits, READ(dst), startmask));
715		dst++;
716	    }
717	    n = nmiddle;
718	    if (destInvarient)
719	    {
720		while (n--)
721		{
722		    bits = READ(src++);
723		    WRITE(dst, FbDoDestInvarientMergeRop(bits));
724		    dst++;
725		}
726	    }
727	    else
728	    {
729		while (n--)
730		{
731		    bits = READ(src++);
732		    WRITE(dst, FbDoMergeRop (bits, READ(dst)));
733		    dst++;
734		}
735	    }
736	    if (endmask)
737	    {
738		bits = READ(src);
739		WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), endmask));
740	    }
741	}
742	else
743	{
744	    bits = 0;
745	    if (srcX > dstX)
746		bits = READ(src++);
747	    if (startmask)
748	    {
749		bits1 = FbScrLeft(bits, leftShift);
750		bits = READ(src++);
751		bits1 |= FbScrRight(bits, rightShift);
752		WRITE(dst, FbDoMaskMergeRop (bits1, READ(dst), startmask));
753		dst++;
754	    }
755	    n = nmiddle;
756	    if (destInvarient)
757	    {
758		while (n--)
759		{
760		    bits1 = FbScrLeft(bits, leftShift);
761		    bits = READ(src++);
762		    bits1 |= FbScrRight(bits, rightShift);
763		    WRITE(dst, FbDoDestInvarientMergeRop(bits1));
764		    dst++;
765		}
766	    }
767	    else
768	    {
769		while (n--)
770		{
771		    bits1 = FbScrLeft(bits, leftShift);
772		    bits = READ(src++);
773		    bits1 |= FbScrRight(bits, rightShift);
774		    WRITE(dst, FbDoMergeRop(bits1, READ(dst)));
775		    dst++;
776		}
777	    }
778	    if (endmask)
779	    {
780		bits1 = FbScrLeft(bits, leftShift);
781		if (FbScrLeft(endmask, rightShift))
782		{
783		    bits = READ(src);
784		    bits1 |= FbScrRight(bits, rightShift);
785		}
786		WRITE(dst, FbDoMaskMergeRop (bits1, READ(dst), endmask));
787	    }
788	}
789    }
790}
791
792#ifdef FB_24BIT
793void
794fbBltOdd24 (FbBits	*srcLine,
795	    FbStride	srcStrideEven,
796	    FbStride	srcStrideOdd,
797	    int		srcXEven,
798	    int		srcXOdd,
799
800	    FbBits	*dstLine,
801	    FbStride	dstStrideEven,
802	    FbStride	dstStrideOdd,
803	    int		dstXEven,
804	    int		dstXOdd,
805
806	    int		width,
807	    int		height,
808
809	    int		alu,
810	    FbBits	pm)
811{
812    Bool    even = TRUE;
813
814    while (height--)
815    {
816	if (even)
817	{
818	    fbBlt24Line (srcLine, srcXEven, dstLine, dstXEven,
819			 width, alu, pm, FALSE);
820	    srcLine += srcStrideEven;
821	    dstLine += dstStrideEven;
822	    even = FALSE;
823	}
824	else
825	{
826	    fbBlt24Line (srcLine, srcXOdd, dstLine, dstXOdd,
827			 width, alu, pm, FALSE);
828	    srcLine += srcStrideOdd;
829	    dstLine += dstStrideOdd;
830	    even = TRUE;
831	}
832    }
833}
834#endif
835
836#endif
837
838#if FB_STIP_SHIFT != FB_SHIFT
839void
840fbSetBltOdd (FbStip	*stip,
841	     FbStride	stipStride,
842	     int	srcX,
843	     FbBits	**bits,
844	     FbStride	*strideEven,
845	     FbStride	*strideOdd,
846	     int	*srcXEven,
847	     int	*srcXOdd)
848{
849    int	    srcAdjust;
850    int	    strideAdjust;
851
852    /*
853     * bytes needed to align source
854     */
855    srcAdjust = (((int) stip) & (FB_MASK >> 3));
856    /*
857     * FbStip units needed to align stride
858     */
859    strideAdjust = stipStride & (FB_MASK >> FB_STIP_SHIFT);
860
861    *bits = (FbBits *) ((char *) stip - srcAdjust);
862    if (srcAdjust)
863    {
864	*strideEven = FbStipStrideToBitsStride (stipStride + 1);
865	*strideOdd = FbStipStrideToBitsStride (stipStride);
866
867	*srcXEven = srcX + (srcAdjust << 3);
868	*srcXOdd = srcX + (srcAdjust << 3) - (strideAdjust << FB_STIP_SHIFT);
869    }
870    else
871    {
872	*strideEven = FbStipStrideToBitsStride (stipStride);
873	*strideOdd = FbStipStrideToBitsStride (stipStride + 1);
874
875	*srcXEven = srcX;
876	*srcXOdd = srcX + (strideAdjust << FB_STIP_SHIFT);
877    }
878}
879#endif
880
881void
882fbBltStip (FbStip   *src,
883	   FbStride srcStride,	    /* in FbStip units, not FbBits units */
884	   int	    srcX,
885
886	   FbStip   *dst,
887	   FbStride dstStride,	    /* in FbStip units, not FbBits units */
888	   int	    dstX,
889
890	   int	    width,
891	   int	    height,
892
893	   int	    alu,
894	   FbBits   pm,
895	   int	    bpp)
896{
897#if FB_STIP_SHIFT != FB_SHIFT
898    if (FB_STIP_ODDSTRIDE(srcStride) || FB_STIP_ODDPTR(src) ||
899	FB_STIP_ODDSTRIDE(dstStride) || FB_STIP_ODDPTR(dst))
900    {
901	FbStride    srcStrideEven, srcStrideOdd;
902	FbStride    dstStrideEven, dstStrideOdd;
903	int	    srcXEven, srcXOdd;
904	int	    dstXEven, dstXOdd;
905	FbBits	    *s, *d;
906	int	    sx, dx;
907
908	src += srcX >> FB_STIP_SHIFT;
909	srcX &= FB_STIP_MASK;
910	dst += dstX >> FB_STIP_SHIFT;
911	dstX &= FB_STIP_MASK;
912
913	fbSetBltOdd (src, srcStride, srcX,
914		     &s,
915		     &srcStrideEven, &srcStrideOdd,
916		     &srcXEven, &srcXOdd);
917
918	fbSetBltOdd (dst, dstStride, dstX,
919		     &d,
920		     &dstStrideEven, &dstStrideOdd,
921		     &dstXEven, &dstXOdd);
922
923#ifdef FB_24BIT
924	if (bpp == 24 && !FbCheck24Pix (pm))
925	{
926	    fbBltOdd24  (s, srcStrideEven, srcStrideOdd,
927			 srcXEven, srcXOdd,
928
929			 d, dstStrideEven, dstStrideOdd,
930			 dstXEven, dstXOdd,
931
932			 width, height, alu, pm);
933	}
934	else
935#endif
936	{
937	    fbBltOdd (s, srcStrideEven, srcStrideOdd,
938		      srcXEven, srcXOdd,
939
940		      d, dstStrideEven, dstStrideOdd,
941		      dstXEven, dstXOdd,
942
943		      width, height, alu, pm, bpp);
944	}
945    }
946    else
947#endif
948    {
949	fbBlt ((FbBits *) src, FbStipStrideToBitsStride (srcStride),
950	       srcX,
951	       (FbBits *) dst, FbStipStrideToBitsStride (dstStride),
952	       dstX,
953	       width, height,
954	       alu, pm, bpp, FALSE, FALSE);
955    }
956}
957