rasops.c revision 1.59
1/* $NetBSD: rasops.c,v 1.59 2009/03/14 15:36:20 dsl 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.59 2009/03/14 15:36:20 dsl 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(void *cookie, int c, u_int *cp) 389{ 390 struct rasops_info *ri; 391 392 ri = (struct rasops_info *)cookie; 393 394#ifdef DIAGNOSTIC 395 if (ri->ri_font == NULL) 396 panic("rasops_mapchar: no font selected"); 397#endif 398 399 if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) { 400 if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) { 401 *cp = ' '; 402 return (0); 403 404 } 405 } 406 407 if (c < ri->ri_font->firstchar) { 408 *cp = ' '; 409 return (0); 410 } 411 412 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) { 413 *cp = ' '; 414 return (0); 415 } 416 417 *cp = c; 418 return (5); 419} 420 421/* 422 * Allocate a color attribute. 423 */ 424static int 425rasops_allocattr_color(void *cookie, int fg, int bg, int flg, 426 long *attr) 427{ 428 int swap; 429 430 if (__predict_false((unsigned int)fg >= sizeof(rasops_isgray) || 431 (unsigned int)bg >= sizeof(rasops_isgray))) 432 return (EINVAL); 433 434#ifdef RASOPS_CLIPPING 435 fg &= 7; 436 bg &= 7; 437#endif 438 if ((flg & WSATTR_BLINK) != 0) 439 return (EINVAL); 440 441 if ((flg & WSATTR_WSCOLORS) == 0) { 442#ifdef WS_DEFAULT_FG 443 fg = WS_DEFAULT_FG; 444#else 445 fg = WSCOL_WHITE; 446#endif 447#ifdef WS_DEFAULT_BG 448 bg = WS_DEFAULT_BG; 449#else 450 bg = WSCOL_BLACK; 451#endif 452 } 453 454 if ((flg & WSATTR_REVERSE) != 0) { 455 swap = fg; 456 fg = bg; 457 bg = swap; 458 } 459 460 if ((flg & WSATTR_HILIT) != 0) 461 fg += 8; 462 463 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); 464 465 if (rasops_isgray[fg]) 466 flg |= 2; 467 468 if (rasops_isgray[bg]) 469 flg |= 4; 470 471 *attr = (bg << 16) | (fg << 24) | flg; 472 return (0); 473} 474 475/* 476 * Allocate a mono attribute. 477 */ 478static int 479rasops_allocattr_mono(void *cookie, int fg, int bg, int flg, 480 long *attr) 481{ 482 int swap; 483 484 if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0) 485 return (EINVAL); 486 487 fg = 1; 488 bg = 0; 489 490 if ((flg & WSATTR_REVERSE) != 0) { 491 swap = fg; 492 fg = bg; 493 bg = swap; 494 } 495 496 *attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6); 497 return (0); 498} 499 500/* 501 * Copy rows. 502 */ 503static void 504rasops_copyrows(cookie, src, dst, num) 505 void *cookie; 506 int src, dst, 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 */ 615void 616rasops_copycols(cookie, row, src, dst, num) 617 void *cookie; 618 int row, src, dst, num; 619{ 620 struct rasops_info *ri; 621 u_char *sp, *dp, *hp; 622 int height; 623 624 ri = (struct rasops_info *)cookie; 625 hp = NULL; 626 627#ifdef RASOPS_CLIPPING 628 if (dst == src) 629 return; 630 631 /* Catches < 0 case too */ 632 if ((unsigned)row >= (unsigned)ri->ri_rows) 633 return; 634 635 if (src < 0) { 636 num += src; 637 src = 0; 638 } 639 640 if ((src + num) > ri->ri_cols) 641 num = ri->ri_cols - src; 642 643 if (dst < 0) { 644 num += dst; 645 dst = 0; 646 } 647 648 if ((dst + num) > ri->ri_cols) 649 num = ri->ri_cols - dst; 650 651 if (num <= 0) 652 return; 653#endif 654 655 num *= ri->ri_xscale; 656 row *= ri->ri_yscale; 657 height = ri->ri_font->fontheight; 658 659 sp = ri->ri_bits + row + src * ri->ri_xscale; 660 dp = ri->ri_bits + row + dst * ri->ri_xscale; 661 if (ri->ri_hwbits) 662 hp = ri->ri_hwbits + row + dst * ri->ri_xscale; 663 664 while (height--) { 665 memmove(dp, sp, num); 666 if (ri->ri_hwbits) { 667 memcpy(hp, sp, num); 668 hp += ri->ri_stride; 669 } 670 dp += ri->ri_stride; 671 sp += ri->ri_stride; 672 } 673} 674 675/* 676 * Turn cursor off/on. 677 */ 678static void 679rasops_cursor(cookie, on, row, col) 680 void *cookie; 681 int on, row, col; 682{ 683 struct rasops_info *ri; 684 685 ri = (struct rasops_info *)cookie; 686 687 /* Turn old cursor off */ 688 if ((ri->ri_flg & RI_CURSOR) != 0) 689#ifdef RASOPS_CLIPPING 690 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 691#endif 692 ri->ri_do_cursor(ri); 693 694 /* Select new cursor */ 695#ifdef RASOPS_CLIPPING 696 ri->ri_flg &= ~RI_CURSORCLIP; 697 698 if (row < 0 || row >= ri->ri_rows) 699 ri->ri_flg |= RI_CURSORCLIP; 700 else if (col < 0 || col >= ri->ri_cols) 701 ri->ri_flg |= RI_CURSORCLIP; 702#endif 703 ri->ri_crow = row; 704 ri->ri_ccol = col; 705 706 if (on) { 707 ri->ri_flg |= RI_CURSOR; 708#ifdef RASOPS_CLIPPING 709 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 710#endif 711 ri->ri_do_cursor(ri); 712 } else 713 ri->ri_flg &= ~RI_CURSOR; 714} 715 716/* 717 * Make the device colormap 718 */ 719static void 720rasops_init_devcmap(struct rasops_info *ri) 721{ 722 const u_char *p; 723 int i, c; 724 725 switch (ri->ri_depth) { 726 case 1: 727 ri->ri_devcmap[0] = 0; 728 for (i = 1; i < 16; i++) 729 ri->ri_devcmap[i] = -1; 730 return; 731 732 case 2: 733 for (i = 1; i < 15; i++) 734 ri->ri_devcmap[i] = 0xaaaaaaaa; 735 736 ri->ri_devcmap[0] = 0; 737 ri->ri_devcmap[8] = 0x55555555; 738 ri->ri_devcmap[15] = -1; 739 return; 740 741 case 8: 742 for (i = 0; i < 16; i++) 743 ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24); 744 return; 745 } 746 747 p = rasops_cmap; 748 749 for (i = 0; i < 16; i++) { 750 if (ri->ri_rnum <= 8) 751 c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 752 else 753 c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 754 p++; 755 756 if (ri->ri_gnum <= 8) 757 c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 758 else 759 c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 760 p++; 761 762 if (ri->ri_bnum <= 8) 763 c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 764 else 765 c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 766 p++; 767 768 /* Fill the word for generic routines, which want this */ 769 if (ri->ri_depth == 24) 770 c = c | ((c & 0xff) << 24); 771 else if (ri->ri_depth <= 16) 772 c = c | (c << 16); 773 774 /* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */ 775 if ((ri->ri_flg & RI_BSWAP) == 0) 776 ri->ri_devcmap[i] = c; 777 else if (ri->ri_depth == 32) 778 ri->ri_devcmap[i] = bswap32(c); 779 else if (ri->ri_depth == 16 || ri->ri_depth == 15) 780 ri->ri_devcmap[i] = bswap16(c); 781 else 782 ri->ri_devcmap[i] = c; 783 } 784} 785 786/* 787 * Unpack a rasops attribute 788 */ 789void 790rasops_unpack_attr(attr, fg, bg, underline) 791 long attr; 792 int *fg, *bg, *underline; 793{ 794 795 *fg = ((u_int)attr >> 24) & 0xf; 796 *bg = ((u_int)attr >> 16) & 0xf; 797 if (underline != NULL) 798 *underline = (u_int)attr & 1; 799} 800 801/* 802 * Erase rows. This isn't static, since 24-bpp uses it in special cases. 803 */ 804void 805rasops_eraserows(cookie, row, num, attr) 806 void *cookie; 807 int row, num; 808 long attr; 809{ 810 struct rasops_info *ri; 811 int np, nw, cnt, delta; 812 int32_t *dp, *hp, clr; 813 int i; 814 815 ri = (struct rasops_info *)cookie; 816 hp = NULL; 817 818#ifdef RASOPS_CLIPPING 819 if (row < 0) { 820 num += row; 821 row = 0; 822 } 823 824 if ((row + num) > ri->ri_rows) 825 num = ri->ri_rows - row; 826 827 if (num <= 0) 828 return; 829#endif 830 831 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 832 833 /* 834 * XXX The wsdisplay_emulops interface seems a little deficient in 835 * that there is no way to clear the *entire* screen. We provide a 836 * workaround here: if the entire console area is being cleared, and 837 * the RI_FULLCLEAR flag is set, clear the entire display. 838 */ 839 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 840 np = ri->ri_stride >> 5; 841 nw = (ri->ri_stride >> 2) & 7; 842 num = ri->ri_height; 843 dp = (int32_t *)ri->ri_origbits; 844 if (ri->ri_hwbits) 845 hp = (int32_t *)ri->ri_hwbits; 846 delta = 0; 847 } else { 848 np = ri->ri_emustride >> 5; 849 nw = (ri->ri_emustride >> 2) & 7; 850 num *= ri->ri_font->fontheight; 851 dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale); 852 if (ri->ri_hwbits) 853 hp = (int32_t *)(ri->ri_hwbits + row * 854 ri->ri_yscale); 855 delta = ri->ri_delta; 856 } 857 858 while (num--) { 859 for (cnt = np; cnt; cnt--) { 860 for (i = 0; i < 8; i++) { 861 dp[i] = clr; 862 if (ri->ri_hwbits) 863 hp[i] = clr; 864 } 865 dp += 8; 866 if (ri->ri_hwbits) 867 hp += 8; 868 } 869 870 for (cnt = nw; cnt; cnt--) { 871 *(int32_t *)dp = clr; 872 DELTA(dp, 4, int32_t *); 873 if (ri->ri_hwbits) { 874 *(int32_t *)hp = clr; 875 DELTA(hp, 4, int32_t *); 876 } 877 } 878 879 DELTA(dp, delta, int32_t *); 880 if (ri->ri_hwbits) 881 DELTA(hp, delta, int32_t *); 882 } 883} 884 885/* 886 * Actually turn the cursor on or off. This does the dirty work for 887 * rasops_cursor(). 888 */ 889static void 890rasops_do_cursor(struct rasops_info *ri) 891{ 892 int full1, height, cnt, slop1, slop2, row, col; 893 u_char *dp, *rp, *hrp, *hp; 894 895 hrp = hp = NULL; 896 897#if NRASOPS_ROTATION > 0 898 if (ri->ri_flg & RI_ROTATE_CW) { 899 /* Rotate rows/columns */ 900 row = ri->ri_ccol; 901 col = ri->ri_rows - ri->ri_crow - 1; 902 } else 903#endif 904 { 905 row = ri->ri_crow; 906 col = ri->ri_ccol; 907 } 908 909 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 910 if (ri->ri_hwbits) 911 hrp = ri->ri_hwbits + row * ri->ri_yscale + col 912 * ri->ri_xscale; 913 height = ri->ri_font->fontheight; 914 slop1 = (4 - ((long)rp & 3)) & 3; 915 916 if (slop1 > ri->ri_xscale) 917 slop1 = ri->ri_xscale; 918 919 slop2 = (ri->ri_xscale - slop1) & 3; 920 full1 = (ri->ri_xscale - slop1 - slop2) >> 2; 921 922 if ((slop1 | slop2) == 0) { 923 /* A common case */ 924 while (height--) { 925 dp = rp; 926 rp += ri->ri_stride; 927 if (ri->ri_hwbits) { 928 hp = hrp; 929 hrp += ri->ri_stride; 930 } 931 932 for (cnt = full1; cnt; cnt--) { 933 *(int32_t *)dp ^= ~0; 934 dp += 4; 935 if (ri->ri_hwbits) { 936 dp -= 4; 937 *(int32_t *)hp = *(int32_t *)dp; 938 hp += 4; 939 dp += 4; 940 } 941 } 942 } 943 } else { 944 /* XXX this is stupid.. use masks instead */ 945 while (height--) { 946 dp = rp; 947 rp += ri->ri_stride; 948 if (ri->ri_hwbits) { 949 hp = hrp; 950 hrp += ri->ri_stride; 951 } 952 953 if (slop1 & 1) { 954 *dp++ ^= ~0; 955 if (ri->ri_hwbits) { 956 *hp++ = *(dp - 1); 957 } 958 } 959 960 if (slop1 & 2) { 961 *(int16_t *)dp ^= ~0; 962 dp += 2; 963 if (ri->ri_hwbits) { 964 dp -= 2; 965 *(int16_t *)hp = *(int16_t *)dp; 966 hp += 2; 967 dp += 2; 968 } 969 } 970 971 for (cnt = full1; cnt; cnt--) { 972 *(int32_t *)dp ^= ~0; 973 dp += 4; 974 if (ri->ri_hwbits) { 975 dp -= 4; 976 *(int32_t *)hp = *(int32_t *)dp; 977 hp += 4; 978 dp += 4; 979 } 980 } 981 982 if (slop2 & 1) { 983 *dp++ ^= ~0; 984 if (ri->ri_hwbits) 985 *hp++ = *(dp - 1); 986 } 987 988 if (slop2 & 2) { 989 *(int16_t *)dp ^= ~0; 990 if (ri->ri_hwbits) 991 *(int16_t *)hp = *(int16_t *)(dp - 2); 992 } 993 } 994 } 995} 996 997/* 998 * Erase columns. 999 */ 1000void 1001rasops_erasecols(cookie, row, col, num, attr) 1002 void *cookie; 1003 int row, col, num; 1004 long attr; 1005{ 1006 int n8, height, cnt, slop1, slop2, clr; 1007 struct rasops_info *ri; 1008 int32_t *rp, *dp, *hrp, *hp; 1009 int i; 1010 1011 ri = (struct rasops_info *)cookie; 1012 hrp = hp = NULL; 1013 1014#ifdef RASOPS_CLIPPING 1015 if ((unsigned)row >= (unsigned)ri->ri_rows) 1016 return; 1017 1018 if (col < 0) { 1019 num += col; 1020 col = 0; 1021 } 1022 1023 if ((col + num) > ri->ri_cols) 1024 num = ri->ri_cols - col; 1025 1026 if (num <= 0) 1027 return; 1028#endif 1029 1030 num = num * ri->ri_xscale; 1031 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 1032 if (ri->ri_hwbits) 1033 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 1034 col*ri->ri_xscale); 1035 height = ri->ri_font->fontheight; 1036 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 1037 1038 /* Don't bother using the full loop for <= 32 pels */ 1039 if (num <= 32) { 1040 if (((num | ri->ri_xscale) & 3) == 0) { 1041 /* Word aligned blt */ 1042 num >>= 2; 1043 1044 while (height--) { 1045 dp = rp; 1046 DELTA(rp, ri->ri_stride, int32_t *); 1047 if (ri->ri_hwbits) { 1048 hp = hrp; 1049 DELTA(hrp, ri->ri_stride, int32_t *); 1050 } 1051 1052 for (cnt = num; cnt; cnt--) { 1053 *dp++ = clr; 1054 if (ri->ri_hwbits) 1055 *hp++ = clr; 1056 } 1057 } 1058 } else if (((num | ri->ri_xscale) & 1) == 0) { 1059 /* 1060 * Halfword aligned blt. This is needed so the 1061 * 15/16 bit ops can use this function. 1062 */ 1063 num >>= 1; 1064 1065 while (height--) { 1066 dp = rp; 1067 DELTA(rp, ri->ri_stride, int32_t *); 1068 if (ri->ri_hwbits) { 1069 hp = hrp; 1070 DELTA(hrp, ri->ri_stride, int32_t *); 1071 } 1072 1073 for (cnt = num; cnt; cnt--) { 1074 *(int16_t *)dp = clr; 1075 DELTA(dp, 2, int32_t *); 1076 if (ri->ri_hwbits) { 1077 *(int16_t *)hp = clr; 1078 DELTA(hp, 2, int32_t *); 1079 } 1080 } 1081 } 1082 } else { 1083 while (height--) { 1084 dp = rp; 1085 DELTA(rp, ri->ri_stride, int32_t *); 1086 if (ri->ri_hwbits) { 1087 hp = hrp; 1088 DELTA(hrp, ri->ri_stride, int32_t *); 1089 } 1090 1091 for (cnt = num; cnt; cnt--) { 1092 *(u_char *)dp = clr; 1093 DELTA(dp, 1, int32_t *); 1094 if (ri->ri_hwbits) { 1095 *(u_char *)hp = clr; 1096 DELTA(hp, 1, int32_t *); 1097 } 1098 } 1099 } 1100 } 1101 1102 return; 1103 } 1104 1105 slop1 = (4 - ((long)rp & 3)) & 3; 1106 slop2 = (num - slop1) & 3; 1107 num -= slop1 + slop2; 1108 n8 = num >> 5; 1109 num = (num >> 2) & 7; 1110 1111 while (height--) { 1112 dp = rp; 1113 DELTA(rp, ri->ri_stride, int32_t *); 1114 if (ri->ri_hwbits) { 1115 hp = hrp; 1116 DELTA(hrp, ri->ri_stride, int32_t *); 1117 } 1118 1119 /* Align span to 4 bytes */ 1120 if (slop1 & 1) { 1121 *(u_char *)dp = clr; 1122 DELTA(dp, 1, int32_t *); 1123 if (ri->ri_hwbits) { 1124 *(u_char *)hp = clr; 1125 DELTA(hp, 1, int32_t *); 1126 } 1127 } 1128 1129 if (slop1 & 2) { 1130 *(int16_t *)dp = clr; 1131 DELTA(dp, 2, int32_t *); 1132 if (ri->ri_hwbits) { 1133 *(int16_t *)hp = clr; 1134 DELTA(hp, 2, int32_t *); 1135 } 1136 } 1137 1138 /* Write 32 bytes per loop */ 1139 for (cnt = n8; cnt; cnt--) { 1140 for (i = 0; i < 8; i++) { 1141 dp[i] = clr; 1142 if (ri->ri_hwbits) 1143 hp[i] = clr; 1144 } 1145 dp += 8; 1146 if (ri->ri_hwbits) 1147 hp += 8; 1148 } 1149 1150 /* Write 4 bytes per loop */ 1151 for (cnt = num; cnt; cnt--) { 1152 *dp++ = clr; 1153 if (ri->ri_hwbits) 1154 *hp++ = clr; 1155 } 1156 1157 /* Write unaligned trailing slop */ 1158 if (slop2 & 1) { 1159 *(u_char *)dp = clr; 1160 DELTA(dp, 1, int32_t *); 1161 if (ri->ri_hwbits) { 1162 *(u_char *)hp = clr; 1163 DELTA(hp, 1, int32_t *); 1164 } 1165 } 1166 1167 if (slop2 & 2) { 1168 *(int16_t *)dp = clr; 1169 if (ri->ri_hwbits) 1170 *(int16_t *)hp = clr; 1171 } 1172 } 1173} 1174 1175#if NRASOPS_ROTATION > 0 1176/* 1177 * Quarter clockwise rotation routines (originally intended for the 1178 * built-in Zaurus C3x00 display in 16bpp). 1179 */ 1180 1181#include <sys/malloc.h> 1182 1183static void 1184rasops_rotate_font(int *cookie) 1185{ 1186 struct rotatedfont *f; 1187 int ncookie; 1188 1189 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1190 if (f->rf_cookie == *cookie) { 1191 *cookie = f->rf_rotated; 1192 return; 1193 } 1194 } 1195 1196 /* 1197 * We did not find a rotated version of this font. Ask the wsfont 1198 * code to compute one for us. 1199 */ 1200 1201 f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK); 1202 if (f == NULL) 1203 return; 1204 1205 if ((ncookie = wsfont_rotate(*cookie)) == -1) 1206 return; 1207 1208 f->rf_cookie = *cookie; 1209 f->rf_rotated = ncookie; 1210 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1211 1212 *cookie = ncookie; 1213} 1214 1215static void 1216rasops_copychar(cookie, srcrow, dstrow, srccol, dstcol) 1217 void *cookie; 1218 int srcrow, dstrow, srccol, dstcol; 1219{ 1220 struct rasops_info *ri; 1221 u_char *sp, *dp; 1222 int height; 1223 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1224 1225 ri = (struct rasops_info *)cookie; 1226 1227 r_srcrow = srccol; 1228 r_dstrow = dstcol; 1229 r_srccol = ri->ri_rows - srcrow - 1; 1230 r_dstcol = ri->ri_rows - dstrow - 1; 1231 1232 r_srcrow *= ri->ri_yscale; 1233 r_dstrow *= ri->ri_yscale; 1234 height = ri->ri_font->fontheight; 1235 1236 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1237 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1238 1239 while (height--) { 1240 memmove(dp, sp, ri->ri_xscale); 1241 dp += ri->ri_stride; 1242 sp += ri->ri_stride; 1243 } 1244} 1245 1246static void 1247rasops_putchar_rotated(cookie, row, col, uc, attr) 1248 void *cookie; 1249 int row, col; 1250 u_int uc; 1251 long attr; 1252{ 1253 struct rasops_info *ri; 1254 u_char *rp; 1255 int height; 1256 1257 ri = (struct rasops_info *)cookie; 1258 1259 if (__predict_false((unsigned int)row > ri->ri_rows || 1260 (unsigned int)col > ri->ri_cols)) 1261 return; 1262 1263 /* Avoid underflow */ 1264 if ((ri->ri_rows - row - 1) < 0) 1265 return; 1266 1267 /* Do rotated char sans (side)underline */ 1268 ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1269 attr & ~1); 1270 1271 /* Do rotated underline */ 1272 rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) * 1273 ri->ri_xscale; 1274 height = ri->ri_font->fontheight; 1275 1276 /* XXX this assumes 16-bit color depth */ 1277 if ((attr & 1) != 0) { 1278 int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1279 1280 while (height--) { 1281 *(int16_t *)rp = c; 1282 rp += ri->ri_stride; 1283 } 1284 } 1285} 1286 1287static void 1288rasops_erasecols_rotated(cookie, row, col, num, attr) 1289 void *cookie; 1290 int row, col, num; 1291 long attr; 1292{ 1293 struct rasops_info *ri; 1294 int i; 1295 1296 ri = (struct rasops_info *)cookie; 1297 1298 for (i = col; i < col + num; i++) 1299 ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1300} 1301 1302/* XXX: these could likely be optimised somewhat. */ 1303static void 1304rasops_copyrows_rotated(cookie, src, dst, num) 1305 void *cookie; 1306 int src, dst, num; 1307{ 1308 struct rasops_info *ri = (struct rasops_info *)cookie; 1309 int col, roff; 1310 1311 if (src > dst) 1312 for (roff = 0; roff < num; roff++) 1313 for (col = 0; col < ri->ri_cols; col++) 1314 rasops_copychar(cookie, src + roff, dst + roff, 1315 col, col); 1316 else 1317 for (roff = num - 1; roff >= 0; roff--) 1318 for (col = 0; col < ri->ri_cols; col++) 1319 rasops_copychar(cookie, src + roff, dst + roff, 1320 col, col); 1321} 1322 1323static void 1324rasops_copycols_rotated(cookie, row, src, dst, num) 1325 void *cookie; 1326 int row, src, dst, num; 1327{ 1328 int coff; 1329 1330 if (src > dst) 1331 for (coff = 0; coff < num; coff++) 1332 rasops_copychar(cookie, row, row, src + coff, dst + coff); 1333 else 1334 for (coff = num - 1; coff >= 0; coff--) 1335 rasops_copychar(cookie, row, row, src + coff, dst + coff); 1336} 1337 1338static void 1339rasops_eraserows_rotated(cookie, row, num, attr) 1340 void *cookie; 1341 int row, num; 1342 long attr; 1343{ 1344 struct rasops_info *ri; 1345 int col, rn; 1346 1347 ri = (struct rasops_info *)cookie; 1348 1349 for (rn = row; rn < row + num; rn++) 1350 for (col = 0; col < ri->ri_cols; col++) 1351 ri->ri_ops.putchar(cookie, rn, col, ' ', attr); 1352} 1353#endif /* NRASOPS_ROTATION */ 1354