rasops.c revision 1.124
1/* $NetBSD: rasops.c,v 1.124 2021/10/04 12:26:29 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.124 2021/10/04 12:26:29 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 kmem_free(ri->ri_optfont.data, len); 380 ri->ri_optfont.data = NULL; 381 aprint_verbose( 382 "%s: font stride assumptions botched", 383 __func__); 384 break; 385 } 386 } 387 } else 388 memset(&ri->ri_optfont, 0, sizeof(ri->ri_optfont)); 389 390 /* Need this to frob the setup below */ 391 bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth); 392 393 if ((ri->ri_flg & RI_CFGDONE) != 0) { 394 ri->ri_bits = ri->ri_origbits; 395 ri->ri_hwbits = ri->ri_hworigbits; 396 } 397 398 /* Don't care if the caller wants a hideously small console */ 399 if (wantrows < 10) 400 wantrows = 10; 401 402 if (wantcols < 20) 403 wantcols = 20; 404 405 /* Now constrain what they get */ 406 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols; 407 ri->ri_emuheight = ri->ri_font->fontheight * wantrows; 408 409 if (ri->ri_emuwidth > ri->ri_width) 410 ri->ri_emuwidth = ri->ri_width; 411 412 if (ri->ri_emuheight > ri->ri_height) 413 ri->ri_emuheight = ri->ri_height; 414 415 /* Reduce width until aligned on a 32-bit boundary */ 416 while ((ri->ri_emuwidth * bpp & 31) != 0) 417 ri->ri_emuwidth--; 418 419#if NRASOPS_ROTATION > 0 420 if (ri->ri_flg & (RI_ROTATE_CW|RI_ROTATE_CCW)) { 421 ri->ri_rows = ri->ri_emuwidth / ri->ri_font->fontwidth; 422 ri->ri_cols = ri->ri_emuheight / ri->ri_font->fontheight; 423 } else 424#endif 425 { 426 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth; 427 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight; 428 } 429 ri->ri_emustride = ri->ri_emuwidth * bpp >> 3; 430 ri->ri_ccol = 0; 431 ri->ri_crow = 0; 432 ri->ri_pelbytes = bpp >> 3; 433 434 ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3; 435 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride; 436 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 437 438 ri->ri_origbits = ri->ri_bits; 439 ri->ri_hworigbits = ri->ri_hwbits; 440 441 /* Clear the entire display */ 442 if ((ri->ri_flg & RI_CLEAR) != 0) { 443 rasops_memset32(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 444 if (ri->ri_hwbits) 445 rasops_memset32(ri->ri_hwbits, 0, 446 ri->ri_stride * ri->ri_height); 447 } 448 449 /* Now centre our window if needs be */ 450 if ((ri->ri_flg & RI_CENTER) != 0) { 451 uint32_t xoff, yoff; 452 453 xoff = ((ri->ri_width * bpp >> 3) - ri->ri_emustride) >> 1; 454 if (ri->ri_depth != 24) { 455 /* 456 * Truncate to word boundary. 457 */ 458 xoff &= ~3; 459 } else { 460 /* 461 * Truncate to both word and 24-bit color boundary. 462 */ 463 xoff -= xoff % 12; 464 } 465 466 yoff = ((ri->ri_height - ri->ri_emuheight) >> 1) * 467 ri->ri_stride; 468 469 ri->ri_bits += xoff; 470 ri->ri_bits += yoff; 471 if (ri->ri_hwbits != NULL) { 472 ri->ri_hwbits += xoff; 473 ri->ri_hwbits += yoff; 474 } 475 476 ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits) / 477 ri->ri_stride; 478 ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits) % 479 ri->ri_stride) * 8 / bpp); 480 } else 481 ri->ri_xorigin = ri->ri_yorigin = 0; 482 483 /* Scaling underline by font height */ 484 height = ri->ri_font->fontheight; 485 ri->ri_ul.off = rounddown(height, 16) / 16; /* offset from bottom */ 486 ri->ri_ul.height = roundup(height, 16) / 16; /* height */ 487 488 /* 489 * Fill in defaults for operations set. XXX this nukes private 490 * routines used by accelerated fb drivers. 491 */ 492 ri->ri_ops.mapchar = rasops_mapchar; 493 ri->ri_ops.copyrows = rasops_copyrows; 494 ri->ri_ops.copycols = rasops_copycols; 495 ri->ri_ops.erasecols = rasops_erasecols; 496 ri->ri_ops.eraserows = rasops_eraserows; 497 ri->ri_ops.cursor = rasops_cursor; 498 ri->ri_do_cursor = rasops_do_cursor; 499 500 ri->ri_caps &= ~(WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 501 WSSCREEN_WSCOLORS | WSSCREEN_REVERSE); 502 503 if ((ri->ri_flg & RI_FORCEMONO) != 0 || 504#ifndef RASOPS_APPLE_PALETTE 505 ri->ri_depth < 8 506#else 507 ri->ri_depth < 4 508#endif 509 ) { 510 ri->ri_ops.allocattr = rasops_allocattr_mono; 511 ri->ri_caps |= WSSCREEN_UNDERLINE | WSSCREEN_REVERSE; 512 } else { 513 ri->ri_ops.allocattr = rasops_allocattr_color; 514 ri->ri_caps |= WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 515 WSSCREEN_WSCOLORS | WSSCREEN_REVERSE; 516 } 517 518 switch (ri->ri_depth) { 519#if NRASOPS1 > 0 520 case 1: 521 rasops1_init(ri); 522 break; 523#endif 524#if NRASOPS2 > 0 525 case 2: 526 rasops2_init(ri); 527 break; 528#endif 529#if NRASOPS4 > 0 530 case 4: 531 rasops4_init(ri); 532 break; 533#endif 534#if NRASOPS8 > 0 535 case 8: 536 rasops8_init(ri); 537 break; 538#endif 539#if (NRASOPS15 + NRASOPS16) > 0 540 case 15: 541 case 16: 542 rasops15_init(ri); 543 break; 544#endif 545#if NRASOPS24 > 0 546 case 24: 547 rasops24_init(ri); 548 break; 549#endif 550#if NRASOPS32 > 0 551 case 32: 552 rasops32_init(ri); 553 break; 554#endif 555 default: 556 ri->ri_flg &= ~RI_CFGDONE; 557 aprint_error("%s: depth not supported\n", __func__); 558 splx(s); 559 return -1; 560 } 561 562#if NRASOPS_ROTATION > 0 563 if (ri->ri_flg & RI_ROTATE_MASK) { 564 if (ri->ri_flg & RI_ROTATE_CW) { 565 ri->ri_real_ops = ri->ri_ops; 566 ri->ri_ops.copycols = rasops_copycols_rotated_cw; 567 ri->ri_ops.copyrows = rasops_copyrows_rotated_cw; 568 ri->ri_ops.erasecols = rasops_erasecols_rotated_cw; 569 ri->ri_ops.eraserows = rasops_eraserows_rotated_cw; 570 ri->ri_ops.putchar = rasops_putchar_rotated_cw; 571 } else if (ri->ri_flg & RI_ROTATE_CCW) { 572 ri->ri_real_ops = ri->ri_ops; 573 ri->ri_ops.copycols = rasops_copycols_rotated_ccw; 574 ri->ri_ops.copyrows = rasops_copyrows_rotated_ccw; 575 ri->ri_ops.erasecols = rasops_erasecols_rotated_ccw; 576 ri->ri_ops.eraserows = rasops_eraserows_rotated_ccw; 577 ri->ri_ops.putchar = rasops_putchar_rotated_ccw; 578 } 579 } 580#endif 581 582 ri->ri_flg |= RI_CFGDONE; 583 splx(s); 584 return 0; 585} 586 587/* 588 * Map a character. 589 */ 590static int 591rasops_mapchar(void *cookie, int c, u_int *cp) 592{ 593 struct rasops_info *ri = (struct rasops_info *)cookie; 594 595 KASSERT(ri->ri_font != NULL); 596 597 if ((c = wsfont_map_unichar(ri->ri_font, c)) < 0 || 598 !CHAR_IN_FONT(c, ri->ri_font)) { 599 *cp = ' '; 600 return 0; 601 } 602 603 *cp = c; 604 return 5; 605} 606 607/* 608 * Allocate a color attribute. 609 */ 610static int 611rasops_allocattr_color(void *cookie, int fg0, int bg0, int flg, long *attr) 612{ 613 uint32_t fg = fg0, bg = bg0; 614 615 if (__predict_false(fg >= sizeof(rasops_isgray) || 616 bg >= sizeof(rasops_isgray))) 617 return EINVAL; 618 619#ifdef RASOPS_CLIPPING 620 fg &= 7; 621 bg &= 7; 622#endif 623 624 if ((flg & WSATTR_BLINK) != 0) 625 return EINVAL; 626 627 if ((flg & WSATTR_WSCOLORS) == 0) { 628#ifdef WS_DEFAULT_FG 629 fg = WS_DEFAULT_FG; 630#else 631 fg = WSCOL_WHITE; 632#endif 633#ifdef WS_DEFAULT_BG 634 bg = WS_DEFAULT_BG; 635#else 636 bg = WSCOL_BLACK; 637#endif 638 } 639 640 if ((flg & WSATTR_HILIT) != 0 && fg < 8) 641 fg += 8; 642 643 if ((flg & WSATTR_REVERSE) != 0) { 644 uint32_t swap = fg; 645 fg = bg; 646 bg = swap; 647 } 648 649 flg &= WSATTR_USERMASK; 650 651 if (rasops_isgray[fg]) 652 flg |= WSATTR_PRIVATE1; 653 654 if (rasops_isgray[bg]) 655 flg |= WSATTR_PRIVATE2; 656 657 *attr = (bg << 16) | (fg << 24) | flg; 658 return 0; 659} 660 661/* 662 * Allocate a mono attribute. 663 */ 664static int 665rasops_allocattr_mono(void *cookie, int fg0, int bg0, int flg, long *attr) 666{ 667 uint32_t fg = fg0, bg = bg0; 668 669 if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0) 670 return EINVAL; 671 672 fg = 0xff; 673 bg = 0; 674 675 if ((flg & WSATTR_REVERSE) != 0) { 676 uint32_t swap = fg; 677 fg = bg; 678 bg = swap; 679 } 680 681 *attr = (bg << 16) | (fg << 24) | flg; 682 return 0; 683} 684 685/* 686 * Copy rows. 687 */ 688static void 689rasops_copyrows(void *cookie, int src, int dst, int num) 690{ 691 struct rasops_info *ri = (struct rasops_info *)cookie; 692 int stride; 693 uint8_t *sp, *dp, *hp; 694 695 hp = NULL; /* XXX GCC */ 696 697 if (__predict_false(dst == src)) 698 return; 699 700#ifdef RASOPS_CLIPPING 701 if (src < 0) { 702 num += src; 703 src = 0; 704 } 705 706 if (src + num > ri->ri_rows) 707 num = ri->ri_rows - src; 708 709 if (dst < 0) { 710 num += dst; 711 dst = 0; 712 } 713 714 if (dst + num > ri->ri_rows) 715 num = ri->ri_rows - dst; 716 717 if (num <= 0) 718 return; 719#endif 720 721 src *= ri->ri_yscale; 722 dst *= ri->ri_yscale; 723 num *= ri->ri_font->fontheight; 724 stride = ri->ri_stride; 725 726 if (src < dst) { 727 /* backward copy */ 728 src += (num - 1) * stride; 729 dst += (num - 1) * stride; 730 stride *= -1; 731 } 732 733 sp = ri->ri_bits + src; 734 dp = ri->ri_bits + dst; 735 if (ri->ri_hwbits) 736 hp = ri->ri_hwbits + dst; 737 738 while (num--) { 739 memcpy(dp, sp, ri->ri_emustride); 740 if (ri->ri_hwbits) { 741 memcpy(hp, dp, ri->ri_emustride); 742 hp += stride; 743 } 744 sp += stride; 745 dp += stride; 746 } 747} 748 749/* 750 * Copy columns. This is slow, and hard to optimize due to alignment, 751 * and the fact that we have to copy both left->right and right->left. 752 * We simply cop-out here and use memmove(), since it handles all of 753 * these cases anyway. 754 */ 755static void 756rasops_copycols(void *cookie, int row, int src, int dst, int num) 757{ 758 struct rasops_info *ri = (struct rasops_info *)cookie; 759 int height; 760 uint8_t *sp, *dp, *hp; 761 762 hp = NULL; /* XXX GCC */ 763 764 if (__predict_false(dst == src)) 765 return; 766 767#ifdef RASOPS_CLIPPING 768 /* Catches < 0 case too */ 769 if ((unsigned)row >= (unsigned)ri->ri_rows) 770 return; 771 772 if (src < 0) { 773 num += src; 774 src = 0; 775 } 776 777 if (src + num > ri->ri_cols) 778 num = ri->ri_cols - src; 779 780 if (dst < 0) { 781 num += dst; 782 dst = 0; 783 } 784 785 if (dst + num > ri->ri_cols) 786 num = ri->ri_cols - dst; 787 788 if (num <= 0) 789 return; 790#endif 791 792 height = ri->ri_font->fontheight; 793 row *= ri->ri_yscale; 794 num *= ri->ri_xscale; 795 796 sp = ri->ri_bits + row + src * ri->ri_xscale; 797 dp = ri->ri_bits + row + dst * ri->ri_xscale; 798 if (ri->ri_hwbits) 799 hp = ri->ri_hwbits + row + dst * ri->ri_xscale; 800 801 while (height--) { 802 memmove(dp, sp, num); 803 if (ri->ri_hwbits) { 804 memcpy(hp, dp, num); 805 hp += ri->ri_stride; 806 } 807 sp += ri->ri_stride; 808 dp += ri->ri_stride; 809 } 810} 811 812/* 813 * Turn cursor off/on. 814 */ 815static void 816rasops_cursor(void *cookie, int on, int row, int col) 817{ 818 struct rasops_info *ri = (struct rasops_info *)cookie; 819 820 /* Turn old cursor off */ 821 if ((ri->ri_flg & RI_CURSOR) != 0) 822#ifdef RASOPS_CLIPPING 823 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 824#endif 825 ri->ri_do_cursor(ri); 826 827 /* Select new cursor */ 828 ri->ri_crow = row; 829 ri->ri_ccol = col; 830 831#ifdef RASOPS_CLIPPING 832 ri->ri_flg &= ~RI_CURSORCLIP; 833 if (row < 0 || row >= ri->ri_rows) 834 ri->ri_flg |= RI_CURSORCLIP; 835 else if (col < 0 || col >= ri->ri_cols) 836 ri->ri_flg |= RI_CURSORCLIP; 837#endif 838 839 if (on) { 840 ri->ri_flg |= RI_CURSOR; 841#ifdef RASOPS_CLIPPING 842 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 843#endif 844 ri->ri_do_cursor(ri); 845 } else 846 ri->ri_flg &= ~RI_CURSOR; 847} 848 849/* 850 * Make the device colormap 851 */ 852static void 853rasops_init_devcmap(struct rasops_info *ri) 854{ 855 int i; 856 uint32_t c; 857 const uint8_t *p; 858 859 switch (ri->ri_depth) { 860 case 1: 861 ri->ri_devcmap[0] = 0; 862 for (i = 1; i < 16; i++) 863 ri->ri_devcmap[i] = -1; 864 return; 865 866 case 2: 867 for (i = 1; i < 15; i++) 868 ri->ri_devcmap[i] = 0xaaaaaaaa; 869 870 ri->ri_devcmap[0] = 0; 871 ri->ri_devcmap[8] = 0x55555555; 872 ri->ri_devcmap[15] = -1; 873 return; 874 875 case 4: 876 for (i = 0; i < 16; i++) { 877#ifdef RASOPS_APPLE_PALETTE 878 c = apple4_devcmap[i]; 879#else 880 c = i; 881#endif 882 ri->ri_devcmap[i] = 883 (c << 0) | (c << 4) | (c << 8) | (c << 12) | 884 (c << 16) | (c << 20) | (c << 24) | (c << 28); 885 } 886 return; 887 888 case 8: 889 if ((ri->ri_flg & RI_8BIT_IS_RGB) == 0) { 890 for (i = 0; i < 16; i++) { 891#ifdef RASOPS_APPLE_PALETTE 892 c = apple8_devcmap[i]; 893#else 894 c = i; 895#endif 896 ri->ri_devcmap[i] = 897 c | (c << 8) | (c << 16) | (c << 24); 898 } 899 return; 900 } 901 } 902 903 p = rasops_cmap; 904 905 for (i = 0; i < 16; i++) { 906 if (ri->ri_rnum <= 8) 907 c = (uint32_t)(*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 908 else 909 c = (uint32_t)(*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 910 p++; 911 912 if (ri->ri_gnum <= 8) 913 c |= (uint32_t)(*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 914 else 915 c |= (uint32_t)(*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 916 p++; 917 918 if (ri->ri_bnum <= 8) 919 c |= (uint32_t)(*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 920 else 921 c |= (uint32_t)(*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 922 p++; 923 924 /* 925 * Swap byte order if necessary. Then, fill the word for 926 * generic routines, which want this. 927 */ 928 switch (ri->ri_depth) { 929 case 8: 930 c |= c << 8; 931 c |= c << 16; 932 break; 933 case 15: 934 case 16: 935 if ((ri->ri_flg & RI_BSWAP) != 0) 936 c = bswap16(c); 937 c |= c << 16; 938 break; 939 case 24: 940#if BYTE_ORDER == LITTLE_ENDIAN 941 if ((ri->ri_flg & RI_BSWAP) == 0) 942#else 943 if ((ri->ri_flg & RI_BSWAP) != 0) 944#endif 945 { 946 /* 947 * Convert to ``big endian'' if not RI_BSWAP. 948 */ 949 c = (c & 0x0000ff) << 16| 950 (c & 0x00ff00) | 951 (c & 0xff0000) >> 16; 952 } 953 /* 954 * No worries, we use generic routines only for 955 * gray colors, where all 3 bytes are same. 956 */ 957 c |= (c & 0xff) << 24; 958 break; 959 case 32: 960 if ((ri->ri_flg & RI_BSWAP) != 0) 961 c = bswap32(c); 962 break; 963 } 964 965 ri->ri_devcmap[i] = c; 966 } 967} 968 969/* 970 * Unpack a rasops attribute 971 */ 972void 973rasops_unpack_attr(long attr, int *fg, int *bg, int *underline) 974{ 975 976 *fg = ((uint32_t)attr >> 24) & 0xf; 977 *bg = ((uint32_t)attr >> 16) & 0xf; 978 if (underline != NULL) 979 *underline = (uint32_t)attr & WSATTR_UNDERLINE; 980} 981 982/* 983 * Erase rows. This isn't static, since 24-bpp uses it in special cases. 984 */ 985void 986rasops_eraserows(void *cookie, int row, int num, long attr) 987{ 988 struct rasops_info *ri = (struct rasops_info *)cookie; 989 int bytes; 990 uint32_t bg, *rp, *hp; 991 992 hp = NULL; /* XXX GCC */ 993 994#ifdef RASOPS_CLIPPING 995 if (row < 0) { 996 num += row; 997 row = 0; 998 } 999 1000 if (row + num > ri->ri_rows) 1001 num = ri->ri_rows - row; 1002 1003 if (num <= 0) 1004 return; 1005#endif 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 bytes = 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 bytes = 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 bg = ATTR_BG(ri, attr); 1028 1029 while (num--) { 1030 rasops_memset32(rp, bg, bytes); 1031 if (ri->ri_hwbits) { 1032 memcpy(hp, rp, bytes); 1033 DELTA(hp, ri->ri_stride, uint32_t *); 1034 } 1035 DELTA(rp, ri->ri_stride, uint32_t *); 1036 } 1037} 1038 1039/* 1040 * Actually turn the cursor on or off. This does the dirty work for 1041 * rasops_cursor(). 1042 */ 1043static void 1044rasops_do_cursor(struct rasops_info *ri) 1045{ 1046 int row, col, height, slop1, slop2, full, cnt; 1047 uint32_t mask1, mask2, *dp; 1048 uint8_t tmp, *rp, *hp; 1049 1050 hp = NULL; /* XXX GCC */ 1051 1052#if NRASOPS_ROTATION > 0 1053 if (ri->ri_flg & RI_ROTATE_MASK) { 1054 if (ri->ri_flg & RI_ROTATE_CW) { 1055 /* Rotate rows/columns */ 1056 row = ri->ri_ccol; 1057 col = ri->ri_rows - ri->ri_crow - 1; 1058 } else if (ri->ri_flg & RI_ROTATE_CCW) { 1059 /* Rotate rows/columns */ 1060 row = ri->ri_cols - ri->ri_ccol - 1; 1061 col = ri->ri_crow; 1062 } else { /* upside-down */ 1063 row = ri->ri_crow; 1064 col = ri->ri_ccol; 1065 } 1066 } else 1067#endif 1068 { 1069 row = ri->ri_crow; 1070 col = ri->ri_ccol; 1071 } 1072 1073 height = ri->ri_font->fontheight; 1074 1075 rp = ri->ri_bits + FBOFFSET(ri, row, col); 1076 if (ri->ri_hwbits) 1077 hp = ri->ri_hwbits + FBOFFSET(ri, row, col); 1078 1079 /* 1080 * For ri_xscale = 1: 1081 * 1082 * Logic below does not work for ri_xscale = 1, e.g., 1083 * fontwidth = 8 and bpp = 1. So we take care of it. 1084 */ 1085 if (ri->ri_xscale == 1) { 1086 while (height--) { 1087 tmp = ~*rp; 1088 *rp = tmp; 1089 if (ri->ri_hwbits) { 1090 *hp = tmp; 1091 hp += ri->ri_stride; 1092 } 1093 rp += ri->ri_stride; 1094 } 1095 return; 1096 } 1097 1098 /* 1099 * For ri_xscale = 2, 3, 4, ...: 1100 * 1101 * Note that siop1 <= ri_xscale even for ri_xscale = 2, 1102 * since rp % 3 = 0 or 2 (ri_stride % 4 = 0). 1103 */ 1104 slop1 = (4 - ((uintptr_t)rp & 3)) & 3; 1105 slop2 = (ri->ri_xscale - slop1) & 3; 1106 full = (ri->ri_xscale - slop1 /* - slop2 */) >> 2; 1107 1108 rp = (uint8_t *)((uintptr_t)rp & ~3); 1109 hp = (uint8_t *)((uintptr_t)hp & ~3); 1110 1111 mask1 = rasops_lmask32[4 - slop1]; 1112 mask2 = rasops_rmask32[slop2]; 1113 1114 while (height--) { 1115 dp = (uint32_t *)rp; 1116 1117 if (slop1) { 1118 *dp = *dp ^ mask1; 1119 dp++; 1120 } 1121 1122 for (cnt = full; cnt; cnt--) { 1123 *dp = ~*dp; 1124 dp++; 1125 } 1126 1127 if (slop2) 1128 *dp = *dp ^ mask2; 1129 1130 if (ri->ri_hwbits) { 1131 memcpy(hp, rp, ((slop1 != 0) + full + 1132 (slop2 != 0)) << 2); 1133 hp += ri->ri_stride; 1134 } 1135 rp += ri->ri_stride; 1136 } 1137} 1138 1139/* 1140 * Erase columns. 1141 */ 1142void 1143rasops_erasecols(void *cookie, int row, int col, int num, long attr) 1144{ 1145 struct rasops_info *ri = (struct rasops_info *)cookie; 1146 int height; 1147 uint32_t bg, *rp, *hp; 1148 1149 hp = NULL; /* XXX GCC */ 1150 1151#ifdef RASOPS_CLIPPING 1152 if ((unsigned)row >= (unsigned)ri->ri_rows) 1153 return; 1154 1155 if (col < 0) { 1156 num += col; 1157 col = 0; 1158 } 1159 1160 if (col + num > ri->ri_cols) 1161 num = ri->ri_cols - col; 1162 1163 if (num <= 0) 1164 return; 1165#endif 1166 1167 height = ri->ri_font->fontheight; 1168 num *= ri->ri_xscale; 1169 1170 rp = (uint32_t *)(ri->ri_bits + FBOFFSET(ri, row, col)); 1171 if (ri->ri_hwbits) 1172 hp = (uint32_t *)(ri->ri_hwbits + FBOFFSET(ri, row, col)); 1173 1174 bg = ATTR_BG(ri, attr); 1175 1176 while (height--) { 1177 rasops_memset32(rp, bg, num); 1178 if (ri->ri_hwbits) { 1179 memcpy(hp, rp, num); 1180 DELTA(hp, ri->ri_stride, uint32_t *); 1181 } 1182 DELTA(rp, ri->ri_stride, uint32_t *); 1183 } 1184} 1185 1186void 1187rasops_make_box_chars_16(struct rasops_info *ri) 1188{ 1189 int c, i, mid; 1190 uint16_t vert_mask, hmask_left, hmask_right; 1191 uint16_t *data = (uint16_t *)ri->ri_optfont.data; 1192 1193 vert_mask = 0xc000U >> ((ri->ri_font->fontwidth >> 1) - 1); 1194 hmask_left = 0xff00U << (8 - (ri->ri_font->fontwidth >> 1)); 1195 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1196 mid = (ri->ri_font->fontheight + 1) >> 1; 1197 1198 /* 0x00 would be empty anyway so don't bother */ 1199 for (c = 1; c < 16; c++) { 1200 data += ri->ri_font->fontheight; 1201 if (c & 1) { 1202 /* upper segment */ 1203 for (i = 0; i < mid; i++) 1204 data[i] = vert_mask; 1205 } 1206 if (c & 4) { 1207 /* lower segment */ 1208 for (i = mid; i < ri->ri_font->fontheight; i++) 1209 data[i] = vert_mask; 1210 } 1211 if (c & 2) { 1212 /* right segment */ 1213 i = ri->ri_font->fontheight >> 1; 1214 data[mid - 1] |= hmask_right; 1215 data[mid] |= hmask_right; 1216 } 1217 if (c & 8) { 1218 /* left segment */ 1219 data[mid - 1] |= hmask_left; 1220 data[mid] |= hmask_left; 1221 } 1222 } 1223} 1224 1225void 1226rasops_make_box_chars_8(struct rasops_info *ri) 1227{ 1228 int c, i, mid; 1229 uint8_t vert_mask, hmask_left, hmask_right; 1230 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1231 1232 vert_mask = 0xc0U >> ((ri->ri_font->fontwidth >> 1) - 1); 1233 hmask_left = 0xf0U << (4 - (ri->ri_font->fontwidth >> 1)); 1234 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1235 mid = (ri->ri_font->fontheight + 1) >> 1; 1236 1237 /* 0x00 would be empty anyway so don't bother */ 1238 for (c = 1; c < 16; c++) { 1239 data += ri->ri_font->fontheight; 1240 if (c & 1) { 1241 /* upper segment */ 1242 for (i = 0; i < mid; i++) 1243 data[i] = vert_mask; 1244 } 1245 if (c & 4) { 1246 /* lower segment */ 1247 for (i = mid; i < ri->ri_font->fontheight; i++) 1248 data[i] = vert_mask; 1249 } 1250 if (c & 2) { 1251 /* right segment */ 1252 i = ri->ri_font->fontheight >> 1; 1253 data[mid - 1] |= hmask_right; 1254 data[mid] |= hmask_right; 1255 } 1256 if (c & 8) { 1257 /* left segment */ 1258 data[mid - 1] |= hmask_left; 1259 data[mid] |= hmask_left; 1260 } 1261 } 1262} 1263 1264void 1265rasops_make_box_chars_32(struct rasops_info *ri) 1266{ 1267 int c, i, mid; 1268 uint32_t vert_mask, hmask_left, hmask_right; 1269 uint32_t *data = (uint32_t *)ri->ri_optfont.data; 1270 1271 vert_mask = 0xc0000000U >> ((ri->ri_font->fontwidth >> 1) - 1); 1272 hmask_left = 0xffff0000U << (16 - (ri->ri_font->fontwidth >> 1)); 1273 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1274 mid = (ri->ri_font->fontheight + 1) >> 1; 1275 1276 /* 0x00 would be empty anyway so don't bother */ 1277 for (c = 1; c < 16; c++) { 1278 data += ri->ri_font->fontheight; 1279 if (c & 1) { 1280 /* upper segment */ 1281 for (i = 0; i < mid; i++) 1282 data[i] = vert_mask; 1283 } 1284 if (c & 4) { 1285 /* lower segment */ 1286 for (i = mid; i < ri->ri_font->fontheight; i++) 1287 data[i] = vert_mask; 1288 } 1289 if (c & 2) { 1290 /* right segment */ 1291 i = ri->ri_font->fontheight >> 1; 1292 data[mid - 1] |= hmask_right; 1293 data[mid] |= hmask_right; 1294 } 1295 if (c & 8) { 1296 /* left segment */ 1297 data[mid - 1] |= hmask_left; 1298 data[mid] |= hmask_left; 1299 } 1300 } 1301} 1302 1303void 1304rasops_make_box_chars_alpha(struct rasops_info *ri) 1305{ 1306 int c, i, hmid, vmid, wi, he; 1307 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1308 uint8_t *ddata; 1309 1310 he = ri->ri_font->fontheight; 1311 wi = ri->ri_font->fontwidth; 1312 1313 vmid = (he + 1) >> 1; 1314 hmid = (wi + 1) >> 1; 1315 1316 /* 0x00 would be empty anyway so don't bother */ 1317 for (c = 1; c < 16; c++) { 1318 data += ri->ri_fontscale; 1319 if (c & 1) { 1320 /* upper segment */ 1321 ddata = data + hmid; 1322 for (i = 0; i <= vmid; i++) { 1323 *ddata = 0xff; 1324 ddata += wi; 1325 } 1326 } 1327 if (c & 4) { 1328 /* lower segment */ 1329 ddata = data + wi * vmid + hmid; 1330 for (i = vmid; i < he; i++) { 1331 *ddata = 0xff; 1332 ddata += wi; 1333 } 1334 } 1335 if (c & 2) { 1336 /* right segment */ 1337 ddata = data + wi * vmid + hmid; 1338 for (i = hmid; i < wi; i++) { 1339 *ddata = 0xff; 1340 ddata++; 1341 } 1342 } 1343 if (c & 8) { 1344 /* left segment */ 1345 ddata = data + wi * vmid; 1346 for (i = 0; i <= hmid; i++) { 1347 *ddata = 0xff; 1348 ddata++; 1349 } 1350 } 1351 } 1352} 1353 1354/* 1355 * Return a colour map appropriate for the given struct rasops_info in the 1356 * same form used by rasops_cmap[] 1357 * For now this is either a copy of rasops_cmap[] or an R3G3B2 map, it should 1358 * probably be a linear ( or gamma corrected? ) ramp for higher depths. 1359 */ 1360int 1361rasops_get_cmap(struct rasops_info *ri, uint8_t *palette, size_t bytes) 1362{ 1363 1364 if ((ri->ri_depth == 8) && ((ri->ri_flg & RI_8BIT_IS_RGB) != 0)) { 1365 /* generate an R3G3B2 palette */ 1366 int i, idx = 0; 1367 uint8_t tmp; 1368 1369 if (bytes < 256 * 3) 1370 return EINVAL; 1371 for (i = 0; i < 256; i++) { 1372 tmp = i & 0xe0; 1373 /* 1374 * replicate bits so 0xe0 maps to a red value of 0xff 1375 * in order to make white look actually white 1376 */ 1377 tmp |= (tmp >> 3) | (tmp >> 6); 1378 palette[idx] = tmp; 1379 idx++; 1380 1381 tmp = (i & 0x1c) << 3; 1382 tmp |= (tmp >> 3) | (tmp >> 6); 1383 palette[idx] = tmp; 1384 idx++; 1385 1386 tmp = (i & 0x03) << 6; 1387 tmp |= tmp >> 2; 1388 tmp |= tmp >> 4; 1389 palette[idx] = tmp; 1390 idx++; 1391 } 1392 } else 1393 memcpy(palette, rasops_cmap, uimin(bytes, sizeof(rasops_cmap))); 1394 1395 return 0; 1396} 1397 1398#if NRASOPS_ROTATION > 0 1399/* 1400 * Quarter clockwise rotation routines (originally intended for the 1401 * built-in Zaurus C3x00 display in 16bpp). 1402 */ 1403 1404static void 1405rasops_rotate_font(int *cookie, int rotate) 1406{ 1407 struct rotatedfont *f; 1408 int ncookie; 1409 1410 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1411 if (f->rf_cookie == *cookie) { 1412 *cookie = f->rf_rotated; 1413 return; 1414 } 1415 } 1416 1417 /* 1418 * We did not find a rotated version of this font. Ask the wsfont 1419 * code to compute one for us. 1420 */ 1421 1422 f = kmem_alloc(sizeof(*f), KM_SLEEP); 1423 1424 if ((ncookie = wsfont_rotate(*cookie, rotate)) == -1) 1425 goto fail; 1426 1427 f->rf_cookie = *cookie; 1428 f->rf_rotated = ncookie; 1429 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1430 1431 *cookie = ncookie; 1432 return; 1433 1434fail: kmem_free(f, sizeof(*f)); 1435 return; 1436} 1437 1438static void 1439rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1440{ 1441 struct rasops_info *ri = (struct rasops_info *)cookie; 1442 int r_srcrow, r_dstrow, r_srccol, r_dstcol, height; 1443 uint8_t *sp, *dp; 1444 1445 r_srcrow = srccol; 1446 r_dstrow = dstcol; 1447 r_srccol = ri->ri_rows - srcrow - 1; 1448 r_dstcol = ri->ri_rows - dstrow - 1; 1449 1450 r_srcrow *= ri->ri_yscale; 1451 r_dstrow *= ri->ri_yscale; 1452 height = ri->ri_font->fontheight; 1453 1454 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1455 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1456 1457 while (height--) { 1458 memmove(dp, sp, ri->ri_xscale); 1459 dp += ri->ri_stride; 1460 sp += ri->ri_stride; 1461 } 1462} 1463 1464static void 1465rasops_putchar_rotated_cw(void *cookie, int row, int col, u_int uc, long attr) 1466{ 1467 struct rasops_info *ri = (struct rasops_info *)cookie; 1468 int height; 1469 uint16_t fg, *rp; 1470 1471 if (__predict_false((unsigned int)row > ri->ri_rows || 1472 (unsigned int)col > ri->ri_cols)) 1473 return; 1474 1475 /* Avoid underflow */ 1476 if (ri->ri_rows - row - 1 < 0) 1477 return; 1478 1479 /* Do rotated char sans (side)underline */ 1480 ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1481 attr & ~WSATTR_UNDERLINE); 1482 1483 /* 1484 * Do rotated underline 1485 * XXX this assumes 16-bit color depth 1486 */ 1487 if ((attr & WSATTR_UNDERLINE) != 0) { 1488 height = ri->ri_font->fontheight; 1489 1490 rp = (uint16_t *)(ri->ri_bits + col * ri->ri_yscale + 1491 (ri->ri_rows - row - 1) * ri->ri_xscale); 1492 1493 fg = (uint16_t)ATTR_FG(ri, attr); 1494 1495 while (height--) { 1496 *rp = fg; 1497 DELTA(rp, ri->ri_stride, uint16_t *); 1498 } 1499 } 1500} 1501 1502static void 1503rasops_erasecols_rotated_cw(void *cookie, int row, int col, int num, long attr) 1504{ 1505 struct rasops_info *ri = (struct rasops_info *)cookie; 1506 int i; 1507 1508 for (i = col; i < col + num; i++) 1509 ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1510} 1511 1512/* XXX: these could likely be optimised somewhat. */ 1513static void 1514rasops_copyrows_rotated_cw(void *cookie, int src, int dst, int num) 1515{ 1516 struct rasops_info *ri = (struct rasops_info *)cookie; 1517 int col, roff; 1518 1519 if (src > dst) 1520 for (roff = 0; roff < num; roff++) 1521 for (col = 0; col < ri->ri_cols; col++) 1522 rasops_copychar(cookie, src + roff, dst + roff, 1523 col, col); 1524 else 1525 for (roff = num - 1; roff >= 0; roff--) 1526 for (col = 0; col < ri->ri_cols; col++) 1527 rasops_copychar(cookie, src + roff, dst + roff, 1528 col, col); 1529} 1530 1531static void 1532rasops_copycols_rotated_cw(void *cookie, int row, int src, int dst, int num) 1533{ 1534 int coff; 1535 1536 if (src > dst) 1537 for (coff = 0; coff < num; coff++) 1538 rasops_copychar(cookie, row, row, src + coff, 1539 dst + coff); 1540 else 1541 for (coff = num - 1; coff >= 0; coff--) 1542 rasops_copychar(cookie, row, row, src + coff, 1543 dst + coff); 1544} 1545 1546static void 1547rasops_eraserows_rotated_cw(void *cookie, int row, int num, long attr) 1548{ 1549 struct rasops_info *ri = (struct rasops_info *)cookie; 1550 int col, rn; 1551 1552 for (rn = row; rn < row + num; rn++) 1553 for (col = 0; col < ri->ri_cols; col++) 1554 ri->ri_ops.putchar(cookie, rn, col, ' ', attr); 1555} 1556 1557/* 1558 * Quarter counter-clockwise rotation routines (originally intended for the 1559 * built-in Sharp W-ZERO3 display in 16bpp). 1560 */ 1561static void 1562rasops_copychar_ccw(void *cookie, int srcrow, int dstrow, int srccol, 1563 int dstcol) 1564{ 1565 struct rasops_info *ri = (struct rasops_info *)cookie; 1566 int r_srcrow, r_dstrow, r_srccol, r_dstcol, height; 1567 uint8_t *sp, *dp; 1568 1569 r_srcrow = ri->ri_cols - srccol - 1; 1570 r_dstrow = ri->ri_cols - dstcol - 1; 1571 r_srccol = srcrow; 1572 r_dstcol = dstrow; 1573 1574 r_srcrow *= ri->ri_yscale; 1575 r_dstrow *= ri->ri_yscale; 1576 height = ri->ri_font->fontheight; 1577 1578 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1579 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1580 1581 while (height--) { 1582 memmove(dp, sp, ri->ri_xscale); 1583 dp += ri->ri_stride; 1584 sp += ri->ri_stride; 1585 } 1586} 1587 1588static void 1589rasops_putchar_rotated_ccw(void *cookie, int row, int col, u_int uc, long attr) 1590{ 1591 struct rasops_info *ri = (struct rasops_info *)cookie; 1592 int height; 1593 uint16_t fg, *rp; 1594 1595 if (__predict_false((unsigned int)row > ri->ri_rows || 1596 (unsigned int)col > ri->ri_cols)) 1597 return; 1598 1599 /* Avoid underflow */ 1600 if (ri->ri_cols - col - 1 < 0) 1601 return; 1602 1603 /* Do rotated char sans (side)underline */ 1604 ri->ri_real_ops.putchar(cookie, ri->ri_cols - col - 1, row, uc, 1605 attr & ~WSATTR_UNDERLINE); 1606 1607 /* 1608 * Do rotated underline 1609 * XXX this assumes 16-bit color depth 1610 */ 1611 if ((attr & WSATTR_UNDERLINE) != 0) { 1612 height = ri->ri_font->fontheight; 1613 1614 rp = (uint16_t *)(ri->ri_bits + 1615 (ri->ri_cols - col - 1) * ri->ri_yscale + 1616 row * ri->ri_xscale + 1617 (ri->ri_font->fontwidth - 1) * ri->ri_pelbytes); 1618 1619 fg = (uint16_t)ATTR_FG(ri, attr); 1620 1621 while (height--) { 1622 *rp = fg; 1623 DELTA(rp, ri->ri_stride, uint16_t *); 1624 } 1625 } 1626} 1627 1628/* XXX: these could likely be optimised somewhat. */ 1629static void 1630rasops_copyrows_rotated_ccw(void *cookie, int src, int dst, int num) 1631{ 1632 struct rasops_info *ri = (struct rasops_info *)cookie; 1633 int col, roff; 1634 1635 if (src > dst) 1636 for (roff = 0; roff < num; roff++) 1637 for (col = 0; col < ri->ri_cols; col++) 1638 rasops_copychar_ccw(cookie, 1639 src + roff, dst + roff, col, col); 1640 else 1641 for (roff = num - 1; roff >= 0; roff--) 1642 for (col = 0; col < ri->ri_cols; col++) 1643 rasops_copychar_ccw(cookie, 1644 src + roff, dst + roff, col, col); 1645} 1646 1647static void 1648rasops_copycols_rotated_ccw(void *cookie, int row, int src, int dst, int num) 1649{ 1650 int coff; 1651 1652 if (src > dst) 1653 for (coff = 0; coff < num; coff++) 1654 rasops_copychar_ccw(cookie, row, row, 1655 src + coff, dst + coff); 1656 else 1657 for (coff = num - 1; coff >= 0; coff--) 1658 rasops_copychar_ccw(cookie, row, row, 1659 src + coff, dst + coff); 1660} 1661#endif /* NRASOPS_ROTATION */ 1662