120f876
From 471289fa1dc359555ceed6302f7d9605ab6be3ea Mon Sep 17 00:00:00 2001
97c6429
From: Dave Airlie <airlied@redhat.com>
120f876
Date: Mon, 2 Apr 2018 16:49:02 -0400
120f876
Subject: [PATCH] autobind GPUs to the screen
97c6429
db3d278
This is a modified version of a patch we've been carry-ing in Fedora and
db3d278
RHEL for years now. This patch automatically adds secondary GPUs to the
db3d278
master as output sink / offload source making e.g. the use of
db3d278
slave-outputs just work, with requiring the user to manually run
db3d278
"xrandr --setprovideroutputsource" before he can hookup an external
db3d278
monitor to his hybrid graphics laptop.
97c6429
db3d278
There is one problem with this patch, which is why it was not upstreamed
db3d278
before. What to do when a secondary GPU gets detected really is a policy
db3d278
decission (e.g. one may want to autobind PCI GPUs but not USB ones) and
db3d278
as such should be under control of the Desktop Environment.
db3d278
db3d278
Unconditionally adding autobinding support to the xserver will result
db3d278
in races between the DE dealing with the hotplug of a secondary GPU
db3d278
and the server itself dealing with it.
db3d278
db3d278
However we've waited for years for any Desktop Environments to actually
db3d278
start doing some sort of autoconfiguration of secondary GPUs and there
db3d278
is still not a single DE dealing with this, so I believe that it is
db3d278
time to upstream this now.
db3d278
db3d278
To avoid potential future problems if any DEs get support for doing
db3d278
secondary GPU configuration themselves, the new autobind functionality
db3d278
is made optional. Since no DEs currently support doing this themselves it
db3d278
is enabled by default. When DEs grow support for doing this themselves
db3d278
they can disable the servers autobinding through the servers cmdline or a
db3d278
xorg.conf snippet.
Dave Airlie 02cbf43
Dave Airlie 02cbf43
Signed-off-by: Dave Airlie <airlied@gmail.com>
6c7b302
[hdegoede@redhat.com: Make configurable, fix with nvidia, submit upstream]
db3d278
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
db3d278
---
db3d278
 hw/xfree86/common/xf86Config.c      | 19 +++++++++++++++++++
db3d278
 hw/xfree86/common/xf86Globals.c     |  2 ++
6c7b302
 hw/xfree86/common/xf86Init.c        | 20 ++++++++++++++++++++
db3d278
 hw/xfree86/common/xf86Priv.h        |  1 +
db3d278
 hw/xfree86/common/xf86Privstr.h     |  1 +
6c7b302
 hw/xfree86/common/xf86platformBus.c |  4 ++++
db3d278
 hw/xfree86/man/Xorg.man             |  7 +++++++
db3d278
 hw/xfree86/man/xorg.conf.man        |  6 ++++++
6c7b302
 randr/randrstr.h                    |  3 +++
6c7b302
 randr/rrprovider.c                  | 22 ++++++++++++++++++++++
db3d278
 10 files changed, 85 insertions(+)
