123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "ureg.h"
- #include "../port/error.h"
- #define Image IMAGE
- #include <draw.h>
- #include <memdraw.h>
- #include <cursor.h>
- #include "screen.h"
- #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
- Point ZP = {0, 0};
- Rectangle physgscreenr;
- Memdata gscreendata;
- Memimage *gscreen;
- VGAscr vgascreen[1];
- Cursor arrow = {
- { -1, -1 },
- { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
- 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
- 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
- 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
- },
- { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
- 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
- 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
- 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
- },
- };
- int didswcursorinit;
- static void *softscreen;
- int
- screensize(int x, int y, int z, uint32_t chan)
- {
- Proc *up = externup();
- VGAscr *scr;
- void *oldsoft;
- lock(&vgascreenlock);
- if(waserror()){
- unlock(&vgascreenlock);
- nexterror();
- }
- memimageinit();
- scr = &vgascreen[0];
- oldsoft = softscreen;
- if(scr->paddr == 0){
- int width = (x*z)/BI2WD;
- void *p;
- p = malloc(width*BY2WD*y);
- if(p == nil)
- error("no memory for vga soft screen");
- gscreendata.bdata = softscreen = p;
- if(scr->dev && scr->dev->page){
- scr->vaddr = KADDR(VGAMEM());
- scr->apsize = 1<<16;
- }
- scr->useflush = 1;
- }
- else{
- gscreendata.bdata = scr->vaddr;
- scr->useflush = scr->dev && scr->dev->flush;
- }
- scr->gscreen = nil;
- if(gscreen)
- freememimage(gscreen);
- gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);
- if(gscreen == nil)
- error("no memory for vga memimage");
- vgaimageinit(chan);
- scr->palettedepth = 6; /* default */
- scr->gscreendata = &gscreendata;
- scr->memdefont = getmemdefont();
- scr->gscreen = gscreen;
- physgscreenr = gscreen->r;
- unlock(&vgascreenlock);
- poperror();
- if(oldsoft)
- free(oldsoft);
- memimagedraw(gscreen, gscreen->r, memblack, ZP, nil, ZP, S);
- flushmemscreen(gscreen->r);
- if(didswcursorinit)
- swcursorinit();
- drawcmap();
- return 0;
- }
- int
- screenaperture(int size, int align)
- {
- VGAscr *scr;
- scr = &vgascreen[0];
- if(scr->paddr) /* set up during enable */
- return 0;
- if(size == 0)
- return 0;
- if(scr->dev && scr->dev->linear){
- scr->dev->linear(scr, size, align);
- return 0;
- }
- /*
- * Need to allocate some physical address space.
- * The driver will tell the card to use it.
- */
- size = ROUNDUP(sizeof(size), 4*KiB);
- scr->paddr = (uint64_t)malloc(size);
- if(scr->paddr == 0)
- return -1;
- scr->vaddr = vmap(scr->paddr, size);
- if(scr->vaddr == nil)
- return -1;
- scr->apsize = size;
- return 0;
- }
- unsigned char*
- attachscreen(Rectangle* r, uint32_t* chan, int* d, int* width, int *softscreen)
- {
- VGAscr *scr;
- scr = &vgascreen[0];
- if(scr->gscreen == nil || scr->gscreendata == nil)
- return nil;
- *r = scr->gscreen->clipr;
- *chan = scr->gscreen->chan;
- *d = scr->gscreen->depth;
- *width = scr->gscreen->width;
- *softscreen = scr->useflush;
- return scr->gscreendata->bdata;
- }
- /*
- * It would be fair to say that this doesn't work for >8-bit screens.
- */
- void
- flushmemscreen(Rectangle r)
- {
- VGAscr *scr;
- unsigned char *sp, *disp, *sdisp, *edisp;
- int y, len, incs, off, page;
- scr = &vgascreen[0];
- if(scr->dev && scr->dev->flush){
- scr->dev->flush(scr, r);
- return;
- }
- if(scr->gscreen == nil || scr->useflush == 0)
- return;
- if(scr->dev == nil || scr->dev->page == nil)
- return;
- if(rectclip(&r, scr->gscreen->r) == 0)
- return;
- incs = scr->gscreen->width * BY2WD;
- switch(scr->gscreen->depth){
- default:
- len = 0;
- panic("flushmemscreen: depth\n");
- break;
- case 8:
- len = Dx(r);
- break;
- }
- if(len < 1)
- return;
- off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
- page = off/scr->apsize;
- off %= scr->apsize;
- disp = scr->vaddr;
- sdisp = disp+off;
- edisp = disp+scr->apsize;
- off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
- sp = scr->gscreendata->bdata + off;
- scr->dev->page(scr, page);
- for(y = r.min.y; y < r.max.y; y++) {
- if(sdisp + incs < edisp) {
- memmove(sdisp, sp, len);
- sp += incs;
- sdisp += incs;
- }
- else {
- off = edisp - sdisp;
- page++;
- if(off <= len){
- if(off > 0)
- memmove(sdisp, sp, off);
- scr->dev->page(scr, page);
- if(len - off > 0)
- memmove(disp, sp+off, len - off);
- }
- else {
- memmove(sdisp, sp, len);
- scr->dev->page(scr, page);
- }
- sp += incs;
- sdisp += incs - scr->apsize;
- }
- }
- }
- void
- getcolor(uint32_t p, uint32_t* pr, uint32_t* pg, uint32_t* pb)
- {
- VGAscr *scr;
- uint32_t x;
- scr = &vgascreen[0];
- if(scr->gscreen == nil)
- return;
- switch(scr->gscreen->depth){
- default:
- x = 0x0F;
- break;
- case 8:
- x = 0xFF;
- break;
- }
- p &= x;
- lock(&cursor.l);
- *pr = scr->colormap[p][0];
- *pg = scr->colormap[p][1];
- *pb = scr->colormap[p][2];
- unlock(&cursor.l);
- }
- int
- setpalette(uint32_t p, uint32_t r, uint32_t g, uint32_t b)
- {
- VGAscr *scr;
- int d;
- scr = &vgascreen[0];
- d = scr->palettedepth;
- lock(&cursor.l);
- scr->colormap[p][0] = r;
- scr->colormap[p][1] = g;
- scr->colormap[p][2] = b;
- vgao(PaddrW, p);
- vgao(Pdata, r>>(32-d));
- vgao(Pdata, g>>(32-d));
- vgao(Pdata, b>>(32-d));
- unlock(&cursor.l);
- return ~0;
- }
- /*
- * On some video cards (e.g. Mach64), the palette is used as the
- * DAC registers for >8-bit modes. We don't want to set them when the user
- * is trying to set a colormap and the card is in one of these modes.
- */
- int
- setcolor(uint32_t p, uint32_t r, uint32_t g, uint32_t b)
- {
- VGAscr *scr;
- int x;
- scr = &vgascreen[0];
- if(scr->gscreen == nil)
- return 0;
- switch(scr->gscreen->depth){
- case 1:
- case 2:
- case 4:
- x = 0x0F;
- break;
- case 8:
- x = 0xFF;
- break;
- default:
- return 0;
- }
- p &= x;
- return setpalette(p, r, g, b);
- }
- int
- cursoron(int dolock)
- {
- VGAscr *scr;
- int v;
- scr = &vgascreen[0];
- if(scr->cur == nil || scr->cur->move == nil)
- return 0;
- if(dolock)
- lock(&cursor.l);
- v = scr->cur->move(scr, mousexy());
- if(dolock)
- unlock(&cursor.l);
- return v;
- }
- void
- cursoroff(int i)
- {
- }
- void
- setcursor(Cursor* curs)
- {
- VGAscr *scr;
- scr = &vgascreen[0];
- if(scr->cur == nil || scr->cur->load == nil)
- return;
- scr->cur->load(scr, curs);
- }
- int hwaccel = 1;
- int hwblank = 0; /* turned on by drivers that are known good */
- int panning = 0;
- int
- hwdraw(Memdrawparam *par)
- {
- VGAscr *scr;
- Memimage *dst, *src, *mask;
- int m;
- if(hwaccel == 0)
- return 0;
- scr = &vgascreen[0];
- if((dst=par->dst) == nil || dst->data == nil)
- return 0;
- if((src=par->src) == nil || src->data == nil)
- return 0;
- if((mask=par->mask) == nil || mask->data == nil)
- return 0;
- if(scr->cur == &swcursor){
- /*
- * always calling swcursorhide here doesn't cure
- * leaving cursor tracks nor failing to refresh menus
- * with the latest libmemdraw/draw.c.
- */
- if(dst->data->bdata == gscreendata.bdata)
- swcursoravoid(par->r);
- if(src->data->bdata == gscreendata.bdata)
- swcursoravoid(par->sr);
- if(mask->data->bdata == gscreendata.bdata)
- swcursoravoid(par->mr);
- }
-
- if(dst->data->bdata != gscreendata.bdata)
- return 0;
- if(scr->fill==nil && scr->scroll==nil)
- return 0;
- /*
- * If we have an opaque mask and source is one opaque
- * pixel we can convert to the destination format and just
- * replicate with memset.
- */
- m = Simplesrc|Simplemask|Fullmask;
- if(scr->fill
- && (par->state&m)==m
- && ((par->srgba&0xFF) == 0xFF)
- && (par->op&S) == S)
- return scr->fill(scr, par->r, par->sdval);
- /*
- * If no source alpha, an opaque mask, we can just copy the
- * source onto the destination. If the channels are the same and
- * the source is not replicated, memmove suffices.
- */
- m = Simplemask|Fullmask;
- if(scr->scroll
- && src->data->bdata==dst->data->bdata
- && !(src->flags&Falpha)
- && (par->state&m)==m
- && (par->op&S) == S)
- return scr->scroll(scr, par->r, par->sr);
- return 0;
- }
- void
- blankscreen(int blank)
- {
- VGAscr *scr;
- scr = &vgascreen[0];
- if(hwblank){
- if(scr->blank)
- scr->blank(scr, blank);
- else
- vgablank(scr, blank);
- }
- }
- void
- vgalinearpciid(VGAscr *scr, int vid, int did)
- {
- Pcidev *p;
- p = nil;
- while((p = pcimatch(p, vid, 0)) != nil){
- if(p->ccrb != 3) /* video card */
- continue;
- if(did != 0 && p->did != did)
- continue;
- break;
- }
- if(p == nil)
- error("pci video card not found");
- scr->pci = p;
- vgalinearpci(scr);
- }
- void
- vgalinearpci(VGAscr *scr)
- {
- uint32_t paddr;
- int i, size, best;
- Pcidev *p;
-
- p = scr->pci;
- if(p == nil)
- return;
- /*
- * Scan for largest memory region on card.
- * Some S3 cards (e.g. Savage) have enormous
- * mmio regions (but even larger frame buffers).
- * Some 3dfx cards (e.g., Voodoo3) have mmio
- * buffers the same size as the frame buffer,
- * but only the frame buffer is marked as
- * prefetchable (bar&8). If a card doesn't fit
- * into these heuristics, its driver will have to
- * call vgalinearaddr directly.
- */
- best = -1;
- for(i=0; i<nelem(p->mem); i++){
- if(p->mem[i].bar&1) /* not memory */
- continue;
- if(p->mem[i].size < 640*480) /* not big enough */
- continue;
- if(best==-1
- || p->mem[i].size > p->mem[best].size
- || (p->mem[i].size == p->mem[best].size
- && (p->mem[i].bar&8)
- && !(p->mem[best].bar&8)))
- best = i;
- }
- if(best >= 0){
- paddr = p->mem[best].bar & ~0x0F;
- size = p->mem[best].size;
- vgalinearaddr(scr, paddr, size);
- return;
- }
- error("no video memory found on pci card");
- }
- void
- vgalinearaddr(VGAscr *scr, uint32_t paddr, int size)
- {
- int x, nsize;
- uint32_t npaddr;
- /*
- * new approach. instead of trying to resize this
- * later, let's assume that we can just allocate the
- * entire window to start with.
- */
- if(scr->paddr == paddr && size <= scr->apsize)
- return;
- if(scr->paddr){
- /*
- * could call vunmap and vmap,
- * but worried about dangling pointers in devdraw
- */
- error("cannot grow vga frame buffer");
- }
-
- /* round to page boundary, just in case */
- x = paddr&(4*KiB-1);
- npaddr = paddr-x;
- nsize = ROUNDUP(size+x, 4*KiB);
- /*
- * Don't bother trying to map more than 4000x4000x32 = 64MB.
- * We only have a 256MB window.
- */
- if(nsize > 64*MB)
- nsize = 64*MB;
- scr->vaddr = vmap(npaddr, nsize);
- if(scr->vaddr == 0)
- error("cannot allocate vga frame buffer");
- scr->vaddr = (char*)scr->vaddr+x;
- scr->paddr = paddr;
- scr->apsize = nsize;
- }
- /*
- * Software cursor.
- */
- int swvisible; /* is the cursor visible? */
- int swenabled; /* is the cursor supposed to be on the screen? */
- Memimage* swback; /* screen under cursor */
- Memimage* swimg; /* cursor image */
- Memimage* swmask; /* cursor mask */
- Memimage* swimg1;
- Memimage* swmask1;
- Point swoffset;
- Rectangle swrect; /* screen rectangle in swback */
- Point swpt; /* desired cursor location */
- Point swvispt; /* actual cursor location */
- int swvers; /* incremented each time cursor image changes */
- int swvisvers; /* the version on the screen */
- /*
- * called with drawlock locked for us, most of the time.
- * kernel prints at inopportune times might mean we don't
- * hold the lock, but memimagedraw is now reentrant so
- * that should be okay: worst case we get cursor droppings.
- */
- void
- swcursorhide(void)
- {
- if(swvisible == 0)
- return;
- if(swback == nil)
- return;
- swvisible = 0;
- memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
- flushmemscreen(swrect);
- }
- void
- swcursoravoid(Rectangle r)
- {
- if(swvisible && rectXrect(r, swrect))
- swcursorhide();
- }
- void
- swcursordraw(void)
- {
- if(swvisible)
- return;
- if(swenabled == 0)
- return;
- if(swback == nil || swimg1 == nil || swmask1 == nil)
- return;
- assert(!canqlock(&drawlock));
- swvispt = swpt;
- swvisvers = swvers;
- swrect = rectaddpt(Rect(0,0,16,16), swvispt);
- memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
- memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
- flushmemscreen(swrect);
- swvisible = 1;
- }
- /*
- * Need to lock drawlock for ourselves.
- */
- void
- swenable(VGAscr *v)
- {
- swenabled = 1;
- if(canqlock(&drawlock)){
- swcursordraw();
- qunlock(&drawlock);
- }
- }
- void
- swdisable(VGAscr *v)
- {
- swenabled = 0;
- if(canqlock(&drawlock)){
- swcursorhide();
- qunlock(&drawlock);
- }
- }
- void
- swload(VGAscr *v, Cursor *curs)
- {
- unsigned char *ip, *mp;
- int i, j, set, clr;
- if(!swimg || !swmask || !swimg1 || !swmask1)
- return;
- /*
- * Build cursor image and mask.
- * Image is just the usual cursor image
- * but mask is a transparent alpha mask.
- *
- * The 16x16x8 memimages do not have
- * padding at the end of their scan lines.
- */
- ip = byteaddr(swimg, ZP);
- mp = byteaddr(swmask, ZP);
- for(i=0; i<32; i++){
- set = curs->set[i];
- clr = curs->clr[i];
- for(j=0x80; j; j>>=1){
- *ip++ = set&j ? 0x00 : 0xFF;
- *mp++ = (clr|set)&j ? 0xFF : 0x00;
- }
- }
- swoffset = curs->offset;
- swvers++;
- memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
- memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
- }
- int
- swmove(VGAscr *v, Point p)
- {
- swpt = addpt(p, swoffset);
- return 0;
- }
- void
- swcursorclock(void)
- {
- int x;
- if(!swenabled)
- return;
- if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
- return;
- x = splhi();
- if(swenabled)
- if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
- if(canqlock(&drawlock)){
- swcursorhide();
- swcursordraw();
- qunlock(&drawlock);
- }
- splx(x);
- }
- void
- swcursorinit(void)
- {
- static int init, warned;
- VGAscr *scr;
- didswcursorinit = 1;
- scr = &vgascreen[0];
- if(scr==nil || scr->gscreen==nil)
- return;
- if(scr->dev == nil || scr->dev->linear == nil){
- if(!warned){
- print("cannot use software cursor on non-linear vga screen\n");
- warned = 1;
- }
- return;
- }
- if(swback){
- freememimage(swback);
- freememimage(swmask);
- freememimage(swmask1);
- freememimage(swimg);
- freememimage(swimg1);
- }
- swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
- swmask = allocmemimage(Rect(0,0,16,16), GREY8);
- swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
- swimg = allocmemimage(Rect(0,0,16,16), GREY8);
- swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
- if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
- print("software cursor: allocmemimage fails");
- return;
- }
- memfillcolor(swmask, DOpaque);
- memfillcolor(swmask1, DOpaque);
- memfillcolor(swimg, DBlack);
- memfillcolor(swimg1, DBlack);
- if(!init){
- init = 1;
- addclock0link(swcursorclock, 10);
- }
- }
- VGAcur swcursor =
- {
- "soft",
- swenable,
- swdisable,
- swload,
- swmove,
- };
- // A bit hokey but it saves dumbness in the build tool and other code.
- VGAcur vgavesacur =
- {
- "vesa",
- swenable,
- swdisable,
- swload,
- swmove,
- };
|