TL;DR: 下面的这些解决方案都集成到 moeOS 包里了, 可以照着那个 Repo 改

前提

自 Turing 之后的显卡都可以启用 Runtime D3 支持, 让 GPU 完全休眠节省电源.

moeOS 包已经开启了这项支持.

观察 GPU 的电源状态

1
watch cat /sys/class/drm/renderD12*/device/power_state

其中, D0 表示活跃中, D3cold 表示完全休眠.

在双显卡系统上, 一般 renderD128 是集成显卡, renderD129 是独立显卡.

如果休眠工作正常, 应当看见类似这样的输出:

1
2
3
4
Every 2.0s: cat /sys/class/drm/renderD128/device/power_state /sys/class/drm...  kimiblocks-moeos: Wed Aug 23 00:01:20 2023

D0
D3cold

GPU 无理由被唤醒

Wayland 下, 这种情况一般集中于打开应用程序 / 调用硬件解码时.

Native App

根据 ArchWiki 可以使用 __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json 避免加载 Nvidia 模块.

moeOS 包默认添加这个环境变量到 /etc/environment/moeOS-Nvidia-RTD3.conf 中, 使得 App 默认不会唤醒独立显卡.

设置这个环境变量之后, 还需要注意使用独立显卡运行 Native Wayland 程序时去除上文设置的环境变量. (env -u ...)

moeOS 包提供了一个 prime-run 脚本来自动修改这个环境变量.

Vulkan App

根据 ArchWiki, 可以使用 VK_ICD_FILENAMES 环境变量来指定 Vulkan 驱动.

目前 Intel iGPU 应当使用

1
VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/intel_icd.x86_64.json:/usr/share/vulkan/icd.d/intel_icd.i686.json

AMD APU 应当使用

1
VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/radeon_icd.i686.json:/usr/share/vulkan/icd.d/radeon_icd.x86_64.json

播放器

集中在 libmpv 套壳播放器中, 例如 Haruna 与 Celluloid. 会出现明明指定使用 VA-API 硬件解码却依然唤醒 GPU 的问题.

mpv (or libmpv)

这是因为 libmpv 与 mpv 的行为有差异:

在 mpv 中 gpu-hwdec-interop 默认的参数为 auto, 也就是动态按需加载 Interop 上下文 (理解为硬件解码驱动); 而 libmpv 却没有这种动态加载机制, 默认参数为 all. 导致了本不该被加载的驱动被加载.

在我所知道的三个 libmpv 播放器里, Celluloid 可以修改命令行参数 --gpu-hwdec-interop=vaapi 达到效果

moeOS 包附带了 /usr/share/moeOS-Docs/Celluloid.d/celluloid.options 以便直接导入配置文件.

Haruna? 找不到修改 libmpv 参数的方法大概是没救了.

WiliWili 是另一个常用的 libmpv 播放器, 使用 aur/wiliwili-wayland隐藏 NVIDIA GPU.

GStreamer

GStreamer 中可能会出现 NVDEC 解码器优先级高于 VAAPI 的情况, 需要设定

1
GST_PLUGIN_FEATURE_RANK=vah264dec:512,vaav1dec:512,vah264lpenc:512,vah265dec:512,vah265lpenc:512,vajpegdec:512,vampeg2dec:512,vavp8dec:512,vavp9dec:512,vacompositor:512

Flatpak App

Flatpak 应用的处境比较复杂: Flatpak 会自动下载匹配 Host Nvidia 驱动版本的运行时.

这时需要使用 flatpak-mask 功能禁止 Flatpak 安装指定特征的包:

1
2
flatpak mask 'org.freedesktop.Platform.GL32.nvidia*'
flatpak mask 'org.freedesktop.Platform.GL.nvidia*'

这样就会禁用 Flatpak 自动下载并安装任何 Nvidia Runtime. 不过, 已安装的 Runtime 并不会被清除, 你需要自行使用 flatpak list | grep GL 找出包并卸载它们. (若 Flatpak 提醒应用需要 Runtime, 直接忽略即可)

这么做带来的问题是无法让 Flatpak 应用运行在独立显卡上, 并引入了一个全新的问题: 许多应用的 EGL 显示会出问题. 症状包括但不限于: Wemeet 闪退, Cavalier 和许多 App 提示 Failed to create EGL display, 或许还有明显的动画卡顿.

还记得前面设置的 __EGL_VENDOR_LIBRARY_FILENAMES 吗?

Flatpak 内无法读取设置的 EGL 库文件 (非充分确定, 更正请求), 于是造成了前面的 Failed to create EGL display 问题.

moeOS 包在安装时会运行 flatpak override --unset-env=__EGL_VENDOR_LIBRARY_FILENAMES 避免这个问题.

不要忘记使用同样的方法忽略 VK_ICD_FILENAMES (moeOS 包还没做, 扁包里能用到 Vulkan 的场景似乎不多…)

Chromium / Electron

使用 bwrap 隐藏 /dev/nvidia*:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
bwrap \
--symlink usr/lib /lib \
--symlink usr/lib64 /lib64 \
--symlink usr/bin /bin \
--symlink usr/bin /sbin \
--ro-bind /usr /usr \
--ro-bind /etc /etc \
--dev /dev \
--dev-bind /dev/dri /dev/dri \
--dev-bind /dev/shm /dev/shm \
--bind /proc /proc \
--ro-bind /sys/dev/char /sys/dev/char \
--ro-bind /sys/devices /sys/devices \
--bind /run /run \
--tmpfs /tmp \
--bind "$HOME" "$HOME" \
--setenv GTK_IM_MODULE ibus \
/usr/bin/chromium \
--gtk-version=4 \
--ozone-platform-hint=auto \
--enable-features=VaapiVideoDecodeLinuxGL,VaapiVideoDecoder \
$@