rasops.c revision 1.113
1/* $NetBSD: rasops.c,v 1.113 2019/08/07 11:03:14 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.113 2019/08/07 11:03:14 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 both word and 24-bit color boundary. 450 */ 451 xoff -= xoff % 12; 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#ifndef RASOPS_APPLE_PALETTE 488 ri->ri_depth < 8 489#else 490 ri->ri_depth < 4 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 = 0xff; 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 src *= ri->ri_yscale; 730 dst *= ri->ri_yscale; 731 732 if (src < dst) { 733 /* backward copy */ 734 src += (num - 1) * stride; 735 dst += (num - 1) * stride; 736 stride *= -1; 737 } 738 739 sp = ri->ri_bits + src; 740 dp = ri->ri_bits + dst; 741 if (ri->ri_hwbits) 742 hp = ri->ri_hwbits + dst; 743 744 while (num--) { 745 memcpy(dp, sp, n); 746 sp += stride; 747 if (ri->ri_hwbits) { 748 memcpy(hp, dp, n); 749 hp += stride; 750 } 751 dp += stride; 752 } 753} 754 755/* 756 * Copy columns. This is slow, and hard to optimize due to alignment, 757 * and the fact that we have to copy both left->right and right->left. 758 * We simply cop-out here and use memmove(), since it handles all of 759 * these cases anyway. 760 */ 761static void 762rasops_copycols(void *cookie, int row, int src, int dst, int num) 763{ 764 struct rasops_info *ri = (struct rasops_info *)cookie; 765 uint8_t *sp, *dp, *hp; 766 int height; 767 768 hp = NULL; /* XXX GCC */ 769 770 if (__predict_false(dst == src)) 771 return; 772 773#ifdef RASOPS_CLIPPING 774 /* Catches < 0 case too */ 775 if ((unsigned)row >= (unsigned)ri->ri_rows) 776 return; 777 778 if (src < 0) { 779 num += src; 780 src = 0; 781 } 782 783 if (src + num > ri->ri_cols) 784 num = ri->ri_cols - src; 785 786 if (dst < 0) { 787 num += dst; 788 dst = 0; 789 } 790 791 if (dst + num > ri->ri_cols) 792 num = ri->ri_cols - dst; 793 794 if (num <= 0) 795 return; 796#endif 797 798 num *= ri->ri_xscale; 799 row *= ri->ri_yscale; 800 height = ri->ri_font->fontheight; 801 802 sp = ri->ri_bits + row + src * ri->ri_xscale; 803 dp = ri->ri_bits + row + dst * ri->ri_xscale; 804 if (ri->ri_hwbits) 805 hp = ri->ri_hwbits + row + dst * ri->ri_xscale; 806 807 while (height--) { 808 memmove(dp, sp, num); 809 if (ri->ri_hwbits) { 810 memcpy(hp, dp, num); 811 hp += ri->ri_stride; 812 } 813 dp += ri->ri_stride; 814 sp += ri->ri_stride; 815 } 816} 817 818/* 819 * Turn cursor off/on. 820 */ 821static void 822rasops_cursor(void *cookie, int on, int row, int col) 823{ 824 struct rasops_info *ri = (struct rasops_info *)cookie; 825 826 /* Turn old cursor off */ 827 if ((ri->ri_flg & RI_CURSOR) != 0) 828#ifdef RASOPS_CLIPPING 829 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 830#endif 831 ri->ri_do_cursor(ri); 832 833 /* Select new cursor */ 834#ifdef RASOPS_CLIPPING 835 ri->ri_flg &= ~RI_CURSORCLIP; 836 837 if (row < 0 || row >= ri->ri_rows) 838 ri->ri_flg |= RI_CURSORCLIP; 839 else if (col < 0 || col >= ri->ri_cols) 840 ri->ri_flg |= RI_CURSORCLIP; 841#endif 842 ri->ri_crow = row; 843 ri->ri_ccol = col; 844 845 if (on) { 846 ri->ri_flg |= RI_CURSOR; 847#ifdef RASOPS_CLIPPING 848 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 849#endif 850 ri->ri_do_cursor(ri); 851 } else 852 ri->ri_flg &= ~RI_CURSOR; 853} 854 855/* 856 * Make the device colormap 857 */ 858static void 859rasops_init_devcmap(struct rasops_info *ri) 860{ 861 int i; 862 uint32_t c; 863 const uint8_t *p; 864 865 switch (ri->ri_depth) { 866 case 1: 867 ri->ri_devcmap[0] = 0; 868 for (i = 1; i < 16; i++) 869 ri->ri_devcmap[i] = -1; 870 return; 871 872 case 2: 873 for (i = 1; i < 15; i++) 874 ri->ri_devcmap[i] = 0xaaaaaaaa; 875 876 ri->ri_devcmap[0] = 0; 877 ri->ri_devcmap[8] = 0x55555555; 878 ri->ri_devcmap[15] = -1; 879 return; 880 881#ifdef RASOPS_APPLE_PALETTE 882 case 4: 883 for (i = 0; i < 16; i++) { 884 c = apple4_devcmap[i]; 885 ri->ri_devcmap[i] = 886 (c << 0) | (c << 4) | (c << 8) | (c << 12) | 887 (c << 16) | (c << 20) | (c << 24) | (c << 28); 888 } 889 return; 890#else 891 /* XXXRO What should we do here? */ 892#endif 893 894 case 8: 895 if ((ri->ri_flg & RI_8BIT_IS_RGB) == 0) { 896 for (i = 0; i < 16; i++) { 897#ifdef RASOPS_APPLE_PALETTE 898 c = apple8_devcmap[i]; 899#else 900 c = i; 901#endif 902 ri->ri_devcmap[i] = 903 c | (c << 8) | (c << 16) | (c << 24); 904 } 905 return; 906 } 907 } 908 909 p = rasops_cmap; 910 911 for (i = 0; i < 16; i++) { 912 if (ri->ri_rnum <= 8) 913 c = (uint32_t)(*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 914 else 915 c = (uint32_t)(*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 916 p++; 917 918 if (ri->ri_gnum <= 8) 919 c |= (uint32_t)(*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 920 else 921 c |= (uint32_t)(*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 922 p++; 923 924 if (ri->ri_bnum <= 8) 925 c |= (uint32_t)(*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 926 else 927 c |= (uint32_t)(*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 928 p++; 929 930 /* 931 * Swap byte order if necessary. Then, fill the word for 932 * generic routines, which want this. 933 */ 934 switch (ri->ri_depth) { 935 case 8: 936 c |= c << 8; 937 c |= c << 16; 938 break; 939 case 15: 940 case 16: 941 if ((ri->ri_flg & RI_BSWAP) != 0) 942 c = bswap16(c); 943 c |= c << 16; 944 break; 945 case 24: 946#if BYTE_ORDER == LITTLE_ENDIAN 947 if ((ri->ri_flg & RI_BSWAP) == 0) 948#else 949 if ((ri->ri_flg & RI_BSWAP) != 0) 950#endif 951 { 952 /* 953 * Convert to ``big endian'' if not RI_BSWAP. 954 */ 955 c = (c & 0x0000ff) << 16| 956 (c & 0x00ff00) | 957 (c & 0xff0000) >> 16; 958 } 959 960 /* 961 * No worries, we use generic routines only for 962 * gray colors, where all 3 bytes are same. 963 */ 964 c |= (c & 0xff) << 24; 965 break; 966 case 32: 967 if ((ri->ri_flg & RI_BSWAP) != 0) 968 c = bswap32(c); 969 break; 970 } 971 972 ri->ri_devcmap[i] = c; 973 } 974} 975 976/* 977 * Unpack a rasops attribute 978 */ 979void 980rasops_unpack_attr(long attr, int *fg, int *bg, int *underline) 981{ 982 983 *fg = ((uint32_t)attr >> 24) & 0xf; 984 *bg = ((uint32_t)attr >> 16) & 0xf; 985 if (underline != NULL) 986 *underline = (uint32_t)attr & WSATTR_UNDERLINE; 987} 988 989/* 990 * Erase rows. This isn't static, since 24-bpp uses it in special cases. 991 */ 992void 993rasops_eraserows(void *cookie, int row, int num, long attr) 994{ 995 struct rasops_info *ri = (struct rasops_info *)cookie; 996 uint32_t *buf = (uint32_t *)ri->ri_buf; 997 uint32_t *rp, *hp, clr; 998 int stride, cnt; 999 1000 hp = NULL; /* XXX GCC */ 1001 1002#ifdef RASOPS_CLIPPING 1003 if (row < 0) { 1004 num += row; 1005 row = 0; 1006 } 1007 1008 if (row + num > ri->ri_rows) 1009 num = ri->ri_rows - row; 1010 1011 if (num <= 0) 1012 return; 1013#endif 1014 1015 clr = ri->ri_devcmap[((uint32_t)attr >> 16) & 0xf]; 1016 1017 /* 1018 * XXX The wsdisplay_emulops interface seems a little deficient in 1019 * that there is no way to clear the *entire* screen. We provide a 1020 * workaround here: if the entire console area is being cleared, and 1021 * the RI_FULLCLEAR flag is set, clear the entire display. 1022 */ 1023 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 1024 stride = ri->ri_stride; 1025 num = ri->ri_height; 1026 rp = (uint32_t *)ri->ri_origbits; 1027 if (ri->ri_hwbits) 1028 hp = (uint32_t *)ri->ri_hworigbits; 1029 } else { 1030 stride = ri->ri_emustride; 1031 num *= ri->ri_font->fontheight; 1032 rp = (uint32_t *)(ri->ri_bits + row * ri->ri_yscale); 1033 if (ri->ri_hwbits) 1034 hp = (uint32_t *)(ri->ri_hwbits + row * ri->ri_yscale); 1035 } 1036 1037 for (cnt = 0; cnt < stride >> 2; cnt++) 1038 buf[cnt] = clr; 1039 1040 while (num--) { 1041 memcpy(rp, buf, stride); 1042 if (ri->ri_hwbits) { 1043 memcpy(hp, buf, stride); 1044 DELTA(hp, ri->ri_stride, uint32_t *); 1045 } 1046 DELTA(rp, ri->ri_stride, uint32_t *); 1047 } 1048} 1049 1050/* 1051 * Actually turn the cursor on or off. This does the dirty work for 1052 * rasops_cursor(). 1053 */ 1054static void 1055rasops_do_cursor(struct rasops_info *ri) 1056{ 1057 int full, height, cnt, slop1, slop2, row, col; 1058 uint32_t tmp32, msk1, msk2; 1059 uint8_t tmp8; 1060 uint8_t *dp, *rp, *hp; 1061 1062 hp = NULL; /* XXX GCC */ 1063 1064#if NRASOPS_ROTATION > 0 1065 if (ri->ri_flg & RI_ROTATE_MASK) { 1066 if (ri->ri_flg & RI_ROTATE_CW) { 1067 /* Rotate rows/columns */ 1068 row = ri->ri_ccol; 1069 col = ri->ri_rows - ri->ri_crow - 1; 1070 } else if (ri->ri_flg & RI_ROTATE_CCW) { 1071 /* Rotate rows/columns */ 1072 row = ri->ri_cols - ri->ri_ccol - 1; 1073 col = ri->ri_crow; 1074 } else { /* upside-down */ 1075 row = ri->ri_crow; 1076 col = ri->ri_ccol; 1077 } 1078 } else 1079#endif 1080 { 1081 row = ri->ri_crow; 1082 col = ri->ri_ccol; 1083 } 1084 1085 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 1086 if (ri->ri_hwbits) 1087 hp = ri->ri_hwbits + row * ri->ri_yscale + col * ri->ri_xscale; 1088 height = ri->ri_font->fontheight; 1089 1090 /* 1091 * For ri_xscale = 1: 1092 * 1093 * Logic below does not work for ri_xscale = 1, e.g., 1094 * fontwidth = 8 and bpp = 1. So we take care of it. 1095 */ 1096 if (ri->ri_xscale == 1) { 1097 while (height--) { 1098 tmp8 = ~*rp; 1099 1100 *rp = tmp8; 1101 rp += ri->ri_stride; 1102 1103 if (ri->ri_hwbits) { 1104 *hp = tmp8; 1105 hp += ri->ri_stride; 1106 } 1107 } 1108 return; 1109 } 1110 1111 /* 1112 * For ri_xscale = 2, 3, 4, ...: 1113 * 1114 * Note that siop1 <= ri_xscale even for ri_xscale = 2, 1115 * since rp % 3 = 0 or 2 (ri_stride % 4 = 0). 1116 */ 1117 slop1 = (4 - ((uintptr_t)rp & 3)) & 3; 1118 slop2 = (ri->ri_xscale - slop1) & 3; 1119 full = (ri->ri_xscale - slop1 /* - slop2 */) >> 2; 1120 1121 rp = (uint8_t *)((uintptr_t)rp & ~3); 1122 hp = (uint8_t *)((uintptr_t)hp & ~3); 1123 1124 msk1 = !slop1 ? 0 : be32toh(0xffffffffU >> (32 - (8 * slop1))); 1125 msk2 = !slop2 ? 0 : be32toh(0xffffffffU << (32 - (8 * slop2))); 1126 1127 while (height--) { 1128 dp = rp; 1129 1130 if (slop1) { 1131 tmp32 = *(uint32_t *)dp ^ msk1; 1132 *(uint32_t *)dp = tmp32; 1133 dp += 4; 1134 } 1135 1136 for (cnt = full; cnt; cnt--) { 1137 tmp32 = ~*(uint32_t *)dp; 1138 *(uint32_t *)dp = tmp32; 1139 dp += 4; 1140 } 1141 1142 if (slop2) { 1143 tmp32 = *(uint32_t *)dp ^ msk2; 1144 *(uint32_t *)dp = tmp32; 1145 } 1146 1147 if (ri->ri_hwbits) { 1148 memcpy(hp, rp, ((slop1 != 0) + full + 1149 (slop2 != 0)) << 2); 1150 hp += ri->ri_stride; 1151 } 1152 rp += ri->ri_stride; 1153 } 1154} 1155 1156/* 1157 * Erase columns. 1158 */ 1159void 1160rasops_erasecols(void *cookie, int row, int col, int num, long attr) 1161{ 1162 struct rasops_info *ri = (struct rasops_info *)cookie; 1163 uint32_t *buf = ri->ri_buf; 1164 int height, cnt, clr; 1165 uint32_t *dp, *rp, *hp; 1166 1167 hp = NULL; /* XXX GCC */ 1168 1169#ifdef RASOPS_CLIPPING 1170 if ((unsigned)row >= (unsigned)ri->ri_rows) 1171 return; 1172 1173 if (col < 0) { 1174 num += col; 1175 col = 0; 1176 } 1177 1178 if (col + num > ri->ri_cols) 1179 num = ri->ri_cols - col; 1180 1181 if (num <= 0) 1182 return; 1183#endif 1184 1185 num *= ri->ri_xscale; 1186 rp = (uint32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 1187 if (ri->ri_hwbits) 1188 hp = (uint32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 1189 col*ri->ri_xscale); 1190 height = ri->ri_font->fontheight; 1191 clr = ri->ri_devcmap[((uint32_t)attr >> 16) & 0xf]; 1192 1193 dp = buf; 1194 1195 /* Write 4 bytes per loop */ 1196 for (cnt = num >> 2; cnt; cnt--) 1197 *dp++ = clr; 1198 1199 /* Write unaligned trailing slop */ 1200 for (cnt = num & 3; cnt; cnt--) { 1201 *(uint8_t *)dp = clr; 1202 DELTA(dp, 1, uint32_t *); 1203 } 1204 1205 while (height--) { 1206 memcpy(rp, buf, num); 1207 DELTA(rp, ri->ri_stride, uint32_t *); 1208 if (ri->ri_hwbits) { 1209 memcpy(hp, buf, num); 1210 DELTA(hp, ri->ri_stride, uint32_t *); 1211 } 1212 } 1213} 1214 1215#if NRASOPS_ROTATION > 0 1216/* 1217 * Quarter clockwise rotation routines (originally intended for the 1218 * built-in Zaurus C3x00 display in 16bpp). 1219 */ 1220 1221static void 1222rasops_rotate_font(int *cookie, int rotate) 1223{ 1224 struct rotatedfont *f; 1225 int ncookie; 1226 1227 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1228 if (f->rf_cookie == *cookie) { 1229 *cookie = f->rf_rotated; 1230 return; 1231 } 1232 } 1233 1234 /* 1235 * We did not find a rotated version of this font. Ask the wsfont 1236 * code to compute one for us. 1237 */ 1238 1239 f = kmem_alloc(sizeof(*f), KM_SLEEP); 1240 1241 if ((ncookie = wsfont_rotate(*cookie, rotate)) == -1) 1242 goto fail; 1243 1244 f->rf_cookie = *cookie; 1245 f->rf_rotated = ncookie; 1246 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1247 1248 *cookie = ncookie; 1249 return; 1250 1251fail: kmem_free(f, sizeof(*f)); 1252 return; 1253} 1254 1255static void 1256rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1257{ 1258 struct rasops_info *ri = (struct rasops_info *)cookie; 1259 int height; 1260 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1261 uint8_t *sp, *dp; 1262 1263 r_srcrow = srccol; 1264 r_dstrow = dstcol; 1265 r_srccol = ri->ri_rows - srcrow - 1; 1266 r_dstcol = ri->ri_rows - dstrow - 1; 1267 1268 r_srcrow *= ri->ri_yscale; 1269 r_dstrow *= ri->ri_yscale; 1270 height = ri->ri_font->fontheight; 1271 1272 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1273 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1274 1275 while (height--) { 1276 memmove(dp, sp, ri->ri_xscale); 1277 dp += ri->ri_stride; 1278 sp += ri->ri_stride; 1279 } 1280} 1281 1282static void 1283rasops_putchar_rotated_cw(void *cookie, int row, int col, u_int uc, long attr) 1284{ 1285 struct rasops_info *ri = (struct rasops_info *)cookie; 1286 int height; 1287 uint8_t *rp; 1288 1289 if (__predict_false((unsigned int)row > ri->ri_rows || 1290 (unsigned int)col > ri->ri_cols)) 1291 return; 1292 1293 /* Avoid underflow */ 1294 if (ri->ri_rows - row - 1 < 0) 1295 return; 1296 1297 /* Do rotated char sans (side)underline */ 1298 ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1299 attr & ~WSATTR_UNDERLINE); 1300 1301 /* Do rotated underline */ 1302 rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) * 1303 ri->ri_xscale; 1304 height = ri->ri_font->fontheight; 1305 1306 /* XXX this assumes 16-bit color depth */ 1307 if ((attr & WSATTR_UNDERLINE) != 0) { 1308 uint16_t c = 1309 (uint16_t)ri->ri_devcmap[((uint32_t)attr >> 24) & 0xf]; 1310 1311 while (height--) { 1312 *(uint16_t *)rp = c; 1313 rp += ri->ri_stride; 1314 } 1315 } 1316} 1317 1318static void 1319rasops_erasecols_rotated_cw(void *cookie, int row, int col, int num, long attr) 1320{ 1321 struct rasops_info *ri = (struct rasops_info *)cookie; 1322 int i; 1323 1324 for (i = col; i < col + num; i++) 1325 ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1326} 1327 1328/* XXX: these could likely be optimised somewhat. */ 1329static void 1330rasops_copyrows_rotated_cw(void *cookie, int src, int dst, int num) 1331{ 1332 struct rasops_info *ri = (struct rasops_info *)cookie; 1333 int col, roff; 1334 1335 if (src > dst) 1336 for (roff = 0; roff < num; roff++) 1337 for (col = 0; col < ri->ri_cols; col++) 1338 rasops_copychar(cookie, src + roff, dst + roff, 1339 col, col); 1340 else 1341 for (roff = num - 1; roff >= 0; roff--) 1342 for (col = 0; col < ri->ri_cols; col++) 1343 rasops_copychar(cookie, src + roff, dst + roff, 1344 col, col); 1345} 1346 1347static void 1348rasops_copycols_rotated_cw(void *cookie, int row, int src, int dst, int num) 1349{ 1350 int coff; 1351 1352 if (src > dst) 1353 for (coff = 0; coff < num; coff++) 1354 rasops_copychar(cookie, row, row, src + coff, 1355 dst + coff); 1356 else 1357 for (coff = num - 1; coff >= 0; coff--) 1358 rasops_copychar(cookie, row, row, src + coff, 1359 dst + coff); 1360} 1361 1362static void 1363rasops_eraserows_rotated_cw(void *cookie, int row, int num, long attr) 1364{ 1365 struct rasops_info *ri = (struct rasops_info *)cookie; 1366 int col, rn; 1367 1368 for (rn = row; rn < row + num; rn++) 1369 for (col = 0; col < ri->ri_cols; col++) 1370 ri->ri_ops.putchar(cookie, rn, col, ' ', attr); 1371} 1372 1373/* 1374 * Quarter counter-clockwise rotation routines (originally intended for the 1375 * built-in Sharp W-ZERO3 display in 16bpp). 1376 */ 1377static void 1378rasops_copychar_ccw(void *cookie, int srcrow, int dstrow, int srccol, 1379 int dstcol) 1380{ 1381 struct rasops_info *ri = (struct rasops_info *)cookie; 1382 int height, r_srcrow, r_dstrow, r_srccol, r_dstcol; 1383 uint8_t *sp, *dp; 1384 1385 r_srcrow = ri->ri_cols - srccol - 1; 1386 r_dstrow = ri->ri_cols - dstcol - 1; 1387 r_srccol = srcrow; 1388 r_dstcol = dstrow; 1389 1390 r_srcrow *= ri->ri_yscale; 1391 r_dstrow *= ri->ri_yscale; 1392 height = ri->ri_font->fontheight; 1393 1394 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1395 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1396 1397 while (height--) { 1398 memmove(dp, sp, ri->ri_xscale); 1399 dp += ri->ri_stride; 1400 sp += ri->ri_stride; 1401 } 1402} 1403 1404static void 1405rasops_putchar_rotated_ccw(void *cookie, int row, int col, u_int uc, long attr) 1406{ 1407 struct rasops_info *ri = (struct rasops_info *)cookie; 1408 int height; 1409 uint8_t *rp; 1410 1411 if (__predict_false((unsigned int)row > ri->ri_rows || 1412 (unsigned int)col > ri->ri_cols)) 1413 return; 1414 1415 /* Avoid underflow */ 1416 if (ri->ri_cols - col - 1 < 0) 1417 return; 1418 1419 /* Do rotated char sans (side)underline */ 1420 ri->ri_real_ops.putchar(cookie, ri->ri_cols - col - 1, row, uc, 1421 attr & ~WSATTR_UNDERLINE); 1422 1423 /* Do rotated underline */ 1424 rp = ri->ri_bits + (ri->ri_cols - col - 1) * ri->ri_yscale + 1425 row * ri->ri_xscale + 1426 (ri->ri_font->fontwidth - 1) * ri->ri_pelbytes; 1427 height = ri->ri_font->fontheight; 1428 1429 /* XXX this assumes 16-bit color depth */ 1430 if ((attr & WSATTR_UNDERLINE) != 0) { 1431 uint16_t c = 1432 (uint16_t)ri->ri_devcmap[((uint32_t)attr >> 24) & 0xf]; 1433 1434 while (height--) { 1435 *(uint16_t *)rp = c; 1436 rp += ri->ri_stride; 1437 } 1438 } 1439} 1440 1441/* XXX: these could likely be optimised somewhat. */ 1442static void 1443rasops_copyrows_rotated_ccw(void *cookie, int src, int dst, int num) 1444{ 1445 struct rasops_info *ri = (struct rasops_info *)cookie; 1446 int col, roff; 1447 1448 if (src > dst) 1449 for (roff = 0; roff < num; roff++) 1450 for (col = 0; col < ri->ri_cols; col++) 1451 rasops_copychar_ccw(cookie, 1452 src + roff, dst + roff, col, col); 1453 else 1454 for (roff = num - 1; roff >= 0; roff--) 1455 for (col = 0; col < ri->ri_cols; col++) 1456 rasops_copychar_ccw(cookie, 1457 src + roff, dst + roff, col, col); 1458} 1459 1460static void 1461rasops_copycols_rotated_ccw(void *cookie, int row, int src, int dst, int num) 1462{ 1463 int coff; 1464 1465 if (src > dst) 1466 for (coff = 0; coff < num; coff++) 1467 rasops_copychar_ccw(cookie, row, row, 1468 src + coff, dst + coff); 1469 else 1470 for (coff = num - 1; coff >= 0; coff--) 1471 rasops_copychar_ccw(cookie, row, row, 1472 src + coff, dst + coff); 1473} 1474#endif /* NRASOPS_ROTATION */ 1475 1476void 1477rasops_make_box_chars_16(struct rasops_info *ri) 1478{ 1479 int c, i, mid; 1480 uint16_t vert_mask, hmask_left, hmask_right; 1481 uint16_t *data = (uint16_t *)ri->ri_optfont.data; 1482 1483 vert_mask = 0xc000U >> ((ri->ri_font->fontwidth >> 1) - 1); 1484 hmask_left = 0xff00U << (8 - (ri->ri_font->fontwidth >> 1)); 1485 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1486 mid = (ri->ri_font->fontheight + 1) >> 1; 1487 1488 /* 0x00 would be empty anyway so don't bother */ 1489 for (c = 1; c < 16; c++) { 1490 data += ri->ri_font->fontheight; 1491 if (c & 1) { 1492 /* upper segment */ 1493 for (i = 0; i < mid; i++) 1494 data[i] = vert_mask; 1495 } 1496 if (c & 4) { 1497 /* lower segment */ 1498 for (i = mid; i < ri->ri_font->fontheight; i++) 1499 data[i] = vert_mask; 1500 } 1501 if (c & 2) { 1502 /* right segment */ 1503 i = ri->ri_font->fontheight >> 1; 1504 data[mid - 1] |= hmask_right; 1505 data[mid] |= hmask_right; 1506 } 1507 if (c & 8) { 1508 /* left segment */ 1509 data[mid - 1] |= hmask_left; 1510 data[mid] |= hmask_left; 1511 } 1512 } 1513} 1514 1515void 1516rasops_make_box_chars_8(struct rasops_info *ri) 1517{ 1518 int c, i, mid; 1519 uint8_t vert_mask, hmask_left, hmask_right; 1520 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1521 1522 vert_mask = 0xc0U >> ((ri->ri_font->fontwidth >> 1) - 1); 1523 hmask_left = 0xf0U << (4 - (ri->ri_font->fontwidth >> 1)); 1524 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1525 mid = (ri->ri_font->fontheight + 1) >> 1; 1526 1527 /* 0x00 would be empty anyway so don't bother */ 1528 for (c = 1; c < 16; c++) { 1529 data += ri->ri_font->fontheight; 1530 if (c & 1) { 1531 /* upper segment */ 1532 for (i = 0; i < mid; i++) 1533 data[i] = vert_mask; 1534 } 1535 if (c & 4) { 1536 /* lower segment */ 1537 for (i = mid; i < ri->ri_font->fontheight; i++) 1538 data[i] = vert_mask; 1539 } 1540 if (c & 2) { 1541 /* right segment */ 1542 i = ri->ri_font->fontheight >> 1; 1543 data[mid - 1] |= hmask_right; 1544 data[mid] |= hmask_right; 1545 } 1546 if (c & 8) { 1547 /* left segment */ 1548 data[mid - 1] |= hmask_left; 1549 data[mid] |= hmask_left; 1550 } 1551 } 1552} 1553 1554void 1555rasops_make_box_chars_32(struct rasops_info *ri) 1556{ 1557 int c, i, mid; 1558 uint32_t vert_mask, hmask_left, hmask_right; 1559 uint32_t *data = (uint32_t *)ri->ri_optfont.data; 1560 1561 vert_mask = 0xc0000000U >> ((ri->ri_font->fontwidth >> 1) - 1); 1562 hmask_left = 0xffff0000U << (16 - (ri->ri_font->fontwidth >> 1)); 1563 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1564 mid = (ri->ri_font->fontheight + 1) >> 1; 1565 1566 /* 0x00 would be empty anyway so don't bother */ 1567 for (c = 1; c < 16; c++) { 1568 data += ri->ri_font->fontheight; 1569 if (c & 1) { 1570 /* upper segment */ 1571 for (i = 0; i < mid; i++) 1572 data[i] = vert_mask; 1573 } 1574 if (c & 4) { 1575 /* lower segment */ 1576 for (i = mid; i < ri->ri_font->fontheight; i++) 1577 data[i] = vert_mask; 1578 } 1579 if (c & 2) { 1580 /* right segment */ 1581 i = ri->ri_font->fontheight >> 1; 1582 data[mid - 1] |= hmask_right; 1583 data[mid] |= hmask_right; 1584 } 1585 if (c & 8) { 1586 /* left segment */ 1587 data[mid - 1] |= hmask_left; 1588 data[mid] |= hmask_left; 1589 } 1590 } 1591} 1592 1593void 1594rasops_make_box_chars_alpha(struct rasops_info *ri) 1595{ 1596 int c, i, hmid, vmid, wi, he; 1597 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1598 uint8_t *ddata; 1599 1600 he = ri->ri_font->fontheight; 1601 wi = ri->ri_font->fontwidth; 1602 1603 vmid = (he + 1) >> 1; 1604 hmid = (wi + 1) >> 1; 1605 1606 /* 0x00 would be empty anyway so don't bother */ 1607 for (c = 1; c < 16; c++) { 1608 data += ri->ri_fontscale; 1609 if (c & 1) { 1610 /* upper segment */ 1611 ddata = data + hmid; 1612 for (i = 0; i <= vmid; i++) { 1613 *ddata = 0xff; 1614 ddata += wi; 1615 } 1616 } 1617 if (c & 4) { 1618 /* lower segment */ 1619 ddata = data + wi * vmid + hmid; 1620 for (i = vmid; i < he; i++) { 1621 *ddata = 0xff; 1622 ddata += wi; 1623 } 1624 } 1625 if (c & 2) { 1626 /* right segment */ 1627 ddata = data + wi * vmid + hmid; 1628 for (i = hmid; i < wi; i++) { 1629 *ddata = 0xff; 1630 ddata++; 1631 } 1632 } 1633 if (c & 8) { 1634 /* left segment */ 1635 ddata = data + wi * vmid; 1636 for (i = 0; i <= hmid; i++) { 1637 *ddata = 0xff; 1638 ddata++; 1639 } 1640 } 1641 } 1642} 1643 1644/* 1645 * Return a colour map appropriate for the given struct rasops_info in the 1646 * same form used by rasops_cmap[] 1647 * For now this is either a copy of rasops_cmap[] or an R3G3B2 map, it should 1648 * probably be a linear ( or gamma corrected? ) ramp for higher depths. 1649 */ 1650int 1651rasops_get_cmap(struct rasops_info *ri, uint8_t *palette, size_t bytes) 1652{ 1653 1654 if ((ri->ri_depth == 8) && ((ri->ri_flg & RI_8BIT_IS_RGB) != 0)) { 1655 /* generate an R3G3B2 palette */ 1656 int i, idx = 0; 1657 uint8_t tmp; 1658 1659 if (bytes < 768) 1660 return EINVAL; 1661 for (i = 0; i < 256; i++) { 1662 tmp = i & 0xe0; 1663 /* 1664 * replicate bits so 0xe0 maps to a red value of 0xff 1665 * in order to make white look actually white 1666 */ 1667 tmp |= (tmp >> 3) | (tmp >> 6); 1668 palette[idx] = tmp; 1669 idx++; 1670 1671 tmp = (i & 0x1c) << 3; 1672 tmp |= (tmp >> 3) | (tmp >> 6); 1673 palette[idx] = tmp; 1674 idx++; 1675 1676 tmp = (i & 0x03) << 6; 1677 tmp |= tmp >> 2; 1678 tmp |= tmp >> 4; 1679 palette[idx] = tmp; 1680 idx++; 1681 } 1682 } else 1683 memcpy(palette, rasops_cmap, uimin(bytes, sizeof(rasops_cmap))); 1684 return 0; 1685} 1686 1687#ifndef RASOPS_SMALL 1688void 1689rasops_allocstamp(struct rasops_info *ri, size_t len) 1690{ 1691 1692 KASSERT(ri->ri_stamp == NULL); 1693 ri->ri_stamp_len = len; 1694 ri->ri_stamp = kmem_zalloc(len, KM_SLEEP); 1695 ri->ri_stamp_attr = 0; 1696} 1697#endif 1698