Hybrid graphics
Hybrid-graphics is a concept that involves two graphics cards on same computer. Devices with two different GPUs, most often laptops, will usually have:
- a Dedicated/Discrete Graphics Processor, that offers higher raw performance but increases the device's power consumption;
- an Integrated Graphics Processor, that in general requires significantly less energy, but only offers enough performance for rendering non-graphics-intensive applications, e.g. browsers and the desktop environment.
Thus, the need for a technology that optimises both use cases naturally emerges. With that in mind, laptop manufacturers have each developed their own hybrid-graphics technologies that allow keeping the dedicated GPU inactive until its 3D rendering performance is needed over the integrated GPU.
There are a variety of implementations that solve this problem. The hybrid-graphics technology is well supported on Windows but is still rough around the edges with Linux distributions. This article will try to explain a little about each approach and describe some community solutions to the lack of GNU/Linux systems support by vendors.
Dynamic switching
Most of the new Hybrid-graphics technologies involve two graphics cards. The dedicated and integrated cards are plugged to a framebuffer and there is no hardware multiplexer. The integrated card is always on and the dedicated card is switched on/off according to a need in performance-rendering or power-saving, respectively. In most cases there is no way to use only the dedicated card and all the switching and rendering is controlled by software. At startup, the Linux kernel starts using a video mode and setting up low-level graphic drivers, which will be used by the applications. Most Linux distributions then use X.org to create a graphical environment. Finally, a few other programs are launched; first a login manager, then a window manager, and so on. In most cases, this hierarchical system has been designed to be used on a single graphics card.
Fully power down discrete GPU
You may want to turn off the high-performance graphics processor to save battery power.
Using BIOS/UEFI
Some laptop manufacturers provide a toggle in the BIOS or UEFI to fully deactivate the dedicated card.
Using udev rules
Ensure any display manager config for NVIDIA is removed.
Blacklist the nouveau drivers by creating
/etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau options nouveau modeset=0
Then create
/etc/udev/rules.d/00-remove-nvidia.rules
# Remove NVIDIA USB xHCI Host Controller devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{power/control}="auto", ATTR{remove}="1"
# Remove NVIDIA USB Type-C UCSI devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{power/control}="auto", ATTR{remove}="1"
# Remove NVIDIA Audio devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{power/control}="auto", ATTR{remove}="1"
# Remove NVIDIA VGA/3D controller devices
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x03[0-9]*", ATTR{power/control}="auto", ATTR{remove}="1"
Reboot and run lspci to see if your NVIDIA GPU is still listed.
Check power usage to ensure your GPU is not drawing power. If it does, #Using acpi_call may be another option to fully power it down.
Using bbswitch
With an NVIDIA GPU, this can be more safely done using bbswitch, which consists of a kernel package that automatically issues the correct ACPI calls to disable the discrete GPU when not needed, or automatically at boot.
Using acpi_call
Otherwise, and for GPUs not supported by bbswitch, the same can be done by manually installing the acpi_call package.
Once installed, load the kernel module:
# modprobe acpi_call
With the kernel module loaded, execute the script at /usr/share/acpi_call/examples/turn_off_gpu.sh
The script will go through all the known data buses and attempt to turn them off. You will get an output similar to the following:
# /usr/share/acpi_call/examples/turn_off_gpu.sh
Trying \_SB.PCI0.P0P1.VGA._OFF: failed Trying \_SB.PCI0.P0P2.VGA._OFF: failed Trying \_SB_.PCI0.OVGA.ATPX: failed Trying \_SB_.PCI0.OVGA.XTPX: failed Trying \_SB.PCI0.P0P3.PEGP._OFF: failed Trying \_SB.PCI0.P0P2.PEGP._OFF: failed Trying \_SB.PCI0.P0P1.PEGP._OFF: failed Trying \_SB.PCI0.MXR0.MXM0._OFF: failed Trying \_SB.PCI0.PEG1.GFX0._OFF: failed Trying \_SB.PCI0.PEG0.GFX0.DOFF: failed Trying \_SB.PCI0.PEG1.GFX0.DOFF: failed Trying \_SB.PCI0.PEG0.PEGP._OFF: works! Trying \_SB.PCI0.XVR0.Z01I.DGOF: failed Trying \_SB.PCI0.PEGR.GFX0._OFF: failed Trying \_SB.PCI0.PEG.VID._OFF: failed Trying \_SB.PCI0.PEG0.VID._OFF: failed Trying \_SB.PCI0.P0P2.DGPU._OFF: failed Trying \_SB.PCI0.P0P4.DGPU.DOFF: failed Trying \_SB.PCI0.IXVE.IGPU.DGOF: failed Trying \_SB.PCI0.RP00.VGA._PS3: failed Trying \_SB.PCI0.RP00.VGA.P3MO: failed Trying \_SB.PCI0.GFX0.DSM._T_0: failed Trying \_SB.PCI0.LPC.EC.PUBS._OFF: failed Trying \_SB.PCI0.P0P2.NVID._OFF: failed Trying \_SB.PCI0.P0P2.VGA.PX02: failed Trying \_SB_.PCI0.PEGP.DGFX._OFF: failed Trying \_SB_.PCI0.VGA.PX02: failed
See the "works"? This means the script found a bus which your GPU sits on and it has now turned off the chip. To confirm this, your battery time remaining should have increased.
Turning off the GPU automatically
Currently, the chip will turn back on with the next reboot. To get around this, load the module at boot:
/etc/modules-load.d/acpi_call.conf
#Load 'acpi_call.ko' at boot. acpi_call
At boot
To turn off the GPU at boot it is possible to use systemd-tmpfiles.
/etc/tmpfiles.d/acpi_call.conf
w /proc/acpi/call - - - - \\_SB.PCI0.PEG0.PEGP._OFF
The configuration above will be loaded at boot by systemd. What it does is write the specific OFF signal to the /proc/acpi/call file. Obviously, replace the \_SB.PCI0.PEG0.PEGP._OFF with the data bus that works on your system (please note that you need to escape the backslash).
After X server initialization
On some systems, turning off the discrete GPU before the X server is initialized may hang the system. In such cases, it may be better to disable the GPU after X server initialization, which is possible with some display managers. In LightDM, for instance, the display-setup-script seat configuration parameter could be used to execute a script as root that disables the GPU. If you use SDDM, then you can add the line echo "\_SB.PCI0.PEG0.PEGP._OFF" > /proc/acpi/call to either /usr/share/sddm/scripts/wayland-session or /usr/share/sddm/scripts/Xsession depending if you use Wayland or Xorg. Remember to replace \_SB.PCI0.PEG0.PEGP._OFF with the one that works on your system!
System76
Some System76 laptops (like the Oryx Pro) have their own unique hybrid graphics option. To make use of it, install system76-powerAUR, enable system76-power.service, and run system76-power graphics hybrid.
Fully power down discrete GPU
First ensure you are using integrated graphics mode by running system76-power graphics integrated and rebooting. Once in integrated mode, to power down the discrete graphics card run system76-power graphics power off. This command is not persistent and will need to be run after each boot.
Troubleshooting
The startup time for certain applications is delayed by 30 seconds
See Vulkan#Vulkan applications launch slowly (30 second delay).
High power draw even after disabling NVIDIA discrete GPU
If after disabling the dedicated GPU bus #Using acpi_call the power draw is still high, check if the nouveau kernel module is loaded with lsmod. If it's not, then make sure it is installed, that any entries in .conf files that blacklist Nouveau in /etc/modprobe.d/ are removed, and that the Nouveau kernel module is automatically loaded at boot. After rebooting the power draw should be lower.
/sys/class/backlight, add line acpi_backlight=native to your kernel parameters.