xref: /netbsd-src/sys/dev/rasops/rasops15.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /* 	$NetBSD: rasops15.c,v 1.19 2010/05/04 04:57:34 macallan 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: rasops15.c,v 1.19 2010/05/04 04:57:34 macallan 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 <dev/wscons/wsdisplayvar.h>
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/rasops/rasops.h>
44 
45 static void 	rasops15_putchar(void *, int, int, u_int, long attr);
46 #ifndef RASOPS_SMALL
47 static void 	rasops15_putchar8(void *, int, int, u_int, long attr);
48 static void 	rasops15_putchar12(void *, int, int, u_int, long attr);
49 static void 	rasops15_putchar16(void *, int, int, u_int, long attr);
50 static void	rasops15_makestamp(struct rasops_info *, long);
51 #endif
52 
53 #ifndef RASOPS_SMALL
54 /*
55  * (2x2)x1 stamp for optimized character blitting
56  */
57 static int32_t	stamp[32];
58 static long	stamp_attr;
59 static int	stamp_mutex;	/* XXX see note in readme */
60 
61 /*
62  * XXX this confuses the hell out of gcc2 (not egcs) which always insists
63  * that the shift count is negative.
64  *
65  * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK
66  * destination int32_t[0] = STAMP_READ(offset)
67  * destination int32_t[1] = STAMP_READ(offset + 4)
68  */
69 #define STAMP_SHIFT(fb,n)	((n*4-3) >= 0 ? (fb)>>(n*4-3):(fb)<<-(n*4-3))
70 #define STAMP_MASK		(15 << 3)
71 #define STAMP_READ(o)		(*(int32_t *)((char *)stamp + (o)))
72 #endif
73 
74 /*
75  * Initialize rasops_info struct for this colordepth.
76  */
77 void
78 rasops15_init(struct rasops_info *ri)
79 {
80 
81 	switch (ri->ri_font->fontwidth) {
82 #ifndef RASOPS_SMALL
83 	case 8:
84 		ri->ri_ops.putchar = rasops15_putchar8;
85 		break;
86 
87 	case 12:
88 		ri->ri_ops.putchar = rasops15_putchar12;
89 		break;
90 
91 	case 16:
92 		ri->ri_ops.putchar = rasops15_putchar16;
93 		break;
94 #endif	/* !RASOPS_SMALL */
95 	default:
96 		ri->ri_ops.putchar = rasops15_putchar;
97 		break;
98 	}
99 
100 	if (ri->ri_rnum == 0) {
101 		ri->ri_rnum = 5;
102 		ri->ri_rpos = 0;
103 		ri->ri_gnum = 5 + (ri->ri_depth == 16);
104 		ri->ri_gpos = 5;
105 		ri->ri_bnum = 5;
106 		ri->ri_bpos = 10 + (ri->ri_depth == 16);
107 	}
108 }
109 
110 /*
111  * Paint a single character.
112  */
113 static void
114 rasops15_putchar(void *cookie, int row, int col, u_int uc, long attr)
115 {
116 	int fb, width, height, cnt, clr[2];
117 	struct rasops_info *ri = (struct rasops_info *)cookie;
118 	struct wsdisplay_font *font = PICK_FONT(ri, uc);
119 	u_char *dp, *rp, *hp, *hrp, *fr;
120 
121 	hp = hrp = NULL;
122 
123 #ifdef RASOPS_CLIPPING
124 	/* Catches 'row < 0' case too */
125 	if ((unsigned)row >= (unsigned)ri->ri_rows)
126 		return;
127 
128 	if ((unsigned)col >= (unsigned)ri->ri_cols)
129 		return;
130 #endif
131 
132 	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
133 	if (ri->ri_hwbits)
134 		hrp = ri->ri_hwbits + row * ri->ri_yscale +
135 		    col * ri->ri_xscale;
136 	height = font->fontheight;
137 	width = font->fontwidth;
138 
139 	clr[1] = ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
140 	clr[0] = ri->ri_devcmap[((u_int)attr >> 16) & 0xf];
141 
142 	if (uc == ' ') {
143 		int16_t c = (int16_t)clr[0];
144 		while (height--) {
145 			dp = rp;
146 			rp += ri->ri_stride;
147 			if (ri->ri_hwbits) {
148 				hp = hrp;
149 				hrp += ri->ri_stride;
150 			}
151 
152 			for (cnt = width; cnt; cnt--) {
153 				*(int16_t *)dp = c;
154 				dp += 2;
155 				if (ri->ri_hwbits) {
156 					*(int16_t *)hp = c;
157 					hp += 2;
158 				}
159 			}
160 		}
161 	} else {
162 		uc -= font->firstchar;
163 		fr = (u_char *)font->data + uc * ri->ri_fontscale;
164 
165 		while (height--) {
166 			dp = rp;
167 			fb = fr[3] | (fr[2] << 8) | (fr[1] << 16) | (fr[0] << 24);
168 			fr += font->stride;
169 			rp += ri->ri_stride;
170 			if (ri->ri_hwbits) {
171 				hp = hrp;
172 				hrp += ri->ri_stride;
173 			}
174 
175 			for (cnt = width; cnt; cnt--) {
176 				*(int16_t *)dp = (int16_t)clr[(fb >> 31) & 1];
177 				if (ri->ri_hwbits)
178 					*(int16_t *)hp =
179 					    (int16_t)clr[(fb >> 31) & 1];
180 				fb <<= 1;
181 				dp += 2;
182 				if (ri->ri_hwbits)
183 					hp += 2;
184 			}
185 		}
186 	}
187 
188 	/* Do underline */
189 	if ((attr & 1) != 0) {
190 		int16_t c = (int16_t)clr[1];
191 		rp -= ri->ri_stride << 1;
192 		if (ri->ri_hwbits)
193 			hrp -= ri->ri_stride << 1;
194 
195 		while (width--) {
196 			*(int16_t *)rp = c;
197 			rp += 2;
198 			if (ri->ri_hwbits) {
199 				*(int16_t *)hrp = c;
200 				hrp += 2;
201 			}
202 		}
203 	}
204 }
205 
206 #ifndef RASOPS_SMALL
207 /*
208  * Recompute the (2x2)x1 blitting stamp.
209  */
210 static void
211 rasops15_makestamp(struct rasops_info *ri, long attr)
212 {
213 	int32_t fg, bg;
214 	int i;
215 
216 	fg = ri->ri_devcmap[((u_int)attr >> 24) & 0xf] & 0xffff;
217 	bg = ri->ri_devcmap[((u_int)attr >> 16) & 0xf] & 0xffff;
218 	stamp_attr = attr;
219 
220 	for (i = 0; i < 32; i += 2) {
221 #if BYTE_ORDER == LITTLE_ENDIAN
222 		stamp[i] = (i & 16 ? fg : bg);
223 		stamp[i] |= ((i & 8 ? fg : bg) << 16);
224 		stamp[i + 1] = (i & 4 ? fg : bg);
225 		stamp[i + 1] |= ((i & 2 ? fg : bg) << 16);
226 #else
227 		stamp[i] = (i & 2 ? fg : bg);
228 		stamp[i] |= ((i & 4 ? fg : bg) << 16);
229 		stamp[i + 1] = (i & 8 ? fg : bg);
230 		stamp[i + 1] |= ((i & 16 ? fg : bg) << 16);
231 #endif
232 	}
233 }
234 
235 /*
236  * Paint a single character. This is for 8-pixel wide fonts.
237  */
238 static void
239 rasops15_putchar8(void *cookie, int row, int col, u_int uc, long attr)
240 {
241 	struct rasops_info *ri = (struct rasops_info *)cookie;
242 	struct wsdisplay_font *font = PICK_FONT(ri, uc);
243 	int height, so, fs;
244 	int32_t *rp, *hrp;
245 	u_char *fr;
246 
247 	/* Can't risk remaking the stamp if it's already in use */
248 	if (stamp_mutex++) {
249 		stamp_mutex--;
250 		rasops15_putchar(cookie, row, col, uc, attr);
251 		return;
252 	}
253 
254 	hrp = NULL;
255 
256 #ifdef RASOPS_CLIPPING
257 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
258 		stamp_mutex--;
259 		return;
260 	}
261 
262 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
263 		stamp_mutex--;
264 		return;
265 	}
266 #endif
267 
268 	/* Recompute stamp? */
269 	if (attr != stamp_attr)
270 		rasops15_makestamp(ri, attr);
271 
272 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
273 	if (ri->ri_hwbits)
274 		hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
275 		    col*ri->ri_xscale);
276 	height = font->fontheight;
277 
278 	if (uc == (u_int)-1) {
279 		int32_t c = stamp[0];
280 		while (height--) {
281 			rp[0] = rp[1] = rp[2] = rp[3] = c;
282 			DELTA(rp, ri->ri_stride, int32_t *);
283 			if (ri->ri_hwbits) {
284 				hrp[0] = hrp[1] = hrp[2] = hrp[3] = c;
285 				DELTA(hrp, ri->ri_stride, int32_t *);
286 			}
287 		}
288 	} else {
289 		uc -= font->firstchar;
290 		fr = (u_char *)font->data + uc*ri->ri_fontscale;
291 		fs = font->stride;
292 
293 		while (height--) {
294 			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
295 			rp[0] = STAMP_READ(so);
296 			rp[1] = STAMP_READ(so + 4);
297 			if (ri->ri_hwbits) {
298 				hrp[0] = STAMP_READ(so);
299 				hrp[1] = STAMP_READ(so + 4);
300 			}
301 
302 			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
303 			rp[2] = STAMP_READ(so);
304 			rp[3] = STAMP_READ(so + 4);
305 			if (ri->ri_hwbits) {
306 				hrp[2] = STAMP_READ(so);
307 				hrp[3] = STAMP_READ(so + 4);
308 			}
309 
310 			fr += fs;
311 			DELTA(rp, ri->ri_stride, int32_t *);
312 			if (ri->ri_hwbits)
313 				DELTA(hrp, ri->ri_stride, int32_t *);
314 		}
315 	}
316 
317 	/* Do underline */
318 	if ((attr & 1) != 0) {
319 		int32_t c = STAMP_READ(28);
320 
321 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
322 		rp[0] = rp[1] = rp[2] = rp[3] = c;
323 		if (ri->ri_hwbits) {
324 			DELTA(hrp, -(ri->ri_stride << 1), int32_t *);
325 			hrp[0] = hrp[1] = hrp[2] = hrp[3] = c;
326 		}
327 	}
328 
329 	stamp_mutex--;
330 }
331 
332 /*
333  * Paint a single character. This is for 12-pixel wide fonts.
334  */
335 static void
336 rasops15_putchar12(void *cookie, int row, int col, u_int uc, long attr)
337 {
338 	struct rasops_info *ri = (struct rasops_info *)cookie;
339 	struct wsdisplay_font *font = PICK_FONT(ri, uc);
340 	int height, so, fs;
341 	int32_t *rp, *hrp;
342 	u_char *fr;
343 
344 	/* Can't risk remaking the stamp if it's already in use */
345 	if (stamp_mutex++) {
346 		stamp_mutex--;
347 		rasops15_putchar(cookie, row, col, uc, attr);
348 		return;
349 	}
350 
351 	hrp = NULL;
352 
353 #ifdef RASOPS_CLIPPING
354 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
355 		stamp_mutex--;
356 		return;
357 	}
358 
359 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
360 		stamp_mutex--;
361 		return;
362 	}
363 #endif
364 
365 	/* Recompute stamp? */
366 	if (attr != stamp_attr)
367 		rasops15_makestamp(ri, attr);
368 
369 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
370 	if (ri->ri_hwbits)
371 		hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
372 		    col*ri->ri_xscale);
373 	height = font->fontheight;
374 
375 	if (uc == (u_int)-1) {
376 		int32_t c = stamp[0];
377 		while (height--) {
378 			rp[0] = rp[1] = rp[2] = rp[3] = rp[4] = rp[5] = c;
379 			DELTA(rp, ri->ri_stride, int32_t *);
380 			if (ri->ri_hwbits) {
381 				hrp[0] = hrp[1] = hrp[2] = hrp[3] = hrp[4] =
382 				    hrp[5] = c;
383 				DELTA(hrp, ri->ri_stride, int32_t *);
384 			}
385 		}
386 	} else {
387 		uc -= font->firstchar;
388 		fr = (u_char *)font->data + uc*ri->ri_fontscale;
389 		fs = font->stride;
390 
391 		while (height--) {
392 			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
393 			rp[0] = STAMP_READ(so);
394 			rp[1] = STAMP_READ(so + 4);
395 			if (ri->ri_hwbits) {
396 				hrp[0] = STAMP_READ(so);
397 				hrp[1] = STAMP_READ(so + 4);
398 			}
399 
400 			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
401 			rp[2] = STAMP_READ(so);
402 			rp[3] = STAMP_READ(so + 4);
403 			if (ri->ri_hwbits) {
404 				hrp[2] = STAMP_READ(so);
405 				hrp[3] = STAMP_READ(so + 4);
406 			}
407 
408 			so = STAMP_SHIFT(fr[1], 1) & STAMP_MASK;
409 			rp[4] = STAMP_READ(so);
410 			rp[5] = STAMP_READ(so + 4);
411 			if (ri->ri_hwbits) {
412 				hrp[4] = STAMP_READ(so);
413 				hrp[5] = STAMP_READ(so + 4);
414 			}
415 
416 			fr += fs;
417 			DELTA(rp, ri->ri_stride, int32_t *);
418 			if (ri->ri_hwbits)
419 				DELTA(hrp, ri->ri_stride, int32_t *);
420 		}
421 	}
422 
423 	/* Do underline */
424 	if (attr & 1) {
425 		int32_t c = STAMP_READ(28);
426 
427 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
428 		rp[0] = rp[1] = rp[2] = rp[3] = rp[4] = rp[5] = c;
429 		if (ri->ri_hwbits) {
430 			DELTA(hrp, -(ri->ri_stride << 1), int32_t *);
431 			hrp[0] = hrp[1] = hrp[2] = hrp[3] = hrp[4] = hrp[5] = c;
432 		}
433 	}
434 
435 	stamp_mutex--;
436 }
437 
438 /*
439  * Paint a single character. This is for 16-pixel wide fonts.
440  */
441 static void
442 rasops15_putchar16(void *cookie, int row, int col, u_int uc, long attr)
443 {
444 	struct rasops_info *ri = (struct rasops_info *)cookie;
445 	struct wsdisplay_font *font = PICK_FONT(ri, uc);
446 	int height, so, fs;
447 	int32_t *rp, *hrp;
448 	u_char *fr;
449 
450 	/* Can't risk remaking the stamp if it's already in use */
451 	if (stamp_mutex++) {
452 		stamp_mutex--;
453 		rasops15_putchar(cookie, row, col, uc, attr);
454 		return;
455 	}
456 
457 	hrp = NULL;
458 
459 #ifdef RASOPS_CLIPPING
460 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
461 		stamp_mutex--;
462 		return;
463 	}
464 
465 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
466 		stamp_mutex--;
467 		return;
468 	}
469 #endif
470 
471 	/* Recompute stamp? */
472 	if (attr != stamp_attr)
473 		rasops15_makestamp(ri, attr);
474 
475 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
476 	if (ri->ri_hwbits)
477 		hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
478 		    col*ri->ri_xscale);
479 	height = font->fontheight;
480 
481 	if (uc == (u_int)-1) {
482 		int32_t c = stamp[0];
483 		while (height--) {
484 			rp[0] = rp[1] = rp[2] = rp[3] =
485 			rp[4] = rp[5] = rp[6] = rp[7] = c;
486 			DELTA(rp, ri->ri_stride, int32_t *);
487 			if (ri->ri_hwbits) {
488 				hrp[0] = hrp[1] = hrp[2] = hrp[3] =
489 				hrp[4] = hrp[5] = hrp[6] = hrp[7] = c;
490 				DELTA(hrp, ri->ri_stride, int32_t *);
491 			}
492 		}
493 	} else {
494 		uc -= font->firstchar;
495 		fr = (u_char *)font->data + uc*ri->ri_fontscale;
496 		fs = font->stride;
497 
498 		while (height--) {
499 			so = STAMP_SHIFT(fr[0], 1) & STAMP_MASK;
500 			rp[0] = STAMP_READ(so);
501 			rp[1] = STAMP_READ(so + 4);
502 			if (ri->ri_hwbits) {
503 				hrp[0] = STAMP_READ(so);
504 				hrp[1] = STAMP_READ(so + 4);
505 			}
506 
507 			so = STAMP_SHIFT(fr[0], 0) & STAMP_MASK;
508 			rp[2] = STAMP_READ(so);
509 			rp[3] = STAMP_READ(so + 4);
510 			if (ri->ri_hwbits) {
511 				hrp[2] = STAMP_READ(so);
512 				hrp[3] = STAMP_READ(so + 4);
513 			}
514 
515 			so = STAMP_SHIFT(fr[1], 1) & STAMP_MASK;
516 			rp[4] = STAMP_READ(so);
517 			rp[5] = STAMP_READ(so + 4);
518 			if (ri->ri_hwbits) {
519 				hrp[4] = STAMP_READ(so);
520 				hrp[5] = STAMP_READ(so + 4);
521 			}
522 
523 			so = STAMP_SHIFT(fr[1], 0) & STAMP_MASK;
524 			rp[6] = STAMP_READ(so);
525 			rp[7] = STAMP_READ(so + 4);
526 			if (ri->ri_hwbits) {
527 				hrp[6] = STAMP_READ(so);
528 				hrp[7] = STAMP_READ(so + 4);
529 			}
530 
531 			DELTA(rp, ri->ri_stride, int32_t *);
532 			if (ri->ri_hwbits)
533 				DELTA(hrp, ri->ri_stride, int32_t *);
534 			fr += fs;
535 		}
536 	}
537 
538 	/* Do underline */
539 	if (attr & 1) {
540 		int32_t c = STAMP_READ(28);
541 
542 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
543 		rp[0] = rp[1] = rp[2] = rp[3] =
544 		rp[4] = rp[5] = rp[6] = rp[7] = c;
545 		if (ri->ri_hwbits) {
546 			DELTA(hrp, -(ri->ri_stride << 1), int32_t *);
547 			hrp[0] = hrp[1] = hrp[2] = hrp[3] =
548 			hrp[4] = hrp[5] = hrp[6] = hrp[7] = c;
549 		}
550 	}
551 
552 	stamp_mutex--;
553 }
554 #endif	/* !RASOPS_SMALL */
555