xref: /netbsd-src/sys/dev/rasops/rasops24.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /* 	$NetBSD: rasops24.c,v 1.25 2008/04/28 20:23:56 martin Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: rasops24.c,v 1.25 2008/04/28 20:23:56 martin Exp $");
34 
35 #include "opt_rasops.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/time.h>
40 
41 #include <machine/endian.h>
42 #include <sys/bswap.h>
43 
44 #include <dev/wscons/wsdisplayvar.h>
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/rasops/rasops.h>
47 
48 static void 	rasops24_erasecols(void *, int, int, int, long);
49 static void 	rasops24_eraserows(void *, int, int, long);
50 static void 	rasops24_putchar(void *, int, int, u_int, long attr);
51 #ifndef RASOPS_SMALL
52 static void 	rasops24_putchar8(void *, int, int, u_int, long attr);
53 static void 	rasops24_putchar12(void *, int, int, u_int, long attr);
54 static void 	rasops24_putchar16(void *, int, int, u_int, long attr);
55 static void	rasops24_makestamp(struct rasops_info *, long);
56 #endif
57 
58 /*
59  * 4x1 stamp for optimized character blitting
60  */
61 static int32_t	stamp[64];
62 static long	stamp_attr;
63 static int	stamp_mutex;	/* XXX see note in readme */
64 
65 /*
66  * XXX this confuses the hell out of gcc2 (not egcs) which always insists
67  * that the shift count is negative.
68  *
69  * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK
70  * destination int32_t[0] = STAMP_READ(offset)
71  * destination int32_t[1] = STAMP_READ(offset + 4)
72  * destination int32_t[2] = STAMP_READ(offset + 8)
73  */
74 #define STAMP_SHIFT(fb,n)	((n*4-4) >= 0 ? (fb)>>(n*4-4):(fb)<<-(n*4-4))
75 #define STAMP_MASK		(0xf << 4)
76 #define STAMP_READ(o)		(*(int32_t *)((char *)stamp + (o)))
77 
78 /*
79  * Initialize rasops_info struct for this colordepth.
80  */
81 void
82 rasops24_init(ri)
83 	struct rasops_info *ri;
84 {
85 
86 	switch (ri->ri_font->fontwidth) {
87 #ifndef RASOPS_SMALL
88 	case 8:
89 		ri->ri_ops.putchar = rasops24_putchar8;
90 		break;
91 	case 12:
92 		ri->ri_ops.putchar = rasops24_putchar12;
93 		break;
94 	case 16:
95 		ri->ri_ops.putchar = rasops24_putchar16;
96 		break;
97 #endif
98 	default:
99 		ri->ri_ops.putchar = rasops24_putchar;
100 		break;
101 	}
102 
103 	if (ri->ri_rnum == 0) {
104 		ri->ri_rnum = 8;
105 		ri->ri_rpos = 0;
106 		ri->ri_gnum = 8;
107 		ri->ri_gpos = 8;
108 		ri->ri_bnum = 8;
109 		ri->ri_bpos = 16;
110 	}
111 
112 	ri->ri_ops.erasecols = rasops24_erasecols;
113 	ri->ri_ops.eraserows = rasops24_eraserows;
114 }
115 
116 /*
117  * Put a single character. This is the generic version.
118  * XXX this bites - we should use masks.
119  */
120 static void
121 rasops24_putchar(cookie, row, col, uc, attr)
122 	void *cookie;
123 	int row, col;
124 	u_int uc;
125 	long attr;
126 {
127 	int fb, width, height, cnt, clr[2];
128 	struct rasops_info *ri;
129 	u_char *dp, *rp, *fr;
130 
131 	ri = (struct rasops_info *)cookie;
132 
133 #ifdef RASOPS_CLIPPING
134 	/* Catches 'row < 0' case too */
135 	if ((unsigned)row >= (unsigned)ri->ri_rows)
136 		return;
137 
138 	if ((unsigned)col >= (unsigned)ri->ri_cols)
139 		return;
140 #endif
141 
142 	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
143 	height = ri->ri_font->fontheight;
144 	width = ri->ri_font->fontwidth;
145 
146 	clr[1] = ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
147 	clr[0] = ri->ri_devcmap[((u_int)attr >> 16) & 0xf];
148 
149 	if (uc == ' ') {
150 		u_char c = clr[0];
151 		while (height--) {
152 			dp = rp;
153 			rp += ri->ri_stride;
154 
155 			for (cnt = width; cnt; cnt--) {
156 				*dp++ = c >> 16;
157 				*dp++ = c >> 8;
158 				*dp++ = c;
159 			}
160 		}
161 	} else {
162 		uc -= ri->ri_font->firstchar;
163 		fr = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
164 
165 		while (height--) {
166 			dp = rp;
167 			fb = fr[3] | (fr[2] << 8) | (fr[1] << 16) |
168 			    (fr[0] << 24);
169 			fr += ri->ri_font->stride;
170 			rp += ri->ri_stride;
171 
172 			for (cnt = width; cnt; cnt--, fb <<= 1) {
173 				if ((fb >> 31) & 1) {
174 					*dp++ = clr[1] >> 16;
175 					*dp++ = clr[1] >> 8;
176 					*dp++ = clr[1];
177 				} else {
178 					*dp++ = clr[0] >> 16;
179 					*dp++ = clr[0] >> 8;
180 					*dp++ = clr[0];
181 				}
182 			}
183 		}
184 	}
185 
186 	/* Do underline */
187 	if ((attr & 1) != 0) {
188 		u_char c = clr[1];
189 
190 		rp -= ri->ri_stride << 1;
191 
192 		while (width--) {
193 			*rp++ = c >> 16;
194 			*rp++ = c >> 8;
195 			*rp++ = c;
196 		}
197 	}
198 }
199 
200 #ifndef RASOPS_SMALL
201 /*
202  * Recompute the blitting stamp.
203  */
204 static void
205 rasops24_makestamp(ri, attr)
206 	struct rasops_info *ri;
207 	long attr;
208 {
209 	u_int fg, bg, c1, c2, c3, c4;
210 	int i;
211 
212 	fg = ri->ri_devcmap[((u_int)attr >> 24) & 0xf] & 0xffffff;
213 	bg = ri->ri_devcmap[((u_int)attr >> 16) & 0xf] & 0xffffff;
214 	stamp_attr = attr;
215 
216 	for (i = 0; i < 64; i += 4) {
217 #if BYTE_ORDER == LITTLE_ENDIAN
218 		c1 = (i & 32 ? fg : bg);
219 		c2 = (i & 16 ? fg : bg);
220 		c3 = (i & 8 ? fg : bg);
221 		c4 = (i & 4 ? fg : bg);
222 #else
223 		c1 = (i & 8 ? fg : bg);
224 		c2 = (i & 4 ? fg : bg);
225 		c3 = (i & 16 ? fg : bg);
226 		c4 = (i & 32 ? fg : bg);
227 #endif
228 		stamp[i+0] = (c1 <<  8) | (c2 >> 16);
229 		stamp[i+1] = (c2 << 16) | (c3 >>  8);
230 		stamp[i+2] = (c3 << 24) | c4;
231 
232 #if BYTE_ORDER == LITTLE_ENDIAN
233 		if ((ri->ri_flg & RI_BSWAP) == 0) {
234 #else
235 		if ((ri->ri_flg & RI_BSWAP) != 0) {
236 #endif
237 			stamp[i+0] = bswap32(stamp[i+0]);
238 			stamp[i+1] = bswap32(stamp[i+1]);
239 			stamp[i+2] = bswap32(stamp[i+2]);
240 		}
241 	}
242 }
243 
244 /*
245  * Put a single character. This is for 8-pixel wide fonts.
246  */
247 static void
248 rasops24_putchar8(cookie, row, col, uc, attr)
249 	void *cookie;
250 	int row, col;
251 	u_int uc;
252 	long attr;
253 {
254 	struct rasops_info *ri;
255 	int height, so, fs;
256 	int32_t *rp;
257 	u_char *fr;
258 
259 	/* Can't risk remaking the stamp if it's already in use */
260 	if (stamp_mutex++) {
261 		stamp_mutex--;
262 		rasops24_putchar(cookie, row, col, uc, attr);
263 		return;
264 	}
265 
266 	ri = (struct rasops_info *)cookie;
267 
268 #ifdef RASOPS_CLIPPING
269 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
270 		stamp_mutex--;
271 		return;
272 	}
273 
274 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
275 		stamp_mutex--;
276 		return;
277 	}
278 #endif
279 
280 	/* Recompute stamp? */
281 	if (attr != stamp_attr)
282 		rasops24_makestamp(ri, attr);
283 
284 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
285 	height = ri->ri_font->fontheight;
286 
287 	if (uc == (u_int)-1) {
288 		int32_t c = stamp[0];
289 		while (height--) {
290 			rp[0] = rp[1] = rp[2] = rp[3] = rp[4] = rp[5] = c;
291 			DELTA(rp, ri->ri_stride, int32_t *);
292 		}
293 	} else {
294 		uc -= ri->ri_font->firstchar;
295 		fr = (u_char *)ri->ri_font->data + uc*ri->ri_fontscale;
296 		fs = ri->ri_font->stride;
297 
298 		while (height--) {
299 			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
300 			rp[0] = STAMP_READ(so);
301 			rp[1] = STAMP_READ(so + 4);
302 			rp[2] = STAMP_READ(so + 8);
303 
304 			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
305 			rp[3] = STAMP_READ(so);
306 			rp[4] = STAMP_READ(so + 4);
307 			rp[5] = STAMP_READ(so + 8);
308 
309 			fr += fs;
310 			DELTA(rp, ri->ri_stride, int32_t *);
311 		}
312 	}
313 
314 	/* Do underline */
315 	if ((attr & 1) != 0) {
316 		int32_t c = STAMP_READ(52);
317 
318 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
319 		rp[0] = rp[1] = rp[2] = rp[3] = rp[4] = rp[5] = c;
320 	}
321 
322 	stamp_mutex--;
323 }
324 
325 /*
326  * Put a single character. This is for 12-pixel wide fonts.
327  */
328 static void
329 rasops24_putchar12(cookie, row, col, uc, attr)
330 	void *cookie;
331 	int row, col;
332 	u_int uc;
333 	long attr;
334 {
335 	struct rasops_info *ri;
336 	int height, so, fs;
337 	int32_t *rp;
338 	u_char *fr;
339 
340 	/* Can't risk remaking the stamp if it's already in use */
341 	if (stamp_mutex++) {
342 		stamp_mutex--;
343 		rasops24_putchar(cookie, row, col, uc, attr);
344 		return;
345 	}
346 
347 	ri = (struct rasops_info *)cookie;
348 
349 #ifdef RASOPS_CLIPPING
350 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
351 		stamp_mutex--;
352 		return;
353 	}
354 
355 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
356 		stamp_mutex--;
357 		return;
358 	}
359 #endif
360 
361 	/* Recompute stamp? */
362 	if (attr != stamp_attr)
363 		rasops24_makestamp(ri, attr);
364 
365 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
366 	height = ri->ri_font->fontheight;
367 
368 	if (uc == (u_int)-1) {
369 		int32_t c = stamp[0];
370 		while (height--) {
371 			rp[0] = rp[1] = rp[2] = rp[3] =
372 			rp[4] = rp[5] = rp[6] = rp[7] = rp[8] = c;
373 			DELTA(rp, ri->ri_stride, int32_t *);
374 		}
375 	} else {
376 		uc -= ri->ri_font->firstchar;
377 		fr = (u_char *)ri->ri_font->data + uc*ri->ri_fontscale;
378 		fs = ri->ri_font->stride;
379 
380 		while (height--) {
381 			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
382 			rp[0] = STAMP_READ(so);
383 			rp[1] = STAMP_READ(so + 4);
384 			rp[2] = STAMP_READ(so + 8);
385 
386 			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
387 			rp[3] = STAMP_READ(so);
388 			rp[4] = STAMP_READ(so + 4);
389 			rp[5] = STAMP_READ(so + 8);
390 
391 			so = STAMP_SHIFT(fr[1], 1) & STAMP_MASK;
392 			rp[6] = STAMP_READ(so);
393 			rp[7] = STAMP_READ(so + 4);
394 			rp[8] = STAMP_READ(so + 8);
395 
396 			fr += fs;
397 			DELTA(rp, ri->ri_stride, int32_t *);
398 		}
399 	}
400 
401 	/* Do underline */
402 	if ((attr & 1) != 0) {
403 		int32_t c = STAMP_READ(52);
404 
405 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
406 		rp[0] = rp[1] = rp[2] = rp[3] =
407 		rp[4] = rp[5] = rp[6] = rp[7] = rp[8] = c;
408 	}
409 
410 	stamp_mutex--;
411 }
412 
413 /*
414  * Put a single character. This is for 16-pixel wide fonts.
415  */
416 static void
417 rasops24_putchar16(cookie, row, col, uc, attr)
418 	void *cookie;
419 	int row, col;
420 	u_int uc;
421 	long attr;
422 {
423 	struct rasops_info *ri;
424 	int height, so, fs;
425 	int32_t *rp;
426 	u_char *fr;
427 
428 	/* Can't risk remaking the stamp if it's already in use */
429 	if (stamp_mutex++) {
430 		stamp_mutex--;
431 		rasops24_putchar(cookie, row, col, uc, attr);
432 		return;
433 	}
434 
435 	ri = (struct rasops_info *)cookie;
436 
437 #ifdef RASOPS_CLIPPING
438 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
439 		stamp_mutex--;
440 		return;
441 	}
442 
443 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
444 		stamp_mutex--;
445 		return;
446 	}
447 #endif
448 
449 	/* Recompute stamp? */
450 	if (attr != stamp_attr)
451 		rasops24_makestamp(ri, attr);
452 
453 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
454 	height = ri->ri_font->fontheight;
455 
456 	if (uc == (u_int)-1) {
457 		int32_t c = stamp[0];
458 		while (height--) {
459 			rp[0] = rp[1] = rp[2] = rp[3] =
460 			rp[4] = rp[5] = rp[6] = rp[7] =
461 			rp[8] = rp[9] = rp[10] = rp[11] = c;
462 			DELTA(rp, ri->ri_stride, int32_t *);
463 		}
464 	} else {
465 		uc -= ri->ri_font->firstchar;
466 		fr = (u_char *)ri->ri_font->data + uc*ri->ri_fontscale;
467 		fs = ri->ri_font->stride;
468 
469 		while (height--) {
470 			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
471 			rp[0] = STAMP_READ(so);
472 			rp[1] = STAMP_READ(so + 4);
473 			rp[2] = STAMP_READ(so + 8);
474 
475 			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
476 			rp[3] = STAMP_READ(so);
477 			rp[4] = STAMP_READ(so + 4);
478 			rp[5] = STAMP_READ(so + 8);
479 
480 			so = STAMP_SHIFT(fr[1], 1) & STAMP_MASK;
481 			rp[6] = STAMP_READ(so);
482 			rp[7] = STAMP_READ(so + 4);
483 			rp[8] = STAMP_READ(so + 8);
484 
485 			so = STAMP_SHIFT(fr[1], 0) & STAMP_MASK;
486 			rp[9] = STAMP_READ(so);
487 			rp[10] = STAMP_READ(so + 4);
488 			rp[11] = STAMP_READ(so + 8);
489 
490 			DELTA(rp, ri->ri_stride, int32_t *);
491 			fr += fs;
492 		}
493 	}
494 
495 	/* Do underline */
496 	if ((attr & 1) != 0) {
497 		int32_t c = STAMP_READ(52);
498 
499 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
500 		rp[0] = rp[1] = rp[2] = rp[3] =
501 		rp[4] = rp[5] = rp[6] = rp[7] =
502 		rp[8] = rp[9] = rp[10] = rp[11] = c;
503 	}
504 
505 	stamp_mutex--;
506 }
507 #endif	/* !RASOPS_SMALL */
508 
509 /*
510  * Erase rows. This is nice and easy due to alignment.
511  */
512 static void
513 rasops24_eraserows(cookie, row, num, attr)
514 	void *cookie;
515 	int row, num;
516 	long attr;
517 {
518 	int n9, n3, n1, cnt, stride, delta;
519 	u_int32_t *dp, clr, xstamp[3];
520 	struct rasops_info *ri;
521 
522 	/*
523 	 * If the color is gray, we can cheat and use the generic routines
524 	 * (which are faster, hopefully) since the r,g,b values are the same.
525 	 */
526 	if ((attr & 4) != 0) {
527 		rasops_eraserows(cookie, row, num, attr);
528 		return;
529 	}
530 
531 	ri = (struct rasops_info *)cookie;
532 
533 #ifdef RASOPS_CLIPPING
534 	if (row < 0) {
535 		num += row;
536 		row = 0;
537 	}
538 
539 	if ((row + num) > ri->ri_rows)
540 		num = ri->ri_rows - row;
541 
542 	if (num <= 0)
543 		return;
544 #endif
545 
546 	clr = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xffffff;
547 	xstamp[0] = (clr <<  8) | (clr >> 16);
548 	xstamp[1] = (clr << 16) | (clr >>  8);
549 	xstamp[2] = (clr << 24) | clr;
550 
551 #if BYTE_ORDER == LITTLE_ENDIAN
552 	if ((ri->ri_flg & RI_BSWAP) == 0) {
553 #else
554 	if ((ri->ri_flg & RI_BSWAP) != 0) {
555 #endif
556 		xstamp[0] = bswap32(xstamp[0]);
557 		xstamp[1] = bswap32(xstamp[1]);
558 		xstamp[2] = bswap32(xstamp[2]);
559 	}
560 
561 	/*
562 	 * XXX the wsdisplay_emulops interface seems a little deficient in
563 	 * that there is no way to clear the *entire* screen. We provide a
564 	 * workaround here: if the entire console area is being cleared, and
565 	 * the RI_FULLCLEAR flag is set, clear the entire display.
566 	 */
567 	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
568 		stride = ri->ri_stride;
569 		num = ri->ri_height;
570 		dp = (int32_t *)ri->ri_origbits;
571 		delta = 0;
572 	} else {
573 		stride = ri->ri_emustride;
574 		num *= ri->ri_font->fontheight;
575 		dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
576 		delta = ri->ri_delta;
577 	}
578 
579 	n9 = stride / 36;
580 	cnt = (n9 << 5) + (n9 << 2); /* (32*n9) + (4*n9) */
581 	n3 = (stride - cnt) / 12;
582 	cnt += (n3 << 3) + (n3 << 2); /* (8*n3) + (4*n3) */
583 	n1 = (stride - cnt) >> 2;
584 
585 	while (num--) {
586 		for (cnt = n9; cnt; cnt--) {
587 			dp[0] = xstamp[0];
588 			dp[1] = xstamp[1];
589 			dp[2] = xstamp[2];
590 			dp[3] = xstamp[0];
591 			dp[4] = xstamp[1];
592 			dp[5] = xstamp[2];
593 			dp[6] = xstamp[0];
594 			dp[7] = xstamp[1];
595 			dp[8] = xstamp[2];
596 			dp += 9;
597 		}
598 
599 		for (cnt = n3; cnt; cnt--) {
600 			dp[0] = xstamp[0];
601 			dp[1] = xstamp[1];
602 			dp[2] = xstamp[2];
603 			dp += 3;
604 		}
605 
606 		for (cnt = 0; cnt < n1; cnt++)
607 			*dp++ = xstamp[cnt];
608 
609 		DELTA(dp, delta, int32_t *);
610 	}
611 }
612 
613 /*
614  * Erase columns.
615  */
616 static void
617 rasops24_erasecols(cookie, row, col, num, attr)
618 	void *cookie;
619 	int row, col, num;
620 	long attr;
621 {
622 	int n12, n4, height, cnt, slop, clr, xstamp[3];
623 	struct rasops_info *ri;
624 	int32_t *dp, *rp;
625 	u_char *dbp;
626 
627 	/*
628 	 * If the color is gray, we can cheat and use the generic routines
629 	 * (which are faster, hopefully) since the r,g,b values are the same.
630 	 */
631 	if ((attr & 4) != 0) {
632 		rasops_erasecols(cookie, row, col, num, attr);
633 		return;
634 	}
635 
636 	ri = (struct rasops_info *)cookie;
637 
638 #ifdef RASOPS_CLIPPING
639 	/* Catches 'row < 0' case too */
640 	if ((unsigned)row >= (unsigned)ri->ri_rows)
641 		return;
642 
643 	if (col < 0) {
644 		num += col;
645 		col = 0;
646 	}
647 
648 	if ((col + num) > ri->ri_cols)
649 		num = ri->ri_cols - col;
650 
651 	if (num <= 0)
652 		return;
653 #endif
654 
655 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
656 	num *= ri->ri_font->fontwidth;
657 	height = ri->ri_font->fontheight;
658 
659 	clr = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xffffff;
660 	xstamp[0] = (clr <<  8) | (clr >> 16);
661 	xstamp[1] = (clr << 16) | (clr >>  8);
662 	xstamp[2] = (clr << 24) | clr;
663 
664 #if BYTE_ORDER == LITTLE_ENDIAN
665 	if ((ri->ri_flg & RI_BSWAP) == 0) {
666 #else
667 	if ((ri->ri_flg & RI_BSWAP) != 0) {
668 #endif
669 		xstamp[0] = bswap32(xstamp[0]);
670 		xstamp[1] = bswap32(xstamp[1]);
671 		xstamp[2] = bswap32(xstamp[2]);
672 	}
673 
674 	/*
675 	 * The current byte offset mod 4 tells us the number of 24-bit pels
676 	 * we need to write for alignment to 32-bits. Once we're aligned on
677 	 * a 32-bit boundary, we're also aligned on a 4 pixel boundary, so
678 	 * the stamp does not need to be rotated. The following shows the
679 	 * layout of 4 pels in a 3 word region and illustrates this:
680 	 *
681 	 *	aaab bbcc cddd
682 	 */
683 	slop = (int)(long)rp & 3;	num -= slop;
684 	n12 = num / 12;		num -= (n12 << 3) + (n12 << 2);
685 	n4 = num >> 2;		num &= 3;
686 
687 	while (height--) {
688 		dbp = (u_char *)rp;
689 		DELTA(rp, ri->ri_stride, int32_t *);
690 
691 		/* Align to 4 bytes */
692 		/* XXX handle with masks, bring under control of RI_BSWAP */
693 		for (cnt = slop; cnt; cnt--) {
694 			*dbp++ = (clr >> 16);
695 			*dbp++ = (clr >> 8);
696 			*dbp++ = clr;
697 		}
698 
699 		dp = (int32_t *)dbp;
700 
701 		/* 12 pels per loop */
702 		for (cnt = n12; cnt; cnt--) {
703 			dp[0] = xstamp[0];
704 			dp[1] = xstamp[1];
705 			dp[2] = xstamp[2];
706 			dp[3] = xstamp[0];
707 			dp[4] = xstamp[1];
708 			dp[5] = xstamp[2];
709 			dp[6] = xstamp[0];
710 			dp[7] = xstamp[1];
711 			dp[8] = xstamp[2];
712 			dp += 9;
713 		}
714 
715 		/* 4 pels per loop */
716 		for (cnt = n4; cnt; cnt--) {
717 			dp[0] = xstamp[0];
718 			dp[1] = xstamp[1];
719 			dp[2] = xstamp[2];
720 			dp += 3;
721 		}
722 
723 		/* Trailing slop */
724 		/* XXX handle with masks, bring under control of RI_BSWAP */
725 		dbp = (u_char *)dp;
726 		for (cnt = num; cnt; cnt--) {
727 			*dbp++ = (clr >> 16);
728 			*dbp++ = (clr >> 8);
729 			*dbp++ = clr;
730 		}
731 	}
732 }
733