The Situation
I had troubles getting the dGPU to work on Fedora 44 using the Cosmic Desktop.
Normally, calling a program with the prefix DRI_PRIM=1 should force it to use the dGPU (given that 1 is actually the dGPU), but this did not work correctly on my machine.
I found a way to force the dGPU globally and I wanted to share this with you in case someone finds it usefull.
A few notes before we start:
- it forces the dGPU for the whole desktop, so battery draw will increase
- it is Cosmic specific and won’t work on other Desktop envs
- the config file is only loaded on log-in, so you need to log-out / -in after changes
- it does not skip the iGPU, the rendering is done on dGPU but it is still routed through the iGPU. While this increased perfomance on my 3D rendering, it also introduced a delay when opening the Cosmic overview (super + w). That felt snappier before. But so far that’s the only place I noticed a delay.
Working Solution
1. Find GPU devices and their pci slot
switcherooctl list
2: Map existing render nodes to pci slots
for r in /sys/class/drm/renderD*; do
echo "$r -> $(cat $r/device/uevent | grep PCI_SLOT_NAME)"
done
3. Force Cosmics compositor to set dGPU as primary render device
replace <n>with the device node that matches with the pci slot your dGPU uses.
mkdir -p ~/.config/environment.d
echo "COSMIC_RENDER_DEVICE=renderD<n>" > ~/.config/environment.d/cosmic-gpu.conf
Background Information
Just some notes I wrote along the way because I found them interesting.
card vs renderD
Each physical GPU exposes two separate DRM device nodes under the same kernel driver instance:
cardN(/dev/dri/cardN) — the full KMS (Kernel Mode-Setting) device. This is the “display” interface: it controls CRTCs, connectors, framebuffers, mode-setting, cursor — everything needed to actually drive a screen. This is what a compositor uses when it needs to scan out to a physical display.renderDN(/dev/dri/renderDN) — a render-only node. No display/mode-setting authority at all — just submit rendering/compute work and get buffers back. This is what unprivileged clients (Mesa, EGL contexts, compute workloads) use, and it’s also what a compositor uses internally just for rendering (as opposed to scanning out).
you can map the cardN just like the renderDN:
for c in /sys/class/drm/card[0-9]; do
echo "$c -> $(cat $c/device/uevent | grep PCI_SLOT_NAME)"
done
The cosmic config variable expects the render node since it does not control which GPU actually drives the display. This is still done by the iGPU, just the rendering is now done by the dGPU.
watch busy%
You can watch how busy the GPUs are by echoing the cardN endpoints:
watch -n0.5 "cat /sys/class/drm/card1/device/gpu_busy_percent; echo ---; cat /sys/class/drm/card2/device/gpu_busy_percent"
Just check which N corresponds to which GPU before.
This aligns with the values the Minimon applet reports, so you might as well use the applet instead.
test dGPU in isolation
There might be a number of reasons a GPU is not used by the browser (more on that below), so it is useful to test the GPU with very basic tools first.
1. Vulkan
Find out which device uses which index with:
vulkaninfo --summary | grep deviceName
display a spinning cube rendered on that device:
vkcube --gpu_number 1
2. OpenGL
Better test if your goal is hardware accel in browser since they use OpenGL
DRI_PRIME=pci-<PCI-SLOT> glxgears
Make sure to select the correct pci slot for the dGPU
Browser Option to check
1. Is the browser installed as flatpak or native?
If it is a flatpak you might need to set the permissions to have access to the dGPU. You can do that using flatseal.
2. Check browser settings
For hardware or GPU acceleration and make sure that is turned on
3. Diagnose
There are logs that tell you which device is used for the graphics.
brave://gpuon braveabout:supporton firefox, scroll down to the graphics section
4. Test
Use this aquarium if you need a website with 3D rendering.
alternatives
If you are using a different desktop env or just want to test a few things I tested here is a list of things to try:
Note: instead of an index you can assign the pci bus to DRI_PRIME.
1. Force DRI device
DRI_PRIME=pci-<PCI-SLOT> MOZ_ENABLE_WAYLAND=1 firefox
flatpak run --env=DRI_PRIME=pci-<PCI-SLOT> com.brave.Browser
This might work on a different desktop env, it did not for me.
2. Force Xwayland instead of Wayland
GDK_BACKEND=x11 MOZ_ENABLE_WAYLAND=0 DRI_PRIME=pci-<PCI-SLOT> firefox
This should have worked since apps like glxgears accepted the DRI flag running on Xwayland.
Haven’t checked if firefox accepted the switch to Xwayland or not so there might be the issue.
Note that you loose Wayland features if you switch (like factional scaling).