rasops.c revision 1.17
1/*	 $NetBSD: rasops.c,v 1.17 1999/09/17 00:09:34 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.17 1999/09/17 00:09:34 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#endif
363	if ((flg & WSATTR_BLINK) != 0)
364		return (EINVAL);
365
366	if ((flg & WSATTR_REVERSE) != 0) {
367		swap = fg;
368		fg = bg;
369		bg = swap;
370	}
371
372	if ((flg & WSATTR_HILIT) != 0)
373		fg += 8;
374
375	flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0);
376
377	if (rasops_isgray[fg])
378		flg |= 2;
379
380	if (rasops_isgray[bg])
381		flg |= 4;
382
383	*attr = (bg << 16) | (fg << 24) | flg;
384	return (0);
385}
386
387
388/*
389 * Allocate a mono attribute.
390 */
391static int
392rasops_alloc_mattr(cookie, fg, bg, flg, attr)
393	void *cookie;
394	int fg, bg, flg;
395	long *attr;
396{
397	int swap;
398
399	fg = (fg == WSCOL_BLACK ? 0 : 1);
400	bg = (bg == WSCOL_BLACK ? 0 : 1);
401
402	if ((flg & (WSATTR_BLINK | WSATTR_HILIT)) != 0)
403		return (EINVAL);
404
405	if ((flg & WSATTR_REVERSE) != 0) {
406		swap = fg;
407		fg = bg;
408		bg = swap;
409	}
410
411	*attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6);
412	return (0);
413}
414
415
416/*
417 * Copy rows.
418 */
419static void
420rasops_copyrows(cookie, src, dst, num)
421	void *cookie;
422	int src, dst, num;
423{
424	struct rasops_info *ri;
425	int32_t *sp, *dp, *srp, *drp;
426	int n8, n1, cnt;
427
428	ri = (struct rasops_info *)cookie;
429
430#ifdef RASOPS_CLIPPING
431	if (dst == src)
432		return;
433
434	if (src < 0) {
435		num += src;
436		src = 0;
437	}
438
439	if ((src + num) > ri->ri_rows)
440		num = ri->ri_rows - src;
441
442	if (dst < 0) {
443		num += dst;
444		dst = 0;
445	}
446
447	if ((dst + num) > ri->ri_rows)
448		num = ri->ri_rows - dst;
449
450	if (num <= 0)
451		return;
452#endif
453
454	num *= ri->ri_font->fontheight;
455	n8 = ri->ri_emustride >> 5;
456	n1 = (ri->ri_emustride >> 2) & 7;
457
458	if (dst < src) {
459		sp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale);
460		dp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale);
461
462		while (num--) {
463			for (cnt = n8; cnt; cnt--) {
464				dp[0] = sp[0];
465				dp[1] = sp[1];
466				dp[2] = sp[2];
467				dp[3] = sp[3];
468				dp[4] = sp[4];
469				dp[5] = sp[5];
470				dp[6] = sp[6];
471				dp[7] = sp[7];
472				dp += 8;
473				sp += 8;
474			}
475
476			for (cnt = n1; cnt; cnt--)
477				*dp++ = *sp++;
478
479			DELTA(dp, ri->ri_delta, int32_t *);
480			DELTA(sp, ri->ri_delta, int32_t *);
481		}
482	} else {
483		src = ri->ri_font->fontheight * src + num - 1;
484		dst = ri->ri_font->fontheight * dst + num - 1;
485
486		srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride);
487		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride);
488
489		while (num--) {
490			dp = drp;
491			sp = srp;
492			DELTA(srp, -ri->ri_stride, int32_t *);
493			DELTA(drp, -ri->ri_stride, int32_t *);
494
495			for (cnt = n8; cnt; cnt--) {
496				dp[0] = sp[0];
497				dp[1] = sp[1];
498				dp[2] = sp[2];
499				dp[3] = sp[3];
500				dp[4] = sp[4];
501				dp[5] = sp[5];
502				dp[6] = sp[6];
503				dp[7] = sp[7];
504				dp += 8;
505				sp += 8;
506			}
507
508			for (cnt = n1; cnt; cnt--)
509				*dp++ = *sp++;
510		}
511	}
512}
513
514
515/*
516 * Copy columns. This is slow, and hard to optimize due to alignment,
517 * and the fact that we have to copy both left->right and right->left.
518 * We simply cop-out here and use bcopy(), since it handles all of
519 * these cases anyway.
520 */
521void
522rasops_copycols(cookie, row, src, dst, num)
523	void *cookie;
524	int row, src, dst, num;
525{
526	struct rasops_info *ri;
527	u_char *sp, *dp;
528	int height;
529
530	ri = (struct rasops_info *)cookie;
531
532#ifdef RASOPS_CLIPPING
533	if (dst == src)
534		return;
535
536	/* Catches < 0 case too */
537	if ((unsigned)row >= (unsigned)ri->ri_rows)
538		return;
539
540	if (src < 0) {
541		num += src;
542		src = 0;
543	}
544
545	if ((src + num) > ri->ri_cols)
546		num = ri->ri_cols - src;
547
548	if (dst < 0) {
549		num += dst;
550		dst = 0;
551	}
552
553	if ((dst + num) > ri->ri_cols)
554		num = ri->ri_cols - dst;
555
556	if (num <= 0)
557		return;
558#endif
559
560	num *= ri->ri_xscale;
561	row *= ri->ri_yscale;
562	height = ri->ri_font->fontheight;
563
564	sp = ri->ri_bits + row + src * ri->ri_xscale;
565	dp = ri->ri_bits + row + dst * ri->ri_xscale;
566
567	while (height--) {
568		bcopy(sp, dp, num);
569		dp += ri->ri_stride;
570		sp += ri->ri_stride;
571	}
572}
573
574
575/*
576 * Turn cursor off/on.
577 */
578static void
579rasops_cursor(cookie, on, row, col)
580	void *cookie;
581	int on, row, col;
582{
583	struct rasops_info *ri;
584
585	ri = (struct rasops_info *)cookie;
586
587	/* Turn old cursor off */
588	if ((ri->ri_flg & RI_CURSOR) != 0)
589#ifdef RASOPS_CLIPPING
590		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
591#endif
592			ri->ri_do_cursor(ri);
593
594	/* Select new cursor */
595#ifdef RASOPS_CLIPPING
596	ri->ri_flg &= ~RI_CURSORCLIP;
597
598	if (row < 0 || row >= ri->ri_rows)
599		ri->ri_flg |= RI_CURSORCLIP;
600	else if (col < 0 || col >= ri->ri_cols)
601		ri->ri_flg |= RI_CURSORCLIP;
602#endif
603	ri->ri_crow = row;
604	ri->ri_ccol = col;
605
606	if (on) {
607		ri->ri_flg |= RI_CURSOR;
608#ifdef RASOPS_CLIPPING
609		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
610#endif
611			ri->ri_do_cursor(ri);
612	} else
613		ri->ri_flg &= ~RI_CURSOR;
614}
615
616
617/*
618 * Make the device colormap
619 */
620static void
621rasops_init_devcmap(ri)
622	struct rasops_info *ri;
623{
624	u_char *p;
625	int i, c;
626
627	switch (ri->ri_depth) {
628	case 1:
629		ri->ri_devcmap[0] = 0;
630		for (i = 1; i < 16; i++)
631			ri->ri_devcmap[i] = -1;
632		return;
633
634	case 2:
635		for (i = 1; i < 15; i++)
636			ri->ri_devcmap[i] = 0xaaaaaaaa;
637
638		ri->ri_devcmap[0] = 0;
639		ri->ri_devcmap[8] = 0x55555555;
640		ri->ri_devcmap[15] = -1;
641		return;
642
643	case 8:
644		for (i = 0; i < 16; i++)
645			ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24);
646		return;
647	}
648
649	p = rasops_cmap;
650
651	for (i = 0; i < 16; i++, p++) {
652		if (ri->ri_rnum <= 8)
653			c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
654		else
655			c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
656
657		if (ri->ri_gnum <= 8)
658			c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
659		else
660			c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
661
662		if (ri->ri_bnum <= 8)
663			c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
664		else
665			c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
666
667		/* Fill the word for generic routines, which want this */
668		if (ri->ri_depth == 24)
669			c = c | ((c & 0xff) << 24);
670		else if (ri->ri_depth <= 16)
671			c = c | (c << 16);
672
673		/* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */
674		if ((ri->ri_flg & RI_BSWAP) == 0)
675			ri->ri_devcmap[i] = c;
676		else if (ri->ri_depth == 32)
677			ri->ri_devcmap[i] = bswap32(c);
678		else if (ri->ri_depth == 16 || ri->ri_depth == 15)
679			ri->ri_devcmap[i] = bswap16(c);
680		else
681			ri->ri_devcmap[i] = c;
682	}
683}
684
685
686/*
687 * Unpack a rasops attribute
688 */
689void
690rasops_unpack_attr(attr, fg, bg, underline)
691	long attr;
692	int *fg, *bg, *underline;
693{
694
695	*fg = ((u_int)attr >> 24) & 15;
696	*bg = ((u_int)attr >> 16) & 15;
697	*underline = (u_int)attr & 1;
698}
699
700
701/*
702 * Erase rows. This isn't static, since 24-bpp uses it in special cases.
703 */
704void
705rasops_eraserows(cookie, row, num, attr)
706	void *cookie;
707	int row, num;
708	long attr;
709{
710	struct rasops_info *ri;
711	int np, nw, cnt, delta;
712	int32_t *dp, clr;
713
714	ri = (struct rasops_info *)cookie;
715
716#ifdef RASOPS_CLIPPING
717	if (row < 0) {
718		num += row;
719		row = 0;
720	}
721
722	if ((row + num) > ri->ri_rows)
723		num = ri->ri_rows - row;
724
725	if (num <= 0)
726		return;
727#endif
728
729	clr = ri->ri_devcmap[(attr >> 16) & 15];
730
731	/*
732	 * XXX the wsdisplay_emulops interface seems a little deficient in
733	 * that there is no way to clear the *entire* screen. We provide a
734	 * workaround here: if the entire console area is being cleared, and
735	 * the RI_FULLCLEAR flag is set, clear the entire display.
736	 */
737	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
738		np = ri->ri_stride >> 5;
739		nw = (ri->ri_stride >> 2) & 7;
740		num = ri->ri_height;
741		dp = (int32_t *)ri->ri_origbits;
742		delta = 0;
743	} else {
744		np = ri->ri_emustride >> 5;
745		nw = (ri->ri_emustride >> 2) & 7;
746		num *= ri->ri_font->fontheight;
747		dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
748		delta = ri->ri_delta;
749	}
750
751	while (num--) {
752		for (cnt = np; cnt; cnt--) {
753			dp[0] = clr;
754			dp[1] = clr;
755			dp[2] = clr;
756			dp[3] = clr;
757			dp[4] = clr;
758			dp[5] = clr;
759			dp[6] = clr;
760			dp[7] = clr;
761			dp += 8;
762		}
763
764		for (cnt = nw; cnt; cnt--) {
765			*(int32_t *)dp = clr;
766			DELTA(dp, 4, int32_t *);
767		}
768
769		DELTA(dp, delta, int32_t *);
770	}
771}
772
773
774/*
775 * Actually turn the cursor on or off. This does the dirty work for
776 * rasops_cursor().
777 */
778static void
779rasops_do_cursor(ri)
780	struct rasops_info *ri;
781{
782	int full1, height, cnt, slop1, slop2, row, col, mask;
783	u_char *dp, *rp;
784
785	row = ri->ri_crow;
786	col = ri->ri_ccol;
787
788	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
789	height = ri->ri_font->fontheight;
790	mask = ri->ri_devcmap[15];
791
792	slop1 = (4 - ((int)rp & 3)) & 3;
793
794	if (slop1 > ri->ri_xscale)
795		slop1 = ri->ri_xscale;
796
797	slop2 = (ri->ri_xscale - slop1) & 3;
798	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
799
800	if ((slop1 | slop2) == 0) {
801		/* A common case */
802		while (height--) {
803			dp = rp;
804			rp += ri->ri_stride;
805
806			for (cnt = full1; cnt; cnt--) {
807				*(int32_t *)dp ^= mask;
808				dp += 4;
809			}
810		}
811	} else {
812		/* XXX this is stupid.. use masks instead */
813		while (height--) {
814			dp = rp;
815			rp += ri->ri_stride;
816
817			if (slop1 & 1)
818				*dp++ ^= mask;
819
820			if (slop1 & 2) {
821				*(int16_t *)dp ^= mask;
822				dp += 2;
823			}
824
825			for (cnt = full1; cnt; cnt--) {
826				*(int32_t *)dp ^= mask;
827				dp += 4;
828			}
829
830			if (slop2 & 1)
831				*dp++ ^= mask;
832
833			if (slop2 & 2)
834				*(int16_t *)dp ^= mask;
835		}
836	}
837}
838
839
840/*
841 * Erase columns.
842 */
843void
844rasops_erasecols(cookie, row, col, num, attr)
845	void *cookie;
846	int row, col, num;
847	long attr;
848{
849	int n8, height, cnt, slop1, slop2, clr;
850	struct rasops_info *ri;
851	int32_t *rp, *dp;
852
853	ri = (struct rasops_info *)cookie;
854
855#ifdef RASOPS_CLIPPING
856	if ((unsigned)row >= (unsigned)ri->ri_rows)
857		return;
858
859	if (col < 0) {
860		num += col;
861		col = 0;
862	}
863
864	if ((col + num) > ri->ri_cols)
865		num = ri->ri_cols - col;
866
867	if (num <= 0)
868		return;
869#endif
870
871	num = num * ri->ri_xscale;
872	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
873	height = ri->ri_font->fontheight;
874	clr = ri->ri_devcmap[(attr >> 16) & 15];
875
876	/* Don't bother using the full loop for <= 32 pels */
877	if (num <= 32) {
878		if (((num | ri->ri_xscale) & 3) == 0) {
879			/* Word aligned blt */
880			num >>= 2;
881
882			while (height--) {
883				dp = rp;
884				DELTA(rp, ri->ri_stride, int32_t *);
885
886				for (cnt = num; cnt; cnt--)
887					*dp++ = clr;
888			}
889		} else if (((num | ri->ri_xscale) & 1) == 0) {
890			/*
891			 * Halfword aligned blt. This is needed so the
892			 * 15/16 bit ops can use this function.
893			 */
894			num >>= 1;
895
896			while (height--) {
897				dp = rp;
898				DELTA(rp, ri->ri_stride, int32_t *);
899
900				for (cnt = num; cnt; cnt--) {
901					*(int16_t *)dp = clr;
902					DELTA(dp, 2, int32_t *);
903				}
904			}
905		} else {
906			while (height--) {
907				dp = rp;
908				DELTA(rp, ri->ri_stride, int32_t *);
909
910				for (cnt = num; cnt; cnt--) {
911					*(u_char *)dp = clr;
912					DELTA(dp, 1, int32_t *);
913				}
914			}
915		}
916
917		return;
918	}
919
920	slop1 = (4 - ((int)rp & 3)) & 3;
921	slop2 = (num - slop1) & 3;
922	num -= slop1 + slop2;
923	n8 = num >> 5;
924	num = (num >> 2) & 7;
925
926	while (height--) {
927		dp = rp;
928		DELTA(rp, ri->ri_stride, int32_t *);
929
930		/* Align span to 4 bytes */
931		if (slop1 & 1) {
932			*(u_char *)dp = clr;
933			DELTA(dp, 1, int32_t *);
934		}
935
936		if (slop1 & 2) {
937			*(int16_t *)dp = clr;
938			DELTA(dp, 2, int32_t *);
939		}
940
941		/* Write 32 bytes per loop */
942		for (cnt = n8; cnt; cnt--) {
943			dp[0] = clr;
944			dp[1] = clr;
945			dp[2] = clr;
946			dp[3] = clr;
947			dp[4] = clr;
948			dp[5] = clr;
949			dp[6] = clr;
950			dp[7] = clr;
951			dp += 8;
952		}
953
954		/* Write 4 bytes per loop */
955		for (cnt = num; cnt; cnt--)
956			*dp++ = clr;
957
958		/* Write unaligned trailing slop */
959		if (slop2 & 1) {
960			*(u_char *)dp = clr;
961			DELTA(dp, 1, int32_t *);
962		}
963
964		if (slop2 & 2)
965			*(int16_t *)dp = clr;
966	}
967}
968