From 75815dbb373d5a74d57cbec9d469f9f88a8ee3ef Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Dec 2012 13:25:19 +0000 Subject: [PATCH] Add missing GTF modes A fixed-mode output device like a panel will often only inform of its preferred mode through its EDID. However, the driver will adjust user specified modes for display through use of a panel-fitter allowing greater flexibility in upscaling. This is often used by games to set a low resolution for performance and use the panel fitter to fill the screen. v2: Use the presence of the 'scaling mode' connector property as an indication that a panel fitter is attached to that pipe. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55564 --- .../drivers/modesetting/drmmode_display.c | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 63cecc3cf..e8ebef17c 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -626,6 +626,78 @@ drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) return MODE_OK; } +static Bool +has_panel_fitter(xf86OutputPtr output) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmModeConnectorPtr koutput = drmmode_output->mode_output; + drmmode_ptr drmmode = drmmode_output->drmmode; + int i; + + /* Presume that if the output supports scaling, then we have a + * panel fitter capable of adjust any mode to suit. + */ + for (i = 0; i < koutput->count_props; i++) { + drmModePropertyPtr props; + Bool found = FALSE; + + props = drmModeGetProperty(drmmode->fd, koutput->props[i]); + if (props) { + found = strcmp(props->name, "scaling mode") == 0; + drmModeFreeProperty(props); + } + + if (found) + return TRUE; + } + + return FALSE; +} + +static DisplayModePtr +drmmode_output_add_gtf_modes(xf86OutputPtr output, + DisplayModePtr Modes) +{ + xf86MonPtr mon = output->MonInfo; + DisplayModePtr i, m, preferred = NULL; + int max_x = 0, max_y = 0; + float max_vrefresh = 0.0; + + if (mon && GTF_SUPPORTED(mon->features.msc)) + return Modes; + + if (!has_panel_fitter(output)) + return Modes; + + for (m = Modes; m; m = m->next) { + if (m->type & M_T_PREFERRED) + preferred = m; + max_x = max(max_x, m->HDisplay); + max_y = max(max_y, m->VDisplay); + max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m)); + } + + max_vrefresh = max(max_vrefresh, 60.0); + max_vrefresh *= (1 + SYNC_TOLERANCE); + + m = xf86GetDefaultModes(); + xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0); + + for (i = m; i; i = i->next) { + if (xf86ModeVRefresh(i) > max_vrefresh) + i->status = MODE_VSYNC; + if (preferred && + i->HDisplay >= preferred->HDisplay && + i->VDisplay >= preferred->VDisplay && + xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred)) + i->status = MODE_VSYNC; + } + + xf86PruneInvalidModes(output->scrn, &m, FALSE); + + return xf86ModesAdd(Modes, m); +} + static DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) { @@ -666,7 +738,8 @@ drmmode_output_get_modes(xf86OutputPtr output) Modes = xf86ModesAdd(Modes, Mode); } - return Modes; + + return drmmode_output_add_gtf_modes(output, Modes); } static void