rasops8.c revision 1.31 1 /* $NetBSD: rasops8.c,v 1.31 2012/01/25 16:38:27 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.31 2012/01/25 16:38:27 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 uint8_t scanline[32] __attribute__ ((aligned(8)));
209
210 hp = hrp = NULL;
211
212 if (!CHAR_IN_FONT(uc, font))
213 return;
214
215 #ifdef RASOPS_CLIPPING
216 /* Catches 'row < 0' case too */
217 if ((unsigned)row >= (unsigned)ri->ri_rows)
218 return;
219
220 if ((unsigned)col >= (unsigned)ri->ri_cols)
221 return;
222 #endif
223 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
224 if (ri->ri_hwbits)
225 hrp = ri->ri_hwbits + row * ri->ri_yscale + col *
226 ri->ri_xscale;
227
228 height = font->fontheight;
229 width = font->fontwidth;
230 bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf];
231 fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf];
232
233 if (uc == ' ') {
234
235 while (height--) {
236 dp = rp;
237 rp += ri->ri_stride;
238 if (ri->ri_hwbits) {
239 hp = hrp;
240 hrp += ri->ri_stride;
241 }
242
243 for (cnt = width; cnt; cnt--) {
244 *dp++ = bg;
245 if (ri->ri_hwbits)
246 *hp++ = bg;
247 }
248 }
249 } else {
250 fr = WSFONT_GLYPH(uc, font);
251 fs = font->stride;
252 /*
253 * we need the RGB colours here, get offsets into rasops_cmap
254 */
255 fgo = ((attr >> 24) & 0xf) * 3;
256 bgo = ((attr >> 16) & 0xf) * 3;
257
258 r0 = rasops_cmap[bgo];
259 r1 = rasops_cmap[fgo];
260 g0 = rasops_cmap[bgo + 1];
261 g1 = rasops_cmap[fgo + 1];
262 b0 = rasops_cmap[bgo + 2];
263 b1 = rasops_cmap[fgo + 2];
264
265 for (y = 0; y < height; y++) {
266 dp = rp;
267 for (x = 0; x < width; x++) {
268 aval = *fr;
269 fr++;
270 if (aval == 0) {
271 pixel = bg;
272 } else if (aval == 255) {
273 pixel = fg;
274 } else {
275 r = aval * r1 + (255 - aval) * r0;
276 g = aval * g1 + (255 - aval) * g0;
277 b = aval * b1 + (255 - aval) * b0;
278 pixel = ((r & 0xe000) >> 8) |
279 ((g & 0xe000) >> 11) |
280 ((b & 0xc000) >> 14);
281 }
282 scanline[x] = pixel;
283 }
284 memcpy(rp, scanline, width);
285 if (ri->ri_hwbits) {
286 memcpy(hrp, scanline, width);
287 hrp += ri->ri_stride;
288 }
289 rp += ri->ri_stride;
290
291 }
292 }
293
294 /* Do underline */
295 if ((attr & 1) != 0) {
296
297 rp -= (ri->ri_stride << 1);
298 if (ri->ri_hwbits)
299 hrp -= (ri->ri_stride << 1);
300
301 while (width--) {
302 *rp++ = fg;
303 if (ri->ri_hwbits)
304 *hrp++ = fg;
305 }
306 }
307 }
308
309 #ifndef RASOPS_SMALL
310 /*
311 * Recompute the 4x1 blitting stamp.
312 */
313 static void
314 rasops8_makestamp(struct rasops_info *ri, long attr)
315 {
316 int32_t fg, bg;
317 int i;
318
319 fg = ri->ri_devcmap[(attr >> 24) & 0xf] & 0xff;
320 bg = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xff;
321 stamp_attr = attr;
322
323 for (i = 0; i < 16; i++) {
324 #if BYTE_ORDER == BIG_ENDIAN
325 #define NEED_LITTLE_ENDIAN_STAMP RI_BSWAP
326 #else
327 #define NEED_LITTLE_ENDIAN_STAMP 0
328 #endif
329 if ((ri->ri_flg & RI_BSWAP) == NEED_LITTLE_ENDIAN_STAMP) {
330 /* little endian */
331 stamp[i] = (i & 8 ? fg : bg);
332 stamp[i] |= ((i & 4 ? fg : bg) << 8);
333 stamp[i] |= ((i & 2 ? fg : bg) << 16);
334 stamp[i] |= ((i & 1 ? fg : bg) << 24);
335 } else {
336 /* big endian */
337 stamp[i] = (i & 1 ? fg : bg);
338 stamp[i] |= ((i & 2 ? fg : bg) << 8);
339 stamp[i] |= ((i & 4 ? fg : bg) << 16);
340 stamp[i] |= ((i & 8 ? fg : bg) << 24);
341 }
342 }
343 }
344
345 /*
346 * Put a single character. This is for 8-pixel wide fonts.
347 */
348 static void
349 rasops8_putchar8(void *cookie, int row, int col, u_int uc, long attr)
350 {
351 struct rasops_info *ri = (struct rasops_info *)cookie;
352 struct wsdisplay_font *font = PICK_FONT(ri, uc);
353 int height, fs;
354 int32_t *rp, *hp;
355 u_char *fr;
356
357 /* Can't risk remaking the stamp if it's already in use */
358 if (stamp_mutex++) {
359 stamp_mutex--;
360 rasops8_putchar(cookie, row, col, uc, attr);
361 return;
362 }
363
364 hp = NULL;
365
366 if (!CHAR_IN_FONT(uc, font))
367 return;
368
369 #ifdef RASOPS_CLIPPING
370 if ((unsigned)row >= (unsigned)ri->ri_rows) {
371 stamp_mutex--;
372 return;
373 }
374
375 if ((unsigned)col >= (unsigned)ri->ri_cols) {
376 stamp_mutex--;
377 return;
378 }
379 #endif
380
381 /* Recompute stamp? */
382 if (attr != stamp_attr)
383 rasops8_makestamp(ri, attr);
384
385 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
386 if (ri->ri_hwbits)
387 hp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
388 col*ri->ri_xscale);
389 height = font->fontheight;
390
391 if (uc == ' ') {
392 while (height--) {
393 rp[0] = rp[1] = stamp[0];
394 DELTA(rp, ri->ri_stride, int32_t *);
395 if (ri->ri_hwbits) {
396 hp[0] = stamp[0];
397 hp[1] = stamp[0];
398 DELTA(hp, ri->ri_stride, int32_t *);
399 }
400 }
401 } else {
402 fr = WSFONT_GLYPH(uc, font);
403 fs = font->stride;
404
405 while (height--) {
406 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
407 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
408 if (ri->ri_hwbits) {
409 hp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) &
410 STAMP_MASK);
411 hp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) &
412 STAMP_MASK);
413 }
414
415 fr += fs;
416 DELTA(rp, ri->ri_stride, int32_t *);
417 if (ri->ri_hwbits)
418 DELTA(hp, ri->ri_stride, int32_t *);
419 }
420 }
421
422 /* Do underline */
423 if ((attr & 1) != 0) {
424 DELTA(rp, -(ri->ri_stride << 1), int32_t *);
425 rp[0] = rp[1] = stamp[15];
426 if (ri->ri_hwbits) {
427 DELTA(hp, -(ri->ri_stride << 1), int32_t *);
428 hp[0] = stamp[15];
429 hp[1] = stamp[15];
430 }
431 }
432
433 stamp_mutex--;
434 }
435
436 /*
437 * Put a single character. This is for 12-pixel wide fonts.
438 */
439 static void
440 rasops8_putchar12(void *cookie, int row, int col, u_int uc, long attr)
441 {
442 struct rasops_info *ri = (struct rasops_info *)cookie;
443 struct wsdisplay_font *font = PICK_FONT(ri, uc);
444 int height, fs;
445 int32_t *rp, *hrp;
446 u_char *fr;
447
448 /* Can't risk remaking the stamp if it's already in use */
449 if (stamp_mutex++) {
450 stamp_mutex--;
451 rasops8_putchar(cookie, row, col, uc, attr);
452 return;
453 }
454
455 hrp = NULL;
456
457 if (!CHAR_IN_FONT(uc, font))
458 return;
459
460 #ifdef RASOPS_CLIPPING
461 if ((unsigned)row >= (unsigned)ri->ri_rows) {
462 stamp_mutex--;
463 return;
464 }
465
466 if ((unsigned)col >= (unsigned)ri->ri_cols) {
467 stamp_mutex--;
468 return;
469 }
470 #endif
471
472 /* Recompute stamp? */
473 if (attr != stamp_attr)
474 rasops8_makestamp(ri, attr);
475
476 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
477 if (ri->ri_hwbits)
478 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
479 col*ri->ri_xscale);
480 height = font->fontheight;
481
482 if (uc == ' ') {
483 while (height--) {
484 int32_t c = stamp[0];
485
486 rp[0] = rp[1] = rp[2] = c;
487 DELTA(rp, ri->ri_stride, int32_t *);
488 if (ri->ri_hwbits) {
489 hrp[0] = c;
490 hrp[1] = c;
491 hrp[2] = c;
492 DELTA(hrp, ri->ri_stride, int32_t *);
493 }
494 }
495 } else {
496 fr = WSFONT_GLYPH(uc, font);
497 fs = font->stride;
498
499 while (height--) {
500 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
501 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
502 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
503 if (ri->ri_hwbits) {
504 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
505 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
506 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
507 }
508
509 fr += fs;
510 DELTA(rp, ri->ri_stride, int32_t *);
511 if (ri->ri_hwbits)
512 DELTA(hrp, ri->ri_stride, int32_t *);
513 }
514 }
515
516 /* Do underline */
517 if ((attr & 1) != 0) {
518 DELTA(rp, -(ri->ri_stride << 1), int32_t *);
519 rp[0] = rp[1] = rp[2] = stamp[15];
520 if (ri->ri_hwbits) {
521 DELTA(hrp, -(ri->ri_stride << 1), int32_t *);
522 hrp[0] = stamp[15];
523 hrp[1] = stamp[15];
524 hrp[2] = stamp[15];
525 }
526 }
527
528 stamp_mutex--;
529 }
530
531 /*
532 * Put a single character. This is for 16-pixel wide fonts.
533 */
534 static void
535 rasops8_putchar16(void *cookie, int row, int col, u_int uc, long attr)
536 {
537 struct rasops_info *ri = (struct rasops_info *)cookie;
538 struct wsdisplay_font *font = PICK_FONT(ri, uc);
539 int height, fs;
540 int32_t *rp, *hrp;
541 u_char *fr;
542
543 /* Can't risk remaking the stamp if it's already in use */
544 if (stamp_mutex++) {
545 stamp_mutex--;
546 rasops8_putchar(cookie, row, col, uc, attr);
547 return;
548 }
549
550 hrp = NULL;
551
552 if (!CHAR_IN_FONT(uc, font))
553 return;
554
555 #ifdef RASOPS_CLIPPING
556 if ((unsigned)row >= (unsigned)ri->ri_rows) {
557 stamp_mutex--;
558 return;
559 }
560
561 if ((unsigned)col >= (unsigned)ri->ri_cols) {
562 stamp_mutex--;
563 return;
564 }
565 #endif
566
567 /* Recompute stamp? */
568 if (attr != stamp_attr)
569 rasops8_makestamp(ri, attr);
570
571 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
572 if (ri->ri_hwbits)
573 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
574 col*ri->ri_xscale);
575
576 height = font->fontheight;
577
578 if (uc == ' ') {
579 while (height--) {
580 rp[0] = rp[1] = rp[2] = rp[3] = stamp[0];
581 if (ri->ri_hwbits) {
582 hrp[0] = stamp[0];
583 hrp[1] = stamp[0];
584 hrp[2] = stamp[0];
585 hrp[3] = stamp[0];
586 }
587 }
588 } else {
589 fr = WSFONT_GLYPH(uc, font);
590 fs = font->stride;
591
592 while (height--) {
593 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
594 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
595 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
596 rp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK);
597 if (ri->ri_hwbits) {
598 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
599 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
600 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
601 hrp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK);
602 }
603
604 fr += fs;
605 DELTA(rp, ri->ri_stride, int32_t *);
606 if (ri->ri_hwbits)
607 DELTA(hrp, ri->ri_stride, int32_t *);
608 }
609 }
610
611 /* Do underline */
612 if ((attr & 1) != 0) {
613 DELTA(rp, -(ri->ri_stride << 1), int32_t *);
614 rp[0] = rp[1] = rp[2] = rp[3] = stamp[15];
615 if (ri->ri_hwbits) {
616 DELTA(hrp, -(ri->ri_stride << 1), int32_t *);
617 hrp[0] = stamp[15];
618 hrp[1] = stamp[15];
619 hrp[2] = stamp[15];
620 hrp[3] = stamp[15];
621 }
622 }
623
624 stamp_mutex--;
625 }
626 #endif /* !RASOPS_SMALL */
627