Published on
· 7 min read

Fixing Poor Battery Life on Linux Laptops with Hybrid Graphics: The RTD3 Solution

Authors

Hybrid Graphics Battery Optimization

If you’ve recently installed Linux on a laptop with hybrid graphics—particularly one with Intel integrated graphics paired with an Nvidia GPU—you might have noticed dramatically shorter battery life compared to Windows. The culprit is often your discrete Nvidia GPU failing to enter its power-saving mode called RTD3 (Runtime D3).

The Problem with Default Configurations

Linux distributions don’t configure hybrid graphics systems with necessary power-saving features by default. This means your Nvidia GPU might be consuming power continuously, even when you’re only using the Intel integrated graphics for basic tasks like web browsing or document editing.

In hybrid systems with Intel/Nvidia configurations, the Nvidia GPU should automatically enter D3cold (the deepest power-saving state) when not in use. However, many users find their GPU stuck in the D0 state, actively consuming battery power.

Checking Your GPU’s Power State

Before applying any fixes, you should first check if your hybrid GPU is entering power-saving mode. Use these commands to verify your current power state:

# List PCI devices to find your Nvidia GPU device ID
lspci | grep -i nvidia

# Check if your GPU supports RTD3 (replace device ID with yours)
cat /proc/driver/nvidia/gpus/0000:01:00.0/power

# Check current power state
cat /sys/class/drm/card*/device/power_state

# Check runtime status
cat /sys/bus/pci/devices/0000:01:00.0/power/runtime_status

If you see “Runtime D3 status: Not supported” or your power state shows “D0” instead of “D3cold,” your GPU isn’t entering power-saving mode.

Prefer the sysfs checks above for verification. Tools like nvidia-smi briefly wake the dGPU, so they can hide a healthy idle state if you check too soon after running them.

The Solution: Manual RTD3 Configuration

Here’s how to properly configure RTD3 power management (Similar steps apply for AMD GPUs, but this guide focuses on Nvidia):

Step 0: Prerequisites

Ensure you’re using the proprietary Nvidia drivers (not Nouveau or open-source alternatives).

Step 1: Configure Nvidia Power Management

Create /etc/modprobe.d/nvidia-pm.conf with the following content:

# For me, below two options were already coming from /usr/lib/modprobe.d/nvidia-* files
# options nvidia NVreg_PreserveVideoMemoryAllocations=1
# options nvidia NVreg_TemporaryFilePath=/var/tmp
options nvidia-drm modeset=1
options nvidia "NVreg_DynamicPowerManagement=0x02" # Use 0x03 for Ampere and later GPUs
options nvidia NVreg_UsePageAttributeTable=1 NVreg_InitializeSystemMemoryAllocations=0
options nvidia NVreg_EnableGpuFirmware=0
options nvidia NVreg_EnableS0ixPowerManagement=1
# Default DynamicPowerManagementVideoMemoryThreshold is 200 (MiB): RTD3 is allowed
# when allocated VRAM is at or below that ceiling. Only needed if you want a tighter
# limit (e.g. 10) after you confirm idle VRAM usage with nvidia-smi.
# options nvidia NVreg_DynamicPowerManagementVideoMemoryThreshold=10

Note: For Turing GPUs (like MX450), use NVreg_DynamicPowerManagement=0x02. Ampere and later GPUs can use 0x03.

Step 2: Check and modify Udev Rules

Inspect /etc/udev/rules.d/80-nvidia-pm.rules (Create it if it doesn’t exist) and ensure that it contains the following rules:

# Remove NVIDIA USB xHCI Host Controller devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1"

# Remove NVIDIA USB Type-C UCSI devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1"

# Remove NVIDIA Audio devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1"

# Enable runtime PM for NVIDIA VGA/3D controller devices on adding device
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"

# Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"

# Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"

Step 3: Update Initramfs and Reboot

For EndeavourOS with dracut:

sudo dracut-rebuild

For Arch Linux:

sudo mkinitcpio -P

For other distributions, use the appropriate command to rebuild your initramfs

Step 4: Enable Nvidia Persistence Daemon

systemctl status nvidia-persistenced
sudo systemctl enable --now nvidia-persistenced

Reboot and Verify

Check if RTD3 is working:

# Should show "Runtime D3 status: Enabled (fine-grained)"
cat /proc/driver/nvidia/gpus/0000:01:00.0/power

# Should show "suspended" when GPU is idle
cat /sys/bus/pci/devices/0000:01:00.0/power/runtime_status

# Should show "D3cold" for the Nvidia card when idle
cat /sys/class/drm/card*/device/power_state

When RTD3 is Enabled but the GPU Stays in D0 (KDE Plasma / Wayland)

After the modprobe and udev setup above, you may still see:

  • Runtime D3 status: Enabled (fine-grained)
  • but runtime_status = active and power_state = D0

