rasops8.c revision 1.30 1 /* $NetBSD: rasops8.c,v 1.30 2012/01/04 20:16:20 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: rasops8.c,v 1.30 2012/01/04 20:16:20 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 rasops8_putchar(void *, int, int, u_int, long attr);
46 static void rasops8_putchar_aa(void *, int, int, u_int, long attr);
47 #ifndef RASOPS_SMALL
48 static void rasops8_putchar8(void *, int, int, u_int, long attr);
49 static void rasops8_putchar12(void *, int, int, u_int, long attr);
50 static void rasops8_putchar16(void *, int, int, u_int, long attr);
51 static void rasops8_makestamp(struct rasops_info *ri, long);
52
53 /*
54 * 4x1 stamp for optimized character blitting
55 */
56 static int32_t stamp[16];
57 static long stamp_attr;
58 static int stamp_mutex; /* XXX see note in README */
59 #endif
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 = STAMP_READ(offset)
67 */
68 #define STAMP_SHIFT(fb,n) ((n*4-2) >= 0 ? (fb)>>(n*4-2):(fb)<<-(n*4-2))
69 #define STAMP_MASK (0xf << 2)
70 #define STAMP_READ(o) (*(int32_t *)((char *)stamp + (o)))
71
72 /*
73 * Initialize a 'rasops_info' descriptor for this depth.
74 */
75 void
76 rasops8_init(struct rasops_info *ri)
77 {
78
79 if FONT_IS_ALPHA(ri->ri_font) {
80 ri->ri_ops.putchar = rasops8_putchar_aa;
81 } else {
82 switch (ri->ri_font->fontwidth) {
83 #ifndef RASOPS_SMALL
84 case 8:
85 ri->ri_ops.putchar = rasops8_putchar8;
86 break;
87 case 12:
88 ri->ri_ops.putchar = rasops8_putchar12;
89 break;
90 case 16:
91 ri->ri_ops.putchar = rasops8_putchar16;
92 break;
93 #endif /* !RASOPS_SMALL */
94 default:
95 ri->ri_ops.putchar = rasops8_putchar;
96 break;
97 }
98 }
99 if (ri->ri_flg & RI_8BIT_IS_RGB) {
100 ri->ri_rnum = 3;
101 ri->ri_rpos = 5;
102 ri->ri_gnum = 3;
103 ri->ri_gpos = 2;
104 ri->ri_bnum = 2;
105 ri->ri_bpos = 0;
106 }
107 }
108
109 /*
110 * Put a single character.
111 */
112 static void
113 rasops8_putchar(void *cookie, int row, int col, u_int uc, long attr)
114 {
115 int width, height, cnt, fs, fb;
116 u_char *dp, *rp, *hp, *hrp, *fr, clr[2];
117 struct rasops_info *ri = (struct rasops_info *)cookie;
118 struct wsdisplay_font *font = PICK_FONT(ri, uc);
119
120 hp = hrp = NULL;
121
122 if (!CHAR_IN_FONT(uc, font))
123 return;
124
125 #ifdef RASOPS_CLIPPING
126 /* Catches 'row < 0' case too */
127 if ((unsigned)row >= (unsigned)ri->ri_rows)
128 return;
129
130 if ((unsigned)col >= (unsigned)ri->ri_cols)
131 return;
132 #endif
133 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
134 if (ri->ri_hwbits)
135 hrp = ri->ri_hwbits + row * ri->ri_yscale + col *
136 ri->ri_xscale;
137
138 height = font->fontheight;
139 width = font->fontwidth;
140 clr[0] = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf];
141 clr[1] = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf];
142
143 if (uc == ' ') {
144 u_char c = clr[0];
145
146 while (height--) {
147 dp = rp;
148 rp += ri->ri_stride;
149 if (ri->ri_hwbits) {
150 hp = hrp;
151 hrp += ri->ri_stride;
152 }
153
154 for (cnt = width; cnt; cnt--) {
155 *dp++ = c;
156 if (ri->ri_hwbits)
157 *hp++ = c;
158 }
159 }
160 } else {
161 fr = WSFONT_GLYPH(uc, font);
162 fs = font->stride;
163
164 while (height--) {
165 dp = rp;
166 if (ri->ri_hwbits)
167 hp = hrp;
168 fb = fr[3] | (fr[2] << 8) | (fr[1] << 16) | (fr[0] << 24);
169 fr += fs;
170 rp += ri->ri_stride;
171 if (ri->ri_hwbits)
172 hrp += ri->ri_stride;
173
174 for (cnt = width; cnt; cnt--) {
175 *dp++ = clr[(fb >> 31) & 1];
176 if (ri->ri_hwbits)
177 *hp++ = clr[(fb >> 31) & 1];
178 fb <<= 1;
179 }
180 }
181 }
182
183 /* Do underline */
184 if ((attr & 1) != 0) {
185 u_char c = clr[1];
186
187 rp -= (ri->ri_stride << 1);
188 if (ri->ri_hwbits)
189 hrp -= (ri->ri_stride << 1);
190
191 while (width--) {
192 *rp++ = c;
193 if (ri->ri_hwbits)
194 *hrp++ = c;
195 }
196 }
197 }
198
199 static void
200 rasops8_putchar_aa(void *cookie, int row, int col, u_int uc, long attr)
201 {
202 int width, height, cnt, fs;
203 u_char *dp, *rp, *hp, *hrp, *fr, bg, fg, pixel;
204 struct rasops_info *ri = (struct rasops_info *)cookie;
205 struct wsdisplay_font *font = PICK_FONT(ri, uc);
206 int x, y, r, g, b, aval;
207 int r1, g1, b1, r0, g0, b0, fgo, bgo;
208
209 hp = hrp = NULL;
210
211 if (!CHAR_IN_FONT(uc, font))
212 return;
213
214 #ifdef RASOPS_CLIPPING
215 /* Catches 'row < 0' case too */
216 if ((unsigned)row >= (unsigned)ri->ri_rows)
217 return;
218
219 if ((unsigned)col >= (unsigned)ri->ri_cols)
220 return;
221 #endif
222 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
223 if (ri->ri_hwbits)
224 hrp = ri->ri_hwbits + row * ri->ri_yscale + col *
225 ri->ri_xscale;
226
227 height = font->fontheight;
228 width = font->fontwidth;
229 bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf];
230 fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf];
231
232 if (uc == ' ') {
233
234 while (height--) {
235 dp = rp;
236 rp += ri->ri_stride;
237 if (ri->ri_hwbits) {
238 hp = hrp;
239 hrp += ri->ri_stride;
240 }
241
242 for (cnt = width; cnt; cnt--) {
243 *dp++ = bg;
244 if (ri->ri_hwbits)
245 *hp++ = bg;
246 }
247 }
248 } else {
249 fr = WSFONT_GLYPH(uc, font);
250 fs = font->stride;
251 /*
252 * we need the RGB colours here, get offsets into rasops_cmap
253 */
254 fgo = ((attr >> 24) & 0xf) * 3;
255 bgo = ((attr >> 16) & 0xf) * 3;
256
257 r0 = rasops_cmap[bgo];
258 r1 = rasops_cmap[fgo];
259 g0 = rasops_cmap[bgo + 1];
260 g1 = rasops_cmap[fgo + 1];
261 b0 = rasops_cmap[bgo + 2];
262 b1 = rasops_cmap[fgo + 2];
263
264 for (y = 0; y < height; y++) {
265 dp = rp;
266 for (x = 0; x < width; x++) {
267 aval = *fr;
268 fr++;
269 if (aval == 0) {
270 pixel = bg;
271 } else if (aval == 255) {
272 pixel = fg;
273 } else {
274 r = aval * r1 + (255 - aval) * r0;
275 g = aval * g1 + (255 - aval) * g0;
276 b = aval * b1 + (255 - aval) * b0;
277 pixel = ((r & 0xe000) >> 8) |
278 ((g & 0xe000) >> 11) |
279 ((b & 0xc000) >> 14);
280 }
281 *dp = pixel;
282 dp++;
283 }
284 if (ri->ri_hwbits) {
285 memcpy(rp, hrp, width);
286 hrp += ri->ri_stride;
287 }
288 rp += ri->ri_stride;
289
290 }
291 }
292
293 /* Do underline */
294 if ((attr & 1) != 0) {
295
296 rp -= (ri->ri_stride << 1);
297 if (ri->ri_hwbits)
298 hrp -= (ri->ri_stride << 1);
299
300 while (width--) {
301 *rp++ = fg;
302 if (ri->ri_hwbits)
303 *hrp++ = fg;
304 }
305 }
306 }
307
308 #ifndef RASOPS_SMALL
309 /*
310 * Recompute the 4x1 blitting stamp.
311 */
312 static void
313 rasops8_makestamp(struct rasops_info *ri, long attr)
314 {
315 int32_t fg, bg;
316 int i;
317
318 fg = ri->ri_devcmap[(attr >> 24) & 0xf] & 0xff;
319 bg = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xff;
320 stamp_attr = attr;
321
322 for (i = 0; i < 16; i++) {
323 #if BYTE_ORDER == BIG_ENDIAN
324 #define NEED_LITTLE_ENDIAN_STAMP RI_BSWAP
325 #else
326 #define NEED_LITTLE_ENDIAN_STAMP 0
327 #endif
328 if ((ri->ri_flg & RI_BSWAP) == NEED_LITTLE_ENDIAN_STAMP) {
329 /* little endian */
330 stamp[i] = (i & 8 ? fg : bg);
331 stamp[i] |= ((i & 4 ? fg : bg) << 8);
332 stamp[i] |= ((i & 2 ? fg : bg) << 16);
333 stamp[i] |= ((i & 1 ? fg : bg) << 24);
334 } else {
335 /* big endian */
336 stamp[i] = (i & 1 ? fg : bg);
337 stamp[i] |= ((i & 2 ? fg : bg) << 8);
338 stamp[i] |= ((i & 4 ? fg : bg) << 16);
339 stamp[i] |= ((i & 8 ? fg : bg) << 24);
340 }
341 }
342 }
343
344 /*
345 * Put a single character. This is for 8-pixel wide fonts.
346 */
347 static void
348 rasops8_putchar8(void *cookie, int row, int col, u_int uc, long attr)
349 {
350 struct rasops_info *ri = (struct rasops_info *)cookie;
351 struct wsdisplay_font *font = PICK_FONT(ri, uc);
352 int height, fs;
353 int32_t *rp, *hp;
354 u_char *fr;
355
356 /* Can't risk remaking the stamp if it's already in use */
357 if (stamp_mutex++) {
358 stamp_mutex--;
359 rasops8_putchar(cookie, row, col, uc, attr);
360 return;
361 }
362
363 hp = NULL;
364
365 if (!CHAR_IN_FONT(uc, font))
366 return;
367
368 #ifdef RASOPS_CLIPPING
369 if ((unsigned)row >= (unsigned)ri->ri_rows) {
370 stamp_mutex--;
371 return;
372 }
373
374 if ((unsigned)col >= (unsigned)ri->ri_cols) {
375 stamp_mutex--;
376 return;
377 }
378 #endif
379
380 /* Recompute stamp? */
381 if (attr != stamp_attr)
382 rasops8_makestamp(ri, attr);
383
384 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
385 if (ri->ri_hwbits)
386 hp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
387 col*ri->ri_xscale);
388 height = font->fontheight;
389
390 if (uc == ' ') {
391 while (height--) {
392 rp[0] = rp[1] = stamp[0];
393 DELTA(rp, ri->ri_stride, int32_t *);
394 if (ri->ri_hwbits) {
395 hp[0] = stamp[0];
396 hp[1] = stamp[0];
397 DELTA(hp, ri->ri_stride, int32_t *);
398 }
399 }
400 } else {
401 fr = WSFONT_GLYPH(uc, font);
402 fs = font->stride;
403
404 while (height--) {
405 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
406 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
407 if (ri->ri_hwbits) {
408 hp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) &
409 STAMP_MASK);
410 hp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) &
411 STAMP_MASK);
412 }
413
414 fr += fs;
415 DELTA(rp, ri->ri_stride, int32_t *);
416 if (ri->ri_hwbits)
417 DELTA(hp, ri->ri_stride, int32_t *);
418 }
419 }
420
421 /* Do underline */
422 if ((attr & 1) != 0) {
423 DELTA(rp, -(ri->ri_stride << 1), int32_t *);
424 rp[0] = rp[1] = stamp[15];
425 if (ri->ri_hwbits) {
426 DELTA(hp, -(ri->ri_stride << 1), int32_t *);
427 hp[0] = stamp[15];
428 hp[1] = stamp[15];
429 }
430 }
431
432 stamp_mutex--;
433 }
434
435 /*
436 * Put a single character. This is for 12-pixel wide fonts.
437 */
438 static void
439 rasops8_putchar12(void *cookie, int row, int col, u_int uc, long attr)
440 {
441 struct rasops_info *ri = (struct rasops_info *)cookie;
442 struct wsdisplay_font *font = PICK_FONT(ri, uc);
443 int height, fs;
444 int32_t *rp, *hrp;
445 u_char *fr;
446
447 /* Can't risk remaking the stamp if it's already in use */
448 if (stamp_mutex++) {
449 stamp_mutex--;
450 rasops8_putchar(cookie, row, col, uc, attr);
451 return;
452 }
453
454 hrp = NULL;
455
456 if (!CHAR_IN_FONT(uc, font))
457 return;
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 rasops8_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 == ' ') {
482 while (height--) {
483 int32_t c = stamp[0];
484
485 rp[0] = rp[1] = rp[2] = c;
486 DELTA(rp, ri->ri_stride, int32_t *);
487 if (ri->ri_hwbits) {
488 hrp[0] = c;
489 hrp[1] = c;
490 hrp[2] = c;
491 DELTA(hrp, ri->ri_stride, int32_t *);
492 }
493 }
494 } else {
495 fr = WSFONT_GLYPH(uc, font);
496 fs = font->stride;
497
498 while (height--) {
499 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
500 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
501 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
502 if (ri->ri_hwbits) {
503 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
504 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
505 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
506 }
507
508 fr += fs;
509 DELTA(rp, ri->ri_stride, int32_t *);
510 if (ri->ri_hwbits)
511 DELTA(hrp, ri->ri_stride, int32_t *);
512 }
513 }
514
515 /* Do underline */
516 if ((attr & 1) != 0) {
517 DELTA(rp, -(ri->ri_stride << 1), int32_t *);
518 rp[0] = rp[1] = rp[2] = stamp[15];
519 if (ri->ri_hwbits) {
520 DELTA(hrp, -(ri->ri_stride << 1), int32_t *);
521 hrp[0] = stamp[15];
522 hrp[1] = stamp[15];
523 hrp[2] = stamp[15];
524 }
525 }
526
527 stamp_mutex--;
528 }
529
530 /*
531 * Put a single character. This is for 16-pixel wide fonts.
532 */
533 static void
534 rasops8_putchar16(void *cookie, int row, int col, u_int uc, long attr)
535 {
536 struct rasops_info *ri = (struct rasops_info *)cookie;
537 struct wsdisplay_font *font = PICK_FONT(ri, uc);
538 int height, fs;
539 int32_t *rp, *hrp;
540 u_char *fr;
541
542 /* Can't risk remaking the stamp if it's already in use */
543 if (stamp_mutex++) {
544 stamp_mutex--;
545 rasops8_putchar(cookie, row, col, uc, attr);
546 return;
547 }
548
549 hrp = NULL;
550
551 if (!CHAR_IN_FONT(uc, font))
552 return;
553
554 #ifdef RASOPS_CLIPPING
555 if ((unsigned)row >= (unsigned)ri->ri_rows) {
556 stamp_mutex--;
557 return;
558 }
559
560 if ((unsigned)col >= (unsigned)ri->ri_cols) {
561 stamp_mutex--;
562 return;
563 }
564 #endif
565
566 /* Recompute stamp? */
567 if (attr != stamp_attr)
568 rasops8_makestamp(ri, attr);
569
570 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
571 if (ri->ri_hwbits)
572 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
573 col*ri->ri_xscale);
574
575 height = font->fontheight;
576
577 if (uc == ' ') {
578 while (height--) {
579 rp[0] = rp[1] = rp[2] = rp[3] = stamp[0];
580 if (ri->ri_hwbits) {
581 hrp[0] = stamp[0];
582 hrp[1] = stamp[0];
583 hrp[2] = stamp[0];
584 hrp[3] = stamp[0];
585 }
586 }
587 } else {
588 fr = WSFONT_GLYPH(uc, font);
589 fs = font->stride;
590
591 while (height--) {
592 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
593 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
594 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
595 rp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK);
596 if (ri->ri_hwbits) {
597 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
598 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
599 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
600 hrp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK);
601 }
602
603 fr += fs;
604 DELTA(rp, ri->ri_stride, int32_t *);
605 if (ri->ri_hwbits)
606 DELTA(hrp, ri->ri_stride, int32_t *);
607 }
608 }
609
610 /* Do underline */
611 if ((attr & 1) != 0) {
612 DELTA(rp, -(ri->ri_stride << 1), int32_t *);
613 rp[0] = rp[1] = rp[2] = rp[3] = stamp[15];
614 if (ri->ri_hwbits) {
615 DELTA(hrp, -(ri->ri_stride << 1), int32_t *);
616 hrp[0] = stamp[15];
617 hrp[1] = stamp[15];
618 hrp[2] = stamp[15];
619 hrp[3] = stamp[15];
620 }
621 }
622
623 stamp_mutex--;
624 }
625 #endif /* !RASOPS_SMALL */
626