hw/xfree86: re-calculate the clock and refresh rate

xserver fails to generate useable resolutions with 90Hz framerate
panels(encounter the same issue with 3 different 2.5k resolution
panels). All the resolutions shown by xrandr lead to blank screen except
the one written in EDID.
Ville Syrjälä from Intel provides a method to calculate the preferred
clock and refresh rate from the existing resolution table and this
works for the issue.

v2. xf86ModeVRefresh might return 0, need to check it before use it.
v3. reported by Markus on launchpad that the issue is not devided by 0,
it's the "preferred" being accessed unconditionally.
BugLink: https://launchpad.net/bugs/1999852

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1388
Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
This commit is contained in:
Chia-Lin Kao (AceLan) 2022-11-08 08:11:50 +08:00 committed by Ville Syrjälä
parent 2bf0f9e113
commit f59871587e
3 changed files with 15 additions and 1 deletions

View File

@ -230,6 +230,8 @@ xf86ModeStatusToString(ModeStatus status)
return "monitor doesn't support reduced blanking"; return "monitor doesn't support reduced blanking";
case MODE_BANDWIDTH: case MODE_BANDWIDTH:
return "mode requires too much memory bandwidth"; return "mode requires too much memory bandwidth";
case MODE_DUPLICATE:
return "the same mode has been added";
case MODE_BAD: case MODE_BAD:
return "unknown reason"; return "unknown reason";
case MODE_ERROR: case MODE_ERROR:

View File

@ -2843,7 +2843,7 @@ static DisplayModePtr
drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes) drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
{ {
xf86MonPtr mon = output->MonInfo; xf86MonPtr mon = output->MonInfo;
DisplayModePtr i, m, preferred = NULL; DisplayModePtr i, j, m, preferred = NULL;
int max_x = 0, max_y = 0; int max_x = 0, max_y = 0;
float max_vrefresh = 0.0; float max_vrefresh = 0.0;
@ -2875,6 +2875,17 @@ drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
i->VDisplay >= preferred->VDisplay && i->VDisplay >= preferred->VDisplay &&
xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred)) xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred))
i->status = MODE_VSYNC; i->status = MODE_VSYNC;
if (preferred && xf86ModeVRefresh(i) > 0.0) {
i->Clock = i->Clock * xf86ModeVRefresh(preferred) / xf86ModeVRefresh(i);
i->VRefresh = xf86ModeVRefresh(preferred);
}
for (j = m; j != i; j = j->next) {
if (!strcmp(i->name, j->name) &&
xf86ModeVRefresh(i) * (1 + SYNC_TOLERANCE) >= xf86ModeVRefresh(j) &&
xf86ModeVRefresh(i) * (1 - SYNC_TOLERANCE) <= xf86ModeVRefresh(j)) {
i->status = MODE_DUPLICATE;
}
}
} }
xf86PruneInvalidModes(output->scrn, &m, FALSE); xf86PruneInvalidModes(output->scrn, &m, FALSE);

View File

@ -47,6 +47,7 @@ typedef enum {
MODE_ONE_SIZE, /* only one resolution is supported */ MODE_ONE_SIZE, /* only one resolution is supported */
MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */
MODE_BANDWIDTH, /* mode requires too much memory bandwidth */ MODE_BANDWIDTH, /* mode requires too much memory bandwidth */
MODE_DUPLICATE, /* mode is duplicated */
MODE_BAD = -2, /* unspecified reason */ MODE_BAD = -2, /* unspecified reason */
MODE_ERROR = -1 /* error condition */ MODE_ERROR = -1 /* error condition */
} ModeStatus; } ModeStatus;