1 /* $NetBSD: rasops8.c,v 1.34 2013/09/15 09:41:55 martin 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: rasops8.c,v 1.34 2013/09/15 09:41:55 martin Exp $"); 34 35 #include "opt_rasops.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/time.h> 40 41 #include <dev/wscons/wsdisplayvar.h> 42 #include <dev/wscons/wsconsio.h> 43 #include <dev/rasops/rasops.h> 44 45 static void rasops8_putchar(void *, int, int, u_int, long attr); 46 static void rasops8_putchar_aa(void *, int, int, u_int, long attr); 47 #ifndef RASOPS_SMALL 48 static void rasops8_putchar8(void *, int, int, u_int, long attr); 49 static void rasops8_putchar12(void *, int, int, u_int, long attr); 50 static void rasops8_putchar16(void *, int, int, u_int, long attr); 51 static void rasops8_makestamp(struct rasops_info *ri, long); 52 53 /* 54 * 4x1 stamp for optimized character blitting 55 */ 56 static int32_t stamp[16]; 57 static long stamp_attr; 58 static int stamp_mutex; /* XXX see note in README */ 59 #endif 60 61 /* 62 * XXX this confuses the hell out of gcc2 (not egcs) which always insists 63 * that the shift count is negative. 64 * 65 * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK 66 * destination = STAMP_READ(offset) 67 */ 68 #define STAMP_SHIFT(fb,n) ((n*4-2) >= 0 ? (fb)>>(n*4-2):(fb)<<-(n*4-2)) 69 #define STAMP_MASK (0xf << 2) 70 #define STAMP_READ(o) (*(int32_t *)((char *)stamp + (o))) 71 72 /* 73 * Initialize a 'rasops_info' descriptor for this depth. 74 */ 75 void 76 rasops8_init(struct rasops_info *ri) 77 { 78 79 if (FONT_IS_ALPHA(ri->ri_font)) { 80 ri->ri_ops.putchar = rasops8_putchar_aa; 81 } else { 82 switch (ri->ri_font->fontwidth) { 83 #ifndef RASOPS_SMALL 84 case 8: 85 ri->ri_ops.putchar = rasops8_putchar8; 86 break; 87 case 12: 88 ri->ri_ops.putchar = rasops8_putchar12; 89 break; 90 case 16: 91 ri->ri_ops.putchar = rasops8_putchar16; 92 break; 93 #endif /* !RASOPS_SMALL */ 94 default: 95 ri->ri_ops.putchar = rasops8_putchar; 96 break; 97 } 98 } 99 if (ri->ri_flg & RI_8BIT_IS_RGB) { 100 ri->ri_rnum = 3; 101 ri->ri_rpos = 5; 102 ri->ri_gnum = 3; 103 ri->ri_gpos = 2; 104 ri->ri_bnum = 2; 105 ri->ri_bpos = 0; 106 } 107 } 108 109 /* 110 * Put a single character. 111 */ 112 static void 113 rasops8_putchar(void *cookie, int row, int col, u_int uc, long attr) 114 { 115 int width, height, cnt, fs, fb; 116 u_char *dp, *rp, *hp, *hrp, *fr, clr[2]; 117 struct rasops_info *ri = (struct rasops_info *)cookie; 118 struct wsdisplay_font *font = PICK_FONT(ri, uc); 119 120 hp = hrp = NULL; 121 122 if (!CHAR_IN_FONT(uc, font)) 123 return; 124 125 #ifdef RASOPS_CLIPPING 126 /* Catches 'row < 0' case too */ 127 if ((unsigned)row >= (unsigned)ri->ri_rows) 128 return; 129 130 if ((unsigned)col >= (unsigned)ri->ri_cols) 131 return; 132 #endif 133 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 134 if (ri->ri_hwbits) 135 hrp = ri->ri_hwbits + row * ri->ri_yscale + col * 136 ri->ri_xscale; 137 138 height = font->fontheight; 139 width = font->fontwidth; 140 clr[0] = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf]; 141 clr[1] = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf]; 142 143 if (uc == ' ') { 144 u_char c = clr[0]; 145 146 while (height--) { 147 memset(rp, c, width); 148 if (ri->ri_hwbits) { 149 memset(hrp, c, width); 150 hrp += ri->ri_stride; 151 } 152 rp += ri->ri_stride; 153 } 154 } else { 155 fr = WSFONT_GLYPH(uc, font); 156 fs = font->stride; 157 158 while (height--) { 159 dp = rp; 160 if (ri->ri_hwbits) 161 hp = hrp; 162 fb = fr[3] | (fr[2] << 8) | (fr[1] << 16) | (fr[0] << 24); 163 fr += fs; 164 rp += ri->ri_stride; 165 if (ri->ri_hwbits) 166 hrp += ri->ri_stride; 167 168 for (cnt = width; cnt; cnt--) { 169 *dp++ = clr[(fb >> 31) & 1]; 170 if (ri->ri_hwbits) 171 *hp++ = clr[(fb >> 31) & 1]; 172 fb <<= 1; 173 } 174 } 175 } 176 177 /* Do underline */ 178 if ((attr & 1) != 0) { 179 u_char c = clr[1]; 180 181 rp -= (ri->ri_stride << 1); 182 if (ri->ri_hwbits) 183 hrp -= (ri->ri_stride << 1); 184 185 while (width--) { 186 *rp++ = c; 187 if (ri->ri_hwbits) 188 *hrp++ = c; 189 } 190 } 191 } 192 193 static void 194 rasops8_putchar_aa(void *cookie, int row, int col, u_int uc, long attr) 195 { 196 int width, height; 197 u_char *rp, *hrp, *fr, bg, fg, pixel; 198 struct rasops_info *ri = (struct rasops_info *)cookie; 199 struct wsdisplay_font *font = PICK_FONT(ri, uc); 200 int x, y, r, g, b, aval; 201 int r1, g1, b1, r0, g0, b0, fgo, bgo; 202 uint8_t scanline[32] __attribute__ ((aligned(8))); 203 204 hrp = NULL; 205 206 if (!CHAR_IN_FONT(uc, font)) 207 return; 208 209 #ifdef RASOPS_CLIPPING 210 /* Catches 'row < 0' case too */ 211 if ((unsigned)row >= (unsigned)ri->ri_rows) 212 return; 213 214 if ((unsigned)col >= (unsigned)ri->ri_cols) 215 return; 216 #endif 217 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 218 if (ri->ri_hwbits) 219 hrp = ri->ri_hwbits + row * ri->ri_yscale + col * 220 ri->ri_xscale; 221 222 height = font->fontheight; 223 width = font->fontwidth; 224 bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf]; 225 fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf]; 226 227 if (uc == ' ') { 228 229 while (height--) { 230 memset(rp, bg, width); 231 if (ri->ri_hwbits) { 232 memset(hrp, bg, width); 233 hrp += ri->ri_stride; 234 } 235 rp += ri->ri_stride; 236 } 237 } else { 238 fr = WSFONT_GLYPH(uc, font); 239 /* 240 * we need the RGB colours here, get offsets into rasops_cmap 241 */ 242 fgo = ((attr >> 24) & 0xf) * 3; 243 bgo = ((attr >> 16) & 0xf) * 3; 244 245 r0 = rasops_cmap[bgo]; 246 r1 = rasops_cmap[fgo]; 247 g0 = rasops_cmap[bgo + 1]; 248 g1 = rasops_cmap[fgo + 1]; 249 b0 = rasops_cmap[bgo + 2]; 250 b1 = rasops_cmap[fgo + 2]; 251 252 for (y = 0; y < height; y++) { 253 for (x = 0; x < width; x++) { 254 aval = *fr; 255 fr++; 256 if (aval == 0) { 257 pixel = bg; 258 } else if (aval == 255) { 259 pixel = fg; 260 } else { 261 r = aval * r1 + (255 - aval) * r0; 262 g = aval * g1 + (255 - aval) * g0; 263 b = aval * b1 + (255 - aval) * b0; 264 pixel = ((r & 0xe000) >> 8) | 265 ((g & 0xe000) >> 11) | 266 ((b & 0xc000) >> 14); 267 } 268 scanline[x] = pixel; 269 } 270 memcpy(rp, scanline, width); 271 if (ri->ri_hwbits) { 272 memcpy(hrp, scanline, width); 273 hrp += ri->ri_stride; 274 } 275 rp += ri->ri_stride; 276 277 } 278 } 279 280 /* Do underline */ 281 if ((attr & 1) != 0) { 282 283 rp -= (ri->ri_stride << 1); 284 if (ri->ri_hwbits) 285 hrp -= (ri->ri_stride << 1); 286 287 while (width--) { 288 *rp++ = fg; 289 if (ri->ri_hwbits) 290 *hrp++ = fg; 291 } 292 } 293 } 294 295 #ifndef RASOPS_SMALL 296 /* 297 * Recompute the 4x1 blitting stamp. 298 */ 299 static void 300 rasops8_makestamp(struct rasops_info *ri, long attr) 301 { 302 int32_t fg, bg; 303 int i; 304 305 fg = ri->ri_devcmap[(attr >> 24) & 0xf] & 0xff; 306 bg = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xff; 307 stamp_attr = attr; 308 309 for (i = 0; i < 16; i++) { 310 #if BYTE_ORDER == BIG_ENDIAN 311 #define NEED_LITTLE_ENDIAN_STAMP RI_BSWAP 312 #else 313 #define NEED_LITTLE_ENDIAN_STAMP 0 314 #endif 315 if ((ri->ri_flg & RI_BSWAP) == NEED_LITTLE_ENDIAN_STAMP) { 316 /* little endian */ 317 stamp[i] = (i & 8 ? fg : bg); 318 stamp[i] |= ((i & 4 ? fg : bg) << 8); 319 stamp[i] |= ((i & 2 ? fg : bg) << 16); 320 stamp[i] |= ((i & 1 ? fg : bg) << 24); 321 } else { 322 /* big endian */ 323 stamp[i] = (i & 1 ? fg : bg); 324 stamp[i] |= ((i & 2 ? fg : bg) << 8); 325 stamp[i] |= ((i & 4 ? fg : bg) << 16); 326 stamp[i] |= ((i & 8 ? fg : bg) << 24); 327 } 328 } 329 } 330 331 /* 332 * Put a single character. This is for 8-pixel wide fonts. 333 */ 334 static void 335 rasops8_putchar8(void *cookie, int row, int col, u_int uc, long attr) 336 { 337 struct rasops_info *ri = (struct rasops_info *)cookie; 338 struct wsdisplay_font *font = PICK_FONT(ri, uc); 339 int height, fs; 340 int32_t *rp, *hp; 341 u_char *fr; 342 343 /* Can't risk remaking the stamp if it's already in use */ 344 if (stamp_mutex++) { 345 stamp_mutex--; 346 rasops8_putchar(cookie, row, col, uc, attr); 347 return; 348 } 349 350 hp = NULL; 351 352 if (!CHAR_IN_FONT(uc, font)) 353 return; 354 355 #ifdef RASOPS_CLIPPING 356 if ((unsigned)row >= (unsigned)ri->ri_rows) { 357 stamp_mutex--; 358 return; 359 } 360 361 if ((unsigned)col >= (unsigned)ri->ri_cols) { 362 stamp_mutex--; 363 return; 364 } 365 #endif 366 367 /* Recompute stamp? */ 368 if (attr != stamp_attr) 369 rasops8_makestamp(ri, attr); 370 371 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 372 if (ri->ri_hwbits) 373 hp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 374 col*ri->ri_xscale); 375 height = font->fontheight; 376 377 if (uc == ' ') { 378 while (height--) { 379 rp[0] = rp[1] = stamp[0]; 380 DELTA(rp, ri->ri_stride, int32_t *); 381 if (ri->ri_hwbits) { 382 hp[0] = stamp[0]; 383 hp[1] = stamp[0]; 384 DELTA(hp, ri->ri_stride, int32_t *); 385 } 386 } 387 } else { 388 fr = WSFONT_GLYPH(uc, font); 389 fs = font->stride; 390 391 while (height--) { 392 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 393 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 394 if (ri->ri_hwbits) { 395 hp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & 396 STAMP_MASK); 397 hp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & 398 STAMP_MASK); 399 } 400 401 fr += fs; 402 DELTA(rp, ri->ri_stride, int32_t *); 403 if (ri->ri_hwbits) 404 DELTA(hp, ri->ri_stride, int32_t *); 405 } 406 } 407 408 /* Do underline */ 409 if ((attr & 1) != 0) { 410 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 411 rp[0] = rp[1] = stamp[15]; 412 if (ri->ri_hwbits) { 413 DELTA(hp, -(ri->ri_stride << 1), int32_t *); 414 hp[0] = stamp[15]; 415 hp[1] = stamp[15]; 416 } 417 } 418 419 stamp_mutex--; 420 } 421 422 /* 423 * Put a single character. This is for 12-pixel wide fonts. 424 */ 425 static void 426 rasops8_putchar12(void *cookie, int row, int col, u_int uc, long attr) 427 { 428 struct rasops_info *ri = (struct rasops_info *)cookie; 429 struct wsdisplay_font *font = PICK_FONT(ri, uc); 430 int height, fs; 431 int32_t *rp, *hrp; 432 u_char *fr; 433 434 /* Can't risk remaking the stamp if it's already in use */ 435 if (stamp_mutex++) { 436 stamp_mutex--; 437 rasops8_putchar(cookie, row, col, uc, attr); 438 return; 439 } 440 441 hrp = NULL; 442 443 if (!CHAR_IN_FONT(uc, font)) 444 return; 445 446 #ifdef RASOPS_CLIPPING 447 if ((unsigned)row >= (unsigned)ri->ri_rows) { 448 stamp_mutex--; 449 return; 450 } 451 452 if ((unsigned)col >= (unsigned)ri->ri_cols) { 453 stamp_mutex--; 454 return; 455 } 456 #endif 457 458 /* Recompute stamp? */ 459 if (attr != stamp_attr) 460 rasops8_makestamp(ri, attr); 461 462 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 463 if (ri->ri_hwbits) 464 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 465 col*ri->ri_xscale); 466 height = font->fontheight; 467 468 if (uc == ' ') { 469 while (height--) { 470 int32_t c = stamp[0]; 471 472 rp[0] = rp[1] = rp[2] = c; 473 DELTA(rp, ri->ri_stride, int32_t *); 474 if (ri->ri_hwbits) { 475 hrp[0] = c; 476 hrp[1] = c; 477 hrp[2] = c; 478 DELTA(hrp, ri->ri_stride, int32_t *); 479 } 480 } 481 } else { 482 fr = WSFONT_GLYPH(uc, font); 483 fs = font->stride; 484 485 while (height--) { 486 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 487 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 488 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 489 if (ri->ri_hwbits) { 490 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 491 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 492 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 493 } 494 495 fr += fs; 496 DELTA(rp, ri->ri_stride, int32_t *); 497 if (ri->ri_hwbits) 498 DELTA(hrp, ri->ri_stride, int32_t *); 499 } 500 } 501 502 /* Do underline */ 503 if ((attr & 1) != 0) { 504 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 505 rp[0] = rp[1] = rp[2] = stamp[15]; 506 if (ri->ri_hwbits) { 507 DELTA(hrp, -(ri->ri_stride << 1), int32_t *); 508 hrp[0] = stamp[15]; 509 hrp[1] = stamp[15]; 510 hrp[2] = stamp[15]; 511 } 512 } 513 514 stamp_mutex--; 515 } 516 517 /* 518 * Put a single character. This is for 16-pixel wide fonts. 519 */ 520 static void 521 rasops8_putchar16(void *cookie, int row, int col, u_int uc, long attr) 522 { 523 struct rasops_info *ri = (struct rasops_info *)cookie; 524 struct wsdisplay_font *font = PICK_FONT(ri, uc); 525 int height, fs; 526 int32_t *rp, *hrp; 527 u_char *fr; 528 529 /* Can't risk remaking the stamp if it's already in use */ 530 if (stamp_mutex++) { 531 stamp_mutex--; 532 rasops8_putchar(cookie, row, col, uc, attr); 533 return; 534 } 535 536 hrp = NULL; 537 538 if (!CHAR_IN_FONT(uc, font)) 539 return; 540 541 #ifdef RASOPS_CLIPPING 542 if ((unsigned)row >= (unsigned)ri->ri_rows) { 543 stamp_mutex--; 544 return; 545 } 546 547 if ((unsigned)col >= (unsigned)ri->ri_cols) { 548 stamp_mutex--; 549 return; 550 } 551 #endif 552 553 /* Recompute stamp? */ 554 if (attr != stamp_attr) 555 rasops8_makestamp(ri, attr); 556 557 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 558 if (ri->ri_hwbits) 559 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 560 col*ri->ri_xscale); 561 562 height = font->fontheight; 563 564 if (uc == ' ') { 565 while (height--) { 566 rp[0] = rp[1] = rp[2] = rp[3] = stamp[0]; 567 if (ri->ri_hwbits) { 568 hrp[0] = stamp[0]; 569 hrp[1] = stamp[0]; 570 hrp[2] = stamp[0]; 571 hrp[3] = stamp[0]; 572 } 573 } 574 } else { 575 fr = WSFONT_GLYPH(uc, font); 576 fs = font->stride; 577 578 while (height--) { 579 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 580 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 581 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 582 rp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK); 583 if (ri->ri_hwbits) { 584 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 585 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 586 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 587 hrp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK); 588 } 589 590 fr += fs; 591 DELTA(rp, ri->ri_stride, int32_t *); 592 if (ri->ri_hwbits) 593 DELTA(hrp, ri->ri_stride, int32_t *); 594 } 595 } 596 597 /* Do underline */ 598 if ((attr & 1) != 0) { 599 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 600 rp[0] = rp[1] = rp[2] = rp[3] = stamp[15]; 601 if (ri->ri_hwbits) { 602 DELTA(hrp, -(ri->ri_stride << 1), int32_t *); 603 hrp[0] = stamp[15]; 604 hrp[1] = stamp[15]; 605 hrp[2] = stamp[15]; 606 hrp[3] = stamp[15]; 607 } 608 } 609 610 stamp_mutex--; 611 } 612 #endif /* !RASOPS_SMALL */ 613