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
9505b261ecSmrg    FbInitializeMergeRop(alu, pm);
9605b261ecSmrg    destInvarient = FbDestInvarientMergeRop();
9735c4bbdfSmrg    if (upsidedown) {
9835c4bbdfSmrg        srcLine += (height - 1) * (srcStride);
9935c4bbdfSmrg        dstLine += (height - 1) * (dstStride);
10035c4bbdfSmrg        srcStride = -srcStride;
10135c4bbdfSmrg        dstStride = -dstStride;
10205b261ecSmrg    }
10335c4bbdfSmrg    FbMaskBitsBytes(dstX, width, destInvarient, startmask, startbyte,
10435c4bbdfSmrg                    nmiddle, endmask, endbyte);
10535c4bbdfSmrg    if (reverse) {
10635c4bbdfSmrg        srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1;
10735c4bbdfSmrg        dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1;
10835c4bbdfSmrg        srcX = (srcX + width - 1) & FB_MASK;
10935c4bbdfSmrg        dstX = (dstX + width - 1) & FB_MASK;
11005b261ecSmrg    }
11135c4bbdfSmrg    else {
11235c4bbdfSmrg        srcLine += srcX >> FB_SHIFT;
11335c4bbdfSmrg        dstLine += dstX >> FB_SHIFT;
11435c4bbdfSmrg        srcX &= FB_MASK;
11535c4bbdfSmrg        dstX &= FB_MASK;
11605b261ecSmrg    }
11735c4bbdfSmrg    if (srcX == dstX) {
11835c4bbdfSmrg        while (height--) {
11935c4bbdfSmrg            src = srcLine;
12035c4bbdfSmrg            srcLine += srcStride;
12135c4bbdfSmrg            dst = dstLine;
12235c4bbdfSmrg            dstLine += dstStride;
12335c4bbdfSmrg            if (reverse) {
12435c4bbdfSmrg                if (endmask) {
12535c4bbdfSmrg                    bits = READ(--src);
12635c4bbdfSmrg                    --dst;
12735c4bbdfSmrg                    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
12835c4bbdfSmrg                }
12935c4bbdfSmrg                n = nmiddle;
13035c4bbdfSmrg                if (destInvarient) {
13135c4bbdfSmrg                    while (n--)
13235c4bbdfSmrg                        WRITE(--dst, FbDoDestInvarientMergeRop(READ(--src)));
13335c4bbdfSmrg                }
13435c4bbdfSmrg                else {
13535c4bbdfSmrg                    while (n--) {
13635c4bbdfSmrg                        bits = READ(--src);
13735c4bbdfSmrg                        --dst;
13835c4bbdfSmrg                        WRITE(dst, FbDoMergeRop(bits, READ(dst)));
13935c4bbdfSmrg                    }
14035c4bbdfSmrg                }
14135c4bbdfSmrg                if (startmask) {
14235c4bbdfSmrg                    bits = READ(--src);
14335c4bbdfSmrg                    --dst;
14435c4bbdfSmrg                    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
14535c4bbdfSmrg                }
14635c4bbdfSmrg            }
14735c4bbdfSmrg            else {
14835c4bbdfSmrg                if (startmask) {
14935c4bbdfSmrg                    bits = READ(src++);
15035c4bbdfSmrg                    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
15135c4bbdfSmrg                    dst++;
15235c4bbdfSmrg                }
15335c4bbdfSmrg                n = nmiddle;
15435c4bbdfSmrg                if (destInvarient) {
15505b261ecSmrg#if 0
15635c4bbdfSmrg                    /*
15735c4bbdfSmrg                     * This provides some speedup on screen->screen blts
15835c4bbdfSmrg                     * over the PCI bus, usually about 10%.  But fb
15935c4bbdfSmrg                     * isn't usually used for this operation...
16035c4bbdfSmrg                     */
16135c4bbdfSmrg                    if (_ca2 + 1 == 0 && _cx2 == 0) {
16235c4bbdfSmrg                        FbBits t1, t2, t3, t4;
16335c4bbdfSmrg
16435c4bbdfSmrg                        while (n >= 4) {
16535c4bbdfSmrg                            t1 = *src++;
16635c4bbdfSmrg                            t2 = *src++;
16735c4bbdfSmrg                            t3 = *src++;
16835c4bbdfSmrg                            t4 = *src++;
16935c4bbdfSmrg                            *dst++ = t1;
17035c4bbdfSmrg                            *dst++ = t2;
17135c4bbdfSmrg                            *dst++ = t3;
17235c4bbdfSmrg                            *dst++ = t4;
17335c4bbdfSmrg                            n -= 4;
17435c4bbdfSmrg                        }
17535c4bbdfSmrg                    }
17605b261ecSmrg#endif
17735c4bbdfSmrg                    while (n--)
17835c4bbdfSmrg                        WRITE(dst++, FbDoDestInvarientMergeRop(READ(src++)));
17935c4bbdfSmrg                }
18035c4bbdfSmrg                else {
18135c4bbdfSmrg                    while (n--) {
18235c4bbdfSmrg                        bits = READ(src++);
18335c4bbdfSmrg                        WRITE(dst, FbDoMergeRop(bits, READ(dst)));
18435c4bbdfSmrg                        dst++;
18535c4bbdfSmrg                    }
18635c4bbdfSmrg                }
18735c4bbdfSmrg                if (endmask) {
18835c4bbdfSmrg                    bits = READ(src);
18935c4bbdfSmrg                    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
19035c4bbdfSmrg                }
19135c4bbdfSmrg            }
19235c4bbdfSmrg        }
19305b261ecSmrg    }
19435c4bbdfSmrg    else {
19535c4bbdfSmrg        if (srcX > dstX) {
19635c4bbdfSmrg            leftShift = srcX - dstX;
19735c4bbdfSmrg            rightShift = FB_UNIT - leftShift;
19835c4bbdfSmrg        }
19935c4bbdfSmrg        else {
20035c4bbdfSmrg            rightShift = dstX - srcX;
20135c4bbdfSmrg            leftShift = FB_UNIT - rightShift;
20235c4bbdfSmrg        }
20335c4bbdfSmrg        while (height--) {
20435c4bbdfSmrg            src = srcLine;
20535c4bbdfSmrg            srcLine += srcStride;
20635c4bbdfSmrg            dst = dstLine;
20735c4bbdfSmrg            dstLine += dstStride;
20835c4bbdfSmrg
20935c4bbdfSmrg            bits1 = 0;
21035c4bbdfSmrg            if (reverse) {
21135c4bbdfSmrg                if (srcX < dstX)
21235c4bbdfSmrg                    bits1 = READ(--src);
21335c4bbdfSmrg                if (endmask) {
21435c4bbdfSmrg                    bits = FbScrRight(bits1, rightShift);
21535c4bbdfSmrg                    if (FbScrRight(endmask, leftShift)) {
21635c4bbdfSmrg                        bits1 = READ(--src);
21735c4bbdfSmrg                        bits |= FbScrLeft(bits1, leftShift);
21835c4bbdfSmrg                    }
21935c4bbdfSmrg                    --dst;
22035c4bbdfSmrg                    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
22135c4bbdfSmrg                }
22235c4bbdfSmrg                n = nmiddle;
22335c4bbdfSmrg                if (destInvarient) {
22435c4bbdfSmrg                    while (n--) {
22535c4bbdfSmrg                        bits = FbScrRight(bits1, rightShift);
22635c4bbdfSmrg                        bits1 = READ(--src);
22735c4bbdfSmrg                        bits |= FbScrLeft(bits1, leftShift);
22835c4bbdfSmrg                        --dst;
22935c4bbdfSmrg                        WRITE(dst, FbDoDestInvarientMergeRop(bits));
23035c4bbdfSmrg                    }
23135c4bbdfSmrg                }
23235c4bbdfSmrg                else {
23335c4bbdfSmrg                    while (n--) {
23435c4bbdfSmrg                        bits = FbScrRight(bits1, rightShift);
23535c4bbdfSmrg                        bits1 = READ(--src);
23635c4bbdfSmrg                        bits |= FbScrLeft(bits1, leftShift);
23735c4bbdfSmrg                        --dst;
23835c4bbdfSmrg                        WRITE(dst, FbDoMergeRop(bits, READ(dst)));
23935c4bbdfSmrg                    }
24035c4bbdfSmrg                }
24135c4bbdfSmrg                if (startmask) {
24235c4bbdfSmrg                    bits = FbScrRight(bits1, rightShift);
24335c4bbdfSmrg                    if (FbScrRight(startmask, leftShift)) {
24435c4bbdfSmrg                        bits1 = READ(--src);
24535c4bbdfSmrg                        bits |= FbScrLeft(bits1, leftShift);
24635c4bbdfSmrg                    }
24735c4bbdfSmrg                    --dst;
24835c4bbdfSmrg                    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
24935c4bbdfSmrg                }
25035c4bbdfSmrg            }
25135c4bbdfSmrg            else {
25235c4bbdfSmrg                if (srcX > dstX)
25335c4bbdfSmrg                    bits1 = READ(src++);
25435c4bbdfSmrg                if (startmask) {
25535c4bbdfSmrg                    bits = FbScrLeft(bits1, leftShift);
25635c4bbdfSmrg                    if (FbScrLeft(startmask, rightShift)) {
25735c4bbdfSmrg                        bits1 = READ(src++);
25835c4bbdfSmrg                        bits |= FbScrRight(bits1, rightShift);
25935c4bbdfSmrg                    }
26035c4bbdfSmrg                    FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
26135c4bbdfSmrg                    dst++;
26235c4bbdfSmrg                }
26335c4bbdfSmrg                n = nmiddle;
26435c4bbdfSmrg                if (destInvarient) {
26535c4bbdfSmrg                    while (n--) {
26635c4bbdfSmrg                        bits = FbScrLeft(bits1, leftShift);
26735c4bbdfSmrg                        bits1 = READ(src++);
26835c4bbdfSmrg                        bits |= FbScrRight(bits1, rightShift);
26935c4bbdfSmrg                        WRITE(dst, FbDoDestInvarientMergeRop(bits));
27035c4bbdfSmrg                        dst++;
27135c4bbdfSmrg                    }
27235c4bbdfSmrg                }
27335c4bbdfSmrg                else {
27435c4bbdfSmrg                    while (n--) {
27535c4bbdfSmrg                        bits = FbScrLeft(bits1, leftShift);
27635c4bbdfSmrg                        bits1 = READ(src++);
27735c4bbdfSmrg                        bits |= FbScrRight(bits1, rightShift);
27835c4bbdfSmrg                        WRITE(dst, FbDoMergeRop(bits, READ(dst)));
27935c4bbdfSmrg                        dst++;
28035c4bbdfSmrg                    }
28135c4bbdfSmrg                }
28235c4bbdfSmrg                if (endmask) {
28335c4bbdfSmrg                    bits = FbScrLeft(bits1, leftShift);
28435c4bbdfSmrg                    if (FbScrLeft(endmask, rightShift)) {
28535c4bbdfSmrg                        bits1 = READ(src);
28635c4bbdfSmrg                        bits |= FbScrRight(bits1, rightShift);
28735c4bbdfSmrg                    }
28835c4bbdfSmrg                    FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
28935c4bbdfSmrg                }
29035c4bbdfSmrg            }
29135c4bbdfSmrg        }
29205b261ecSmrg    }
29305b261ecSmrg}
29405b261ecSmrg
29505b261ecSmrgvoid
29635c4bbdfSmrgfbBltStip(FbStip * src, FbStride srcStride,     /* in FbStip units, not FbBits units */
29735c4bbdfSmrg          int srcX, FbStip * dst, FbStride dstStride,   /* in FbStip units, not FbBits units */
29835c4bbdfSmrg          int dstX, int width, int height, int alu, FbBits pm, int bpp)
29905b261ecSmrg{
30035c4bbdfSmrg    fbBlt((FbBits *) src, FbStipStrideToBitsStride(srcStride), srcX,
30135c4bbdfSmrg          (FbBits *) dst, FbStipStrideToBitsStride(dstStride), dstX,
30235c4bbdfSmrg          width, height, alu, pm, bpp, FALSE, FALSE);
30305b261ecSmrg}
304