2 #include "../port/lib.h"
8 #include "../port/error.h"
16 #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
20 Rectangle physgscreenr;
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,
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,
43 static void *softscreen;
46 screensize(int x, int y, int z, ulong chan)
53 unlock(&vgascreenlock);
62 int width = (x*z)/BI2WD;
65 p = xalloc(width*BY2WD*y);
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());
76 gscreendata.bdata = scr->vaddr;
77 scr->useflush = scr->dev && scr->dev->flush;
82 freememimage(gscreen);
83 gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);
85 error("no memory for vga memimage");
88 scr->palettedepth = 6; /* default */
89 scr->gscreendata = &gscreendata;
90 scr->memdefont = getmemdefont();
91 scr->gscreen = gscreen;
93 physgscreenr = gscreen->r;
94 unlock(&vgascreenlock);
99 memimagedraw(gscreen, gscreen->r, memblack, ZP, nil, ZP, S);
100 flushmemscreen(gscreen->r);
109 screenaperture(int size, int align)
115 if(scr->paddr) /* set up during enable */
121 if(scr->dev && scr->dev->linear){
122 scr->dev->linear(scr, size, align);
127 * Need to allocate some physical address space.
128 * The driver will tell the card to use it.
130 size = PGROUND(size);
131 scr->paddr = upaalloc(size, align);
134 scr->vaddr = vmap(scr->paddr, size);
135 if(scr->vaddr == nil)
143 attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
148 if(scr->gscreen == nil || scr->gscreendata == nil)
151 *r = scr->gscreen->clipr;
152 *chan = scr->gscreen->chan;
153 *d = scr->gscreen->depth;
154 *width = scr->gscreen->width;
155 *softscreen = scr->useflush;
157 return scr->gscreendata->bdata;
161 * It would be fair to say that this doesn't work for >8-bit screens.
164 flushmemscreen(Rectangle r)
167 uchar *sp, *disp, *sdisp, *edisp;
168 int y, len, incs, off, page;
171 if(scr->dev && scr->dev->flush){
172 scr->dev->flush(scr, r);
175 if(scr->gscreen == nil || scr->useflush == 0)
177 if(scr->dev == nil || scr->dev->page == nil)
180 if(rectclip(&r, scr->gscreen->r) == 0)
183 incs = scr->gscreen->width * BY2WD;
185 switch(scr->gscreen->depth){
188 panic("flushmemscreen: depth\n");
197 off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
198 page = off/scr->apsize;
202 edisp = disp+scr->apsize;
204 off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
206 sp = scr->gscreendata->bdata + off;
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);
220 memmove(sdisp, sp, off);
221 scr->dev->page(scr, page);
223 memmove(disp, sp+off, len - off);
226 memmove(sdisp, sp, len);
227 scr->dev->page(scr, page);
230 sdisp += incs - scr->apsize;
236 getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
242 if(scr->gscreen == nil)
245 switch(scr->gscreen->depth){
256 *pr = scr->colormap[p][0];
257 *pg = scr->colormap[p][1];
258 *pb = scr->colormap[p][2];
263 setpalette(ulong p, ulong r, ulong g, ulong b)
269 d = scr->palettedepth;
272 scr->colormap[p][0] = r;
273 scr->colormap[p][1] = g;
274 scr->colormap[p][2] = b;
276 vgao(Pdata, r>>(32-d));
277 vgao(Pdata, g>>(32-d));
278 vgao(Pdata, b>>(32-d));
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.
290 setcolor(ulong p, ulong r, ulong g, ulong b)
296 if(scr->gscreen == nil)
299 switch(scr->gscreen->depth){
313 return setpalette(p, r, g, b);
323 if(scr->cur == nil || scr->cur->move == nil)
328 v = scr->cur->move(scr, mousexy());
341 setcursor(Cursor* curs)
346 if(scr->cur == nil || scr->cur->load == nil)
349 scr->cur->load(scr, curs);
353 int hwblank = 0; /* turned on by drivers that are known good */
357 hwdraw(Memdrawparam *par)
360 Memimage *dst, *src, *mask;
367 if((dst=par->dst) == nil || dst->data == nil)
369 if((src=par->src) == nil || src->data == nil)
371 if((mask=par->mask) == nil || mask->data == nil)
374 if(scr->cur == &swcursor){
376 * always calling swcursorhide here doesn't cure
377 * leaving cursor tracks nor failing to refresh menus
378 * with the latest libmemdraw/draw.c.
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);
388 if(dst->data->bdata != gscreendata.bdata)
391 if(scr->fill==nil && scr->scroll==nil)
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.
399 m = Simplesrc|Simplemask|Fullmask;
402 && ((par->srgba&0xFF) == 0xFF)
404 return scr->fill(scr, par->r, par->sdval);
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.
411 m = Simplemask|Fullmask;
413 && src->data->bdata==dst->data->bdata
414 && !(src->flags&Falpha)
417 return scr->scroll(scr, par->r, par->sr);
423 blankscreen(int blank)
430 scr->blank(scr, blank);
432 vgablank(scr, blank);
437 vgalinearpciid(VGAscr *scr, int vid, int did)
442 while((p = pcimatch(p, vid, 0)) != nil){
443 if(p->ccrb != 3) /* video card */
445 if(did != 0 && p->did != did)
450 error("pci video card not found");
457 vgalinearpci(VGAscr *scr)
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.
479 for(i=0; i<nelem(p->mem); i++){
480 if(p->mem[i].bar&1) /* not memory */
482 if(p->mem[i].size < 640*480) /* not big enough */
485 || p->mem[i].size > p->mem[best].size
486 || (p->mem[i].size == p->mem[best].size
488 && !(p->mem[best].bar&8)))
492 paddr = p->mem[best].bar & ~0x0F;
493 size = p->mem[best].size;
494 vgalinearaddr(scr, paddr, size);
497 error("no video memory found on pci card");
501 vgalinearaddr(VGAscr *scr, ulong paddr, int size)
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.
512 if(scr->paddr == paddr && size <= scr->apsize)
517 * could call vunmap and vmap,
518 * but worried about dangling pointers in devdraw
520 error("cannot grow vga frame buffer");
523 /* round to page boundary, just in case */
526 nsize = PGROUND(size+x);
529 * Don't bother trying to map more than 4000x4000x32 = 64MB.
530 * We only have a 256MB window.
534 scr->vaddr = vmap(npaddr, nsize);
536 error("cannot allocate vga frame buffer");
537 scr->vaddr = (char*)scr->vaddr+x;
540 /* let mtrr harmlessly fail on old CPUs, e.g., P54C */
542 mtrr(npaddr, nsize, "wc");
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 */
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 */
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.
580 memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
581 flushmemscreen(swrect);
585 swcursoravoid(Rectangle r)
587 if(swvisible && rectXrect(r, swrect))
598 if(swback == nil || swimg1 == nil || swmask1 == nil)
600 assert(!canqlock(&drawlock));
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);
611 * Need to lock drawlock for ourselves.
617 if(canqlock(&drawlock)){
627 if(canqlock(&drawlock)){
634 swload(VGAscr*, Cursor *curs)
639 if(!swimg || !swmask || !swimg1 || !swmask1)
642 * Build cursor image and mask.
643 * Image is just the usual cursor image
644 * but mask is a transparent alpha mask.
646 * The 16x16x8 memimages do not have
647 * padding at the end of their scan lines.
649 ip = byteaddr(swimg, ZP);
650 mp = byteaddr(swmask, ZP);
654 for(j=0x80; j; j>>=1){
655 *ip++ = set&j ? 0x00 : 0xFF;
656 *mp++ = (clr|set)&j ? 0xFF : 0x00;
659 swoffset = curs->offset;
661 memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
662 memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
666 swmove(VGAscr*, Point p)
668 swpt = addpt(p, swoffset);
679 if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
684 if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
685 if(canqlock(&drawlock)){
696 static int init, warned;
702 addclock0link(swcursorclock, 10);
705 if(scr==nil || scr->gscreen==nil)
708 if(scr->dev == nil || scr->dev->linear == nil){
710 print("cannot use software cursor on non-linear vga screen\n");
717 freememimage(swback);
718 freememimage(swmask);
719 freememimage(swmask1);
721 freememimage(swimg1);
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");
734 memfillcolor(swmask, DOpaque);
735 memfillcolor(swmask1, DOpaque);
736 memfillcolor(swimg, DBlack);
737 memfillcolor(swimg1, DBlack);