fbblt.c revision 35c4bbdf
105b261ecSmrg/*
205b261ecSmrg * Copyright © 1998 Keith Packard
305b261ecSmrg *
405b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
505b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
605b261ecSmrg * the above copyright notice appear in all copies and that both that
705b261ecSmrg * copyright notice and this permission notice appear in supporting
805b261ecSmrg * documentation, and that the name of Keith Packard not be used in
905b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1005b261ecSmrg * specific, written prior permission.  Keith Packard makes no
1105b261ecSmrg * representations about the suitability of this software for any purpose.  It
1205b261ecSmrg * is provided "as is" without express or implied warranty.
1305b261ecSmrg *
1405b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1505b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1605b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1705b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1805b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1905b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2005b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2105b261ecSmrg */
2205b261ecSmrg
2305b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2405b261ecSmrg#include <dix-config.h>
2505b261ecSmrg#endif
2605b261ecSmrg
2705b261ecSmrg#include <string.h>
2805b261ecSmrg#include "fb.h"
2905b261ecSmrg
3005b261ecSmrg#define InitializeShifts(sx,dx,ls,rs) { \
3105b261ecSmrg    if (sx != dx) { \
3205b261ecSmrg	if (sx > dx) { \
3305b261ecSmrg	    ls = sx - dx; \
3405b261ecSmrg	    rs = FB_UNIT - ls; \
3505b261ecSmrg	} else { \
3605b261ecSmrg	    rs = dx - sx; \
3705b261ecSmrg	    ls = FB_UNIT - rs; \
3805b261ecSmrg	} \
3905b261ecSmrg    } \
4005b261ecSmrg}
4105b261ecSmrg
4205b261ecSmrgvoid
4335c4bbdfSmrgfbBlt(FbBits * srcLine,
4435c4bbdfSmrg      FbStride srcStride,
4535c4bbdfSmrg      int srcX,
4635c4bbdfSmrg      FbBits * dstLine,
4735c4bbdfSmrg      FbStride dstStride,
4835c4bbdfSmrg      int dstX,
4935c4bbdfSmrg      int width,
5035c4bbdfSmrg      int height, int alu, FbBits pm, int bpp, Bool reverse, Bool upsidedown)
5105b261ecSmrg{
5235c4bbdfSmrg    FbBits *src, *dst;
5335c4bbdfSmrg    int leftShift, rightShift;
5435c4bbdfSmrg    FbBits startmask, endmask;
5535c4bbdfSmrg    FbBits bits, bits1;
5635c4bbdfSmrg    int n, nmiddle;
5735c4bbdfSmrg    Bool destInvarient;
5835c4bbdfSmrg    int startbyte, endbyte;
5935c4bbdfSmrg
6035c4bbdfSmrg    FbDeclareMergeRop();
6135c4bbdfSmrg
6235c4bbdfSmrg    if (alu == GXcopy && pm == FB_ALLONES &&
6335c4bbdfSmrg        !(srcX & 7) && !(dstX & 7) && !(width & 7))
6405b261ecSmrg    {
6535c4bbdfSmrg        CARD8           *src_byte = (CARD8 *) srcLine + (srcX >> 3);
6635c4bbdfSmrg        CARD8           *dst_byte = (CARD8 *) dstLine + (dstX >> 3);
6735c4bbdfSmrg        FbStride        src_byte_stride = srcStride << (FB_SHIFT - 3);
6835c4bbdfSmrg        FbStride        dst_byte_stride = dstStride << (FB_SHIFT - 3);
6935c4bbdfSmrg        int             width_byte = (width >> 3);
7035c4bbdfSmrg
7135c4bbdfSmrg        /* Make sure there's no overlap; we can't use memcpy in that
7235c4bbdfSmrg         * case as it's not well defined, so fall through to the
7335c4bbdfSmrg         * general code
7435c4bbdfSmrg         */
7535c4bbdfSmrg        if (src_byte + width_byte <= dst_byte ||
7635c4bbdfSmrg            dst_byte + width_byte <= src_byte)
7735c4bbdfSmrg        {
7835c4bbdfSmrg            int i;
7935c4bbdfSmrg
8035c4bbdfSmrg            if (!upsidedown)
8135c4bbdfSmrg                for (i = 0; i < height; i++)
8235c4bbdfSmrg                    MEMCPY_WRAPPED(dst_byte + i * dst_byte_stride,
8335c4bbdfSmrg                                   src_byte + i * src_byte_stride,
8435c4bbdfSmrg                                   width_byte);
8535c4bbdfSmrg            else
8635c4bbdfSmrg                for (i = height - 1; i >= 0; i--)
8735c4bbdfSmrg                    MEMCPY_WRAPPED(dst_byte + i * dst_byte_stride,
8835c4bbdfSmrg                                   src_byte + i * src_byte_stride,
8935c4bbdfSmrg                                   width_byte);
9035c4bbdfSmrg
9135c4bbdfSmrg            return;
9235c4bbdfSmrg        }
9305b261ecSmrg    }
9405b261ecSmrg
9535c4bbdfSmrg    if (bpp == 24 && !FbCheck24Pix(pm)) {
9635c4bbdfSmrg        fbBlt24(srcLine, srcStride, srcX, dstLine, dstStride, dstX,
9735c4bbdfSmrg                width, height, alu, pm, reverse, upsidedown);
9805b261ecSmrg        return;
9905b261ecSmrg    }
10005b261ecSmrg
10105b261ecSmrg    FbInitializeMergeRop(alu, pm);
10205b261ecSmrg    destInvarient = FbDestInvarientMergeRop();
10335c4bbdfSmrg    if (upsidedown) {
10435c4bbdfSmrg        srcLine += (height - 1) * (srcStride);
10535c4bbdfSmrg        dstLine += (height - 1) * (dstStride);
10635c4bbdfSmrg        srcStride = -srcStride;
10735c4bbdfSmrg        dstStride = -dstStride;
10805b261ecSmrg    }
10935c4bbdfSmrg    FbMaskBitsBytes(dstX, width, destInvarient, startmask, startbyte,
11035c4bbdfSmrg                    nmiddle, endmask, endbyte);
11135c4bbdfSmrg    if (reverse) {
11235c4bbdfSmrg        srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1;
11335c4bbdfSmrg        dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1;
11435c4bbdfSmrg        srcX = (srcX + width - 1) & FB_MASK;
11535c4bbdfSmrg        dstX = (dstX + width - 1) & FB_MASK;
11605b261ecSmrg    }
11735c4bbdfSmrg    else {
11835c4bbdfSmrg        srcLine += srcX >> FB_SHIFT;
11935c4bbdfSmrg        dstLine += dstX >> FB_SHIFT;
12035c4bbdfSmrg        srcX &= FB_MASK;
12135c4bbdfSmrg        dstX &= FB_MASK;
12205b261ecSmrg    }
12335c4bbdfSmrg    if (srcX == dstX) {
12435c4bbdfSmrg        while (height--) {
12535c4bbdfSmrg            src = srcLine;
12635c4bbdfSmrg            srcLine += srcStride;
12735c4bbdfSmrg            dst = dstLine;
12835c4bbdfSmrg            dstLine += dstStride;
12935c4bbdfSmrg            if (reverse) {
13035c4bbdfSmrg                if (endmask) {
13135c4bbdfSmrg                    bits = READ(--src);
13235c4bbdfSmrg                    --dst;
13335c4bbdfSmrg                    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
13435c4bbdfSmrg                }
13535c4bbdfSmrg                n = nmiddle;
13635c4bbdfSmrg                if (destInvarient) {
13735c4bbdfSmrg                    while (n--)
13835c4bbdfSmrg                        WRITE(--dst, FbDoDestInvarientMergeRop(READ(--src)));
13935c4bbdfSmrg                }
14035c4bbdfSmrg                else {
14135c4bbdfSmrg                    while (n--) {
14235c4bbdfSmrg                        bits = READ(--src);
14335c4bbdfSmrg                        --dst;
14435c4bbdfSmrg                        WRITE(dst, FbDoMergeRop(bits, READ(dst)));
14535c4bbdfSmrg                    }
14635c4bbdfSmrg                }
14735c4bbdfSmrg                if (startmask) {
14835c4bbdfSmrg                    bits = READ(--src);
14935c4bbdfSmrg                    --dst;
15035c4bbdfSmrg                    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
15135c4bbdfSmrg                }
15235c4bbdfSmrg            }
15335c4bbdfSmrg            else {
15435c4bbdfSmrg                if (startmask) {
15535c4bbdfSmrg                    bits = READ(src++);
15635c4bbdfSmrg                    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
15735c4bbdfSmrg                    dst++;
15835c4bbdfSmrg                }
15935c4bbdfSmrg                n = nmiddle;
16035c4bbdfSmrg                if (destInvarient) {
16105b261ecSmrg#if 0
16235c4bbdfSmrg                    /*
16335c4bbdfSmrg                     * This provides some speedup on screen->screen blts
16435c4bbdfSmrg                     * over the PCI bus, usually about 10%.  But fb
16535c4bbdfSmrg                     * isn't usually used for this operation...
16635c4bbdfSmrg                     */
16735c4bbdfSmrg                    if (_ca2 + 1 == 0 && _cx2 == 0) {
16835c4bbdfSmrg                        FbBits t1, t2, t3, t4;
16935c4bbdfSmrg
17035c4bbdfSmrg                        while (n >= 4) {
17135c4bbdfSmrg                            t1 = *src++;
17235c4bbdfSmrg                            t2 = *src++;
17335c4bbdfSmrg                            t3 = *src++;
17435c4bbdfSmrg                            t4 = *src++;
17535c4bbdfSmrg                            *dst++ = t1;
17635c4bbdfSmrg                            *dst++ = t2;
17735c4bbdfSmrg                            *dst++ = t3;
17835c4bbdfSmrg                            *dst++ = t4;
17935c4bbdfSmrg                            n -= 4;
18035c4bbdfSmrg                        }
18135c4bbdfSmrg                    }
18205b261ecSmrg#endif
18335c4bbdfSmrg                    while (n--)
18435c4bbdfSmrg                        WRITE(dst++, FbDoDestInvarientMergeRop(READ(src++)));
18535c4bbdfSmrg                }
18635c4bbdfSmrg                else {
18735c4bbdfSmrg                    while (n--) {
18835c4bbdfSmrg                        bits = READ(src++);
18935c4bbdfSmrg                        WRITE(dst, FbDoMergeRop(bits, READ(dst)));
19035c4bbdfSmrg                        dst++;
19135c4bbdfSmrg                    }
19235c4bbdfSmrg                }
19335c4bbdfSmrg                if (endmask) {
19435c4bbdfSmrg                    bits = READ(src);
19535c4bbdfSmrg                    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
19635c4bbdfSmrg                }
19735c4bbdfSmrg            }
19835c4bbdfSmrg        }
19905b261ecSmrg    }
20035c4bbdfSmrg    else {
20135c4bbdfSmrg        if (srcX > dstX) {
20235c4bbdfSmrg            leftShift = srcX - dstX;
20335c4bbdfSmrg            rightShift = FB_UNIT - leftShift;
20435c4bbdfSmrg        }
20535c4bbdfSmrg        else {
20635c4bbdfSmrg            rightShift = dstX - srcX;
20735c4bbdfSmrg            leftShift = FB_UNIT - rightShift;
20835c4bbdfSmrg        }
20935c4bbdfSmrg        while (height--) {
21035c4bbdfSmrg            src = srcLine;
21135c4bbdfSmrg            srcLine += srcStride;
21235c4bbdfSmrg            dst = dstLine;
21335c4bbdfSmrg            dstLine += dstStride;
21435c4bbdfSmrg
21535c4bbdfSmrg            bits1 = 0;
21635c4bbdfSmrg            if (reverse) {
21735c4bbdfSmrg                if (srcX < dstX)
21835c4bbdfSmrg                    bits1 = READ(--src);
21935c4bbdfSmrg                if (endmask) {
22035c4bbdfSmrg                    bits = FbScrRight(bits1, rightShift);
22135c4bbdfSmrg                    if (FbScrRight(endmask, leftShift)) {
22235c4bbdfSmrg                        bits1 = READ(--src);
22335c4bbdfSmrg                        bits |= FbScrLeft(bits1, leftShift);
22435c4bbdfSmrg                    }
22535c4bbdfSmrg                    --dst;
22635c4bbdfSmrg                    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
22735c4bbdfSmrg                }
22835c4bbdfSmrg                n = nmiddle;
22935c4bbdfSmrg                if (destInvarient) {
23035c4bbdfSmrg                    while (n--) {
23135c4bbdfSmrg                        bits = FbScrRight(bits1, rightShift);
23235c4bbdfSmrg                        bits1 = READ(--src);
23335c4bbdfSmrg                        bits |= FbScrLeft(bits1, leftShift);
23435c4bbdfSmrg                        --dst;
23535c4bbdfSmrg                        WRITE(dst, FbDoDestInvarientMergeRop(bits));
23635c4bbdfSmrg                    }
23735c4bbdfSmrg                }
23835c4bbdfSmrg                else {
23935c4bbdfSmrg                    while (n--) {
24035c4bbdfSmrg                        bits = FbScrRight(bits1, rightShift);
24135c4bbdfSmrg                        bits1 = READ(--src);
24235c4bbdfSmrg                        bits |= FbScrLeft(bits1, leftShift);
24335c4bbdfSmrg                        --dst;
24435c4bbdfSmrg                        WRITE(dst, FbDoMergeRop(bits, READ(dst)));
24535c4bbdfSmrg                    }
24635c4bbdfSmrg                }
24735c4bbdfSmrg                if (startmask) {
24835c4bbdfSmrg                    bits = FbScrRight(bits1, rightShift);
24935c4bbdfSmrg                    if (FbScrRight(startmask, leftShift)) {
25035c4bbdfSmrg                        bits1 = READ(--src);
25135c4bbdfSmrg                        bits |= FbScrLeft(bits1, leftShift);
25235c4bbdfSmrg                    }
25335c4bbdfSmrg                    --dst;
25435c4bbdfSmrg                    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
25535c4bbdfSmrg                }
25635c4bbdfSmrg            }
25735c4bbdfSmrg            else {
25835c4bbdfSmrg                if (srcX > dstX)
25935c4bbdfSmrg                    bits1 = READ(src++);
26035c4bbdfSmrg                if (startmask) {
26135c4bbdfSmrg                    bits = FbScrLeft(bits1, leftShift);
26235c4bbdfSmrg                    if (FbScrLeft(startmask, rightShift)) {
26335c4bbdfSmrg                        bits1 = READ(src++);
26435c4bbdfSmrg                        bits |= FbScrRight(bits1, rightShift);
26535c4bbdfSmrg                    }
26635c4bbdfSmrg                    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
26735c4bbdfSmrg                    dst++;
26835c4bbdfSmrg                }
26935c4bbdfSmrg                n = nmiddle;
27035c4bbdfSmrg                if (destInvarient) {
27135c4bbdfSmrg                    while (n--) {
27235c4bbdfSmrg                        bits = FbScrLeft(bits1, leftShift);
27335c4bbdfSmrg                        bits1 = READ(src++);
27435c4bbdfSmrg                        bits |= FbScrRight(bits1, rightShift);
27535c4bbdfSmrg                        WRITE(dst, FbDoDestInvarientMergeRop(bits));
27635c4bbdfSmrg                        dst++;
27735c4bbdfSmrg                    }
27835c4bbdfSmrg                }
27935c4bbdfSmrg                else {
28035c4bbdfSmrg                    while (n--) {
28135c4bbdfSmrg                        bits = FbScrLeft(bits1, leftShift);
28235c4bbdfSmrg                        bits1 = READ(src++);
28335c4bbdfSmrg                        bits |= FbScrRight(bits1, rightShift);
28435c4bbdfSmrg                        WRITE(dst, FbDoMergeRop(bits, READ(dst)));
28535c4bbdfSmrg                        dst++;
28635c4bbdfSmrg                    }
28735c4bbdfSmrg                }
28835c4bbdfSmrg                if (endmask) {
28935c4bbdfSmrg                    bits = FbScrLeft(bits1, leftShift);
29035c4bbdfSmrg                    if (FbScrLeft(endmask, rightShift)) {
29135c4bbdfSmrg                        bits1 = READ(src);
29235c4bbdfSmrg                        bits |= FbScrRight(bits1, rightShift);
29335c4bbdfSmrg                    }
29435c4bbdfSmrg                    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
29535c4bbdfSmrg                }
29635c4bbdfSmrg            }
29735c4bbdfSmrg        }
29805b261ecSmrg    }
29905b261ecSmrg}
30005b261ecSmrg
30105b261ecSmrg#undef DEBUG_BLT24
30205b261ecSmrg#ifdef DEBUG_BLT24
30305b261ecSmrg
30405b261ecSmrgstatic unsigned long
30535c4bbdfSmrggetPixel(char *src, int x)
30605b261ecSmrg{
30735c4bbdfSmrg    unsigned long l;
30805b261ecSmrg
30905b261ecSmrg    l = 0;
31035c4bbdfSmrg    memcpy(&l, src + x * 3, 3);
31105b261ecSmrg    return l;
31205b261ecSmrg}
31305b261ecSmrg#endif
31405b261ecSmrg
31505b261ecSmrgstatic void
31635c4bbdfSmrgfbBlt24Line(FbBits * src,
31735c4bbdfSmrg            int srcX,
31835c4bbdfSmrg            FbBits * dst, int dstX, int width, int alu, FbBits pm, Bool reverse)
31905b261ecSmrg{
32005b261ecSmrg#ifdef DEBUG_BLT24
32135c4bbdfSmrg    char *origDst = (char *) dst;
32235c4bbdfSmrg    FbBits *origLine = dst + ((dstX >> FB_SHIFT) - 1);
32335c4bbdfSmrg    int origNlw = ((width + FB_MASK) >> FB_SHIFT) + 3;
32435c4bbdfSmrg    int origX = dstX / 24;
32505b261ecSmrg#endif
32605b261ecSmrg
32735c4bbdfSmrg    int leftShift, rightShift;
32835c4bbdfSmrg    FbBits startmask, endmask;
32935c4bbdfSmrg    int n;
33035c4bbdfSmrg
33135c4bbdfSmrg    FbBits bits, bits1;
33235c4bbdfSmrg    FbBits mask;
33335c4bbdfSmrg
33435c4bbdfSmrg    int rot;
33535c4bbdfSmrg
33635c4bbdfSmrg    FbDeclareMergeRop();
33735c4bbdfSmrg
33835c4bbdfSmrg    FbInitializeMergeRop(alu, FB_ALLONES);
33905b261ecSmrg    FbMaskBits(dstX, width, startmask, n, endmask);
34005b261ecSmrg#ifdef DEBUG_BLT24
34135c4bbdfSmrg    ErrorF("dstX %d width %d reverse %d\n", dstX, width, reverse);
34205b261ecSmrg#endif
34335c4bbdfSmrg    if (reverse) {
34435c4bbdfSmrg        src += ((srcX + width - 1) >> FB_SHIFT) + 1;
34535c4bbdfSmrg        dst += ((dstX + width - 1) >> FB_SHIFT) + 1;
34635c4bbdfSmrg        rot = FbFirst24Rot(((dstX + width - 8) & FB_MASK));
34735c4bbdfSmrg        rot = FbPrev24Rot(rot);
34805b261ecSmrg#ifdef DEBUG_BLT24
34935c4bbdfSmrg        ErrorF("dstX + width - 8: %d rot: %d\n", (dstX + width - 8) & FB_MASK,
35035c4bbdfSmrg               rot);
35105b261ecSmrg#endif
35235c4bbdfSmrg        srcX = (srcX + width - 1) & FB_MASK;
35335c4bbdfSmrg        dstX = (dstX + width - 1) & FB_MASK;
35405b261ecSmrg    }
35535c4bbdfSmrg    else {
35635c4bbdfSmrg        src += srcX >> FB_SHIFT;
35735c4bbdfSmrg        dst += dstX >> FB_SHIFT;
35835c4bbdfSmrg        srcX &= FB_MASK;
35935c4bbdfSmrg        dstX &= FB_MASK;
36035c4bbdfSmrg        rot = FbFirst24Rot(dstX);
36105b261ecSmrg#ifdef DEBUG_BLT24
36235c4bbdfSmrg        ErrorF("dstX: %d rot: %d\n", dstX, rot);
36305b261ecSmrg#endif
36405b261ecSmrg    }
36535c4bbdfSmrg    mask = FbRot24(pm, rot);
36605b261ecSmrg#ifdef DEBUG_BLT24
36735c4bbdfSmrg    ErrorF("pm 0x%x mask 0x%x\n", pm, mask);
36805b261ecSmrg#endif
36935c4bbdfSmrg    if (srcX == dstX) {
37035c4bbdfSmrg        if (reverse) {
37135c4bbdfSmrg            if (endmask) {
37235c4bbdfSmrg                bits = READ(--src);
37335c4bbdfSmrg                --dst;
37435c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & endmask));
37535c4bbdfSmrg                mask = FbPrev24Pix(mask);
37635c4bbdfSmrg            }
37735c4bbdfSmrg            while (n--) {
37835c4bbdfSmrg                bits = READ(--src);
37935c4bbdfSmrg                --dst;
38035c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask));
38135c4bbdfSmrg                mask = FbPrev24Pix(mask);
38235c4bbdfSmrg            }
38335c4bbdfSmrg            if (startmask) {
38435c4bbdfSmrg                bits = READ(--src);
38535c4bbdfSmrg                --dst;
38635c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & startmask));
38735c4bbdfSmrg            }
38835c4bbdfSmrg        }
38935c4bbdfSmrg        else {
39035c4bbdfSmrg            if (startmask) {
39135c4bbdfSmrg                bits = READ(src++);
39235c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & startmask));
39335c4bbdfSmrg                dst++;
39435c4bbdfSmrg                mask = FbNext24Pix(mask);
39535c4bbdfSmrg            }
39635c4bbdfSmrg            while (n--) {
39735c4bbdfSmrg                bits = READ(src++);
39835c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask));
39935c4bbdfSmrg                dst++;
40035c4bbdfSmrg                mask = FbNext24Pix(mask);
40135c4bbdfSmrg            }
40235c4bbdfSmrg            if (endmask) {
40335c4bbdfSmrg                bits = READ(src);
40435c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & endmask));
40535c4bbdfSmrg            }
40635c4bbdfSmrg        }
40705b261ecSmrg    }
40835c4bbdfSmrg    else {
40935c4bbdfSmrg        if (srcX > dstX) {
41035c4bbdfSmrg            leftShift = srcX - dstX;
41135c4bbdfSmrg            rightShift = FB_UNIT - leftShift;
41235c4bbdfSmrg        }
41335c4bbdfSmrg        else {
41435c4bbdfSmrg            rightShift = dstX - srcX;
41535c4bbdfSmrg            leftShift = FB_UNIT - rightShift;
41635c4bbdfSmrg        }
41735c4bbdfSmrg
41835c4bbdfSmrg        bits1 = 0;
41935c4bbdfSmrg        if (reverse) {
42035c4bbdfSmrg            if (srcX < dstX)
42135c4bbdfSmrg                bits1 = READ(--src);
42235c4bbdfSmrg            if (endmask) {
42335c4bbdfSmrg                bits = FbScrRight(bits1, rightShift);
42435c4bbdfSmrg                if (FbScrRight(endmask, leftShift)) {
42535c4bbdfSmrg                    bits1 = READ(--src);
42635c4bbdfSmrg                    bits |= FbScrLeft(bits1, leftShift);
42735c4bbdfSmrg                }
42835c4bbdfSmrg                --dst;
42935c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & endmask));
43035c4bbdfSmrg                mask = FbPrev24Pix(mask);
43135c4bbdfSmrg            }
43235c4bbdfSmrg            while (n--) {
43335c4bbdfSmrg                bits = FbScrRight(bits1, rightShift);
43435c4bbdfSmrg                bits1 = READ(--src);
43535c4bbdfSmrg                bits |= FbScrLeft(bits1, leftShift);
43635c4bbdfSmrg                --dst;
43735c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask));
43835c4bbdfSmrg                mask = FbPrev24Pix(mask);
43935c4bbdfSmrg            }
44035c4bbdfSmrg            if (startmask) {
44135c4bbdfSmrg                bits = FbScrRight(bits1, rightShift);
44235c4bbdfSmrg                if (FbScrRight(startmask, leftShift)) {
44335c4bbdfSmrg                    bits1 = READ(--src);
44435c4bbdfSmrg                    bits |= FbScrLeft(bits1, leftShift);
44535c4bbdfSmrg                }
44635c4bbdfSmrg                --dst;
44735c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & startmask));
44835c4bbdfSmrg            }
44935c4bbdfSmrg        }
45035c4bbdfSmrg        else {
45135c4bbdfSmrg            if (srcX > dstX)
45235c4bbdfSmrg                bits1 = READ(src++);
45335c4bbdfSmrg            if (startmask) {
45435c4bbdfSmrg                bits = FbScrLeft(bits1, leftShift);
45535c4bbdfSmrg                bits1 = READ(src++);
45635c4bbdfSmrg                bits |= FbScrRight(bits1, rightShift);
45735c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & startmask));
45835c4bbdfSmrg                dst++;
45935c4bbdfSmrg                mask = FbNext24Pix(mask);
46035c4bbdfSmrg            }
46135c4bbdfSmrg            while (n--) {
46235c4bbdfSmrg                bits = FbScrLeft(bits1, leftShift);
46335c4bbdfSmrg                bits1 = READ(src++);
46435c4bbdfSmrg                bits |= FbScrRight(bits1, rightShift);
46535c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask));
46635c4bbdfSmrg                dst++;
46735c4bbdfSmrg                mask = FbNext24Pix(mask);
46835c4bbdfSmrg            }
46935c4bbdfSmrg            if (endmask) {
47035c4bbdfSmrg                bits = FbScrLeft(bits1, leftShift);
47135c4bbdfSmrg                if (FbScrLeft(endmask, rightShift)) {
47235c4bbdfSmrg                    bits1 = READ(src);
47335c4bbdfSmrg                    bits |= FbScrRight(bits1, rightShift);
47435c4bbdfSmrg                }
47535c4bbdfSmrg                WRITE(dst, FbDoMaskMergeRop(bits, READ(dst), mask & endmask));
47635c4bbdfSmrg            }
47735c4bbdfSmrg        }
47805b261ecSmrg    }
47905b261ecSmrg#ifdef DEBUG_BLT24
48005b261ecSmrg    {
48135c4bbdfSmrg        int firstx, lastx, x;
48235c4bbdfSmrg
48335c4bbdfSmrg        firstx = origX;
48435c4bbdfSmrg        if (firstx)
48535c4bbdfSmrg            firstx--;
48635c4bbdfSmrg        lastx = origX + width / 24 + 1;
48735c4bbdfSmrg        for (x = firstx; x <= lastx; x++)
48835c4bbdfSmrg            ErrorF("%06x ", getPixel(origDst, x));
48935c4bbdfSmrg        ErrorF("\n");
49035c4bbdfSmrg        while (origNlw--)
49135c4bbdfSmrg            ErrorF("%08x ", *origLine++);
49235c4bbdfSmrg        ErrorF("\n");
49305b261ecSmrg    }
49405b261ecSmrg#endif
49505b261ecSmrg}
49605b261ecSmrg
49705b261ecSmrgvoid
49835c4bbdfSmrgfbBlt24(FbBits * srcLine,
49935c4bbdfSmrg        FbStride srcStride,
50035c4bbdfSmrg        int srcX,
50135c4bbdfSmrg        FbBits * dstLine,
50235c4bbdfSmrg        FbStride dstStride,
50335c4bbdfSmrg        int dstX,
50435c4bbdfSmrg        int width,
50535c4bbdfSmrg        int height, int alu, FbBits pm, Bool reverse, Bool upsidedown)
50605b261ecSmrg{
50735c4bbdfSmrg    if (upsidedown) {
50835c4bbdfSmrg        srcLine += (height - 1) * srcStride;
50935c4bbdfSmrg        dstLine += (height - 1) * dstStride;
51035c4bbdfSmrg        srcStride = -srcStride;
51135c4bbdfSmrg        dstStride = -dstStride;
51205b261ecSmrg    }
51335c4bbdfSmrg    while (height--) {
51435c4bbdfSmrg        fbBlt24Line(srcLine, srcX, dstLine, dstX, width, alu, pm, reverse);
51535c4bbdfSmrg        srcLine += srcStride;
51635c4bbdfSmrg        dstLine += dstStride;
51705b261ecSmrg    }
51805b261ecSmrg#ifdef DEBUG_BLT24
51935c4bbdfSmrg    ErrorF("\n");
52005b261ecSmrg#endif
52105b261ecSmrg}
52205b261ecSmrg
52305b261ecSmrgvoid
52435c4bbdfSmrgfbBltStip(FbStip * src, FbStride srcStride,     /* in FbStip units, not FbBits units */
52535c4bbdfSmrg          int srcX, FbStip * dst, FbStride dstStride,   /* in FbStip units, not FbBits units */
52635c4bbdfSmrg          int dstX, int width, int height, int alu, FbBits pm, int bpp)
52705b261ecSmrg{
52835c4bbdfSmrg    fbBlt((FbBits *) src, FbStipStrideToBitsStride(srcStride), srcX,
52935c4bbdfSmrg          (FbBits *) dst, FbStipStrideToBitsStride(dstStride), dstX,
53035c4bbdfSmrg          width, height, alu, pm, bpp, FALSE, FALSE);
53105b261ecSmrg}
532