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