rasops.c revision 1.3 1 /* $NetBSD: rasops.c,v 1.3 1999/04/13 03:02:40 ad Exp $ */
2
3 /*
4 * Copyright (c) 1999 Andy Doran <ad (at) NetBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: rasops.c,v 1.3 1999/04/13 03:02:40 ad Exp $");
32
33 #include "opt_rasops.h"
34
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/time.h>
39
40 #include <machine/bswap.h>
41
42 #include <dev/wscons/wsdisplayvar.h>
43 #include <dev/wscons/wsconsio.h>
44 #include <dev/wsfont/wsfont.h>
45 #include <dev/rasops/rasops.h>
46
47 /* ANSI colormap (R,G,B). Upper 8 are high-intensity */
48 u_char rasops_cmap[256*3] = {
49 0x00, 0x00, 0x00, /* black */
50 0x7f, 0x00, 0x00, /* red */
51 0x00, 0x7f, 0x00, /* green */
52 0x7f, 0x7f, 0x00, /* brown */
53 0x00, 0x00, 0x7f, /* blue */
54 0x7f, 0x00, 0x7f, /* magenta */
55 0x00, 0x7f, 0x7f, /* cyan */
56 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
57
58 0x7f, 0x7f, 0x7f, /* black */
59 0xff, 0x00, 0x00, /* red */
60 0x00, 0xff, 0x00, /* green */
61 0xff, 0xff, 0x00, /* brown */
62 0x00, 0x00, 0xff, /* blue */
63 0xff, 0x00, 0xff, /* magenta */
64 0x00, 0xff, 0xff, /* cyan */
65 0xff, 0xff, 0xff, /* white */
66 };
67
68 /* True if color is gray */
69 u_char rasops_isgray[16] = {
70 1, 0, 0, 0,
71 0, 0, 0, 1,
72 1, 0, 0, 0,
73 0, 0, 0, 1
74 };
75
76 /* Common functions */
77 static void rasops_copycols __P((void *, int, int, int, int));
78 static void rasops_copyrows __P((void *, int, int, int));
79 static int rasops_mapchar __P((void *, int, u_int *));
80 static void rasops_cursor __P((void *, int, int, int));
81 static int rasops_alloc_cattr __P((void *, int, int, int, long *));
82 static int rasops_alloc_mattr __P((void *, int, int, int, long *));
83
84 /* Per-depth initalization functions */
85 void rasops1_init __P((struct rasops_info *));
86 void rasops8_init __P((struct rasops_info *));
87 void rasops15_init __P((struct rasops_info *));
88 void rasops24_init __P((struct rasops_info *));
89 void rasops32_init __P((struct rasops_info *));
90
91 /*
92 * Initalize a 'rasops_info' descriptor.
93 */
94 int
95 rasops_init(ri, wantrows, wantcols, clear, center)
96 struct rasops_info *ri;
97 int wantrows, wantcols, clear, center;
98 {
99
100 /* Select a font if the caller doesn't care */
101 if (ri->ri_font == NULL) {
102 int cookie;
103
104 wsfont_init();
105
106 /* Want 8 pixel wide, don't care about aestethics */
107 if ((cookie = wsfont_find(NULL, 8, 0, 0)) < 0)
108 cookie = wsfont_find(NULL, 0, 0, 0);
109
110 if (cookie < 0) {
111 printf("rasops_init: font table is empty\n");
112 return (-1);
113 }
114
115 if (wsfont_lock(cookie, &ri->ri_font,
116 WSFONT_LITTLE, WSFONT_LITTLE) < 0) {
117 printf("rasops_init: couldn't lock font\n");
118 return (-1);
119 }
120 }
121
122 /* This should never happen in reality... */
123 #ifdef DEBUG
124 if ((int)ri->ri_bits & 3) {
125 printf("rasops_init: bits not aligned on 32-bit boundary\n");
126 return (-1);
127 }
128
129 if ((int)ri->ri_stride & 3) {
130 printf("rasops_init: stride not aligned on 32-bit boundary\n");
131 return (-1);
132 }
133
134 if (ri->ri_font->fontwidth > 32) {
135 printf("rasops_init: fontwidth > 32\n");
136 return (-1);
137 }
138 #endif
139
140 /* Fix color palette. We need this for the cursor to work. */
141 rasops_cmap[255*3+0] = 0xff;
142 rasops_cmap[255*3+1] = 0xff;
143 rasops_cmap[255*3+2] = 0xff;
144
145 /* Don't care if the caller wants a hideously small console */
146 if (wantrows < 10)
147 wantrows = 5000;
148
149 if (wantcols < 20)
150 wantcols = 5000;
151
152 /* Now constrain what they get */
153 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
154 ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
155
156 if (ri->ri_emuwidth > ri->ri_width)
157 ri->ri_emuwidth = ri->ri_width;
158
159 if (ri->ri_emuheight > ri->ri_height)
160 ri->ri_emuheight = ri->ri_height;
161
162 /* Reduce width until aligned on a 32-bit boundary */
163 while ((ri->ri_emuwidth*ri->ri_depth & 31) != 0)
164 ri->ri_emuwidth--;
165
166 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
167 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
168 ri->ri_emustride = ri->ri_emuwidth * ri->ri_depth >> 3;
169 ri->ri_delta = ri->ri_stride - ri->ri_emustride;
170 ri->ri_ccol = 0;
171 ri->ri_crow = 0;
172 ri->ri_pelbytes = ri->ri_depth >> 3;
173
174 ri->ri_xscale = (ri->ri_font->fontwidth * ri->ri_depth) >> 3;
175 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
176 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
177
178 #ifdef DEBUG
179 if (ri->ri_delta & 3)
180 panic("rasops_init: delta isn't aligned on 32-bit boundary!");
181 #endif
182 /* Clear the entire display */
183 if (clear)
184 bzero(ri->ri_bits, ri->ri_stride * ri->ri_height);
185
186 /* Now centre our window if needs be */
187 ri->ri_origbits = ri->ri_bits;
188
189 if (center) {
190 ri->ri_bits += ((ri->ri_stride - ri->ri_emustride) >> 1) & ~3;
191 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
192 ri->ri_stride;
193 }
194
195 /* Fill in defaults for operations set */
196 ri->ri_ops.mapchar = rasops_mapchar;
197 ri->ri_ops.copyrows = rasops_copyrows;
198 ri->ri_ops.copycols = rasops_copycols;
199 ri->ri_ops.cursor = rasops_cursor;
200
201 if (ri->ri_depth == 1 || ri->ri_forcemono)
202 ri->ri_ops.alloc_attr = rasops_alloc_mattr;
203 else
204 ri->ri_ops.alloc_attr = rasops_alloc_cattr;
205
206 switch (ri->ri_depth) {
207 #ifdef RASOPS1
208 case 1:
209 rasops1_init(ri);
210 break;
211 #endif
212
213 #ifdef RASOPS8
214 case 8:
215 rasops8_init(ri);
216 break;
217 #endif
218
219 #if defined(RASOPS15) || defined(RASOPS16)
220 case 15:
221 case 16:
222 rasops15_init(ri);
223 break;
224 #endif
225
226 #ifdef RASOPS24
227 case 24:
228 rasops24_init(ri);
229 break;
230 #endif
231
232 #ifdef RASOPS24
233 case 32:
234 rasops32_init(ri);
235 break;
236 #endif
237 default:
238 ri->ri_flg = 0;
239 return (-1);
240 }
241
242 ri->ri_flg = RASOPS_INITTED;
243 return (0);
244 }
245
246
247 /*
248 * Map a character.
249 */
250 static int
251 rasops_mapchar(cookie, c, cp)
252 void *cookie;
253 int c;
254 u_int *cp;
255 {
256 struct rasops_info *ri;
257
258 ri = (struct rasops_info *)cookie;
259
260 if (c < ri->ri_font->firstchar) {
261 *cp = ' ';
262 return (0);
263 }
264
265 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) {
266 *cp = ' ';
267 return (0);
268 }
269
270 *cp = c;
271 return (5);
272 }
273
274
275 /*
276 * Allocate a color attribute.
277 */
278 static int
279 rasops_alloc_cattr(cookie, fg, bg, flg, attr)
280 void *cookie;
281 int fg, bg, flg;
282 long *attr;
283 {
284 int swap;
285
286 #ifdef RASOPS_CLIPPING
287 fg &= 7;
288 bg &= 7;
289 flg &= 255;
290 #endif
291 if (flg & WSATTR_BLINK)
292 return (EINVAL);
293
294 if (flg & WSATTR_REVERSE) {
295 swap = fg;
296 fg = bg;
297 bg = swap;
298 }
299
300 if (flg & WSATTR_HILIT)
301 fg += 8;
302
303 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0);
304
305 if (rasops_isgray[fg])
306 flg |= 2;
307
308 if (rasops_isgray[bg])
309 flg |= 4;
310
311 *attr = (bg << 16) | (fg << 24) | flg;
312 return 0;
313 }
314
315
316 /*
317 * Allocate a mono attribute.
318 */
319 static int
320 rasops_alloc_mattr(cookie, fg, bg, flg, attr)
321 void *cookie;
322 int fg, bg, flg;
323 long *attr;
324 {
325 int swap;
326
327 #ifdef RASOPS_CLIPPING
328 flg &= 255;
329 #endif
330 fg = fg ? 1 : 0;
331 bg = bg ? 1 : 0;
332
333 if (flg & WSATTR_BLINK)
334 return (EINVAL);
335
336 if (!(flg & WSATTR_REVERSE) ^ !(flg & WSATTR_HILIT)) {
337 swap = fg;
338 fg = bg;
339 bg = swap;
340 }
341
342 *attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6);
343 return 0;
344 }
345
346
347 /*
348 * Copy rows.
349 */
350 static void
351 rasops_copyrows(cookie, src, dst, num)
352 void *cookie;
353 int src, dst, num;
354 {
355 struct rasops_info *ri;
356 int32_t *sp, *dp, *srp, *drp;
357 int n8, n1, cnt;
358
359 ri = (struct rasops_info *)cookie;
360
361 #ifdef RASOPS_CLIPPING
362 if (dst == src)
363 return;
364
365 if (src < 0) {
366 num += src;
367 src = 0;
368 }
369
370 if ((src + num) > ri->ri_rows)
371 num = ri->ri_rows - src;
372
373 if (dst < 0) {
374 num += dst;
375 dst = 0;
376 }
377
378 if ((dst + num) > ri->ri_rows)
379 num = ri->ri_rows - dst;
380
381 if (num <= 0)
382 return;
383 #endif
384
385 num *= ri->ri_font->fontheight;
386 n8 = ri->ri_emustride >> 5;
387 n1 = (ri->ri_emustride >> 2) & 7;
388
389 if (dst < src) {
390 sp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale);
391 dp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale);
392
393 while (num--) {
394 for (cnt = n8; cnt; cnt--) {
395 dp[0] = sp[0];
396 dp[1] = sp[1];
397 dp[2] = sp[2];
398 dp[3] = sp[3];
399 dp[4] = sp[4];
400 dp[5] = sp[5];
401 dp[6] = sp[6];
402 dp[7] = sp[7];
403 dp += 8;
404 sp += 8;
405 }
406
407 for (cnt = n1; cnt; cnt--)
408 *dp++ = *sp++;
409
410 DELTA(dp, ri->ri_delta, int32_t *);
411 DELTA(sp, ri->ri_delta, int32_t *);
412 }
413 } else {
414 src = ri->ri_font->fontheight * src + num - 1;
415 dst = ri->ri_font->fontheight * dst + num - 1;
416
417 srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride);
418 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride);
419
420 while (num--) {
421 dp = drp;
422 sp = srp;
423 DELTA(srp, -ri->ri_stride, int32_t *);
424 DELTA(drp, -ri->ri_stride, int32_t *);
425
426 for (cnt = n8; cnt; cnt--) {
427 dp[0] = sp[0];
428 dp[1] = sp[1];
429 dp[2] = sp[2];
430 dp[3] = sp[3];
431 dp[4] = sp[4];
432 dp[5] = sp[5];
433 dp[6] = sp[6];
434 dp[7] = sp[7];
435 dp += 8;
436 sp += 8;
437 }
438
439 for (cnt = n1; cnt; cnt--)
440 *dp++ = *sp++;
441 }
442 }
443 }
444
445
446 /*
447 * Copy columns. This is slow, and hard to optimize due to alignment,
448 * and the fact that we have to copy both left->right and right->left.
449 * We simply cop-out here and use bcopy(), since it handles all of
450 * these cases anyway.
451 */
452 static void
453 rasops_copycols(cookie, row, src, dst, num)
454 void *cookie;
455 int row, src, dst, num;
456 {
457 struct rasops_info *ri;
458 u_char *sp, *dp;
459 int height;
460
461 ri = (struct rasops_info *)cookie;
462
463 #ifdef RASOPS_CLIPPING
464 if (dst == src)
465 return;
466
467 /* Catches < 0 case too */
468 if ((unsigned)row >= (unsigned)ri->ri_rows)
469 return;
470
471 if (src < 0) {
472 num += src;
473 src = 0;
474 }
475
476 if ((src + num) > ri->ri_cols)
477 num = ri->ri_cols - src;
478
479 if (dst < 0) {
480 num += dst;
481 dst = 0;
482 }
483
484 if ((dst + num) > ri->ri_cols)
485 num = ri->ri_cols - dst;
486
487 if (num <= 0)
488 return;
489 #endif
490
491 num *= ri->ri_xscale;
492 row *= ri->ri_yscale;
493 height = ri->ri_font->fontheight;
494
495 sp = ri->ri_bits + row + src * ri->ri_xscale;
496 dp = ri->ri_bits + row + dst * ri->ri_xscale;
497
498 while (height--) {
499 bcopy(sp, dp, num);
500 dp += ri->ri_stride;
501 sp += ri->ri_stride;
502 }
503 }
504
505
506 /*
507 * Turn cursor off/on.
508 */
509 static void
510 rasops_cursor(cookie, on, row, col)
511 void *cookie;
512 int on, row, col;
513 {
514 struct rasops_info *ri;
515
516 ri = (struct rasops_info *)cookie;
517
518 /* Turn old cursor off */
519 if (ri->ri_flg & RASOPS_CURSOR)
520 #ifdef RASOPS_CLIPPING
521 if (!(ri->ri_flg & RASOPS_CURSOR_CLIPPED))
522 #endif
523 ri->ri_do_cursor(ri);
524
525 /* Select new cursor */
526 #ifdef RASOPS_CLIPPING
527 ri->ri_flg &= ~RASOPS_CURSOR_CLIPPED;
528
529 if (row < 0 || row >= ri->ri_rows)
530 ri->ri_flg |= RASOPS_CURSOR_CLIPPED;
531 else if (col < 0 || col >= ri->ri_cols)
532 ri->ri_flg |= RASOPS_CURSOR_CLIPPED;
533 #endif
534 ri->ri_crow = row;
535 ri->ri_ccol = col;
536
537 if (on) {
538 ri->ri_flg |= RASOPS_CURSOR;
539 #ifdef RASOPS_CLIPPING
540 if (!(ri->ri_flg & RASOPS_CURSOR_CLIPPED))
541 #endif
542 ri->ri_do_cursor(ri);
543 } else
544 ri->ri_flg &= ~RASOPS_CURSOR;
545 }
546
547
548 #if (RASOPS15 + RASOPS16 + RASOPS32)
549 /*
550 * Make the device colormap
551 */
552 void
553 rasops_init_devcmap(ri)
554 struct rasops_info *ri;
555 {
556 int i, c;
557 u_char *p;
558
559 p = rasops_cmap;
560
561 for (i = 0; i < 16; i++) {
562 if (ri->ri_rnum <= 8)
563 c = (*p++ >> (8 - ri->ri_rnum)) << ri->ri_rpos;
564 else
565 c = (*p++ << (ri->ri_rnum - 8)) << ri->ri_rpos;
566
567 if (ri->ri_gnum <= 8)
568 c = (*p++ >> (8 - ri->ri_gnum)) << ri->ri_gpos;
569 else
570 c = (*p++ << (ri->ri_gnum - 8)) << ri->ri_gpos;
571
572 if (ri->ri_bnum <= 8)
573 c = (*p++ >> (8 - ri->ri_bnum)) << ri->ri_bpos;
574 else
575 c = (*p++ << (ri->ri_bnum - 8)) << ri->ri_bpos;
576
577 if (!ri->ri_swab)
578 ri->ri_devcmap[i] = c;
579 else if (ri->ri_depth <= 32)
580 ri->ri_devcmap[i] = bswap32(c);
581 else /* if (ri->ri_depth <= 16) */
582 ri->ri_devcmap[i] = bswap16(c);
583 }
584 }
585 #endif
586
587
588 /*
589 * Unpack a rasops attribute
590 */
591 void
592 rasops_unpack_attr(attr, fg, bg, underline)
593 long attr;
594 int *fg, *bg, *underline;
595 {
596
597 *fg = ((u_int)attr >> 24) & 15;
598 *bg = ((u_int)attr >> 16) & 15;
599 *underline = (u_int)attr & 1;
600 }
601