git: 9front

Download patch

ref: 517bee76dd1bec0afaefe4d01e63ec2baaf596fa
parent: 360e5ebe0e8c0712266d7354deca091fbf3d9acc
author: ftrvxmtrx <ftrvxmtrx@gmail.com>
date: Fri Dec 26 10:40:06 EST 2014

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.

--- a/sys/man/3/vga
+++ b/sys/man/3/vga
@@ -198,6 +198,17 @@
 .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
--- a/sys/src/9/pc/devvga.c
+++ b/sys/src/9/pc/devvga.c
@@ -48,6 +48,7 @@
 	CMunblank,
 	CMsoftscreen,
 	CMpcidev,
+	CMscaling,
 };
 
 static Cmdtab vgactlmsg[] = {
@@ -67,6 +68,7 @@
 	CMunblank,	"unblank",	1,
 	CMsoftscreen,	"softscreen",	2,
 	CMpcidev,	"pcidev",	2,
+	CMscaling,	"scaling",	2,
 };
 
 static void
@@ -303,6 +305,19 @@
 				scr->pci = p;
 		} else
 			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:
--- a/sys/src/9/pc/screen.h
+++ b/sys/src/9/pc/screen.h
@@ -49,6 +49,15 @@
 	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 @@
 	void	(*ovlctl)(VGAscr*, Chan*, void*, int);
 	int	(*ovlwrite)(VGAscr*, void*, int, vlong);
 	void (*flush)(VGAscr*, Rectangle);
+	void	(*scaling)(VGAscr*, int);
 };
 
 struct VGAcur {
--- a/sys/src/9/pc/vgavesa.c
+++ b/sys/src/9/pc/vgavesa.c
@@ -23,6 +23,7 @@
 	Cdisable = 0,
 	Cenable,
 	Cblank,
+	Cscaling,
 
 	RealModeBuf = 0x9000,
 };
@@ -32,6 +33,7 @@
 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 @@
 			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
@@ -253,6 +261,21 @@
 }
 
 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)
 {
 	scr->blank = vesablank;
@@ -262,7 +285,12 @@
 	"vesa",
 	vesaenable,
 	vesadisable,
-	0,
+	nil,
 	vesalinear,
 	vesadrawinit,
+	nil,
+	nil,
+	nil,
+	nil,
+	vesascaling,
 };
--