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