1 /* $NetBSD: rasops8.c,v 1.32 2012/01/25 20:18:04 macallan 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.32 2012/01/25 20:18:04 macallan 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, fs; 197 u_char *dp, *rp, *hp, *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 hp = 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 fs = font->stride; 240 /* 241 * we need the RGB colours here, get offsets into rasops_cmap 242 */ 243 fgo = ((attr >> 24) & 0xf) * 3; 244 bgo = ((attr >> 16) & 0xf) * 3; 245 246 r0 = rasops_cmap[bgo]; 247 r1 = rasops_cmap[fgo]; 248 g0 = rasops_cmap[bgo + 1]; 249 g1 = rasops_cmap[fgo + 1]; 250 b0 = rasops_cmap[bgo + 2]; 251 b1 = rasops_cmap[fgo + 2]; 252 253 for (y = 0; y < height; y++) { 254 dp = rp; 255 for (x = 0; x < width; x++) { 256 aval = *fr; 257 fr++; 258 if (aval == 0) { 259 pixel = bg; 260 } else if (aval == 255) { 261 pixel = fg; 262 } else { 263 r = aval * r1 + (255 - aval) * r0; 264 g = aval * g1 + (255 - aval) * g0; 265 b = aval * b1 + (255 - aval) * b0; 266 pixel = ((r & 0xe000) >> 8) | 267 ((g & 0xe000) >> 11) | 268 ((b & 0xc000) >> 14); 269 } 270 scanline[x] = pixel; 271 } 272 memcpy(rp, scanline, width); 273 if (ri->ri_hwbits) { 274 memcpy(hrp, scanline, width); 275 hrp += ri->ri_stride; 276 } 277 rp += ri->ri_stride; 278 279 } 280 } 281 282 /* Do underline */ 283 if ((attr & 1) != 0) { 284 285 rp -= (ri->ri_stride << 1); 286 if (ri->ri_hwbits) 287 hrp -= (ri->ri_stride << 1); 288 289 while (width--) { 290 *rp++ = fg; 291 if (ri->ri_hwbits) 292 *hrp++ = fg; 293 } 294 } 295 } 296 297 #ifndef RASOPS_SMALL 298 /* 299 * Recompute the 4x1 blitting stamp. 300 */ 301 static void 302 rasops8_makestamp(struct rasops_info *ri, long attr) 303 { 304 int32_t fg, bg; 305 int i; 306 307 fg = ri->ri_devcmap[(attr >> 24) & 0xf] & 0xff; 308 bg = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xff; 309 stamp_attr = attr; 310 311 for (i = 0; i < 16; i++) { 312 #if BYTE_ORDER == BIG_ENDIAN 313 #define NEED_LITTLE_ENDIAN_STAMP RI_BSWAP 314 #else 315 #define NEED_LITTLE_ENDIAN_STAMP 0 316 #endif 317 if ((ri->ri_flg & RI_BSWAP) == NEED_LITTLE_ENDIAN_STAMP) { 318 /* little endian */ 319 stamp[i] = (i & 8 ? fg : bg); 320 stamp[i] |= ((i & 4 ? fg : bg) << 8); 321 stamp[i] |= ((i & 2 ? fg : bg) << 16); 322 stamp[i] |= ((i & 1 ? fg : bg) << 24); 323 } else { 324 /* big endian */ 325 stamp[i] = (i & 1 ? fg : bg); 326 stamp[i] |= ((i & 2 ? fg : bg) << 8); 327 stamp[i] |= ((i & 4 ? fg : bg) << 16); 328 stamp[i] |= ((i & 8 ? fg : bg) << 24); 329 } 330 } 331 } 332 333 /* 334 * Put a single character. This is for 8-pixel wide fonts. 335 */ 336 static void 337 rasops8_putchar8(void *cookie, int row, int col, u_int uc, long attr) 338 { 339 struct rasops_info *ri = (struct rasops_info *)cookie; 340 struct wsdisplay_font *font = PICK_FONT(ri, uc); 341 int height, fs; 342 int32_t *rp, *hp; 343 u_char *fr; 344 345 /* Can't risk remaking the stamp if it's already in use */ 346 if (stamp_mutex++) { 347 stamp_mutex--; 348 rasops8_putchar(cookie, row, col, uc, attr); 349 return; 350 } 351 352 hp = NULL; 353 354 if (!CHAR_IN_FONT(uc, font)) 355 return; 356 357 #ifdef RASOPS_CLIPPING 358 if ((unsigned)row >= (unsigned)ri->ri_rows) { 359 stamp_mutex--; 360 return; 361 } 362 363 if ((unsigned)col >= (unsigned)ri->ri_cols) { 364 stamp_mutex--; 365 return; 366 } 367 #endif 368 369 /* Recompute stamp? */ 370 if (attr != stamp_attr) 371 rasops8_makestamp(ri, attr); 372 373 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 374 if (ri->ri_hwbits) 375 hp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 376 col*ri->ri_xscale); 377 height = font->fontheight; 378 379 if (uc == ' ') { 380 while (height--) { 381 rp[0] = rp[1] = stamp[0]; 382 DELTA(rp, ri->ri_stride, int32_t *); 383 if (ri->ri_hwbits) { 384 hp[0] = stamp[0]; 385 hp[1] = stamp[0]; 386 DELTA(hp, ri->ri_stride, int32_t *); 387 } 388 } 389 } else { 390 fr = WSFONT_GLYPH(uc, font); 391 fs = font->stride; 392 393 while (height--) { 394 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 395 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 396 if (ri->ri_hwbits) { 397 hp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & 398 STAMP_MASK); 399 hp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & 400 STAMP_MASK); 401 } 402 403 fr += fs; 404 DELTA(rp, ri->ri_stride, int32_t *); 405 if (ri->ri_hwbits) 406 DELTA(hp, ri->ri_stride, int32_t *); 407 } 408 } 409 410 /* Do underline */ 411 if ((attr & 1) != 0) { 412 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 413 rp[0] = rp[1] = stamp[15]; 414 if (ri->ri_hwbits) { 415 DELTA(hp, -(ri->ri_stride << 1), int32_t *); 416 hp[0] = stamp[15]; 417 hp[1] = stamp[15]; 418 } 419 } 420 421 stamp_mutex--; 422 } 423 424 /* 425 * Put a single character. This is for 12-pixel wide fonts. 426 */ 427 static void 428 rasops8_putchar12(void *cookie, int row, int col, u_int uc, long attr) 429 { 430 struct rasops_info *ri = (struct rasops_info *)cookie; 431 struct wsdisplay_font *font = PICK_FONT(ri, uc); 432 int height, fs; 433 int32_t *rp, *hrp; 434 u_char *fr; 435 436 /* Can't risk remaking the stamp if it's already in use */ 437 if (stamp_mutex++) { 438 stamp_mutex--; 439 rasops8_putchar(cookie, row, col, uc, attr); 440 return; 441 } 442 443 hrp = NULL; 444 445 if (!CHAR_IN_FONT(uc, font)) 446 return; 447 448 #ifdef RASOPS_CLIPPING 449 if ((unsigned)row >= (unsigned)ri->ri_rows) { 450 stamp_mutex--; 451 return; 452 } 453 454 if ((unsigned)col >= (unsigned)ri->ri_cols) { 455 stamp_mutex--; 456 return; 457 } 458 #endif 459 460 /* Recompute stamp? */ 461 if (attr != stamp_attr) 462 rasops8_makestamp(ri, attr); 463 464 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 465 if (ri->ri_hwbits) 466 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 467 col*ri->ri_xscale); 468 height = font->fontheight; 469 470 if (uc == ' ') { 471 while (height--) { 472 int32_t c = stamp[0]; 473 474 rp[0] = rp[1] = rp[2] = c; 475 DELTA(rp, ri->ri_stride, int32_t *); 476 if (ri->ri_hwbits) { 477 hrp[0] = c; 478 hrp[1] = c; 479 hrp[2] = c; 480 DELTA(hrp, ri->ri_stride, int32_t *); 481 } 482 } 483 } else { 484 fr = WSFONT_GLYPH(uc, font); 485 fs = font->stride; 486 487 while (height--) { 488 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 489 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 490 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 491 if (ri->ri_hwbits) { 492 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 493 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 494 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 495 } 496 497 fr += fs; 498 DELTA(rp, ri->ri_stride, int32_t *); 499 if (ri->ri_hwbits) 500 DELTA(hrp, ri->ri_stride, int32_t *); 501 } 502 } 503 504 /* Do underline */ 505 if ((attr & 1) != 0) { 506 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 507 rp[0] = rp[1] = rp[2] = stamp[15]; 508 if (ri->ri_hwbits) { 509 DELTA(hrp, -(ri->ri_stride << 1), int32_t *); 510 hrp[0] = stamp[15]; 511 hrp[1] = stamp[15]; 512 hrp[2] = stamp[15]; 513 } 514 } 515 516 stamp_mutex--; 517 } 518 519 /* 520 * Put a single character. This is for 16-pixel wide fonts. 521 */ 522 static void 523 rasops8_putchar16(void *cookie, int row, int col, u_int uc, long attr) 524 { 525 struct rasops_info *ri = (struct rasops_info *)cookie; 526 struct wsdisplay_font *font = PICK_FONT(ri, uc); 527 int height, fs; 528 int32_t *rp, *hrp; 529 u_char *fr; 530 531 /* Can't risk remaking the stamp if it's already in use */ 532 if (stamp_mutex++) { 533 stamp_mutex--; 534 rasops8_putchar(cookie, row, col, uc, attr); 535 return; 536 } 537 538 hrp = NULL; 539 540 if (!CHAR_IN_FONT(uc, font)) 541 return; 542 543 #ifdef RASOPS_CLIPPING 544 if ((unsigned)row >= (unsigned)ri->ri_rows) { 545 stamp_mutex--; 546 return; 547 } 548 549 if ((unsigned)col >= (unsigned)ri->ri_cols) { 550 stamp_mutex--; 551 return; 552 } 553 #endif 554 555 /* Recompute stamp? */ 556 if (attr != stamp_attr) 557 rasops8_makestamp(ri, attr); 558 559 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 560 if (ri->ri_hwbits) 561 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 562 col*ri->ri_xscale); 563 564 height = font->fontheight; 565 566 if (uc == ' ') { 567 while (height--) { 568 rp[0] = rp[1] = rp[2] = rp[3] = stamp[0]; 569 if (ri->ri_hwbits) { 570 hrp[0] = stamp[0]; 571 hrp[1] = stamp[0]; 572 hrp[2] = stamp[0]; 573 hrp[3] = stamp[0]; 574 } 575 } 576 } else { 577 fr = WSFONT_GLYPH(uc, font); 578 fs = font->stride; 579 580 while (height--) { 581 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 582 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 583 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 584 rp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK); 585 if (ri->ri_hwbits) { 586 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 587 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 588 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 589 hrp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK); 590 } 591 592 fr += fs; 593 DELTA(rp, ri->ri_stride, int32_t *); 594 if (ri->ri_hwbits) 595 DELTA(hrp, ri->ri_stride, int32_t *); 596 } 597 } 598 599 /* Do underline */ 600 if ((attr & 1) != 0) { 601 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 602 rp[0] = rp[1] = rp[2] = rp[3] = stamp[15]; 603 if (ri->ri_hwbits) { 604 DELTA(hrp, -(ri->ri_stride << 1), int32_t *); 605 hrp[0] = stamp[15]; 606 hrp[1] = stamp[15]; 607 hrp[2] = stamp[15]; 608 hrp[3] = stamp[15]; 609 } 610 } 611 612 stamp_mutex--; 613 } 614 #endif /* !RASOPS_SMALL */ 615