xref: /netbsd-src/sys/dev/rasops/rasops8.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /* 	$NetBSD: rasops8.c,v 1.17 2004/03/05 08:33:53 petrov 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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: rasops8.c,v 1.17 2004/03/05 08:33:53 petrov Exp $");
41 
42 #include "opt_rasops.h"
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/time.h>
47 #include <sys/bswap.h>
48 
49 #include <dev/wscons/wsdisplayvar.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/rasops/rasops.h>
52 
53 static void 	rasops8_putchar __P((void *, int, int, u_int, long attr));
54 #ifndef RASOPS_SMALL
55 static void 	rasops8_putchar8 __P((void *, int, int, u_int, long attr));
56 static void 	rasops8_putchar12 __P((void *, int, int, u_int, long attr));
57 static void 	rasops8_putchar16 __P((void *, int, int, u_int, long attr));
58 static void	rasops8_makestamp __P((struct rasops_info *ri, long));
59 
60 /*
61  * 4x1 stamp for optimized character blitting
62  */
63 static int32_t	stamp[16];
64 static long	stamp_attr;
65 static int	stamp_mutex;	/* XXX see note in README */
66 #endif
67 
68 /*
69  * XXX this confuses the hell out of gcc2 (not egcs) which always insists
70  * that the shift count is negative.
71  *
72  * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK
73  * destination = STAMP_READ(offset)
74  */
75 #define STAMP_SHIFT(fb,n)	((n*4-2) >= 0 ? (fb)>>(n*4-2):(fb)<<-(n*4-2))
76 #define STAMP_MASK		(0xf << 2)
77 #define STAMP_READ(o)		(*(int32_t *)((caddr_t)stamp + (o)))
78 
79 /*
80  * Initialize a 'rasops_info' descriptor for this depth.
81  */
82 void
83 rasops8_init(ri)
84 	struct rasops_info *ri;
85 {
86 
87 	switch (ri->ri_font->fontwidth) {
88 #ifndef RASOPS_SMALL
89 	case 8:
90 		ri->ri_ops.putchar = rasops8_putchar8;
91 		break;
92 	case 12:
93 		ri->ri_ops.putchar = rasops8_putchar12;
94 		break;
95 	case 16:
96 		ri->ri_ops.putchar = rasops8_putchar16;
97 		break;
98 #endif /* !RASOPS_SMALL */
99 	default:
100 		ri->ri_ops.putchar = rasops8_putchar;
101 		break;
102 	}
103 }
104 
105 /*
106  * Put a single character.
107  */
108 static void
109 rasops8_putchar(cookie, row, col, uc, attr)
110 	void *cookie;
111 	int row, col;
112 	u_int uc;
113 	long attr;
114 {
115 	int width, height, cnt, fs, fb;
116 	u_char *dp, *rp, *fr, clr[2];
117 	struct rasops_info *ri;
118 
119 	ri = (struct rasops_info *)cookie;
120 
121 	if (!CHAR_IN_FONT(uc, ri->ri_font))
122 		return;
123 
124 #ifdef RASOPS_CLIPPING
125 	/* Catches 'row < 0' case too */
126 	if ((unsigned)row >= (unsigned)ri->ri_rows)
127 		return;
128 
129 	if ((unsigned)col >= (unsigned)ri->ri_cols)
130 		return;
131 #endif
132 	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
133 
134 	height = ri->ri_font->fontheight;
135 	width = ri->ri_font->fontwidth;
136 	clr[0] = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf];
137 	clr[1] = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf];
138 
139 	if (uc == ' ') {
140 		u_char c = clr[0];
141 
142 		while (height--) {
143 			dp = rp;
144 			rp += ri->ri_stride;
145 
146 			for (cnt = width; cnt; cnt--)
147 				*dp++ = c;
148 		}
149 	} else {
150 		uc -= ri->ri_font->firstchar;
151 		fr = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
152 		fs = ri->ri_font->stride;
153 
154 		while (height--) {
155 			dp = rp;
156 			fb = fr[3] | (fr[2] << 8) | (fr[1] << 16) | (fr[0] << 24);
157 			fr += fs;
158 			rp += ri->ri_stride;
159 
160 			for (cnt = width; cnt; cnt--) {
161 				*dp++ = clr[(fb >> 31) & 1];
162 				fb <<= 1;
163 			}
164 		}
165 	}
166 
167 	/* Do underline */
168 	if ((attr & 1) != 0) {
169 		u_char c = clr[1];
170 
171 		rp -= (ri->ri_stride << 1);
172 
173 		while (width--)
174 			*rp++ = c;
175 	}
176 }
177 
178 #ifndef RASOPS_SMALL
179 /*
180  * Recompute the 4x1 blitting stamp.
181  */
182 static void
183 rasops8_makestamp(ri, attr)
184 	struct rasops_info *ri;
185 	long attr;
186 {
187 	int32_t fg, bg;
188 	int i;
189 
190 	fg = ri->ri_devcmap[(attr >> 24) & 0xf] & 0xff;
191 	bg = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xff;
192 	stamp_attr = attr;
193 
194 	for (i = 0; i < 16; i++) {
195 #if BYTE_ORDER == BIG_ENDIAN
196 #define NEED_LITTLE_ENDIAN_STAMP RI_BSWAP
197 #else
198 #define NEED_LITTLE_ENDIAN_STAMP 0
199 #endif
200 		if ((ri->ri_flg & RI_BSWAP) == NEED_LITTLE_ENDIAN_STAMP) {
201 			/* little endian */
202 			stamp[i] = (i & 8 ? fg : bg);
203 			stamp[i] |= ((i & 4 ? fg : bg) << 8);
204 			stamp[i] |= ((i & 2 ? fg : bg) << 16);
205 			stamp[i] |= ((i & 1 ? fg : bg) << 24);
206 		} else {
207 			/* big endian */
208 			stamp[i] = (i & 1 ? fg : bg);
209 			stamp[i] |= ((i & 2 ? fg : bg) << 8);
210 			stamp[i] |= ((i & 4 ? fg : bg) << 16);
211 			stamp[i] |= ((i & 8 ? fg : bg) << 24);
212 		}
213 	}
214 }
215 
216 /*
217  * Put a single character. This is for 8-pixel wide fonts.
218  */
219 static void
220 rasops8_putchar8(cookie, row, col, uc, attr)
221 	void *cookie;
222 	int row, col;
223 	u_int uc;
224 	long attr;
225 {
226 	struct rasops_info *ri;
227 	int height, fs;
228 	int32_t *rp;
229 	u_char *fr;
230 
231 	/* Can't risk remaking the stamp if it's already in use */
232 	if (stamp_mutex++) {
233 		stamp_mutex--;
234 		rasops8_putchar(cookie, row, col, uc, attr);
235 		return;
236 	}
237 
238 	ri = (struct rasops_info *)cookie;
239 
240 	if (!CHAR_IN_FONT(uc, ri->ri_font))
241 		return;
242 
243 #ifdef RASOPS_CLIPPING
244 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
245 		stamp_mutex--;
246 		return;
247 	}
248 
249 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
250 		stamp_mutex--;
251 		return;
252 	}
253 #endif
254 
255 	/* Recompute stamp? */
256 	if (attr != stamp_attr)
257 		rasops8_makestamp(ri, attr);
258 
259 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
260 	height = ri->ri_font->fontheight;
261 
262 	if (uc == ' ') {
263 		while (height--) {
264 			rp[0] = rp[1] = stamp[0];
265 			DELTA(rp, ri->ri_stride, int32_t *);
266 		}
267 	} else {
268 		uc -= ri->ri_font->firstchar;
269 		fr = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
270 		fs = ri->ri_font->stride;
271 
272 		while (height--) {
273 			rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
274 			rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
275 
276 			fr += fs;
277 			DELTA(rp, ri->ri_stride, int32_t *);
278 		}
279 	}
280 
281 	/* Do underline */
282 	if ((attr & 1) != 0) {
283 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
284 		rp[0] = rp[1] = stamp[15];
285 	}
286 
287 	stamp_mutex--;
288 }
289 
290 /*
291  * Put a single character. This is for 12-pixel wide fonts.
292  */
293 static void
294 rasops8_putchar12(cookie, row, col, uc, attr)
295 	void *cookie;
296 	int row, col;
297 	u_int uc;
298 	long attr;
299 {
300 	struct rasops_info *ri;
301 	int height, fs;
302 	int32_t *rp;
303 	u_char *fr;
304 
305 	/* Can't risk remaking the stamp if it's already in use */
306 	if (stamp_mutex++) {
307 		stamp_mutex--;
308 		rasops8_putchar(cookie, row, col, uc, attr);
309 		return;
310 	}
311 
312 	ri = (struct rasops_info *)cookie;
313 
314 	if (!CHAR_IN_FONT(uc, ri->ri_font))
315 	    return;
316 
317 #ifdef RASOPS_CLIPPING
318 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
319 		stamp_mutex--;
320 		return;
321 	}
322 
323 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
324 		stamp_mutex--;
325 		return;
326 	}
327 #endif
328 
329 	/* Recompute stamp? */
330 	if (attr != stamp_attr)
331 		rasops8_makestamp(ri, attr);
332 
333 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
334 	height = ri->ri_font->fontheight;
335 
336 	if (uc == ' ') {
337 		while (height--) {
338 			int32_t c = stamp[0];
339 
340 			rp[0] = rp[1] = rp[2] = c;
341 			DELTA(rp, ri->ri_stride, int32_t *);
342 		}
343 	} else {
344 		uc -= ri->ri_font->firstchar;
345 		fr = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
346 		fs = ri->ri_font->stride;
347 
348 		while (height--) {
349 			rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
350 			rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
351 			rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
352 
353 			fr += fs;
354 			DELTA(rp, ri->ri_stride, int32_t *);
355 		}
356 	}
357 
358 	/* Do underline */
359 	if ((attr & 1) != 0) {
360 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
361 		rp[0] = rp[1] = rp[2] = stamp[15];
362 	}
363 
364 	stamp_mutex--;
365 }
366 
367 /*
368  * Put a single character. This is for 16-pixel wide fonts.
369  */
370 static void
371 rasops8_putchar16(cookie, row, col, uc, attr)
372 	void *cookie;
373 	int row, col;
374 	u_int uc;
375 	long attr;
376 {
377 	struct rasops_info *ri;
378 	int height, fs;
379 	int32_t *rp;
380 	u_char *fr;
381 
382 	/* Can't risk remaking the stamp if it's already in use */
383 	if (stamp_mutex++) {
384 		stamp_mutex--;
385 		rasops8_putchar(cookie, row, col, uc, attr);
386 		return;
387 	}
388 
389 	ri = (struct rasops_info *)cookie;
390 
391 	if (!CHAR_IN_FONT(uc, ri->ri_font))
392 		return;
393 
394 #ifdef RASOPS_CLIPPING
395 	if ((unsigned)row >= (unsigned)ri->ri_rows) {
396 		stamp_mutex--;
397 		return;
398 	}
399 
400 	if ((unsigned)col >= (unsigned)ri->ri_cols) {
401 		stamp_mutex--;
402 		return;
403 	}
404 #endif
405 
406 	/* Recompute stamp? */
407 	if (attr != stamp_attr)
408 		rasops8_makestamp(ri, attr);
409 
410 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
411 	height = ri->ri_font->fontheight;
412 
413 	if (uc == ' ') {
414 		while (height--)
415 			rp[0] = rp[1] = rp[2] = rp[3] = stamp[0];
416 	} else {
417 		uc -= ri->ri_font->firstchar;
418 		fr = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
419 		fs = ri->ri_font->stride;
420 
421 		while (height--) {
422 			rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK);
423 			rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK);
424 			rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK);
425 			rp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK);
426 
427 			fr += fs;
428 			DELTA(rp, ri->ri_stride, int32_t *);
429 		}
430 	}
431 
432 	/* Do underline */
433 	if ((attr & 1) != 0) {
434 		DELTA(rp, -(ri->ri_stride << 1), int32_t *);
435 		rp[0] = rp[1] = rp[2] = rp[3] = stamp[15];
436 	}
437 
438 	stamp_mutex--;
439 }
440 #endif /* !RASOPS_SMALL */
441