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