2 * Copyright © 1998 Keith Packard
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.
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.
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
30 /* shift overflow is intentional */
31 #pragma clang diagnostic ignored "-Wshift-overflow"
35 * Example: srcX = 13 dstX = 8 (FB unit 32 dstBpp 8)
37 * **** **** **** **** **** **** **** ****
39 * ******** ******** ******** ********
44 * Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
46 * **** **** **** **** **** **** **** ****
48 * ******** ******** ******** ********
57 bitsRight = (src < srcEnd ? READ(src++) : 0); \
58 bits = (FbStipLeft (bitsLeft, leftShift) | \
59 FbStipRight(bitsRight, rightShift)); \
60 bitsLeft = bitsRight; \
62 bits = (src < srcEnd ? READ(src++) : 0); \
65 #define LaneCases1(n,a) case n: FbLaneCase(n,a); break
66 #define LaneCases2(n,a) LaneCases1(n,a); LaneCases1(n+1,a)
67 #define LaneCases4(n,a) LaneCases2(n,a); LaneCases2(n+2,a)
68 #define LaneCases8(n,a) LaneCases4(n,a); LaneCases4(n+4,a)
69 #define LaneCases16(n,a) LaneCases8(n,a); LaneCases8(n+8,a)
70 #define LaneCases32(n,a) LaneCases16(n,a); LaneCases16(n+16,a)
71 #define LaneCases64(n,a) LaneCases32(n,a); LaneCases32(n+32,a)
72 #define LaneCases128(n,a) LaneCases64(n,a); LaneCases64(n+64,a)
73 #define LaneCases256(n,a) LaneCases128(n,a); LaneCases128(n+128,a)
76 #define LaneCases(a) LaneCases256(0,a)
80 #define LaneCases(a) LaneCases16(0,a)
84 CARD8 fb8Lane
[256] = {
85 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
87 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
88 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
89 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
90 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
91 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
93 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
95 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
97 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
99 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
101 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
103 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
105 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
107 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
110 CARD8 fb16Lane
[256] = {
111 0x00, 0x03, 0x0c, 0x0f,
112 0x30, 0x33, 0x3c, 0x3f,
113 0xc0, 0xc3, 0xcc, 0xcf,
114 0xf0, 0xf3, 0xfc, 0xff,
117 CARD8 fb32Lane
[16] = {
118 0x00, 0x0f, 0xf0, 0xff,
123 CARD8 fb8Lane
[16] = {
124 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
127 CARD8 fb16Lane
[16] = {
128 0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131 CARD8 fb32Lane
[16] = {
132 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
136 CARD8
*fbLaneTable
[33] = {
137 0, 0, 0, 0, 0, 0, 0, 0,
138 fb8Lane
, 0, 0, 0, 0, 0, 0, 0,
139 fb16Lane
, 0, 0, 0, 0, 0, 0, 0,
140 0, 0, 0, 0, 0, 0, 0, 0,
145 fbBltOne(FbStip
* src
, FbStride srcStride
, /* FbStip units per scanline */
146 int srcX
, /* bit position of source */
147 FbBits
* dst
, FbStride dstStride
, /* FbBits units per scanline */
148 int dstX
, /* bit position of dest */
149 int dstBpp
, /* bits per destination unit */
150 int width
, /* width in bits of destination */
151 int height
, /* height in scanlines */
152 FbBits fgand
, /* rrop values */
153 FbBits fgxor
, FbBits bgand
, FbBits bgxor
)
155 const FbBits
*fbBits
;
157 int pixelsPerDst
; /* dst pixels per FbBits */
158 int unitsPerSrc
; /* src patterns per FbStip */
159 int leftShift
, rightShift
; /* align source with dest */
160 FbBits startmask
, endmask
; /* dest scanline masks */
161 FbStip bits
= 0, bitsLeft
, bitsRight
; /* source bits */
164 int nDst
; /* dest longwords (w.o. end) */
167 int dstS
; /* stipple-relative dst X coordinate */
168 Bool copy
; /* accelerate dest-invariant */
169 Bool transparent
; /* accelerate 0 nop */
170 int srcinc
; /* source units consumed */
171 Bool endNeedsLoad
= FALSE
; /* need load for endmask */
173 int startbyte
, endbyte
;
176 fbBltOne24(src
, srcStride
, srcX
,
177 dst
, dstStride
, dstX
, dstBpp
,
178 width
, height
, fgand
, fgxor
, bgand
, bgxor
);
183 * Do not read past the end of the buffer!
185 srcEnd
= src
+ height
* srcStride
;
188 * Number of destination units in FbBits == number of stipple pixels
191 pixelsPerDst
= FB_UNIT
/ dstBpp
;
194 * Number of source stipple patterns in FbStip
196 unitsPerSrc
= FB_STIP_UNIT
/ pixelsPerDst
;
200 if (bgand
== 0 && fgand
== 0)
202 else if (bgand
== FB_ALLONES
&& bgxor
== 0)
206 * Adjust source and dest to nearest FbBits boundary
208 src
+= srcX
>> FB_STIP_SHIFT
;
209 dst
+= dstX
>> FB_SHIFT
;
210 srcX
&= FB_STIP_MASK
;
213 FbMaskBitsBytes(dstX
, width
, copy
,
214 startmask
, startbyte
, nmiddle
, endmask
, endbyte
);
217 * Compute effective dest alignment requirement for
218 * source -- must align source to dest unit boundary
220 dstS
= dstX
/ dstBpp
;
222 * Compute shift constants for effective alignement
225 leftShift
= srcX
- dstS
;
226 rightShift
= FB_STIP_UNIT
- leftShift
;
229 rightShift
= dstS
- srcX
;
230 leftShift
= FB_STIP_UNIT
- rightShift
;
233 * Get pointer to stipple mask array for this depth
235 fbBits
= 0; /* unused */
236 if (pixelsPerDst
<= 8)
237 fbBits
= fbStippleTable
[pixelsPerDst
];
239 if (transparent
&& fgand
== 0 && dstBpp
>= 8)
240 fbLane
= fbLaneTable
[dstBpp
];
243 * Compute total number of destination words written, but
244 * don't count endmask
253 * Compute total number of source words consumed
256 srcinc
= (nDst
+ unitsPerSrc
- 1) / unitsPerSrc
;
261 endNeedsLoad
= nDst
% unitsPerSrc
== 0;
272 w
= nDst
; /* total units across scanline */
273 n
= unitsPerSrc
; /* units avail in single stipple */
279 bitsLeft
= READ(src
++);
282 * Load first set of stipple bits
287 * Consume stipple bits for startmask
291 if (pixelsPerDst
== 16)
292 mask
= FbStipple16Bits(FbLeftStipBits(bits
, 16));
295 mask
= fbBits
[FbLeftStipBits(bits
, pixelsPerDst
)];
297 fbTransparentSpan(dst
, mask
& startmask
, fgxor
, 1);
300 if (mask
|| !transparent
)
301 FbDoLeftMaskByteStippleRRop(dst
, mask
,
302 fgand
, fgxor
, bgand
, bgxor
,
303 startbyte
, startmask
);
305 bits
= FbStipLeft(bits
, pixelsPerDst
);
311 * Consume stipple bits across scanline
318 if (pixelsPerDst
== 16)
319 mask
= FbStipple16Bits(FbLeftStipBits(bits
, 16));
322 mask
= fbBits
[FbLeftStipBits(bits
, pixelsPerDst
)];
323 WRITE(dst
, FbOpaqueStipple(mask
, fgxor
, bgxor
));
325 bits
= FbStipLeft(bits
, pixelsPerDst
);
331 switch (fbLane
[FbLeftStipBits(bits
, pixelsPerDst
)]) {
332 LaneCases((CARD8
*) dst
);
334 bits
= FbStipLeft(bits
, pixelsPerDst
);
342 left
= FbLeftStipBits(bits
, pixelsPerDst
);
343 if (left
|| !transparent
) {
345 WRITE(dst
, FbStippleRRop(READ(dst
), mask
,
350 bits
= FbStipLeft(bits
, pixelsPerDst
);
357 * Load another set and reset number of available units
366 * Consume stipple bits for endmask
373 if (pixelsPerDst
== 16)
374 mask
= FbStipple16Bits(FbLeftStipBits(bits
, 16));
377 mask
= fbBits
[FbLeftStipBits(bits
, pixelsPerDst
)];
379 fbTransparentSpan(dst
, mask
& endmask
, fgxor
, 1);
382 if (mask
|| !transparent
)
383 FbDoRightMaskByteStippleRRop(dst
, mask
,
384 fgand
, fgxor
, bgand
, bgxor
,
394 * Crufty macros to initialize the mask array, most of this
395 * is to avoid compile-time warnings about shift overflow
398 #if BITMAP_BIT_ORDER == MSBFirst
399 #define Mask24Pos(x,r) ((x)*24-(r))
401 #define Mask24Pos(x,r) ((x)*24-((r) ? 24 - (r) : 0))
404 #define Mask24Neg(x,r) (Mask24Pos(x,r) < 0 ? -Mask24Pos(x,r) : 0)
405 #define Mask24Check(x,r) (Mask24Pos(x,r) < 0 ? 0 : \
406 Mask24Pos(x,r) >= FB_UNIT ? 0 : Mask24Pos(x,r))
408 #define Mask24(x,r) (Mask24Pos(x,r) < FB_UNIT ? \
409 (Mask24Pos(x,r) < 0 ? \
410 0xffffffU >> Mask24Neg (x,r) : \
411 0xffffffU << Mask24Check(x,r)) : 0)
413 #define SelMask24(b,n,r) ((((b) >> n) & 1) * Mask24(n,r))
416 * Untested for MSBFirst or FB_UNIT == 32
421 (SelMask24(b,0,r) | \
426 #define FbStip24New(rot) (2 + (rot != 0))
427 #define FbStip24Len 4
429 const FbBits fbStipple24Bits
[3][1 << FbStip24Len
] = {
432 C4_24(0, 0), C4_24(1, 0), C4_24(2, 0), C4_24(3, 0),
433 C4_24(4, 0), C4_24(5, 0), C4_24(6, 0), C4_24(7, 0),
434 C4_24(8, 0), C4_24(9, 0), C4_24(10, 0), C4_24(11, 0),
435 C4_24(12, 0), C4_24(13, 0), C4_24(14, 0), C4_24(15, 0),
439 C4_24(0, 8), C4_24(1, 8), C4_24(2, 8), C4_24(3, 8),
440 C4_24(4, 8), C4_24(5, 8), C4_24(6, 8), C4_24(7, 8),
441 C4_24(8, 8), C4_24(9, 8), C4_24(10, 8), C4_24(11, 8),
442 C4_24(12, 8), C4_24(13, 8), C4_24(14, 8), C4_24(15, 8),
446 C4_24(0, 16), C4_24(1, 16), C4_24(2, 16), C4_24(3, 16),
447 C4_24(4, 16), C4_24(5, 16), C4_24(6, 16), C4_24(7, 16),
448 C4_24(8, 16), C4_24(9, 16), C4_24(10, 16), C4_24(11, 16),
449 C4_24(12, 16), C4_24(13, 16), C4_24(14, 16), C4_24(15, 16),
457 (SelMask24(b,0,r) | \
460 #define FbStip24Len 2
461 #if BITMAP_BIT_ORDER == MSBFirst
462 #define FbStip24New(rot) (1 + (rot == 0))
464 #define FbStip24New(rot) (1 + (rot == 8))
467 const FbBits fbStipple24Bits
[3][1 << FbStip24Len
] = {
470 C2_24(0, 0), C2_24(1, 0), C2_24(2, 0), C2_24(3, 0),
474 C2_24(0, 8), C2_24(1, 8), C2_24(2, 8), C2_24(3, 8),
478 C2_24(0, 16), C2_24(1, 16), C2_24(2, 16), C2_24(3, 16),
483 #if BITMAP_BIT_ORDER == LSBFirst
485 #define FbMergeStip24Bits(left, right, new) \
486 (FbStipLeft (left, new) | FbStipRight ((right), (FbStip24Len - (new))))
488 #define FbMergePartStip24Bits(left, right, llen, rlen) \
489 (left | FbStipRight(right, llen))
493 #define FbMergeStip24Bits(left, right, new) \
494 ((FbStipLeft (left, new) & ((1 << FbStip24Len) - 1)) | right)
496 #define FbMergePartStip24Bits(left, right, llen, rlen) \
497 (FbStipLeft(left, rlen) | right)
501 #define fbFirstStipBits(len,stip) {\
503 if (len <= remain) { \
504 stip = FbLeftStipBits(bits, len); \
506 stip = FbLeftStipBits(bits, remain); \
507 bits = (src < srcEnd ? READ(src++) : 0); \
508 __len = (len) - remain; \
509 stip = FbMergePartStip24Bits(stip, FbLeftStipBits(bits, __len), \
511 remain = FB_STIP_UNIT; \
513 bits = FbStipLeft (bits, __len); \
517 #define fbInitStipBits(offset,len,stip) {\
518 bits = FbStipLeft (READ(src++),offset); \
519 remain = FB_STIP_UNIT - offset; \
520 fbFirstStipBits(len,stip); \
521 stip = FbMergeStip24Bits (0, stip, len); \
524 #define fbNextStipBits(rot,stip) {\
525 int __new = FbStip24New(rot); \
527 fbFirstStipBits(__new, __right); \
528 stip = FbMergeStip24Bits (stip, __right, __new); \
529 rot = FbNext24Rot (rot); \
533 * Use deep mask tables that incorporate rotation, pull
534 * a variable number of bits out of the stipple and
535 * reuse the right bits as needed for the next write
537 * Yes, this is probably too much code, but most 24-bpp screens
538 * have no acceleration so this code is used for stipples, copyplane
542 fbBltOne24(FbStip
* srcLine
, FbStride srcStride
, /* FbStip units per scanline */
543 int srcX
, /* bit position of source */
544 FbBits
* dst
, FbStride dstStride
, /* FbBits units per scanline */
545 int dstX
, /* bit position of dest */
546 int dstBpp
, /* bits per destination unit */
547 int width
, /* width in bits of destination */
548 int height
, /* height in scanlines */
549 FbBits fgand
, /* rrop values */
550 FbBits fgxor
, FbBits bgand
, FbBits bgxor
)
552 FbStip
*src
, *srcEnd
;
553 FbBits leftMask
, rightMask
, mask
;
563 * Do not read past the end of the buffer!
565 srcEnd
= srcLine
+ height
* srcStride
;
567 srcLine
+= srcX
>> FB_STIP_SHIFT
;
568 dst
+= dstX
>> FB_SHIFT
;
569 srcX
&= FB_STIP_MASK
;
571 rot0
= FbFirst24Rot(dstX
);
573 FbMaskBits(dstX
, width
, leftMask
, nlMiddle
, rightMask
);
575 dstS
= (dstX
+ 23) / 24;
576 firstlen
= FbStip24Len
- dstS
;
584 if (bgand
== 0 && fgand
== 0) {
588 srcLine
+= srcStride
;
589 fbInitStipBits(srcX
, firstlen
, stip
);
591 mask
= fbStipple24Bits
[rot
>> 3][stip
];
592 WRITE(dst
, (READ(dst
) & ~leftMask
) |
593 (FbOpaqueStipple(mask
,
594 FbRot24(fgxor
, rot
), FbRot24(bgxor
, rot
))
597 fbNextStipBits(rot
, stip
);
601 mask
= fbStipple24Bits
[rot
>> 3][stip
];
602 WRITE(dst
, FbOpaqueStipple(mask
,
604 FbRot24(bgxor
, rot
)));
606 fbNextStipBits(rot
, stip
);
609 mask
= fbStipple24Bits
[rot
>> 3][stip
];
610 WRITE(dst
, (READ(dst
) & ~rightMask
) |
611 (FbOpaqueStipple(mask
,
612 FbRot24(fgxor
, rot
), FbRot24(bgxor
, rot
))
619 /* transparent copy */
620 else if (bgand
== FB_ALLONES
&& bgxor
== 0 && fgand
== 0) {
624 srcLine
+= srcStride
;
625 fbInitStipBits(srcX
, firstlen
, stip
);
628 mask
= fbStipple24Bits
[rot
>> 3][stip
] & leftMask
;
630 (READ(dst
) & ~mask
) | (FbRot24(fgxor
, rot
) & mask
));
633 fbNextStipBits(rot
, stip
);
638 mask
= fbStipple24Bits
[rot
>> 3][stip
];
640 (READ(dst
) & ~mask
) | (FbRot24(fgxor
, rot
) & mask
));
643 fbNextStipBits(rot
, stip
);
647 mask
= fbStipple24Bits
[rot
>> 3][stip
] & rightMask
;
649 (READ(dst
) & ~mask
) | (FbRot24(fgxor
, rot
) & mask
));
659 srcLine
+= srcStride
;
660 fbInitStipBits(srcX
, firstlen
, stip
);
662 mask
= fbStipple24Bits
[rot
>> 3][stip
];
663 WRITE(dst
, FbStippleRRopMask(READ(dst
), mask
,
667 FbRot24(bgxor
, rot
), leftMask
));
669 fbNextStipBits(rot
, stip
);
673 mask
= fbStipple24Bits
[rot
>> 3][stip
];
674 WRITE(dst
, FbStippleRRop(READ(dst
), mask
,
678 FbRot24(bgxor
, rot
)));
680 fbNextStipBits(rot
, stip
);
683 mask
= fbStipple24Bits
[rot
>> 3][stip
];
684 WRITE(dst
, FbStippleRRopMask(READ(dst
), mask
,
688 FbRot24(bgxor
, rot
), rightMask
));
696 * Not very efficient, but simple -- copy a single plane
697 * from an N bit image to a 1 bit image
701 fbBltPlane(FbBits
* src
,
711 FbStip fgxor
, FbStip bgand
, FbStip bgxor
, Pixel planeMask
)
732 src
+= srcX
>> FB_SHIFT
;
735 dst
+= dstX
>> FB_STIP_SHIFT
;
736 dstX
&= FB_STIP_MASK
;
740 pm
= fbReplicatePixel(planeMask
, srcBpp
);
744 rot0
= FbFirst24Rot(srcX
);
745 if (srcX
+ tmpw
> FB_UNIT
)
746 tmpw
= FB_UNIT
- srcX
;
747 srcMaskFirst
= FbRot24(pm
, rot0
) & FbBitsMask(srcX
, tmpw
);
751 srcMaskFirst
= pm
& FbBitsMask(srcX
, srcBpp
);
752 srcMask0
= pm
& FbBitsMask(0, srcBpp
);
755 dstMaskFirst
= FbStipMask(dstX
, 1);
762 srcMask
= srcMaskFirst
;
764 srcMask0
= FbRot24(pm
, rot0
) & FbBitsMask(0, srcBpp
);
767 dstMask
= dstMaskFirst
;
777 srcMask0
= FbNext24Pix(srcMask0
) & FbBitsMask(0, 24);
781 WRITE(d
, FbStippleRRopMask(READ(d
), dstBits
,
782 fgand
, fgxor
, bgand
, bgxor
,
785 dstMask
= FbStipMask(0, 1);
789 if (srcBits
& srcMask
)
792 if (srcBpp
== FB_UNIT
)
795 srcMask
= FbScrRight(srcMask
, srcBpp
);
796 dstMask
= FbStipRight(dstMask
, 1);
799 WRITE(d
, FbStippleRRopMask(READ(d
), dstBits
,
800 fgand
, fgxor
, bgand
, bgxor
, dstUnion
));