1 /* $NetBSD: rasops24.c,v 1.26 2009/03/14 15:36:20 dsl Exp $ */
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: rasops24.c,v 1.26 2009/03/14 15:36:20 dsl Exp $");
35 #include "opt_rasops.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
41 #include <machine/endian.h>
42 #include <sys/bswap.h>
44 #include <dev/wscons/wsdisplayvar.h>
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/rasops/rasops.h>
48 static void rasops24_erasecols(void *, int, int, int, long);
49 static void rasops24_eraserows(void *, int, int, long);
50 static void rasops24_putchar(void *, int, int, u_int
, long attr
);
52 static void rasops24_putchar8(void *, int, int, u_int
, long attr
);
53 static void rasops24_putchar12(void *, int, int, u_int
, long attr
);
54 static void rasops24_putchar16(void *, int, int, u_int
, long attr
);
55 static void rasops24_makestamp(struct rasops_info
*, long);
59 * 4x1 stamp for optimized character blitting
61 static int32_t stamp
[64];
62 static long stamp_attr
;
63 static int stamp_mutex
; /* XXX see note in readme */
66 * XXX this confuses the hell out of gcc2 (not egcs) which always insists
67 * that the shift count is negative.
69 * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK
70 * destination int32_t[0] = STAMP_READ(offset)
71 * destination int32_t[1] = STAMP_READ(offset + 4)
72 * destination int32_t[2] = STAMP_READ(offset + 8)
74 #define STAMP_SHIFT(fb,n) ((n*4-4) >= 0 ? (fb)>>(n*4-4):(fb)<<-(n*4-4))
75 #define STAMP_MASK (0xf << 4)
76 #define STAMP_READ(o) (*(int32_t *)((char *)stamp + (o)))
79 * Initialize rasops_info struct for this colordepth.
82 rasops24_init(struct rasops_info
*ri
)
85 switch (ri
->ri_font
->fontwidth
) {
88 ri
->ri_ops
.putchar
= rasops24_putchar8
;
91 ri
->ri_ops
.putchar
= rasops24_putchar12
;
94 ri
->ri_ops
.putchar
= rasops24_putchar16
;
98 ri
->ri_ops
.putchar
= rasops24_putchar
;
102 if (ri
->ri_rnum
== 0) {
111 ri
->ri_ops
.erasecols
= rasops24_erasecols
;
112 ri
->ri_ops
.eraserows
= rasops24_eraserows
;
116 * Put a single character. This is the generic version.
117 * XXX this bites - we should use masks.
120 rasops24_putchar(void *cookie
, int row
, int col
, u_int uc
, long attr
)
122 int fb
, width
, height
, cnt
, clr
[2];
123 struct rasops_info
*ri
;
124 u_char
*dp
, *rp
, *fr
;
126 ri
= (struct rasops_info
*)cookie
;
128 #ifdef RASOPS_CLIPPING
129 /* Catches 'row < 0' case too */
130 if ((unsigned)row
>= (unsigned)ri
->ri_rows
)
133 if ((unsigned)col
>= (unsigned)ri
->ri_cols
)
137 rp
= ri
->ri_bits
+ row
* ri
->ri_yscale
+ col
* ri
->ri_xscale
;
138 height
= ri
->ri_font
->fontheight
;
139 width
= ri
->ri_font
->fontwidth
;
141 clr
[1] = ri
->ri_devcmap
[((u_int
)attr
>> 24) & 0xf];
142 clr
[0] = ri
->ri_devcmap
[((u_int
)attr
>> 16) & 0xf];
150 for (cnt
= width
; cnt
; cnt
--) {
157 uc
-= ri
->ri_font
->firstchar
;
158 fr
= (u_char
*)ri
->ri_font
->data
+ uc
* ri
->ri_fontscale
;
162 fb
= fr
[3] | (fr
[2] << 8) | (fr
[1] << 16) |
164 fr
+= ri
->ri_font
->stride
;
167 for (cnt
= width
; cnt
; cnt
--, fb
<<= 1) {
168 if ((fb
>> 31) & 1) {
169 *dp
++ = clr
[1] >> 16;
173 *dp
++ = clr
[0] >> 16;
182 if ((attr
& 1) != 0) {
185 rp
-= ri
->ri_stride
<< 1;
197 * Recompute the blitting stamp.
200 rasops24_makestamp(struct rasops_info
*ri
, long attr
)
202 u_int fg
, bg
, c1
, c2
, c3
, c4
;
205 fg
= ri
->ri_devcmap
[((u_int
)attr
>> 24) & 0xf] & 0xffffff;
206 bg
= ri
->ri_devcmap
[((u_int
)attr
>> 16) & 0xf] & 0xffffff;
209 for (i
= 0; i
< 64; i
+= 4) {
210 #if BYTE_ORDER == LITTLE_ENDIAN
211 c1
= (i
& 32 ? fg
: bg
);
212 c2
= (i
& 16 ? fg
: bg
);
213 c3
= (i
& 8 ? fg
: bg
);
214 c4
= (i
& 4 ? fg
: bg
);
216 c1
= (i
& 8 ? fg
: bg
);
217 c2
= (i
& 4 ? fg
: bg
);
218 c3
= (i
& 16 ? fg
: bg
);
219 c4
= (i
& 32 ? fg
: bg
);
221 stamp
[i
+0] = (c1
<< 8) | (c2
>> 16);
222 stamp
[i
+1] = (c2
<< 16) | (c3
>> 8);
223 stamp
[i
+2] = (c3
<< 24) | c4
;
225 #if BYTE_ORDER == LITTLE_ENDIAN
226 if ((ri
->ri_flg
& RI_BSWAP
) == 0) {
228 if ((ri
->ri_flg
& RI_BSWAP
) != 0) {
230 stamp
[i
+0] = bswap32(stamp
[i
+0]);
231 stamp
[i
+1] = bswap32(stamp
[i
+1]);
232 stamp
[i
+2] = bswap32(stamp
[i
+2]);
238 * Put a single character. This is for 8-pixel wide fonts.
241 rasops24_putchar8(void *cookie
, int row
, int col
, u_int uc
, long attr
)
243 struct rasops_info
*ri
;
248 /* Can't risk remaking the stamp if it's already in use */
251 rasops24_putchar(cookie
, row
, col
, uc
, attr
);
255 ri
= (struct rasops_info
*)cookie
;
257 #ifdef RASOPS_CLIPPING
258 if ((unsigned)row
>= (unsigned)ri
->ri_rows
) {
263 if ((unsigned)col
>= (unsigned)ri
->ri_cols
) {
269 /* Recompute stamp? */
270 if (attr
!= stamp_attr
)
271 rasops24_makestamp(ri
, attr
);
273 rp
= (int32_t *)(ri
->ri_bits
+ row
*ri
->ri_yscale
+ col
*ri
->ri_xscale
);
274 height
= ri
->ri_font
->fontheight
;
276 if (uc
== (u_int
)-1) {
277 int32_t c
= stamp
[0];
279 rp
[0] = rp
[1] = rp
[2] = rp
[3] = rp
[4] = rp
[5] = c
;
280 DELTA(rp
, ri
->ri_stride
, int32_t *);
283 uc
-= ri
->ri_font
->firstchar
;
284 fr
= (u_char
*)ri
->ri_font
->data
+ uc
*ri
->ri_fontscale
;
285 fs
= ri
->ri_font
->stride
;
288 so
= STAMP_SHIFT(fr
[0], 1) & STAMP_MASK
;
289 rp
[0] = STAMP_READ(so
);
290 rp
[1] = STAMP_READ(so
+ 4);
291 rp
[2] = STAMP_READ(so
+ 8);
293 so
= STAMP_SHIFT(fr
[0], 0) & STAMP_MASK
;
294 rp
[3] = STAMP_READ(so
);
295 rp
[4] = STAMP_READ(so
+ 4);
296 rp
[5] = STAMP_READ(so
+ 8);
299 DELTA(rp
, ri
->ri_stride
, int32_t *);
304 if ((attr
& 1) != 0) {
305 int32_t c
= STAMP_READ(52);
307 DELTA(rp
, -(ri
->ri_stride
<< 1), int32_t *);
308 rp
[0] = rp
[1] = rp
[2] = rp
[3] = rp
[4] = rp
[5] = c
;
315 * Put a single character. This is for 12-pixel wide fonts.
318 rasops24_putchar12(void *cookie
, int row
, int col
, u_int uc
, long attr
)
320 struct rasops_info
*ri
;
325 /* Can't risk remaking the stamp if it's already in use */
328 rasops24_putchar(cookie
, row
, col
, uc
, attr
);
332 ri
= (struct rasops_info
*)cookie
;
334 #ifdef RASOPS_CLIPPING
335 if ((unsigned)row
>= (unsigned)ri
->ri_rows
) {
340 if ((unsigned)col
>= (unsigned)ri
->ri_cols
) {
346 /* Recompute stamp? */
347 if (attr
!= stamp_attr
)
348 rasops24_makestamp(ri
, attr
);
350 rp
= (int32_t *)(ri
->ri_bits
+ row
*ri
->ri_yscale
+ col
*ri
->ri_xscale
);
351 height
= ri
->ri_font
->fontheight
;
353 if (uc
== (u_int
)-1) {
354 int32_t c
= stamp
[0];
356 rp
[0] = rp
[1] = rp
[2] = rp
[3] =
357 rp
[4] = rp
[5] = rp
[6] = rp
[7] = rp
[8] = c
;
358 DELTA(rp
, ri
->ri_stride
, int32_t *);
361 uc
-= ri
->ri_font
->firstchar
;
362 fr
= (u_char
*)ri
->ri_font
->data
+ uc
*ri
->ri_fontscale
;
363 fs
= ri
->ri_font
->stride
;
366 so
= STAMP_SHIFT(fr
[0], 1) & STAMP_MASK
;
367 rp
[0] = STAMP_READ(so
);
368 rp
[1] = STAMP_READ(so
+ 4);
369 rp
[2] = STAMP_READ(so
+ 8);
371 so
= STAMP_SHIFT(fr
[0], 0) & STAMP_MASK
;
372 rp
[3] = STAMP_READ(so
);
373 rp
[4] = STAMP_READ(so
+ 4);
374 rp
[5] = STAMP_READ(so
+ 8);
376 so
= STAMP_SHIFT(fr
[1], 1) & STAMP_MASK
;
377 rp
[6] = STAMP_READ(so
);
378 rp
[7] = STAMP_READ(so
+ 4);
379 rp
[8] = STAMP_READ(so
+ 8);
382 DELTA(rp
, ri
->ri_stride
, int32_t *);
387 if ((attr
& 1) != 0) {
388 int32_t c
= STAMP_READ(52);
390 DELTA(rp
, -(ri
->ri_stride
<< 1), int32_t *);
391 rp
[0] = rp
[1] = rp
[2] = rp
[3] =
392 rp
[4] = rp
[5] = rp
[6] = rp
[7] = rp
[8] = c
;
399 * Put a single character. This is for 16-pixel wide fonts.
402 rasops24_putchar16(void *cookie
, int row
, int col
, u_int uc
, long attr
)
404 struct rasops_info
*ri
;
409 /* Can't risk remaking the stamp if it's already in use */
412 rasops24_putchar(cookie
, row
, col
, uc
, attr
);
416 ri
= (struct rasops_info
*)cookie
;
418 #ifdef RASOPS_CLIPPING
419 if ((unsigned)row
>= (unsigned)ri
->ri_rows
) {
424 if ((unsigned)col
>= (unsigned)ri
->ri_cols
) {
430 /* Recompute stamp? */
431 if (attr
!= stamp_attr
)
432 rasops24_makestamp(ri
, attr
);
434 rp
= (int32_t *)(ri
->ri_bits
+ row
*ri
->ri_yscale
+ col
*ri
->ri_xscale
);
435 height
= ri
->ri_font
->fontheight
;
437 if (uc
== (u_int
)-1) {
438 int32_t c
= stamp
[0];
440 rp
[0] = rp
[1] = rp
[2] = rp
[3] =
441 rp
[4] = rp
[5] = rp
[6] = rp
[7] =
442 rp
[8] = rp
[9] = rp
[10] = rp
[11] = c
;
443 DELTA(rp
, ri
->ri_stride
, int32_t *);
446 uc
-= ri
->ri_font
->firstchar
;
447 fr
= (u_char
*)ri
->ri_font
->data
+ uc
*ri
->ri_fontscale
;
448 fs
= ri
->ri_font
->stride
;
451 so
= STAMP_SHIFT(fr
[0], 1) & STAMP_MASK
;
452 rp
[0] = STAMP_READ(so
);
453 rp
[1] = STAMP_READ(so
+ 4);
454 rp
[2] = STAMP_READ(so
+ 8);
456 so
= STAMP_SHIFT(fr
[0], 0) & STAMP_MASK
;
457 rp
[3] = STAMP_READ(so
);
458 rp
[4] = STAMP_READ(so
+ 4);
459 rp
[5] = STAMP_READ(so
+ 8);
461 so
= STAMP_SHIFT(fr
[1], 1) & STAMP_MASK
;
462 rp
[6] = STAMP_READ(so
);
463 rp
[7] = STAMP_READ(so
+ 4);
464 rp
[8] = STAMP_READ(so
+ 8);
466 so
= STAMP_SHIFT(fr
[1], 0) & STAMP_MASK
;
467 rp
[9] = STAMP_READ(so
);
468 rp
[10] = STAMP_READ(so
+ 4);
469 rp
[11] = STAMP_READ(so
+ 8);
471 DELTA(rp
, ri
->ri_stride
, int32_t *);
477 if ((attr
& 1) != 0) {
478 int32_t c
= STAMP_READ(52);
480 DELTA(rp
, -(ri
->ri_stride
<< 1), int32_t *);
481 rp
[0] = rp
[1] = rp
[2] = rp
[3] =
482 rp
[4] = rp
[5] = rp
[6] = rp
[7] =
483 rp
[8] = rp
[9] = rp
[10] = rp
[11] = c
;
488 #endif /* !RASOPS_SMALL */
491 * Erase rows. This is nice and easy due to alignment.
494 rasops24_eraserows(void *cookie
, int row
, int num
, long attr
)
496 int n9
, n3
, n1
, cnt
, stride
, delta
;
497 u_int32_t
*dp
, clr
, xstamp
[3];
498 struct rasops_info
*ri
;
501 * If the color is gray, we can cheat and use the generic routines
502 * (which are faster, hopefully) since the r,g,b values are the same.
504 if ((attr
& 4) != 0) {
505 rasops_eraserows(cookie
, row
, num
, attr
);
509 ri
= (struct rasops_info
*)cookie
;
511 #ifdef RASOPS_CLIPPING
517 if ((row
+ num
) > ri
->ri_rows
)
518 num
= ri
->ri_rows
- row
;
524 clr
= ri
->ri_devcmap
[(attr
>> 16) & 0xf] & 0xffffff;
525 xstamp
[0] = (clr
<< 8) | (clr
>> 16);
526 xstamp
[1] = (clr
<< 16) | (clr
>> 8);
527 xstamp
[2] = (clr
<< 24) | clr
;
529 #if BYTE_ORDER == LITTLE_ENDIAN
530 if ((ri
->ri_flg
& RI_BSWAP
) == 0) {
532 if ((ri
->ri_flg
& RI_BSWAP
) != 0) {
534 xstamp
[0] = bswap32(xstamp
[0]);
535 xstamp
[1] = bswap32(xstamp
[1]);
536 xstamp
[2] = bswap32(xstamp
[2]);
540 * XXX the wsdisplay_emulops interface seems a little deficient in
541 * that there is no way to clear the *entire* screen. We provide a
542 * workaround here: if the entire console area is being cleared, and
543 * the RI_FULLCLEAR flag is set, clear the entire display.
545 if (num
== ri
->ri_rows
&& (ri
->ri_flg
& RI_FULLCLEAR
) != 0) {
546 stride
= ri
->ri_stride
;
548 dp
= (int32_t *)ri
->ri_origbits
;
551 stride
= ri
->ri_emustride
;
552 num
*= ri
->ri_font
->fontheight
;
553 dp
= (int32_t *)(ri
->ri_bits
+ row
* ri
->ri_yscale
);
554 delta
= ri
->ri_delta
;
558 cnt
= (n9
<< 5) + (n9
<< 2); /* (32*n9) + (4*n9) */
559 n3
= (stride
- cnt
) / 12;
560 cnt
+= (n3
<< 3) + (n3
<< 2); /* (8*n3) + (4*n3) */
561 n1
= (stride
- cnt
) >> 2;
564 for (cnt
= n9
; cnt
; cnt
--) {
577 for (cnt
= n3
; cnt
; cnt
--) {
584 for (cnt
= 0; cnt
< n1
; cnt
++)
587 DELTA(dp
, delta
, int32_t *);
595 rasops24_erasecols(void *cookie
, int row
, int col
, int num
, long attr
)
597 int n12
, n4
, height
, cnt
, slop
, clr
, xstamp
[3];
598 struct rasops_info
*ri
;
603 * If the color is gray, we can cheat and use the generic routines
604 * (which are faster, hopefully) since the r,g,b values are the same.
606 if ((attr
& 4) != 0) {
607 rasops_erasecols(cookie
, row
, col
, num
, attr
);
611 ri
= (struct rasops_info
*)cookie
;
613 #ifdef RASOPS_CLIPPING
614 /* Catches 'row < 0' case too */
615 if ((unsigned)row
>= (unsigned)ri
->ri_rows
)
623 if ((col
+ num
) > ri
->ri_cols
)
624 num
= ri
->ri_cols
- col
;
630 rp
= (int32_t *)(ri
->ri_bits
+ row
*ri
->ri_yscale
+ col
*ri
->ri_xscale
);
631 num
*= ri
->ri_font
->fontwidth
;
632 height
= ri
->ri_font
->fontheight
;
634 clr
= ri
->ri_devcmap
[(attr
>> 16) & 0xf] & 0xffffff;
635 xstamp
[0] = (clr
<< 8) | (clr
>> 16);
636 xstamp
[1] = (clr
<< 16) | (clr
>> 8);
637 xstamp
[2] = (clr
<< 24) | clr
;
639 #if BYTE_ORDER == LITTLE_ENDIAN
640 if ((ri
->ri_flg
& RI_BSWAP
) == 0) {
642 if ((ri
->ri_flg
& RI_BSWAP
) != 0) {
644 xstamp
[0] = bswap32(xstamp
[0]);
645 xstamp
[1] = bswap32(xstamp
[1]);
646 xstamp
[2] = bswap32(xstamp
[2]);
650 * The current byte offset mod 4 tells us the number of 24-bit pels
651 * we need to write for alignment to 32-bits. Once we're aligned on
652 * a 32-bit boundary, we're also aligned on a 4 pixel boundary, so
653 * the stamp does not need to be rotated. The following shows the
654 * layout of 4 pels in a 3 word region and illustrates this:
658 slop
= (int)(long)rp
& 3; num
-= slop
;
659 n12
= num
/ 12; num
-= (n12
<< 3) + (n12
<< 2);
660 n4
= num
>> 2; num
&= 3;
664 DELTA(rp
, ri
->ri_stride
, int32_t *);
666 /* Align to 4 bytes */
667 /* XXX handle with masks, bring under control of RI_BSWAP */
668 for (cnt
= slop
; cnt
; cnt
--) {
669 *dbp
++ = (clr
>> 16);
676 /* 12 pels per loop */
677 for (cnt
= n12
; cnt
; cnt
--) {
690 /* 4 pels per loop */
691 for (cnt
= n4
; cnt
; cnt
--) {
699 /* XXX handle with masks, bring under control of RI_BSWAP */
701 for (cnt
= num
; cnt
; cnt
--) {
702 *dbp
++ = (clr
>> 16);