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