GPU hotplugging - loads/unloads based upon udev events
Created by: neon64
(this description is mostly copied from the main commit message)
This has been implemented specifically for the use case of Nvidia Optimus laptops with display ports hardwired to the dGPU. I'm hoping it may prove useful for other use-cases as well, such as hotplugging external GPUs.
The implementation is not pretty, and likely is full of bugs and special-cases. I am not familiar with the internal architecture of wlroots, so would love any constructive criticism of the implementation / C style.
The status quo:
- with both i915 and nouveau drivers loaded, sway can use both the laptop monitor AND external monitors, enabling and disabling outputs as needed
- BUT, the
nouveau
driver always stays loaded, and so my laptop idles at 20W instead of 3-5W :( - unloading
nouveau
requires restarting sway. This is annoying.
After this patch:
- run
sudo modprobe nouveau
while sway is running - wlroots will detect the udev event and add a new drm backend and then add it to the multi backend. - unplug all outputs from the dGPU, and sway will destroy the dGPU drm
backend.
You can verify that the nouveau driver is no longer in use,
by running
lsof /dev/dri/card*
- The user must still manually run
sudo rmmod nouveau
and then also usebbswitch
, to fully power off the dGPU and achieve power-saving gains. Though still somewhat manual, this whole process can be done WITHOUT shutting down sway, which is awesome for productivity (no longer have to restart the swaywm several times throughout the day).
The future (perhaps a separate script):
- Automatically loads
nouveau
when a cable is connected (unsure if this is possible due to hardwiring of HDMI port, see below) - Automatically unloads
nouveau
and runs bbswitch after all monitors have been disconnected for a while. - This would be BLISS - basically as automatic as Windows when it comes to using Nvidia Optimus configuration - except of course that sway won't actually render from the dGPU. For my workloads, this isn't a problem, but perhaps someone will take this further and reimplement something like bumblebee but for Wayland. Is that even a good idea? I don't know.
Note: at the moment, this driver unloading only occurs when you unplug all monitors from a given card. This results in some undesirable behaviour (https://github.com/swaywm/wlroots/issues/1278#issuecomment-705874280) Perhaps there should be an explicit command, e.g.: "unload all unused drm backends" that can be called by some other script, which will trigger unloading. Or perhaps, if a drm backend is unused for a given amount of time (e.g.: a few minutes) it will get unloaded.
Also note, at least on my laptop, there seemingly no way to tell when a
cable is plugged into the HDMI port (probably because it is hardwired to
the Nvidia GPU). If this were possible, then you could write a script
which will automatically power on the nvidia GPU when an external
monitor is connected. Currently, you need to do this manually, with sudo modprobe nouveau
.