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 alignment
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