shithub: riscv

Download patch

ref: b9ca8e83784b94e709e7d412eb4f87fa0a1885a8
parent: 5654f15e56087986812c557412d558482383fc8b
author: cinap_lenrek <[email protected]>
date: Wed Jul 18 06:16:00 EDT 2012

vga: softscreen

allow the shadow framebuffer (softscreen) to be used with any
vga driver, not just vesa. this removes the ugly scr->paddr = 0
hack employed by vesa driver to force softscreen and adds a
softscreen vgactl message that can switch the feature on and off
at runtime.

softscreen can greatly improve graphics performance when bus
reads are slow even tho it disables hardware acceleration.

--- a/sys/man/3/vga
+++ b/sys/man/3/vga
@@ -170,6 +170,22 @@
 The default setting is
 .BR on .
 .TP
+.BI softscreen " mode"
+Depending on whether
+.I mode
+is 
+.B on
+or
+.BR off ,
+enable or disable shadow framebuffer to reduce
+slow bus reads. Enabling
+.BI softscreen
+disables hardware acceleration. The default setting is
+.BR off
+except for the
+.BR vesa
+driver. 
+.TP
 .BI hwblank " mode"
 Depending on whether
 .I mode
--- a/sys/man/8/plan9.ini
+++ b/sys/man/8/plan9.ini
@@ -781,10 +781,6 @@
 .BR off .
 The first two specify differing levels of power saving;
 the third turns the monitor off completely.
-.SS \fL*novesashadow=\fP
-This disables the shadow framebuffer or softscreen of the VESA
-video driver. This can improve performance on some graphics
-cards.
 .SS NVRAM
 .SS \fLnvram=\fIfile\fP
 .SS \fLnvrlen=\fIlength\fP
--- a/sys/src/9/pc/devvga.c
+++ b/sys/src/9/pc/devvga.c
@@ -46,6 +46,7 @@
 	CMtextmode,
 	CMtype,
 	CMunblank,
+	CMsoftscreen,
 };
 
 static Cmdtab vgactlmsg[] = {
@@ -63,6 +64,7 @@
 	CMtextmode,	"textmode",	1,
 	CMtype,		"type",		2,
 	CMunblank,	"unblank",	1,
+	CMsoftscreen,	"softscreen",	2,
 };
 
 static void
@@ -200,6 +202,7 @@
 		len += snprint(p+len, READSTR-len, "hwblank %s\n", hwblank ? "on" : "off");
 		len += snprint(p+len, READSTR-len, "panning %s\n", panning ? "on" : "off");
 		len += snprint(p+len, READSTR-len, "addr p 0x%lux v 0x%p size 0x%ux\n", scr->paddr, scr->vaddr, scr->apsize);
+		len += snprint(p+len, READSTR-len, "softscreen %s\n", scr->softscreen ? "on" : "off");
 		USED(len);
 
 		n = readstr(offset, a, n, p);
@@ -352,6 +355,24 @@
 		scr->palettedepth = x;
 		return;
 
+	case CMsoftscreen:
+		if(strcmp(cb->f[1], "on") == 0)
+			scr->softscreen = 1;
+		else if(strcmp(cb->f[1], "off") == 0)
+			scr->softscreen = 0;
+		else
+			break;
+		if(scr->gscreen == nil)
+			return;
+		x = scr->gscreen->r.max.x;
+		y = scr->gscreen->r.max.y;
+		z = scr->gscreen->depth;
+		chan = scr->gscreen->chan;
+		cursoroff(1);
+		deletescreenimage();
+		if(screensize(x, y, z, chan))
+			error(Egreg);
+		/* no break */
 	case CMdrawinit:
 		if(scr->gscreen == nil)
 			error("drawinit: no gscreen");
@@ -358,12 +379,12 @@
 		if(scr->dev && scr->dev->drawinit)
 			scr->dev->drawinit(scr);
 		hwblank = scr->blank != nil;
-		hwaccel = scr->scroll || scr->fill;
+		hwaccel = !scr->softscreen && (scr->scroll || scr->fill);
 		vgascreenwin(scr);
 		resetscreenimage();
 		cursoron(1);
 		return;
-	
+
 	case CMlinear:
 		if(cb->nf!=2 && cb->nf!=3)
 			error(Ebadarg);
