fbbltone.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 "fb.h"
2805b261ecSmrg
2935c4bbdfSmrg/*
3035c4bbdfSmrg * Stipple masks are independent of bit/byte order as long
3135c4bbdfSmrg * as bitorder == byteorder.  FB doesn't handle the case
3235c4bbdfSmrg * where these differ
3335c4bbdfSmrg */
3435c4bbdfSmrg#define BitsMask(x,w)	((FB_ALLONES << ((x) & FB_MASK)) & \
3535c4bbdfSmrg			 (FB_ALLONES >> ((FB_UNIT - ((x) + (w))) & FB_MASK)))
3635c4bbdfSmrg
3735c4bbdfSmrg#define Mask(x,w)	BitsMask((x)*(w),(w))
3835c4bbdfSmrg
3935c4bbdfSmrg#define SelMask(b,n,w)	((((b) >> n) & 1) * Mask(n,w))
4035c4bbdfSmrg
4135c4bbdfSmrg#define C1(b,w) \
4235c4bbdfSmrg    (SelMask(b,0,w))
4335c4bbdfSmrg
4435c4bbdfSmrg#define C2(b,w) \
4535c4bbdfSmrg    (SelMask(b,0,w) | \
4635c4bbdfSmrg     SelMask(b,1,w))
4735c4bbdfSmrg
4835c4bbdfSmrg#define C4(b,w) \
4935c4bbdfSmrg    (SelMask(b,0,w) | \
5035c4bbdfSmrg     SelMask(b,1,w) | \
5135c4bbdfSmrg     SelMask(b,2,w) | \
5235c4bbdfSmrg     SelMask(b,3,w))
5335c4bbdfSmrg
5435c4bbdfSmrg#define C8(b,w) \
5535c4bbdfSmrg    (SelMask(b,0,w) | \
5635c4bbdfSmrg     SelMask(b,1,w) | \
5735c4bbdfSmrg     SelMask(b,2,w) | \
5835c4bbdfSmrg     SelMask(b,3,w) | \
5935c4bbdfSmrg     SelMask(b,4,w) | \
6035c4bbdfSmrg     SelMask(b,5,w) | \
6135c4bbdfSmrg     SelMask(b,6,w) | \
6235c4bbdfSmrg     SelMask(b,7,w))
6335c4bbdfSmrg
6435c4bbdfSmrgstatic const FbBits fbStipple8Bits[256] = {
6535c4bbdfSmrg    C8(0, 4), C8(1, 4), C8(2, 4), C8(3, 4), C8(4, 4), C8(5, 4),
6635c4bbdfSmrg    C8(6, 4), C8(7, 4), C8(8, 4), C8(9, 4), C8(10, 4), C8(11, 4),
6735c4bbdfSmrg    C8(12, 4), C8(13, 4), C8(14, 4), C8(15, 4), C8(16, 4), C8(17, 4),
6835c4bbdfSmrg    C8(18, 4), C8(19, 4), C8(20, 4), C8(21, 4), C8(22, 4), C8(23, 4),
6935c4bbdfSmrg    C8(24, 4), C8(25, 4), C8(26, 4), C8(27, 4), C8(28, 4), C8(29, 4),
7035c4bbdfSmrg    C8(30, 4), C8(31, 4), C8(32, 4), C8(33, 4), C8(34, 4), C8(35, 4),
7135c4bbdfSmrg    C8(36, 4), C8(37, 4), C8(38, 4), C8(39, 4), C8(40, 4), C8(41, 4),
7235c4bbdfSmrg    C8(42, 4), C8(43, 4), C8(44, 4), C8(45, 4), C8(46, 4), C8(47, 4),
7335c4bbdfSmrg    C8(48, 4), C8(49, 4), C8(50, 4), C8(51, 4), C8(52, 4), C8(53, 4),
7435c4bbdfSmrg    C8(54, 4), C8(55, 4), C8(56, 4), C8(57, 4), C8(58, 4), C8(59, 4),
7535c4bbdfSmrg    C8(60, 4), C8(61, 4), C8(62, 4), C8(63, 4), C8(64, 4), C8(65, 4),
7635c4bbdfSmrg    C8(66, 4), C8(67, 4), C8(68, 4), C8(69, 4), C8(70, 4), C8(71, 4),
7735c4bbdfSmrg    C8(72, 4), C8(73, 4), C8(74, 4), C8(75, 4), C8(76, 4), C8(77, 4),
7835c4bbdfSmrg    C8(78, 4), C8(79, 4), C8(80, 4), C8(81, 4), C8(82, 4), C8(83, 4),
7935c4bbdfSmrg    C8(84, 4), C8(85, 4), C8(86, 4), C8(87, 4), C8(88, 4), C8(89, 4),
8035c4bbdfSmrg    C8(90, 4), C8(91, 4), C8(92, 4), C8(93, 4), C8(94, 4), C8(95, 4),
8135c4bbdfSmrg    C8(96, 4), C8(97, 4), C8(98, 4), C8(99, 4), C8(100, 4), C8(101, 4),
8235c4bbdfSmrg    C8(102, 4), C8(103, 4), C8(104, 4), C8(105, 4), C8(106, 4), C8(107, 4),
8335c4bbdfSmrg    C8(108, 4), C8(109, 4), C8(110, 4), C8(111, 4), C8(112, 4), C8(113, 4),
8435c4bbdfSmrg    C8(114, 4), C8(115, 4), C8(116, 4), C8(117, 4), C8(118, 4), C8(119, 4),
8535c4bbdfSmrg    C8(120, 4), C8(121, 4), C8(122, 4), C8(123, 4), C8(124, 4), C8(125, 4),
8635c4bbdfSmrg    C8(126, 4), C8(127, 4), C8(128, 4), C8(129, 4), C8(130, 4), C8(131, 4),
8735c4bbdfSmrg    C8(132, 4), C8(133, 4), C8(134, 4), C8(135, 4), C8(136, 4), C8(137, 4),
8835c4bbdfSmrg    C8(138, 4), C8(139, 4), C8(140, 4), C8(141, 4), C8(142, 4), C8(143, 4),
8935c4bbdfSmrg    C8(144, 4), C8(145, 4), C8(146, 4), C8(147, 4), C8(148, 4), C8(149, 4),
9035c4bbdfSmrg    C8(150, 4), C8(151, 4), C8(152, 4), C8(153, 4), C8(154, 4), C8(155, 4),
9135c4bbdfSmrg    C8(156, 4), C8(157, 4), C8(158, 4), C8(159, 4), C8(160, 4), C8(161, 4),
9235c4bbdfSmrg    C8(162, 4), C8(163, 4), C8(164, 4), C8(165, 4), C8(166, 4), C8(167, 4),
9335c4bbdfSmrg    C8(168, 4), C8(169, 4), C8(170, 4), C8(171, 4), C8(172, 4), C8(173, 4),
9435c4bbdfSmrg    C8(174, 4), C8(175, 4), C8(176, 4), C8(177, 4), C8(178, 4), C8(179, 4),
9535c4bbdfSmrg    C8(180, 4), C8(181, 4), C8(182, 4), C8(183, 4), C8(184, 4), C8(185, 4),
9635c4bbdfSmrg    C8(186, 4), C8(187, 4), C8(188, 4), C8(189, 4), C8(190, 4), C8(191, 4),
9735c4bbdfSmrg    C8(192, 4), C8(193, 4), C8(194, 4), C8(195, 4), C8(196, 4), C8(197, 4),
9835c4bbdfSmrg    C8(198, 4), C8(199, 4), C8(200, 4), C8(201, 4), C8(202, 4), C8(203, 4),
9935c4bbdfSmrg    C8(204, 4), C8(205, 4), C8(206, 4), C8(207, 4), C8(208, 4), C8(209, 4),
10035c4bbdfSmrg    C8(210, 4), C8(211, 4), C8(212, 4), C8(213, 4), C8(214, 4), C8(215, 4),
10135c4bbdfSmrg    C8(216, 4), C8(217, 4), C8(218, 4), C8(219, 4), C8(220, 4), C8(221, 4),
10235c4bbdfSmrg    C8(222, 4), C8(223, 4), C8(224, 4), C8(225, 4), C8(226, 4), C8(227, 4),
10335c4bbdfSmrg    C8(228, 4), C8(229, 4), C8(230, 4), C8(231, 4), C8(232, 4), C8(233, 4),
10435c4bbdfSmrg    C8(234, 4), C8(235, 4), C8(236, 4), C8(237, 4), C8(238, 4), C8(239, 4),
10535c4bbdfSmrg    C8(240, 4), C8(241, 4), C8(242, 4), C8(243, 4), C8(244, 4), C8(245, 4),
10635c4bbdfSmrg    C8(246, 4), C8(247, 4), C8(248, 4), C8(249, 4), C8(250, 4), C8(251, 4),
10735c4bbdfSmrg    C8(252, 4), C8(253, 4), C8(254, 4), C8(255, 4),
10835c4bbdfSmrg};
10935c4bbdfSmrg
11035c4bbdfSmrgstatic const FbBits fbStipple4Bits[16] = {
11135c4bbdfSmrg    C4(0, 8), C4(1, 8), C4(2, 8), C4(3, 8), C4(4, 8), C4(5, 8),
11235c4bbdfSmrg    C4(6, 8), C4(7, 8), C4(8, 8), C4(9, 8), C4(10, 8), C4(11, 8),
11335c4bbdfSmrg    C4(12, 8), C4(13, 8), C4(14, 8), C4(15, 8),
11435c4bbdfSmrg};
11535c4bbdfSmrg
11635c4bbdfSmrgstatic const FbBits fbStipple2Bits[4] = {
11735c4bbdfSmrg    C2(0, 16), C2(1, 16), C2(2, 16), C2(3, 16),
11835c4bbdfSmrg};
11935c4bbdfSmrg
12035c4bbdfSmrgstatic const FbBits fbStipple1Bits[2] = {
12135c4bbdfSmrg    C1(0, 32), C1(1, 32),
12235c4bbdfSmrg};
12335c4bbdfSmrg
12435c4bbdfSmrg#ifdef __clang__
12535c4bbdfSmrg/* shift overflow is intentional */
12635c4bbdfSmrg#pragma clang diagnostic ignored "-Wshift-overflow"
12735c4bbdfSmrg#endif
12835c4bbdfSmrg
12905b261ecSmrg/*
13005b261ecSmrg *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
13105b261ecSmrg *
13205b261ecSmrg *	**** **** **** **** **** **** **** ****
13305b261ecSmrg *			^
13405b261ecSmrg *	********  ********  ********  ********
13505b261ecSmrg *		  ^
13605b261ecSmrg *  leftShift = 12
13705b261ecSmrg *  rightShift = 20
13805b261ecSmrg *
13905b261ecSmrg *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
14005b261ecSmrg *
14105b261ecSmrg *	**** **** **** **** **** **** **** ****
14205b261ecSmrg *	^
14305b261ecSmrg *	********  ********  ********  ********
14405b261ecSmrg *		  ^
14505b261ecSmrg *
14605b261ecSmrg *  leftShift = 24
14705b261ecSmrg *  rightShift = 8
14805b261ecSmrg */
14905b261ecSmrg
15005b261ecSmrg#define LoadBits {\
15105b261ecSmrg    if (leftShift) { \
15205b261ecSmrg	bitsRight = (src < srcEnd ? READ(src++) : 0); \
15305b261ecSmrg	bits = (FbStipLeft (bitsLeft, leftShift) | \
15405b261ecSmrg		FbStipRight(bitsRight, rightShift)); \
15505b261ecSmrg	bitsLeft = bitsRight; \
15605b261ecSmrg    } else \
15705b261ecSmrg	bits = (src < srcEnd ? READ(src++) : 0); \
15805b261ecSmrg}
15905b261ecSmrg
16005b261ecSmrgvoid
16135c4bbdfSmrgfbBltOne(FbStip * src, FbStride srcStride,      /* FbStip units per scanline */
16235c4bbdfSmrg         int srcX,              /* bit position of source */
16335c4bbdfSmrg         FbBits * dst, FbStride dstStride,      /* FbBits units per scanline */
16435c4bbdfSmrg         int dstX,              /* bit position of dest */
16535c4bbdfSmrg         int dstBpp,            /* bits per destination unit */
16635c4bbdfSmrg         int width,             /* width in bits of destination */
16735c4bbdfSmrg         int height,            /* height in scanlines */
16835c4bbdfSmrg         FbBits fgand,          /* rrop values */
16935c4bbdfSmrg         FbBits fgxor, FbBits bgand, FbBits bgxor)
17005b261ecSmrg{
17135c4bbdfSmrg    const FbBits *fbBits;
17235c4bbdfSmrg    FbBits *srcEnd;
17335c4bbdfSmrg    int pixelsPerDst;           /* dst pixels per FbBits */
17435c4bbdfSmrg    int unitsPerSrc;            /* src patterns per FbStip */
17535c4bbdfSmrg    int leftShift, rightShift;  /* align source with dest */
17635c4bbdfSmrg    FbBits startmask, endmask;  /* dest scanline masks */
17735c4bbdfSmrg    FbStip bits = 0, bitsLeft, bitsRight;       /* source bits */
17835c4bbdfSmrg    FbStip left;
17935c4bbdfSmrg    FbBits mask;
18035c4bbdfSmrg    int nDst;                   /* dest longwords (w.o. end) */
18135c4bbdfSmrg    int w;
18235c4bbdfSmrg    int n, nmiddle;
18335c4bbdfSmrg    int dstS;                   /* stipple-relative dst X coordinate */
18435c4bbdfSmrg    Bool copy;                  /* accelerate dest-invariant */
18535c4bbdfSmrg    Bool transparent;           /* accelerate 0 nop */
18635c4bbdfSmrg    int srcinc;                 /* source units consumed */
18735c4bbdfSmrg    Bool endNeedsLoad = FALSE;  /* need load for endmask */
18835c4bbdfSmrg    int startbyte, endbyte;
18935c4bbdfSmrg
19035c4bbdfSmrg    if (dstBpp == 24) {
19135c4bbdfSmrg        fbBltOne24(src, srcStride, srcX,
19235c4bbdfSmrg                   dst, dstStride, dstX, dstBpp,
19335c4bbdfSmrg                   width, height, fgand, fgxor, bgand, bgxor);
19435c4bbdfSmrg        return;
19505b261ecSmrg    }
19605b261ecSmrg
19705b261ecSmrg    /*
19805b261ecSmrg     * Do not read past the end of the buffer!
19905b261ecSmrg     */
20005b261ecSmrg    srcEnd = src + height * srcStride;
20105b261ecSmrg
20205b261ecSmrg    /*
20305b261ecSmrg     * Number of destination units in FbBits == number of stipple pixels
20405b261ecSmrg     * used each time
20505b261ecSmrg     */
20605b261ecSmrg    pixelsPerDst = FB_UNIT / dstBpp;
20705b261ecSmrg
20805b261ecSmrg    /*
20935c4bbdfSmrg     * Number of source stipple patterns in FbStip
21005b261ecSmrg     */
21105b261ecSmrg    unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
21235c4bbdfSmrg
21305b261ecSmrg    copy = FALSE;
21405b261ecSmrg    transparent = FALSE;
21505b261ecSmrg    if (bgand == 0 && fgand == 0)
21635c4bbdfSmrg        copy = TRUE;
21705b261ecSmrg    else if (bgand == FB_ALLONES && bgxor == 0)
21835c4bbdfSmrg        transparent = TRUE;
21905b261ecSmrg
22005b261ecSmrg    /*
22105b261ecSmrg     * Adjust source and dest to nearest FbBits boundary
22205b261ecSmrg     */
22305b261ecSmrg    src += srcX >> FB_STIP_SHIFT;
22405b261ecSmrg    dst += dstX >> FB_SHIFT;
22505b261ecSmrg    srcX &= FB_STIP_MASK;
22605b261ecSmrg    dstX &= FB_MASK;
22705b261ecSmrg
22835c4bbdfSmrg    FbMaskBitsBytes(dstX, width, copy,
22935c4bbdfSmrg                    startmask, startbyte, nmiddle, endmask, endbyte);
23005b261ecSmrg
23105b261ecSmrg    /*
23205b261ecSmrg     * Compute effective dest alignment requirement for
23305b261ecSmrg     * source -- must align source to dest unit boundary
23405b261ecSmrg     */
23505b261ecSmrg    dstS = dstX / dstBpp;
23605b261ecSmrg    /*
23705b261ecSmrg     * Compute shift constants for effective alignement
23805b261ecSmrg     */
23935c4bbdfSmrg    if (srcX >= dstS) {
24035c4bbdfSmrg        leftShift = srcX - dstS;
24135c4bbdfSmrg        rightShift = FB_STIP_UNIT - leftShift;
24205b261ecSmrg    }
24335c4bbdfSmrg    else {
24435c4bbdfSmrg        rightShift = dstS - srcX;
24535c4bbdfSmrg        leftShift = FB_STIP_UNIT - rightShift;
24605b261ecSmrg    }
24705b261ecSmrg    /*
24805b261ecSmrg     * Get pointer to stipple mask array for this depth
24905b261ecSmrg     */
25035c4bbdfSmrg    fbBits = 0;                 /* unused */
25135c4bbdfSmrg    switch (pixelsPerDst) {
25235c4bbdfSmrg    case 8:
25335c4bbdfSmrg        fbBits = fbStipple8Bits;
25435c4bbdfSmrg        break;
25535c4bbdfSmrg    case 4:
25635c4bbdfSmrg        fbBits = fbStipple4Bits;
25735c4bbdfSmrg        break;
25835c4bbdfSmrg    case 2:
25935c4bbdfSmrg        fbBits = fbStipple2Bits;
26035c4bbdfSmrg        break;
26135c4bbdfSmrg    case 1:
26235c4bbdfSmrg        fbBits = fbStipple1Bits;
26335c4bbdfSmrg        break;
26435c4bbdfSmrg    default:
26535c4bbdfSmrg        return;
26635c4bbdfSmrg    }
26735c4bbdfSmrg
26805b261ecSmrg    /*
26935c4bbdfSmrg     * Compute total number of destination words written, but
27035c4bbdfSmrg     * don't count endmask
27105b261ecSmrg     */
27205b261ecSmrg    nDst = nmiddle;
27305b261ecSmrg    if (startmask)
27435c4bbdfSmrg        nDst++;
27535c4bbdfSmrg
27605b261ecSmrg    dstStride -= nDst;
27705b261ecSmrg
27805b261ecSmrg    /*
27905b261ecSmrg     * Compute total number of source words consumed
28005b261ecSmrg     */
28135c4bbdfSmrg
28205b261ecSmrg    srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
28335c4bbdfSmrg
28405b261ecSmrg    if (srcX > dstS)
28535c4bbdfSmrg        srcinc++;
28635c4bbdfSmrg    if (endmask) {
28735c4bbdfSmrg        endNeedsLoad = nDst % unitsPerSrc == 0;
28835c4bbdfSmrg        if (endNeedsLoad)
28935c4bbdfSmrg            srcinc++;
29005b261ecSmrg    }
29105b261ecSmrg
29205b261ecSmrg    srcStride -= srcinc;
29335c4bbdfSmrg
29405b261ecSmrg    /*
29505b261ecSmrg     * Copy rectangle
29605b261ecSmrg     */
29735c4bbdfSmrg    while (height--) {
29835c4bbdfSmrg        w = nDst;               /* total units across scanline */
29935c4bbdfSmrg        n = unitsPerSrc;        /* units avail in single stipple */
30035c4bbdfSmrg        if (n > w)
30135c4bbdfSmrg            n = w;
30235c4bbdfSmrg
30335c4bbdfSmrg        bitsLeft = 0;
30435c4bbdfSmrg        if (srcX > dstS)
30535c4bbdfSmrg            bitsLeft = READ(src++);
30635c4bbdfSmrg        if (n) {
30735c4bbdfSmrg            /*
30835c4bbdfSmrg             * Load first set of stipple bits
30935c4bbdfSmrg             */
31035c4bbdfSmrg            LoadBits;
31135c4bbdfSmrg
31235c4bbdfSmrg            /*
31335c4bbdfSmrg             * Consume stipple bits for startmask
31435c4bbdfSmrg             */
31535c4bbdfSmrg            if (startmask) {
31635c4bbdfSmrg                mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
31735c4bbdfSmrg                if (mask || !transparent)
31835c4bbdfSmrg                    FbDoLeftMaskByteStippleRRop(dst, mask,
31935c4bbdfSmrg                                                fgand, fgxor, bgand, bgxor,
32035c4bbdfSmrg                                                startbyte, startmask);
32135c4bbdfSmrg                bits = FbStipLeft(bits, pixelsPerDst);
32235c4bbdfSmrg                dst++;
32335c4bbdfSmrg                n--;
32435c4bbdfSmrg                w--;
32535c4bbdfSmrg            }
32635c4bbdfSmrg            /*
32735c4bbdfSmrg             * Consume stipple bits across scanline
32835c4bbdfSmrg             */
32935c4bbdfSmrg            for (;;) {
33035c4bbdfSmrg                w -= n;
33135c4bbdfSmrg                if (copy) {
33235c4bbdfSmrg                    while (n--) {
33335c4bbdfSmrg                        mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
33435c4bbdfSmrg                        WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor));
33535c4bbdfSmrg                        dst++;
33635c4bbdfSmrg                        bits = FbStipLeft(bits, pixelsPerDst);
33735c4bbdfSmrg                    }
33835c4bbdfSmrg                }
33935c4bbdfSmrg                else {
34035c4bbdfSmrg                    while (n--) {
34135c4bbdfSmrg                        left = FbLeftStipBits(bits, pixelsPerDst);
34235c4bbdfSmrg                        if (left || !transparent) {
34335c4bbdfSmrg                            mask = fbBits[left];
34435c4bbdfSmrg                            WRITE(dst, FbStippleRRop(READ(dst), mask, fgand,
34535c4bbdfSmrg                                                     fgxor, bgand, bgxor));
34635c4bbdfSmrg                        }
34735c4bbdfSmrg                        dst++;
34835c4bbdfSmrg                        bits = FbStipLeft(bits, pixelsPerDst);
34935c4bbdfSmrg                    }
35035c4bbdfSmrg                }
35135c4bbdfSmrg                if (!w)
35235c4bbdfSmrg                    break;
35335c4bbdfSmrg                /*
35435c4bbdfSmrg                 * Load another set and reset number of available units
35535c4bbdfSmrg                 */
35635c4bbdfSmrg                LoadBits;
35735c4bbdfSmrg                n = unitsPerSrc;
35835c4bbdfSmrg                if (n > w)
35935c4bbdfSmrg                    n = w;
36035c4bbdfSmrg            }
36135c4bbdfSmrg        }
36235c4bbdfSmrg        /*
36335c4bbdfSmrg         * Consume stipple bits for endmask
36435c4bbdfSmrg         */
36535c4bbdfSmrg        if (endmask) {
36635c4bbdfSmrg            if (endNeedsLoad) {
36735c4bbdfSmrg                LoadBits;
36835c4bbdfSmrg            }
36935c4bbdfSmrg            mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
37035c4bbdfSmrg            if (mask || !transparent)
37135c4bbdfSmrg                FbDoRightMaskByteStippleRRop(dst, mask, fgand, fgxor,
37235c4bbdfSmrg                                             bgand, bgxor, endbyte, endmask);
37335c4bbdfSmrg        }
37435c4bbdfSmrg        dst += dstStride;
37535c4bbdfSmrg        src += srcStride;
37605b261ecSmrg    }
37705b261ecSmrg}
37805b261ecSmrg
37905b261ecSmrg/*
38005b261ecSmrg * Crufty macros to initialize the mask array, most of this
38105b261ecSmrg * is to avoid compile-time warnings about shift overflow
38205b261ecSmrg */
38305b261ecSmrg
38405b261ecSmrg#if BITMAP_BIT_ORDER == MSBFirst
38505b261ecSmrg#define Mask24Pos(x,r) ((x)*24-(r))
38605b261ecSmrg#else
38705b261ecSmrg#define Mask24Pos(x,r) ((x)*24-((r) ? 24 - (r) : 0))
38805b261ecSmrg#endif
38905b261ecSmrg
39005b261ecSmrg#define Mask24Neg(x,r)	(Mask24Pos(x,r) < 0 ? -Mask24Pos(x,r) : 0)
39105b261ecSmrg#define Mask24Check(x,r)    (Mask24Pos(x,r) < 0 ? 0 : \
39205b261ecSmrg			     Mask24Pos(x,r) >= FB_UNIT ? 0 : Mask24Pos(x,r))
39305b261ecSmrg
39405b261ecSmrg#define Mask24(x,r) (Mask24Pos(x,r) < FB_UNIT ? \
39505b261ecSmrg		     (Mask24Pos(x,r) < 0 ? \
3969ace9065Smrg		      0xffffffU >> Mask24Neg (x,r) : \
3979ace9065Smrg		      0xffffffU << Mask24Check(x,r)) : 0)
39805b261ecSmrg
39905b261ecSmrg#define SelMask24(b,n,r)	((((b) >> n) & 1) * Mask24(n,r))
40005b261ecSmrg
40105b261ecSmrg#define C2_24(b,r)  \
40205b261ecSmrg    (SelMask24(b,0,r) | \
40305b261ecSmrg     SelMask24(b,1,r))
40405b261ecSmrg
40505b261ecSmrg#define FbStip24Len	    2
40605b261ecSmrg#if BITMAP_BIT_ORDER == MSBFirst
40705b261ecSmrg#define FbStip24New(rot)    (1 + (rot == 0))
40805b261ecSmrg#else
40905b261ecSmrg#define FbStip24New(rot)    (1 + (rot == 8))
41005b261ecSmrg#endif
41105b261ecSmrg
41235c4bbdfSmrgconst FbBits fbStipple24Bits[3][1 << FbStip24Len] = {
41305b261ecSmrg    /* rotate 0 */
41405b261ecSmrg    {
41535c4bbdfSmrg     C2_24(0, 0), C2_24(1, 0), C2_24(2, 0), C2_24(3, 0),
41635c4bbdfSmrg     },
41705b261ecSmrg    /* rotate 8 */
41805b261ecSmrg    {
41935c4bbdfSmrg     C2_24(0, 8), C2_24(1, 8), C2_24(2, 8), C2_24(3, 8),
42035c4bbdfSmrg     },
42105b261ecSmrg    /* rotate 16 */
42205b261ecSmrg    {
42335c4bbdfSmrg     C2_24(0, 16), C2_24(1, 16), C2_24(2, 16), C2_24(3, 16),
42435c4bbdfSmrg     }
42505b261ecSmrg};
42605b261ecSmrg
42705b261ecSmrg#if BITMAP_BIT_ORDER == LSBFirst
42805b261ecSmrg
42905b261ecSmrg#define FbMergeStip24Bits(left, right, new) \
43005b261ecSmrg	(FbStipLeft (left, new) | FbStipRight ((right), (FbStip24Len - (new))))
43105b261ecSmrg
43205b261ecSmrg#define FbMergePartStip24Bits(left, right, llen, rlen) \
43305b261ecSmrg	(left | FbStipRight(right, llen))
43405b261ecSmrg
43505b261ecSmrg#else
43605b261ecSmrg
43705b261ecSmrg#define FbMergeStip24Bits(left, right, new) \
43805b261ecSmrg	((FbStipLeft (left, new) & ((1 << FbStip24Len) - 1)) | right)
43905b261ecSmrg
44005b261ecSmrg#define FbMergePartStip24Bits(left, right, llen, rlen) \
44105b261ecSmrg	(FbStipLeft(left, rlen) | right)
44205b261ecSmrg
44305b261ecSmrg#endif
44405b261ecSmrg
44505b261ecSmrg#define fbFirstStipBits(len,stip) {\
44605b261ecSmrg    int	__len = (len); \
44705b261ecSmrg    if (len <= remain) { \
44805b261ecSmrg	stip = FbLeftStipBits(bits, len); \
44905b261ecSmrg    } else { \
45005b261ecSmrg	stip = FbLeftStipBits(bits, remain); \
45105b261ecSmrg	bits = (src < srcEnd ? READ(src++) : 0); \
45205b261ecSmrg	__len = (len) - remain; \
45305b261ecSmrg	stip = FbMergePartStip24Bits(stip, FbLeftStipBits(bits, __len), \
45405b261ecSmrg				     remain, __len); \
45505b261ecSmrg	remain = FB_STIP_UNIT; \
45605b261ecSmrg    } \
45705b261ecSmrg    bits = FbStipLeft (bits, __len); \
45805b261ecSmrg    remain -= __len; \
45905b261ecSmrg}
46005b261ecSmrg
46105b261ecSmrg#define fbInitStipBits(offset,len,stip) {\
46205b261ecSmrg    bits = FbStipLeft (READ(src++),offset); \
46305b261ecSmrg    remain = FB_STIP_UNIT - offset; \
46405b261ecSmrg    fbFirstStipBits(len,stip); \
46505b261ecSmrg    stip = FbMergeStip24Bits (0, stip, len); \
46605b261ecSmrg}
46735c4bbdfSmrg
46805b261ecSmrg#define fbNextStipBits(rot,stip) {\
46905b261ecSmrg    int	    __new = FbStip24New(rot); \
47005b261ecSmrg    FbStip  __right; \
47105b261ecSmrg    fbFirstStipBits(__new, __right); \
47205b261ecSmrg    stip = FbMergeStip24Bits (stip, __right, __new); \
47305b261ecSmrg    rot = FbNext24Rot (rot); \
47405b261ecSmrg}
47505b261ecSmrg
47605b261ecSmrg/*
47705b261ecSmrg * Use deep mask tables that incorporate rotation, pull
47805b261ecSmrg * a variable number of bits out of the stipple and
47905b261ecSmrg * reuse the right bits as needed for the next write
48005b261ecSmrg *
48105b261ecSmrg * Yes, this is probably too much code, but most 24-bpp screens
48205b261ecSmrg * have no acceleration so this code is used for stipples, copyplane
48305b261ecSmrg * and text
48405b261ecSmrg */
48505b261ecSmrgvoid
48635c4bbdfSmrgfbBltOne24(FbStip * srcLine, FbStride srcStride,        /* FbStip units per scanline */
48735c4bbdfSmrg           int srcX,            /* bit position of source */
48835c4bbdfSmrg           FbBits * dst, FbStride dstStride,    /* FbBits units per scanline */
48935c4bbdfSmrg           int dstX,            /* bit position of dest */
49035c4bbdfSmrg           int dstBpp,          /* bits per destination unit */
49135c4bbdfSmrg           int width,           /* width in bits of destination */
49235c4bbdfSmrg           int height,          /* height in scanlines */
49335c4bbdfSmrg           FbBits fgand,        /* rrop values */
49435c4bbdfSmrg           FbBits fgxor, FbBits bgand, FbBits bgxor)
49505b261ecSmrg{
49635c4bbdfSmrg    FbStip *src, *srcEnd;
49735c4bbdfSmrg    FbBits leftMask, rightMask, mask;
49835c4bbdfSmrg    int nlMiddle, nl;
49935c4bbdfSmrg    FbStip stip, bits;
50035c4bbdfSmrg    int remain;
50135c4bbdfSmrg    int dstS;
50235c4bbdfSmrg    int firstlen;
50335c4bbdfSmrg    int rot0, rot;
50435c4bbdfSmrg    int nDst;
50535c4bbdfSmrg
50605b261ecSmrg    /*
50705b261ecSmrg     * Do not read past the end of the buffer!
50805b261ecSmrg     */
50905b261ecSmrg    srcEnd = srcLine + height * srcStride;
51005b261ecSmrg
51105b261ecSmrg    srcLine += srcX >> FB_STIP_SHIFT;
51205b261ecSmrg    dst += dstX >> FB_SHIFT;
51305b261ecSmrg    srcX &= FB_STIP_MASK;
51405b261ecSmrg    dstX &= FB_MASK;
51535c4bbdfSmrg    rot0 = FbFirst24Rot(dstX);
51635c4bbdfSmrg
51735c4bbdfSmrg    FbMaskBits(dstX, width, leftMask, nlMiddle, rightMask);
51835c4bbdfSmrg
51905b261ecSmrg    dstS = (dstX + 23) / 24;
52005b261ecSmrg    firstlen = FbStip24Len - dstS;
52135c4bbdfSmrg
52205b261ecSmrg    nDst = nlMiddle;
52305b261ecSmrg    if (leftMask)
52435c4bbdfSmrg        nDst++;
52505b261ecSmrg    dstStride -= nDst;
52635c4bbdfSmrg
52705b261ecSmrg    /* opaque copy */
52835c4bbdfSmrg    if (bgand == 0 && fgand == 0) {
52935c4bbdfSmrg        while (height--) {
53035c4bbdfSmrg            rot = rot0;
53135c4bbdfSmrg            src = srcLine;
53235c4bbdfSmrg            srcLine += srcStride;
53335c4bbdfSmrg            fbInitStipBits(srcX, firstlen, stip);
53435c4bbdfSmrg            if (leftMask) {
53535c4bbdfSmrg                mask = fbStipple24Bits[rot >> 3][stip];
53635c4bbdfSmrg                WRITE(dst, (READ(dst) & ~leftMask) |
53735c4bbdfSmrg                      (FbOpaqueStipple(mask,
53835c4bbdfSmrg                                       FbRot24(fgxor, rot), FbRot24(bgxor, rot))
53935c4bbdfSmrg                       & leftMask));
54035c4bbdfSmrg                dst++;
54135c4bbdfSmrg                fbNextStipBits(rot, stip);
54235c4bbdfSmrg            }
54335c4bbdfSmrg            nl = nlMiddle;
54435c4bbdfSmrg            while (nl--) {
54535c4bbdfSmrg                mask = fbStipple24Bits[rot >> 3][stip];
54635c4bbdfSmrg                WRITE(dst, FbOpaqueStipple(mask,
54735c4bbdfSmrg                                           FbRot24(fgxor, rot),
54835c4bbdfSmrg                                           FbRot24(bgxor, rot)));
54935c4bbdfSmrg                dst++;
55035c4bbdfSmrg                fbNextStipBits(rot, stip);
55135c4bbdfSmrg            }
55235c4bbdfSmrg            if (rightMask) {
55335c4bbdfSmrg                mask = fbStipple24Bits[rot >> 3][stip];
55435c4bbdfSmrg                WRITE(dst, (READ(dst) & ~rightMask) |
55535c4bbdfSmrg                      (FbOpaqueStipple(mask,
55635c4bbdfSmrg                                       FbRot24(fgxor, rot), FbRot24(bgxor, rot))
55735c4bbdfSmrg                       & rightMask));
55835c4bbdfSmrg            }
55935c4bbdfSmrg            dst += dstStride;
56035c4bbdfSmrg            src += srcStride;
56135c4bbdfSmrg        }
56205b261ecSmrg    }
56305b261ecSmrg    /* transparent copy */
56435c4bbdfSmrg    else if (bgand == FB_ALLONES && bgxor == 0 && fgand == 0) {
56535c4bbdfSmrg        while (height--) {
56635c4bbdfSmrg            rot = rot0;
56735c4bbdfSmrg            src = srcLine;
56835c4bbdfSmrg            srcLine += srcStride;
56935c4bbdfSmrg            fbInitStipBits(srcX, firstlen, stip);
57035c4bbdfSmrg            if (leftMask) {
57135c4bbdfSmrg                if (stip) {
57235c4bbdfSmrg                    mask = fbStipple24Bits[rot >> 3][stip] & leftMask;
57335c4bbdfSmrg                    WRITE(dst,
57435c4bbdfSmrg                          (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
57535c4bbdfSmrg                }
57635c4bbdfSmrg                dst++;
57735c4bbdfSmrg                fbNextStipBits(rot, stip);
57835c4bbdfSmrg            }
57935c4bbdfSmrg            nl = nlMiddle;
58035c4bbdfSmrg            while (nl--) {
58135c4bbdfSmrg                if (stip) {
58235c4bbdfSmrg                    mask = fbStipple24Bits[rot >> 3][stip];
58335c4bbdfSmrg                    WRITE(dst,
58435c4bbdfSmrg                          (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
58535c4bbdfSmrg                }
58635c4bbdfSmrg                dst++;
58735c4bbdfSmrg                fbNextStipBits(rot, stip);
58835c4bbdfSmrg            }
58935c4bbdfSmrg            if (rightMask) {
59035c4bbdfSmrg                if (stip) {
59135c4bbdfSmrg                    mask = fbStipple24Bits[rot >> 3][stip] & rightMask;
59235c4bbdfSmrg                    WRITE(dst,
59335c4bbdfSmrg                          (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
59435c4bbdfSmrg                }
59535c4bbdfSmrg            }
59635c4bbdfSmrg            dst += dstStride;
59735c4bbdfSmrg        }
59805b261ecSmrg    }
59935c4bbdfSmrg    else {
60035c4bbdfSmrg        while (height--) {
60135c4bbdfSmrg            rot = rot0;
60235c4bbdfSmrg            src = srcLine;
60335c4bbdfSmrg            srcLine += srcStride;
60435c4bbdfSmrg            fbInitStipBits(srcX, firstlen, stip);
60535c4bbdfSmrg            if (leftMask) {
60635c4bbdfSmrg                mask = fbStipple24Bits[rot >> 3][stip];
60735c4bbdfSmrg                WRITE(dst, FbStippleRRopMask(READ(dst), mask,
60835c4bbdfSmrg                                             FbRot24(fgand, rot),
60935c4bbdfSmrg                                             FbRot24(fgxor, rot),
61035c4bbdfSmrg                                             FbRot24(bgand, rot),
61135c4bbdfSmrg                                             FbRot24(bgxor, rot), leftMask));
61235c4bbdfSmrg                dst++;
61335c4bbdfSmrg                fbNextStipBits(rot, stip);
61435c4bbdfSmrg            }
61535c4bbdfSmrg            nl = nlMiddle;
61635c4bbdfSmrg            while (nl--) {
61735c4bbdfSmrg                mask = fbStipple24Bits[rot >> 3][stip];
61835c4bbdfSmrg                WRITE(dst, FbStippleRRop(READ(dst), mask,
61935c4bbdfSmrg                                         FbRot24(fgand, rot),
62035c4bbdfSmrg                                         FbRot24(fgxor, rot),
62135c4bbdfSmrg                                         FbRot24(bgand, rot),
62235c4bbdfSmrg                                         FbRot24(bgxor, rot)));
62335c4bbdfSmrg                dst++;
62435c4bbdfSmrg                fbNextStipBits(rot, stip);
62535c4bbdfSmrg            }
62635c4bbdfSmrg            if (rightMask) {
62735c4bbdfSmrg                mask = fbStipple24Bits[rot >> 3][stip];
62835c4bbdfSmrg                WRITE(dst, FbStippleRRopMask(READ(dst), mask,
62935c4bbdfSmrg                                             FbRot24(fgand, rot),
63035c4bbdfSmrg                                             FbRot24(fgxor, rot),
63135c4bbdfSmrg                                             FbRot24(bgand, rot),
63235c4bbdfSmrg                                             FbRot24(bgxor, rot), rightMask));
63335c4bbdfSmrg            }
63435c4bbdfSmrg            dst += dstStride;
63535c4bbdfSmrg        }
63605b261ecSmrg    }
63705b261ecSmrg}
63805b261ecSmrg
63905b261ecSmrg/*
64005b261ecSmrg * Not very efficient, but simple -- copy a single plane
64105b261ecSmrg * from an N bit image to a 1 bit image
64205b261ecSmrg */
64335c4bbdfSmrg
64405b261ecSmrgvoid
64535c4bbdfSmrgfbBltPlane(FbBits * src,
64635c4bbdfSmrg           FbStride srcStride,
64735c4bbdfSmrg           int srcX,
64835c4bbdfSmrg           int srcBpp,
64935c4bbdfSmrg           FbStip * dst,
65035c4bbdfSmrg           FbStride dstStride,
65135c4bbdfSmrg           int dstX,
65235c4bbdfSmrg           int width,
65335c4bbdfSmrg           int height,
65435c4bbdfSmrg           FbStip fgand,
65535c4bbdfSmrg           FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask)
65605b261ecSmrg{
65735c4bbdfSmrg    FbBits *s;
65835c4bbdfSmrg    FbBits pm;
65935c4bbdfSmrg    FbBits srcMask;
66035c4bbdfSmrg    FbBits srcMaskFirst;
66135c4bbdfSmrg    FbBits srcMask0 = 0;
66235c4bbdfSmrg    FbBits srcBits;
66335c4bbdfSmrg
66435c4bbdfSmrg    FbStip dstBits;
66535c4bbdfSmrg    FbStip *d;
66635c4bbdfSmrg    FbStip dstMask;
66735c4bbdfSmrg    FbStip dstMaskFirst;
66835c4bbdfSmrg    FbStip dstUnion;
66935c4bbdfSmrg    int w;
67035c4bbdfSmrg    int wt;
67135c4bbdfSmrg    int rot0;
67205b261ecSmrg
67305b261ecSmrg    if (!width)
67435c4bbdfSmrg        return;
67535c4bbdfSmrg
67605b261ecSmrg    src += srcX >> FB_SHIFT;
67705b261ecSmrg    srcX &= FB_MASK;
67805b261ecSmrg
67905b261ecSmrg    dst += dstX >> FB_STIP_SHIFT;
68005b261ecSmrg    dstX &= FB_STIP_MASK;
68135c4bbdfSmrg
68205b261ecSmrg    w = width / srcBpp;
68305b261ecSmrg
68435c4bbdfSmrg    pm = fbReplicatePixel(planeMask, srcBpp);
68535c4bbdfSmrg    if (srcBpp == 24) {
68635c4bbdfSmrg        int tmpw = 24;
68705b261ecSmrg
68835c4bbdfSmrg        rot0 = FbFirst24Rot(srcX);
68935c4bbdfSmrg        if (srcX + tmpw > FB_UNIT)
69035c4bbdfSmrg            tmpw = FB_UNIT - srcX;
69135c4bbdfSmrg        srcMaskFirst = FbRot24(pm, rot0) & FbBitsMask(srcX, tmpw);
69205b261ecSmrg    }
69335c4bbdfSmrg    else {
69435c4bbdfSmrg        rot0 = 0;
69535c4bbdfSmrg        srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
69635c4bbdfSmrg        srcMask0 = pm & FbBitsMask(0, srcBpp);
69705b261ecSmrg    }
69835c4bbdfSmrg
69935c4bbdfSmrg    dstMaskFirst = FbStipMask(dstX, 1);
70035c4bbdfSmrg    while (height--) {
70135c4bbdfSmrg        d = dst;
70235c4bbdfSmrg        dst += dstStride;
70335c4bbdfSmrg        s = src;
70435c4bbdfSmrg        src += srcStride;
70535c4bbdfSmrg
70635c4bbdfSmrg        srcMask = srcMaskFirst;
70735c4bbdfSmrg        if (srcBpp == 24)
70835c4bbdfSmrg            srcMask0 = FbRot24(pm, rot0) & FbBitsMask(0, srcBpp);
70935c4bbdfSmrg        srcBits = READ(s++);
71035c4bbdfSmrg
71135c4bbdfSmrg        dstMask = dstMaskFirst;
71235c4bbdfSmrg        dstUnion = 0;
71335c4bbdfSmrg        dstBits = 0;
71435c4bbdfSmrg
71535c4bbdfSmrg        wt = w;
71635c4bbdfSmrg
71735c4bbdfSmrg        while (wt--) {
71835c4bbdfSmrg            if (!srcMask) {
71935c4bbdfSmrg                srcBits = READ(s++);
72035c4bbdfSmrg                if (srcBpp == 24)
72135c4bbdfSmrg                    srcMask0 = FbNext24Pix(srcMask0) & FbBitsMask(0, 24);
72235c4bbdfSmrg                srcMask = srcMask0;
72335c4bbdfSmrg            }
72435c4bbdfSmrg            if (!dstMask) {
72535c4bbdfSmrg                WRITE(d, FbStippleRRopMask(READ(d), dstBits,
72635c4bbdfSmrg                                           fgand, fgxor, bgand, bgxor,
72735c4bbdfSmrg                                           dstUnion));
72835c4bbdfSmrg                d++;
72935c4bbdfSmrg                dstMask = FbStipMask(0, 1);
73035c4bbdfSmrg                dstUnion = 0;
73135c4bbdfSmrg                dstBits = 0;
73235c4bbdfSmrg            }
73335c4bbdfSmrg            if (srcBits & srcMask)
73435c4bbdfSmrg                dstBits |= dstMask;
73535c4bbdfSmrg            dstUnion |= dstMask;
73635c4bbdfSmrg            if (srcBpp == FB_UNIT)
73735c4bbdfSmrg                srcMask = 0;
73835c4bbdfSmrg            else
73935c4bbdfSmrg                srcMask = FbScrRight(srcMask, srcBpp);
74035c4bbdfSmrg            dstMask = FbStipRight(dstMask, 1);
74135c4bbdfSmrg        }
74235c4bbdfSmrg        if (dstUnion)
74335c4bbdfSmrg            WRITE(d, FbStippleRRopMask(READ(d), dstBits,
74435c4bbdfSmrg                                       fgand, fgxor, bgand, bgxor, dstUnion));
74505b261ecSmrg    }
74605b261ecSmrg}
747