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