summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2007-07-13 13:17:52 -0700
committerAaron Plattner <aaron@weasel.nvidia.com>2007-07-13 13:19:15 -0700
commitf0ebb42ee94eac4b294d12d02f4406a444b347ff (patch)
treebb2dadeb8583dc2630767e743a1c777c129b716a /src
parentec78618d685759a39d386e9929661037b167fe68 (diff)
G80: Add an LVDS flat panel scaling property.
This property controls how non-native resolutions are scaled to the native resolution. Valid values are: * center: 1:1 pixel ratio with black borders to center the image. * fill: Scale image to the native resolution. * aspect: Scale image to fit the screen, adding black bars to preserve square pixels. Defaults to "aspect". Change with "xrandr --output LVDS --set scale <foo>".
Diffstat (limited to 'src')
-rw-r--r--src/g80_display.c65
-rw-r--r--src/g80_display.h7
-rw-r--r--src/g80_sor.c63
3 files changed, 126 insertions, 9 deletions
diff --git a/src/g80_display.c b/src/g80_display.c
index 04ae3ec..14352aa 100644
--- a/src/g80_display.c
+++ b/src/g80_display.c
@@ -42,6 +42,7 @@ typedef struct G80CrtcPrivRec {
Bool cursorVisible;
Bool skipModeFixup;
Bool dither;
+ enum G80ScaleMode scale;
} G80CrtcPrivRec, *G80CrtcPrivPtr;
static void G80CrtcShowHideCursor(xf86CrtcPtr crtc, Bool show, Bool update);
@@ -364,18 +365,11 @@ G80CrtcModeSet(xf86CrtcPtr crtc, DisplayModePtr mode,
case 24: C(0x00000870 + headOff, 0xCF00); break;
}
G80CrtcSetDither(crtc, pPriv->dither, FALSE);
- if((adjusted_mode->Flags & V_DBLSCAN) || (adjusted_mode->Flags & V_INTERLACE) ||
- adjusted_mode->CrtcHDisplay != HDisplay || adjusted_mode->CrtcVDisplay != VDisplay) {
- C(0x000008A4 + headOff, 9);
- } else {
- C(0x000008A4 + headOff, 0);
- }
+ G80CrtcSetScale(crtc, adjusted_mode, pPriv->scale, FALSE);
C(0x000008A8 + headOff, 0x40000);
C(0x000008C0 + headOff, y << 16 | x);
C(0x000008C8 + headOff, VDisplay << 16 | HDisplay);
C(0x000008D4 + headOff, 0);
- C(0x000008D8 + headOff, adjusted_mode->CrtcVDisplay << 16 | adjusted_mode->CrtcHDisplay);
- C(0x000008DC + headOff, adjusted_mode->CrtcVDisplay << 16 | adjusted_mode->CrtcHDisplay);
G80CrtcBlankScreen(crtc, FALSE);
}
@@ -493,6 +487,60 @@ G80CrtcSetDither(xf86CrtcPtr crtc, Bool dither, Bool update)
if(update) C(0x00000080, 0);
}
+static void ComputeAspectScale(DisplayModePtr mode, int *outX, int *outY)
+{
+ float scaleX, scaleY, scale;
+
+ scaleX = mode->CrtcHDisplay / (float)mode->HDisplay;
+ scaleY = mode->CrtcVDisplay / (float)mode->VDisplay;
+
+ if(scaleX > scaleY)
+ scale = scaleY;
+ else
+ scale = scaleX;
+
+ *outX = mode->HDisplay * scale;
+ *outY = mode->VDisplay * scale;
+}
+
+void G80CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode,
+ enum G80ScaleMode scale, Bool update)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ G80CrtcPrivPtr pPriv = crtc->driver_private;
+ const int headOff = 0x400 * pPriv->head;
+ int outX, outY;
+
+ pPriv->scale = scale;
+
+ switch(scale) {
+ case G80_SCALE_ASPECT:
+ ComputeAspectScale(mode, &outX, &outY);
+ break;
+
+ case G80_SCALE_FILL:
+ outX = mode->CrtcHDisplay;
+ outY = mode->CrtcVDisplay;
+ break;
+
+ case G80_SCALE_CENTER:
+ outX = mode->HDisplay;
+ outY = mode->VDisplay;
+ break;
+ }
+
+ if((mode->Flags & V_DBLSCAN) || (mode->Flags & V_INTERLACE) ||
+ mode->HDisplay != outX || mode->VDisplay != outY) {
+ C(0x000008A4 + headOff, 9);
+ } else {
+ C(0x000008A4 + headOff, 0);
+ }
+ C(0x000008D8 + headOff, outY << 16 | outX);
+ C(0x000008DC + headOff, outY << 16 | outX);
+
+ if(update) C(0x00000080, 0);
+}
+
static void
G80CrtcCommit(xf86CrtcPtr crtc)
{
@@ -552,6 +600,7 @@ G80DispCreateCrtcs(ScrnInfoPtr pScrn)
g80_crtc = xnfcalloc(sizeof(*g80_crtc), 1);
g80_crtc->head = head;
g80_crtc->dither = pNv->Dither;
+ g80_crtc->scale = G80_SCALE_ASPECT;
crtc->driver_private = g80_crtc;
}
}
diff --git a/src/g80_display.h b/src/g80_display.h
index 4ab1d55..8bd3bfb 100644
--- a/src/g80_display.h
+++ b/src/g80_display.h
@@ -1,3 +1,9 @@
+enum G80ScaleMode {
+ G80_SCALE_ASPECT,
+ G80_SCALE_FILL,
+ G80_SCALE_CENTER,
+};
+
Bool G80DispPreInit(ScrnInfoPtr);
Bool G80DispInit(ScrnInfoPtr);
void G80DispShutdown(ScrnInfoPtr);
@@ -13,5 +19,6 @@ void G80CrtcDisableCursor(xf86CrtcPtr, Bool update);
void G80CrtcSetCursorPosition(xf86CrtcPtr, int x, int y);
void G80CrtcSkipModeFixup(xf86CrtcPtr);
void G80CrtcSetDither(xf86CrtcPtr, Bool dither, Bool update);
+void G80CrtcSetScale(xf86CrtcPtr, DisplayModePtr, enum G80ScaleMode, Bool update);
void G80DispCreateCrtcs(ScrnInfoPtr pScrn);
diff --git a/src/g80_sor.c b/src/g80_sor.c
index c4c640c..8ba3425 100644
--- a/src/g80_sor.c
+++ b/src/g80_sor.c
@@ -211,6 +211,7 @@ struct property {
static struct {
struct property dither;
+ struct property scale;
} properties;
static void
@@ -219,7 +220,9 @@ G80SorCreateResources(xf86OutputPtr output)
ScrnInfoPtr pScrn = output->scrn;
G80Ptr pNv = G80PTR(pScrn);
int data, err;
+ const char *s;
+ /******** dithering ********/
properties.dither.atom = MAKE_ATOM("dither");
properties.dither.range[0] = 0;
properties.dither.range[1] = 1;
@@ -240,6 +243,26 @@ G80SorCreateResources(xf86OutputPtr output)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to set dithering property for %s: error %d\n",
output->name, err);
+
+ /******** scaling ********/
+ properties.scale.atom = MAKE_ATOM("scale");
+ err = RRConfigureOutputProperty(output->randr_output,
+ properties.scale.atom, FALSE, FALSE,
+ FALSE, 0, NULL);
+ if(err)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to configure scaling property for %s: error %d\n",
+ output->name, err);
+
+ // Set the default value
+ s = "aspect";
+ err = RRChangeOutputProperty(output->randr_output, properties.scale.atom,
+ XA_STRING, 8, PropModeReplace, strlen(s),
+ (pointer)s, FALSE, FALSE);
+ if(err)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to set scaling property for %s: error %d\n",
+ output->name, err);
}
static Bool
@@ -256,9 +279,47 @@ G80SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val)
return FALSE;
G80CrtcSetDither(output->crtc, i, TRUE);
+ return TRUE;
+ } else if(prop == properties.scale.atom) {
+ const char *s;
+ enum G80ScaleMode scale;
+ DisplayModePtr mode;
+ int i;
+ const struct {
+ const char *name;
+ enum G80ScaleMode scale;
+ } modes[] = {
+ { "aspect", G80_SCALE_ASPECT },
+ { "fill", G80_SCALE_FILL },
+ { "center", G80_SCALE_CENTER },
+ { NULL, 0 },
+ };
+
+ if(val->type != XA_STRING || val->format != 8)
+ return FALSE;
+ s = (char*)val->data;
+
+ for(i = 0; modes[i].name; i++) {
+ const char *name = modes[i].name;
+ const int len = strlen(name);
+
+ if(val->size == len && !strncmp(name, s, len)) {
+ scale = modes[i].scale;
+ break;
+ }
+ }
+ if(!modes[i].name)
+ return FALSE;
+
+ /* Need to construct an adjusted mode */
+ mode = xf86DuplicateMode(&output->crtc->mode);
+ output->funcs->mode_fixup(output, &output->crtc->mode, mode);
+ G80CrtcSetScale(output->crtc, mode, scale, TRUE);
+ xfree(mode);
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
#endif // RANDR_12_INTERFACE