rasops.c revision 1.80
1/* $NetBSD: rasops.c,v 1.80 2019/07/21 16:19:45 rin 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.80 2019/07/21 16:19:45 rin 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#include <sys/kmem.h> 43 44#include <sys/bswap.h> 45#include <machine/endian.h> 46 47#include <dev/wscons/wsdisplayvar.h> 48#include <dev/wscons/wsconsio.h> 49#include <dev/wsfont/wsfont.h> 50#include <dev/rasops/rasops.h> 51 52#ifndef _KERNEL 53#include <errno.h> 54#endif 55 56#ifdef RASOPS_DEBUG 57#define DPRINTF aprint_error 58#else 59#define DPRINTF while (0) printf 60#endif 61 62struct rasops_matchdata { 63 struct rasops_info *ri; 64 int wantcols, wantrows; 65 int bestscore; 66 struct wsdisplay_font *pick; 67 int ident; 68}; 69 70/* ANSI colormap (R,G,B). Upper 8 are high-intensity */ 71const u_char rasops_cmap[256*3] = { 72 0x00, 0x00, 0x00, /* black */ 73 0x7f, 0x00, 0x00, /* red */ 74 0x00, 0x7f, 0x00, /* green */ 75 0x7f, 0x7f, 0x00, /* brown */ 76 0x00, 0x00, 0x7f, /* blue */ 77 0x7f, 0x00, 0x7f, /* magenta */ 78 0x00, 0x7f, 0x7f, /* cyan */ 79 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */ 80 81 0x7f, 0x7f, 0x7f, /* black */ 82 0xff, 0x00, 0x00, /* red */ 83 0x00, 0xff, 0x00, /* green */ 84 0xff, 0xff, 0x00, /* brown */ 85 0x00, 0x00, 0xff, /* blue */ 86 0xff, 0x00, 0xff, /* magenta */ 87 0x00, 0xff, 0xff, /* cyan */ 88 0xff, 0xff, 0xff, /* white */ 89 90 /* 91 * For the cursor, we need at least the last (255th) 92 * color to be white. Fill up white completely for 93 * simplicity. 94 */ 95#define _CMWHITE 0xff, 0xff, 0xff, 96#define _CMWHITE16 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 97 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 98 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 99 _CMWHITE _CMWHITE _CMWHITE _CMWHITE 100 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 101 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 102 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 /* but not the last one */ 103#undef _CMWHITE16 104#undef _CMWHITE 105 106 /* 107 * For the cursor the fg/bg indices are bit inverted, so 108 * provide complimentary colors in the upper 16 entries. 109 */ 110 0x7f, 0x7f, 0x7f, /* black */ 111 0xff, 0x00, 0x00, /* red */ 112 0x00, 0xff, 0x00, /* green */ 113 0xff, 0xff, 0x00, /* brown */ 114 0x00, 0x00, 0xff, /* blue */ 115 0xff, 0x00, 0xff, /* magenta */ 116 0x00, 0xff, 0xff, /* cyan */ 117 0xff, 0xff, 0xff, /* white */ 118 119 0x00, 0x00, 0x00, /* black */ 120 0x7f, 0x00, 0x00, /* red */ 121 0x00, 0x7f, 0x00, /* green */ 122 0x7f, 0x7f, 0x00, /* brown */ 123 0x00, 0x00, 0x7f, /* blue */ 124 0x7f, 0x00, 0x7f, /* magenta */ 125 0x00, 0x7f, 0x7f, /* cyan */ 126 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */ 127}; 128 129/* True if color is gray */ 130const u_char rasops_isgray[16] = { 131 1, 0, 0, 0, 132 0, 0, 0, 1, 133 1, 0, 0, 0, 134 0, 0, 0, 1 135}; 136 137/* Generic functions */ 138static void rasops_copyrows(void *, int, int, int); 139static int rasops_mapchar(void *, int, u_int *); 140static void rasops_cursor(void *, int, int, int); 141static int rasops_allocattr_color(void *, int, int, int, long *); 142static int rasops_allocattr_mono(void *, int, int, int, long *); 143static void rasops_do_cursor(struct rasops_info *); 144static void rasops_init_devcmap(struct rasops_info *); 145 146#if NRASOPS_ROTATION > 0 147static void rasops_rotate_font(int *, int); 148static void rasops_copychar(void *, int, int, int, int); 149 150/* rotate clockwise */ 151static void rasops_copycols_rotated_cw(void *, int, int, int, int); 152static void rasops_copyrows_rotated_cw(void *, int, int, int); 153static void rasops_erasecols_rotated_cw(void *, int, int, int, long); 154static void rasops_eraserows_rotated_cw(void *, int, int, long); 155static void rasops_putchar_rotated_cw(void *, int, int, u_int, long); 156 157/* rotate counter-clockwise */ 158static void rasops_copychar_ccw(void *, int, int, int, int); 159static void rasops_copycols_rotated_ccw(void *, int, int, int, int); 160static void rasops_copyrows_rotated_ccw(void *, int, int, int); 161#define rasops_erasecols_rotated_ccw rasops_erasecols_rotated_cw 162#define rasops_eraserows_rotated_ccw rasops_eraserows_rotated_cw 163static void rasops_putchar_rotated_ccw(void *, int, int, u_int, long); 164 165/* 166 * List of all rotated fonts 167 */ 168SLIST_HEAD(, rotatedfont) rotatedfonts = SLIST_HEAD_INITIALIZER(rotatedfonts); 169struct rotatedfont { 170 SLIST_ENTRY(rotatedfont) rf_next; 171 int rf_cookie; 172 int rf_rotated; 173}; 174#endif /* NRASOPS_ROTATION > 0 */ 175 176void rasops_make_box_chars_8(struct rasops_info *); 177void rasops_make_box_chars_16(struct rasops_info *); 178void rasops_make_box_chars_32(struct rasops_info *); 179void rasops_make_box_chars_alpha(struct rasops_info *); 180 181extern int cold; 182 183/* 184 * Initialize a 'rasops_info' descriptor. 185 */ 186int 187rasops_init(struct rasops_info *ri, int wantrows, int wantcols) 188{ 189 190 memset (&ri->ri_optfont, 0, sizeof(ri->ri_optfont)); 191#ifdef _KERNEL 192 /* Select a font if the caller doesn't care */ 193 if (ri->ri_font == NULL) { 194 int cookie = -1; 195 int flags; 196 197 wsfont_init(); 198 199 /* 200 * first, try to find something that's as close as possible 201 * to the caller's requested terminal size 202 */ 203 if (wantrows == 0) 204 wantrows = RASOPS_DEFAULT_HEIGHT; 205 if (wantcols == 0) 206 wantcols = RASOPS_DEFAULT_WIDTH; 207 208 flags = WSFONT_FIND_BESTWIDTH | WSFONT_FIND_BITMAP; 209 if ((ri->ri_flg & RI_ENABLE_ALPHA) != 0) 210 flags |= WSFONT_FIND_ALPHA; 211 if ((ri->ri_flg & RI_PREFER_ALPHA) != 0) 212 flags |= WSFONT_PREFER_ALPHA; 213 cookie = wsfont_find(NULL, 214 ri->ri_width / wantcols, 215 0, 216 0, 217 WSDISPLAY_FONTORDER_L2R, 218 WSDISPLAY_FONTORDER_L2R, 219 flags); 220 221 /* 222 * this means there is no supported font in the list 223 */ 224 if (cookie <= 0) { 225 aprint_error("rasops_init: font table is empty\n"); 226 return (-1); 227 } 228 229#if NRASOPS_ROTATION > 0 230 /* 231 * Pick the rotated version of this font. This will create it 232 * if necessary. 233 */ 234 if (ri->ri_flg & RI_ROTATE_MASK) { 235 if (ri->ri_flg & RI_ROTATE_CW) 236 rasops_rotate_font(&cookie, WSFONT_ROTATE_CW); 237 else if (ri->ri_flg & RI_ROTATE_CCW) 238 rasops_rotate_font(&cookie, WSFONT_ROTATE_CCW); 239 } 240#endif 241 242 if (wsfont_lock(cookie, &ri->ri_font)) { 243 aprint_error("rasops_init: couldn't lock font\n"); 244 return (-1); 245 } 246 247 ri->ri_wsfcookie = cookie; 248 } 249#endif 250 251 /* This should never happen in reality... */ 252#ifdef DEBUG 253 if ((long)ri->ri_bits & 3) { 254 aprint_error("rasops_init: bits not aligned on 32-bit boundary\n"); 255 return (-1); 256 } 257 258 if ((int)ri->ri_stride & 3) { 259 aprint_error("rasops_init: stride not aligned on 32-bit boundary\n"); 260 return (-1); 261 } 262#endif 263 264 if (rasops_reconfig(ri, wantrows, wantcols)) 265 return (-1); 266 267 rasops_init_devcmap(ri); 268 return (0); 269} 270 271/* 272 * Reconfigure (because parameters have changed in some way). 273 */ 274int 275rasops_reconfig(struct rasops_info *ri, int wantrows, int wantcols) 276{ 277 int bpp, s, len; 278 279 s = splhigh(); 280 281 if (wantrows == 0) 282 wantrows = RASOPS_DEFAULT_HEIGHT; 283 if (wantcols == 0) 284 wantcols = RASOPS_DEFAULT_WIDTH; 285 286 /* throw away old line drawing character bitmaps, if we have any */ 287 if (ri->ri_optfont.data != NULL) { 288 kmem_free(ri->ri_optfont.data, ri->ri_optfont.stride * 289 ri->ri_optfont.fontheight * ri->ri_optfont.numchars); 290 ri->ri_optfont.data = NULL; 291 } 292 293 /* autogenerate box drawing characters */ 294 ri->ri_optfont.firstchar = WSFONT_FLAG_OPT; 295 ri->ri_optfont.numchars = 16; 296 ri->ri_optfont.fontwidth = ri->ri_font->fontwidth; 297 ri->ri_optfont.fontheight = ri->ri_font->fontheight; 298 ri->ri_optfont.stride = ri->ri_font->stride; 299 len = ri->ri_optfont.fontheight * ri->ri_optfont.stride * 300 ri->ri_optfont.numchars; 301 302 if ((ri->ri_flg & RI_NO_AUTO) == 0) { 303 ri->ri_optfont.data = kmem_zalloc(len, KM_SLEEP); 304 if (ri->ri_optfont.stride < ri->ri_optfont.fontwidth) { 305 switch (ri->ri_optfont.stride) { 306 case 1: 307 rasops_make_box_chars_8(ri); 308 break; 309 case 2: 310 rasops_make_box_chars_16(ri); 311 break; 312 case 4: 313 rasops_make_box_chars_32(ri); 314 break; 315 } 316 } else { 317 rasops_make_box_chars_alpha(ri); 318 } 319 } else 320 memset(&ri->ri_optfont, 0, sizeof(ri->ri_optfont)); 321 322 if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4) 323 panic("rasops_init: fontwidth assumptions botched!"); 324 325 /* Need this to frob the setup below */ 326 bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth); 327 328 if ((ri->ri_flg & RI_CFGDONE) != 0) { 329 ri->ri_bits = ri->ri_origbits; 330 ri->ri_hwbits = ri->ri_hworigbits; 331 } 332 333 /* Don't care if the caller wants a hideously small console */ 334 if (wantrows < 10) 335 wantrows = 10; 336 337 if (wantcols < 20) 338 wantcols = 20; 339 340 /* Now constrain what they get */ 341 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols; 342 ri->ri_emuheight = ri->ri_font->fontheight * wantrows; 343 344 if (ri->ri_emuwidth > ri->ri_width) 345 ri->ri_emuwidth = ri->ri_width; 346 347 if (ri->ri_emuheight > ri->ri_height) 348 ri->ri_emuheight = ri->ri_height; 349 350 /* Reduce width until aligned on a 32-bit boundary */ 351 while ((ri->ri_emuwidth * bpp & 31) != 0) 352 ri->ri_emuwidth--; 353 354#if NRASOPS_ROTATION > 0 355 if (ri->ri_flg & (RI_ROTATE_CW|RI_ROTATE_CCW)) { 356 ri->ri_rows = ri->ri_emuwidth / ri->ri_font->fontwidth; 357 ri->ri_cols = ri->ri_emuheight / ri->ri_font->fontheight; 358 } else 359#endif 360 { 361 362 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth; 363 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight; 364 } 365 ri->ri_emustride = ri->ri_emuwidth * bpp >> 3; 366 ri->ri_delta = ri->ri_stride - ri->ri_emustride; 367 ri->ri_ccol = 0; 368 ri->ri_crow = 0; 369 ri->ri_pelbytes = bpp >> 3; 370 371 ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3; 372 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride; 373 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 374 375#ifdef DEBUG 376 if ((ri->ri_delta & 3) != 0) 377 panic("rasops_init: ri_delta not aligned on 32-bit boundary"); 378#endif 379 ri->ri_origbits = ri->ri_bits; 380 ri->ri_hworigbits = ri->ri_hwbits; 381 382 /* Clear the entire display */ 383 if ((ri->ri_flg & RI_CLEAR) != 0) 384 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 385 386 /* Now centre our window if needs be */ 387 if ((ri->ri_flg & RI_CENTER) != 0) { 388 ri->ri_bits += (((ri->ri_width * bpp >> 3) - 389 ri->ri_emustride) >> 1) & ~3; 390 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) * 391 ri->ri_stride; 392 if (ri->ri_hwbits != NULL) { 393 ri->ri_hwbits += (((ri->ri_width * bpp >> 3) - 394 ri->ri_emustride) >> 1) & ~3; 395 ri->ri_hwbits += ((ri->ri_height - ri->ri_emuheight) >> 1) * 396 ri->ri_stride; 397 } 398 ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits) 399 / ri->ri_stride; 400 ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits) 401 % ri->ri_stride) * 8 / bpp); 402 } else 403 ri->ri_xorigin = ri->ri_yorigin = 0; 404 405 /* 406 * Fill in defaults for operations set. XXX this nukes private 407 * routines used by accelerated fb drivers. 408 */ 409 ri->ri_ops.mapchar = rasops_mapchar; 410 ri->ri_ops.copyrows = rasops_copyrows; 411 ri->ri_ops.copycols = rasops_copycols; 412 ri->ri_ops.erasecols = rasops_erasecols; 413 ri->ri_ops.eraserows = rasops_eraserows; 414 ri->ri_ops.cursor = rasops_cursor; 415 ri->ri_do_cursor = rasops_do_cursor; 416 417 ri->ri_caps &= ~(WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 418 WSSCREEN_WSCOLORS | WSSCREEN_REVERSE); 419 if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) { 420 ri->ri_ops.allocattr = rasops_allocattr_mono; 421 ri->ri_caps |= WSSCREEN_UNDERLINE | WSSCREEN_REVERSE; 422 } else { 423 ri->ri_ops.allocattr = rasops_allocattr_color; 424 ri->ri_caps |= WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 425 WSSCREEN_WSCOLORS | WSSCREEN_REVERSE; 426 } 427 428 switch (ri->ri_depth) { 429#if NRASOPS1 > 0 430 case 1: 431 rasops1_init(ri); 432 break; 433#endif 434#if NRASOPS2 > 0 435 case 2: 436 rasops2_init(ri); 437 break; 438#endif 439#if NRASOPS4 > 0 440 case 4: 441 rasops4_init(ri); 442 break; 443#endif 444#if NRASOPS8 > 0 445 case 8: 446 rasops8_init(ri); 447 break; 448#endif 449#if NRASOPS15 > 0 || NRASOPS16 > 0 450 case 15: 451 case 16: 452 rasops15_init(ri); 453 break; 454#endif 455#if NRASOPS24 > 0 456 case 24: 457 rasops24_init(ri); 458 break; 459#endif 460#if NRASOPS32 > 0 461 case 32: 462 rasops32_init(ri); 463 break; 464#endif 465 default: 466 ri->ri_flg &= ~RI_CFGDONE; 467 splx(s); 468 return (-1); 469 } 470 471#if NRASOPS_ROTATION > 0 472 if (ri->ri_flg & RI_ROTATE_MASK) { 473 if (ri->ri_flg & RI_ROTATE_CW) { 474 ri->ri_real_ops = ri->ri_ops; 475 ri->ri_ops.copycols = rasops_copycols_rotated_cw; 476 ri->ri_ops.copyrows = rasops_copyrows_rotated_cw; 477 ri->ri_ops.erasecols = rasops_erasecols_rotated_cw; 478 ri->ri_ops.eraserows = rasops_eraserows_rotated_cw; 479 ri->ri_ops.putchar = rasops_putchar_rotated_cw; 480 } else if (ri->ri_flg & RI_ROTATE_CCW) { 481 ri->ri_real_ops = ri->ri_ops; 482 ri->ri_ops.copycols = rasops_copycols_rotated_ccw; 483 ri->ri_ops.copyrows = rasops_copyrows_rotated_ccw; 484 ri->ri_ops.erasecols = rasops_erasecols_rotated_ccw; 485 ri->ri_ops.eraserows = rasops_eraserows_rotated_ccw; 486 ri->ri_ops.putchar = rasops_putchar_rotated_ccw; 487 } 488 } 489#endif 490 491 ri->ri_flg |= RI_CFGDONE; 492 splx(s); 493 return (0); 494} 495 496/* 497 * Map a character. 498 */ 499static int 500rasops_mapchar(void *cookie, int c, u_int *cp) 501{ 502 struct rasops_info *ri; 503 504 ri = (struct rasops_info *)cookie; 505 506#ifdef DIAGNOSTIC 507 if (ri->ri_font == NULL) 508 panic("rasops_mapchar: no font selected"); 509#endif 510 511 if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) { 512 *cp = ' '; 513 return (0); 514 } 515 516 if (c < ri->ri_font->firstchar) { 517 *cp = ' '; 518 return (0); 519 } 520 521#if 0 522 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) { 523 *cp = ' '; 524 return (0); 525 } 526#endif 527 *cp = c; 528 return (5); 529} 530 531/* 532 * Allocate a color attribute. 533 */ 534static int 535rasops_allocattr_color(void *cookie, int fg, int bg, int flg, 536 long *attr) 537{ 538 int swap; 539 540 if (__predict_false((unsigned int)fg >= sizeof(rasops_isgray) || 541 (unsigned int)bg >= sizeof(rasops_isgray))) 542 return (EINVAL); 543 544#ifdef RASOPS_CLIPPING 545 fg &= 7; 546 bg &= 7; 547#endif 548 if ((flg & WSATTR_BLINK) != 0) 549 return (EINVAL); 550 551 if ((flg & WSATTR_WSCOLORS) == 0) { 552#ifdef WS_DEFAULT_FG 553 fg = WS_DEFAULT_FG; 554#else 555 fg = WSCOL_WHITE; 556#endif 557#ifdef WS_DEFAULT_BG 558 bg = WS_DEFAULT_BG; 559#else 560 bg = WSCOL_BLACK; 561#endif 562 } 563 564 if ((flg & WSATTR_REVERSE) != 0) { 565 swap = fg; 566 fg = bg; 567 bg = swap; 568 } 569 570 if ((flg & WSATTR_HILIT) != 0) 571 fg += 8; 572 573 flg = flg & WSATTR_USERMASK; 574 575 if (rasops_isgray[fg]) 576 flg |= WSATTR_PRIVATE1; 577 578 if (rasops_isgray[bg]) 579 flg |= WSATTR_PRIVATE2; 580 581 *attr = (bg << 16) | (fg << 24) | flg; 582 return (0); 583} 584 585/* 586 * Allocate a mono attribute. 587 */ 588static int 589rasops_allocattr_mono(void *cookie, int fg, int bg, int flg, 590 long *attr) 591{ 592 int swap; 593 594 if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0) 595 return (EINVAL); 596 597 fg = 1; 598 bg = 0; 599 600 if ((flg & WSATTR_REVERSE) != 0) { 601 swap = fg; 602 fg = bg; 603 bg = swap; 604 } 605 606 *attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6); 607 return (0); 608} 609 610/* 611 * Copy rows. 612 */ 613static void 614rasops_copyrows(void *cookie, int src, int dst, int num) 615{ 616 int32_t *sp, *dp, *hp, *srp, *drp, *hrp; 617 struct rasops_info *ri; 618 int n8, n1, cnt, delta; 619 620 ri = (struct rasops_info *)cookie; 621 hp = hrp = NULL; 622 623#ifdef RASOPS_CLIPPING 624 if (dst == src) 625 return; 626 627 if (src < 0) { 628 num += src; 629 src = 0; 630 } 631 632 if ((src + num) > ri->ri_rows) 633 num = ri->ri_rows - src; 634 635 if (dst < 0) { 636 num += dst; 637 dst = 0; 638 } 639 640 if ((dst + num) > ri->ri_rows) 641 num = ri->ri_rows - dst; 642 643 if (num <= 0) 644 return; 645#endif 646 647 num *= ri->ri_font->fontheight; 648 n8 = ri->ri_emustride >> 5; 649 n1 = (ri->ri_emustride >> 2) & 7; 650 651 if (dst < src) { 652 srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale); 653 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale); 654 if (ri->ri_hwbits) 655 hrp = (int32_t *)(ri->ri_hwbits + dst * 656 ri->ri_yscale); 657 delta = ri->ri_stride; 658 } else { 659 src = ri->ri_font->fontheight * src + num - 1; 660 dst = ri->ri_font->fontheight * dst + num - 1; 661 srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride); 662 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride); 663 if (ri->ri_hwbits) 664 hrp = (int32_t *)(ri->ri_hwbits + dst * 665 ri->ri_stride); 666 667 delta = -ri->ri_stride; 668 } 669 670 while (num--) { 671 dp = drp; 672 sp = srp; 673 if (ri->ri_hwbits) 674 hp = hrp; 675 676 DELTA(drp, delta, int32_t *); 677 DELTA(srp, delta, int32_t *); 678 if (ri->ri_hwbits) 679 DELTA(hrp, delta, int32_t *); 680 681 for (cnt = n8; cnt; cnt--) { 682 dp[0] = sp[0]; 683 dp[1] = sp[1]; 684 dp[2] = sp[2]; 685 dp[3] = sp[3]; 686 dp[4] = sp[4]; 687 dp[5] = sp[5]; 688 dp[6] = sp[6]; 689 dp[7] = sp[7]; 690 dp += 8; 691 sp += 8; 692 } 693 if (ri->ri_hwbits) { 694 sp -= (8 * n8); 695 for (cnt = n8; cnt; cnt--) { 696 hp[0] = sp[0]; 697 hp[1] = sp[1]; 698 hp[2] = sp[2]; 699 hp[3] = sp[3]; 700 hp[4] = sp[4]; 701 hp[5] = sp[5]; 702 hp[6] = sp[6]; 703 hp[7] = sp[7]; 704 hp += 8; 705 sp += 8; 706 } 707 } 708 709 for (cnt = n1; cnt; cnt--) { 710 *dp++ = *sp++; 711 if (ri->ri_hwbits) 712 *hp++ = *(sp - 1); 713 } 714 } 715} 716 717/* 718 * Copy columns. This is slow, and hard to optimize due to alignment, 719 * and the fact that we have to copy both left->right and right->left. 720 * We simply cop-out here and use memmove(), since it handles all of 721 * these cases anyway. 722 */ 723void 724rasops_copycols(void *cookie, int row, int src, int dst, int num) 725{ 726 struct rasops_info *ri; 727 u_char *sp, *dp, *hp; 728 int height; 729 730 ri = (struct rasops_info *)cookie; 731 hp = NULL; 732 733#ifdef RASOPS_CLIPPING 734 if (dst == src) 735 return; 736 737 /* Catches < 0 case too */ 738 if ((unsigned)row >= (unsigned)ri->ri_rows) 739 return; 740 741 if (src < 0) { 742 num += src; 743 src = 0; 744 } 745 746 if ((src + num) > ri->ri_cols) 747 num = ri->ri_cols - src; 748 749 if (dst < 0) { 750 num += dst; 751 dst = 0; 752 } 753 754 if ((dst + num) > ri->ri_cols) 755 num = ri->ri_cols - dst; 756 757 if (num <= 0) 758 return; 759#endif 760 761 num *= ri->ri_xscale; 762 row *= ri->ri_yscale; 763 height = ri->ri_font->fontheight; 764 765 sp = ri->ri_bits + row + src * ri->ri_xscale; 766 dp = ri->ri_bits + row + dst * ri->ri_xscale; 767 if (ri->ri_hwbits) 768 hp = ri->ri_hwbits + row + dst * ri->ri_xscale; 769 770 while (height--) { 771 memmove(dp, sp, num); 772 if (ri->ri_hwbits) { 773 memcpy(hp, sp, num); 774 hp += ri->ri_stride; 775 } 776 dp += ri->ri_stride; 777 sp += ri->ri_stride; 778 } 779} 780 781/* 782 * Turn cursor off/on. 783 */ 784static void 785rasops_cursor(void *cookie, int on, int row, int col) 786{ 787 struct rasops_info *ri; 788 789 ri = (struct rasops_info *)cookie; 790 791 /* Turn old cursor off */ 792 if ((ri->ri_flg & RI_CURSOR) != 0) 793#ifdef RASOPS_CLIPPING 794 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 795#endif 796 ri->ri_do_cursor(ri); 797 798 /* Select new cursor */ 799#ifdef RASOPS_CLIPPING 800 ri->ri_flg &= ~RI_CURSORCLIP; 801 802 if (row < 0 || row >= ri->ri_rows) 803 ri->ri_flg |= RI_CURSORCLIP; 804 else if (col < 0 || col >= ri->ri_cols) 805 ri->ri_flg |= RI_CURSORCLIP; 806#endif 807 ri->ri_crow = row; 808 ri->ri_ccol = col; 809 810 if (on) { 811 ri->ri_flg |= RI_CURSOR; 812#ifdef RASOPS_CLIPPING 813 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 814#endif 815 ri->ri_do_cursor(ri); 816 } else 817 ri->ri_flg &= ~RI_CURSOR; 818} 819 820/* 821 * Make the device colormap 822 */ 823static void 824rasops_init_devcmap(struct rasops_info *ri) 825{ 826 const u_char *p; 827 int i, c; 828 829 switch (ri->ri_depth) { 830 case 1: 831 ri->ri_devcmap[0] = 0; 832 for (i = 1; i < 16; i++) 833 ri->ri_devcmap[i] = -1; 834 return; 835 836 case 2: 837 for (i = 1; i < 15; i++) 838 ri->ri_devcmap[i] = 0xaaaaaaaa; 839 840 ri->ri_devcmap[0] = 0; 841 ri->ri_devcmap[8] = 0x55555555; 842 ri->ri_devcmap[15] = -1; 843 return; 844 845 case 8: 846 if ((ri->ri_flg & RI_8BIT_IS_RGB) == 0) { 847 for (i = 0; i < 16; i++) 848 ri->ri_devcmap[i] = 849 i | (i<<8) | (i<<16) | (i<<24); 850 return; 851 } 852 } 853 854 p = rasops_cmap; 855 856 for (i = 0; i < 16; i++) { 857 if (ri->ri_rnum <= 8) 858 c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 859 else 860 c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 861 p++; 862 863 if (ri->ri_gnum <= 8) 864 c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 865 else 866 c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 867 p++; 868 869 if (ri->ri_bnum <= 8) 870 c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 871 else 872 c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 873 p++; 874 875 /* Fill the word for generic routines, which want this */ 876 if (ri->ri_depth == 24) 877 c = c | ((c & 0xff) << 24); 878 else if (ri->ri_depth == 8) { 879 c = c | (c << 8); 880 c |= c << 16; 881 } else if (ri->ri_depth <= 16) 882 c = c | (c << 16); 883 884 /* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */ 885 if ((ri->ri_flg & RI_BSWAP) == 0) 886 ri->ri_devcmap[i] = c; 887 else if (ri->ri_depth == 32) 888 ri->ri_devcmap[i] = bswap32(c); 889 else if (ri->ri_depth == 16 || ri->ri_depth == 15) 890 ri->ri_devcmap[i] = bswap16(c); 891 else 892 ri->ri_devcmap[i] = c; 893 } 894} 895 896/* 897 * Unpack a rasops attribute 898 */ 899void 900rasops_unpack_attr(long attr, int *fg, int *bg, int *underline) 901{ 902 903 *fg = ((u_int)attr >> 24) & 0xf; 904 *bg = ((u_int)attr >> 16) & 0xf; 905 if (underline != NULL) 906 *underline = (u_int)attr & WSATTR_UNDERLINE; 907} 908 909/* 910 * Erase rows. This isn't static, since 24-bpp uses it in special cases. 911 */ 912void 913rasops_eraserows(void *cookie, int row, int num, long attr) 914{ 915 struct rasops_info *ri; 916 int np, nw, cnt, delta; 917 int32_t *dp, *hp, clr; 918 int i; 919 920 ri = (struct rasops_info *)cookie; 921 hp = NULL; 922 923#ifdef RASOPS_CLIPPING 924 if (row < 0) { 925 num += row; 926 row = 0; 927 } 928 929 if ((row + num) > ri->ri_rows) 930 num = ri->ri_rows - row; 931 932 if (num <= 0) 933 return; 934#endif 935 936 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 937 938 /* 939 * XXX The wsdisplay_emulops interface seems a little deficient in 940 * that there is no way to clear the *entire* screen. We provide a 941 * workaround here: if the entire console area is being cleared, and 942 * the RI_FULLCLEAR flag is set, clear the entire display. 943 */ 944 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 945 np = ri->ri_stride >> 5; 946 nw = (ri->ri_stride >> 2) & 7; 947 num = ri->ri_height; 948 dp = (int32_t *)ri->ri_origbits; 949 if (ri->ri_hwbits) 950 hp = (int32_t *)ri->ri_hworigbits; 951 delta = 0; 952 } else { 953 np = ri->ri_emustride >> 5; 954 nw = (ri->ri_emustride >> 2) & 7; 955 num *= ri->ri_font->fontheight; 956 dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale); 957 if (ri->ri_hwbits) 958 hp = (int32_t *)(ri->ri_hwbits + row * 959 ri->ri_yscale); 960 delta = ri->ri_delta; 961 } 962 963 while (num--) { 964 for (cnt = np; cnt; cnt--) { 965 for (i = 0; i < 8; i++) { 966 dp[i] = clr; 967 if (ri->ri_hwbits) 968 hp[i] = clr; 969 } 970 dp += 8; 971 if (ri->ri_hwbits) 972 hp += 8; 973 } 974 975 for (cnt = nw; cnt; cnt--) { 976 *(int32_t *)dp = clr; 977 DELTA(dp, 4, int32_t *); 978 if (ri->ri_hwbits) { 979 *(int32_t *)hp = clr; 980 DELTA(hp, 4, int32_t *); 981 } 982 } 983 984 DELTA(dp, delta, int32_t *); 985 if (ri->ri_hwbits) 986 DELTA(hp, delta, int32_t *); 987 } 988} 989 990/* 991 * Actually turn the cursor on or off. This does the dirty work for 992 * rasops_cursor(). 993 */ 994static void 995rasops_do_cursor(struct rasops_info *ri) 996{ 997 int full1, height, cnt, slop1, slop2, row, col; 998 u_char *dp, *rp, *hrp, *hp; 999 1000 hrp = hp = NULL; 1001 1002#if NRASOPS_ROTATION > 0 1003 if (ri->ri_flg & RI_ROTATE_MASK) { 1004 if (ri->ri_flg & RI_ROTATE_CW) { 1005 /* Rotate rows/columns */ 1006 row = ri->ri_ccol; 1007 col = ri->ri_rows - ri->ri_crow - 1; 1008 } else if (ri->ri_flg & RI_ROTATE_CCW) { 1009 /* Rotate rows/columns */ 1010 row = ri->ri_cols - ri->ri_ccol - 1; 1011 col = ri->ri_crow; 1012 } else { /* upside-down */ 1013 row = ri->ri_crow; 1014 col = ri->ri_ccol; 1015 } 1016 } else 1017#endif 1018 { 1019 row = ri->ri_crow; 1020 col = ri->ri_ccol; 1021 } 1022 1023 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 1024 if (ri->ri_hwbits) 1025 hrp = ri->ri_hwbits + row * ri->ri_yscale + col 1026 * ri->ri_xscale; 1027 height = ri->ri_font->fontheight; 1028 1029 /* 1030 * For ri_xscale = 1: 1031 * 1032 * Logic below does not work for ri_xscale = 1, e.g., 1033 * fontwidth = 8 and bpp = 1. So we take care of it. 1034 */ 1035 if (ri->ri_xscale == 1) { 1036 while (height--) { 1037 uint8_t tmp8 = ~*rp; 1038 1039 *rp = tmp8; 1040 rp += ri->ri_stride; 1041 1042 if (ri->ri_hwbits) { 1043 *hrp = tmp8; 1044 hrp += ri->ri_stride; 1045 } 1046 } 1047 return; 1048 } 1049 1050 /* 1051 * For ri_xscale = 2, 3, 4, ...: 1052 * 1053 * Note that siop1 <= ri_xscale even for ri_xscale = 2, 1054 * since rp % 3 = 0 or 2. 1055 */ 1056 slop1 = (4 - ((uintptr_t)rp & 3)) & 3; 1057 slop2 = (ri->ri_xscale - slop1) & 3; 1058 full1 = (ri->ri_xscale - slop1 - slop2) >> 2; 1059 1060 if ((slop1 | slop2) == 0) { 1061 uint32_t tmp32; 1062 /* A common case */ 1063 while (height--) { 1064 dp = rp; 1065 rp += ri->ri_stride; 1066 if (ri->ri_hwbits) { 1067 hp = hrp; 1068 hrp += ri->ri_stride; 1069 } 1070 1071 for (cnt = full1; cnt; cnt--) { 1072 tmp32 = *(int32_t *)dp ^ ~0; 1073 *(int32_t *)dp = tmp32; 1074 dp += 4; 1075 if (ri->ri_hwbits) { 1076 *(int32_t *)hp = tmp32; 1077 hp += 4; 1078 } 1079 } 1080 } 1081 } else { 1082 uint32_t tmp32, msk1, msk2; 1083 1084 msk1 = be32toh(0xffffffff >> (32 - (8 * slop1))); 1085 msk2 = be32toh(0xffffffff << (32 - (8 * slop2))); 1086 1087 while (height--) { 1088 dp = (u_char *)((uintptr_t)rp & ~3); 1089 rp += ri->ri_stride; 1090 if (ri->ri_hwbits) { 1091 hp = (u_char *)((uintptr_t)hrp & ~3); 1092 hrp += ri->ri_stride; 1093 } 1094 1095 if (msk1 != 0) { 1096 tmp32 = *(int32_t *)dp ^ msk1; 1097 *(uint32_t *)dp = tmp32; 1098 dp += 4; 1099 if (ri->ri_hwbits) { 1100 *(int32_t *)hp = tmp32; 1101 hp += 4; 1102 } 1103 } 1104 1105 for (cnt = full1; cnt; cnt--) { 1106 tmp32 = *(int32_t *)dp ^ ~0; 1107 *(uint32_t *)dp = tmp32; 1108 dp += 4; 1109 if (ri->ri_hwbits) { 1110 *(int32_t *)hp = tmp32; 1111 hp += 4; 1112 } 1113 } 1114 1115 if (msk2 != 0) { 1116 tmp32 = *(int32_t *)dp ^ msk2; 1117 *(uint32_t *)dp = tmp32; 1118 if (ri->ri_hwbits) 1119 *(int32_t *)hp = tmp32; 1120 } 1121 } 1122 } 1123} 1124 1125/* 1126 * Erase columns. 1127 */ 1128void 1129rasops_erasecols(void *cookie, int row, int col, int num, long attr) 1130{ 1131 int n8, height, cnt, slop1, slop2, clr; 1132 struct rasops_info *ri; 1133 int32_t *rp, *dp, *hrp, *hp; 1134 int i; 1135 1136 ri = (struct rasops_info *)cookie; 1137 hrp = hp = NULL; 1138 1139#ifdef RASOPS_CLIPPING 1140 if ((unsigned)row >= (unsigned)ri->ri_rows) 1141 return; 1142 1143 if (col < 0) { 1144 num += col; 1145 col = 0; 1146 } 1147 1148 if ((col + num) > ri->ri_cols) 1149 num = ri->ri_cols - col; 1150 1151 if (num <= 0) 1152 return; 1153#endif 1154 1155 num = num * ri->ri_xscale; 1156 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 1157 if (ri->ri_hwbits) 1158 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 1159 col*ri->ri_xscale); 1160 height = ri->ri_font->fontheight; 1161 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 1162 1163 /* Don't bother using the full loop for <= 32 pels */ 1164 if (num <= 32) { 1165 if (((num | ri->ri_xscale) & 3) == 0) { 1166 /* Word aligned blt */ 1167 num >>= 2; 1168 1169 while (height--) { 1170 dp = rp; 1171 DELTA(rp, ri->ri_stride, int32_t *); 1172 if (ri->ri_hwbits) { 1173 hp = hrp; 1174 DELTA(hrp, ri->ri_stride, int32_t *); 1175 } 1176 1177 for (cnt = num; cnt; cnt--) { 1178 *dp++ = clr; 1179 if (ri->ri_hwbits) 1180 *hp++ = clr; 1181 } 1182 } 1183 } else if (((num | ri->ri_xscale) & 1) == 0) { 1184 /* 1185 * Halfword aligned blt. This is needed so the 1186 * 15/16 bit ops can use this function. 1187 */ 1188 num >>= 1; 1189 1190 while (height--) { 1191 dp = rp; 1192 DELTA(rp, ri->ri_stride, int32_t *); 1193 if (ri->ri_hwbits) { 1194 hp = hrp; 1195 DELTA(hrp, ri->ri_stride, int32_t *); 1196 } 1197 1198 for (cnt = num; cnt; cnt--) { 1199 *(int16_t *)dp = clr; 1200 DELTA(dp, 2, int32_t *); 1201 if (ri->ri_hwbits) { 1202 *(int16_t *)hp = clr; 1203 DELTA(hp, 2, int32_t *); 1204 } 1205 } 1206 } 1207 } else { 1208 while (height--) { 1209 dp = rp; 1210 DELTA(rp, ri->ri_stride, int32_t *); 1211 if (ri->ri_hwbits) { 1212 hp = hrp; 1213 DELTA(hrp, ri->ri_stride, int32_t *); 1214 } 1215 1216 for (cnt = num; cnt; cnt--) { 1217 *(u_char *)dp = clr; 1218 DELTA(dp, 1, int32_t *); 1219 if (ri->ri_hwbits) { 1220 *(u_char *)hp = clr; 1221 DELTA(hp, 1, int32_t *); 1222 } 1223 } 1224 } 1225 } 1226 1227 return; 1228 } 1229 1230 slop1 = (4 - ((long)rp & 3)) & 3; 1231 slop2 = (num - slop1) & 3; 1232 num -= slop1 + slop2; 1233 n8 = num >> 5; 1234 num = (num >> 2) & 7; 1235 1236 while (height--) { 1237 dp = rp; 1238 DELTA(rp, ri->ri_stride, int32_t *); 1239 if (ri->ri_hwbits) { 1240 hp = hrp; 1241 DELTA(hrp, ri->ri_stride, int32_t *); 1242 } 1243 1244 /* Align span to 4 bytes */ 1245 if (slop1 & 1) { 1246 *(u_char *)dp = clr; 1247 DELTA(dp, 1, int32_t *); 1248 if (ri->ri_hwbits) { 1249 *(u_char *)hp = clr; 1250 DELTA(hp, 1, int32_t *); 1251 } 1252 } 1253 1254 if (slop1 & 2) { 1255 *(int16_t *)dp = clr; 1256 DELTA(dp, 2, int32_t *); 1257 if (ri->ri_hwbits) { 1258 *(int16_t *)hp = clr; 1259 DELTA(hp, 2, int32_t *); 1260 } 1261 } 1262 1263 /* Write 32 bytes per loop */ 1264 for (cnt = n8; cnt; cnt--) { 1265 for (i = 0; i < 8; i++) { 1266 dp[i] = clr; 1267 if (ri->ri_hwbits) 1268 hp[i] = clr; 1269 } 1270 dp += 8; 1271 if (ri->ri_hwbits) 1272 hp += 8; 1273 } 1274 1275 /* Write 4 bytes per loop */ 1276 for (cnt = num; cnt; cnt--) { 1277 *dp++ = clr; 1278 if (ri->ri_hwbits) 1279 *hp++ = clr; 1280 } 1281 1282 /* Write unaligned trailing slop */ 1283 if (slop2 & 1) { 1284 *(u_char *)dp = clr; 1285 DELTA(dp, 1, int32_t *); 1286 if (ri->ri_hwbits) { 1287 *(u_char *)hp = clr; 1288 DELTA(hp, 1, int32_t *); 1289 } 1290 } 1291 1292 if (slop2 & 2) { 1293 *(int16_t *)dp = clr; 1294 if (ri->ri_hwbits) 1295 *(int16_t *)hp = clr; 1296 } 1297 } 1298} 1299 1300#if NRASOPS_ROTATION > 0 1301/* 1302 * Quarter clockwise rotation routines (originally intended for the 1303 * built-in Zaurus C3x00 display in 16bpp). 1304 */ 1305 1306#include <sys/malloc.h> 1307 1308static void 1309rasops_rotate_font(int *cookie, int rotate) 1310{ 1311 struct rotatedfont *f; 1312 int ncookie; 1313 1314 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1315 if (f->rf_cookie == *cookie) { 1316 *cookie = f->rf_rotated; 1317 return; 1318 } 1319 } 1320 1321 /* 1322 * We did not find a rotated version of this font. Ask the wsfont 1323 * code to compute one for us. 1324 */ 1325 1326 f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK); 1327 if (f == NULL) 1328 goto fail0; 1329 1330 if ((ncookie = wsfont_rotate(*cookie, rotate)) == -1) 1331 goto fail1; 1332 1333 f->rf_cookie = *cookie; 1334 f->rf_rotated = ncookie; 1335 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1336 1337 *cookie = ncookie; 1338 return; 1339 1340fail1: free(f, M_DEVBUF); 1341fail0: /* Just use the existing font, I guess... */ 1342 return; 1343} 1344 1345static void 1346rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1347{ 1348 struct rasops_info *ri; 1349 u_char *sp, *dp; 1350 int height; 1351 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1352 1353 ri = (struct rasops_info *)cookie; 1354 1355 r_srcrow = srccol; 1356 r_dstrow = dstcol; 1357 r_srccol = ri->ri_rows - srcrow - 1; 1358 r_dstcol = ri->ri_rows - dstrow - 1; 1359 1360 r_srcrow *= ri->ri_yscale; 1361 r_dstrow *= ri->ri_yscale; 1362 height = ri->ri_font->fontheight; 1363 1364 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1365 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1366 1367 while (height--) { 1368 memmove(dp, sp, ri->ri_xscale); 1369 dp += ri->ri_stride; 1370 sp += ri->ri_stride; 1371 } 1372} 1373 1374static void 1375rasops_putchar_rotated_cw(void *cookie, int row, int col, u_int uc, long attr) 1376{ 1377 struct rasops_info *ri; 1378 u_char *rp; 1379 int height; 1380 1381 ri = (struct rasops_info *)cookie; 1382 1383 if (__predict_false((unsigned int)row > ri->ri_rows || 1384 (unsigned int)col > ri->ri_cols)) 1385 return; 1386 1387 /* Avoid underflow */ 1388 if ((ri->ri_rows - row - 1) < 0) 1389 return; 1390 1391 /* Do rotated char sans (side)underline */ 1392 ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1393 attr & ~WSATTR_UNDERLINE); 1394 1395 /* Do rotated underline */ 1396 rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) * 1397 ri->ri_xscale; 1398 height = ri->ri_font->fontheight; 1399 1400 /* XXX this assumes 16-bit color depth */ 1401 if ((attr & WSATTR_UNDERLINE) != 0) { 1402 int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1403 1404 while (height--) { 1405 *(int16_t *)rp = c; 1406 rp += ri->ri_stride; 1407 } 1408 } 1409} 1410 1411static void 1412rasops_erasecols_rotated_cw(void *cookie, int row, int col, int num, long attr) 1413{ 1414 struct rasops_info *ri; 1415 int i; 1416 1417 ri = (struct rasops_info *)cookie; 1418 1419 for (i = col; i < col + num; i++) 1420 ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1421} 1422 1423/* XXX: these could likely be optimised somewhat. */ 1424static void 1425rasops_copyrows_rotated_cw(void *cookie, int src, int dst, int num) 1426{ 1427 struct rasops_info *ri = (struct rasops_info *)cookie; 1428 int col, roff; 1429 1430 if (src > dst) 1431 for (roff = 0; roff < num; roff++) 1432 for (col = 0; col < ri->ri_cols; col++) 1433 rasops_copychar(cookie, src + roff, dst + roff, 1434 col, col); 1435 else 1436 for (roff = num - 1; roff >= 0; roff--) 1437 for (col = 0; col < ri->ri_cols; col++) 1438 rasops_copychar(cookie, src + roff, dst + roff, 1439 col, col); 1440} 1441 1442static void 1443rasops_copycols_rotated_cw(void *cookie, int row, int src, int dst, int num) 1444{ 1445 int coff; 1446 1447 if (src > dst) 1448 for (coff = 0; coff < num; coff++) 1449 rasops_copychar(cookie, row, row, src + coff, dst + coff); 1450 else 1451 for (coff = num - 1; coff >= 0; coff--) 1452 rasops_copychar(cookie, row, row, src + coff, dst + coff); 1453} 1454 1455static void 1456rasops_eraserows_rotated_cw(void *cookie, int row, int num, long attr) 1457{ 1458 struct rasops_info *ri; 1459 int col, rn; 1460 1461 ri = (struct rasops_info *)cookie; 1462 1463 for (rn = row; rn < row + num; rn++) 1464 for (col = 0; col < ri->ri_cols; col++) 1465 ri->ri_ops.putchar(cookie, rn, col, ' ', attr); 1466} 1467 1468/* 1469 * Quarter counter-clockwise rotation routines (originally intended for the 1470 * built-in Sharp W-ZERO3 display in 16bpp). 1471 */ 1472static void 1473rasops_copychar_ccw(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1474{ 1475 struct rasops_info *ri; 1476 u_char *sp, *dp; 1477 int height; 1478 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1479 1480 ri = (struct rasops_info *)cookie; 1481 1482 r_srcrow = ri->ri_cols - srccol - 1; 1483 r_dstrow = ri->ri_cols - dstcol - 1; 1484 r_srccol = srcrow; 1485 r_dstcol = dstrow; 1486 1487 r_srcrow *= ri->ri_yscale; 1488 r_dstrow *= ri->ri_yscale; 1489 height = ri->ri_font->fontheight; 1490 1491 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1492 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1493 1494 while (height--) { 1495 memmove(dp, sp, ri->ri_xscale); 1496 dp += ri->ri_stride; 1497 sp += ri->ri_stride; 1498 } 1499} 1500 1501static void 1502rasops_putchar_rotated_ccw(void *cookie, int row, int col, u_int uc, long attr) 1503{ 1504 struct rasops_info *ri; 1505 u_char *rp; 1506 int height; 1507 1508 ri = (struct rasops_info *)cookie; 1509 1510 if (__predict_false((unsigned int)row > ri->ri_rows || 1511 (unsigned int)col > ri->ri_cols)) 1512 return; 1513 1514 /* Avoid underflow */ 1515 if ((ri->ri_cols - col - 1) < 0) 1516 return; 1517 1518 /* Do rotated char sans (side)underline */ 1519 ri->ri_real_ops.putchar(cookie, ri->ri_cols - col - 1, row, uc, 1520 attr & ~WSATTR_UNDERLINE); 1521 1522 /* Do rotated underline */ 1523 rp = ri->ri_bits + (ri->ri_cols - col - 1) * ri->ri_yscale + 1524 row * ri->ri_xscale + 1525 (ri->ri_font->fontwidth - 1) * ri->ri_pelbytes; 1526 height = ri->ri_font->fontheight; 1527 1528 /* XXX this assumes 16-bit color depth */ 1529 if ((attr & WSATTR_UNDERLINE) != 0) { 1530 int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1531 1532 while (height--) { 1533 *(int16_t *)rp = c; 1534 rp += ri->ri_stride; 1535 } 1536 } 1537} 1538 1539/* XXX: these could likely be optimised somewhat. */ 1540static void 1541rasops_copyrows_rotated_ccw(void *cookie, int src, int dst, int num) 1542{ 1543 struct rasops_info *ri = (struct rasops_info *)cookie; 1544 int col, roff; 1545 1546 if (src > dst) 1547 for (roff = 0; roff < num; roff++) 1548 for (col = 0; col < ri->ri_cols; col++) 1549 rasops_copychar_ccw(cookie, 1550 src + roff, dst + roff, col, col); 1551 else 1552 for (roff = num - 1; roff >= 0; roff--) 1553 for (col = 0; col < ri->ri_cols; col++) 1554 rasops_copychar_ccw(cookie, 1555 src + roff, dst + roff, col, col); 1556} 1557 1558static void 1559rasops_copycols_rotated_ccw(void *cookie, int row, int src, int dst, int num) 1560{ 1561 int coff; 1562 1563 if (src > dst) 1564 for (coff = 0; coff < num; coff++) 1565 rasops_copychar_ccw(cookie, row, row, 1566 src + coff, dst + coff); 1567 else 1568 for (coff = num - 1; coff >= 0; coff--) 1569 rasops_copychar_ccw(cookie, row, row, 1570 src + coff, dst + coff); 1571} 1572#endif /* NRASOPS_ROTATION */ 1573 1574void 1575rasops_make_box_chars_16(struct rasops_info *ri) 1576{ 1577 uint16_t vert_mask, hmask_left, hmask_right; 1578 uint16_t *data = (uint16_t *)ri->ri_optfont.data; 1579 int c, i, mid; 1580 1581 vert_mask = 0xc000 >> ((ri->ri_font->fontwidth >> 1) - 1); 1582 hmask_left = 0xff00 << (8 - (ri->ri_font->fontwidth >> 1)); 1583 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1)>> 1); 1584 mid = (ri->ri_font->fontheight + 1) >> 1; 1585 1586 /* 0x00 would be empty anyway so don't bother */ 1587 for (c = 1; c < 16; c++) { 1588 data += ri->ri_font->fontheight; 1589 if (c & 1) { 1590 /* upper segment */ 1591 for (i = 0; i < mid; i++) 1592 data[i] = vert_mask; 1593 } 1594 if (c & 4) { 1595 /* lower segment */ 1596 for (i = mid; i < ri->ri_font->fontheight; i++) 1597 data[i] = vert_mask; 1598 } 1599 if (c & 2) { 1600 /* right segment */ 1601 i = ri->ri_font->fontheight >> 1; 1602 data[mid - 1] |= hmask_right; 1603 data[mid] |= hmask_right; 1604 } 1605 if (c & 8) { 1606 /* left segment */ 1607 data[mid - 1] |= hmask_left; 1608 data[mid] |= hmask_left; 1609 } 1610 } 1611} 1612 1613void 1614rasops_make_box_chars_8(struct rasops_info *ri) 1615{ 1616 uint8_t vert_mask, hmask_left, hmask_right; 1617 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1618 int c, i, mid; 1619 1620 vert_mask = 0xc0 >> ((ri->ri_font->fontwidth >> 1) - 1); 1621 hmask_left = 0xf0 << (4 - (ri->ri_font->fontwidth >> 1)); 1622 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1)>> 1); 1623 mid = (ri->ri_font->fontheight + 1) >> 1; 1624 1625 /* 0x00 would be empty anyway so don't bother */ 1626 for (c = 1; c < 16; c++) { 1627 data += ri->ri_font->fontheight; 1628 if (c & 1) { 1629 /* upper segment */ 1630 for (i = 0; i < mid; i++) 1631 data[i] = vert_mask; 1632 } 1633 if (c & 4) { 1634 /* lower segment */ 1635 for (i = mid; i < ri->ri_font->fontheight; i++) 1636 data[i] = vert_mask; 1637 } 1638 if (c & 2) { 1639 /* right segment */ 1640 i = ri->ri_font->fontheight >> 1; 1641 data[mid - 1] |= hmask_right; 1642 data[mid] |= hmask_right; 1643 } 1644 if (c & 8) { 1645 /* left segment */ 1646 data[mid - 1] |= hmask_left; 1647 data[mid] |= hmask_left; 1648 } 1649 } 1650} 1651 1652void 1653rasops_make_box_chars_32(struct rasops_info *ri) 1654{ 1655 uint32_t vert_mask, hmask_left, hmask_right; 1656 uint32_t *data = (uint32_t *)ri->ri_optfont.data; 1657 int c, i, mid; 1658 1659 vert_mask = 0xc0000000 >> ((ri->ri_font->fontwidth >> 1) - 1); 1660 hmask_left = 0xffff0000 << (16 - (ri->ri_font->fontwidth >> 1)); 1661 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1)>> 1); 1662 mid = (ri->ri_font->fontheight + 1) >> 1; 1663 1664 /* 0x00 would be empty anyway so don't bother */ 1665 for (c = 1; c < 16; c++) { 1666 data += ri->ri_font->fontheight; 1667 if (c & 1) { 1668 /* upper segment */ 1669 for (i = 0; i < mid; i++) 1670 data[i] = vert_mask; 1671 } 1672 if (c & 4) { 1673 /* lower segment */ 1674 for (i = mid; i < ri->ri_font->fontheight; i++) 1675 data[i] = vert_mask; 1676 } 1677 if (c & 2) { 1678 /* right segment */ 1679 i = ri->ri_font->fontheight >> 1; 1680 data[mid - 1] |= hmask_right; 1681 data[mid] |= hmask_right; 1682 } 1683 if (c & 8) { 1684 /* left segment */ 1685 data[mid - 1] |= hmask_left; 1686 data[mid] |= hmask_left; 1687 } 1688 } 1689} 1690 1691void 1692rasops_make_box_chars_alpha(struct rasops_info *ri) 1693{ 1694 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1695 uint8_t *ddata; 1696 int c, i, hmid, vmid, wi, he; 1697 1698 wi = ri->ri_font->fontwidth; 1699 he = ri->ri_font->fontheight; 1700 1701 vmid = (he + 1) >> 1; 1702 hmid = (wi + 1) >> 1; 1703 1704 /* 0x00 would be empty anyway so don't bother */ 1705 for (c = 1; c < 16; c++) { 1706 data += ri->ri_fontscale; 1707 if (c & 1) { 1708 /* upper segment */ 1709 ddata = data + hmid; 1710 for (i = 0; i <= vmid; i++) { 1711 *ddata = 0xff; 1712 ddata += wi; 1713 } 1714 } 1715 if (c & 4) { 1716 /* lower segment */ 1717 ddata = data + wi * vmid + hmid; 1718 for (i = vmid; i < he; i++) { 1719 *ddata = 0xff; 1720 ddata += wi; 1721 } 1722 } 1723 if (c & 2) { 1724 /* right segment */ 1725 ddata = data + wi * vmid + hmid; 1726 for (i = hmid; i < wi; i++) { 1727 *ddata = 0xff; 1728 ddata++; 1729 } 1730 } 1731 if (c & 8) { 1732 /* left segment */ 1733 ddata = data + wi * vmid; 1734 for (i = 0; i <= hmid; i++) { 1735 *ddata = 0xff; 1736 ddata++; 1737 } 1738 } 1739 } 1740} 1741 1742/* 1743 * Return a colour map appropriate for the given struct rasops_info in the 1744 * same form used by rasops_cmap[] 1745 * For now this is either a copy of rasops_cmap[] or an R3G3B2 map, it should 1746 * probably be a linear ( or gamma corrected? ) ramp for higher depths. 1747 */ 1748 1749int 1750rasops_get_cmap(struct rasops_info *ri, uint8_t *palette, size_t bytes) 1751{ 1752 if ((ri->ri_depth == 8 ) && ((ri->ri_flg & RI_8BIT_IS_RGB) > 0)) { 1753 /* generate an R3G3B2 palette */ 1754 int i, idx = 0; 1755 uint8_t tmp; 1756 1757 if (bytes < 768) 1758 return EINVAL; 1759 for (i = 0; i < 256; i++) { 1760 tmp = i & 0xe0; 1761 /* 1762 * replicate bits so 0xe0 maps to a red value of 0xff 1763 * in order to make white look actually white 1764 */ 1765 tmp |= (tmp >> 3) | (tmp >> 6); 1766 palette[idx] = tmp; 1767 idx++; 1768 1769 tmp = (i & 0x1c) << 3; 1770 tmp |= (tmp >> 3) | (tmp >> 6); 1771 palette[idx] = tmp; 1772 idx++; 1773 1774 tmp = (i & 0x03) << 6; 1775 tmp |= tmp >> 2; 1776 tmp |= tmp >> 4; 1777 palette[idx] = tmp; 1778 idx++; 1779 } 1780 } else { 1781 memcpy(palette, rasops_cmap, MIN(bytes, sizeof(rasops_cmap))); 1782 } 1783 return 0; 1784} 1785