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