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