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