--- a/sys/src/9/pc/screen.c
+++ b/sys/src/9/pc/screen.c
@@ -67,17 +67,21 @@
 	}
 
 	if(scr->paddr == 0){
-		gscreen = allocmemimage(Rect(0,0,x,y), chan);
 		if(scr->dev && scr->dev->page){
 			scr->vaddr = KADDR(VGAMEM());
 			scr->apsize = 1<<16;
 		}
+		scr->softscreen = 1;
+	}
+	if(scr->softscreen){
+		gscreen = allocmemimage(Rect(0,0,x,y), chan);
 		scr->useflush = 1;
 	}else{
 		static Memdata md;
 
 		md.ref = 1;
-		md.bdata = scr->vaddr;
+		if((md.bdata = scr->vaddr) == 0)
+			error("framebuffer not maped");
 		gscreen = allocmemimaged(Rect(0,0,x,y), chan, &md);
 		scr->useflush = scr->dev && scr->dev->flush;
 	}
@@ -167,15 +171,12 @@
 	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;
 	uchar *sp, *disp, *sdisp, *edisp;
-	int y, len, incs, off, page;
+	int y, len, incs, off, xoff, page;
 
 	scr = &vgascreen[0];
 	if(scr->gscreen == nil || scr->useflush == 0)
@@ -184,14 +185,38 @@
 		scr->dev->flush(scr, r);
 		return;
 	}
-	if(scr->dev == nil || scr->dev->page == nil)
+	if(rectclip(&r, scr->gscreen->r) == 0)
 		return;
+	disp = scr->vaddr;
+	incs = scr->gscreen->width * BY2WD;
+	xoff = (r.min.x*scr->gscreen->depth) / 8;
+	off = r.min.y*incs + xoff;
+	sp = scr->gscreendata->bdata + scr->gscreen->zero + off;
 
-	if(rectclip(&r, scr->gscreen->r) == 0)
+	/*
+	 * Linear framebuffer but with softscreen.
+	 */
+	if(scr->paddr){
+		len = (r.max.x*scr->gscreen->depth + 7) / 8;
+		len -= xoff;
+		sdisp = disp + off;
+		edisp = sdisp + Dy(r)*incs;
+		while(sdisp < edisp){
+			memmove(sdisp, sp, len);
+			sdisp += incs;
+			sp += incs;
+		}
 		return;
+	}
 
-	incs = scr->gscreen->width * BY2WD;
 
+	/*
+	 * Paged access thru 64K window.
+	 * It would be fair to say that this doesn't work for >8-bit screens.
+	 */
+	if(scr->dev == nil || scr->dev->page == nil)
+		return;
+
 	switch(scr->gscreen->depth){
 	default:
 		len = 0;
@@ -202,18 +227,11 @@
 	}
 	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) {
@@ -740,4 +758,3 @@
 	swload,
 	swmove,
 };
-
--- a/sys/src/9/pc/screen.h
+++ b/sys/src/9/pc/screen.h
@@ -120,6 +120,7 @@
 	ulong	id;	/* internal identifier for driver use */
 	int isblank;
 	int overlayinit;
+	int softscreen;
 };
 
 extern VGAscr vgascreen[];
--- a/sys/src/9/pc/vganvidia.c
+++ b/sys/src/9/pc/vganvidia.c
@@ -69,12 +69,12 @@
 
 #define SKIPS 8
 
-struct {
+static struct {
 	ulong	*dmabase;
-	int		dmacurrent;
-	int		dmaput;
-	int		dmafree;
-	int		dmamax;
+	int	dmacurrent;
+	int	dmaput;
+	int	dmafree;
+	int	dmamax;
 } nv;
 
 static Pcidev*
@@ -91,11 +91,6 @@
 }
 
 static void
