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