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