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
---
 src/drmmode_display.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 74 insertions(+), 1 deletion(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 63cecc3..e8ebef1 100644
--- a/src/drmmode_display.c
+++ b/src/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
-- 
1.7.10.4

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to