1 /* $OpenBSD: rasops.c,v 1.17 2006/12/02 18:02:53 miod Exp $ */
2 /* $NetBSD: rasops.c,v 1.35 2001/02/02 06:01:01 marcus Exp $ */
3
4 /*-
5 * Copyright (c) 1999 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Andrew Doran.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/time.h>
43
44 #include <machine/endian.h>
45
46 #include <dev/wscons/wsdisplayvar.h>
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wsfont/wsfont.h>
49 #include <dev/rasops/rasops.h>
50
51 #ifndef _KERNEL
52 #include <errno.h>
53 #endif
54
55 /* ANSI colormap (R,G,B) */
56
57 #define NORMAL_BLACK 0x000000
58 #define NORMAL_RED 0x7f0000
59 #define NORMAL_GREEN 0x007f00
60 #define NORMAL_BROWN 0x7f7f00
61 #define NORMAL_BLUE 0x00007f
62 #define NORMAL_MAGENTA 0x7f007f
63 #define NORMAL_CYAN 0x007f7f
64 #define NORMAL_WHITE 0xc7c7c7 /* XXX too dim? */
65
66 #define HILITE_BLACK 0x7f7f7f
67 #define HILITE_RED 0xff0000
68 #define HILITE_GREEN 0x00ff00
69 #define HILITE_BROWN 0xffff00
70 #define HILITE_BLUE 0x0000ff
71 #define HILITE_MAGENTA 0xff00ff
72 #define HILITE_CYAN 0x00ffff
73 #define HILITE_WHITE 0xffffff
74
75 const u_char rasops_cmap[256 * 3] = {
76 #define _C(x) ((x) & 0xff0000) >> 16, ((x) & 0x00ff00) >> 8, ((x) & 0x0000ff)
77
78 _C(NORMAL_BLACK),
79 _C(NORMAL_RED),
80 _C(NORMAL_GREEN),
81 _C(NORMAL_BROWN),
82 _C(NORMAL_BLUE),
83 _C(NORMAL_MAGENTA),
84 _C(NORMAL_CYAN),
85 _C(NORMAL_WHITE),
86
87 _C(HILITE_BLACK),
88 _C(HILITE_RED),
89 _C(HILITE_GREEN),
90 _C(HILITE_BROWN),
91 _C(HILITE_BLUE),
92 _C(HILITE_MAGENTA),
93 _C(HILITE_CYAN),
94 _C(HILITE_WHITE),
95
96 /*
97 * For the cursor, we need the last 16 colors to be the
98 * opposite of the first 16. Fill the intermediate space with
99 * white completely for simplicity.
100 */
101 #define _CMWHITE16 \
102 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), \
103 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), \
104 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), \
105 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE),
106 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
107 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
108 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
109 #undef _CMWHITE16
110
111 _C(~HILITE_WHITE),
112 _C(~HILITE_CYAN),
113 _C(~HILITE_MAGENTA),
114 _C(~HILITE_BLUE),
115 _C(~HILITE_BROWN),
116 _C(~HILITE_GREEN),
117 _C(~HILITE_RED),
118 _C(~HILITE_BLACK),
119
120 _C(~NORMAL_WHITE),
121 _C(~NORMAL_CYAN),
122 _C(~NORMAL_MAGENTA),
123 _C(~NORMAL_BLUE),
124 _C(~NORMAL_BROWN),
125 _C(~NORMAL_GREEN),
126 _C(~NORMAL_RED),
127 _C(~NORMAL_BLACK),
128
129 #undef _C
130 };
131
132 /* True if color is gray */
133 const u_char rasops_isgray[16] = {
134 1, 0, 0, 0,
135 0, 0, 0, 1,
136 1, 0, 0, 0,
137 0, 0, 0, 1
138 };
139
140 /* Generic functions */
141 void rasops_copycols(void *, int, int, int, int);
142 void rasops_copyrows(void *, int, int, int);
143 int rasops_mapchar(void *, int, u_int *);
144 void rasops_cursor(void *, int, int, int);
145 int rasops_alloc_cattr(void *, int, int, int, long *);
146 int rasops_alloc_mattr(void *, int, int, int, long *);
147 void rasops_do_cursor(struct rasops_info *);
148 void rasops_init_devcmap(struct rasops_info *);
149 void rasops_unpack_attr(void *, long, int *, int *, int *);
150 #if NRASOPS_BSWAP > 0
151 static void slow_ovbcopy(void *, void *, size_t);
152 #endif
153 #if NRASOPS_ROTATION > 0
154 void rasops_copychar(void *, int, int, int, int);
155 void rasops_copycols_rotated(void *, int, int, int, int);
156 void rasops_copyrows_rotated(void *, int, int, int);
157 void rasops_erasecols_rotated(void *, int, int, int, long);
158 void rasops_eraserows_rotated(void *, int, int, long);
159 void rasops_putchar_rotated(void *, int, int, u_int, long);
160 void rasops_rotate_font(int *);
161
162 /*
163 * List of all rotated fonts
164 */
165 SLIST_HEAD(, rotatedfont) rotatedfonts = SLIST_HEAD_INITIALIZER(rotatedfonts);
166 struct rotatedfont {
167 SLIST_ENTRY(rotatedfont) rf_next;
168 int rf_cookie;
169 int rf_rotated;
170 };
171 #endif
172
173 /*
174 * Initialize a 'rasops_info' descriptor.
175 */
176 int
rasops_init(ri,wantrows,wantcols)177 rasops_init(ri, wantrows, wantcols)
178 struct rasops_info *ri;
179 int wantrows, wantcols;
180 {
181
182 #ifdef _KERNEL
183 /* Select a font if the caller doesn't care */
184 if (ri->ri_font == NULL) {
185 int cookie;
186
187 wsfont_init();
188
189 if (ri->ri_width > 80*12)
190 /* High res screen, choose a big font */
191 cookie = wsfont_find(NULL, 12, 0, 0);
192 else
193 /* lower res, choose a 8 pixel wide font */
194 cookie = wsfont_find(NULL, 8, 0, 0);
195
196 if (cookie <= 0)
197 cookie = wsfont_find(NULL, 0, 0, 0);
198
199 if (cookie <= 0) {
200 printf("rasops_init: font table is empty\n");
201 return (-1);
202 }
203
204 #if NRASOPS_ROTATION > 0
205 /*
206 * Pick the rotated version of this font. This will create it
207 * if necessary.
208 */
209 if (ri->ri_flg & RI_ROTATE_CW)
210 rasops_rotate_font(&cookie);
211 #endif
212
213 if (wsfont_lock(cookie, &ri->ri_font,
214 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
215 printf("rasops_init: couldn't lock font\n");
216 return (-1);
217 }
218
219 ri->ri_wsfcookie = cookie;
220 }
221 #endif
222
223 /* This should never happen in reality... */
224 #ifdef DEBUG
225 if ((long)ri->ri_bits & 3) {
226 printf("rasops_init: bits not aligned on 32-bit boundary\n");
227 return (-1);
228 }
229
230 if ((int)ri->ri_stride & 3) {
231 printf("rasops_init: stride not aligned on 32-bit boundary\n");
232 return (-1);
233 }
234 #endif
235
236 if (rasops_reconfig(ri, wantrows, wantcols))
237 return (-1);
238
239 rasops_init_devcmap(ri);
240 return (0);
241 }
242
243 /*
244 * Reconfigure (because parameters have changed in some way).
245 */
246 int
rasops_reconfig(ri,wantrows,wantcols)247 rasops_reconfig(ri, wantrows, wantcols)
248 struct rasops_info *ri;
249 int wantrows, wantcols;
250 {
251 int l, bpp, s;
252
253 s = splhigh();
254
255 if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4)
256 panic("rasops_init: fontwidth assumptions botched!");
257
258 /* Need this to frob the setup below */
259 bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth);
260
261 if ((ri->ri_flg & RI_CFGDONE) != 0)
262 ri->ri_bits = ri->ri_origbits;
263
264 /* Don't care if the caller wants a hideously small console */
265 if (wantrows < 10)
266 wantrows = 10;
267
268 if (wantcols < 20)
269 wantcols = 20;
270
271 /* Now constrain what they get */
272 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
273 ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
274
275 if (ri->ri_emuwidth > ri->ri_width)
276 ri->ri_emuwidth = ri->ri_width;
277
278 if (ri->ri_emuheight > ri->ri_height)
279 ri->ri_emuheight = ri->ri_height;
280
281 /* Reduce width until aligned on a 32-bit boundary */
282 while ((ri->ri_emuwidth * bpp & 31) != 0)
283 ri->ri_emuwidth--;
284
285 #if NRASOPS_ROTATION > 0
286 if (ri->ri_flg & RI_ROTATE_CW) {
287 ri->ri_rows = ri->ri_emuwidth / ri->ri_font->fontwidth;
288 ri->ri_cols = ri->ri_emuheight / ri->ri_font->fontheight;
289 } else
290 #endif
291 {
292 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
293 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
294 }
295 ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
296 ri->ri_delta = ri->ri_stride - ri->ri_emustride;
297 ri->ri_ccol = 0;
298 ri->ri_crow = 0;
299 ri->ri_pelbytes = bpp >> 3;
300
301 ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
302 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
303 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
304
305 #ifdef DEBUG
306 if ((ri->ri_delta & 3) != 0)
307 panic("rasops_init: ri_delta not aligned on 32-bit boundary");
308 #endif
309 /* Clear the entire display */
310 if ((ri->ri_flg & RI_CLEAR) != 0) {
311 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
312 ri->ri_flg &= ~RI_CLEARMARGINS;
313 }
314
315 /* Now centre our window if needs be */
316 ri->ri_origbits = ri->ri_bits;
317
318 if ((ri->ri_flg & RI_CENTER) != 0) {
319 ri->ri_bits += (((ri->ri_width * bpp >> 3) -
320 ri->ri_emustride) >> 1) & ~3;
321 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
322 ri->ri_stride;
323
324 ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
325 / ri->ri_stride;
326 ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
327 % ri->ri_stride) * 8 / bpp);
328 } else
329 ri->ri_xorigin = ri->ri_yorigin = 0;
330
331 /* Clear the margins */
332 if ((ri->ri_flg & RI_CLEARMARGINS) != 0) {
333 memset(ri->ri_origbits, 0, ri->ri_bits - ri->ri_origbits);
334 for (l = 0; l < ri->ri_emuheight; l++)
335 memset(ri->ri_bits + ri->ri_emustride +
336 l * ri->ri_stride, 0,
337 ri->ri_stride - ri->ri_emustride);
338 memset(ri->ri_bits + ri->ri_emuheight * ri->ri_stride, 0,
339 (ri->ri_origbits + ri->ri_height * ri->ri_stride) -
340 (ri->ri_bits + ri->ri_emuheight * ri->ri_stride));
341 }
342
343 /*
344 * Fill in defaults for operations set. XXX this nukes private
345 * routines used by accelerated fb drivers.
346 */
347 ri->ri_ops.mapchar = rasops_mapchar;
348 ri->ri_ops.copyrows = rasops_copyrows;
349 ri->ri_ops.copycols = rasops_copycols;
350 ri->ri_ops.erasecols = rasops_erasecols;
351 ri->ri_ops.eraserows = rasops_eraserows;
352 ri->ri_ops.cursor = rasops_cursor;
353 ri->ri_ops.unpack_attr = rasops_unpack_attr;
354 ri->ri_do_cursor = rasops_do_cursor;
355 ri->ri_updatecursor = NULL;
356
357 if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) {
358 ri->ri_ops.alloc_attr = rasops_alloc_mattr;
359 ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_REVERSE;
360 } else {
361 ri->ri_ops.alloc_attr = rasops_alloc_cattr;
362 ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
363 WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
364 }
365
366 switch (ri->ri_depth) {
367 #if NRASOPS1 > 0
368 case 1:
369 rasops1_init(ri);
370 break;
371 #endif
372 #if NRASOPS2 > 0
373 case 2:
374 rasops2_init(ri);
375 break;
376 #endif
377 #if NRASOPS4 > 0
378 case 4:
379 rasops4_init(ri);
380 break;
381 #endif
382 #if NRASOPS8 > 0
383 case 8:
384 rasops8_init(ri);
385 break;
386 #endif
387 #if NRASOPS15 > 0 || NRASOPS16 > 0
388 case 15:
389 case 16:
390 rasops15_init(ri);
391 break;
392 #endif
393 #if NRASOPS24 > 0
394 case 24:
395 rasops24_init(ri);
396 break;
397 #endif
398 #if NRASOPS32 > 0
399 case 32:
400 rasops32_init(ri);
401 break;
402 #endif
403 default:
404 ri->ri_flg &= ~RI_CFGDONE;
405 splx(s);
406 return (-1);
407 }
408
409 #if NRASOPS_ROTATION > 0
410 if (ri->ri_flg & RI_ROTATE_CW) {
411 ri->ri_real_ops = ri->ri_ops;
412 ri->ri_ops.copycols = rasops_copycols_rotated;
413 ri->ri_ops.copyrows = rasops_copyrows_rotated;
414 ri->ri_ops.erasecols = rasops_erasecols_rotated;
415 ri->ri_ops.eraserows = rasops_eraserows_rotated;
416 ri->ri_ops.putchar = rasops_putchar_rotated;
417 }
418 #endif
419
420 ri->ri_flg |= RI_CFGDONE;
421 splx(s);
422 return (0);
423 }
424
425 /*
426 * Map a character.
427 */
428 int
rasops_mapchar(cookie,c,cp)429 rasops_mapchar(cookie, c, cp)
430 void *cookie;
431 int c;
432 u_int *cp;
433 {
434 struct rasops_info *ri;
435
436 ri = (struct rasops_info *)cookie;
437
438 #ifdef DIAGNOSTIC
439 if (ri->ri_font == NULL)
440 panic("rasops_mapchar: no font selected");
441 #endif
442 if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) {
443
444 if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) {
445
446 *cp = ' ';
447 return (0);
448
449 }
450 }
451
452
453 if (c < ri->ri_font->firstchar) {
454 *cp = ' ';
455 return (0);
456 }
457
458 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) {
459 *cp = ' ';
460 return (0);
461 }
462
463 *cp = c;
464 return (5);
465 }
466
467 /*
468 * Allocate a color attribute.
469 */
470 int
rasops_alloc_cattr(cookie,fg,bg,flg,attr)471 rasops_alloc_cattr(cookie, fg, bg, flg, attr)
472 void *cookie;
473 int fg, bg, flg;
474 long *attr;
475 {
476 int swap;
477
478 #ifdef RASOPS_CLIPPING
479 fg &= 7;
480 bg &= 7;
481 #endif
482 if ((flg & WSATTR_BLINK) != 0)
483 return (EINVAL);
484
485 if ((flg & WSATTR_WSCOLORS) == 0) {
486 fg = WSCOL_WHITE;
487 bg = WSCOL_BLACK;
488 }
489
490 if ((flg & WSATTR_REVERSE) != 0) {
491 swap = fg;
492 fg = bg;
493 bg = swap;
494 if ((flg & WSATTR_WSCOLORS) == 0)
495 flg |= 8;
496 }
497
498 if ((flg & WSATTR_HILIT) != 0)
499 fg += 8;
500
501 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0);
502
503 if (rasops_isgray[fg])
504 flg |= 2;
505
506 if (rasops_isgray[bg])
507 flg |= 4;
508
509 *attr = (bg << 16) | (fg << 24) | flg;
510 return (0);
511 }
512
513 /*
514 * Allocate a mono attribute.
515 */
516 int
rasops_alloc_mattr(cookie,fg,bg,flg,attr)517 rasops_alloc_mattr(cookie, fg, bg, flg, attr)
518 void *cookie;
519 int fg, bg, flg;
520 long *attr;
521 {
522 int swap = 0;
523
524 if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0)
525 return (EINVAL);
526
527 fg = 1;
528 bg = 0;
529
530 if ((flg & WSATTR_REVERSE) != 0) {
531 swap = fg;
532 fg = bg;
533 bg = swap;
534 swap = 8;
535 }
536
537 swap |= (flg & WSATTR_UNDERLINE) ? 7 : 6;
538 *attr = (bg << 16) | (fg << 24) | swap;
539 return (0);
540 }
541
542 /*
543 * Copy rows.
544 */
545 void
rasops_copyrows(cookie,src,dst,num)546 rasops_copyrows(cookie, src, dst, num)
547 void *cookie;
548 int src, dst, num;
549 {
550 int32_t *sp, *dp, *srp, *drp;
551 struct rasops_info *ri;
552 int n8, n1, cnt, delta;
553
554 ri = (struct rasops_info *)cookie;
555
556 #ifdef RASOPS_CLIPPING
557 if (dst == src)
558 return;
559
560 if (src < 0) {
561 num += src;
562 src = 0;
563 }
564
565 if ((src + num) > ri->ri_rows)
566 num = ri->ri_rows - src;
567
568 if (dst < 0) {
569 num += dst;
570 dst = 0;
571 }
572
573 if ((dst + num) > ri->ri_rows)
574 num = ri->ri_rows - dst;
575
576 if (num <= 0)
577 return;
578 #endif
579
580 num *= ri->ri_font->fontheight;
581 n8 = ri->ri_emustride >> 5;
582 n1 = (ri->ri_emustride >> 2) & 7;
583
584 if (dst < src) {
585 srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale);
586 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale);
587 delta = ri->ri_stride;
588 } else {
589 src = ri->ri_font->fontheight * src + num - 1;
590 dst = ri->ri_font->fontheight * dst + num - 1;
591 srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride);
592 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride);
593 delta = -ri->ri_stride;
594 }
595
596 while (num--) {
597 dp = drp;
598 sp = srp;
599 DELTA(drp, delta, int32_t *);
600 DELTA(srp, delta, int32_t *);
601
602 for (cnt = n8; cnt; cnt--) {
603 dp[0] = sp[0];
604 dp[1] = sp[1];
605 dp[2] = sp[2];
606 dp[3] = sp[3];
607 dp[4] = sp[4];
608 dp[5] = sp[5];
609 dp[6] = sp[6];
610 dp[7] = sp[7];
611 dp += 8;
612 sp += 8;
613 }
614
615 for (cnt = n1; cnt; cnt--)
616 *dp++ = *sp++;
617 }
618 }
619
620 /*
621 * Copy columns. This is slow, and hard to optimize due to alignment,
622 * and the fact that we have to copy both left->right and right->left.
623 * We simply cop-out here and use ovbcopy(), since it handles all of
624 * these cases anyway.
625 */
626 void
rasops_copycols(cookie,row,src,dst,num)627 rasops_copycols(cookie, row, src, dst, num)
628 void *cookie;
629 int row, src, dst, num;
630 {
631 struct rasops_info *ri;
632 u_char *sp, *dp;
633 int height;
634
635 ri = (struct rasops_info *)cookie;
636
637 #ifdef RASOPS_CLIPPING
638 if (dst == src)
639 return;
640
641 /* Catches < 0 case too */
642 if ((unsigned)row >= (unsigned)ri->ri_rows)
643 return;
644
645 if (src < 0) {
646 num += src;
647 src = 0;
648 }
649
650 if ((src + num) > ri->ri_cols)
651 num = ri->ri_cols - src;
652
653 if (dst < 0) {
654 num += dst;
655 dst = 0;
656 }
657
658 if ((dst + num) > ri->ri_cols)
659 num = ri->ri_cols - dst;
660
661 if (num <= 0)
662 return;
663 #endif
664
665 num *= ri->ri_xscale;
666 row *= ri->ri_yscale;
667 height = ri->ri_font->fontheight;
668
669 sp = ri->ri_bits + row + src * ri->ri_xscale;
670 dp = ri->ri_bits + row + dst * ri->ri_xscale;
671
672 #if NRASOPS_BSWAP > 0
673 if (ri->ri_flg & RI_BSWAP) {
674 while (height--) {
675 slow_ovbcopy(sp, dp, num);
676 dp += ri->ri_stride;
677 sp += ri->ri_stride;
678 }
679 } else
680 #endif
681 {
682 while (height--) {
683 ovbcopy(sp, dp, num);
684 dp += ri->ri_stride;
685 sp += ri->ri_stride;
686 }
687 }
688 }
689
690 /*
691 * Turn cursor off/on.
692 */
693 void
rasops_cursor(cookie,on,row,col)694 rasops_cursor(cookie, on, row, col)
695 void *cookie;
696 int on, row, col;
697 {
698 struct rasops_info *ri;
699
700 ri = (struct rasops_info *)cookie;
701
702 /* Turn old cursor off */
703 if ((ri->ri_flg & RI_CURSOR) != 0)
704 #ifdef RASOPS_CLIPPING
705 if ((ri->ri_flg & RI_CURSORCLIP) == 0)
706 #endif
707 ri->ri_do_cursor(ri);
708
709 /* Select new cursor */
710 #ifdef RASOPS_CLIPPING
711 ri->ri_flg &= ~RI_CURSORCLIP;
712
713 if (row < 0 || row >= ri->ri_rows)
714 ri->ri_flg |= RI_CURSORCLIP;
715 else if (col < 0 || col >= ri->ri_cols)
716 ri->ri_flg |= RI_CURSORCLIP;
717 #endif
718 ri->ri_crow = row;
719 ri->ri_ccol = col;
720
721 if (ri->ri_updatecursor != NULL)
722 ri->ri_updatecursor(ri);
723
724 if (on) {
725 ri->ri_flg |= RI_CURSOR;
726 #ifdef RASOPS_CLIPPING
727 if ((ri->ri_flg & RI_CURSORCLIP) == 0)
728 #endif
729 ri->ri_do_cursor(ri);
730 } else
731 ri->ri_flg &= ~RI_CURSOR;
732 }
733
734 /*
735 * Make the device colormap
736 */
737 void
rasops_init_devcmap(ri)738 rasops_init_devcmap(ri)
739 struct rasops_info *ri;
740 {
741 int i;
742 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
743 const u_char *p;
744 #endif
745 #if NRASOPS4 > 0 || NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
746 int c;
747 #endif
748
749 switch (ri->ri_depth) {
750 #if NRASOPS1 > 0
751 case 1:
752 ri->ri_devcmap[0] = 0;
753 for (i = 1; i < 16; i++)
754 ri->ri_devcmap[i] = 0xffffffff;
755 return;
756 #endif
757 #if NRASOPS2 > 0
758 case 2:
759 for (i = 1; i < 15; i++)
760 ri->ri_devcmap[i] = 0xaaaaaaaa;
761
762 ri->ri_devcmap[0] = 0;
763 ri->ri_devcmap[8] = 0x55555555;
764 ri->ri_devcmap[15] = 0xffffffff;
765 return;
766 #endif
767 #if NRASOPS4 > 0
768 case 4:
769 for (i = 0; i < 16; i++) {
770 c = i | (i << 4);
771 ri->ri_devcmap[i] = c | (c<<8) | (c<<16) | (c<<24);
772 }
773 return;
774 #endif
775 #if NRASOPS8 > 0
776 case 8:
777 for (i = 0; i < 16; i++)
778 ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24);
779 return;
780 #endif
781 default:
782 break;
783 }
784
785 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
786 p = rasops_cmap;
787
788 for (i = 0; i < 16; i++) {
789 if (ri->ri_rnum <= 8)
790 c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
791 else
792 c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
793 p++;
794
795 if (ri->ri_gnum <= 8)
796 c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
797 else
798 c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
799 p++;
800
801 if (ri->ri_bnum <= 8)
802 c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
803 else
804 c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
805 p++;
806
807 /* Fill the word for generic routines, which want this */
808 if (ri->ri_depth == 24)
809 c = c | ((c & 0xff) << 24);
810 else if (ri->ri_depth <= 16)
811 c = c | (c << 16);
812
813 /* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */
814 #if NRASOPS_BSWAP > 0
815 if ((ri->ri_flg & RI_BSWAP) == 0)
816 ri->ri_devcmap[i] = c;
817 else if (ri->ri_depth == 32)
818 ri->ri_devcmap[i] = swap32(c);
819 else if (ri->ri_depth == 16 || ri->ri_depth == 15)
820 ri->ri_devcmap[i] = swap16(c);
821 else
822 ri->ri_devcmap[i] = c;
823 #else
824 ri->ri_devcmap[i] = c;
825 #endif
826 }
827 #endif
828 }
829
830 /*
831 * Unpack a rasops attribute
832 */
833 void
rasops_unpack_attr(cookie,attr,fg,bg,flags)834 rasops_unpack_attr(cookie, attr, fg, bg, flags)
835 void *cookie;
836 long attr;
837 int *fg, *bg, *flags;
838 {
839 *fg = ((u_int)attr >> 24) & 0xf;
840 *bg = ((u_int)attr >> 16) & 0xf;
841 if (flags != NULL)
842 *flags = (((u_int)attr & 1) ? WSATTR_UNDERLINE : 0) |
843 (((u_int)attr & 8) ? WSATTR_REVERSE : 0) |
844 (*fg & 8 ? WSATTR_HILIT : 0);
845 }
846
847 /*
848 * Erase rows
849 */
850 void
rasops_eraserows(cookie,row,num,attr)851 rasops_eraserows(cookie, row, num, attr)
852 void *cookie;
853 int row, num;
854 long attr;
855 {
856 struct rasops_info *ri;
857 int np, nw, cnt, delta;
858 int32_t *dp, clr;
859
860 ri = (struct rasops_info *)cookie;
861
862 #ifdef RASOPS_CLIPPING
863 if (row < 0) {
864 num += row;
865 row = 0;
866 }
867
868 if ((row + num) > ri->ri_rows)
869 num = ri->ri_rows - row;
870
871 if (num <= 0)
872 return;
873 #endif
874
875 clr = ri->ri_devcmap[(attr >> 16) & 0xf];
876
877 /*
878 * XXX The wsdisplay_emulops interface seems a little deficient in
879 * that there is no way to clear the *entire* screen. We provide a
880 * workaround here: if the entire console area is being cleared, and
881 * the RI_FULLCLEAR flag is set, clear the entire display.
882 */
883 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
884 np = ri->ri_stride >> 5;
885 nw = (ri->ri_stride >> 2) & 7;
886 num = ri->ri_height;
887 dp = (int32_t *)ri->ri_origbits;
888 delta = 0;
889 } else {
890 np = ri->ri_emustride >> 5;
891 nw = (ri->ri_emustride >> 2) & 7;
892 num *= ri->ri_font->fontheight;
893 dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
894 delta = ri->ri_delta;
895 }
896
897 while (num--) {
898 for (cnt = np; cnt; cnt--) {
899 dp[0] = clr;
900 dp[1] = clr;
901 dp[2] = clr;
902 dp[3] = clr;
903 dp[4] = clr;
904 dp[5] = clr;
905 dp[6] = clr;
906 dp[7] = clr;
907 dp += 8;
908 }
909
910 for (cnt = nw; cnt; cnt--) {
911 *(int32_t *)dp = clr;
912 DELTA(dp, 4, int32_t *);
913 }
914
915 DELTA(dp, delta, int32_t *);
916 }
917 }
918
919 /*
920 * Actually turn the cursor on or off. This does the dirty work for
921 * rasops_cursor().
922 */
923 void
rasops_do_cursor(ri)924 rasops_do_cursor(ri)
925 struct rasops_info *ri;
926 {
927 int full1, height, cnt, slop1, slop2, row, col;
928 u_char *dp, *rp;
929
930 #if NRASOPS_ROTATION > 0
931 if (ri->ri_flg & RI_ROTATE_CW) {
932 /* Rotate rows/columns */
933 row = ri->ri_ccol;
934 col = ri->ri_rows - ri->ri_crow - 1;
935 } else
936 #endif
937 {
938 row = ri->ri_crow;
939 col = ri->ri_ccol;
940 }
941
942 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
943 height = ri->ri_font->fontheight;
944 slop1 = (4 - ((long)rp & 3)) & 3;
945
946 if (slop1 > ri->ri_xscale)
947 slop1 = ri->ri_xscale;
948
949 slop2 = (ri->ri_xscale - slop1) & 3;
950 full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
951
952 if ((slop1 | slop2) == 0) {
953 /* A common case */
954 while (height--) {
955 dp = rp;
956 rp += ri->ri_stride;
957
958 for (cnt = full1; cnt; cnt--) {
959 *(int32_t *)dp ^= ~0;
960 dp += 4;
961 }
962 }
963 } else {
964 /* XXX this is stupid.. use masks instead */
965 while (height--) {
966 dp = rp;
967 rp += ri->ri_stride;
968
969 if (slop1 & 1)
970 *dp++ ^= ~0;
971
972 if (slop1 & 2) {
973 *(int16_t *)dp ^= ~0;
974 dp += 2;
975 }
976
977 for (cnt = full1; cnt; cnt--) {
978 *(int32_t *)dp ^= ~0;
979 dp += 4;
980 }
981
982 if (slop2 & 1)
983 *dp++ ^= ~0;
984
985 if (slop2 & 2)
986 *(int16_t *)dp ^= ~0;
987 }
988 }
989 }
990
991 /*
992 * Erase columns.
993 */
994 void
rasops_erasecols(cookie,row,col,num,attr)995 rasops_erasecols(cookie, row, col, num, attr)
996 void *cookie;
997 int row, col, num;
998 long attr;
999 {
1000 int n8, height, cnt, slop1, slop2, clr;
1001 struct rasops_info *ri;
1002 int32_t *rp, *dp;
1003
1004 ri = (struct rasops_info *)cookie;
1005
1006 #ifdef RASOPS_CLIPPING
1007 if ((unsigned)row >= (unsigned)ri->ri_rows)
1008 return;
1009
1010 if (col < 0) {
1011 num += col;
1012 col = 0;
1013 }
1014
1015 if ((col + num) > ri->ri_cols)
1016 num = ri->ri_cols - col;
1017
1018 if (num <= 0)
1019 return;
1020 #endif
1021
1022 num = num * ri->ri_xscale;
1023 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
1024 height = ri->ri_font->fontheight;
1025 clr = ri->ri_devcmap[(attr >> 16) & 0xf];
1026
1027 /* Don't bother using the full loop for <= 32 pels */
1028 if (num <= 32) {
1029 if (((num | ri->ri_xscale) & 3) == 0) {
1030 /* Word aligned blt */
1031 num >>= 2;
1032
1033 while (height--) {
1034 dp = rp;
1035 DELTA(rp, ri->ri_stride, int32_t *);
1036
1037 for (cnt = num; cnt; cnt--)
1038 *dp++ = clr;
1039 }
1040 } else if (((num | ri->ri_xscale) & 1) == 0) {
1041 /*
1042 * Halfword aligned blt. This is needed so the
1043 * 15/16 bit ops can use this function.
1044 */
1045 num >>= 1;
1046
1047 while (height--) {
1048 dp = rp;
1049 DELTA(rp, ri->ri_stride, int32_t *);
1050
1051 for (cnt = num; cnt; cnt--) {
1052 *(int16_t *)dp = clr;
1053 DELTA(dp, 2, int32_t *);
1054 }
1055 }
1056 } else {
1057 while (height--) {
1058 dp = rp;
1059 DELTA(rp, ri->ri_stride, int32_t *);
1060
1061 for (cnt = num; cnt; cnt--) {
1062 *(u_char *)dp = clr;
1063 DELTA(dp, 1, int32_t *);
1064 }
1065 }
1066 }
1067
1068 return;
1069 }
1070
1071 slop1 = (4 - ((long)rp & 3)) & 3;
1072 slop2 = (num - slop1) & 3;
1073 num -= slop1 + slop2;
1074 n8 = num >> 5;
1075 num = (num >> 2) & 7;
1076
1077 while (height--) {
1078 dp = rp;
1079 DELTA(rp, ri->ri_stride, int32_t *);
1080
1081 /* Align span to 4 bytes */
1082 if (slop1 & 1) {
1083 *(u_char *)dp = clr;
1084 DELTA(dp, 1, int32_t *);
1085 }
1086
1087 if (slop1 & 2) {
1088 *(int16_t *)dp = clr;
1089 DELTA(dp, 2, int32_t *);
1090 }
1091
1092 /* Write 32 bytes per loop */
1093 for (cnt = n8; cnt; cnt--) {
1094 dp[0] = clr;
1095 dp[1] = clr;
1096 dp[2] = clr;
1097 dp[3] = clr;
1098 dp[4] = clr;
1099 dp[5] = clr;
1100 dp[6] = clr;
1101 dp[7] = clr;
1102 dp += 8;
1103 }
1104
1105 /* Write 4 bytes per loop */
1106 for (cnt = num; cnt; cnt--)
1107 *dp++ = clr;
1108
1109 /* Write unaligned trailing slop */
1110 if (slop2 & 1) {
1111 *(u_char *)dp = clr;
1112 DELTA(dp, 1, int32_t *);
1113 }
1114
1115 if (slop2 & 2)
1116 *(int16_t *)dp = clr;
1117 }
1118 }
1119
1120 #if NRASOPS_ROTATION > 0
1121 /*
1122 * Quarter clockwise rotation routines (originally intended for the
1123 * built-in Zaurus C3x00 display in 16bpp).
1124 */
1125
1126 #include <sys/malloc.h>
1127
1128 void
rasops_rotate_font(int * cookie)1129 rasops_rotate_font(int *cookie)
1130 {
1131 struct rotatedfont *f;
1132 int ncookie;
1133
1134 SLIST_FOREACH(f, &rotatedfonts, rf_next) {
1135 if (f->rf_cookie == *cookie) {
1136 *cookie = f->rf_rotated;
1137 return;
1138 }
1139 }
1140
1141 /*
1142 * We did not find a rotated version of this font. Ask the wsfont
1143 * code to compute one for us.
1144 */
1145
1146 f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK);
1147 if (f == NULL)
1148 return;
1149
1150 if ((ncookie = wsfont_rotate(*cookie)) == -1)
1151 return;
1152
1153 f->rf_cookie = *cookie;
1154 f->rf_rotated = ncookie;
1155 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next);
1156
1157 *cookie = ncookie;
1158 }
1159
1160 void
rasops_copychar(cookie,srcrow,dstrow,srccol,dstcol)1161 rasops_copychar(cookie, srcrow, dstrow, srccol, dstcol)
1162 void *cookie;
1163 int srcrow, dstrow, srccol, dstcol;
1164 {
1165 struct rasops_info *ri;
1166 u_char *sp, *dp;
1167 int height;
1168 int r_srcrow, r_dstrow, r_srccol, r_dstcol;
1169
1170 ri = (struct rasops_info *)cookie;
1171
1172 r_srcrow = srccol;
1173 r_dstrow = dstcol;
1174 r_srccol = ri->ri_rows - srcrow - 1;
1175 r_dstcol = ri->ri_rows - dstrow - 1;
1176
1177 r_srcrow *= ri->ri_yscale;
1178 r_dstrow *= ri->ri_yscale;
1179 height = ri->ri_font->fontheight;
1180
1181 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale;
1182 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale;
1183
1184 #if NRASOPS_BSWAP > 0
1185 if (ri->ri_flg & RI_BSWAP) {
1186 while (height--) {
1187 slow_ovbcopy(sp, dp, ri->ri_xscale);
1188 dp += ri->ri_stride;
1189 sp += ri->ri_stride;
1190 }
1191 } else
1192 #endif
1193 {
1194 while (height--) {
1195 ovbcopy(sp, dp, ri->ri_xscale);
1196 dp += ri->ri_stride;
1197 sp += ri->ri_stride;
1198 }
1199 }
1200 }
1201
1202 void
rasops_putchar_rotated(cookie,row,col,uc,attr)1203 rasops_putchar_rotated(cookie, row, col, uc, attr)
1204 void *cookie;
1205 int row, col;
1206 u_int uc;
1207 long attr;
1208 {
1209 struct rasops_info *ri;
1210 u_char *rp;
1211 int height;
1212
1213 ri = (struct rasops_info *)cookie;
1214
1215 /* Do rotated char sans (side)underline */
1216 ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc,
1217 attr & ~1);
1218
1219 /* Do rotated underline */
1220 rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) *
1221 ri->ri_xscale;
1222 height = ri->ri_font->fontheight;
1223
1224 /* XXX this assumes 16-bit color depth */
1225 if ((attr & 1) != 0) {
1226 int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
1227
1228 while (height--) {
1229 *(int16_t *)rp = c;
1230 rp += ri->ri_stride;
1231 }
1232 }
1233 }
1234
1235 void
rasops_erasecols_rotated(cookie,row,col,num,attr)1236 rasops_erasecols_rotated(cookie, row, col, num, attr)
1237 void *cookie;
1238 int row, col, num;
1239 long attr;
1240 {
1241 struct rasops_info *ri;
1242 int i;
1243
1244 ri = (struct rasops_info *)cookie;
1245
1246 for (i = col; i < col + num; i++)
1247 ri->ri_ops.putchar(cookie, row, i, ' ', attr);
1248 }
1249
1250 /* XXX: these could likely be optimised somewhat. */
1251 void
rasops_copyrows_rotated(cookie,src,dst,num)1252 rasops_copyrows_rotated(cookie, src, dst, num)
1253 void *cookie;
1254 int src, dst, num;
1255 {
1256 struct rasops_info *ri = (struct rasops_info *)cookie;
1257 int col, roff;
1258
1259 if (src > dst)
1260 for (roff = 0; roff < num; roff++)
1261 for (col = 0; col < ri->ri_cols; col++)
1262 rasops_copychar(cookie, src + roff, dst + roff,
1263 col, col);
1264 else
1265 for (roff = num - 1; roff >= 0; roff--)
1266 for (col = 0; col < ri->ri_cols; col++)
1267 rasops_copychar(cookie, src + roff, dst + roff,
1268 col, col);
1269 }
1270
1271 void
rasops_copycols_rotated(cookie,row,src,dst,num)1272 rasops_copycols_rotated(cookie, row, src, dst, num)
1273 void *cookie;
1274 int row, src, dst, num;
1275 {
1276 int coff;
1277
1278 if (src > dst)
1279 for (coff = 0; coff < num; coff++)
1280 rasops_copychar(cookie, row, row, src + coff, dst + coff);
1281 else
1282 for (coff = num - 1; coff >= 0; coff--)
1283 rasops_copychar(cookie, row, row, src + coff, dst + coff);
1284 }
1285
1286 void
rasops_eraserows_rotated(cookie,row,num,attr)1287 rasops_eraserows_rotated(cookie, row, num, attr)
1288 void *cookie;
1289 int row, num;
1290 long attr;
1291 {
1292 struct rasops_info *ri;
1293 int col, rn;
1294
1295 ri = (struct rasops_info *)cookie;
1296
1297 for (rn = row; rn < row + num; rn++)
1298 for (col = 0; col < ri->ri_cols; col++)
1299 ri->ri_ops.putchar(cookie, rn, col, ' ', attr);
1300 }
1301 #endif /* NRASOPS_ROTATION */
1302
1303 #if NRASOPS_BSWAP > 0
1304 /*
1305 * Strictly byte-only ovbcopy() version, to be used with RI_BSWAP, as the
1306 * regular ovbcopy() may want to optimize things by doing larger-than-byte
1307 * reads or write. This may confuse things if src and dst have different
1308 * alignments.
1309 */
1310 void
slow_ovbcopy(void * s,void * d,size_t len)1311 slow_ovbcopy(void *s, void *d, size_t len)
1312 {
1313 u_int8_t *src = s;
1314 u_int8_t *dst = d;
1315
1316 if ((vaddr_t)dst <= (vaddr_t)src) {
1317 while (len-- != 0)
1318 *dst++ = *src++;
1319 } else {
1320 src += len;
1321 dst += len;
1322 if (len != 0)
1323 while (--len != 0)
1324 *--dst = *--src;
1325 }
1326 }
1327 #endif /* NRASOPS_BSWAP */
1328