diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/g80_display.c | 65 | ||||
-rw-r--r-- | src/g80_display.h | 7 | ||||
-rw-r--r-- | src/g80_sor.c | 63 |
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 |