rasops.c revision 1.11
1/*	 $NetBSD: rasops.c,v 1.11 1999/06/15 22:34:45 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.11 1999/06/15 22:34:45 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, clear, center)
112	struct rasops_info *ri;
113	int wantrows, wantcols, clear, center;
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#ifdef DIAGNOSTIC
138		if (ri->ri_font == NULL)
139			panic("rasops_init: locked font, but got no pointer\n");
140#endif
141		ri->ri_wsfcookie = cookie;
142	}
143#endif
144
145	/* This should never happen in reality... */
146#ifdef DEBUG
147	if ((int)ri->ri_bits & 3) {
148		printf("rasops_init: bits not aligned on 32-bit boundary\n");
149		return (-1);
150	}
151
152	if ((int)ri->ri_stride & 3) {
153		printf("rasops_init: stride not aligned on 32-bit boundary\n");
154		return (-1);
155	}
156#endif
157
158	/* Fix color palette. We need this for the cursor to work. */
159	rasops_cmap[255*3+0] = 0xff;
160	rasops_cmap[255*3+1] = 0xff;
161	rasops_cmap[255*3+2] = 0xff;
162
163	/* setfont does most of the work */
164	if (rasops_setfont(ri, wantrows, wantcols, clear, center))
165		return (-1);
166
167	rasops_init_devcmap(ri);
168	ri->ri_flg = RASOPS_INITTED;
169	return (0);
170}
171
172
173/*
174 * Choose a different font. The new font will already be set in ri_font.
175 */
176int
177rasops_setfont(ri, wantrows, wantcols, clear, center)
178	struct rasops_info *ri;
179	int wantrows, wantcols, clear, center;
180{
181	int bpp;
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 & RASOPS_INITTED)
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 = 5000;
195
196	if (wantcols < 20)
197		wantcols = 5000;
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)
227		panic("rasops_init: delta isn't aligned on 32-bit boundary!");
228#endif
229	/* Clear the entire display */
230	if (clear)
231		bzero(ri->ri_bits, 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 (center) {
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_forcemono) {
261		ri->ri_ops.alloc_attr = rasops_alloc_mattr;
262		ri->ri_caps = WSATTR_UNDERLINE | WSATTR_REVERSE;
263	} else {
264		ri->ri_ops.alloc_attr = rasops_alloc_cattr;
265		ri->ri_caps = WSATTR_UNDERLINE | WSATTR_HILIT |
266		    WSATTR_WSCOLORS | WSATTR_REVERSE;
267	}
268
269	switch (ri->ri_depth) {
270#if NRASOPS1
271	case 1:
272		rasops1_init(ri);
273		break;
274#endif
275
276#if NRASOPS2
277	case 2:
278		rasops2_init(ri);
279		break;
280#endif
281
282#if NRASOPS8
283	case 8:
284		rasops8_init(ri);
285		break;
286#endif
287
288#if NRASOPS15 || NRASOPS16
289	case 15:
290	case 16:
291		rasops15_init(ri);
292		break;
293#endif
294
295#if NRASOPS24
296	case 24:
297		rasops24_init(ri);
298		break;
299#endif
300
301#if NRASOPS32
302	case 32:
303		rasops32_init(ri);
304		break;
305#endif
306	default:
307		ri->ri_flg = 0;
308		return (-1);
309	}
310
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 & RASOPS_CURSOR)
593#ifdef RASOPS_CLIPPING
594		if (!(ri->ri_flg & RASOPS_CURSOR_CLIPPED))
595#endif
596			ri->ri_do_cursor(ri);
597
598	/* Select new cursor */
599#ifdef RASOPS_CLIPPING
600	ri->ri_flg &= ~RASOPS_CURSOR_CLIPPED;
601
602	if (row < 0 || row >= ri->ri_rows)
603		ri->ri_flg |= RASOPS_CURSOR_CLIPPED;
604	else if (col < 0 || col >= ri->ri_cols)
605		ri->ri_flg |= RASOPS_CURSOR_CLIPPED;
606#endif
607	ri->ri_crow = row;
608	ri->ri_ccol = col;
609
610	if (on) {
611		ri->ri_flg |= RASOPS_CURSOR;
612#ifdef RASOPS_CLIPPING
613		if (!(ri->ri_flg & RASOPS_CURSOR_CLIPPED))
614#endif
615			ri->ri_do_cursor(ri);
616	} else
617		ri->ri_flg &= ~RASOPS_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++) {
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_swab)
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;
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	num *= ri->ri_font->fontheight;
735	dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
736
737	np = ri->ri_emustride >> 5;
738	nw = (ri->ri_emustride >> 2) & 7;
739
740	while (num--) {
741		for (cnt = np; cnt; cnt--) {
742			dp[0] = clr;
743			dp[1] = clr;
744			dp[2] = clr;
745			dp[3] = clr;
746			dp[4] = clr;
747			dp[5] = clr;
748			dp[6] = clr;
749			dp[7] = clr;
750			dp += 8;
751		}
752
753		for (cnt = nw; cnt; cnt--) {
754			*(int32_t *)dp = clr;
755			DELTA(dp, 4, int32_t *);
756		}
757
758		DELTA(dp, ri->ri_delta, int32_t *);
759	}
760}
761
762
763/*
764 * Actually turn the cursor on or off. This does the dirty work for
765 * rasops_cursor().
766 */
767static void
768rasops_do_cursor(ri)
769	struct rasops_info *ri;
770{
771	int full1, height, cnt, slop1, slop2, row, col, mask;
772	u_char *dp, *rp;
773
774	row = ri->ri_crow;
775	col = ri->ri_ccol;
776
777	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
778	height = ri->ri_font->fontheight;
779	mask = ri->ri_devcmap[15];
780
781	slop1 = (4 - ((int)rp & 3)) & 3;
782
783	if (slop1 > ri->ri_xscale)
784		slop1 = ri->ri_xscale;
785
786	slop2 = (ri->ri_xscale - slop1) & 3;
787	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
788
789	if ((slop1 | slop2) == 0) {
790		/* A common case */
791		while (height--) {
792			dp = rp;
793			rp += ri->ri_stride;
794
795			for (cnt = full1; cnt; cnt--) {
796				*(int32_t *)dp ^= mask;
797				dp += 4;
798			}
799		}
800	} else {
801		/* XXX this is stupid.. use masks instead */
802		while (height--) {
803			dp = rp;
804			rp += ri->ri_stride;
805
806			if (slop1 & 1)
807				*dp++ ^= mask;
808
809			if (slop1 & 2) {
810				*(int16_t *)dp ^= mask;
811				dp += 2;
812			}
813
814			for (cnt = full1; cnt; cnt--) {
815				*(int32_t *)dp ^= mask;
816				dp += 4;
817			}
818
819			if (slop2 & 1)
820				*dp++ ^= mask;
821
822			if (slop2 & 2)
823				*(int16_t *)dp ^= mask;
824		}
825	}
826}
827
828
829/*
830 * Erase columns.
831 */
832void
833rasops_erasecols(cookie, row, col, num, attr)
834	void *cookie;
835	int row, col, num;
836	long attr;
837{
838	int n8, height, cnt, slop1, slop2, clr;
839	struct rasops_info *ri;
840	int32_t *rp, *dp;
841
842	ri = (struct rasops_info *)cookie;
843
844#ifdef RASOPS_CLIPPING
845	if ((unsigned)row >= (unsigned)ri->ri_rows)
846		return;
847
848	if (col < 0) {
849		num += col;
850		col = 0;
851	}
852
853	if ((col + num) > ri->ri_cols)
854		num = ri->ri_cols - col;
855
856	if (num <= 0)
857		return;
858#endif
859
860	num = num * ri->ri_xscale;
861	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
862	height = ri->ri_font->fontheight;
863	clr = ri->ri_devcmap[(attr >> 16) & 15];
864
865	/* Don't bother using the full loop for <= 32 pels */
866	if (num <= 32) {
867		if (((num | ri->ri_xscale) & 3) == 0) {
868			/* Word aligned blt */
869			num >>= 2;
870
871			while (height--) {
872				dp = rp;
873				DELTA(rp, ri->ri_stride, int32_t *);
874
875				for (cnt = num; cnt; cnt--)
876					*dp++ = clr;
877			}
878		} else if (((num | ri->ri_xscale) & 1) == 0) {
879			/*
880			 * Halfword aligned blt. This is needed so the
881			 * 15/16 bit ops can use this function.
882			 */
883			num >>= 1;
884
885			while (height--) {
886				dp = rp;
887				DELTA(rp, ri->ri_stride, int32_t *);
888
889				for (cnt = num; cnt; cnt--) {
890					*(int16_t *)dp = clr;
891					DELTA(dp, 2, int32_t *);
892				}
893			}
894		} else {
895			while (height--) {
896				dp = rp;
897				DELTA(rp, ri->ri_stride, int32_t *);
898
899				for (cnt = num; cnt; cnt--) {
900					*(u_char *)dp = clr;
901					DELTA(dp, 1, int32_t *);
902				}
903			}
904		}
905
906		return;
907	}
908
909	slop1 = (4 - ((int)rp & 3)) & 3;
910	slop2 = (num - slop1) & 3;
911	num -= slop1 + slop2;
912	n8 = num >> 5;
913	num = (num >> 2) & 7;
914
915	while (height--) {
916		dp = rp;
917		DELTA(rp, ri->ri_stride, int32_t *);
918
919		/* Align span to 4 bytes */
920		if (slop1 & 1) {
921			*(u_char *)dp = clr;
922			DELTA(dp, 1, int32_t *);
923		}
924
925		if (slop1 & 2) {
926			*(int16_t *)dp = clr;
927			DELTA(dp, 2, int32_t *);
928		}
929
930		/* Write 32 bytes per loop */
931		for (cnt = n8; cnt; cnt--) {
932			dp[0] = clr;
933			dp[1] = clr;
934			dp[2] = clr;
935			dp[3] = clr;
936			dp[4] = clr;
937			dp[5] = clr;
938			dp[6] = clr;
939			dp[7] = clr;
940			dp += 8;
941		}
942
943		/* Write 4 bytes per loop */
944		for (cnt = num; cnt; cnt--)
945			*dp++ = clr;
946
947		/* Write unaligned trailing slop */
948		if (slop2 & 1) {
949			*(u_char *)dp = clr;
950			DELTA(dp, 1, int32_t *);
951		}
952
953		if (slop2 & 2)
954			*(int16_t *)dp = clr;
955	}
956}
957