Prefer driver-provided modes when matching name strings to modelines.

Well, kinda.  Strictly we prefer M_T_BUILTIN strongest since those are modes
where the driver has said it absolutely can't do anything else (VBE).  Then
we look for user-defined modes, ie, modelines from the config file.  Then
we consider modes reported by the monitor via EDID.  Finally if nothing has
matched yet we consider the default mode pool.

Within each of the above-mentioned classes, modes with the M_T_PREFERRED bit
take priority over other modes in the same class.

This logic ensures that the timings sent to the monitor exactly match the
timings it reported as supported, which occasionally don't match the numbers
you might get for that mode from CVT or GTF.
This commit is contained in:
Adam Jackson 2006-09-14 19:24:41 -04:00
parent 81ef1b6d60
commit a8f9936f55

View File

@ -445,6 +445,17 @@ xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep,
ModeStatus status = MODE_NOMODE; ModeStatus status = MODE_NOMODE;
Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0; Bool allowDiv2 = (strategy & LOOKUP_CLKDIV2) != 0;
Bool haveBuiltin; Bool haveBuiltin;
int n;
const int types[] = {
M_T_BUILTIN | M_T_PREFERRED,
M_T_BUILTIN,
M_T_USERDEF | M_T_PREFERRED,
M_T_USERDEF,
M_T_DRIVER | M_T_PREFERRED,
M_T_DRIVER,
0
};
const int ntypes = sizeof(types) / sizeof(int);
strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES); strategy &= ~(LOOKUP_CLKDIV2 | LOOKUP_OPTIONAL_TOLERANCES);
@ -464,143 +475,141 @@ xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep,
cp->ClockMulFactor = max(1, cp->ClockMulFactor); cp->ClockMulFactor = max(1, cp->ClockMulFactor);
} }
haveBuiltin = FALSE;
/* Scan the mode pool for matching names */ /* Scan the mode pool for matching names */
for (p = scrp->modePool; p != NULL; p = p->next) { for (n = 0; n < ntypes; n++) {
if (strcmp(p->name, modep->name) == 0) { int type = types[n];
/* for (p = scrp->modePool; p != NULL; p = p->next) {
* Requested mode is a built-in mode. Don't let the user
* override it.
* Since built-in modes always come before user specified
* modes it will always be found first.
*/
if (p->type & M_T_BUILTIN) {
haveBuiltin = TRUE;
}
if (haveBuiltin && !(p->type & M_T_BUILTIN)) /* scan through the modes in the sort order above */
if ((p->type & type) != type)
continue; continue;
/* Skip over previously rejected modes */ if (strcmp(p->name, modep->name) == 0) {
if (p->status != MODE_OK) {
if (!found)
status = p->status;
continue;
}
/* Skip over previously considered modes */ /* Skip over previously rejected modes */
if (p->prev) if (p->status != MODE_OK) {
continue; if (!found)
status = p->status;
continue;
}
if (p->type & M_T_BUILTIN) { /* Skip over previously considered modes */
return xf86HandleBuiltinMode(scrp, p,modep, clockRanges, if (p->prev)
allowDiv2); continue;
}
if (p->type & M_T_BUILTIN) {
return xf86HandleBuiltinMode(scrp, p,modep, clockRanges,
allowDiv2);
}
/* Check clock is in range */
cp = xf86FindClockRangeForMode(clockRanges, p);
if (cp == NULL) {
/*
* XXX Could do more here to provide a more detailed
* reason for not finding a mode.
*/
p->status = MODE_CLOCK_RANGE;
if (!found)
status = MODE_CLOCK_RANGE;
continue;
}
/* Check clock is in range */
cp = xf86FindClockRangeForMode(clockRanges, p);
if (cp == NULL) {
/* /*
* XXX Could do more here to provide a more detailed * If programmable clock and strategy is not
* reason for not finding a mode. * LOOKUP_BEST_REFRESH, the required mode has been found,
* otherwise record the refresh and continue looking.
*/ */
p->status = MODE_CLOCK_RANGE; if (scrp->progClock) {
if (!found) found = TRUE;
status = MODE_CLOCK_RANGE; if (strategy != LOOKUP_BEST_REFRESH) {
continue; bestMode = p;
} DivFactor = cp->ClockDivFactor;
MulFactor = cp->ClockMulFactor;
ModePrivFlags = cp->PrivFlags;
break;
}
refresh = ModeVRefresh(p);
if (p->Flags & V_INTERLACE)
refresh /= INTERLACE_REFRESH_WEIGHT;
if (refresh > bestRefresh) {
bestMode = p;
DivFactor = cp->ClockDivFactor;
MulFactor = cp->ClockMulFactor;
ModePrivFlags = cp->PrivFlags;
bestRefresh = refresh;
}
continue;
}
/* /*
* If programmable clock and strategy is not LOOKUP_BEST_REFRESH, * Clock is in range, so if it is not a programmable clock, find
* the required mode has been found, otherwise record the refresh * a matching clock.
* and continue looking. */
*/
if (scrp->progClock) { i = xf86GetNearestClock(scrp, p->Clock, allowDiv2,
cp->ClockDivFactor, cp->ClockMulFactor, &k);
/*
* If the clock is too far from the requested clock, this
* mode is no good.
*/
if (k & V_CLKDIV2)
gap = abs((p->Clock * 2) -
((scrp->clock[i] * cp->ClockDivFactor) /
cp->ClockMulFactor));
else
gap = abs(p->Clock -
((scrp->clock[i] * cp->ClockDivFactor) /
cp->ClockMulFactor));
if (gap > minimumGap) {
p->status = MODE_NOCLOCK;
if (!found)
status = MODE_NOCLOCK;
continue;
}
found = TRUE; found = TRUE;
if (strategy != LOOKUP_BEST_REFRESH) {
bestMode = p;
DivFactor = cp->ClockDivFactor;
MulFactor = cp->ClockMulFactor;
ModePrivFlags = cp->PrivFlags;
break;
}
refresh = ModeVRefresh(p);
if (p->Flags & V_INTERLACE)
refresh /= INTERLACE_REFRESH_WEIGHT;
if (refresh > bestRefresh) {
bestMode = p;
DivFactor = cp->ClockDivFactor;
MulFactor = cp->ClockMulFactor;
ModePrivFlags = cp->PrivFlags;
bestRefresh = refresh;
}
continue;
}
/* if (strategy == LOOKUP_BEST_REFRESH) {
* Clock is in range, so if it is not a programmable clock, find refresh = ModeVRefresh(p);
* a matching clock. if (p->Flags & V_INTERLACE)
*/ refresh /= INTERLACE_REFRESH_WEIGHT;
if (refresh > bestRefresh) {
i = xf86GetNearestClock(scrp, p->Clock, allowDiv2, bestMode = p;
cp->ClockDivFactor, cp->ClockMulFactor, &k); DivFactor = cp->ClockDivFactor;
/* MulFactor = cp->ClockMulFactor;
* If the clock is too far from the requested clock, this ModePrivFlags = cp->PrivFlags;
* mode is no good. extraFlags = k;
*/ clockIndex = i;
if (k & V_CLKDIV2) bestRefresh = refresh;
gap = abs((p->Clock * 2) - }
((scrp->clock[i] * cp->ClockDivFactor) / cp->ClockMulFactor)); continue;
else
gap = abs(p->Clock -
((scrp->clock[i] * cp->ClockDivFactor) / cp->ClockMulFactor));
if (gap > minimumGap) {
p->status = MODE_NOCLOCK;
if (!found)
status = MODE_NOCLOCK;
continue;
}
found = TRUE;
if (strategy == LOOKUP_BEST_REFRESH) {
refresh = ModeVRefresh(p);
if (p->Flags & V_INTERLACE)
refresh /= INTERLACE_REFRESH_WEIGHT;
if (refresh > bestRefresh) {
bestMode = p;
DivFactor = cp->ClockDivFactor;
MulFactor = cp->ClockMulFactor;
ModePrivFlags = cp->PrivFlags;
extraFlags = k;
clockIndex = i;
bestRefresh = refresh;
} }
continue; if (strategy == LOOKUP_CLOSEST_CLOCK) {
} if (gap < minimumGap) {
if (strategy == LOOKUP_CLOSEST_CLOCK) { bestMode = p;
if (gap < minimumGap) { DivFactor = cp->ClockDivFactor;
bestMode = p; MulFactor = cp->ClockMulFactor;
DivFactor = cp->ClockDivFactor; ModePrivFlags = cp->PrivFlags;
MulFactor = cp->ClockMulFactor; extraFlags = k;
ModePrivFlags = cp->PrivFlags; clockIndex = i;
extraFlags = k; minimumGap = gap;
clockIndex = i; }
minimumGap = gap; continue;
} }
continue; /*
* If strategy is neither LOOKUP_BEST_REFRESH or
* LOOKUP_CLOSEST_CLOCK the required mode has been found.
*/
bestMode = p;
DivFactor = cp->ClockDivFactor;
MulFactor = cp->ClockMulFactor;
ModePrivFlags = cp->PrivFlags;
extraFlags = k;
clockIndex = i;
break;
} }
/*
* If strategy is neither LOOKUP_BEST_REFRESH or
* LOOKUP_CLOSEST_CLOCK the required mode has been found.
*/
bestMode = p;
DivFactor = cp->ClockDivFactor;
MulFactor = cp->ClockMulFactor;
ModePrivFlags = cp->PrivFlags;
extraFlags = k;
clockIndex = i;
break;
} }
if (found) break;
} }
if (!found || bestMode == NULL) if (!found || bestMode == NULL)
return status; return status;
@ -611,7 +620,8 @@ xf86LookupMode(ScrnInfoPtr scrp, DisplayModePtr modep,
modep->ClockIndex = -1; modep->ClockIndex = -1;
modep->SynthClock = (modep->Clock * MulFactor) / DivFactor; modep->SynthClock = (modep->Clock * MulFactor) / DivFactor;
} else { } else {
modep->Clock = (scrp->clock[clockIndex] * DivFactor) / MulFactor; modep->Clock = (scrp->clock[clockIndex] * DivFactor) /
MulFactor;
modep->ClockIndex = clockIndex; modep->ClockIndex = clockIndex;
modep->SynthClock = scrp->clock[clockIndex]; modep->SynthClock = scrp->clock[clockIndex];
if (extraFlags & V_CLKDIV2) { if (extraFlags & V_CLKDIV2) {