1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "ureg.h" 8 #include "../port/error.h" 9 10 #define Image IMAGE 11 #include <draw.h> 12 #include <memdraw.h> 13 #include <cursor.h> 14 #include "screen.h" 15 16 #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) 17 18 Point ZP = {0, 0}; 19 20 Rectangle physgscreenr; 21 22 Memdata gscreendata; 23 Memimage *gscreen; 24 25 VGAscr vgascreen[1]; 26 27 Cursor arrow = { 28 { -1, -1 }, 29 { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C, 30 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 31 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04, 32 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40, 33 }, 34 { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, 35 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, 36 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, 37 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00, 38 }, 39 }; 40 41 int didswcursorinit; 42 43 static void *softscreen; 44 45 int 46 screensize(int x, int y, int z, ulong chan) 47 { 48 VGAscr *scr; 49 void *oldsoft; 50 51 lock(&vgascreenlock); 52 if(waserror()){ 53 unlock(&vgascreenlock); 54 nexterror(); 55 } 56 57 memimageinit(); 58 scr = &vgascreen[0]; 59 oldsoft = softscreen; 60 61 if(scr->paddr == 0){ 62 int width = (x*z)/BI2WD; 63 void *p; 64 65 p = xalloc(width*BY2WD*y); 66 if(p == nil) 67 error("no memory for vga soft screen"); 68 gscreendata.bdata = softscreen = p; 69 if(scr->dev && scr->dev->page){ 70 scr->vaddr = KADDR(VGAMEM()); 71 scr->apsize = 1<<16; 72 } 73 scr->useflush = 1; 74 } 75 else{ 76 gscreendata.bdata = scr->vaddr; 77 scr->useflush = scr->dev && scr->dev->flush; 78 } 79 80 scr->gscreen = nil; 81 if(gscreen) 82 freememimage(gscreen); 83 gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata); 84 if(gscreen == nil) 85 error("no memory for vga memimage"); 86 vgaimageinit(chan); 87 88 scr->palettedepth = 6; /* default */ 89 scr->gscreendata = &gscreendata; 90 scr->memdefont = getmemdefont(); 91 scr->gscreen = gscreen; 92 93 physgscreenr = gscreen->r; 94 unlock(&vgascreenlock); 95 poperror(); 96 if(oldsoft) 97 xfree(oldsoft); 98 99 memimagedraw(gscreen, gscreen->r, memblack, ZP, nil, ZP, S); 100 flushmemscreen(gscreen->r); 101 102 if(didswcursorinit) 103 swcursorinit(); 104 drawcmap(); 105 return 0; 106 } 107 108 int 109 screenaperture(int size, int align) 110 { 111 VGAscr *scr; 112 113 scr = &vgascreen[0]; 114 115 if(scr->paddr) /* set up during enable */ 116 return 0; 117 118 if(size == 0) 119 return 0; 120 121 if(scr->dev && scr->dev->linear){ 122 scr->dev->linear(scr, size, align); 123 return 0; 124 } 125 126 /* 127 * Need to allocate some physical address space. 128 * The driver will tell the card to use it. 129 */ 130 size = PGROUND(size); 131 scr->paddr = upaalloc(size, align); 132 if(scr->paddr == 0) 133 return -1; 134 scr->vaddr = vmap(scr->paddr, size); 135 if(scr->vaddr == nil) 136 return -1; 137 scr->apsize = size; 138 139 return 0; 140 } 141 142 uchar* 143 attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen) 144 { 145 VGAscr *scr; 146 147 scr = &vgascreen[0]; 148 if(scr->gscreen == nil || scr->gscreendata == nil) 149 return nil; 150 151 *r = scr->gscreen->clipr; 152 *chan = scr->gscreen->chan; 153 *d = scr->gscreen->depth; 154 *width = scr->gscreen->width; 155 *softscreen = scr->useflush; 156 157 return scr->gscreendata->bdata; 158 } 159 160 /* 161 * It would be fair to say that this doesn't work for >8-bit screens. 162 */ 163 void 164 flushmemscreen(Rectangle r) 165 { 166 VGAscr *scr; 167 uchar *sp, *disp, *sdisp, *edisp; 168 int y, len, incs, off, page; 169 170 scr = &vgascreen[0]; 171 if(scr->dev && scr->dev->flush){ 172 scr->dev->flush(scr, r); 173 return; 174 } 175 if(scr->gscreen == nil || scr->useflush == 0) 176 return; 177 if(scr->dev == nil || scr->dev->page == nil) 178 return; 179 180 if(rectclip(&r, scr->gscreen->r) == 0) 181 return; 182 183 incs = scr->gscreen->width * BY2WD; 184 185 switch(scr->gscreen->depth){ 186 default: 187 len = 0; 188 panic("flushmemscreen: depth\n"); 189 break; 190 case 8: 191 len = Dx(r); 192 break; 193 } 194 if(len < 1) 195 return; 196 197 off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8; 198 page = off/scr->apsize; 199 off %= scr->apsize; 200 disp = scr->vaddr; 201 sdisp = disp+off; 202 edisp = disp+scr->apsize; 203 204 off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8; 205 206 sp = scr->gscreendata->bdata + off; 207 208 scr->dev->page(scr, page); 209 for(y = r.min.y; y < r.max.y; y++) { 210 if(sdisp + incs < edisp) { 211 memmove(sdisp, sp, len); 212 sp += incs; 213 sdisp += incs; 214 } 215 else { 216 off = edisp - sdisp; 217 page++; 218 if(off <= len){ 219 if(off > 0) 220 memmove(sdisp, sp, off); 221 scr->dev->page(scr, page); 222 if(len - off > 0) 223 memmove(disp, sp+off, len - off); 224 } 225 else { 226 memmove(sdisp, sp, len); 227 scr->dev->page(scr, page); 228 } 229 sp += incs; 230 sdisp += incs - scr->apsize; 231 } 232 } 233 } 234 235 void 236 getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb) 237 { 238 VGAscr *scr; 239 ulong x; 240 241 scr = &vgascreen[0]; 242 if(scr->gscreen == nil) 243 return; 244 245 switch(scr->gscreen->depth){ 246 default: 247 x = 0x0F; 248 break; 249 case 8: 250 x = 0xFF; 251 break; 252 } 253 p &= x; 254 255 lock(&cursor); 256 *pr = scr->colormap[p][0]; 257 *pg = scr->colormap[p][1]; 258 *pb = scr->colormap[p][2]; 259 unlock(&cursor); 260 } 261 262 int 263 setpalette(ulong p, ulong r, ulong g, ulong b) 264 { 265 VGAscr *scr; 266 int d; 267 268 scr = &vgascreen[0]; 269 d = scr->palettedepth; 270 271 lock(&cursor); 272 scr->colormap[p][0] = r; 273 scr->colormap[p][1] = g; 274 scr->colormap[p][2] = b; 275 vgao(PaddrW, p); 276 vgao(Pdata, r>>(32-d)); 277 vgao(Pdata, g>>(32-d)); 278 vgao(Pdata, b>>(32-d)); 279 unlock(&cursor); 280 281 return ~0; 282 } 283 284 /* 285 * On some video cards (e.g. Mach64), the palette is used as the 286 * DAC registers for >8-bit modes. We don't want to set them when the user 287 * is trying to set a colormap and the card is in one of these modes. 288 */ 289 int 290 setcolor(ulong p, ulong r, ulong g, ulong b) 291 { 292 VGAscr *scr; 293 int x; 294 295 scr = &vgascreen[0]; 296 if(scr->gscreen == nil) 297 return 0; 298 299 switch(scr->gscreen->depth){ 300 case 1: 301 case 2: 302 case 4: 303 x = 0x0F; 304 break; 305 case 8: 306 x = 0xFF; 307 break; 308 default: 309 return 0; 310 } 311 p &= x; 312 313 return setpalette(p, r, g, b); 314 } 315 316 int 317 cursoron(int dolock) 318 { 319 VGAscr *scr; 320 int v; 321 322 scr = &vgascreen[0]; 323 if(scr->cur == nil || scr->cur->move == nil) 324 return 0; 325 326 if(dolock) 327 lock(&cursor); 328 v = scr->cur->move(scr, mousexy()); 329 if(dolock) 330 unlock(&cursor); 331 332 return v; 333 } 334 335 void 336 cursoroff(int) 337 { 338 } 339 340 void 341 setcursor(Cursor* curs) 342 { 343 VGAscr *scr; 344 345 scr = &vgascreen[0]; 346 if(scr->cur == nil || scr->cur->load == nil) 347 return; 348 349 scr->cur->load(scr, curs); 350 } 351 352 int hwaccel = 1; 353 int hwblank = 0; /* turned on by drivers that are known good */ 354 int panning = 0; 355 356 int 357 hwdraw(Memdrawparam *par) 358 { 359 VGAscr *scr; 360 Memimage *dst, *src, *mask; 361 int m; 362 363 if(hwaccel == 0) 364 return 0; 365 366 scr = &vgascreen[0]; 367 if((dst=par->dst) == nil || dst->data == nil) 368 return 0; 369 if((src=par->src) == nil || src->data == nil) 370 return 0; 371 if((mask=par->mask) == nil || mask->data == nil) 372 return 0; 373 374 if(scr->cur == &swcursor){ 375 /* 376 * always calling swcursorhide here doesn't cure 377 * leaving cursor tracks nor failing to refresh menus 378 * with the latest libmemdraw/draw.c. 379 */ 380 if(dst->data->bdata == gscreendata.bdata) 381 swcursoravoid(par->r); 382 if(src->data->bdata == gscreendata.bdata) 383 swcursoravoid(par->sr); 384 if(mask->data->bdata == gscreendata.bdata) 385 swcursoravoid(par->mr); 386 } 387 388 if(dst->data->bdata != gscreendata.bdata) 389 return 0; 390 391 if(scr->fill==nil && scr->scroll==nil) 392 return 0; 393 394 /* 395 * If we have an opaque mask and source is one opaque 396 * pixel we can convert to the destination format and just 397 * replicate with memset. 398 */ 399 m = Simplesrc|Simplemask|Fullmask; 400 if(scr->fill 401 && (par->state&m)==m 402 && ((par->srgba&0xFF) == 0xFF) 403 && (par->op&S) == S) 404 return scr->fill(scr, par->r, par->sdval); 405 406 /* 407 * If no source alpha, an opaque mask, we can just copy the 408 * source onto the destination. If the channels are the same and 409 * the source is not replicated, memmove suffices. 410 */ 411 m = Simplemask|Fullmask; 412 if(scr->scroll 413 && src->data->bdata==dst->data->bdata 414 && !(src->flags&Falpha) 415 && (par->state&m)==m 416 && (par->op&S) == S) 417 return scr->scroll(scr, par->r, par->sr); 418 419 return 0; 420 } 421 422 void 423 blankscreen(int blank) 424 { 425 VGAscr *scr; 426 427 scr = &vgascreen[0]; 428 if(hwblank){ 429 if(scr->blank) 430 scr->blank(scr, blank); 431 else 432 vgablank(scr, blank); 433 } 434 } 435 436 void 437 vgalinearpciid(VGAscr *scr, int vid, int did) 438 { 439 Pcidev *p; 440 441 p = nil; 442 while((p = pcimatch(p, vid, 0)) != nil){ 443 if(p->ccrb != 3) /* video card */ 444 continue; 445 if(did != 0 && p->did != did) 446 continue; 447 break; 448 } 449 if(p == nil) 450 error("pci video card not found"); 451 452 scr->pci = p; 453 vgalinearpci(scr); 454 } 455 456 void 457 vgalinearpci(VGAscr *scr) 458 { 459 ulong paddr; 460 int i, size, best; 461 Pcidev *p; 462 463 p = scr->pci; 464 if(p == nil) 465 return; 466 467 /* 468 * Scan for largest memory region on card. 469 * Some S3 cards (e.g. Savage) have enormous 470 * mmio regions (but even larger frame buffers). 471 * Some 3dfx cards (e.g., Voodoo3) have mmio 472 * buffers the same size as the frame buffer, 473 * but only the frame buffer is marked as 474 * prefetchable (bar&8). If a card doesn't fit 475 * into these heuristics, its driver will have to 476 * call vgalinearaddr directly. 477 */ 478 best = -1; 479 for(i=0; i<nelem(p->mem); i++){ 480 if(p->mem[i].bar&1) /* not memory */ 481 continue; 482 if(p->mem[i].size < 640*480) /* not big enough */ 483 continue; 484 if(best==-1 485 || p->mem[i].size > p->mem[best].size 486 || (p->mem[i].size == p->mem[best].size 487 && (p->mem[i].bar&8) 488 && !(p->mem[best].bar&8))) 489 best = i; 490 } 491 if(best >= 0){ 492 paddr = p->mem[best].bar & ~0x0F; 493 size = p->mem[best].size; 494 vgalinearaddr(scr, paddr, size); 495 return; 496 } 497 error("no video memory found on pci card"); 498 } 499 500 void 501 vgalinearaddr(VGAscr *scr, ulong paddr, int size) 502 { 503 int x, nsize; 504 ulong npaddr; 505 506 /* 507 * new approach. instead of trying to resize this 508 * later, let's assume that we can just allocate the 509 * entire window to start with. 510 */ 511 512 if(scr->paddr == paddr && size <= scr->apsize) 513 return; 514 515 if(scr->paddr){ 516 /* 517 * could call vunmap and vmap, 518 * but worried about dangling pointers in devdraw 519 */ 520 error("cannot grow vga frame buffer"); 521 } 522 523 /* round to page boundary, just in case */ 524 x = paddr&(BY2PG-1); 525 npaddr = paddr-x; 526 nsize = PGROUND(size+x); 527 528 /* 529 * Don't bother trying to map more than 4000x4000x32 = 64MB. 530 * We only have a 256MB window. 531 */ 532 if(nsize > 64*MB) 533 nsize = 64*MB; 534 scr->vaddr = vmap(npaddr, nsize); 535 if(scr->vaddr == 0) 536 error("cannot allocate vga frame buffer"); 537 scr->vaddr = (char*)scr->vaddr+x; 538 scr->paddr = paddr; 539 scr->apsize = nsize; 540 /* let mtrr harmlessly fail on old CPUs, e.g., P54C */ 541 if(!waserror()){ 542 mtrr(npaddr, nsize, "wc"); 543 poperror(); 544 } 545 } 546 547 548 /* 549 * Software cursor. 550 */ 551 int swvisible; /* is the cursor visible? */ 552 int swenabled; /* is the cursor supposed to be on the screen? */ 553 Memimage* swback; /* screen under cursor */ 554 Memimage* swimg; /* cursor image */ 555 Memimage* swmask; /* cursor mask */ 556 Memimage* swimg1; 557 Memimage* swmask1; 558 559 Point swoffset; 560 Rectangle swrect; /* screen rectangle in swback */ 561 Point swpt; /* desired cursor location */ 562 Point swvispt; /* actual cursor location */ 563 int swvers; /* incremented each time cursor image changes */ 564 int swvisvers; /* the version on the screen */ 565 566 /* 567 * called with drawlock locked for us, most of the time. 568 * kernel prints at inopportune times might mean we don't 569 * hold the lock, but memimagedraw is now reentrant so 570 * that should be okay: worst case we get cursor droppings. 571 */ 572 void 573 swcursorhide(void) 574 { 575 if(swvisible == 0) 576 return; 577 if(swback == nil) 578 return; 579 swvisible = 0; 580 memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S); 581 flushmemscreen(swrect); 582 } 583 584 void 585 swcursoravoid(Rectangle r) 586 { 587 if(swvisible && rectXrect(r, swrect)) 588 swcursorhide(); 589 } 590 591 void 592 swcursordraw(void) 593 { 594 if(swvisible) 595 return; 596 if(swenabled == 0) 597 return; 598 if(swback == nil || swimg1 == nil || swmask1 == nil) 599 return; 600 assert(!canqlock(&drawlock)); 601 swvispt = swpt; 602 swvisvers = swvers; 603 swrect = rectaddpt(Rect(0,0,16,16), swvispt); 604 memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S); 605 memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD); 606 flushmemscreen(swrect); 607 swvisible = 1; 608 } 609 610 /* 611 * Need to lock drawlock for ourselves. 612 */ 613 void 614 swenable(VGAscr*) 615 { 616 swenabled = 1; 617 if(canqlock(&drawlock)){ 618 swcursordraw(); 619 qunlock(&drawlock); 620 } 621 } 622 623 void 624 swdisable(VGAscr*) 625 { 626 swenabled = 0; 627 if(canqlock(&drawlock)){ 628 swcursorhide(); 629 qunlock(&drawlock); 630 } 631 } 632 633 void 634 swload(VGAscr*, Cursor *curs) 635 { 636 uchar *ip, *mp; 637 int i, j, set, clr; 638 639 if(!swimg || !swmask || !swimg1 || !swmask1) 640 return; 641 /* 642 * Build cursor image and mask. 643 * Image is just the usual cursor image 644 * but mask is a transparent alpha mask. 645 * 646 * The 16x16x8 memimages do not have 647 * padding at the end of their scan lines. 648 */ 649 ip = byteaddr(swimg, ZP); 650 mp = byteaddr(swmask, ZP); 651 for(i=0; i<32; i++){ 652 set = curs->set[i]; 653 clr = curs->clr[i]; 654 for(j=0x80; j; j>>=1){ 655 *ip++ = set&j ? 0x00 : 0xFF; 656 *mp++ = (clr|set)&j ? 0xFF : 0x00; 657 } 658 } 659 swoffset = curs->offset; 660 swvers++; 661 memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S); 662 memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S); 663 } 664 665 int 666 swmove(VGAscr*, Point p) 667 { 668 swpt = addpt(p, swoffset); 669 return 0; 670 } 671 672 void 673 swcursorclock(void) 674 { 675 int x; 676 677 if(!swenabled) 678 return; 679 if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers) 680 return; 681 682 x = splhi(); 683 if(swenabled) 684 if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers) 685 if(canqlock(&drawlock)){ 686 swcursorhide(); 687 swcursordraw(); 688 qunlock(&drawlock); 689 } 690 splx(x); 691 } 692 693 void 694 swcursorinit(void) 695 { 696 static int init, warned; 697 VGAscr *scr; 698 699 didswcursorinit = 1; 700 if(!init){ 701 init = 1; 702 addclock0link(swcursorclock, 10); 703 } 704 scr = &vgascreen[0]; 705 if(scr==nil || scr->gscreen==nil) 706 return; 707 708 if(scr->dev == nil || scr->dev->linear == nil){ 709 if(!warned){ 710 print("cannot use software cursor on non-linear vga screen\n"); 711 warned = 1; 712 } 713 return; 714 } 715 716 if(swback){ 717 freememimage(swback); 718 freememimage(swmask); 719 freememimage(swmask1); 720 freememimage(swimg); 721 freememimage(swimg1); 722 } 723 724 swback = allocmemimage(Rect(0,0,32,32), gscreen->chan); 725 swmask = allocmemimage(Rect(0,0,16,16), GREY8); 726 swmask1 = allocmemimage(Rect(0,0,16,16), GREY1); 727 swimg = allocmemimage(Rect(0,0,16,16), GREY8); 728 swimg1 = allocmemimage(Rect(0,0,16,16), GREY1); 729 if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){ 730 print("software cursor: allocmemimage fails"); 731 return; 732 } 733 734 memfillcolor(swmask, DOpaque); 735 memfillcolor(swmask1, DOpaque); 736 memfillcolor(swimg, DBlack); 737 memfillcolor(swimg1, DBlack); 738 } 739 740 VGAcur swcursor = 741 { 742 "soft", 743 swenable, 744 swdisable, 745 swload, 746 swmove, 747 }; 748 749