rasops8.c revision 1.41
1/* $NetBSD: rasops8.c,v 1.41 2019/07/25 03:02: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: rasops8.c,v 1.41 2019/07/25 03:02:44 rin 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 45static void rasops8_putchar(void *, int, int, u_int, long attr); 46static void rasops8_putchar_aa(void *, int, int, u_int, long attr); 47#ifndef RASOPS_SMALL 48static void rasops8_putchar8(void *, int, int, u_int, long attr); 49static void rasops8_putchar12(void *, int, int, u_int, long attr); 50static void rasops8_putchar16(void *, int, int, u_int, long attr); 51static void rasops8_makestamp(struct rasops_info *ri, long); 52 53/* 54 * 4x1 stamp for optimized character blitting 55 */ 56static uint32_t stamp[16]; 57static long stamp_attr; 58static 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) (*(uint32_t *)((char *)stamp + (o))) 71 72/* 73 * Initialize a 'rasops_info' descriptor for this depth. 74 */ 75void 76rasops8_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 */ 112static void 113rasops8_putchar(void *cookie, int row, int col, u_int uc, long attr) 114{ 115 int width, height, cnt, fs, fb; 116 uint8_t *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] = (uint8_t)ri->ri_devcmap[(attr >> 16) & 0xf]; 141 clr[1] = (uint8_t)ri->ri_devcmap[(attr >> 24) & 0xf]; 142 143 if (uc == ' ') { 144 uint8_t 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 = FONT_GLYPH(uc, font, ri); 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) | 163 (fr[0] << 24); 164 fr += fs; 165 rp += ri->ri_stride; 166 if (ri->ri_hwbits) 167 hrp += ri->ri_stride; 168 169 for (cnt = width; cnt; cnt--) { 170 *dp++ = clr[(fb >> 31) & 1]; 171 if (ri->ri_hwbits) 172 *hp++ = clr[(fb >> 31) & 1]; 173 fb <<= 1; 174 } 175 } 176 } 177 178 /* Do underline */ 179 if ((attr & WSATTR_UNDERLINE) != 0) { 180 uint8_t c = clr[1]; 181 182 rp -= (ri->ri_stride << 1); 183 if (ri->ri_hwbits) 184 hrp -= (ri->ri_stride << 1); 185 186 while (width--) { 187 *rp++ = c; 188 if (ri->ri_hwbits) 189 *hrp++ = c; 190 } 191 } 192} 193 194static void 195rasops8_putchar_aa(void *cookie, int row, int col, u_int uc, long attr) 196{ 197 int width, height; 198 uint8_t *rp, *hrp, *fr, bg, fg, pixel; 199 struct rasops_info *ri = (struct rasops_info *)cookie; 200 struct wsdisplay_font *font = PICK_FONT(ri, uc); 201 int x, y, r, g, b, aval; 202 int r1, g1, b1, r0, g0, b0, fgo, bgo; 203 uint8_t scanline[32] __attribute__ ((aligned(8))); 204 205 hrp = NULL; 206 207 if (!CHAR_IN_FONT(uc, font)) 208 return; 209 210#ifdef RASOPS_CLIPPING 211 /* Catches 'row < 0' case too */ 212 if ((unsigned)row >= (unsigned)ri->ri_rows) 213 return; 214 215 if ((unsigned)col >= (unsigned)ri->ri_cols) 216 return; 217#endif 218 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 219 if (ri->ri_hwbits) 220 hrp = ri->ri_hwbits + row * ri->ri_yscale + col * 221 ri->ri_xscale; 222 223 height = font->fontheight; 224 width = font->fontwidth; 225 bg = (uint8_t)ri->ri_devcmap[(attr >> 16) & 0xf]; 226 fg = (uint8_t)ri->ri_devcmap[(attr >> 24) & 0xf]; 227 228 if (uc == ' ') { 229 230 while (height--) { 231 memset(rp, bg, width); 232 if (ri->ri_hwbits) { 233 memset(hrp, bg, width); 234 hrp += ri->ri_stride; 235 } 236 rp += ri->ri_stride; 237 } 238 } else { 239 fr = FONT_GLYPH(uc, font, ri); 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 for (x = 0; x < width; x++) { 255 aval = *fr; 256 fr++; 257 if (aval == 0) { 258 pixel = bg; 259 } else if (aval == 255) { 260 pixel = fg; 261 } else { 262 r = aval * r1 + (255 - aval) * r0; 263 g = aval * g1 + (255 - aval) * g0; 264 b = aval * b1 + (255 - aval) * b0; 265 pixel = ((r & 0xe000) >> 8) | 266 ((g & 0xe000) >> 11) | 267 ((b & 0xc000) >> 14); 268 } 269 scanline[x] = pixel; 270 } 271 memcpy(rp, scanline, width); 272 if (ri->ri_hwbits) { 273 memcpy(hrp, scanline, width); 274 hrp += ri->ri_stride; 275 } 276 rp += ri->ri_stride; 277 278 } 279 } 280 281 /* Do underline */ 282 if ((attr & WSATTR_UNDERLINE) != 0) { 283 284 rp -= (ri->ri_stride << 1); 285 if (ri->ri_hwbits) 286 hrp -= (ri->ri_stride << 1); 287 288 while (width--) { 289 *rp++ = fg; 290 if (ri->ri_hwbits) 291 *hrp++ = fg; 292 } 293 } 294} 295 296#ifndef RASOPS_SMALL 297/* 298 * Recompute the 4x1 blitting stamp. 299 */ 300static void 301rasops8_makestamp(struct rasops_info *ri, long attr) 302{ 303 uint32_t fg, bg; 304 int i; 305 306 fg = ri->ri_devcmap[(attr >> 24) & 0xf] & 0xff; 307 bg = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xff; 308 stamp_attr = attr; 309 310 for (i = 0; i < 16; i++) { 311#if BYTE_ORDER == BIG_ENDIAN 312#define NEED_LITTLE_ENDIAN_STAMP RI_BSWAP 313#else 314#define NEED_LITTLE_ENDIAN_STAMP 0 315#endif 316 if ((ri->ri_flg & RI_BSWAP) == NEED_LITTLE_ENDIAN_STAMP) { 317 /* little endian */ 318 stamp[i] = (i & 8 ? fg : bg); 319 stamp[i] |= ((i & 4 ? fg : bg) << 8); 320 stamp[i] |= ((i & 2 ? fg : bg) << 16); 321 stamp[i] |= ((i & 1 ? fg : bg) << 24); 322 } else { 323 /* big endian */ 324 stamp[i] = (i & 1 ? fg : bg); 325 stamp[i] |= ((i & 2 ? fg : bg) << 8); 326 stamp[i] |= ((i & 4 ? fg : bg) << 16); 327 stamp[i] |= ((i & 8 ? fg : bg) << 24); 328 } 329 } 330} 331 332/* 333 * Put a single character. This is for 8-pixel wide fonts. 334 */ 335static void 336rasops8_putchar8(void *cookie, int row, int col, u_int uc, long attr) 337{ 338 struct rasops_info *ri = (struct rasops_info *)cookie; 339 struct wsdisplay_font *font = PICK_FONT(ri, uc); 340 int height, fs; 341 uint32_t *rp, *hp; 342 uint8_t *fr; 343 344 /* Can't risk remaking the stamp if it's already in use */ 345 if (stamp_mutex++) { 346 stamp_mutex--; 347 rasops8_putchar(cookie, row, col, uc, attr); 348 return; 349 } 350 351 hp = NULL; 352 353 if (!CHAR_IN_FONT(uc, font)) 354 return; 355 356#ifdef RASOPS_CLIPPING 357 if ((unsigned)row >= (unsigned)ri->ri_rows) { 358 stamp_mutex--; 359 return; 360 } 361 362 if ((unsigned)col >= (unsigned)ri->ri_cols) { 363 stamp_mutex--; 364 return; 365 } 366#endif 367 368 /* Recompute stamp? */ 369 if (attr != stamp_attr) 370 rasops8_makestamp(ri, attr); 371 372 rp = (uint32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 373 if (ri->ri_hwbits) 374 hp = (uint32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 375 col*ri->ri_xscale); 376 height = font->fontheight; 377 378 if (uc == ' ') { 379 while (height--) { 380 rp[0] = rp[1] = stamp[0]; 381 DELTA(rp, ri->ri_stride, uint32_t *); 382 if (ri->ri_hwbits) { 383 hp[0] = hp[1] = stamp[0]; 384 DELTA(hp, ri->ri_stride, uint32_t *); 385 } 386 } 387 } else { 388 fr = FONT_GLYPH(uc, font, ri); 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, uint32_t *); 403 if (ri->ri_hwbits) 404 DELTA(hp, ri->ri_stride, uint32_t *); 405 } 406 } 407 408 /* Do underline */ 409 if ((attr & WSATTR_UNDERLINE) != 0) { 410 DELTA(rp, -(ri->ri_stride << 1), uint32_t *); 411 rp[0] = rp[1] = stamp[15]; 412 if (ri->ri_hwbits) { 413 DELTA(hp, -(ri->ri_stride << 1), uint32_t *); 414 hp[0] = hp[1] = stamp[15]; 415 } 416 } 417 418 stamp_mutex--; 419} 420 421/* 422 * Put a single character. This is for 12-pixel wide fonts. 423 */ 424static void 425rasops8_putchar12(void *cookie, int row, int col, u_int uc, long attr) 426{ 427 struct rasops_info *ri = (struct rasops_info *)cookie; 428 struct wsdisplay_font *font = PICK_FONT(ri, uc); 429 int height, fs; 430 uint32_t *rp, *hrp; 431 uint8_t *fr; 432 433 /* Can't risk remaking the stamp if it's already in use */ 434 if (stamp_mutex++) { 435 stamp_mutex--; 436 rasops8_putchar(cookie, row, col, uc, attr); 437 return; 438 } 439 440 hrp = NULL; 441 442 if (!CHAR_IN_FONT(uc, font)) 443 return; 444 445#ifdef RASOPS_CLIPPING 446 if ((unsigned)row >= (unsigned)ri->ri_rows) { 447 stamp_mutex--; 448 return; 449 } 450 451 if ((unsigned)col >= (unsigned)ri->ri_cols) { 452 stamp_mutex--; 453 return; 454 } 455#endif 456 457 /* Recompute stamp? */ 458 if (attr != stamp_attr) 459 rasops8_makestamp(ri, attr); 460 461 rp = (uint32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 462 if (ri->ri_hwbits) 463 hrp = (uint32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 464 col*ri->ri_xscale); 465 height = font->fontheight; 466 467 if (uc == ' ') { 468 while (height--) { 469 rp[0] = rp[1] = rp[2] = stamp[0]; 470 DELTA(rp, ri->ri_stride, uint32_t *); 471 if (ri->ri_hwbits) { 472 hrp[0] = hrp[1] = hrp[2] = stamp[0]; 473 DELTA(hrp, ri->ri_stride, uint32_t *); 474 } 475 } 476 } else { 477 fr = FONT_GLYPH(uc, font, ri); 478 fs = font->stride; 479 480 while (height--) { 481 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 482 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 483 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 484 if (ri->ri_hwbits) { 485 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & 486 STAMP_MASK); 487 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & 488 STAMP_MASK); 489 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & 490 STAMP_MASK); 491 } 492 493 fr += fs; 494 DELTA(rp, ri->ri_stride, uint32_t *); 495 if (ri->ri_hwbits) 496 DELTA(hrp, ri->ri_stride, uint32_t *); 497 } 498 } 499 500 /* Do underline */ 501 if ((attr & WSATTR_UNDERLINE) != 0) { 502 DELTA(rp, -(ri->ri_stride << 1), uint32_t *); 503 rp[0] = rp[1] = rp[2] = stamp[15]; 504 if (ri->ri_hwbits) { 505 DELTA(hrp, -(ri->ri_stride << 1), uint32_t *); 506 hrp[0] = hrp[1] = hrp[2] = stamp[15]; 507 } 508 } 509 510 stamp_mutex--; 511} 512 513/* 514 * Put a single character. This is for 16-pixel wide fonts. 515 */ 516static void 517rasops8_putchar16(void *cookie, int row, int col, u_int uc, long attr) 518{ 519 struct rasops_info *ri = (struct rasops_info *)cookie; 520 struct wsdisplay_font *font = PICK_FONT(ri, uc); 521 int height, fs; 522 uint32_t *rp, *hrp; 523 uint8_t *fr; 524 525 /* Can't risk remaking the stamp if it's already in use */ 526 if (stamp_mutex++) { 527 stamp_mutex--; 528 rasops8_putchar(cookie, row, col, uc, attr); 529 return; 530 } 531 532 hrp = NULL; 533 534 if (!CHAR_IN_FONT(uc, font)) 535 return; 536 537#ifdef RASOPS_CLIPPING 538 if ((unsigned)row >= (unsigned)ri->ri_rows) { 539 stamp_mutex--; 540 return; 541 } 542 543 if ((unsigned)col >= (unsigned)ri->ri_cols) { 544 stamp_mutex--; 545 return; 546 } 547#endif 548 549 /* Recompute stamp? */ 550 if (attr != stamp_attr) 551 rasops8_makestamp(ri, attr); 552 553 rp = (uint32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 554 if (ri->ri_hwbits) 555 hrp = (uint32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 556 col*ri->ri_xscale); 557 height = font->fontheight; 558 559 if (uc == ' ') { 560 while (height--) { 561 rp[0] = rp[1] = rp[2] = rp[3] = stamp[0]; 562 DELTA(rp, ri->ri_stride, uint32_t *); 563 if (ri->ri_hwbits) { 564 hrp[0] = hrp[1] = hrp[2] = hrp[3] = stamp[0]; 565 DELTA(hrp, ri->ri_stride, uint32_t *); 566 } 567 } 568 } else { 569 fr = FONT_GLYPH(uc, font, ri); 570 fs = font->stride; 571 572 while (height--) { 573 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 574 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 575 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 576 rp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK); 577 if (ri->ri_hwbits) { 578 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & 579 STAMP_MASK); 580 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & 581 STAMP_MASK); 582 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & 583 STAMP_MASK); 584 hrp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & 585 STAMP_MASK); 586 } 587 588 fr += fs; 589 DELTA(rp, ri->ri_stride, uint32_t *); 590 if (ri->ri_hwbits) 591 DELTA(hrp, ri->ri_stride, uint32_t *); 592 } 593 } 594 595 /* Do underline */ 596 if ((attr & WSATTR_UNDERLINE) != 0) { 597 DELTA(rp, -(ri->ri_stride << 1), uint32_t *); 598 rp[0] = rp[1] = rp[2] = rp[3] = stamp[15]; 599 if (ri->ri_hwbits) { 600 DELTA(hrp, -(ri->ri_stride << 1), uint32_t *); 601 hrp[0] = hrp[1] = hrp[2] = hrp[3] = stamp[15]; 602 } 603 } 604 605 stamp_mutex--; 606} 607#endif /* !RASOPS_SMALL */ 608