1 /* $NetBSD: rasops8.c,v 1.27 2010/05/04 04:57:34 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.27 2010/05/04 04:57:34 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 #ifndef RASOPS_SMALL 47 static void rasops8_putchar8(void *, int, int, u_int, long attr); 48 static void rasops8_putchar12(void *, int, int, u_int, long attr); 49 static void rasops8_putchar16(void *, int, int, u_int, long attr); 50 static void rasops8_makestamp(struct rasops_info *ri, long); 51 52 /* 53 * 4x1 stamp for optimized character blitting 54 */ 55 static int32_t stamp[16]; 56 static long stamp_attr; 57 static int stamp_mutex; /* XXX see note in README */ 58 #endif 59 60 /* 61 * XXX this confuses the hell out of gcc2 (not egcs) which always insists 62 * that the shift count is negative. 63 * 64 * offset = STAMP_SHIFT(fontbits, nibble #) & STAMP_MASK 65 * destination = STAMP_READ(offset) 66 */ 67 #define STAMP_SHIFT(fb,n) ((n*4-2) >= 0 ? (fb)>>(n*4-2):(fb)<<-(n*4-2)) 68 #define STAMP_MASK (0xf << 2) 69 #define STAMP_READ(o) (*(int32_t *)((char *)stamp + (o))) 70 71 /* 72 * Initialize a 'rasops_info' descriptor for this depth. 73 */ 74 void 75 rasops8_init(struct rasops_info *ri) 76 { 77 78 switch (ri->ri_font->fontwidth) { 79 #ifndef RASOPS_SMALL 80 case 8: 81 ri->ri_ops.putchar = rasops8_putchar8; 82 break; 83 case 12: 84 ri->ri_ops.putchar = rasops8_putchar12; 85 break; 86 case 16: 87 ri->ri_ops.putchar = rasops8_putchar16; 88 break; 89 #endif /* !RASOPS_SMALL */ 90 default: 91 ri->ri_ops.putchar = rasops8_putchar; 92 break; 93 } 94 } 95 96 /* 97 * Put a single character. 98 */ 99 static void 100 rasops8_putchar(void *cookie, int row, int col, u_int uc, long attr) 101 { 102 int width, height, cnt, fs, fb; 103 u_char *dp, *rp, *hp, *hrp, *fr, clr[2]; 104 struct rasops_info *ri = (struct rasops_info *)cookie; 105 struct wsdisplay_font *font = PICK_FONT(ri, uc); 106 107 hp = hrp = NULL; 108 109 if (!CHAR_IN_FONT(uc, font)) 110 return; 111 112 #ifdef RASOPS_CLIPPING 113 /* Catches 'row < 0' case too */ 114 if ((unsigned)row >= (unsigned)ri->ri_rows) 115 return; 116 117 if ((unsigned)col >= (unsigned)ri->ri_cols) 118 return; 119 #endif 120 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 121 if (ri->ri_hwbits) 122 hrp = ri->ri_hwbits + row * ri->ri_yscale + col * 123 ri->ri_xscale; 124 125 height = font->fontheight; 126 width = font->fontwidth; 127 clr[0] = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf]; 128 clr[1] = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf]; 129 130 if (uc == ' ') { 131 u_char c = clr[0]; 132 133 while (height--) { 134 dp = rp; 135 rp += ri->ri_stride; 136 if (ri->ri_hwbits) { 137 hp = hrp; 138 hrp += ri->ri_stride; 139 } 140 141 for (cnt = width; cnt; cnt--) { 142 *dp++ = c; 143 if (ri->ri_hwbits) 144 *hp++ = c; 145 } 146 } 147 } else { 148 uc -= font->firstchar; 149 fr = (u_char *)font->data + uc * ri->ri_fontscale; 150 fs = font->stride; 151 152 while (height--) { 153 dp = rp; 154 if (ri->ri_hwbits) 155 hp = hrp; 156 fb = fr[3] | (fr[2] << 8) | (fr[1] << 16) | (fr[0] << 24); 157 fr += fs; 158 rp += ri->ri_stride; 159 if (ri->ri_hwbits) 160 hrp += ri->ri_stride; 161 162 for (cnt = width; cnt; cnt--) { 163 *dp++ = clr[(fb >> 31) & 1]; 164 if (ri->ri_hwbits) 165 *hp++ = clr[(fb >> 31) & 1]; 166 fb <<= 1; 167 } 168 } 169 } 170 171 /* Do underline */ 172 if ((attr & 1) != 0) { 173 u_char c = clr[1]; 174 175 rp -= (ri->ri_stride << 1); 176 if (ri->ri_hwbits) 177 hrp -= (ri->ri_stride << 1); 178 179 while (width--) { 180 *rp++ = c; 181 if (ri->ri_hwbits) 182 *hrp++ = c; 183 } 184 } 185 } 186 187 #ifndef RASOPS_SMALL 188 /* 189 * Recompute the 4x1 blitting stamp. 190 */ 191 static void 192 rasops8_makestamp(struct rasops_info *ri, long attr) 193 { 194 int32_t fg, bg; 195 int i; 196 197 fg = ri->ri_devcmap[(attr >> 24) & 0xf] & 0xff; 198 bg = ri->ri_devcmap[(attr >> 16) & 0xf] & 0xff; 199 stamp_attr = attr; 200 201 for (i = 0; i < 16; i++) { 202 #if BYTE_ORDER == BIG_ENDIAN 203 #define NEED_LITTLE_ENDIAN_STAMP RI_BSWAP 204 #else 205 #define NEED_LITTLE_ENDIAN_STAMP 0 206 #endif 207 if ((ri->ri_flg & RI_BSWAP) == NEED_LITTLE_ENDIAN_STAMP) { 208 /* little endian */ 209 stamp[i] = (i & 8 ? fg : bg); 210 stamp[i] |= ((i & 4 ? fg : bg) << 8); 211 stamp[i] |= ((i & 2 ? fg : bg) << 16); 212 stamp[i] |= ((i & 1 ? fg : bg) << 24); 213 } else { 214 /* big endian */ 215 stamp[i] = (i & 1 ? fg : bg); 216 stamp[i] |= ((i & 2 ? fg : bg) << 8); 217 stamp[i] |= ((i & 4 ? fg : bg) << 16); 218 stamp[i] |= ((i & 8 ? fg : bg) << 24); 219 } 220 } 221 } 222 223 /* 224 * Put a single character. This is for 8-pixel wide fonts. 225 */ 226 static void 227 rasops8_putchar8(void *cookie, int row, int col, u_int uc, long attr) 228 { 229 struct rasops_info *ri = (struct rasops_info *)cookie; 230 struct wsdisplay_font *font = PICK_FONT(ri, uc); 231 int height, fs; 232 int32_t *rp, *hp; 233 u_char *fr; 234 235 /* Can't risk remaking the stamp if it's already in use */ 236 if (stamp_mutex++) { 237 stamp_mutex--; 238 rasops8_putchar(cookie, row, col, uc, attr); 239 return; 240 } 241 242 hp = NULL; 243 244 if (!CHAR_IN_FONT(uc, font)) 245 return; 246 247 #ifdef RASOPS_CLIPPING 248 if ((unsigned)row >= (unsigned)ri->ri_rows) { 249 stamp_mutex--; 250 return; 251 } 252 253 if ((unsigned)col >= (unsigned)ri->ri_cols) { 254 stamp_mutex--; 255 return; 256 } 257 #endif 258 259 /* Recompute stamp? */ 260 if (attr != stamp_attr) 261 rasops8_makestamp(ri, attr); 262 263 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 264 if (ri->ri_hwbits) 265 hp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 266 col*ri->ri_xscale); 267 height = font->fontheight; 268 269 if (uc == ' ') { 270 while (height--) { 271 rp[0] = rp[1] = stamp[0]; 272 DELTA(rp, ri->ri_stride, int32_t *); 273 if (ri->ri_hwbits) { 274 hp[0] = stamp[0]; 275 hp[1] = stamp[0]; 276 DELTA(hp, ri->ri_stride, int32_t *); 277 } 278 } 279 } else { 280 uc -= font->firstchar; 281 fr = (u_char *)font->data + uc * ri->ri_fontscale; 282 fs = font->stride; 283 284 while (height--) { 285 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 286 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 287 if (ri->ri_hwbits) { 288 hp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & 289 STAMP_MASK); 290 hp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & 291 STAMP_MASK); 292 } 293 294 fr += fs; 295 DELTA(rp, ri->ri_stride, int32_t *); 296 if (ri->ri_hwbits) 297 DELTA(hp, ri->ri_stride, int32_t *); 298 } 299 } 300 301 /* Do underline */ 302 if ((attr & 1) != 0) { 303 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 304 rp[0] = rp[1] = stamp[15]; 305 if (ri->ri_hwbits) { 306 DELTA(hp, -(ri->ri_stride << 1), int32_t *); 307 hp[0] = stamp[15]; 308 hp[1] = stamp[15]; 309 } 310 } 311 312 stamp_mutex--; 313 } 314 315 /* 316 * Put a single character. This is for 12-pixel wide fonts. 317 */ 318 static void 319 rasops8_putchar12(void *cookie, int row, int col, u_int uc, long attr) 320 { 321 struct rasops_info *ri = (struct rasops_info *)cookie; 322 struct wsdisplay_font *font = PICK_FONT(ri, uc); 323 int height, fs; 324 int32_t *rp, *hrp; 325 u_char *fr; 326 327 /* Can't risk remaking the stamp if it's already in use */ 328 if (stamp_mutex++) { 329 stamp_mutex--; 330 rasops8_putchar(cookie, row, col, uc, attr); 331 return; 332 } 333 334 hrp = NULL; 335 336 if (!CHAR_IN_FONT(uc, font)) 337 return; 338 339 #ifdef RASOPS_CLIPPING 340 if ((unsigned)row >= (unsigned)ri->ri_rows) { 341 stamp_mutex--; 342 return; 343 } 344 345 if ((unsigned)col >= (unsigned)ri->ri_cols) { 346 stamp_mutex--; 347 return; 348 } 349 #endif 350 351 /* Recompute stamp? */ 352 if (attr != stamp_attr) 353 rasops8_makestamp(ri, attr); 354 355 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 356 if (ri->ri_hwbits) 357 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 358 col*ri->ri_xscale); 359 height = font->fontheight; 360 361 if (uc == ' ') { 362 while (height--) { 363 int32_t c = stamp[0]; 364 365 rp[0] = rp[1] = rp[2] = c; 366 DELTA(rp, ri->ri_stride, int32_t *); 367 if (ri->ri_hwbits) { 368 hrp[0] = c; 369 hrp[1] = c; 370 hrp[2] = c; 371 DELTA(hrp, ri->ri_stride, int32_t *); 372 } 373 } 374 } else { 375 uc -= font->firstchar; 376 fr = (u_char *)font->data + uc * ri->ri_fontscale; 377 fs = font->stride; 378 379 while (height--) { 380 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 381 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 382 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 383 if (ri->ri_hwbits) { 384 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 385 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 386 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 387 } 388 389 fr += fs; 390 DELTA(rp, ri->ri_stride, int32_t *); 391 if (ri->ri_hwbits) 392 DELTA(hrp, ri->ri_stride, int32_t *); 393 } 394 } 395 396 /* Do underline */ 397 if ((attr & 1) != 0) { 398 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 399 rp[0] = rp[1] = rp[2] = stamp[15]; 400 if (ri->ri_hwbits) { 401 DELTA(hrp, -(ri->ri_stride << 1), int32_t *); 402 hrp[0] = stamp[15]; 403 hrp[1] = stamp[15]; 404 hrp[2] = stamp[15]; 405 } 406 } 407 408 stamp_mutex--; 409 } 410 411 /* 412 * Put a single character. This is for 16-pixel wide fonts. 413 */ 414 static void 415 rasops8_putchar16(void *cookie, int row, int col, u_int uc, long attr) 416 { 417 struct rasops_info *ri = (struct rasops_info *)cookie; 418 struct wsdisplay_font *font = PICK_FONT(ri, uc); 419 int height, fs; 420 int32_t *rp, *hrp; 421 u_char *fr; 422 423 /* Can't risk remaking the stamp if it's already in use */ 424 if (stamp_mutex++) { 425 stamp_mutex--; 426 rasops8_putchar(cookie, row, col, uc, attr); 427 return; 428 } 429 430 hrp = NULL; 431 432 if (!CHAR_IN_FONT(uc, font)) 433 return; 434 435 #ifdef RASOPS_CLIPPING 436 if ((unsigned)row >= (unsigned)ri->ri_rows) { 437 stamp_mutex--; 438 return; 439 } 440 441 if ((unsigned)col >= (unsigned)ri->ri_cols) { 442 stamp_mutex--; 443 return; 444 } 445 #endif 446 447 /* Recompute stamp? */ 448 if (attr != stamp_attr) 449 rasops8_makestamp(ri, attr); 450 451 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 452 if (ri->ri_hwbits) 453 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 454 col*ri->ri_xscale); 455 456 height = font->fontheight; 457 458 if (uc == ' ') { 459 while (height--) { 460 rp[0] = rp[1] = rp[2] = rp[3] = stamp[0]; 461 if (ri->ri_hwbits) { 462 hrp[0] = stamp[0]; 463 hrp[1] = stamp[0]; 464 hrp[2] = stamp[0]; 465 hrp[3] = stamp[0]; 466 } 467 } 468 } else { 469 uc -= font->firstchar; 470 fr = (u_char *)font->data + uc * ri->ri_fontscale; 471 fs = font->stride; 472 473 while (height--) { 474 rp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 475 rp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 476 rp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 477 rp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK); 478 if (ri->ri_hwbits) { 479 hrp[0] = STAMP_READ(STAMP_SHIFT(fr[0], 1) & STAMP_MASK); 480 hrp[1] = STAMP_READ(STAMP_SHIFT(fr[0], 0) & STAMP_MASK); 481 hrp[2] = STAMP_READ(STAMP_SHIFT(fr[1], 1) & STAMP_MASK); 482 hrp[3] = STAMP_READ(STAMP_SHIFT(fr[1], 0) & STAMP_MASK); 483 } 484 485 fr += fs; 486 DELTA(rp, ri->ri_stride, int32_t *); 487 if (ri->ri_hwbits) 488 DELTA(hrp, ri->ri_stride, int32_t *); 489 } 490 } 491 492 /* Do underline */ 493 if ((attr & 1) != 0) { 494 DELTA(rp, -(ri->ri_stride << 1), int32_t *); 495 rp[0] = rp[1] = rp[2] = rp[3] = stamp[15]; 496 if (ri->ri_hwbits) { 497 DELTA(hrp, -(ri->ri_stride << 1), int32_t *); 498 hrp[0] = stamp[15]; 499 hrp[1] = stamp[15]; 500 hrp[2] = stamp[15]; 501 hrp[3] = stamp[15]; 502 } 503 } 504 505 stamp_mutex--; 506 } 507 #endif /* !RASOPS_SMALL */ 508