97c6429
db3d278
diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c
120f876
index 2c1d335..d7d7c2e 100644
db3d278
--- a/hw/xfree86/common/xf86Config.c
db3d278
+++ b/hw/xfree86/common/xf86Config.c
120f876
@@ -643,6 +643,7 @@ typedef enum {
db3d278
     FLAG_DRI2,
db3d278
     FLAG_USE_SIGIO,
db3d278
     FLAG_AUTO_ADD_GPU,
db3d278
+    FLAG_AUTO_BIND_GPU,
db3d278
     FLAG_MAX_CLIENTS,
db3d278
     FLAG_IGLX,
120f876
     FLAG_DEBUG,
120f876
@@ -699,6 +700,8 @@ static OptionInfoRec FlagOptions[] = {
db3d278
      {0}, FALSE},
db3d278
     {FLAG_AUTO_ADD_GPU, "AutoAddGPU", OPTV_BOOLEAN,
db3d278
      {0}, FALSE},
db3d278
+    {FLAG_AUTO_BIND_GPU, "AutoBindGPU", OPTV_BOOLEAN,
db3d278
+     {0}, FALSE},
db3d278
     {FLAG_MAX_CLIENTS, "MaxClients", OPTV_INTEGER,
db3d278
      {0}, FALSE },
db3d278
     {FLAG_IGLX, "IndirectGLX", OPTV_BOOLEAN,
120f876
@@ -779,6 +782,22 @@ configServerFlags(XF86ConfFlagsPtr flagsconf, XF86OptionPtr layoutopts)
db3d278
     }
db3d278
     xf86Msg(from, "%sutomatically adding GPU devices\n",
db3d278
             xf86Info.autoAddGPU ? "A" : "Not a");
db3d278
+
db3d278
+    if (xf86AutoBindGPUDisabled) {
db3d278
+        xf86Info.autoBindGPU = FALSE;
db3d278
+        from = X_CMDLINE;
db3d278
+    }
db3d278
+    else if (xf86IsOptionSet(FlagOptions, FLAG_AUTO_BIND_GPU)) {
db3d278
+        xf86GetOptValBool(FlagOptions, FLAG_AUTO_BIND_GPU,
db3d278
+                          &xf86Info.autoBindGPU);
db3d278
+        from = X_CONFIG;
db3d278
+    }
db3d278
+    else {
db3d278
+        from = X_DEFAULT;
db3d278
+    }
db3d278
+    xf86Msg(from, "%sutomatically binding GPU devices\n",
db3d278
+            xf86Info.autoBindGPU ? "A" : "Not a");
db3d278
+
db3d278
     /*
db3d278
      * Set things up based on the config file information.  Some of these
db3d278
      * settings may be overridden later when the command line options are
db3d278
diff --git a/hw/xfree86/common/xf86Globals.c b/hw/xfree86/common/xf86Globals.c
120f876
index e890f05..7b27b4c 100644
db3d278
--- a/hw/xfree86/common/xf86Globals.c
db3d278
+++ b/hw/xfree86/common/xf86Globals.c
120f876
@@ -131,6 +131,7 @@ xf86InfoRec xf86Info = {
db3d278
 #else
db3d278
     .autoAddGPU = FALSE,
db3d278
 #endif
db3d278
+    .autoBindGPU = TRUE,
db3d278
 };
db3d278
 
db3d278
 const char *xf86ConfigFile = NULL;
120f876
@@ -191,6 +192,7 @@ Bool xf86FlipPixels = FALSE;
db3d278
 Gamma xf86Gamma = { 0.0, 0.0, 0.0 };
db3d278
 
db3d278
 Bool xf86AllowMouseOpenFail = FALSE;
db3d278
+Bool xf86AutoBindGPUDisabled = FALSE;
db3d278
 
db3d278
 #ifdef XF86VIDMODE
db3d278
 Bool xf86VidModeDisabled = FALSE;
97c6429
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
120f876
index ea42ec9..ec255b6 100644
97c6429
--- a/hw/xfree86/common/xf86Init.c
97c6429
+++ b/hw/xfree86/common/xf86Init.c
db3d278
@@ -76,6 +76,7 @@
db3d278
 #include "xf86DDC.h"
db3d278
 #include "xf86Xinput.h"
db3d278
 #include "xf86InPriv.h"
db3d278
+#include "xf86Crtc.h"
db3d278
 #include "picturestr.h"
120f876
 #include "randrstr.h"
120f876
 #include "glxvndabi.h"
120f876
@@ -237,6 +238,19 @@ xf86PrivsElevated(void)
120f876
     return PrivsElevated();
fc48514
 }
97c6429
 
120f876
+static void
fc48514
+xf86AutoConfigOutputDevices(void)
fc48514
+{
fc48514
+    int i;
fc48514
+
6c7b302
+    if (!xf86Info.autoBindGPU)
6c7b302
+        return;
6c7b302
+
fc48514
+    for (i = 0; i < xf86NumGPUScreens; i++)
6c7b302
+        RRProviderAutoConfigGpuScreen(xf86ScrnToScreen(xf86GPUScreens[i]),
6c7b302
+                                      xf86ScrnToScreen(xf86Screens[0]));
fc48514
+}
fc48514
+
120f876
 static void
120f876
 TrapSignals(void)
fc48514
 {
120f876
@@ -770,6 +784,8 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
fc48514
     for (i = 0; i < xf86NumGPUScreens; i++)
fc48514
         AttachUnboundGPU(xf86Screens[0]->pScreen, xf86GPUScreens[i]->pScreen);
97c6429
 
fc48514
+    xf86AutoConfigOutputDevices();
fc48514
+
97c6429
     xf86VGAarbiterWrapFunctions();
97c6429
     if (sigio_blocked)
db3d278
         input_unlock();
120f876
@@ -1278,6 +1294,10 @@ ddxProcessArgument(int argc, char **argv, int i)
db3d278
         xf86Info.iglxFrom = X_CMDLINE;
db3d278
         return 0;
db3d278
     }
db3d278
+    if (!strcmp(argv[i], "-noautoBindGPU")) {
db3d278
+        xf86AutoBindGPUDisabled = TRUE;
db3d278
+        return 1;
db3d278
+    }
db3d278
 
db3d278
     /* OS-specific processing */
db3d278
     return xf86ProcessArgument(argc, argv, i);
db3d278
diff --git a/hw/xfree86/common/xf86Priv.h b/hw/xfree86/common/xf86Priv.h
120f876
index 4fe2b5f..6566622 100644
db3d278
--- a/hw/xfree86/common/xf86Priv.h
db3d278
+++ b/hw/xfree86/common/xf86Priv.h
db3d278
@@ -46,6 +46,7 @@
db3d278
 extern _X_EXPORT const char *xf86ConfigFile;
db3d278
 extern _X_EXPORT const char *xf86ConfigDir;
db3d278
 extern _X_EXPORT Bool xf86AllowMouseOpenFail;
db3d278
+extern _X_EXPORT Bool xf86AutoBindGPUDisabled;
db3d278
 
db3d278
 #ifdef XF86VIDMODE
db3d278
 extern _X_EXPORT Bool xf86VidModeDisabled;
db3d278
diff --git a/hw/xfree86/common/xf86Privstr.h b/hw/xfree86/common/xf86Privstr.h
120f876
index 21c2e1f..6c71863 100644
db3d278
--- a/hw/xfree86/common/xf86Privstr.h
db3d278
+++ b/hw/xfree86/common/xf86Privstr.h
120f876
@@ -98,6 +98,7 @@ typedef struct {
db3d278
 
db3d278
     Bool autoAddGPU;
120f876
     const char *debug;
db3d278
+    Bool autoBindGPU;
db3d278
 } xf86InfoRec, *xf86InfoPtr;
db3d278
 
120f876
 /* ISC's cc can't handle ~ of UL constants, so explicitly type cast them. */
97c6429
diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c
120f876
index cef47da..913a324 100644
97c6429
--- a/hw/xfree86/common/xf86platformBus.c
97c6429
+++ b/hw/xfree86/common/xf86platformBus.c
120f876
@@ -49,6 +49,7 @@
db3d278
 #include "Pci.h"
db3d278
 #include "xf86platformBus.h"
db3d278
 #include "xf86Config.h"
db3d278
+#include "xf86Crtc.h"
97c6429
 
db3d278
 #include "randrstr.h"
db3d278
 int platformSlotClaimed;
120f876
@@ -665,6 +666,9 @@ xf86platformAddDevice(int index)
Dave Airlie 9dc0b02
    }
