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