summaryrefslogtreecommitdiff
path: root/hw/xfree86/common/xf86Mode.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/xfree86/common/xf86Mode.c')
-rw-r--r--hw/xfree86/common/xf86Mode.c357
1 files changed, 267 insertions, 90 deletions
diff --git a/hw/xfree86/common/xf86Mode.c b/hw/xfree86/common/xf86Mode.c
index ba73921e4..fd2ff4a22 100644
--- a/hw/xfree86/common/xf86Mode.c
+++ b/hw/xfree86/common/xf86Mode.c
@@ -1,10 +1,36 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86Mode.c,v 1.63.2.1 2003/04/08 20:51:27 tsi Exp $ */
-
+/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86Mode.c,v 1.69 2003/10/08 14:58:28 dawes Exp $ */
/*
- * Copyright (c) 1997,1998 by The XFree86 Project, Inc.
+ * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
* Authors: Dirk Hohndel <hohndel@XFree86.Org>
* David Dawes <dawes@XFree86.Org>
+ * Marc La France <tsi@XFree86.Org>
+ * ... and others
*
* This file includes helper functions for mode related things.
*/
@@ -13,6 +39,7 @@
#include "os.h"
#include "servermd.h"
#include "mibank.h"
+#include "globals.h"
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86DDC.h"
@@ -318,6 +345,25 @@ xf86HandleBuiltinMode(ScrnInfoPtr scrp,
return MODE_OK;
}
+static double
+ModeVRefresh(DisplayModePtr mode)
+{
+ double refresh = 0.0;
+
+ if (mode->VRefresh > 0.0)
+ refresh = mode->VRefresh;
+ else if (mode->HTotal > 0 && mode->VTotal > 0) {
+ refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
+ if (mode->Flags & V_INTERLACE)
+ refresh *= 2.0;
+ if (mode->Flags & V_DBLSCAN)
+ refresh /= 2.0;
+ if (mode->VScan > 1)
+ refresh /= mode->VScan;
+ }
+ return refresh;
+}
+
/*
* xf86LookupMode
*
@@ -442,17 +488,7 @@ xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep,
ModePrivFlags = cp->PrivFlags;
break;
}
- if (p->VRefresh > 0.0)
- refresh = p->VRefresh;
- else {
- refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
- if (p->Flags & V_INTERLACE)
- refresh *= 2.0;
- if (p->Flags & V_DBLSCAN)
- refresh /= 2.0;
- if (p->VScan > 1)
- refresh /= p->VScan;
- }
+ refresh = ModeVRefresh(p);
if (p->Flags & V_INTERLACE)
refresh /= INTERLACE_REFRESH_WEIGHT;
if (refresh > bestRefresh) {
@@ -491,17 +527,7 @@ xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep,
found = TRUE;
if (strategy == LOOKUP_BEST_REFRESH) {
- if (p->VRefresh > 0.0)
- refresh = p->VRefresh;
- else {
- refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
- if (p->Flags & V_INTERLACE)
- refresh *= 2.0;
- if (p->Flags & V_DBLSCAN)
- refresh /= 2.0;
- if (p->VScan > 1)
- refresh /= p->VScan;
- }
+ refresh = ModeVRefresh(p);
if (p->Flags & V_INTERLACE)
refresh /= INTERLACE_REFRESH_WEIGHT;
if (refresh > bestRefresh) {
@@ -847,7 +873,7 @@ xf86InitialCheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode,
int i, needDiv2;
/* Sanity checks */
- if (!scrp || !mode /*|| !clockRanges*/) {
+ if (!scrp || !mode || !clockRanges) {
ErrorF("xf86InitialCheckModeForDriver: "
"called with invalid parameters\n");
return MODE_ERROR;
@@ -1186,13 +1212,17 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
int linePitch = -1, virtX = 0, virtY = 0;
int newLinePitch, newVirtX, newVirtY;
int modeSize; /* in pixels */
- Bool validateAllDefaultModes;
+ Bool validateAllDefaultModes = FALSE;
Bool userModes = FALSE;
int saveType;
PixmapFormatRec *BankFormat;
ClockRangePtr cp;
ClockRangesPtr storeClockRanges;
struct monitor_ranges *mon_range = NULL;
+ double targetRefresh = 0.0;
+ int numTimings = 0;
+ range hsync[MAX_HSYNC];
+ range vrefresh[MAX_VREFRESH];
#ifdef DEBUG
ErrorF("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n",
@@ -1222,58 +1252,164 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
return -1;
}
- /* Probe monitor so that we can enforce/warn about its limits */
+ /*
+ * Probe monitor so that we can enforce/warn about its limits.
+ * If one or more DS_RANGES descriptions are present, use the parameters
+ * that they provide. Otherwise, deduce limits based on the modes that
+ * are shown as supported via standard and detailed timings.
+ *
+ * XXX The full potential of the DDC/EDID data still isn't being tapped.
+ */
if (scrp->monitor->DDC) {
MonPtr monitor = scrp->monitor;
xf86MonPtr DDC = (xf86MonPtr)(scrp->monitor->DDC);
- struct detailed_monitor_section* detMon;
- int i;
+ int i, j;
+ float hmin = 1e6, hmax = 0.0, vmin = 1e6, vmax = 0.0;
+ float h;
+ struct std_timings *t;
+ struct detailed_timings *dt;
+
+ numTimings = 0;
+ for (i = 0; i < DET_TIMINGS; i++) {
+ switch (DDC->det_mon[i].type) {
+ case DS_RANGES:
+ mon_range = &DDC->det_mon[i].section.ranges;
+ hsync[numTimings].lo = mon_range->min_h;
+ hsync[numTimings].hi = mon_range->max_h;
+ vrefresh[numTimings].lo = mon_range->min_v;
+ vrefresh[numTimings].hi = mon_range->max_v;
+ numTimings++;
+ break;
- for (i = 0; i < 4; i++) {
- detMon = &DDC->det_mon[i];
- if(detMon->type == DS_RANGES) {
- mon_range = &detMon->section.ranges;
+ case DS_STD_TIMINGS:
+ t = DDC->det_mon[i].section.std_t;
+ for (j = 0; j < 5; j++) {
+ if (t[j].hsize > 256) { /* sanity check */
+ if (t[j].refresh < vmin)
+ vmin = t[i].refresh;
+ if (t[j].refresh > vmax)
+ vmax = t[i].refresh;
+ /*
+ * For typical modes this is a reasonable estimate
+ * of the horizontal sync rate.
+ */
+ h = t[j].refresh * 1.07 * t[j].vsize / 1000.0;
+ if (h < hmin)
+ hmin = h;
+ if (h > hmax)
+ hmax = h;
+ }
+ }
+ break;
+
+ case DT:
+ dt = &DDC->det_mon[i].section.d_timings;
+ if (dt->clock > 15000000) { /* sanity check */
+ float v;
+ h = (float)dt->clock / (dt->h_active + dt->h_blanking);
+ v = h / (dt->v_active + dt->v_blanking);
+ h /= 1000.0;
+ if (dt->interlaced)
+ v /= 2.0;
+
+ if (v < vmin)
+ vmin = v;
+ if (v > vmax)
+ vmax = v;
+ if (h < hmin)
+ hmin = h;
+ if (h > hmax)
+ hmax = h;
+ }
+ break;
}
+
+ if (numTimings > MAX_HSYNC)
+ break;
}
- if (mon_range) {
+
+ if (numTimings == 0) {
+ t = DDC->timings2;
+ for (i = 0; i < STD_TIMINGS; i++) {
+ if (t[i].hsize > 256) { /* sanity check */
+ if (t[i].refresh < vmin)
+ vmin = t[i].refresh;
+ if (t[i].refresh > vmax)
+ vmax = t[i].refresh;
+ /*
+ * For typical modes this is a reasonable estimate
+ * of the horizontal sync rate.
+ */
+ h = t[i].refresh * 1.07 * t[i].vsize / 1000.0;
+ if (h < hmin)
+ hmin = h;
+ if (h > hmax)
+ hmax = h;
+ }
+ }
+
+ if (hmax > 0.0) {
+ hsync[numTimings].lo = hmin;
+ hsync[numTimings].hi = hmax;
+ vrefresh[numTimings].lo = vmin;
+ vrefresh[numTimings].hi = vmax;
+ numTimings++;
+ }
+ }
+
+ if (numTimings > 0) {
#ifdef DEBUG
- ErrorF("DDC - Max clock %d, Hsync %d-%d kHz - Vrefresh %d-%d Hz\n",
- mon_range->max_clock, mon_range->min_h, mon_range->max_h,
- mon_range->min_v, mon_range->max_v );
+ for (i = 0; i < numTimings; i++) {
+ ErrorF("DDC - Hsync %.1f-%.1f kHz - Vrefresh %.1f-%.1f Hz\n",
+ hsync[i].lo, hsync[i].hi,
+ vrefresh[i].lo, vrefresh[i].hi);
+ }
#endif
#define DDC_SYNC_TOLERANCE SYNC_TOLERANCE
if (monitor->nHsync > 0) {
for (i = 0; i < monitor->nHsync; i++) {
- if ((1.0 - DDC_SYNC_TOLERANCE) * mon_range->min_h >
- monitor->hsync[i].lo ||
- (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_h <
+ Bool good = FALSE;
+ for (j = 0; j < numTimings; j++) {
+ if ((1.0 - DDC_SYNC_TOLERANCE) * hsync[j].lo <=
+ monitor->hsync[i].lo &&
+ (1.0 + DDC_SYNC_TOLERANCE) * hsync[j].hi >=
monitor->hsync[i].hi) {
+ good = TRUE;
+ break;
+ }
+ }
+ if (!good) {
xf86DrvMsg(scrp->scrnIndex, X_WARNING,
"config file hsync range %g-%gkHz not within DDC "
- "hsync range %d-%dkHz\n",
- monitor->hsync[i].lo, monitor->hsync[i].hi,
- mon_range->min_h, mon_range->max_h);
+ "hsync ranges.\n",
+ monitor->hsync[i].lo, monitor->hsync[i].hi);
}
}
}
if (monitor->nVrefresh > 0) {
- for (i=0; i<monitor->nVrefresh; i++) {
- if ((1.0 - DDC_SYNC_TOLERANCE) * mon_range->min_v >
- monitor->vrefresh[0].lo ||
- (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_v <
+ for (i = 0; i < monitor->nVrefresh; i++) {
+ Bool good = FALSE;
+ for (j = 0; j < numTimings; j++) {
+ if ((1.0 - DDC_SYNC_TOLERANCE) * vrefresh[j].lo <=
+ monitor->vrefresh[0].lo &&
+ (1.0 + DDC_SYNC_TOLERANCE) * vrefresh[j].hi >=
monitor->vrefresh[0].hi) {
+ good = TRUE;
+ break;
+ }
+ }
+ if (!good) {
xf86DrvMsg(scrp->scrnIndex, X_WARNING,
"config file vrefresh range %g-%gHz not within DDC "
- "vrefresh range %d-%dHz\n",
- monitor->vrefresh[i].lo, monitor->vrefresh[i].hi,
- mon_range->min_v, mon_range->max_v);
+ "vrefresh ranges.\n",
+ monitor->vrefresh[i].lo, monitor->vrefresh[i].hi);
}
}
}
- } /* if (mon_range) */
+ }
}
/*
@@ -1283,58 +1419,61 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
if (strategy & LOOKUP_OPTIONAL_TOLERANCES) {
strategy &= ~LOOKUP_OPTIONAL_TOLERANCES;
} else {
+ const char *type = "";
+
if (scrp->monitor->nHsync <= 0) {
- if (mon_range) {
- scrp->monitor->hsync[0].lo = mon_range->min_h;
- scrp->monitor->hsync[0].hi = mon_range->max_h;
+ if (numTimings > 0) {
+ scrp->monitor->nHsync = numTimings;
+ for (i = 0; i < numTimings; i++) {
+ scrp->monitor->hsync[i].lo = hsync[i].lo;
+ scrp->monitor->hsync[i].hi = hsync[i].hi;
+ }
} else {
scrp->monitor->hsync[0].lo = 28;
scrp->monitor->hsync[0].hi = 33;
+ scrp->monitor->nHsync = 1;
}
- xf86DrvMsg(scrp->scrnIndex, X_WARNING,
- "%s: Using default hsync range of %.2f-%.2fkHz\n",
- scrp->monitor->id,
- scrp->monitor->hsync[0].lo, scrp->monitor->hsync[0].hi);
- scrp->monitor->nHsync = 1;
- } else {
- for (i = 0; i < scrp->monitor->nHsync; i++)
+ type = "default ";
+ }
+ for (i = 0; i < scrp->monitor->nHsync; i++) {
if (scrp->monitor->hsync[i].lo == scrp->monitor->hsync[i].hi)
xf86DrvMsg(scrp->scrnIndex, X_INFO,
- "%s: Using hsync value of %.2f kHz\n",
- scrp->monitor->id,
+ "%s: Using %shsync value of %.2f kHz\n",
+ scrp->monitor->id, type,
scrp->monitor->hsync[i].lo);
else
xf86DrvMsg(scrp->scrnIndex, X_INFO,
- "%s: Using hsync range of %.2f-%.2f kHz\n",
- scrp->monitor->id,
+ "%s: Using %shsync range of %.2f-%.2f kHz\n",
+ scrp->monitor->id, type,
scrp->monitor->hsync[i].lo,
scrp->monitor->hsync[i].hi);
}
+
+ type = "";
if (scrp->monitor->nVrefresh <= 0) {
- if (mon_range) {
- scrp->monitor->vrefresh[0].lo = mon_range->min_v;
- scrp->monitor->vrefresh[0].hi = mon_range->max_v;
+ if (numTimings > 0) {
+ scrp->monitor->nVrefresh = numTimings;
+ for (i = 0; i < numTimings; i++) {
+ scrp->monitor->vrefresh[i].lo = vrefresh[i].lo;
+ scrp->monitor->vrefresh[i].hi = vrefresh[i].hi;
+ }
} else {
scrp->monitor->vrefresh[0].lo = 43;
scrp->monitor->vrefresh[0].hi = 72;
+ scrp->monitor->nVrefresh = 1;
}
- xf86DrvMsg(scrp->scrnIndex, X_WARNING,
- "%s: using default vrefresh range of %.2f-%.2fHz\n",
- scrp->monitor->id,
- scrp->monitor->vrefresh[0].lo,
- scrp->monitor->vrefresh[0].hi);
- scrp->monitor->nVrefresh = 1;
- } else {
- for (i = 0; i < scrp->monitor->nVrefresh; i++)
+ type = "default ";
+ }
+ for (i = 0; i < scrp->monitor->nVrefresh; i++) {
if (scrp->monitor->vrefresh[i].lo == scrp->monitor->vrefresh[i].hi)
xf86DrvMsg(scrp->scrnIndex, X_INFO,
- "%s: Using vrefresh value of %.2f Hz\n",
- scrp->monitor->id,
+ "%s: Using %svrefresh value of %.2f Hz\n",
+ scrp->monitor->id, type,
scrp->monitor->vrefresh[i].lo);
else
xf86DrvMsg(scrp->scrnIndex, X_INFO,
- "%s: Using vrefresh range of %.2f-%.2f Hz\n",
- scrp->monitor->id,
+ "%s: Using %svrefresh range of %.2f-%.2f Hz\n",
+ scrp->monitor->id, type,
scrp->monitor->vrefresh[i].lo,
scrp->monitor->vrefresh[i].hi);
}
@@ -1498,6 +1637,26 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
}
/*
+ * Go through the mode pool and see if any modes match the target
+ * refresh rate, (if specified). If no modes match, abandon the target.
+ */
+ targetRefresh = xf86SetRealOption(scrp->options,
+ "TargetRefresh", 0.0);
+ if (targetRefresh > 0.0) {
+ for (p = scrp->modePool; p != NULL; p = p->next) {
+ if (ModeVRefresh(p) > targetRefresh * (1.0 - SYNC_TOLERANCE))
+ break;
+ }
+ if (!p)
+ targetRefresh = 0.0;
+ }
+
+ if (targetRefresh > 0.0) {
+ xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
+ "Target refresh rate is %.1f Hz\n", targetRefresh);
+ }
+
+ /*
* Allocate one entry in scrp->modes for each named mode.
*/
while (scrp->modes)
@@ -1520,7 +1679,15 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
}
/* Lookup each mode */
- validateAllDefaultModes = TRUE;
+#ifdef RANDR
+ if (!xf86Info.disableRandR
+#ifdef PANORAMIX
+ && noPanoramiXExtension
+#endif
+ )
+ validateAllDefaultModes = TRUE;
+#endif
+
for (p = scrp->modes; ; p = p->next) {
Bool repeat;
@@ -1561,6 +1728,14 @@ xf86ValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
((double)q->HTotal / (double)q->HDisplay) < 1.15)
continue;
+ /*
+ * If there is a target refresh rate, skip modes that
+ * don't match up.
+ */
+ if (ModeVRefresh(q) <
+ (1.0 - SYNC_TOLERANCE) * targetRefresh)
+ continue;
+
if (modeSize < (q->HDisplay * q->VDisplay)) {
r = q;
modeSize = q->HDisplay * q->VDisplay;
@@ -1833,8 +2008,16 @@ xf86PruneDriverModes(ScrnInfoPtr scrp)
} while (p != NULL && p != first);
/* modePool is no longer needed, turf it */
- while (scrp->modePool)
+ while (scrp->modePool) {
+ /*
+ * A modePool mode's prev field is used to hold a pointer to the
+ * member of the scrp->modes list for which a match was considered.
+ * Clear that pointer first, otherwise xf86DeleteMode might get
+ * confused
+ */
+ scrp->modePool->prev = NULL;
xf86DeleteMode(&scrp->modePool, scrp->modePool);
+ }
}
@@ -1946,22 +2129,16 @@ xf86PrintModes(ScrnInfoPtr scrp)
hsync = (float)p->Clock / (float)p->HTotal;
else
hsync = 0.0;
- if (p->VTotal > 0)
- refresh = hsync * 1000.0 / p->VTotal;
+ refresh = ModeVRefresh(p);
if (p->Flags & V_INTERLACE) {
- refresh *= 2.0;
desc = " (I)";
}
if (p->Flags & V_DBLSCAN) {
- refresh /= 2.0;
desc = " (D)";
}
if (p->VScan > 1) {
- refresh /= p->VScan;
desc2 = " (VScan)";
}
- if (p->VRefresh > 0.0)
- refresh = p->VRefresh;
if (p->type & M_T_BUILTIN)
prefix = "Built-in mode";
else if (p->type & M_T_DEFAULT)