vga, vesa: scaling modes

At least on some NVIDIA cards the default scaling mode makes
black borders visible on all sides, even on native resolution.
This patch adds a generic "scaling MODE" command to vgactl
and adds support for it on VESA through NVIDIA VBE OEM extension.
It hasn't been tested on any other video cards, but shouldn't
break anything as the scaling mode is only set on write to vgactl.
This commit is contained in:
ftrvxmtrx 2014-12-26 15:40:06 +01:00
parent 7f5f69ebb5
commit 2cc7c72f8e
4 changed files with 70 additions and 6 deletions

View file

@ -198,6 +198,17 @@ enable or disable the use of DPMS blanking
.B blank
above).
.TP
.BI scaling " mode"
Set the GPU scaling
.I mode
to
.BR off ,
.B full
or
.B aspect
to either disable scaling, scale to full screen, or
to scale while preserving aspect ratio.
.TP
.BI linear " size align"
Use a linear screen aperture of size
.I size

View file

@ -48,6 +48,7 @@ enum {
CMunblank,
CMsoftscreen,
CMpcidev,
CMscaling,
};
static Cmdtab vgactlmsg[] = {
@ -67,6 +68,7 @@ static Cmdtab vgactlmsg[] = {
CMunblank, "unblank", 1,
CMsoftscreen, "softscreen", 2,
CMpcidev, "pcidev", 2,
CMscaling, "scaling", 2,
};
static void
@ -305,6 +307,19 @@ vgactl(Cmdbuf *cb)
error(Ebadarg);
return;
case CMscaling:
if(scr != nil && scr->dev != nil){
if(scr->dev->scaling == nil)
error("scaling not supported");
else if(strcmp(cb->f[1], "aspect") == 0)
scr->dev->scaling(scr, Saspect);
else if(strcmp(cb->f[1], "full") == 0)
scr->dev->scaling(scr, Sfull);
else if(strcmp(cb->f[1], "off") == 0)
scr->dev->scaling(scr, Soff);
}
return;
case CMtype:
for(i = 0; vgadev[i]; i++){
if(strcmp(cb->f[1], vgadev[i]->name))

View file

@ -49,6 +49,15 @@ enum {
Pwhite = 0xFF,
};
/*
* Scaling modes.
*/
enum {
Soff,
Sfull,
Saspect,
};
#define VGAMEM() 0xA0000
#define vgai(port) inb(port)
#define vgao(port, data) outb(port, data)
@ -74,6 +83,7 @@ struct VGAdev {
void (*ovlctl)(VGAscr*, Chan*, void*, int);
int (*ovlwrite)(VGAscr*, void*, int, vlong);
void (*flush)(VGAscr*, Rectangle);
void (*scaling)(VGAscr*, int);
};
struct VGAcur {

View file

@ -23,6 +23,7 @@ enum {
Cdisable = 0,
Cenable,
Cblank,
Cscaling,
RealModeBuf = 0x9000,
};
@ -32,6 +33,7 @@ static Chan *creg, *cmem;
static QLock vesaq;
static Rendez vesar;
static int vesactl;
static int scaling;
#define WORD(p) ((p)[0] | ((p)[1]<<8))
#define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
@ -183,11 +185,17 @@ vesaproc(void*)
sleep(&vesar, gotctl, &ctl);
ctl = vesactl;
vbesetup(&u, 0x4f10);
if(ctl == Cblank)
u.bx = 0x0101;
else
u.bx = 0x0001;
if(ctl == Cscaling){
vbesetup(&u, 0x4f14);
u.bx = 0x102;
u.cx = scaling;
}else{
vbesetup(&u, 0x4f10);
if(ctl == Cblank)
u.bx = 0x0101;
else
u.bx = 0x0001;
}
/*
* dont wait forever here. some BIOS get stuck
@ -252,6 +260,21 @@ vesablank(VGAscr *, int blank)
}
}
static void
vesascaling(VGAscr *, int mode)
{
if(vesactl != Cdisable){
vesactl = Cscaling;
if(mode == Soff)
scaling = 1;
else if(mode == Saspect)
scaling = 3;
else if(mode == Sfull)
scaling = 0;
wakeup(&vesar);
}
}
static void
vesadrawinit(VGAscr *scr)
{
@ -262,7 +285,12 @@ VGAdev vgavesadev = {
"vesa",
vesaenable,
vesadisable,
0,
nil,
vesalinear,
vesadrawinit,
nil,
nil,
nil,
nil,
vesascaling,
};