How to Setup Dual GPU Systems (Gaming Laptops) in Hyprland

The Hyprland wiki tells you how to make Hyprland use one GPU over the other.
This article expands on the above, focusing on the most common dual GPU systems, i.e., gaming laptops.
I own an ASUS Zephyrus G-15 laptop, that has an AMD iGPU and an NVIDIA dGPU.
Due to this combo, I have run into a lot of weird problems in the past, without even knowing they were due to the GPU.

  • Resume from suspend broken
  • Extremely horrible battery life
  • System running too hot for the task
  • Some games lagging too much

This blog would be the most helpful to people who have an NVIDIA GPU, since sadly, it still doesn’t like to play well with Linux systems.

This article will have 3 main sections:

  1. How to set the main GPU as your iGPU in Hyprland
  2. How to configure hardware video decoding properly
  3. How to switch between your iGPU + dGPU to iGPU only for better battery performance

How to Set the Main GPU as Your Integrated GPU

Why would you want to do this?
Well, iGPUs are generally less power hungry, and are generally better supported in Linux.
Meaning you likely won’t run into weird flickering / black screens while using your iGPU.

Hyprland uses an Environment Variable called AQ_DRM_DEVICES.
This is a comma separated list of devices to use, ordered by priority.
The first device is the main GPU, and the second device is the secondary GPU, in case you connect an external monitor directly to your dGPU.
To get the device name, so that you can add it to the list, you have to follow some peculiar steps:

  1. Run lspci -d ::03xx to get all the available cards for rendering. The output should look like this:
❯ lspci -d ::03xx
01:00.0 VGA compatible controller: NVIDIA Corporation GA106M [GeForce RTX 3060 Mobile / Max-Q] (rev a1)
06:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Cezanne [Radeon Vega Series / Radeon Vega Mobile Series] (rev c5)

As you can see, I have 2 GPUs, an RTX 3060, having pci id 01:00.0, and an AMD Vega, having pci id 06:00.0.

  1. Create a symlink to the device cards and place them in /dev/dri

Linux exposes hardware through device nodes in /dev.
/dev/dri/ contains device nodes created by the DRM subsystem (Direct Rendering Manager).
For each card we need to set-up a udev rule, so that when the device is added, it creates a symlink for us to reference. So, in my case, I need 2 rules. For that I’ll make 2 files

  • /etc/udev/rules.d/igpu-device-path.rules
  • /etc/udev/rules.d/dgpu-device-path.rules
sudo touch /etc/udev/rules.d/igpu-device-path.rules
sudo touch /etc/udev/rules.d/dgpu-device-path.rules

Now, we need to create the rules. Copy everything as is, just change the pci ids and the SYMLINK names

So, Since my AMD card is 06:00.0, the rule will look like this(Note we prepend the pci ids with 000): File: /etc/udev/rules.d/igpu-device-path.rules

KERNEL=="card*", KERNELS=="0000:06:00.0", SUBSYSTEM=="drm", SUBSYSTEMS=="pci", SYMLINK+="dri/amd-igpu"

And since my RTX card is 01:00.0, the rule will look like this(Note we prepend the pci ids with 000): File: /etc/udev/rules.d/dgpu-device-path.rules

KERNEL=="card*", KERNELS=="0000:01:00.0", SUBSYSTEM=="drm", SUBSYSTEMS=="pci", SYMLINK+="dri/nvidia-dgpu"
  1. Reload the udev rules to apply the changes:
sudo udevadm control --reload-rules
sudo udevadm trigger
  1. See your new symlinks in /dev/dri:
❯ ls /dev/dri
amd-igpu  by-path  card1  card2 nvidia-dgpu renderD128  renderD129
  1. Set the main GPU as your iGPU in Hyprland:

Add the following to your hyprland.conf

env = AQ_DRM_DEVICES, /dev/dri/amd-igpu:/dev/dri/nvidia-dgpu

Done. now you can restart and Hyprland will use your iGPU.

How to Configure Hardware Video Decoding Properly

Why do you need to set this up?
To stream ANY content, you need to decode the stream.
This decoding can be done on your CPU, but, its

  1. Slow
  2. Makes your computer hot
  3. Causes stutter at high resolution, high framerate content

Firefox supports hardware decoding most painlessly

check if your system supports it already

Download libva-utils

sudo pacman -S libva-utils

Run vainfo

❯ vainfo
Trying display: wayland
vainfo: VA-API version: 1.22 (libva 2.22.0)
vainfo: Driver version: Mesa Gallium driver 25.3.5-arch1.2 for AMD Radeon Graphics (radeonsi, renoir, ACO, DRM 3.64, 6.19.0-2-cachyos)
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileVC1Simple              :	VAEntrypointVLD
      VAProfileVC1Main                :	VAEntrypointVLD
      VAProfileVC1Advanced            :	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointEncSlice
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointEncSlice
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointEncSlice
      VAProfileHEVCMain               :	VAEntrypointVLD
      VAProfileHEVCMain               :	VAEntrypointEncSlice
      VAProfileHEVCMain10             :	VAEntrypointVLD
      VAProfileHEVCMain10             :	VAEntrypointEncSlice
      VAProfileJPEGBaseline           :	VAEntrypointVLD
      VAProfileVP9Profile0            :	VAEntrypointVLD
      VAProfileVP9Profile2            :	VAEntrypointVLD
      VAProfileNone                   :	VAEntrypointVideoProc

if your output looks like this, your system supports hardware decoding already, if not, there could be 2 reasons

  1. Drivers not present

If this is the case for you, please go through the Arch wiki

  1. vainfo is picking the wrong GPU for decoding

You need to set the LIBVA_DRIVER_NAME to the name of the driver you want to use

export LIBVA_DRIVER_NAME=radeonsi

Generally:
Nvidia -> nvidia
AMD -> radeonsi
Intel -> i965 or iHD

You can find the driver name by running:

❯ ls /usr/lib/dri/ -1 | grep 'drv_video.so'
d3d12_drv_video.so
nouveau_drv_video.so
nvidia_drv_video.so
r600_drv_video.so
radeonsi_drv_video.so
virtio_gpu_drv_video.so

and then edit the hyprland.conf accordingly

env = LIBVA_DRIVER_NAME, radeonsi

And voila! Most apps should now support hardware decoding.

How to Switch Between Your IGPU + DGPU to IGPU Only for Better Battery Performance

For this all you need is supergfxctl

sudo pacman -S supergfxctl

Get all supported modes:

❯ supergfxctl -s
[Integrated, Hybrid]

Check which mode you are in:

❯ supergfxctl -g
Hybrid

And then set the mode to Integrated:

❯ supergfxctl -m Integrated

When you want to game, set it back to Hybrid:

❯ supergfxctl -m Hybrid 

These are the most important steps for dual GPU systems.
I’ll update this post as I keep finding more peculiarity
Thanks for reading!