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,
};