fc48514
    /* attach unbound to 0 protocol screen */
fc48514
    AttachUnboundGPU(xf86Screens[0]->pScreen, xf86GPUScreens[i]->pScreen);
6c7b302
+   if (xf86Info.autoBindGPU)
6c7b302
+       RRProviderAutoConfigGpuScreen(xf86ScrnToScreen(xf86GPUScreens[i]),
6c7b302
+                                     xf86ScrnToScreen(xf86Screens[0]));
fc48514
 
488b3f2
    RRResourcesChanged(xf86Screens[0]->pScreen);
488b3f2
    RRTellChanged(xf86Screens[0]->pScreen);
db3d278
diff --git a/hw/xfree86/man/Xorg.man b/hw/xfree86/man/Xorg.man
120f876
index 13a9dc3..745f986 100644
db3d278
--- a/hw/xfree86/man/Xorg.man
db3d278
+++ b/hw/xfree86/man/Xorg.man
db3d278
@@ -283,6 +283,13 @@ is a comma separated list of directories to search for
db3d278
 server modules.  This option is only available when the server is run
db3d278
 as root (i.e, with real-uid 0).
db3d278
 .TP 8
db3d278
+.B \-noautoBindGPU
db3d278
+Disable automatically setting secondary GPUs up as output sinks and offload
db3d278
+sources. This is equivalent to setting the
db3d278
+.B AutoBindGPU
db3d278
+xorg.conf(__filemansuffix__) file option. To
db3d278
+.B false.
db3d278
+.TP 8
db3d278
 .B \-nosilk
