Imported Upstream version 1.15.1
[deb_xorg-server.git] / fb / fbbltone.c
CommitLineData
a09e091a
JB
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#ifdef __clang__
30/* shift overflow is intentional */
31#pragma clang diagnostic ignored "-Wshift-overflow"
32#endif
33
34/*
35 * Example: srcX = 13 dstX = 8 (FB unit 32 dstBpp 8)
36 *
37 * **** **** **** **** **** **** **** ****
38 * ^
39 * ******** ******** ******** ********
40 * ^
41 * leftShift = 12
42 * rightShift = 20
43 *
44 * Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
45 *
46 * **** **** **** **** **** **** **** ****
47 * ^
48 * ******** ******** ******** ********
49 * ^
50 *
51 * leftShift = 24
52 * rightShift = 8
53 */
54
55#define LoadBits {\
56 if (leftShift) { \
57 bitsRight = (src < srcEnd ? READ(src++) : 0); \
58 bits = (FbStipLeft (bitsLeft, leftShift) | \
59 FbStipRight(bitsRight, rightShift)); \
60 bitsLeft = bitsRight; \
61 } else \
62 bits = (src < srcEnd ? READ(src++) : 0); \
63}
64
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)
74
75#if FB_SHIFT == 6
76#define LaneCases(a) LaneCases256(0,a)
77#endif
78
79#if FB_SHIFT == 5
80#define LaneCases(a) LaneCases16(0,a)
81#endif
82
83#if FB_SHIFT == 6
84CARD8 fb8Lane[256] = {
85 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
86 21,
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,
92 113, 114, 115,
93 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
94 131, 132, 133,
95 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
96 149, 150, 151,
97 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
98 167, 168, 169,
99 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
100 185, 186, 187,
101 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
102 203, 204, 205,
103 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
104 221, 222, 223,
105 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
106 239, 240, 241,
107 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
108};
109
110CARD8 fb16Lane[256] = {
111 0x00, 0x03, 0x0c, 0x0f,
112 0x30, 0x33, 0x3c, 0x3f,
113 0xc0, 0xc3, 0xcc, 0xcf,
114 0xf0, 0xf3, 0xfc, 0xff,
115};
116
117CARD8 fb32Lane[16] = {
118 0x00, 0x0f, 0xf0, 0xff,
119};
120#endif
121
122#if FB_SHIFT == 5
123CARD8 fb8Lane[16] = {
124 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
125};
126
127CARD8 fb16Lane[16] = {
128 0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129};
130
131CARD8 fb32Lane[16] = {
132 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133};
134#endif
135
136CARD8 *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,
141 fb32Lane
142};
143
144void
145fbBltOne(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)
154{
155 const FbBits *fbBits;
156 FbBits *srcEnd;
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 */
162 FbStip left;
163 FbBits mask;
164 int nDst; /* dest longwords (w.o. end) */
165 int w;
166 int n, nmiddle;
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 */
172 CARD8 *fbLane;
173 int startbyte, endbyte;
174
175 if (dstBpp == 24) {
176 fbBltOne24(src, srcStride, srcX,
177 dst, dstStride, dstX, dstBpp,
178 width, height, fgand, fgxor, bgand, bgxor);
179 return;
180 }
181
182 /*
183 * Do not read past the end of the buffer!
184 */
185 srcEnd = src + height * srcStride;
186
187 /*
188 * Number of destination units in FbBits == number of stipple pixels
189 * used each time
190 */
191 pixelsPerDst = FB_UNIT / dstBpp;
192
193 /*
194 * Number of source stipple patterns in FbStip
195 */
196 unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
197
198 copy = FALSE;
199 transparent = FALSE;
200 if (bgand == 0 && fgand == 0)
201 copy = TRUE;
202 else if (bgand == FB_ALLONES && bgxor == 0)
203 transparent = TRUE;
204
205 /*
206 * Adjust source and dest to nearest FbBits boundary
207 */
208 src += srcX >> FB_STIP_SHIFT;
209 dst += dstX >> FB_SHIFT;
210 srcX &= FB_STIP_MASK;
211 dstX &= FB_MASK;
212
213 FbMaskBitsBytes(dstX, width, copy,
214 startmask, startbyte, nmiddle, endmask, endbyte);
215
216 /*
217 * Compute effective dest alignment requirement for
218 * source -- must align source to dest unit boundary
219 */
220 dstS = dstX / dstBpp;
221 /*
222 * Compute shift constants for effective alignement
223 */
224 if (srcX >= dstS) {
225 leftShift = srcX - dstS;
226 rightShift = FB_STIP_UNIT - leftShift;
227 }
228 else {
229 rightShift = dstS - srcX;
230 leftShift = FB_STIP_UNIT - rightShift;
231 }
232 /*
233 * Get pointer to stipple mask array for this depth
234 */
235 fbBits = 0; /* unused */
236 if (pixelsPerDst <= 8)
237 fbBits = fbStippleTable[pixelsPerDst];
238 fbLane = 0;
239 if (transparent && fgand == 0 && dstBpp >= 8)
240 fbLane = fbLaneTable[dstBpp];
241
242 /*
243 * Compute total number of destination words written, but
244 * don't count endmask
245 */
246 nDst = nmiddle;
247 if (startmask)
248 nDst++;
249
250 dstStride -= nDst;
251
252 /*
253 * Compute total number of source words consumed
254 */
255
256 srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
257
258 if (srcX > dstS)
259 srcinc++;
260 if (endmask) {
261 endNeedsLoad = nDst % unitsPerSrc == 0;
262 if (endNeedsLoad)
263 srcinc++;
264 }
265
266 srcStride -= srcinc;
267
268 /*
269 * Copy rectangle
270 */
271 while (height--) {
272 w = nDst; /* total units across scanline */
273 n = unitsPerSrc; /* units avail in single stipple */
274 if (n > w)
275 n = w;
276
277 bitsLeft = 0;
278 if (srcX > dstS)
279 bitsLeft = READ(src++);
280 if (n) {
281 /*
282 * Load first set of stipple bits
283 */
284 LoadBits;
285
286 /*
287 * Consume stipple bits for startmask
288 */
289 if (startmask) {
290#if FB_UNIT > 32
291 if (pixelsPerDst == 16)
292 mask = FbStipple16Bits(FbLeftStipBits(bits, 16));
293 else
294#endif
295 mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
296 if (fbLane) {
297 fbTransparentSpan(dst, mask & startmask, fgxor, 1);
298 }
299 else {
300 if (mask || !transparent)
301 FbDoLeftMaskByteStippleRRop(dst, mask,
302 fgand, fgxor, bgand, bgxor,
303 startbyte, startmask);
304 }
305 bits = FbStipLeft(bits, pixelsPerDst);
306 dst++;
307 n--;
308 w--;
309 }
310 /*
311 * Consume stipple bits across scanline
312 */
313 for (;;) {
314 w -= n;
315 if (copy) {
316 while (n--) {
317#if FB_UNIT > 32
318 if (pixelsPerDst == 16)
319 mask = FbStipple16Bits(FbLeftStipBits(bits, 16));
320 else
321#endif
322 mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
323 WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor));
324 dst++;
325 bits = FbStipLeft(bits, pixelsPerDst);
326 }
327 }
328 else {
329 if (fbLane) {
330 while (bits && n) {
331 switch (fbLane[FbLeftStipBits(bits, pixelsPerDst)]) {
332 LaneCases((CARD8 *) dst);
333 }
334 bits = FbStipLeft(bits, pixelsPerDst);
335 dst++;
336 n--;
337 }
338 dst += n;
339 }
340 else {
341 while (n--) {
342 left = FbLeftStipBits(bits, pixelsPerDst);
343 if (left || !transparent) {
344 mask = fbBits[left];
345 WRITE(dst, FbStippleRRop(READ(dst), mask,
346 fgand, fgxor, bgand,
347 bgxor));
348 }
349 dst++;
350 bits = FbStipLeft(bits, pixelsPerDst);
351 }
352 }
353 }
354 if (!w)
355 break;
356 /*
357 * Load another set and reset number of available units
358 */
359 LoadBits;
360 n = unitsPerSrc;
361 if (n > w)
362 n = w;
363 }
364 }
365 /*
366 * Consume stipple bits for endmask
367 */
368 if (endmask) {
369 if (endNeedsLoad) {
370 LoadBits;
371 }
372#if FB_UNIT > 32
373 if (pixelsPerDst == 16)
374 mask = FbStipple16Bits(FbLeftStipBits(bits, 16));
375 else
376#endif
377 mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
378 if (fbLane) {
379 fbTransparentSpan(dst, mask & endmask, fgxor, 1);
380 }
381 else {
382 if (mask || !transparent)
383 FbDoRightMaskByteStippleRRop(dst, mask,
384 fgand, fgxor, bgand, bgxor,
385 endbyte, endmask);
386 }
387 }
388 dst += dstStride;
389 src += srcStride;
390 }
391}
392
393/*
394 * Crufty macros to initialize the mask array, most of this
395 * is to avoid compile-time warnings about shift overflow
396 */
397
398#if BITMAP_BIT_ORDER == MSBFirst
399#define Mask24Pos(x,r) ((x)*24-(r))
400#else
401#define Mask24Pos(x,r) ((x)*24-((r) ? 24 - (r) : 0))
402#endif
403
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))
407
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)
412
413#define SelMask24(b,n,r) ((((b) >> n) & 1) * Mask24(n,r))
414
415/*
416 * Untested for MSBFirst or FB_UNIT == 32
417 */
418
419#if FB_UNIT == 64
420#define C4_24(b,r) \
421 (SelMask24(b,0,r) | \
422 SelMask24(b,1,r) | \
423 SelMask24(b,2,r) | \
424 SelMask24(b,3,r))
425
426#define FbStip24New(rot) (2 + (rot != 0))
427#define FbStip24Len 4
428
429const FbBits fbStipple24Bits[3][1 << FbStip24Len] = {
430 /* rotate 0 */
431 {
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),
436 },
437 /* rotate 8 */
438 {
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),
443 },
444 /* rotate 16 */
445 {
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),
450 }
451};
452
453#endif
454
455#if FB_UNIT == 32
456#define C2_24(b,r) \
457 (SelMask24(b,0,r) | \
458 SelMask24(b,1,r))
459
460#define FbStip24Len 2
461#if BITMAP_BIT_ORDER == MSBFirst
462#define FbStip24New(rot) (1 + (rot == 0))
463#else
464#define FbStip24New(rot) (1 + (rot == 8))
465#endif
466
467const FbBits fbStipple24Bits[3][1 << FbStip24Len] = {
468 /* rotate 0 */
469 {
470 C2_24(0, 0), C2_24(1, 0), C2_24(2, 0), C2_24(3, 0),
471 },
472 /* rotate 8 */
473 {
474 C2_24(0, 8), C2_24(1, 8), C2_24(2, 8), C2_24(3, 8),
475 },
476 /* rotate 16 */
477 {
478 C2_24(0, 16), C2_24(1, 16), C2_24(2, 16), C2_24(3, 16),
479 }
480};
481#endif
482
483#if BITMAP_BIT_ORDER == LSBFirst
484
485#define FbMergeStip24Bits(left, right, new) \
486 (FbStipLeft (left, new) | FbStipRight ((right), (FbStip24Len - (new))))
487
488#define FbMergePartStip24Bits(left, right, llen, rlen) \
489 (left | FbStipRight(right, llen))
490
491#else
492
493#define FbMergeStip24Bits(left, right, new) \
494 ((FbStipLeft (left, new) & ((1 << FbStip24Len) - 1)) | right)
495
496#define FbMergePartStip24Bits(left, right, llen, rlen) \
497 (FbStipLeft(left, rlen) | right)
498
499#endif
500
501#define fbFirstStipBits(len,stip) {\
502 int __len = (len); \
503 if (len <= remain) { \
504 stip = FbLeftStipBits(bits, len); \
505 } else { \
506 stip = FbLeftStipBits(bits, remain); \
507 bits = (src < srcEnd ? READ(src++) : 0); \
508 __len = (len) - remain; \
509 stip = FbMergePartStip24Bits(stip, FbLeftStipBits(bits, __len), \
510 remain, __len); \
511 remain = FB_STIP_UNIT; \
512 } \
513 bits = FbStipLeft (bits, __len); \
514 remain -= __len; \
515}
516
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); \
522}
523
524#define fbNextStipBits(rot,stip) {\
525 int __new = FbStip24New(rot); \
526 FbStip __right; \
527 fbFirstStipBits(__new, __right); \
528 stip = FbMergeStip24Bits (stip, __right, __new); \
529 rot = FbNext24Rot (rot); \
530}
531
532/*
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
536 *
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
539 * and text
540 */
541void
542fbBltOne24(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)
551{
552 FbStip *src, *srcEnd;
553 FbBits leftMask, rightMask, mask;
554 int nlMiddle, nl;
555 FbStip stip, bits;
556 int remain;
557 int dstS;
558 int firstlen;
559 int rot0, rot;
560 int nDst;
561
562 /*
563 * Do not read past the end of the buffer!
564 */
565 srcEnd = srcLine + height * srcStride;
566
567 srcLine += srcX >> FB_STIP_SHIFT;
568 dst += dstX >> FB_SHIFT;
569 srcX &= FB_STIP_MASK;
570 dstX &= FB_MASK;
571 rot0 = FbFirst24Rot(dstX);
572
573 FbMaskBits(dstX, width, leftMask, nlMiddle, rightMask);
574
575 dstS = (dstX + 23) / 24;
576 firstlen = FbStip24Len - dstS;
577
578 nDst = nlMiddle;
579 if (leftMask)
580 nDst++;
581 dstStride -= nDst;
582
583 /* opaque copy */
584 if (bgand == 0 && fgand == 0) {
585 while (height--) {
586 rot = rot0;
587 src = srcLine;
588 srcLine += srcStride;
589 fbInitStipBits(srcX, firstlen, stip);
590 if (leftMask) {
591 mask = fbStipple24Bits[rot >> 3][stip];
592 WRITE(dst, (READ(dst) & ~leftMask) |
593 (FbOpaqueStipple(mask,
594 FbRot24(fgxor, rot), FbRot24(bgxor, rot))
595 & leftMask));
596 dst++;
597 fbNextStipBits(rot, stip);
598 }
599 nl = nlMiddle;
600 while (nl--) {
601 mask = fbStipple24Bits[rot >> 3][stip];
602 WRITE(dst, FbOpaqueStipple(mask,
603 FbRot24(fgxor, rot),
604 FbRot24(bgxor, rot)));
605 dst++;
606 fbNextStipBits(rot, stip);
607 }
608 if (rightMask) {
609 mask = fbStipple24Bits[rot >> 3][stip];
610 WRITE(dst, (READ(dst) & ~rightMask) |
611 (FbOpaqueStipple(mask,
612 FbRot24(fgxor, rot), FbRot24(bgxor, rot))
613 & rightMask));
614 }
615 dst += dstStride;
616 src += srcStride;
617 }
618 }
619 /* transparent copy */
620 else if (bgand == FB_ALLONES && bgxor == 0 && fgand == 0) {
621 while (height--) {
622 rot = rot0;
623 src = srcLine;
624 srcLine += srcStride;
625 fbInitStipBits(srcX, firstlen, stip);
626 if (leftMask) {
627 if (stip) {
628 mask = fbStipple24Bits[rot >> 3][stip] & leftMask;
629 WRITE(dst,
630 (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
631 }
632 dst++;
633 fbNextStipBits(rot, stip);
634 }
635 nl = nlMiddle;
636 while (nl--) {
637 if (stip) {
638 mask = fbStipple24Bits[rot >> 3][stip];
639 WRITE(dst,
640 (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
641 }
642 dst++;
643 fbNextStipBits(rot, stip);
644 }
645 if (rightMask) {
646 if (stip) {
647 mask = fbStipple24Bits[rot >> 3][stip] & rightMask;
648 WRITE(dst,
649 (READ(dst) & ~mask) | (FbRot24(fgxor, rot) & mask));
650 }
651 }
652 dst += dstStride;
653 }
654 }
655 else {
656 while (height--) {
657 rot = rot0;
658 src = srcLine;
659 srcLine += srcStride;
660 fbInitStipBits(srcX, firstlen, stip);
661 if (leftMask) {
662 mask = fbStipple24Bits[rot >> 3][stip];
663 WRITE(dst, FbStippleRRopMask(READ(dst), mask,
664 FbRot24(fgand, rot),
665 FbRot24(fgxor, rot),
666 FbRot24(bgand, rot),
667 FbRot24(bgxor, rot), leftMask));
668 dst++;
669 fbNextStipBits(rot, stip);
670 }
671 nl = nlMiddle;
672 while (nl--) {
673 mask = fbStipple24Bits[rot >> 3][stip];
674 WRITE(dst, FbStippleRRop(READ(dst), mask,
675 FbRot24(fgand, rot),
676 FbRot24(fgxor, rot),
677 FbRot24(bgand, rot),
678 FbRot24(bgxor, rot)));
679 dst++;
680 fbNextStipBits(rot, stip);
681 }
682 if (rightMask) {
683 mask = fbStipple24Bits[rot >> 3][stip];
684 WRITE(dst, FbStippleRRopMask(READ(dst), mask,
685 FbRot24(fgand, rot),
686 FbRot24(fgxor, rot),
687 FbRot24(bgand, rot),
688 FbRot24(bgxor, rot), rightMask));
689 }
690 dst += dstStride;
691 }
692 }
693}
694
695/*
696 * Not very efficient, but simple -- copy a single plane
697 * from an N bit image to a 1 bit image
698 */
699
700void
701fbBltPlane(FbBits * src,
702 FbStride srcStride,
703 int srcX,
704 int srcBpp,
705 FbStip * dst,
706 FbStride dstStride,
707 int dstX,
708 int width,
709 int height,
710 FbStip fgand,
711 FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask)
712{
713 FbBits *s;
714 FbBits pm;
715 FbBits srcMask;
716 FbBits srcMaskFirst;
717 FbBits srcMask0 = 0;
718 FbBits srcBits;
719
720 FbStip dstBits;
721 FbStip *d;
722 FbStip dstMask;
723 FbStip dstMaskFirst;
724 FbStip dstUnion;
725 int w;
726 int wt;
727 int rot0;
728
729 if (!width)
730 return;
731
732 src += srcX >> FB_SHIFT;
733 srcX &= FB_MASK;
734
735 dst += dstX >> FB_STIP_SHIFT;
736 dstX &= FB_STIP_MASK;
737
738 w = width / srcBpp;
739
740 pm = fbReplicatePixel(planeMask, srcBpp);
741 if (srcBpp == 24) {
742 int tmpw = 24;
743
744 rot0 = FbFirst24Rot(srcX);
745 if (srcX + tmpw > FB_UNIT)
746 tmpw = FB_UNIT - srcX;
747 srcMaskFirst = FbRot24(pm, rot0) & FbBitsMask(srcX, tmpw);
748 }
749 else {
750 rot0 = 0;
751 srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
752 srcMask0 = pm & FbBitsMask(0, srcBpp);
753 }
754
755 dstMaskFirst = FbStipMask(dstX, 1);
756 while (height--) {
757 d = dst;
758 dst += dstStride;
759 s = src;
760 src += srcStride;
761
762 srcMask = srcMaskFirst;
763 if (srcBpp == 24)
764 srcMask0 = FbRot24(pm, rot0) & FbBitsMask(0, srcBpp);
765 srcBits = READ(s++);
766
767 dstMask = dstMaskFirst;
768 dstUnion = 0;
769 dstBits = 0;
770
771 wt = w;
772
773 while (wt--) {
774 if (!srcMask) {
775 srcBits = READ(s++);
776 if (srcBpp == 24)
777 srcMask0 = FbNext24Pix(srcMask0) & FbBitsMask(0, 24);
778 srcMask = srcMask0;
779 }
780 if (!dstMask) {
781 WRITE(d, FbStippleRRopMask(READ(d), dstBits,
782 fgand, fgxor, bgand, bgxor,
783 dstUnion));
784 d++;
785 dstMask = FbStipMask(0, 1);
786 dstUnion = 0;
787 dstBits = 0;
788 }
789 if (srcBits & srcMask)
790 dstBits |= dstMask;
791 dstUnion |= dstMask;
792 if (srcBpp == FB_UNIT)
793 srcMask = 0;
794 else
795 srcMask = FbScrRight(srcMask, srcBpp);
796 dstMask = FbStipRight(dstMask, 1);
797 }
798 if (dstUnion)
799 WRITE(d, FbStippleRRopMask(READ(d), dstBits,
800 fgand, fgxor, bgand, bgxor, dstUnion));
801 }
802}