In that case the driver stack is fine; something is keeping a client on the dGPU.

Who is holding the GPU?

nvidia-smi

On an older working setup, only something like Xorg (PRIME / XWayland) might appear with a few MiB. If kwin_wayland also shows up (often type C+G), Plasma is opening the Nvidia device and can prevent D3cold even when the compositor is “idle.”

Why KWin hits Nvidia on hybrid laptops

  1. DRM device order may list Nvidia as an available GPU.
  2. GLVND EGL vendor files prefer Nvidia first on many installs:
/usr/share/glvnd/egl_vendor.d/10_nvidia.json
/usr/share/glvnd/egl_vendor.d/50_mesa.json

So KWin can open Nvidia via EGL even when the panel is driven by Intel.

What does not fix this (common false leads)

HypothesisNotes
NVreg_DynamicPowerManagementVideoMemoryThresholdDefault 200 MiB is a ceiling: RTD3 allowed if allocated VRAM ≤ threshold. Tightening to 10 is optional, not required for a few MiB of idle clients.
Switching LTS vs custom kernelsCan be ruled out if both stay in D0 with the same clients.
nvidia-smi -pm 0 / stopping nvidia-persistencedWorth testing, but persistence alone may not be the hold if KWin is on the dGPU.
Putting env vars in ~/.zshrcDoes not work for KWin. The compositor starts from SDDM/Plasma before your shell.

Fix: keep KWin on Intel + Mesa EGL only

Map which DRM card is Intel (vendor 0x8086) vs Nvidia (0x10de):

for c in /sys/class/drm/card[0-9]; do
  echo "$(basename $c): vendor=$(cat $c/device/vendor) driver=$(basename $(readlink $c/device/driver))"
done

Example on one ThinkPad hybrid setup: card1 = nvidia, card2 = i915. Adjust paths if your numbering differs.

Create an executable Plasma session env script (not your shell profile):

mkdir -p ~/.config/plasma-workspace/env

~/.config/plasma-workspace/env/kwin-intel.sh:

#!/bin/sh
# Prefer Intel for KWin display; force Mesa EGL so GLVND does not pick NVIDIA.
export KWIN_DRM_DEVICES=/dev/dri/card2
export __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json
chmod +x ~/.config/plasma-workspace/env/kwin-intel.sh

Then fully log out and back in, or reboot.

Important: KWIN_DRM_DEVICES alone may still leave KWin in nvidia-smi. Forcing Mesa via __EGL_VENDOR_LIBRARY_FILENAMES was required in practice so GLVND does not select Nvidia.

Verify after the KWin fix

# Env should appear on the wrapper
tr '\0' '\n' < /proc/$(pgrep -n kwin_wayland_wrapper)/environ | grep -E 'KWIN_DRM|EGL_VENDOR'

# kwin_wayland should no longer list under NVIDIA (Xorg alone for PRIME is OK)
nvidia-smi

# Real power check (wait after any nvidia-smi)
sleep 15
cat /sys/bus/pci/devices/0000:01:00.0/power/runtime_status   # suspended
cat /sys/bus/pci/devices/0000:01:00.0/power_state              # D3cold
# or: cat /sys/class/drm/card*/device/power_state

With this in place, RTD3 returned to suspended / D3cold while modprobe/udev settings were already correct.

Important Notes and Additional Recommendations

  • Avoid continuous use of monitoring tools that query GPU status frequently, such as nvidia-smi or nvtop, since these can prevent the Nvidia GPU from entering its deepest power-saving state (D3cold), leading to unnecessary power use.
  • Use power optimization tools like Powertop and auto-cpufreq alongside this configuration. Powertop analyzes power consumption and suggests tunings to reduce power drain across your system, while auto-cpufreq automatically adjusts CPU frequency and power profiles based on usage and battery health, helping extend battery life without manual intervention.
  • Xorg may still appear in nvidia-smi with a few MiB for PRIME/XWayland; that alone is often compatible with fine-grained RTD3. A persistent KWin client on Nvidia is the more common modern regression under Plasma Wayland.
  • This solution has been tested on EndeavourOS but should apply with minor tweaks to Arch and other Linux distributions that support Nvidia proprietary drivers and RTD3.

By combining RTD3 configuration with Powertop and auto-cpufreq—and keeping the compositor off the dGPU under Wayland—you can significantly improve battery life on hybrid Intel/Nvidia laptops running Linux.

For an in-depth discussion and step-by-step instructions used for an Nvidia MX450 on EndeavourOS, check out the full post: Nvidia/Intel Hybrid Graphics poor battery life: Nvidia not entering D3 (RTD3)

With these configurations, my years old thinkpad is showing 6+ hours battery life although realistically it’s around 4+ hours with normal usage, which is a significant improvement over the previous 2-3 hours.

Powertop screenshot with 6+ hours of remaining battery