[PATCH v6 xserver] autobind GPUs to the screen

Hans de Goede hdegoede at redhat.com
Wed Sep 7 16:00:30 UTC 2016


From: Dave Airlie <airlied at redhat.com>

This is a modified version of a patch we've been carry-ing in Fedora and
RHEL for years now. This patch automatically adds secondary GPUs to the
master as output sink / offload source making e.g. the use of
slave-outputs just work, with requiring the user to manually run
"xrandr --setprovideroutputsource" before he can hookup an external
monitor to his hybrid graphics laptop.

There is one problem with this patch, which is why it was not upstreamed
before. What to do when a secondary GPU gets detected really is a policy
decission (e.g. one may want to autobind PCI GPUs but not USB ones) and
as such should be under control of the Desktop Environment.

Unconditionally adding autobinding support to the xserver will result
in races between the DE dealing with the hotplug of a secondary GPU
and the server itself dealing with it.

However we've waited for years for any Desktop Environments to actually
start doing some sort of autoconfiguration of secondary GPUs and there
is still not a single DE dealing with this, so I believe that it is
time to upstream this now.

To avoid potential future problems if DEs any get support for doing
secondary GPU configuration themselves, the new autobind functionality
is made optional and is disabled by default.

An example 10-auto-bind-gpu.conf file is provided to enable it and
distros are advised to install this.

Signed-off-by: Dave Airlie <airlied at gmail.com>
[hdegoede at redhat.com: Make configurable, submit upstream]
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 config/10-auto-bind-gpu.conf        |  3 +++
 config/Makefile.am                  |  4 ++--
 hw/xfree86/common/xf86Config.c      | 19 +++++++++++++++++++
 hw/xfree86/common/xf86Globals.c     |  2 ++
 hw/xfree86/common/xf86Init.c        | 16 ++++++++++++++++
 hw/xfree86/common/xf86Priv.h        |  1 +
 hw/xfree86/common/xf86Privstr.h     |  1 +
 hw/xfree86/common/xf86platformBus.c |  2 ++
 hw/xfree86/man/Xorg.man             |  8 ++++++++
 hw/xfree86/man/xorg.conf.man        |  6 ++++++
 hw/xfree86/modes/xf86Crtc.c         | 28 ++++++++++++++++++++++++++++
 hw/xfree86/modes/xf86Crtc.h         |  3 +++
 12 files changed, 91 insertions(+), 2 deletions(-)
 create mode 100644 config/10-auto-bind-gpu.conf

diff --git a/config/10-auto-bind-gpu.conf b/config/10-auto-bind-gpu.conf
new file mode 100644
index 0000000..7fbff4b
--- /dev/null
+++ b/config/10-auto-bind-gpu.conf
@@ -0,0 +1,3 @@
+Section "ServerFlags"
+    Option "AutoBindGPU" "true"
+EndSection
diff --git a/config/Makefile.am b/config/Makefile.am
index 51aae47..532e51a 100644
--- a/config/Makefile.am
+++ b/config/Makefile.am
@@ -18,7 +18,7 @@ libconfig_la_LIBADD += $(UDEV_LIBS)
 
 if XORG
 xorgconfddir = $(datadir)/X11/$(XF86CONFIGDIR)
-xorgconfd_DATA = 10-quirks.conf
+xorgconfd_DATA = 10-quirks.conf 10-auto-bind-gpu.conf
 endif
 
 else
@@ -38,4 +38,4 @@ endif # !CONFIG_HAL
 
 endif # !CONFIG_UDEV
 
-EXTRA_DIST = x11-input.fdi fdi2iclass.py 10-quirks.conf
+EXTRA_DIST = x11-input.fdi fdi2iclass.py 10-quirks.conf 10-auto-bind-gpu.conf
diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c
index 560e2ea..acf64e2 100644
--- a/hw/xfree86/common/xf86Config.c
+++ b/hw/xfree86/common/xf86Config.c
@@ -720,6 +720,7 @@ typedef enum {
     FLAG_DRI2,
     FLAG_USE_SIGIO,
     FLAG_AUTO_ADD_GPU,
+    FLAG_AUTO_BIND_GPU,
     FLAG_MAX_CLIENTS,
     FLAG_IGLX,
 } FlagValues;
@@ -781,6 +782,8 @@ static OptionInfoRec FlagOptions[] = {
      {0}, FALSE},
     {FLAG_AUTO_ADD_GPU, "AutoAddGPU", OPTV_BOOLEAN,
      {0}, FALSE},
+    {FLAG_AUTO_BIND_GPU, "AutoBindGPU", OPTV_BOOLEAN,
+     {0}, FALSE},
     {FLAG_MAX_CLIENTS, "MaxClients", OPTV_INTEGER,
      {0}, FALSE },
     {FLAG_IGLX, "IndirectGLX", OPTV_BOOLEAN,
@@ -860,6 +863,22 @@ configServerFlags(XF86ConfFlagsPtr flagsconf, XF86OptionPtr layoutopts)
     }
     xf86Msg(from, "%sutomatically adding GPU devices\n",
             xf86Info.autoAddGPU ? "A" : "Not a");
+
+    if (xf86AutoBindGPU) {
+        xf86Info.autoBindGPU = TRUE;
+        from = X_CMDLINE;
+    }
+    else if (xf86IsOptionSet(FlagOptions, FLAG_AUTO_BIND_GPU)) {
+        xf86GetOptValBool(FlagOptions, FLAG_AUTO_BIND_GPU,
+                          &xf86Info.autoBindGPU);
+        from = X_CONFIG;
+    }
+    else {
+        from = X_DEFAULT;
+    }
+    xf86Msg(from, "%sutomatically binding GPU devices\n",
+            xf86Info.autoBindGPU ? "A" : "Not a");
+
     /*
      * Set things up based on the config file information.  Some of these
      * settings may be overridden later when the command line options are
diff --git a/hw/xfree86/common/xf86Globals.c b/hw/xfree86/common/xf86Globals.c
index 07cfabf..ba27812 100644
--- a/hw/xfree86/common/xf86Globals.c
+++ b/hw/xfree86/common/xf86Globals.c
@@ -136,6 +136,7 @@ xf86InfoRec xf86Info = {
 #else
     .autoAddGPU = FALSE,
 #endif
+    .autoBindGPU = FALSE,
 };
 
 const char *xf86ConfigFile = NULL;
@@ -196,6 +197,7 @@ Bool xf86FlipPixels = FALSE;
 Gamma xf86Gamma = { 0.0, 0.0, 0.0 };
 
 Bool xf86AllowMouseOpenFail = FALSE;
+Bool xf86AutoBindGPU = FALSE;
 
 #ifdef XF86VIDMODE
 Bool xf86VidModeDisabled = FALSE;
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
index a544b65..aa198e6 100644
--- a/hw/xfree86/common/xf86Init.c
+++ b/hw/xfree86/common/xf86Init.c
@@ -76,6 +76,7 @@
 #include "xf86DDC.h"
 #include "xf86Xinput.h"
 #include "xf86InPriv.h"
+#include "xf86Crtc.h"
 #include "picturestr.h"
 
 #include "xf86Bus.h"
@@ -298,6 +299,15 @@ xf86PrivsElevated(void)
 }
 
 static void
+xf86AutoConfigOutputDevices(void)
+{
+    int i;
+
+    for (i = 0; i < xf86NumGPUScreens; i++)
+        xf86AutoConfigOutputDevice(xf86GPUScreens[i], xf86Screens[0]);
+}
+
+static void
 InstallSignalHandlers(void)
 {
     /*
@@ -871,6 +881,8 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
     for (i = 0; i < xf86NumGPUScreens; i++)
         AttachUnboundGPU(xf86Screens[0]->pScreen, xf86GPUScreens[i]->pScreen);
 
+    xf86AutoConfigOutputDevices();
+
     xf86VGAarbiterWrapFunctions();
     if (sigio_blocked)
         input_unlock();
@@ -1389,6 +1401,10 @@ ddxProcessArgument(int argc, char **argv, int i)
         xf86Info.iglxFrom = X_CMDLINE;
         return 0;
     }
+    if (!strcmp(argv[i], "-autoBindGPU")) {
+        xf86AutoBindGPU = TRUE;
+        return 1;
+    }
 
     /* OS-specific processing */
     return xf86ProcessArgument(argc, argv, i);
diff --git a/hw/xfree86/common/xf86Priv.h b/hw/xfree86/common/xf86Priv.h
index c1f8a18..ccd52c2 100644
--- a/hw/xfree86/common/xf86Priv.h
+++ b/hw/xfree86/common/xf86Priv.h
@@ -46,6 +46,7 @@
 extern _X_EXPORT const char *xf86ConfigFile;
 extern _X_EXPORT const char *xf86ConfigDir;
 extern _X_EXPORT Bool xf86AllowMouseOpenFail;
+extern _X_EXPORT Bool xf86AutoBindGPU;
 
 #ifdef XF86VIDMODE
 extern _X_EXPORT Bool xf86VidModeDisabled;
diff --git a/hw/xfree86/common/xf86Privstr.h b/hw/xfree86/common/xf86Privstr.h
index 9e327b9..a0a98aa 100644
--- a/hw/xfree86/common/xf86Privstr.h
+++ b/hw/xfree86/common/xf86Privstr.h
@@ -104,6 +104,7 @@ typedef struct {
     MessageType dri2From;
 
     Bool autoAddGPU;
+    Bool autoBindGPU;
 } xf86InfoRec, *xf86InfoPtr;
 
 #ifdef DPMSExtension
diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c
index 96895a6..028db03 100644
--- a/hw/xfree86/common/xf86platformBus.c
+++ b/hw/xfree86/common/xf86platformBus.c
@@ -48,6 +48,7 @@
 #include "Pci.h"
 #include "xf86platformBus.h"
 #include "xf86Config.h"
+#include "xf86Crtc.h"
 
 #include "randrstr.h"
 int platformSlotClaimed;
@@ -540,6 +541,7 @@ xf86platformAddDevice(int index)
    }
    /* attach unbound to 0 protocol screen */
    AttachUnboundGPU(xf86Screens[0]->pScreen, xf86GPUScreens[i]->pScreen);
+   xf86AutoConfigOutputDevice(xf86GPUScreens[i], xf86Screens[0]);
 
    RRResourcesChanged(xf86Screens[0]->pScreen);
    RRTellChanged(xf86Screens[0]->pScreen);
diff --git a/hw/xfree86/man/Xorg.man b/hw/xfree86/man/Xorg.man
index def9bfc..8cde45d 100644
--- a/hw/xfree86/man/Xorg.man
+++ b/hw/xfree86/man/Xorg.man
@@ -154,6 +154,14 @@ option, and is provided for compatibility with the native SCO X server.
 Sets the default color depth.  Legal values are 1, 4, 8, 15, 16, and
 24.  Not all drivers support all values.
 .TP 8
+.B \-autoBindGPU
+Enable automatically setting secondary GPUs up as output sinks and offload
+sources. Making e.g. laptop outputs connected only to the secondary GPU directly
+available for use without needing to run "xrandr --setprovideroutputsource".
+This is equivalent to the
+.B AutoBindGPU
+xorg.conf(__filemansuffix__) file option.
+.TP 8
 .B \-disableVidMode
 Disable the parts of the VidMode extension (used by the xvidtune
 client) that can be used to change the video modes.  This is equivalent
diff --git a/hw/xfree86/man/xorg.conf.man b/hw/xfree86/man/xorg.conf.man
index 94b199e..3b09127 100644
--- a/hw/xfree86/man/xorg.conf.man
+++ b/hw/xfree86/man/xorg.conf.man
@@ -676,6 +676,12 @@ Enabled by default.
 If this option is disabled, then no GPU devices will be added from the udev
 backend. Enabled by default. (May need to be disabled to setup Xinerama).
 .TP 7
+.BI "Option \*qAutoBindGPU\*q  \*q" boolean \*q
+If enabled then secondary GPUs will be automatically set up as output-sinks and
+offload-sources. Making e.g. laptop outputs connected only to the secondary
+GPU directly available for use without needing to run
+"xrandr --setprovideroutputsource". Disabled by default.
+.TP 7
 .BI "Option \*qLog\*q \*q" string \*q
 This option controls whether the log is flushed and/or synced to disk after
 each message.
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 966a168..4960678 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -3462,3 +3462,31 @@ xf86DetachAllCrtc(ScrnInfoPtr scrn)
             crtc->x = crtc->y = 0;
         }
 }
+
+void xf86AutoConfigOutputDevice(ScrnInfoPtr pScrn, ScrnInfoPtr master)
+{
+    RRProviderPtr master_provider;
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(master);
+    xf86CrtcConfigPtr slave_config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+    if (!xf86Info.autoBindGPU)
+        return;
+
+    if (!config || !slave_config)
+        return;
+
+    master_provider = config->randr_provider;
+
+    if ((master->capabilities & RR_Capability_SinkOffload) &&
+               pScrn->capabilities & RR_Capability_SourceOffload) {
+        /* source offload */
+        AttachOffloadGPU(master->pScreen, pScrn->pScreen);
+        slave_config->randr_provider->offload_sink = master_provider;
+    }
+    if ((master->capabilities & RR_Capability_SourceOutput) &&
+               pScrn->capabilities & RR_Capability_SinkOutput) {
+        /* sink offload */
+        AttachOutputGPU(master->pScreen, pScrn->pScreen);
+        slave_config->randr_provider->output_source = master_provider;
+    }
+}
diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index 9d1a1e1..5299b08 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -1055,4 +1055,7 @@ xf86ProviderSetup(ScrnInfoPtr scrn,
 extern _X_EXPORT void
 xf86DetachAllCrtc(ScrnInfoPtr scrn);
 
+extern _X_EXPORT void
+xf86AutoConfigOutputDevice(ScrnInfoPtr pScrn, ScrnInfoPtr master);
+
 #endif                          /* _XF86CRTC_H_ */
-- 
2.9.3



More information about the xorg-devel mailing list