rasops8.c revision 1.41
1/* 	$NetBSD: rasops8.c,v 1.41 2019/07/25 03:02:44 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.41 2019/07/25 03:02:44 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
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 uint32_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)		(*(uint32_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	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 = FONT_GLYPH(uc, font, ri);
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
194static void
195rasops8_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 = FONT_GLYPH(uc, font, ri);
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 */
300static void
301rasops8_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 */
335static void
336rasops8_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 = FONT_GLYPH(uc, font, ri);
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 */
424static void
425rasops8_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 = FONT_GLYPH(uc, font, ri);
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 */
516static void
517rasops8_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 = FONT_GLYPH(uc, font, ri);
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