1 /* $NetBSD: rasops.c,v 1.129 2025/11/02 22:16:24 nia 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.129 2025/11/02 22:16:24 nia 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 = 0xff; 710 bg = 0; 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 * Erase rows. This isn't static, since 24-bpp uses it in special cases. 1047 */ 1048 void 1049 rasops_eraserows(void *cookie, int row, int num, long attr) 1050 { 1051 struct rasops_info *ri = (struct rasops_info *)cookie; 1052 int bytes; 1053 uint32_t bg, *rp, *hp; 1054 1055 hp = NULL; /* XXX GCC */ 1056 1057 #ifdef RASOPS_CLIPPING 1058 if (row < 0) { 1059 num += row; 1060 row = 0; 1061 } 1062 1063 if (row + num > ri->ri_rows) 1064 num = ri->ri_rows - row; 1065 1066 if (num <= 0) 1067 return; 1068 #endif 1069 1070 /* 1071 * XXX The wsdisplay_emulops interface seems a little deficient in 1072 * that there is no way to clear the *entire* screen. We provide a 1073 * workaround here: if the entire console area is being cleared, and 1074 * the RI_FULLCLEAR flag is set, clear the entire display. 1075 */ 1076 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 1077 bytes = ri->ri_stride; 1078 num = ri->ri_height; 1079 rp = (uint32_t *)ri->ri_origbits; 1080 if (ri->ri_hwbits) 1081 hp = (uint32_t *)ri->ri_hworigbits; 1082 } else { 1083 bytes = ri->ri_emustride; 1084 num *= ri->ri_font->fontheight; 1085 rp = (uint32_t *)(ri->ri_bits + row * ri->ri_yscale); 1086 if (ri->ri_hwbits) 1087 hp = (uint32_t *)(ri->ri_hwbits + row * ri->ri_yscale); 1088 } 1089 1090 bg = ATTR_BG(ri, attr); 1091 1092 while (num--) { 1093 rasops_memset32(rp, bg, bytes); 1094 if (ri->ri_hwbits) { 1095 memcpy(hp, rp, bytes); 1096 DELTA(hp, ri->ri_stride, uint32_t *); 1097 } 1098 DELTA(rp, ri->ri_stride, uint32_t *); 1099 } 1100 } 1101 1102 /* 1103 * Actually turn the cursor on or off. This does the dirty work for 1104 * rasops_cursor(). 1105 */ 1106 static void 1107 rasops_do_cursor(struct rasops_info *ri) 1108 { 1109 int row, col, height, slop1, slop2, full, cnt; 1110 uint32_t mask1, mask2, *dp; 1111 uint8_t tmp, *rp, *hp; 1112 1113 hp = NULL; /* XXX GCC */ 1114 1115 #if NRASOPS_ROTATION > 0 1116 if (ri->ri_flg & RI_ROTATE_MASK) { 1117 if (ri->ri_flg & RI_ROTATE_CW) { 1118 /* Rotate rows/columns */ 1119 row = ri->ri_ccol; 1120 col = ri->ri_rows - ri->ri_crow - 1; 1121 } else if (ri->ri_flg & RI_ROTATE_CCW) { 1122 /* Rotate rows/columns */ 1123 row = ri->ri_cols - ri->ri_ccol - 1; 1124 col = ri->ri_crow; 1125 } else { /* upside-down */ 1126 row = ri->ri_crow; 1127 col = ri->ri_ccol; 1128 } 1129 } else 1130 #endif 1131 { 1132 row = ri->ri_crow; 1133 col = ri->ri_ccol; 1134 } 1135 1136 height = ri->ri_font->fontheight; 1137 1138 rp = ri->ri_bits + FBOFFSET(ri, row, col); 1139 if (ri->ri_hwbits) 1140 hp = ri->ri_hwbits + FBOFFSET(ri, row, col); 1141 1142 /* 1143 * For ri_xscale = 1: 1144 * 1145 * Logic below does not work for ri_xscale = 1, e.g., 1146 * fontwidth = 8 and bpp = 1. So we take care of it. 1147 */ 1148 if (ri->ri_xscale == 1) { 1149 while (height--) { 1150 tmp = ~*rp; 1151 *rp = tmp; 1152 if (ri->ri_hwbits) { 1153 *hp = tmp; 1154 hp += ri->ri_stride; 1155 } 1156 rp += ri->ri_stride; 1157 } 1158 return; 1159 } 1160 1161 /* 1162 * For ri_xscale = 2, 3, 4, ...: 1163 * 1164 * Note that siop1 <= ri_xscale even for ri_xscale = 2, 1165 * since rp % 3 = 0 or 2 (ri_stride % 4 = 0). 1166 */ 1167 slop1 = (4 - ((uintptr_t)rp & 3)) & 3; 1168 slop2 = (ri->ri_xscale - slop1) & 3; 1169 full = (ri->ri_xscale - slop1 /* - slop2 */) >> 2; 1170 1171 rp = (uint8_t *)((uintptr_t)rp & ~3); 1172 hp = (uint8_t *)((uintptr_t)hp & ~3); 1173 1174 mask1 = rasops_lmask32[4 - slop1]; 1175 mask2 = rasops_rmask32[slop2]; 1176 1177 while (height--) { 1178 dp = (uint32_t *)rp; 1179 1180 if (slop1) { 1181 *dp = *dp ^ mask1; 1182 dp++; 1183 } 1184 1185 for (cnt = full; cnt; cnt--) { 1186 *dp = ~*dp; 1187 dp++; 1188 } 1189 1190 if (slop2) 1191 *dp = *dp ^ mask2; 1192 1193 if (ri->ri_hwbits) { 1194 memcpy(hp, rp, ((slop1 != 0) + full + 1195 (slop2 != 0)) << 2); 1196 hp += ri->ri_stride; 1197 } 1198 rp += ri->ri_stride; 1199 } 1200 } 1201 1202 /* 1203 * Erase columns. 1204 */ 1205 void 1206 rasops_erasecols(void *cookie, int row, int col, int num, long attr) 1207 { 1208 struct rasops_info *ri = (struct rasops_info *)cookie; 1209 int height; 1210 uint32_t bg, *rp, *hp; 1211 1212 hp = NULL; /* XXX GCC */ 1213 1214 #ifdef RASOPS_CLIPPING 1215 if ((unsigned)row >= (unsigned)ri->ri_rows) 1216 return; 1217 1218 if (col < 0) { 1219 num += col; 1220 col = 0; 1221 } 1222 1223 if (col + num > ri->ri_cols) 1224 num = ri->ri_cols - col; 1225 1226 if (num <= 0) 1227 return; 1228 #endif 1229 1230 height = ri->ri_font->fontheight; 1231 num *= ri->ri_xscale; 1232 1233 rp = (uint32_t *)(ri->ri_bits + FBOFFSET(ri, row, col)); 1234 if (ri->ri_hwbits) 1235 hp = (uint32_t *)(ri->ri_hwbits + FBOFFSET(ri, row, col)); 1236 1237 bg = ATTR_BG(ri, attr); 1238 1239 while (height--) { 1240 rasops_memset32(rp, bg, num); 1241 if (ri->ri_hwbits) { 1242 memcpy(hp, rp, num); 1243 DELTA(hp, ri->ri_stride, uint32_t *); 1244 } 1245 DELTA(rp, ri->ri_stride, uint32_t *); 1246 } 1247 } 1248 1249 void 1250 rasops_make_box_chars_16(struct rasops_info *ri) 1251 { 1252 int c, i, mid; 1253 uint16_t vert_mask, hmask_left, hmask_right; 1254 uint16_t *data = (uint16_t *)ri->ri_optfont.data; 1255 1256 vert_mask = 0xc000U >> ((ri->ri_font->fontwidth >> 1) - 1); 1257 hmask_left = 0xff00U << (8 - (ri->ri_font->fontwidth >> 1)); 1258 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1259 1260 vert_mask = htobe16(vert_mask); 1261 hmask_left = htobe16(hmask_left); 1262 hmask_right = htobe16(hmask_right); 1263 1264 mid = (ri->ri_font->fontheight + 1) >> 1; 1265 1266 /* 0x00 would be empty anyway so don't bother */ 1267 for (c = 1; c < 16; c++) { 1268 data += ri->ri_font->fontheight; 1269 if (c & 1) { 1270 /* upper segment */ 1271 for (i = 0; i < mid; i++) 1272 data[i] = vert_mask; 1273 } 1274 if (c & 4) { 1275 /* lower segment */ 1276 for (i = mid; i < ri->ri_font->fontheight; i++) 1277 data[i] = vert_mask; 1278 } 1279 if (c & 2) { 1280 /* right segment */ 1281 i = ri->ri_font->fontheight >> 1; 1282 data[mid - 1] |= hmask_right; 1283 data[mid] |= hmask_right; 1284 } 1285 if (c & 8) { 1286 /* left segment */ 1287 data[mid - 1] |= hmask_left; 1288 data[mid] |= hmask_left; 1289 } 1290 } 1291 } 1292 1293 void 1294 rasops_make_box_chars_8(struct rasops_info *ri) 1295 { 1296 int c, i, mid; 1297 uint8_t vert_mask, hmask_left, hmask_right; 1298 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1299 1300 vert_mask = 0xc0U >> ((ri->ri_font->fontwidth >> 1) - 1); 1301 hmask_left = 0xf0U << (4 - (ri->ri_font->fontwidth >> 1)); 1302 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1303 1304 mid = (ri->ri_font->fontheight + 1) >> 1; 1305 1306 /* 0x00 would be empty anyway so don't bother */ 1307 for (c = 1; c < 16; c++) { 1308 data += ri->ri_font->fontheight; 1309 if (c & 1) { 1310 /* upper segment */ 1311 for (i = 0; i < mid; i++) 1312 data[i] = vert_mask; 1313 } 1314 if (c & 4) { 1315 /* lower segment */ 1316 for (i = mid; i < ri->ri_font->fontheight; i++) 1317 data[i] = vert_mask; 1318 } 1319 if (c & 2) { 1320 /* right segment */ 1321 i = ri->ri_font->fontheight >> 1; 1322 data[mid - 1] |= hmask_right; 1323 data[mid] |= hmask_right; 1324 } 1325 if (c & 8) { 1326 /* left segment */ 1327 data[mid - 1] |= hmask_left; 1328 data[mid] |= hmask_left; 1329 } 1330 } 1331 } 1332 1333 void 1334 rasops_make_box_chars_32(struct rasops_info *ri) 1335 { 1336 int c, i, mid; 1337 uint32_t vert_mask, hmask_left, hmask_right; 1338 uint32_t *data = (uint32_t *)ri->ri_optfont.data; 1339 1340 vert_mask = 0xc0000000U >> ((ri->ri_font->fontwidth >> 1) - 1); 1341 hmask_left = 0xffff0000U << (16 - (ri->ri_font->fontwidth >> 1)); 1342 hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1); 1343 1344 vert_mask = htobe32(vert_mask); 1345 hmask_left = htobe32(hmask_left); 1346 hmask_right = htobe32(hmask_right); 1347 1348 mid = (ri->ri_font->fontheight + 1) >> 1; 1349 1350 /* 0x00 would be empty anyway so don't bother */ 1351 for (c = 1; c < 16; c++) { 1352 data += ri->ri_font->fontheight; 1353 if (c & 1) { 1354 /* upper segment */ 1355 for (i = 0; i < mid; i++) 1356 data[i] = vert_mask; 1357 } 1358 if (c & 4) { 1359 /* lower segment */ 1360 for (i = mid; i < ri->ri_font->fontheight; i++) 1361 data[i] = vert_mask; 1362 } 1363 if (c & 2) { 1364 /* right segment */ 1365 i = ri->ri_font->fontheight >> 1; 1366 data[mid - 1] |= hmask_right; 1367 data[mid] |= hmask_right; 1368 } 1369 if (c & 8) { 1370 /* left segment */ 1371 data[mid - 1] |= hmask_left; 1372 data[mid] |= hmask_left; 1373 } 1374 } 1375 } 1376 1377 void 1378 rasops_make_box_chars_alpha(struct rasops_info *ri) 1379 { 1380 int c, i, hmid, vmid, wi, he; 1381 uint8_t *data = (uint8_t *)ri->ri_optfont.data; 1382 uint8_t *ddata; 1383 1384 he = ri->ri_font->fontheight; 1385 wi = ri->ri_font->fontwidth; 1386 1387 vmid = (he + 1) >> 1; 1388 hmid = (wi + 1) >> 1; 1389 1390 /* 0x00 would be empty anyway so don't bother */ 1391 for (c = 1; c < 16; c++) { 1392 data += ri->ri_fontscale; 1393 if (c & 1) { 1394 /* upper segment */ 1395 ddata = data + hmid; 1396 for (i = 0; i <= vmid; i++) { 1397 *ddata = 0xff; 1398 ddata += wi; 1399 } 1400 } 1401 if (c & 4) { 1402 /* lower segment */ 1403 ddata = data + wi * vmid + hmid; 1404 for (i = vmid; i < he; i++) { 1405 *ddata = 0xff; 1406 ddata += wi; 1407 } 1408 } 1409 if (c & 2) { 1410 /* right segment */ 1411 ddata = data + wi * vmid + hmid; 1412 for (i = hmid; i < wi; i++) { 1413 *ddata = 0xff; 1414 ddata++; 1415 } 1416 } 1417 if (c & 8) { 1418 /* left segment */ 1419 ddata = data + wi * vmid; 1420 for (i = 0; i <= hmid; i++) { 1421 *ddata = 0xff; 1422 ddata++; 1423 } 1424 } 1425 } 1426 } 1427 1428 /* 1429 * Return a colour map appropriate for the given struct rasops_info in the 1430 * same form used by rasops_cmap[] 1431 * For now this is either a copy of rasops_cmap[] or an R3G3B2 map, it should 1432 * probably be a linear ( or gamma corrected? ) ramp for higher depths. 1433 */ 1434 int 1435 rasops_get_cmap(struct rasops_info *ri, uint8_t *palette, size_t bytes) 1436 { 1437 1438 if ((ri->ri_depth == 8) && ((ri->ri_flg & RI_8BIT_IS_RGB) != 0)) { 1439 /* generate an R3G3B2 palette */ 1440 int i, idx = 0; 1441 uint8_t tmp; 1442 1443 if (bytes < 256 * 3) 1444 return EINVAL; 1445 for (i = 0; i < 256; i++) { 1446 tmp = i & 0xe0; 1447 /* 1448 * replicate bits so 0xe0 maps to a red value of 0xff 1449 * in order to make white look actually white 1450 */ 1451 tmp |= (tmp >> 3) | (tmp >> 6); 1452 palette[idx] = tmp; 1453 idx++; 1454 1455 tmp = (i & 0x1c) << 3; 1456 tmp |= (tmp >> 3) | (tmp >> 6); 1457 palette[idx] = tmp; 1458 idx++; 1459 1460 tmp = (i & 0x03) << 6; 1461 tmp |= tmp >> 2; 1462 tmp |= tmp >> 4; 1463 palette[idx] = tmp; 1464 idx++; 1465 } 1466 } else 1467 memcpy(palette, rasops_cmap, uimin(bytes, sizeof(rasops_cmap))); 1468 1469 return 0; 1470 } 1471 1472 #if NRASOPS_ROTATION > 0 1473 /* 1474 * Quarter clockwise rotation routines (originally intended for the 1475 * built-in Zaurus C3x00 display in 16bpp). 1476 */ 1477 1478 static void 1479 rasops_rotate_font(int *cookie, int rotate) 1480 { 1481 struct rotatedfont *f; 1482 int ncookie; 1483 1484 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1485 if (f->rf_cookie == *cookie) { 1486 *cookie = f->rf_rotated; 1487 return; 1488 } 1489 } 1490 1491 /* 1492 * We did not find a rotated version of this font. Ask the wsfont 1493 * code to compute one for us. 1494 */ 1495 1496 f = kmem_alloc(sizeof(*f), KM_SLEEP); 1497 1498 if ((ncookie = wsfont_rotate(*cookie, rotate)) == -1) 1499 goto fail; 1500 1501 f->rf_cookie = *cookie; 1502 f->rf_rotated = ncookie; 1503 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1504 1505 *cookie = ncookie; 1506 return; 1507 1508 fail: kmem_free(f, sizeof(*f)); 1509 return; 1510 } 1511 1512 static void 1513 rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1514 { 1515 struct rasops_info *ri = (struct rasops_info *)cookie; 1516 int r_srcrow, r_dstrow, r_srccol, r_dstcol, height; 1517 uint8_t *sp, *dp; 1518 1519 r_srcrow = srccol; 1520 r_dstrow = dstcol; 1521 r_srccol = ri->ri_rows - srcrow - 1; 1522 r_dstcol = ri->ri_rows - dstrow - 1; 1523 1524 r_srcrow *= ri->ri_yscale; 1525 r_dstrow *= ri->ri_yscale; 1526 height = ri->ri_font->fontheight; 1527 1528 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1529 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1530 1531 while (height--) { 1532 memmove(dp, sp, ri->ri_xscale); 1533 dp += ri->ri_stride; 1534 sp += ri->ri_stride; 1535 } 1536 } 1537 1538 static void 1539 rasops_putchar_rotated_cw(void *cookie, int row, int col, u_int uc, long attr) 1540 { 1541 struct rasops_info *ri = (struct rasops_info *)cookie; 1542 int height; 1543 uint16_t fg, *rp; 1544 1545 if (__predict_false((unsigned int)row > ri->ri_rows || 1546 (unsigned int)col > ri->ri_cols)) 1547 return; 1548 1549 /* Avoid underflow */ 1550 if (ri->ri_rows - row - 1 < 0) 1551 return; 1552 1553 /* Do rotated char sans (side)underline */ 1554 ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1555 attr & ~WSATTR_UNDERLINE); 1556 1557 /* 1558 * Do rotated underline 1559 * XXX this assumes 16-bit color depth 1560 */ 1561 if ((attr & WSATTR_UNDERLINE) != 0) { 1562 height = ri->ri_font->fontheight; 1563 1564 rp = (uint16_t *)(ri->ri_bits + col * ri->ri_yscale + 1565 (ri->ri_rows - row - 1) * ri->ri_xscale); 1566 1567 fg = (uint16_t)ATTR_FG(ri, attr); 1568 1569 while (height--) { 1570 *rp = fg; 1571 DELTA(rp, ri->ri_stride, uint16_t *); 1572 } 1573 } 1574 } 1575 1576 static void 1577 rasops_erasecols_rotated_cw(void *cookie, int row, int col, int num, long attr) 1578 { 1579 struct rasops_info *ri = (struct rasops_info *)cookie; 1580 int i; 1581 1582 for (i = col; i < col + num; i++) 1583 ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1584 } 1585 1586 /* XXX: these could likely be optimised somewhat. */ 1587 static void 1588 rasops_copyrows_rotated_cw(void *cookie, int src, int dst, int num) 1589 { 1590 struct rasops_info *ri = (struct rasops_info *)cookie; 1591 int col, roff; 1592 1593 if (src > dst) 1594 for (roff = 0; roff < num; roff++) 1595 for (col = 0; col < ri->ri_cols; col++) 1596 rasops_copychar(cookie, src + roff, dst + roff, 1597 col, col); 1598 else 1599 for (roff = num - 1; roff >= 0; roff--) 1600 for (col = 0; col < ri->ri_cols; col++) 1601 rasops_copychar(cookie, src + roff, dst + roff, 1602 col, col); 1603 } 1604 1605 static void 1606 rasops_copycols_rotated_cw(void *cookie, int row, int src, int dst, int num) 1607 { 1608 int coff; 1609 1610 if (src > dst) 1611 for (coff = 0; coff < num; coff++) 1612 rasops_copychar(cookie, row, row, src + coff, 1613 dst + coff); 1614 else 1615 for (coff = num - 1; coff >= 0; coff--) 1616 rasops_copychar(cookie, row, row, src + coff, 1617 dst + coff); 1618 } 1619 1620 static void 1621 rasops_eraserows_rotated_cw(void *cookie, int row, int num, long attr) 1622 { 1623 struct rasops_info *ri = (struct rasops_info *)cookie; 1624 int col, rn; 1625 1626 for (rn = row; rn < row + num; rn++) 1627 for (col = 0; col < ri->ri_cols; col++) 1628 ri->ri_ops.putchar(cookie, rn, col, ' ', attr); 1629 } 1630 1631 /* 1632 * Quarter counter-clockwise rotation routines (originally intended for the 1633 * built-in Sharp W-ZERO3 display in 16bpp). 1634 */ 1635 static void 1636 rasops_copychar_ccw(void *cookie, int srcrow, int dstrow, int srccol, 1637 int dstcol) 1638 { 1639 struct rasops_info *ri = (struct rasops_info *)cookie; 1640 int r_srcrow, r_dstrow, r_srccol, r_dstcol, height; 1641 uint8_t *sp, *dp; 1642 1643 r_srcrow = ri->ri_cols - srccol - 1; 1644 r_dstrow = ri->ri_cols - dstcol - 1; 1645 r_srccol = srcrow; 1646 r_dstcol = dstrow; 1647 1648 r_srcrow *= ri->ri_yscale; 1649 r_dstrow *= ri->ri_yscale; 1650 height = ri->ri_font->fontheight; 1651 1652 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1653 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1654 1655 while (height--) { 1656 memmove(dp, sp, ri->ri_xscale); 1657 dp += ri->ri_stride; 1658 sp += ri->ri_stride; 1659 } 1660 } 1661 1662 static void 1663 rasops_putchar_rotated_ccw(void *cookie, int row, int col, u_int uc, long attr) 1664 { 1665 struct rasops_info *ri = (struct rasops_info *)cookie; 1666 int height; 1667 uint16_t fg, *rp; 1668 1669 if (__predict_false((unsigned int)row > ri->ri_rows || 1670 (unsigned int)col > ri->ri_cols)) 1671 return; 1672 1673 /* Avoid underflow */ 1674 if (ri->ri_cols - col - 1 < 0) 1675 return; 1676 1677 /* Do rotated char sans (side)underline */ 1678 ri->ri_real_ops.putchar(cookie, ri->ri_cols - col - 1, row, uc, 1679 attr & ~WSATTR_UNDERLINE); 1680 1681 /* 1682 * Do rotated underline 1683 * XXX this assumes 16-bit color depth 1684 */ 1685 if ((attr & WSATTR_UNDERLINE) != 0) { 1686 height = ri->ri_font->fontheight; 1687 1688 rp = (uint16_t *)(ri->ri_bits + 1689 (ri->ri_cols - col - 1) * ri->ri_yscale + 1690 row * ri->ri_xscale + 1691 (ri->ri_font->fontwidth - 1) * ri->ri_pelbytes); 1692 1693 fg = (uint16_t)ATTR_FG(ri, attr); 1694 1695 while (height--) { 1696 *rp = fg; 1697 DELTA(rp, ri->ri_stride, uint16_t *); 1698 } 1699 } 1700 } 1701 1702 /* XXX: these could likely be optimised somewhat. */ 1703 static void 1704 rasops_copyrows_rotated_ccw(void *cookie, int src, int dst, int num) 1705 { 1706 struct rasops_info *ri = (struct rasops_info *)cookie; 1707 int col, roff; 1708 1709 if (src > dst) 1710 for (roff = 0; roff < num; roff++) 1711 for (col = 0; col < ri->ri_cols; col++) 1712 rasops_copychar_ccw(cookie, 1713 src + roff, dst + roff, col, col); 1714 else 1715 for (roff = num - 1; roff >= 0; roff--) 1716 for (col = 0; col < ri->ri_cols; col++) 1717 rasops_copychar_ccw(cookie, 1718 src + roff, dst + roff, col, col); 1719 } 1720 1721 static void 1722 rasops_copycols_rotated_ccw(void *cookie, int row, int src, int dst, int num) 1723 { 1724 int coff; 1725 1726 if (src > dst) 1727 for (coff = 0; coff < num; coff++) 1728 rasops_copychar_ccw(cookie, row, row, 1729 src + coff, dst + coff); 1730 else 1731 for (coff = num - 1; coff >= 0; coff--) 1732 rasops_copychar_ccw(cookie, row, row, 1733 src + coff, dst + coff); 1734 } 1735 #endif /* NRASOPS_ROTATION */ 1736