summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/xfree86/common/xf86Mode.c91
-rw-r--r--hw/xfree86/ddc/ddcProperty.c23
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: