rasops.c revision 1.14
1/*	 $NetBSD: rasops.c,v 1.14 1999/08/25 08:45:25 ad 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 Andy 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: rasops.c,v 1.14 1999/08/25 08:45:25 ad Exp $");
41
42#include "rasops_glue.h"
43
44#include <sys/types.h>
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/time.h>
48
49#include <machine/bswap.h>
50#include <machine/endian.h>
51
52#include <dev/wscons/wsdisplayvar.h>
53#include <dev/wscons/wsconsio.h>
54#include <dev/wsfont/wsfont.h>
55#include <dev/rasops/rasops.h>
56
57#ifndef _KERNEL
58#include <errno.h>
59#endif
60
61/* ANSI colormap (R,G,B). Upper 8 are high-intensity */
62u_char rasops_cmap[256*3] = {
63	0x00, 0x00, 0x00, /* black */
64	0x7f, 0x00, 0x00, /* red */
65	0x00, 0x7f, 0x00, /* green */
66	0x7f, 0x7f, 0x00, /* brown */
67	0x00, 0x00, 0x7f, /* blue */
68	0x7f, 0x00, 0x7f, /* magenta */
69	0x00, 0x7f, 0x7f, /* cyan */
70	0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
71
72	0x7f, 0x7f, 0x7f, /* black */
73	0xff, 0x00, 0x00, /* red */
74	0x00, 0xff, 0x00, /* green */
75	0xff, 0xff, 0x00, /* brown */
76	0x00, 0x00, 0xff, /* blue */
77	0xff, 0x00, 0xff, /* magenta */
78	0x00, 0xff, 0xff, /* cyan */
79	0xff, 0xff, 0xff, /* white */
80};
81
82/* True if color is gray */
83u_char rasops_isgray[16] = {
84	1, 0, 0, 0,
85	0, 0, 0, 1,
86	1, 0, 0, 0,
87	0, 0, 0, 1
88};
89
90/* Generic functions */
91static void	rasops_copyrows __P((void *, int, int, int));
92static int	rasops_mapchar __P((void *, int, u_int *));
93static void	rasops_cursor __P((void *, int, int, int));
94static int	rasops_alloc_cattr __P((void *, int, int, int, long *));
95static int	rasops_alloc_mattr __P((void *, int, int, int, long *));
96static void	rasops_do_cursor __P((struct rasops_info *));
97static void	rasops_init_devcmap __P((struct rasops_info *));
98
99/* Per-depth initalization functions */
100void	rasops1_init __P((struct rasops_info *));
101void	rasops2_init __P((struct rasops_info *));
102void	rasops8_init __P((struct rasops_info *));
103void	rasops15_init __P((struct rasops_info *));
104void	rasops24_init __P((struct rasops_info *));
105void	rasops32_init __P((struct rasops_info *));
106
107/*
108 * Initalize a 'rasops_info' descriptor.
109 */
110int
111rasops_init(ri, wantrows, wantcols)
112	struct rasops_info *ri;
113	int wantrows, wantcols;
114{
115#ifdef _KERNEL
116	/* Select a font if the caller doesn't care */
117	if (ri->ri_font == NULL) {
118		int cookie;
119
120		wsfont_init();
121
122		/* Want 8 pixel wide, don't care about aestethics */
123		if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
124			cookie = wsfont_find(NULL, 0, 0, 0);
125
126		if (cookie <= 0) {
127			printf("rasops_init: font table is empty\n");
128			return (-1);
129		}
130
131		if (wsfont_lock(cookie, &ri->ri_font,
132		    WSFONT_L2R, WSFONT_L2R) <= 0) {
133			printf("rasops_init: couldn't lock font\n");
134			return (-1);
135		}
136
137		ri->ri_wsfcookie = cookie;
138	}
139#endif
140
141	/* This should never happen in reality... */
142#ifdef DEBUG
143	if ((int)ri->ri_bits & 3) {
144		printf("rasops_init: bits not aligned on 32-bit boundary\n");
145		return (-1);
146	}
147
148	if ((int)ri->ri_stride & 3) {
149		printf("rasops_init: stride not aligned on 32-bit boundary\n");
150		return (-1);
151	}
152#endif
153
154	/* Fix colormap. We need this for the cursor to work. */
155	rasops_cmap[255*3+0] = 0xff;
156	rasops_cmap[255*3+1] = 0xff;
157	rasops_cmap[255*3+2] = 0xff;
158
159	if (rasops_reconfig(ri, wantrows, wantcols))
160		return (-1);
161
162	rasops_init_devcmap(ri);
163	return (0);
164}
165
166
167/*
168 * Reconfigure (because parameters have changed in some way).
169 */
170int
171rasops_reconfig(ri, wantrows, wantcols)
172	struct rasops_info *ri;
173	int wantrows, wantcols;
174{
175	int bpp;
176	int s;
177
178	s = splhigh();
179
180	if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4)
181		panic("rasops_init: fontwidth assumptions botched!\n");
182
183	/* Need this to frob the setup below */
184	bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth);
185
186	if ((ri->ri_flg & RI_CFGDONE) != 0)
187		ri->ri_bits = ri->ri_origbits;
188
189	/* Don't care if the caller wants a hideously small console */
190	if (wantrows < 10)
191		wantrows = 10;
192
193	if (wantcols < 20)
194		wantcols = 20;
195
196	/* Now constrain what they get */
197	ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
198	ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
199
200	if (ri->ri_emuwidth > ri->ri_width)
201		ri->ri_emuwidth = ri->ri_width;
202
203	if (ri->ri_emuheight > ri->ri_height)
204		ri->ri_emuheight = ri->ri_height;
205
206	/* Reduce width until aligned on a 32-bit boundary */
207	while ((ri->ri_emuwidth*bpp & 31) != 0)
208		ri->ri_emuwidth--;
209
210	ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
211	ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
212	ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
213	ri->ri_delta = ri->ri_stride - ri->ri_emustride;
214	ri->ri_ccol = 0;
215	ri->ri_crow = 0;
216	ri->ri_pelbytes = bpp >> 3;
217
218	ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
219	ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
220	ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
221
222#ifdef DEBUG
223	if (ri->ri_delta & 3)
224		panic("rasops_init: ri_delta not aligned on 32-bit boundary");
225#endif
226	/* Clear the entire display */
227	if ((ri->ri_flg & RI_CLEAR) != 0)
228		memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
229
230	/* Now centre our window if needs be */
231	ri->ri_origbits = ri->ri_bits;
232
233	if ((ri->ri_flg & RI_CENTER) != 0) {
234		ri->ri_bits += ((ri->ri_stride - ri->ri_emustride) >> 1) & ~3;
235		ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
236		    ri->ri_stride;
237
238		ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
239		   / ri->ri_stride;
240		ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
241		   % ri->ri_stride) * bpp) >> 3;
242	} else
243		ri->ri_xorigin = ri->ri_yorigin = 0;
244
245	/*
246	 * Fill in defaults for operations set.  XXX this nukes private
247	 * routines used by accelerated fb drivers.
248	 */
249	ri->ri_ops.mapchar = rasops_mapchar;
250	ri->ri_ops.copyrows = rasops_copyrows;
251	ri->ri_ops.copycols = rasops_copycols;
252	ri->ri_ops.erasecols = rasops_erasecols;
253	ri->ri_ops.eraserows = rasops_eraserows;
254	ri->ri_ops.cursor = rasops_cursor;
255	ri->ri_do_cursor = rasops_do_cursor;
256
257	if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) {
258		ri->ri_ops.alloc_attr = rasops_alloc_mattr;
259		ri->ri_caps = WSATTR_UNDERLINE | WSATTR_REVERSE;
260	} else {
261		ri->ri_ops.alloc_attr = rasops_alloc_cattr;
262		ri->ri_caps = WSATTR_UNDERLINE | WSATTR_HILIT |
263		    WSATTR_WSCOLORS | WSATTR_REVERSE;
264	}
265
266	switch (ri->ri_depth) {
267#if NRASOPS1
268	case 1:
269		rasops1_init(ri);
270		break;
271#endif
272
273#if NRASOPS2
274	case 2:
275		rasops2_init(ri);
276		break;
277#endif
278
279#if NRASOPS8
280	case 8:
281		rasops8_init(ri);
282		break;
283#endif
284
285#if NRASOPS15 || NRASOPS16
286	case 15:
287	case 16:
288		rasops15_init(ri);
289		break;
290#endif
291
292#if NRASOPS24
293	case 24:
294		rasops24_init(ri);
295		break;
296#endif
297
298#if NRASOPS32
299	case 32:
300		rasops32_init(ri);
301		break;
302#endif
303	default:
304		ri->ri_flg &= ~RI_CFGDONE;
305		splx(s);
306		return (-1);
307	}
308
309	ri->ri_flg |= RI_CFGDONE;
310	splx(s);
311	return (0);
312}
313
314
315/*
316 * Map a character.
317 */
318static int
319rasops_mapchar(cookie, c, cp)
320	void *cookie;
321	int c;
322	u_int *cp;
323{
324	struct rasops_info *ri;
325
326	ri = (struct rasops_info *)cookie;
327
328#ifdef DIAGNOSTIC
329	if (ri->ri_font == NULL)
330		panic("rasops_mapchar: no font selected\n");
331#endif
332
333	if (c < ri->ri_font->firstchar) {
334		*cp = ' ';
335		return (0);
336	}
337
338	if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) {
339		*cp = ' ';
340		return (0);
341	}
342
343	*cp = c;
344	return (5);
345}
346
347
348/*
349 * Allocate a color attribute.
350 */
351static int
352rasops_alloc_cattr(cookie, fg, bg, flg, attr)
353	void *cookie;
354	int fg, bg, flg;
355	long *attr;
356{
357	int swap;
358
359#ifdef RASOPS_CLIPPING
360	fg &= 7;
361	bg &= 7;
362	flg &= 255;
363#endif
364	if (flg & WSATTR_BLINK)
365		return (EINVAL);
366
367	if (flg & WSATTR_REVERSE) {
368		swap = fg;
369		fg = bg;
370		bg = swap;
371	}
372
373	if (flg & WSATTR_HILIT)
374		fg += 8;
375
376	flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0);
377
378	if (rasops_isgray[fg])
379		flg |= 2;
380
381	if (rasops_isgray[bg])
382		flg |= 4;
383
384	*attr = (bg << 16) | (fg << 24) | flg;
385	return 0;
386}
387
388
389/*
390 * Allocate a mono attribute.
391 */
392static int
393rasops_alloc_mattr(cookie, fg, bg, flg, attr)
394	void *cookie;
395	int fg, bg, flg;
396	long *attr;
397{
398	int swap;
399
400#ifdef RASOPS_CLIPPING
401	flg &= 255;
402#endif
403	fg = (fg ? 1 : 0);
404	bg = (bg ? 1 : 0);
405
406	if (flg & WSATTR_BLINK)
407		return (EINVAL);
408
409	if ((flg & WSATTR_REVERSE) != 0) {
410		swap = fg;
411		fg = bg;
412		bg = swap;
413	}
414
415	*attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6);
416	return 0;
417}
418
419
420/*
421 * Copy rows.
422 */
423static void
424rasops_copyrows(cookie, src, dst, num)
425	void *cookie;
426	int src, dst, num;
427{
428	struct rasops_info *ri;
429	int32_t *sp, *dp, *srp, *drp;
430	int n8, n1, cnt;
431
432	ri = (struct rasops_info *)cookie;
433
434#ifdef RASOPS_CLIPPING
435	if (dst == src)
436		return;
437
438	if (src < 0) {
439		num += src;
440		src = 0;
441	}
442
443	if ((src + num) > ri->ri_rows)
444		num = ri->ri_rows - src;
445
446	if (dst < 0) {
447		num += dst;
448		dst = 0;
449	}
450
451	if ((dst + num) > ri->ri_rows)
452		num = ri->ri_rows - dst;
453
454	if (num <= 0)
455		return;
456#endif
457
458	num *= ri->ri_font->fontheight;
459	n8 = ri->ri_emustride >> 5;
460	n1 = (ri->ri_emustride >> 2) & 7;
461
462	if (dst < src) {
463		sp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale);
464		dp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale);
465
466		while (num--) {
467			for (cnt = n8; cnt; cnt--) {
468				dp[0] = sp[0];
469				dp[1] = sp[1];
470				dp[2] = sp[2];
471				dp[3] = sp[3];
472				dp[4] = sp[4];
473				dp[5] = sp[5];
474				dp[6] = sp[6];
475				dp[7] = sp[7];
476				dp += 8;
477				sp += 8;
478			}
479
480			for (cnt = n1; cnt; cnt--)
481				*dp++ = *sp++;
482
483			DELTA(dp, ri->ri_delta, int32_t *);
484			DELTA(sp, ri->ri_delta, int32_t *);
485		}
486	} else {
487		src = ri->ri_font->fontheight * src + num - 1;
488		dst = ri->ri_font->fontheight * dst + num - 1;
489
490		srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride);
491		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride);
492
493		while (num--) {
494			dp = drp;
495			sp = srp;
496			DELTA(srp, -ri->ri_stride, int32_t *);
497			DELTA(drp, -ri->ri_stride, int32_t *);
498
499			for (cnt = n8; cnt; cnt--) {
500				dp[0] = sp[0];
501				dp[1] = sp[1];
502				dp[2] = sp[2];
503				dp[3] = sp[3];
504				dp[4] = sp[4];
505				dp[5] = sp[5];
506				dp[6] = sp[6];
507				dp[7] = sp[7];
508				dp += 8;
509				sp += 8;
510			}
511
512			for (cnt = n1; cnt; cnt--)
513				*dp++ = *sp++;
514		}
515	}
516}
517
518
519/*
520 * Copy columns. This is slow, and hard to optimize due to alignment,
521 * and the fact that we have to copy both left->right and right->left.
522 * We simply cop-out here and use bcopy(), since it handles all of
523 * these cases anyway.
524 */
525void
526rasops_copycols(cookie, row, src, dst, num)
527	void *cookie;
528	int row, src, dst, num;
529{
530	struct rasops_info *ri;
531	u_char *sp, *dp;
532	int height;
533
534	ri = (struct rasops_info *)cookie;
535
536#ifdef RASOPS_CLIPPING
537	if (dst == src)
538		return;
539
540	/* Catches < 0 case too */
541	if ((unsigned)row >= (unsigned)ri->ri_rows)
542		return;
543
544	if (src < 0) {
545		num += src;
546		src = 0;
547	}
548
549	if ((src + num) > ri->ri_cols)
550		num = ri->ri_cols - src;
551
552	if (dst < 0) {
553		num += dst;
554		dst = 0;
555	}
556
557	if ((dst + num) > ri->ri_cols)
558		num = ri->ri_cols - dst;
559
560	if (num <= 0)
561		return;
562#endif
563
564	num *= ri->ri_xscale;
565	row *= ri->ri_yscale;
566	height = ri->ri_font->fontheight;
567
568	sp = ri->ri_bits + row + src * ri->ri_xscale;
569	dp = ri->ri_bits + row + dst * ri->ri_xscale;
570
571	while (height--) {
572		bcopy(sp, dp, num);
573		dp += ri->ri_stride;
574		sp += ri->ri_stride;
575	}
576}
577
578
579/*
580 * Turn cursor off/on.
581 */
582static void
583rasops_cursor(cookie, on, row, col)
584	void *cookie;
585	int on, row, col;
586{
587	struct rasops_info *ri;
588
589	ri = (struct rasops_info *)cookie;
590
591	/* Turn old cursor off */
592	if ((ri->ri_flg & RI_CURSOR) != 0)
593#ifdef RASOPS_CLIPPING
594		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
595#endif
596			ri->ri_do_cursor(ri);
597
598	/* Select new cursor */
599#ifdef RASOPS_CLIPPING
600	ri->ri_flg &= ~RI_CURSORCLIP;
601
602	if (row < 0 || row >= ri->ri_rows)
603		ri->ri_flg |= RI_CURSORCLIP;
604	else if (col < 0 || col >= ri->ri_cols)
605		ri->ri_flg |= RI_CURSORCLIP;
606#endif
607	ri->ri_crow = row;
608	ri->ri_ccol = col;
609
610	if (on) {
611		ri->ri_flg |= RI_CURSOR;
612#ifdef RASOPS_CLIPPING
613		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
614#endif
615			ri->ri_do_cursor(ri);
616	} else
617		ri->ri_flg &= ~RI_CURSOR;
618}
619
620
621/*
622 * Make the device colormap
623 */
624static void
625rasops_init_devcmap(ri)
626	struct rasops_info *ri;
627{
628	u_char *p;
629	int i, c;
630
631	switch (ri->ri_depth) {
632	case 1:
633		ri->ri_devcmap[0] = 0;
634		for (i = 1; i < 16; i++)
635			ri->ri_devcmap[i] = -1;
636		return;
637
638	case 2:
639		for (i = 1; i < 15; i++)
640			ri->ri_devcmap[i] = 0xaaaaaaaa;
641
642		ri->ri_devcmap[0] = 0;
643		ri->ri_devcmap[8] = 0x55555555;
644		ri->ri_devcmap[15] = -1;
645		return;
646
647	case 8:
648		for (i = 0; i < 16; i++)
649			ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24);
650		return;
651	}
652
653	p = rasops_cmap;
654
655	for (i = 0; i < 16; i++, p++) {
656		if (ri->ri_rnum <= 8)
657			c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
658		else
659			c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
660
661		if (ri->ri_gnum <= 8)
662			c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
663		else
664			c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
665
666		if (ri->ri_bnum <= 8)
667			c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
668		else
669			c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
670
671		/* Fill the word for generic routines, which want this */
672		if (ri->ri_depth == 24)
673			c = c | ((c & 0xff) << 24);
674		else if (ri->ri_depth <= 16)
675			c = c | (c << 16);
676
677		/* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */
678		if ((ri->ri_flg & RI_BSWAP) == 0)
679			ri->ri_devcmap[i] = c;
680		else if (ri->ri_depth == 32)
681			ri->ri_devcmap[i] = bswap32(c);
682		else if (ri->ri_depth == 16 || ri->ri_depth == 15)
683			ri->ri_devcmap[i] = bswap16(c);
684		else
685			ri->ri_devcmap[i] = c;
686	}
687}
688
689
690/*
691 * Unpack a rasops attribute
692 */
693void
694rasops_unpack_attr(attr, fg, bg, underline)
695	long attr;
696	int *fg, *bg, *underline;
697{
698
699	*fg = ((u_int)attr >> 24) & 15;
700	*bg = ((u_int)attr >> 16) & 15;
701	*underline = (u_int)attr & 1;
702}
703
704
705/*
706 * Erase rows. This isn't static, since 24-bpp uses it in special cases.
707 */
708void
709rasops_eraserows(cookie, row, num, attr)
710	void *cookie;
711	int row, num;
712	long attr;
713{
714	struct rasops_info *ri;
715	int np, nw, cnt, delta;
716	int32_t *dp, clr;
717
718	ri = (struct rasops_info *)cookie;
719
720#ifdef RASOPS_CLIPPING
721	if (row < 0) {
722		num += row;
723		row = 0;
724	}
725
726	if ((row + num) > ri->ri_rows)
727		num = ri->ri_rows - row;
728
729	if (num <= 0)
730		return;
731#endif
732
733	clr = ri->ri_devcmap[(attr >> 16) & 15];
734
735	/*
736	 * XXX the wsdisplay_emulops interface seems a little deficient in
737	 * that there is no way to clear the *entire* screen. We provide a
738	 * workaround here: if the entire console area is being cleared, and
739	 * the RI_FULLCLEAR flag is set, clear the entire display.
740	 */
741	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
742		np = ri->ri_stride >> 5;
743		nw = (ri->ri_stride >> 2) & 7;
744		num = ri->ri_height;
745		dp = (int32_t *)ri->ri_origbits;
746		delta = 0;
747	} else {
748		np = ri->ri_emustride >> 5;
749		nw = (ri->ri_emustride >> 2) & 7;
750		num *= ri->ri_font->fontheight;
751		dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
752		delta = ri->ri_delta;
753	}
754
755	while (num--) {
756		for (cnt = np; cnt; cnt--) {
757			dp[0] = clr;
758			dp[1] = clr;
759			dp[2] = clr;
760			dp[3] = clr;
761			dp[4] = clr;
762			dp[5] = clr;
763			dp[6] = clr;
764			dp[7] = clr;
765			dp += 8;
766		}
767
768		for (cnt = nw; cnt; cnt--) {
769			*(int32_t *)dp = clr;
770			DELTA(dp, 4, int32_t *);
771		}
772
773		DELTA(dp, delta, int32_t *);
774	}
775}
776
777
778/*
779 * Actually turn the cursor on or off. This does the dirty work for
780 * rasops_cursor().
781 */
782static void
783rasops_do_cursor(ri)
784	struct rasops_info *ri;
785{
786	int full1, height, cnt, slop1, slop2, row, col, mask;
787	u_char *dp, *rp;
788
789	row = ri->ri_crow;
790	col = ri->ri_ccol;
791
792	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
793	height = ri->ri_font->fontheight;
794	mask = ri->ri_devcmap[15];
795
796	slop1 = (4 - ((int)rp & 3)) & 3;
797
798	if (slop1 > ri->ri_xscale)
799		slop1 = ri->ri_xscale;
800
801	slop2 = (ri->ri_xscale - slop1) & 3;
802	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
803
804	if ((slop1 | slop2) == 0) {
805		/* A common case */
806		while (height--) {
807			dp = rp;
808			rp += ri->ri_stride;
809
810			for (cnt = full1; cnt; cnt--) {
811				*(int32_t *)dp ^= mask;
812				dp += 4;
813			}
814		}
815	} else {
816		/* XXX this is stupid.. use masks instead */
817		while (height--) {
818			dp = rp;
819			rp += ri->ri_stride;
820
821			if (slop1 & 1)
822				*dp++ ^= mask;
823
824			if (slop1 & 2) {
825				*(int16_t *)dp ^= mask;
826				dp += 2;
827			}
828
829			for (cnt = full1; cnt; cnt--) {
830				*(int32_t *)dp ^= mask;
831				dp += 4;
832			}
833
834			if (slop2 & 1)
835				*dp++ ^= mask;
836
837			if (slop2 & 2)
838				*(int16_t *)dp ^= mask;
839		}
840	}
841}
842
843
844/*
845 * Erase columns.
846 */
847void
848rasops_erasecols(cookie, row, col, num, attr)
849	void *cookie;
850	int row, col, num;
851	long attr;
852{
853	int n8, height, cnt, slop1, slop2, clr;
854	struct rasops_info *ri;
855	int32_t *rp, *dp;
856
857	ri = (struct rasops_info *)cookie;
858
859#ifdef RASOPS_CLIPPING
860	if ((unsigned)row >= (unsigned)ri->ri_rows)
861		return;
862
863	if (col < 0) {
864		num += col;
865		col = 0;
866	}
867
868	if ((col + num) > ri->ri_cols)
869		num = ri->ri_cols - col;
870
871	if (num <= 0)
872		return;
873#endif
874
875	num = num * ri->ri_xscale;
876	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
877	height = ri->ri_font->fontheight;
878	clr = ri->ri_devcmap[(attr >> 16) & 15];
879
880	/* Don't bother using the full loop for <= 32 pels */
881	if (num <= 32) {
882		if (((num | ri->ri_xscale) & 3) == 0) {
883			/* Word aligned blt */
884			num >>= 2;
885
886			while (height--) {
887				dp = rp;
888				DELTA(rp, ri->ri_stride, int32_t *);
889
890				for (cnt = num; cnt; cnt--)
891					*dp++ = clr;
892			}
893		} else if (((num | ri->ri_xscale) & 1) == 0) {
894			/*
895			 * Halfword aligned blt. This is needed so the
896			 * 15/16 bit ops can use this function.
897			 */
898			num >>= 1;
899
900			while (height--) {
901				dp = rp;
902				DELTA(rp, ri->ri_stride, int32_t *);
903
904				for (cnt = num; cnt; cnt--) {
905					*(int16_t *)dp = clr;
906					DELTA(dp, 2, int32_t *);
907				}
908			}
909		} else {
910			while (height--) {
911				dp = rp;
912				DELTA(rp, ri->ri_stride, int32_t *);
913
914				for (cnt = num; cnt; cnt--) {
915					*(u_char *)dp = clr;
916					DELTA(dp, 1, int32_t *);
917				}
918			}
919		}
920
921		return;
922	}
923
924	slop1 = (4 - ((int)rp & 3)) & 3;
925	slop2 = (num - slop1) & 3;
926	num -= slop1 + slop2;
927	n8 = num >> 5;
928	num = (num >> 2) & 7;
929
930	while (height--) {
931		dp = rp;
932		DELTA(rp, ri->ri_stride, int32_t *);
933
934		/* Align span to 4 bytes */
935		if (slop1 & 1) {
936			*(u_char *)dp = clr;
937			DELTA(dp, 1, int32_t *);
938		}
939
940		if (slop1 & 2) {
941			*(int16_t *)dp = clr;
942			DELTA(dp, 2, int32_t *);
943		}
944
945		/* Write 32 bytes per loop */
946		for (cnt = n8; cnt; cnt--) {
947			dp[0] = clr;
948			dp[1] = clr;
949			dp[2] = clr;
950			dp[3] = clr;
951			dp[4] = clr;
952			dp[5] = clr;
953			dp[6] = clr;
954			dp[7] = clr;
955			dp += 8;
956		}
957
958		/* Write 4 bytes per loop */
959		for (cnt = num; cnt; cnt--)
960			*dp++ = clr;
961
962		/* Write unaligned trailing slop */
963		if (slop2 & 1) {
964			*(u_char *)dp = clr;
965			DELTA(dp, 1, int32_t *);
966		}
967
968		if (slop2 & 2)
969			*(int16_t *)dp = clr;
970	}
971}
972