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