-nvidialinear(VGAscr*, int, int)
-{
-}
-
-static void
 nvidiaenable(VGAscr* scr)
 {
 	Pcidev *p;
@@ -114,11 +109,9 @@
 	if(scr->mmio == nil)
 		return;
 	addvgaseg("nvidiammio", p->mem[0].bar&~0x0F, p->mem[0].size);
-
 	vgalinearpci(scr);
 	if(scr->apsize)
 		addvgaseg("nvidiascreen", scr->paddr, scr->apsize);
-
 	/* find video memory size */
 	switch (scr->id & 0x0ff0) {
 	case 0x0020:
@@ -156,6 +149,11 @@
 }
 
 static void
+nvidialinear(VGAscr *, int, int)
+{
+}
+
+static void
 nvidiacurdisable(VGAscr* scr)
 {
 	if(scr->mmio == 0)
@@ -223,8 +221,6 @@
 
 	scr->offset = curs->offset;
 	vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01);
-
-	return;
 }
 
 static int
@@ -355,12 +351,15 @@
 		iprint("idle stat %lud scrio %#p scr %#p pc %#p\n", *pgraph, scr->mmio, scr, getcallerpc(&scr));
 }
 
-static void
+static int
 nvresetgraphics(VGAscr *scr)
 {
 	ulong	surfaceFormat, patternFormat, rectFormat, lineFormat;
-	int		pitch, i;
+	int	pitch, i;
 
+	if(scr->paddr == 0)
+		return -1;
+
 	pitch = scr->gscreen->width*BY2WD;
 
 	/*
@@ -373,10 +372,8 @@
 		else{
 			nv.dmabase = (void*)vmap(scr->paddr + scr->storage - 128*1024, 128*1024);
 			if(nv.dmabase == 0){
-				hwaccel = 0;
-				hwblank = 0;
 				print("vmap nvidia dma failed\n");
-				return;
+				return -1;
 			}
 		}
 	}
@@ -455,6 +452,8 @@
 
 	nvdmakickoff(scr);
 	waitforidle(scr);
+
+	return 0;
 }
 
 
@@ -513,9 +512,9 @@
 static void
 nvidiadrawinit(VGAscr *scr)
 {
-	nvresetgraphics(scr);
 	scr->blank = nvidiablank;
-	hwblank = 1;
+	if(nvresetgraphics(scr) < 0)
+		return;
 	scr->fill = nvidiahwfill;
 	scr->scroll = nvidiahwscroll;
 }
--- a/sys/src/9/pc/vgavesa.c
+++ b/sys/src/9/pc/vgavesa.c
@@ -24,7 +24,6 @@
 	RealModeBuf = 0x9000,
 };
 
-static void *hardscreen;
 static uchar modebuf[0x1000];
 static Chan *creg, *cmem;
 static QLock vesaq;
@@ -108,12 +107,6 @@
 	Pcidev *pci;
 	uchar *p;
 
-	if(hardscreen) {
-		scr->vaddr = hardscreen;
-		scr->paddr = scr->apsize = 0;
-		return;
-	}
-
 	vbecheck();
 	mode = vbegetmode();
 	/*
@@ -163,38 +156,8 @@
 	vgalinearaddr(scr, paddr, size);
 	if(scr->apsize)
 		addvgaseg("vesascreen", scr->paddr, scr->apsize);
-	if(getconf("*novesashadow"))
-		return;
-	hardscreen = scr->vaddr;
-	scr->paddr = scr->apsize = 0;
-}
 
-static void
-vesaflush(VGAscr *scr, Rectangle r)
-{
-	int t, w, wid, off;
-	ulong *hp, *sp, *esp;
-
-	if(hardscreen == nil)
-		return;
-	if(rectclip(&r, scr->gscreen->r) == 0)
-		return;
-	sp = (ulong*)(scr->gscreendata->bdata + scr->gscreen->zero);
-	t = (r.max.x * scr->gscreen->depth + 2*BI2WD-1) / BI2WD;
-	w = (r.min.x * scr->gscreen->depth) / BI2WD;
-	w = (t - w) * BY2WD;
-	wid = scr->gscreen->width;
-	off = r.min.y * wid + (r.min.x * scr->gscreen->depth) / BI2WD;
-
-	hp = hardscreen;
-	hp += off;
-	sp += off;
-	esp = sp + Dy(r) * wid;
-	while(sp < esp){
-		memmove(hp, sp, w);
-		hp += wid;
-		sp += wid;
-	}
+	scr->softscreen = 1;
 }
 
 static int
@@ -285,8 +248,4 @@
 	0,
 	vesalinear,
 	vesadrawinit,
-	0,
-	0,
-	0,
-	vesaflush,
 };