fbbltone.c revision 1b5d61b8
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 "fb.h"
28
29/*
30 * Stipple masks are independent of bit/byte order as long
31 * as bitorder == byteorder.  FB doesn't handle the case
32 * where these differ
33 */
34#define BitsMask(x,w)	((FB_ALLONES << ((x) & FB_MASK)) & \
35			 (FB_ALLONES >> ((FB_UNIT - ((x) + (w))) & FB_MASK)))
36
37#define Mask(x,w)	BitsMask((x)*(w),(w))
38
39#define SelMask(b,n,w)	((((b) >> n) & 1) * Mask(n,w))
40
41#define C1(b,w) \
42    (SelMask(b,0,w))
43
44#define C2(b,w) \
45    (SelMask(b,0,w) | \
46     SelMask(b,1,w))
47
48#define C4(b,w) \
49    (SelMask(b,0,w) | \
50     SelMask(b,1,w) | \
51     SelMask(b,2,w) | \
52     SelMask(b,3,w))
53
54#define C8(b,w) \
55    (SelMask(b,0,w) | \
56     SelMask(b,1,w) | \
57     SelMask(b,2,w) | \
58     SelMask(b,3,w) | \
59     SelMask(b,4,w) | \
60     SelMask(b,5,w) | \
61     SelMask(b,6,w) | \
62     SelMask(b,7,w))
63
64static const FbBits fbStipple8Bits[256] = {
65    C8(0, 4), C8(1, 4), C8(2, 4), C8(3, 4), C8(4, 4), C8(5, 4),
66    C8(6, 4), C8(7, 4), C8(8, 4), C8(9, 4), C8(10, 4), C8(11, 4),
67    C8(12, 4), C8(13, 4), C8(14, 4), C8(15, 4), C8(16, 4), C8(17, 4),
68    C8(18, 4), C8(19, 4), C8(20, 4), C8(21, 4), C8(22, 4), C8(23, 4),
69    C8(24, 4), C8(25, 4), C8(26, 4), C8(27, 4), C8(28, 4), C8(29, 4),
70    C8(30, 4), C8(31, 4), C8(32, 4), C8(33, 4), C8(34, 4), C8(35, 4),
71    C8(36, 4), C8(37, 4), C8(38, 4), C8(39, 4), C8(40, 4), C8(41, 4),
72    C8(42, 4), C8(43, 4), C8(44, 4), C8(45, 4), C8(46, 4), C8(47, 4),
73    C8(48, 4), C8(49, 4), C8(50, 4), C8(51, 4), C8(52, 4), C8(53, 4),
74    C8(54, 4), C8(55, 4), C8(56, 4), C8(57, 4), C8(58, 4), C8(59, 4),
75    C8(60, 4), C8(61, 4), C8(62, 4), C8(63, 4), C8(64, 4), C8(65, 4),
76    C8(66, 4), C8(67, 4), C8(68, 4), C8(69, 4), C8(70, 4), C8(71, 4),
77    C8(72, 4), C8(73, 4), C8(74, 4), C8(75, 4), C8(76, 4), C8(77, 4),
78    C8(78, 4), C8(79, 4), C8(80, 4), C8(81, 4), C8(82, 4), C8(83, 4),
79    C8(84, 4), C8(85, 4), C8(86, 4), C8(87, 4), C8(88, 4), C8(89, 4),
80    C8(90, 4), C8(91, 4), C8(92, 4), C8(93, 4), C8(94, 4), C8(95, 4),
81    C8(96, 4), C8(97, 4), C8(98, 4), C8(99, 4), C8(100, 4), C8(101, 4),
82    C8(102, 4), C8(103, 4), C8(104, 4), C8(105, 4), C8(106, 4), C8(107, 4),
83    C8(108, 4), C8(109, 4), C8(110, 4), C8(111, 4), C8(112, 4), C8(113, 4),
84    C8(114, 4), C8(115, 4), C8(116, 4), C8(117, 4), C8(118, 4), C8(119, 4),
85    C8(120, 4), C8(121, 4), C8(122, 4), C8(123, 4), C8(124, 4), C8(125, 4),
86    C8(126, 4), C8(127, 4), C8(128, 4), C8(129, 4), C8(130, 4), C8(131, 4),
87    C8(132, 4), C8(133, 4), C8(134, 4), C8(135, 4), C8(136, 4), C8(137, 4),
88    C8(138, 4), C8(139, 4), C8(140, 4), C8(141, 4), C8(142, 4), C8(143, 4),
89    C8(144, 4), C8(145, 4), C8(146, 4), C8(147, 4), C8(148, 4), C8(149, 4),
90    C8(150, 4), C8(151, 4), C8(152, 4), C8(153, 4), C8(154, 4), C8(155, 4),
91    C8(156, 4), C8(157, 4), C8(158, 4), C8(159, 4), C8(160, 4), C8(161, 4),
92    C8(162, 4), C8(163, 4), C8(164, 4), C8(165, 4), C8(166, 4), C8(167, 4),
93    C8(168, 4), C8(169, 4), C8(170, 4), C8(171, 4), C8(172, 4), C8(173, 4),
94    C8(174, 4), C8(175, 4), C8(176, 4), C8(177, 4), C8(178, 4), C8(179, 4),
95    C8(180, 4), C8(181, 4), C8(182, 4), C8(183, 4), C8(184, 4), C8(185, 4),
96    C8(186, 4), C8(187, 4), C8(188, 4), C8(189, 4), C8(190, 4), C8(191, 4),
97    C8(192, 4), C8(193, 4), C8(194, 4), C8(195, 4), C8(196, 4), C8(197, 4),
98    C8(198, 4), C8(199, 4), C8(200, 4), C8(201, 4), C8(202, 4), C8(203, 4),
99    C8(204, 4), C8(205, 4), C8(206, 4), C8(207, 4), C8(208, 4), C8(209, 4),
100    C8(210, 4), C8(211, 4), C8(212, 4), C8(213, 4), C8(214, 4), C8(215, 4),
101    C8(216, 4), C8(217, 4), C8(218, 4), C8(219, 4), C8(220, 4), C8(221, 4),
102    C8(222, 4), C8(223, 4), C8(224, 4), C8(225, 4), C8(226, 4), C8(227, 4),
103    C8(228, 4), C8(229, 4), C8(230, 4), C8(231, 4), C8(232, 4), C8(233, 4),
104    C8(234, 4), C8(235, 4), C8(236, 4), C8(237, 4), C8(238, 4), C8(239, 4),
105    C8(240, 4), C8(241, 4), C8(242, 4), C8(243, 4), C8(244, 4), C8(245, 4),
106    C8(246, 4), C8(247, 4), C8(248, 4), C8(249, 4), C8(250, 4), C8(251, 4),
107    C8(252, 4), C8(253, 4), C8(254, 4), C8(255, 4),
108};
109
110static const FbBits fbStipple4Bits[16] = {
111    C4(0, 8), C4(1, 8), C4(2, 8), C4(3, 8), C4(4, 8), C4(5, 8),
112    C4(6, 8), C4(7, 8), C4(8, 8), C4(9, 8), C4(10, 8), C4(11, 8),
113    C4(12, 8), C4(13, 8), C4(14, 8), C4(15, 8),
114};
115
116static const FbBits fbStipple2Bits[4] = {
117    C2(0, 16), C2(1, 16), C2(2, 16), C2(3, 16),
118};
119
120static const FbBits fbStipple1Bits[2] = {
121    C1(0, 32), C1(1, 32),
122};
123
124#ifdef __clang__
125/* shift overflow is intentional */
126#pragma clang diagnostic ignored "-Wshift-overflow"
127#endif
128
129/*
130 *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
131 *
132 *	**** **** **** **** **** **** **** ****
133 *			^
134 *	********  ********  ********  ********
135 *		  ^
136 *  leftShift = 12
137 *  rightShift = 20
138 *
139 *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
140 *
141 *	**** **** **** **** **** **** **** ****
142 *	^
143 *	********  ********  ********  ********
144 *		  ^
145 *
146 *  leftShift = 24
147 *  rightShift = 8
148 */
149
150#define LoadBits {\
151    if (leftShift) { \
152	bitsRight = (src < srcEnd ? READ(src++) : 0); \
153	bits = (FbStipLeft (bitsLeft, leftShift) | \
154		FbStipRight(bitsRight, rightShift)); \
155	bitsLeft = bitsRight; \
156    } else \
157	bits = (src < srcEnd ? READ(src++) : 0); \
158}
159
160void
161fbBltOne(FbStip * src, FbStride srcStride,      /* FbStip units per scanline */
162         int srcX,              /* bit position of source */
163         FbBits * dst, FbStride dstStride,      /* FbBits units per scanline */
164         int dstX,              /* bit position of dest */
165         int dstBpp,            /* bits per destination unit */
166         int width,             /* width in bits of destination */
167         int height,            /* height in scanlines */
168         FbBits fgand,          /* rrop values */
169         FbBits fgxor, FbBits bgand, FbBits bgxor)
170{
171    const FbBits *fbBits;
172    FbBits *srcEnd;
173    int pixelsPerDst;           /* dst pixels per FbBits */
174    int unitsPerSrc;            /* src patterns per FbStip */
175    int leftShift, rightShift;  /* align source with dest */
176    FbBits startmask, endmask;  /* dest scanline masks */
177    FbStip bits = 0, bitsLeft, bitsRight;       /* source bits */
178    FbStip left;
179    FbBits mask;
180    int nDst;                   /* dest longwords (w.o. end) */
181    int w;
182    int n, nmiddle;
183    int dstS;                   /* stipple-relative dst X coordinate */
184    Bool copy;                  /* accelerate dest-invariant */
185    Bool transparent;           /* accelerate 0 nop */
186    int srcinc;                 /* source units consumed */
187    Bool endNeedsLoad = FALSE;  /* need load for endmask */
188    int startbyte, endbyte;
189
190    /*
191     * Do not read past the end of the buffer!
192     */
193    srcEnd = src + height * srcStride;
194
195    /*
196     * Number of destination units in FbBits == number of stipple pixels
197     * used each time
198     */
199    pixelsPerDst = FB_UNIT / dstBpp;
200
201    /*
202     * Number of source stipple patterns in FbStip
203     */
204    unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
205
206    copy = FALSE;
207    transparent = FALSE;
208    if (bgand == 0 && fgand == 0)
209        copy = TRUE;
210    else if (bgand == FB_ALLONES && bgxor == 0)
211        transparent = TRUE;
212
213    /*
214     * Adjust source and dest to nearest FbBits boundary
215     */
216    src += srcX >> FB_STIP_SHIFT;
217    dst += dstX >> FB_SHIFT;
218    srcX &= FB_STIP_MASK;
219    dstX &= FB_MASK;
220
221    FbMaskBitsBytes(dstX, width, copy,
222                    startmask, startbyte, nmiddle, endmask, endbyte);
223
224    /*
225     * Compute effective dest alignment requirement for
226     * source -- must align source to dest unit boundary
227     */
228    dstS = dstX / dstBpp;
229    /*
230     * Compute shift constants for effective alignement
231     */
232    if (srcX >= dstS) {
233        leftShift = srcX - dstS;
234        rightShift = FB_STIP_UNIT - leftShift;
235    }
236    else {
237        rightShift = dstS - srcX;
238        leftShift = FB_STIP_UNIT - rightShift;
239    }
240    /*
241     * Get pointer to stipple mask array for this depth
242     */
243    fbBits = 0;                 /* unused */
244    switch (pixelsPerDst) {
245    case 8:
246        fbBits = fbStipple8Bits;
247        break;
248    case 4:
249        fbBits = fbStipple4Bits;
250        break;
251    case 2:
252        fbBits = fbStipple2Bits;
253        break;
254    case 1:
255        fbBits = fbStipple1Bits;
256        break;
257    default:
258        return;
259    }
260
261    /*
262     * Compute total number of destination words written, but
263     * don't count endmask
264     */
265    nDst = nmiddle;
266    if (startmask)
267        nDst++;
268
269    dstStride -= nDst;
270
271    /*
272     * Compute total number of source words consumed
273     */
274
275    srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
276
277    if (srcX > dstS)
278        srcinc++;
279    if (endmask) {
280        endNeedsLoad = nDst % unitsPerSrc == 0;
281        if (endNeedsLoad)
282            srcinc++;
283    }
284
285    srcStride -= srcinc;
286
287    /*
288     * Copy rectangle
289     */
290    while (height--) {
291        w = nDst;               /* total units across scanline */
292        n = unitsPerSrc;        /* units avail in single stipple */
293        if (n > w)
294            n = w;
295
296        bitsLeft = 0;
297        if (srcX > dstS)
298            bitsLeft = READ(src++);
299        if (n) {
300            /*
301             * Load first set of stipple bits
302             */
303            LoadBits;
304
305            /*
306             * Consume stipple bits for startmask
307             */
308            if (startmask) {
309                mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
310                if (mask || !transparent)
311                    FbDoLeftMaskByteStippleRRop(dst, mask,
312                                                fgand, fgxor, bgand, bgxor,
313                                                startbyte, startmask);
314                bits = FbStipLeft(bits, pixelsPerDst);
315                dst++;
316                n--;
317                w--;
318            }
319            /*
320             * Consume stipple bits across scanline
321             */
322            for (;;) {
323                w -= n;
324                if (copy) {
325                    while (n--) {
326                        mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
327                        WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor));
328                        dst++;
329                        bits = FbStipLeft(bits, pixelsPerDst);
330                    }
331                }
332                else {
333                    while (n--) {
334                        left = FbLeftStipBits(bits, pixelsPerDst);
335                        if (left || !transparent) {
336                            mask = fbBits[left];
337                            WRITE(dst, FbStippleRRop(READ(dst), mask, fgand,
338                                                     fgxor, bgand, bgxor));
339                        }
340                        dst++;
341                        bits = FbStipLeft(bits, pixelsPerDst);
342                    }
343                }
344                if (!w)
345                    break;
346                /*
347                 * Load another set and reset number of available units
348                 */
349                LoadBits;
350                n = unitsPerSrc;
351                if (n > w)
352                    n = w;
353            }
354        }
355        /*
356         * Consume stipple bits for endmask
357         */
358        if (endmask) {
359            if (endNeedsLoad) {
360                LoadBits;
361            }
362            mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
363            if (mask || !transparent)
364                FbDoRightMaskByteStippleRRop(dst, mask, fgand, fgxor,
365                                             bgand, bgxor, endbyte, endmask);
366        }
367        dst += dstStride;
368        src += srcStride;
369    }
370}
371
372/*
373 * Not very efficient, but simple -- copy a single plane
374 * from an N bit image to a 1 bit image
375 */
376
377void
378fbBltPlane(FbBits * src,
379           FbStride srcStride,
380           int srcX,
381           int srcBpp,
382           FbStip * dst,
383           FbStride dstStride,
384           int dstX,
385           int width,
386           int height,
387           FbStip fgand,
388           FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask)
389{
390    FbBits *s;
391    FbBits pm;
392    FbBits srcMask;
393    FbBits srcMaskFirst;
394    FbBits srcMask0 = 0;
395    FbBits srcBits;
396
397    FbStip dstBits;
398    FbStip *d;
399    FbStip dstMask;
400    FbStip dstMaskFirst;
401    FbStip dstUnion;
402    int w;
403    int wt;
404
405    if (!width)
406        return;
407
408    src += srcX >> FB_SHIFT;
409    srcX &= FB_MASK;
410
411    dst += dstX >> FB_STIP_SHIFT;
412    dstX &= FB_STIP_MASK;
413
414    w = width / srcBpp;
415
416    pm = fbReplicatePixel(planeMask, srcBpp);
417    srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
418    srcMask0 = pm & FbBitsMask(0, srcBpp);
419
420    dstMaskFirst = FbStipMask(dstX, 1);
421    while (height--) {
422        d = dst;
423        dst += dstStride;
424        s = src;
425        src += srcStride;
426
427        srcMask = srcMaskFirst;
428        srcBits = READ(s++);
429
430        dstMask = dstMaskFirst;
431        dstUnion = 0;
432        dstBits = 0;
433
434        wt = w;
435
436        while (wt--) {
437            if (!srcMask) {
438                srcBits = READ(s++);
439                srcMask = srcMask0;
440            }
441            if (!dstMask) {
442                WRITE(d, FbStippleRRopMask(READ(d), dstBits,
443                                           fgand, fgxor, bgand, bgxor,
444                                           dstUnion));
445                d++;
446                dstMask = FbStipMask(0, 1);
447                dstUnion = 0;
448                dstBits = 0;
449            }
450            if (srcBits & srcMask)
451                dstBits |= dstMask;
452            dstUnion |= dstMask;
453            if (srcBpp == FB_UNIT)
454                srcMask = 0;
455            else
456                srcMask = FbScrRight(srcMask, srcBpp);
457            dstMask = FbStipRight(dstMask, 1);
458        }
459        if (dstUnion)
460            WRITE(d, FbStippleRRopMask(READ(d), dstBits,
461                                       fgand, fgxor, bgand, bgxor, dstUnion));
462    }
463}
464