diff options
author | Adam Jackson <ajax@benzedrine.nwnk.net> | 2006-09-14 19:18:58 -0400 |
---|---|---|
committer | Adam Jackson <ajax@benzedrine.nwnk.net> | 2006-09-14 19:18:58 -0400 |
commit | 81ef1b6d6063c20db4963abf7b7848e235aa4ebb (patch) | |
tree | 9607fe767bebecb12d5a827192a081867db6fa7e /hw/xfree86 | |
parent | 43d9edd31e31b33b9da4a50d8ab05004881c8d5a (diff) |
Mark EDID modes as driver modes. Infer virtual size from driver modes.
This allows the server to guess an appropriate initial virtual size and
resolution. The heuristic is to select the largest driver-reported mode
that matches the monitor's physical aspect ratio. We revalidate this
estimate after mode validation, since we may have filtered away all
modes that would fill that size.
Also, the EDID preferred timing is now marked as M_T_PREFERRED as well.
Diffstat (limited to 'hw/xfree86')
-rw-r--r-- | hw/xfree86/common/xf86Mode.c | 91 | ||||
-rw-r--r-- | hw/xfree86/ddc/ddcProperty.c | 23 |
2 files changed, 105 insertions, 9 deletions
diff --git a/hw/xfree86/common/xf86Mode.c b/hw/xfree86/common/xf86Mode.c index c66a3fb74..a3ef42071 100644 --- a/hw/xfree86/common/xf86Mode.c +++ b/hw/xfree86/common/xf86Mode.c @@ -45,6 +45,7 @@ #include "globals.h" #include "xf86.h" #include "xf86Priv.h" +#include "edid.h" static void printModeRejectMessage(int index, DisplayModePtr p, int status) @@ -55,6 +56,8 @@ printModeRejectMessage(int index, DisplayModePtr p, int status) type = "built-in "; else if (p->type & M_T_DEFAULT) type = "default "; + else if (p->type & M_T_DRIVER) + type = "driver "; else type = ""; @@ -1177,6 +1180,58 @@ xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags) return MODE_OK; } +static int +inferVirtualSize(ScrnInfoPtr scrp, DisplayModePtr modes, int *vx, int *vy) +{ + float aspect = 0.0; + MonPtr mon = scrp->monitor; + int x = 0, y = 0; + DisplayModePtr mode; + + if (!mon) return 0; + + /* + * technically this triggers if _either_ is zero, which is not what EDID + * says, but if only one is zero this is best effort. also we don't + * know that all projectors are 4:3, but we certainly suspect it. + */ + if (!mon->widthmm || !mon->heightmm) + aspect = 4.0/3.0; + else + aspect = (float)mon->widthmm / (float)mon->heightmm; + + /* find the largest M_T_DRIVER mode with that aspect ratio */ + for (mode = modes; mode; mode = mode->next) { + float mode_aspect, metaspect; + if (!(mode->type & (M_T_DRIVER|M_T_USERDEF))) + continue; + mode_aspect = (float)mode->HDisplay / (float)mode->VDisplay; + metaspect = aspect / mode_aspect; + /* 5% slop or so, since we only get size in centimeters */ + if (fabs(1.0 - metaspect) < 0.05) { + if ((mode->HDisplay > x) && (mode->VDisplay > y)) { + x = mode->HDisplay; + y = mode->VDisplay; + } + } + } + + if (!x || !y) { + xf86DrvMsg(scrp->scrnIndex, X_WARNING, + "Unable to estimate virtual size\n"); + return 0; + } + + *vx = x; + *vy = y; + + xf86DrvMsg(scrp->scrnIndex, X_INFO, + "Estimated virtual size for aspect ratio %.4f is %dx%d\n", + aspect, *vx, *vy); + + return 1; +} + /* * xf86ValidateModes * @@ -1248,6 +1303,7 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, int numTimings = 0; range hsync[MAX_HSYNC]; range vrefresh[MAX_VREFRESH]; + Bool inferred_virtual = FALSE; #ifdef DEBUG ErrorF("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n", @@ -1440,6 +1496,13 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, virtX = virtualX; virtY = virtualY; scrp->virtualFrom = X_CONFIG; + } else if (!modeNames || !*modeNames) { + /* No virtual size given in the config, try to infer */ + /* XXX this doesn't take m{in,ax}Pitch into account; oh well */ + inferred_virtual = inferVirtualSize(scrp, availModes, &virtX, &virtY); + if (inferred_virtual) + linePitch = miScanLineWidth(virtX, virtY, minPitch, apertureSize, + BankFormat, pitchInc); } /* Print clock ranges and scaled clocks */ @@ -1456,7 +1519,7 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, for (p = availModes; p != NULL; p = p->next) { status = xf86InitialCheckModeForDriver(scrp, p, clockRanges, strategy, maxPitch, - virtualX, virtualY); + virtX, virtY); if (status == MODE_OK) { status = xf86CheckModeForMonitor(p, scrp->monitor); @@ -1733,6 +1796,30 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, #undef _VIRTUALX + /* + * If we estimated the virtual size above, we may have filtered away all + * the modes that maximally match that size; scan again to find out and + * fix up if so. + */ + if (inferred_virtual) { + int vx = 0, vy = 0; + for (p = scrp->modes; p; p = p->next) { + if (p->HDisplay > vx && p->VDisplay > vy) { + vx = p->HDisplay; + vy = p->VDisplay; + } + } + if (vx < virtX || vy < virtY) { + xf86DrvMsg(scrp->scrnIndex, X_WARNING, + "Shrinking virtual size estimate from %dx%d to %dx%d\n", + virtX, virtY, vx, vy); + virtX = vx; + virtY = vy; + linePitch = miScanLineWidth(vx, vy, linePitch, apertureSize, + BankFormat, pitchInc); + } + } + /* Update the ScrnInfoRec parameters */ scrp->virtualX = virtX; @@ -1955,6 +2042,8 @@ xf86PrintModes(ScrnInfoPtr scrp) prefix = "Built-in mode"; else if (p->type & M_T_DEFAULT) prefix = "Default mode"; + else if (p->type & M_T_DRIVER) + prefix = "Driver mode"; else prefix = "Mode"; if (p->type & M_T_USERDEF) diff --git a/hw/xfree86/ddc/ddcProperty.c b/hw/xfree86/ddc/ddcProperty.c index 59873fafd..a1650bc03 100644 --- a/hw/xfree86/ddc/ddcProperty.c +++ b/hw/xfree86/ddc/ddcProperty.c @@ -127,9 +127,8 @@ PrintModeline(int scrnIndex,DisplayModePtr mode) /* * TODO: * - for those with access to the VESA DMT standard; review please. - * - swap M_T_DEFAULT for M_T_EDID_... */ -#define MODEPREFIX(name) NULL, NULL, name, 0,M_T_DEFAULT +#define MODEPREFIX(name) NULL, NULL, name, 0,M_T_DRIVER #define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 DisplayModeRec DDCEstablishedModes[17] = { @@ -182,6 +181,7 @@ DDCModesFromStandardTiming(int scrnIndex, struct std_timings *timing) if (timing[i].hsize && timing[i].vsize && timing[i].refresh) { Mode = xf86CVTMode(timing[i].hsize, timing[i].vsize, timing[i].refresh, FALSE, FALSE); + Mode->type = M_T_DRIVER; Modes = xf86ModesAdd(Modes, Mode); } @@ -192,7 +192,8 @@ DDCModesFromStandardTiming(int scrnIndex, struct std_timings *timing) * */ static DisplayModePtr -DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing) +DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing, + int preferred) { DisplayModePtr Mode; @@ -205,9 +206,8 @@ DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing) /* We only do seperate sync currently */ if (timing->sync != 0x03) { - xf86DrvMsg(scrnIndex, X_INFO, "%s: Ignoring: We only handle seperate" - " sync.\n", __func__); - return NULL; + xf86DrvMsg(scrnIndex, X_INFO, "%s: %dx%d Warning: We only handle seperate" + " sync.\n", __func__, timing->h_active, timing->v_active); } Mode = xnfalloc(sizeof(DisplayModeRec)); @@ -217,7 +217,9 @@ DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing) xf86snprintf(Mode->name, 20, "%dx%d", timing->h_active, timing->v_active); - Mode->type = M_T_DEFAULT; /* get ourselves a nice type of our own */ + Mode->type = M_T_DRIVER; + if (preferred) + Mode->type |= M_T_PREFERRED; Mode->Clock = timing->clock / 1000.0; @@ -302,12 +304,15 @@ xf86DDCMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC) DisplayModePtr Modes = NULL, Mode; int i, clock; Bool have_hsync = FALSE, have_vrefresh = FALSE; + int preferred; if (!Monitor || !DDC) return; Monitor->DDC = DDC; + preferred = PREFERRED_TIMING_MODE(DDC->features.msc); + Monitor->widthmm = 10 * DDC->features.hsize; Monitor->heightmm = 10 * DDC->features.vsize; @@ -367,7 +372,9 @@ xf86DDCMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC) break; case DT: Mode = DDCModeFromDetailedTiming(scrnIndex, - &DDC->det_mon[i].section.d_timings); + &DDC->det_mon[i].section.d_timings, + preferred); + preferred = 0; Modes = xf86ModesAdd(Modes, Mode); break; case DS_STD_TIMINGS: |