db3d278
 Disable Silken Mouse support.
db3d278
 .TP 8
db3d278
diff --git a/hw/xfree86/man/xorg.conf.man b/hw/xfree86/man/xorg.conf.man
120f876
index 9589262..8d51e06 100644
db3d278
--- a/hw/xfree86/man/xorg.conf.man
db3d278
+++ b/hw/xfree86/man/xorg.conf.man
120f876
@@ -672,6 +672,12 @@ Enabled by default.
db3d278
 If this option is disabled, then no GPU devices will be added from the udev
db3d278
 backend. Enabled by default. (May need to be disabled to setup Xinerama).
db3d278
 .TP 7
db3d278
+.BI "Option \*qAutoBindGPU\*q  \*q" boolean \*q
db3d278
+If enabled then secondary GPUs will be automatically set up as output-sinks and
db3d278
+offload-sources. Making e.g. laptop outputs connected only to the secondary
db3d278
+GPU directly available for use without needing to run
db3d278
+"xrandr --setprovideroutputsource". Enabled by default.
db3d278
+.TP 7
db3d278
 .BI "Option \*qLog\*q \*q" string \*q
db3d278
 This option controls whether the log is flushed and/or synced to disk after
db3d278
 each message.
6c7b302
diff --git a/randr/randrstr.h b/randr/randrstr.h
120f876
index f94174b..092d726 100644
6c7b302
--- a/randr/randrstr.h
6c7b302
+++ b/randr/randrstr.h
120f876
@@ -1039,6 +1039,9 @@ RRProviderLookup(XID id, RRProviderPtr *provider_p);
6c7b302
 extern _X_EXPORT void
6c7b302
 RRDeliverProviderEvent(ClientPtr client, WindowPtr pWin, RRProviderPtr provider);
6c7b302
 
6c7b302
+extern _X_EXPORT void
6c7b302
+RRProviderAutoConfigGpuScreen(ScreenPtr pScreen, ScreenPtr masterScreen);
6c7b302
+
6c7b302
 /* rrproviderproperty.c */
6c7b302
 
6c7b302
 extern _X_EXPORT void
6c7b302
diff --git a/randr/rrprovider.c b/randr/rrprovider.c
120f876
index e4bc2bf..e04c18f 100644
6c7b302
--- a/randr/rrprovider.c
6c7b302
+++ b/randr/rrprovider.c
120f876
@@ -485,3 +485,25 @@ RRDeliverProviderEvent(ClientPtr client, WindowPtr pWin, RRProviderPtr provider)
6c7b302
 
6c7b302
     WriteEventsToClient(client, 1, (xEvent *) &pe);
fc48514
 }
fc48514
+
6c7b302
+void
6c7b302
+RRProviderAutoConfigGpuScreen(ScreenPtr pScreen, ScreenPtr masterScreen)
fc48514
+{
6c7b302
+    rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen);
6c7b302
+    rrScrPrivPtr masterPriv = rrGetScrPriv(masterScreen);
6c7b302
+    RRProviderPtr provider = pScrPriv->provider;
6c7b302
+    RRProviderPtr master_provider = masterPriv->provider;
db3d278
+
6c7b302
+    if (!provider || !master_provider)
8830e76
+        return;
8830e76
+
6c7b302
+    if ((provider->capabilities & RR_Capability_SinkOutput) &&
6c7b302
+        (master_provider->capabilities & RR_Capability_SourceOutput)) {
6c7b302
+        pScrPriv->rrProviderSetOutputSource(pScreen, provider, master_provider);
6c7b302
+        RRInitPrimeSyncProps(pScreen);
fc48514
+    }
db3d278
+
6c7b302
+    if ((provider->capabilities & RR_Capability_SourceOffload) &&
6c7b302
+        (master_provider->capabilities & RR_Capability_SinkOffload))
6c7b302
+        pScrPriv->rrProviderSetOffloadSink(pScreen, provider, master_provider);
6c7b302
+}
Dave Airlie 9dc0b02
-- 
120f876
2.16.2
Dave Airlie 9dc0b02