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