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