rasops.c revision 1.2
1/* $NetBSD: rasops.c,v 1.2 1999/04/13 00:40:08 ad Exp $ */ 2 3/* 4 * Copyright (c) 1999 Andy Doran <ad@NetBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30#include <sys/cdefs.h> 31__KERNEL_RCSID(0, "$NetBSD: rasops.c,v 1.2 1999/04/13 00:40:08 ad Exp $"); 32 33#include "opt_rasops.h" 34 35#include <sys/types.h> 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/time.h> 39 40#include <dev/wscons/wsdisplayvar.h> 41#include <dev/wscons/wsconsio.h> 42#include <dev/wsfont/wsfont.h> 43#include <dev/rasops/rasops.h> 44 45/* ANSI colormap (R,G,B). Upper 8 are high-intensity */ 46u_char rasops_cmap[256*3] = { 47 0x00, 0x00, 0x00, /* black */ 48 0x7f, 0x00, 0x00, /* red */ 49 0x00, 0x7f, 0x00, /* green */ 50 0x7f, 0x7f, 0x00, /* brown */ 51 0x00, 0x00, 0x7f, /* blue */ 52 0x7f, 0x00, 0x7f, /* magenta */ 53 0x00, 0x7f, 0x7f, /* cyan */ 54 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */ 55 56 0x7f, 0x7f, 0x7f, /* black */ 57 0xff, 0x00, 0x00, /* red */ 58 0x00, 0xff, 0x00, /* green */ 59 0xff, 0xff, 0x00, /* brown */ 60 0x00, 0x00, 0xff, /* blue */ 61 0xff, 0x00, 0xff, /* magenta */ 62 0x00, 0xff, 0xff, /* cyan */ 63 0xff, 0xff, 0xff, /* white */ 64}; 65 66/* True if color is gray */ 67u_char rasops_isgray[16] = { 68 1, 0, 0, 0, 69 0, 0, 0, 1, 70 1, 0, 0, 0, 71 0, 0, 0, 1 72}; 73 74/* Common functions */ 75static void rasops_copycols __P((void *, int, int, int, int)); 76static void rasops_copyrows __P((void *, int, int, int)); 77static int rasops_mapchar __P((void *, int, u_int *)); 78static void rasops_cursor __P((void *, int, int, int)); 79static int rasops_alloc_cattr __P((void *, int, int, int, long *)); 80static int rasops_alloc_mattr __P((void *, int, int, int, long *)); 81 82/* Per-depth initalization functions */ 83void rasops1_init __P((struct rasops_info *)); 84void rasops8_init __P((struct rasops_info *)); 85void rasops15_init __P((struct rasops_info *)); 86void rasops24_init __P((struct rasops_info *)); 87void rasops32_init __P((struct rasops_info *)); 88 89/* 90 * Initalize a 'rasops_info' descriptor. 91 */ 92int 93rasops_init(ri, wantrows, wantcols, clear, center) 94 struct rasops_info *ri; 95 int wantrows, wantcols, clear, center; 96{ 97 98 /* Select a font if the caller doesn't care */ 99 if (ri->ri_font == NULL) { 100 int cookie; 101 102 wsfont_init(); 103 104 /* Want 8 pixel wide, don't care about aestethics */ 105 if ((cookie = wsfont_find(NULL, 8, 0, 0)) < 0) 106 cookie = wsfont_find(NULL, 0, 0, 0); 107 108 if (cookie < 0) { 109 printf("rasops_init: font table is empty\n"); 110 return (-1); 111 } 112 113 if (wsfont_lock(cookie, &ri->ri_font, 114 WSFONT_LITTLE, WSFONT_LITTLE) < 0) { 115 printf("rasops_init: couldn't lock font\n"); 116 return (-1); 117 } 118 } 119 120 /* This should never happen in reality... */ 121#ifdef DEBUG 122 if ((int)ri->ri_bits & 3) { 123 printf("rasops_init: bits not aligned on 32-bit boundary\n"); 124 return (-1); 125 } 126 127 if ((int)ri->ri_stride & 3) { 128 printf("rasops_init: stride not aligned on 32-bit boundary\n"); 129 return (-1); 130 } 131 132 if (ri->ri_font->fontwidth > 32) { 133 printf("rasops_init: fontwidth > 32\n"); 134 return (-1); 135 } 136#endif 137 138 /* Fix color palette. We need this for the cursor to work. */ 139 rasops_cmap[255*3+0] = 0xff; 140 rasops_cmap[255*3+1] = 0xff; 141 rasops_cmap[255*3+2] = 0xff; 142 143 /* Don't care if the caller wants a hideously small console */ 144 if (wantrows < 10) 145 wantrows = 5000; 146 147 if (wantcols < 20) 148 wantcols = 5000; 149 150 /* Now constrain what they get */ 151 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols; 152 ri->ri_emuheight = ri->ri_font->fontheight * wantrows; 153 154 if (ri->ri_emuwidth > ri->ri_width) 155 ri->ri_emuwidth = ri->ri_width; 156 157 if (ri->ri_emuheight > ri->ri_height) 158 ri->ri_emuheight = ri->ri_height; 159 160 /* Reduce width until aligned on a 32-bit boundary */ 161 while ((ri->ri_emuwidth*ri->ri_depth & 31) != 0) 162 ri->ri_emuwidth--; 163 164 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth; 165 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight; 166 ri->ri_emustride = ri->ri_emuwidth * ri->ri_depth >> 3; 167 ri->ri_delta = ri->ri_stride - ri->ri_emustride; 168 ri->ri_ccol = 0; 169 ri->ri_crow = 0; 170 ri->ri_pelbytes = ri->ri_depth >> 3; 171 172 ri->ri_xscale = (ri->ri_font->fontwidth * ri->ri_depth) >> 3; 173 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride; 174 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 175 176#ifdef DEBUG 177 if (ri->ri_delta & 3) 178 panic("rasops_init: delta isn't aligned on 32-bit boundary!"); 179#endif 180 /* Clear the entire display */ 181 if (clear) 182 bzero(ri->ri_bits, ri->ri_stride * ri->ri_height); 183 184 /* Now centre our window if needs be */ 185 ri->ri_origbits = ri->ri_bits; 186 187 if (center) { 188 ri->ri_bits += ((ri->ri_stride - ri->ri_emustride) >> 1) & ~3; 189 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) * 190 ri->ri_stride; 191 } 192 193 /* Fill in defaults for operations set */ 194 ri->ri_ops.mapchar = rasops_mapchar; 195 ri->ri_ops.copyrows = rasops_copyrows; 196 ri->ri_ops.copycols = rasops_copycols; 197 ri->ri_ops.cursor = rasops_cursor; 198 199 if (ri->ri_depth == 1 || ri->ri_forcemono) 200 ri->ri_ops.alloc_attr = rasops_alloc_mattr; 201 else 202 ri->ri_ops.alloc_attr = rasops_alloc_cattr; 203 204 switch (ri->ri_depth) { 205#ifdef RASOPS1 206 case 1: 207 rasops1_init(ri); 208 break; 209#endif 210 211#ifdef RASOPS8 212 case 8: 213 rasops8_init(ri); 214 break; 215#endif 216 217#if defined(RASOPS15) || defined(RASOPS16) 218 case 15: 219 case 16: 220 rasops15_init(ri); 221 break; 222#endif 223 224#ifdef RASOPS24 225 case 24: 226 rasops24_init(ri); 227 break; 228#endif 229 230#ifdef RASOPS24 231 case 32: 232 rasops32_init(ri); 233 break; 234#endif 235 default: 236 ri->ri_flg = 0; 237 return (-1); 238 } 239 240 ri->ri_flg = RASOPS_INITTED; 241 return (0); 242} 243 244 245/* 246 * Map a character. 247 */ 248static int 249rasops_mapchar(cookie, c, cp) 250 void *cookie; 251 int c; 252 u_int *cp; 253{ 254 struct rasops_info *ri; 255 256 ri = (struct rasops_info *)cookie; 257 258 if (c < ri->ri_font->firstchar) { 259 *cp = ' '; 260 return (0); 261 } 262 263 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) { 264 *cp = ' '; 265 return (0); 266 } 267 268 *cp = c; 269 return (5); 270} 271 272 273/* 274 * Allocate a color attribute. 275 */ 276static int 277rasops_alloc_cattr(cookie, fg, bg, flg, attr) 278 void *cookie; 279 int fg, bg, flg; 280 long *attr; 281{ 282 int swap; 283 284#ifdef RASOPS_CLIPPING 285 fg &= 7; 286 bg &= 7; 287 flg &= 255; 288#endif 289 if (flg & WSATTR_BLINK) 290 return (EINVAL); 291 292 if (flg & WSATTR_REVERSE) { 293 swap = fg; 294 fg = bg; 295 bg = swap; 296 } 297 298 if (flg & WSATTR_HILIT) 299 fg += 8; 300 301 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); 302 303 if (rasops_isgray[fg]) 304 flg |= 2; 305 306 if (rasops_isgray[bg]) 307 flg |= 4; 308 309 *attr = (bg << 16) | (fg << 24) | flg; 310 return 0; 311} 312 313 314/* 315 * Allocate a mono attribute. 316 */ 317static int 318rasops_alloc_mattr(cookie, fg, bg, flg, attr) 319 void *cookie; 320 int fg, bg, flg; 321 long *attr; 322{ 323 int swap; 324 325#ifdef RASOPS_CLIPPING 326 flg &= 255; 327#endif 328 fg = fg ? 1 : 0; 329 bg = bg ? 1 : 0; 330 331 if (flg & WSATTR_BLINK) 332 return (EINVAL); 333 334 if (!(flg & WSATTR_REVERSE) ^ !(flg & WSATTR_HILIT)) { 335 swap = fg; 336 fg = bg; 337 bg = swap; 338 } 339 340 *attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6); 341 return 0; 342} 343 344 345/* 346 * Copy rows. 347 */ 348static void 349rasops_copyrows(cookie, src, dst, num) 350 void *cookie; 351 int src, dst, num; 352{ 353 struct rasops_info *ri; 354 int32_t *sp, *dp, *srp, *drp; 355 int n8, n1, cnt; 356 357 ri = (struct rasops_info *)cookie; 358 359#ifdef RASOPS_CLIPPING 360 if (dst == src) 361 return; 362 363 if (src < 0) { 364 num += src; 365 src = 0; 366 } 367 368 if ((src + num) > ri->ri_rows) 369 num = ri->ri_rows - src; 370 371 if (dst < 0) { 372 num += dst; 373 dst = 0; 374 } 375 376 if ((dst + num) > ri->ri_rows) 377 num = ri->ri_rows - dst; 378 379 if (num <= 0) 380 return; 381#endif 382 383 num *= ri->ri_font->fontheight; 384 n8 = ri->ri_emustride >> 5; 385 n1 = (ri->ri_emustride >> 2) & 7; 386 387 if (dst < src) { 388 sp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale); 389 dp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale); 390 391 while (num--) { 392 for (cnt = n8; cnt; cnt--) { 393 dp[0] = sp[0]; 394 dp[1] = sp[1]; 395 dp[2] = sp[2]; 396 dp[3] = sp[3]; 397 dp[4] = sp[4]; 398 dp[5] = sp[5]; 399 dp[6] = sp[6]; 400 dp[7] = sp[7]; 401 dp += 8; 402 sp += 8; 403 } 404 405 for (cnt = n1; cnt; cnt--) 406 *dp++ = *sp++; 407 408 DELTA(dp, ri->ri_delta, int32_t *); 409 DELTA(sp, ri->ri_delta, int32_t *); 410 } 411 } else { 412 src = ri->ri_font->fontheight * src + num - 1; 413 dst = ri->ri_font->fontheight * dst + num - 1; 414 415 srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride); 416 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride); 417 418 while (num--) { 419 dp = drp; 420 sp = srp; 421 DELTA(srp, -ri->ri_stride, int32_t *); 422 DELTA(drp, -ri->ri_stride, int32_t *); 423 424 for (cnt = n8; cnt; cnt--) { 425 dp[0] = sp[0]; 426 dp[1] = sp[1]; 427 dp[2] = sp[2]; 428 dp[3] = sp[3]; 429 dp[4] = sp[4]; 430 dp[5] = sp[5]; 431 dp[6] = sp[6]; 432 dp[7] = sp[7]; 433 dp += 8; 434 sp += 8; 435 } 436 437 for (cnt = n1; cnt; cnt--) 438 *dp++ = *sp++; 439 } 440 } 441} 442 443 444/* 445 * Copy columns. This is slow, and hard to optimize due to alignment, 446 * and the fact that we have to copy both left->right and right->left. 447 * We simply cop-out here and use bcopy(), since it handles all of 448 * these cases anyway. 449 */ 450static void 451rasops_copycols(cookie, row, src, dst, num) 452 void *cookie; 453 int row, src, dst, num; 454{ 455 struct rasops_info *ri; 456 u_char *sp, *dp; 457 int height; 458 459 ri = (struct rasops_info *)cookie; 460 461#ifdef RASOPS_CLIPPING 462 if (dst == src) 463 return; 464 465 if (row < 0 || row >= ri->ri_rows) 466 return; 467 468 if (src < 0) { 469 num += src; 470 src = 0; 471 } 472 473 if ((src + num) > ri->ri_cols) 474 num = ri->ri_cols - src; 475 476 if (dst < 0) { 477 num += dst; 478 dst = 0; 479 } 480 481 if ((dst + num) > ri->ri_cols) 482 num = ri->ri_cols - dst; 483 484 if (num <= 0) 485 return; 486#endif 487 488 num *= ri->ri_xscale; 489 row *= ri->ri_yscale; 490 height = ri->ri_font->fontheight; 491 492 sp = ri->ri_bits + row + src * ri->ri_xscale; 493 dp = ri->ri_bits + row + dst * ri->ri_xscale; 494 495 while (height--) { 496 bcopy(sp, dp, num); 497 dp += ri->ri_stride; 498 sp += ri->ri_stride; 499 } 500} 501 502 503/* 504 * Turn cursor off/on. 505 */ 506static void 507rasops_cursor(cookie, on, row, col) 508 void *cookie; 509 int on, row, col; 510{ 511 struct rasops_info *ri; 512 513 ri = (struct rasops_info *)cookie; 514 515 /* Turn old cursor off */ 516 if (ri->ri_flg & RASOPS_CURSOR) 517#ifdef RASOPS_CLIPPING 518 if (!(ri->ri_flg & RASOPS_CURSOR_CLIPPED)) 519#endif 520 ri->ri_do_cursor(ri); 521 522 /* Select new cursor */ 523#ifdef RASOPS_CLIPPING 524 ri->ri_flg &= ~RASOPS_CURSOR_CLIPPED; 525 526 if (row < 0 || row >= ri->ri_rows) 527 ri->ri_flg |= RASOPS_CURSOR_CLIPPED; 528 else if (col < 0 || col >= ri->ri_cols) 529 ri->ri_flg |= RASOPS_CURSOR_CLIPPED; 530#endif 531 ri->ri_crow = row; 532 ri->ri_ccol = col; 533 534 if (on) { 535 ri->ri_flg |= RASOPS_CURSOR; 536#ifdef RASOPS_CLIPPING 537 if (!(ri->ri_flg & RASOPS_CURSOR_CLIPPED)) 538#endif 539 ri->ri_do_cursor(ri); 540 } else 541 ri->ri_flg &= ~RASOPS_CURSOR; 542} 543 544 545#if (RASOPS15 + RASOPS16 + RASOPS32) 546/* 547 * Make the device colormap 548 */ 549void 550rasops_init_devcmap(ri) 551 struct rasops_info *ri; 552{ 553 int i, c; 554 u_char *p; 555 556 p = rasops_cmap; 557 558 for (i = 0; i < 16; i++) { 559 if (ri->ri_rnum <= 8) 560 c = (*p++ >> (8 - ri->ri_rnum)) << ri->ri_rpos; 561 else 562 c = (*p++ << (ri->ri_rnum - 8)) << ri->ri_rpos; 563 564 if (ri->ri_gnum <= 8) 565 c = (*p++ >> (8 - ri->ri_gnum)) << ri->ri_gpos; 566 else 567 c = (*p++ << (ri->ri_gnum - 8)) << ri->ri_gpos; 568 569 if (ri->ri_bnum <= 8) 570 c = (*p++ >> (8 - ri->ri_bnum)) << ri->ri_bpos; 571 else 572 c = (*p++ << (ri->ri_bnum - 8)) << ri->ri_bpos; 573 574 ri->ri_devcmap[i] = c; 575 } 576} 577#endif 578 579 580/* 581 * Unpack a rasops attribute 582 */ 583void 584rasops_unpack_attr(attr, fg, bg, underline) 585 long attr; 586 int *fg, *bg, *underline; 587{ 588 589 *fg = ((u_int)attr >> 24) & 15; 590 *bg = ((u_int)attr >> 16) & 15; 591 *underline = (u_int)attr & 1; 592} 593