⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 screen.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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;intscreensize(int x, int y, int z, ulong chan){	VGAscr *scr;	lock(&vgascreenlock);	memimageinit();	scr = &vgascreen[0];	/*	 * BUG: need to check if any xalloc'ed memory needs to	 * be given back if aperture is set.	 */	if(scr->paddr == 0){		int width = (x*z)/BI2WD;		gscreendata.bdata = xalloc(width*BY2WD*y);		if(gscreendata.bdata == 0)			error("screensize: vga soft memory");/*		memset(gscreendata.bdata, 0x72, width*BY2WD*y);	/* not really black */		scr->useflush = 1;		scr->paddr = VGAMEM();		scr->vaddr = KADDR(scr->paddr);		scr->apsize = 1<<16;	}	else		gscreendata.bdata = scr->vaddr;	if(gscreen)		freememimage(gscreen);	scr->gscreen = nil;	gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);	vgaimageinit(chan);	if(gscreen == nil){		unlock(&vgascreenlock);		return -1;	}	if(scr->dev && scr->dev->flush)		scr->useflush = 1;	scr->palettedepth = 6;	/* default */	scr->gscreendata = &gscreendata;	scr->memdefont = getmemdefont();	scr->gscreen = gscreen;	physgscreenr = gscreen->r;	unlock(&vgascreenlock);	if(didswcursorinit)		swcursorinit();	drawcmap();	return 0;}intscreenaperture(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 = PGROUND(size);	scr->paddr = upaalloc(size, align);	if(scr->paddr == 0)		return -1;	scr->vaddr = vmap(scr->paddr, size);	if(scr->vaddr == nil)		return -1;	scr->apsize = size;	return 0;}uchar*attachscreen(Rectangle* r, ulong* 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. */voidflushmemscreen(Rectangle r){	VGAscr *scr;	uchar *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;		}	}}voidgetcolor(ulong p, ulong* pr, ulong* pg, ulong* pb){	VGAscr *scr;	ulong 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);	*pr = scr->colormap[p][0];	*pg = scr->colormap[p][1];	*pb = scr->colormap[p][2];	unlock(&cursor);}intsetpalette(ulong p, ulong r, ulong g, ulong b){	VGAscr *scr;	int d;	scr = &vgascreen[0];	d = scr->palettedepth;	lock(&cursor);	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);	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. */intsetcolor(ulong p, ulong r, ulong g, ulong 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);}intcursoron(int dolock){	VGAscr *scr;	int v;	scr = &vgascreen[0];	if(scr->cur == nil || scr->cur->move == nil)		return 0;	if(dolock)		lock(&cursor);	v = scr->cur->move(scr, mousexy());	if(dolock)		unlock(&cursor);	return v;}voidcursoroff(int){}voidsetcursor(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;inthwdraw(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){		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;	}voidblankscreen(int blank){	VGAscr *scr;	scr = &vgascreen[0];	if(hwblank){		if(scr->blank)			scr->blank(scr, blank);		else			vgablank(scr, blank);	}}voidvgalinearpciid(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);}voidvgalinearpci(VGAscr *scr){	ulong 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");}voidvgalinearaddr(VGAscr *scr, ulong paddr, int size){	int x, nsize;	ulong 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&(BY2PG-1);	npaddr = paddr-x;	nsize = PGROUND(size+x);	/*	 * 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. */voidswcursorhide(void){	if(swvisible == 0)		return;	if(swback == nil)		return;	swvisible = 0;	memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);}voidswcursoravoid(Rectangle r){	if(swvisible && rectXrect(r, swrect))		swcursorhide();}voidswcursordraw(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);	swvisible = 1;}/* * Need to lock drawlock for ourselves. */voidswenable(VGAscr*){	swenabled = 1;	if(canqlock(&drawlock)){		swcursordraw();		qunlock(&drawlock);	}}voidswdisable(VGAscr*){	swenabled = 0;	if(canqlock(&drawlock)){		swcursorhide();		qunlock(&drawlock);	}}voidswload(VGAscr*, Cursor *curs){	uchar *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);}intswmove(VGAscr*, Point p){	swpt = addpt(p, swoffset);	return 0;}voidswcursorclock(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);}voidswcursorinit(void){	static int init, warned;	VGAscr *scr;	didswcursorinit = 1;	if(!init){		init = 1;		addclock0link(swcursorclock, 10);	}	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: %r");		return;	}	memfillcolor(swmask, DOpaque);	memfillcolor(swmask1, DOpaque);	memfillcolor(swimg, DBlack);	memfillcolor(swimg1, DBlack);}VGAcur swcursor ={	"soft",	swenable,	swdisable,	swload,	swmove,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -