From 326f992a90dae7a747da45626e588fa3c1dfa5dc Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 21 Sep 2018 14:38:31 -0400
Subject: [PATCH xserver] xfree86: try harder to span on multihead

right now if one of the monitors can't give
it's native resolution because of bandwidth limitations,
X decides to avoid spanning and instead clone.

That's suboptimal, spanning is normally the right
thing to do (with the exception of some projector
use cases and other edge cases)

This commit tries harder to make spanning work.
---
 hw/xfree86/modes/xf86Crtc.c | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 37a45bb3a..686cb51b8 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -2132,135 +2132,160 @@ bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect)
             if (test->HDisplay != mode->HDisplay ||
                 test->VDisplay != mode->VDisplay) {
                 test = NULL;
                 break;
             }
         }
 
         /* if we didn't match it on all outputs, try the next one */
         if (!test)
             continue;
 
         /* if it's bigger than the last one, save it */
         if (!match || (test->HDisplay > match->HDisplay))
             match = test;
     }
 
     /* return the biggest one found */
     return match;
 }
 
 static int
 numEnabledOutputs(xf86CrtcConfigPtr config, Bool *enabled)
 {
     int i = 0, p;
 
     for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ;
 
     return i;
 }
 
+static DisplayModePtr
+findReasonableMode(xf86CrtcConfigPtr config, xf86OutputPtr output, Bool *enabled, int width, int height)
+{
+    DisplayModePtr mode =
+        xf86OutputHasPreferredMode(output, width, height);
+
+    /* if there's no preferred mode, just try to find a reasonable one */
+    if (!mode) {
+        float aspect = 0.0;
+        DisplayModePtr a = NULL, b = NULL;
+
+        if (output->mm_height)
+            aspect = (float) output->mm_width /
+                (float) output->mm_height;
+
+        a = bestModeForAspect(config, enabled, 4.0/3.0);
+        if (aspect)
+            b = bestModeForAspect(config, enabled, aspect);
+
+        mode = biggestMode(a, b);
+    }
+
+    return mode;
+}
+
 static Bool
 xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
                   DisplayModePtr *modes, Bool *enabled,
                   int width, int height)
 {
     int o;
     int w = 0;
     Bool has_tile = FALSE;
     uint32_t configured_outputs;
 
     xf86GetOptValBool(config->options, OPTION_PREFER_CLONEMODE,
                       &scrn->preferClone);
     if (scrn->preferClone)
         return FALSE;
 
     if (numEnabledOutputs(config, enabled) < 2)
         return FALSE;
 
     for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
         DisplayModePtr mode =
-            xf86OutputHasPreferredMode(config->output[o], width, height);
+            findReasonableMode(config, config->output[o], enabled, width, height);
 
         if (!mode)
             return FALSE;
 
         w += mode->HDisplay;
     }
 
     if (w > width)
         return FALSE;
 
     w = 0;
     configured_outputs = 0;
 
     for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
         DisplayModePtr mode =
-            xf86OutputHasPreferredMode(config->output[o], width, height);
+            findReasonableMode(config, config->output[o], enabled, width, height);
 
         if (configured_outputs & (1 << o))
             continue;
 
         if (config->output[o]->tile_info.group_id) {
             has_tile = TRUE;
             continue;
         }
 
         config->output[o]->initial_x = w;
         w += mode->HDisplay;
 
         configured_outputs |= (1 << o);
         modes[o] = mode;
     }
 
     if (has_tile) {
         for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
             int ht, vt, ot;
             int add_x, cur_x = w;
             struct xf86CrtcTileInfo *tile_info = &config->output[o]->tile_info, *this_tile;
             if (configured_outputs & (1 << o))
                 continue;
             if (!tile_info->group_id)
                 continue;
 
             if (tile_info->tile_h_loc != 0 && tile_info->tile_v_loc != 0)
                 continue;
 
             for (ht = 0; ht < tile_info->num_h_tile; ht++) {
                 int cur_y = 0;
                 add_x = 0;
                 for (vt = 0; vt < tile_info->num_v_tile; vt++) {
 
                     for (ot = -1; nextEnabledOutput(config, enabled, &ot); ) {
-
                         DisplayModePtr mode =
-                            xf86OutputHasPreferredMode(config->output[ot], width, height);
+                            findReasonableMode(config, config->output[ot], enabled, width, height);
+
                         if (!config->output[ot]->tile_info.group_id)
                             continue;
 
                         this_tile = &config->output[ot]->tile_info;
                         if (this_tile->group_id != tile_info->group_id)
                             continue;
 
                         if (this_tile->tile_h_loc != ht ||
                             this_tile->tile_v_loc != vt)
                             continue;
 
                         config->output[ot]->initial_x = cur_x;
                         config->output[ot]->initial_y = cur_y;
 
                         if (vt == 0)
                             add_x = this_tile->tile_h_size;
                         cur_y += this_tile->tile_v_size;
                         configured_outputs |= (1 << ot);
                         modes[ot] = mode;
                     }
                 }
                 cur_x += add_x;
             }
             w = cur_x;
         }
     }
     return TRUE;
 }
 
 static Bool
-- 
2.17.1

