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 
64 static 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 
110 static 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 
116 static const FbBits fbStipple2Bits[4] = {
117     C2(0, 16), C2(1, 16), C2(2, 16), C2(3, 16),
118 };
119 
120 static 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 
160 void
fbBltOne(FbStip * src,FbStride srcStride,int srcX,FbBits * dst,FbStride dstStride,int dstX,int dstBpp,int width,int height,FbBits fgand,FbBits fgxor,FbBits bgand,FbBits bgxor)161 fbBltOne(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 
377 void
fbBltPlane(FbBits * src,FbStride srcStride,int srcX,int srcBpp,FbStip * dst,FbStride dstStride,int dstX,int width,int height,FbStip fgand,FbStip fgxor,FbStip bgand,FbStip bgxor,Pixel planeMask)378 fbBltPlane(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