外部 GPU
在配备了 Thunderbolt 3+ 或 USB4 的计算机上,可以使用 GPU 扩展坞连接桌面级独立显卡 (eGPU)。eGPU.io 是一个很好的资源,提供购买指南和社区论坛。虽然大多数操作模式需要一些手动配置(如下所示),但 Linux 对 eGPU 的支持总体上良好。
安装
Thunderbolt
eGPU 扩展坞 Thunderbolt 设备可能需要在插入后首先进行授权(基于您的 BIOS/UEFI 固件配置)。请按照 Thunderbolt#用户设备授权 进行操作。如果成功,外部显卡应在 lspci
中显示。
$ lspci -d ::03xx
00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 620 (rev 07) # internal GPU 1a:10.3 VGA compatible controller: NVIDIA Corporation GP107 [GeForce GTX 1050] (rev a1) # external GPU
根据您的计算机、其固件和扩展坞固件,Thunderbolt 会在一定程度上限制主机 <-> eGPU 带宽,这是由于 PCIe 通道数量和 OPI 模式。
# dmesg | grep PCIe
[19888.928225] pci 0000:1a:10.3: 8.000 Gb/s available PCIe bandwidth, limited by 2.5 GT/s PCIe x4 link at 0000:05:01.0 (capable of 126.016 Gb/s with 8.0 GT/s PCIe x16 link)
驱动程序
应安装与您的 GPU 型号兼容的驱动程序。
如果安装成功,lspci -k
应显示驱动程序已与您的显卡关联。
$ lspci -k -d ::03xx
1a:10.3 VGA compatible controller: NVIDIA Corporation GP107 [GeForce GTX 1050] (rev a1) Subsystem: NVIDIA Corporation GP107 [GeForce GTX 1050] Kernel driver in use: nvidia Kernel modules: nouveau, nvidia_drm, nvidia
AMDGPU
请注意,AMDGPU 驱动程序(无论使用 Thunderbolt 还是 USB4)在某些情况下可能会设置错误的 pcie_gen_cap 选项,并回退到 PCIe gen 1.1 速度,这可能会导致严重的性能问题。在这种情况下,可以将正确的值设置为模块选项(请参阅 内核模块#使用 modprobe.d)甚至作为 内核参数 传递。
/etc/modprobe.d/amd-egpu-pcie-speed.conf
options amdgpu pcie_gen_cap=0x40000
这将设置 PCIe gen 3 速度。完整的选项列表可以在 amd_pcie.h 中找到。
NVIDIA
对于某些系统上的 NVIDIA eGPU,您可能需要提前加载 thunderbolt 内核模块,以确保它在 nvidia_drm
之前加载。
- 如果您使用 mkinitcpio initramfs,请按照 mkinitcpio#MODULES 添加模块。
- 如果您使用 Booster,请按照 Booster#早期模块加载 进行操作。
- 如果您使用 dracut,请按照 dracut#早期内核模块加载 进行操作。
仅计算工作负载
完成 安装步骤 后,像 GPGPU#CUDA 这样不需要显示任何内容的仅计算工作负载应该无需任何额外配置即可工作。nvidia-smi 实用程序(由 nvidia-utils 软件包提供)应与闭源 NVIDIA 驱动程序一起工作。闭源 NVENC/NVDEC 应该可以工作(没有 OpenGL 互操作)。
此用例还应支持完全热插拔。热拔插也应该是可能的(可能取决于使用的驱动程序)。在 NVIDIA 上,活动的 nvidia-persistenced
预计会阻止干净的热拔插。
Xorg
内部 (iGPU) 和外部 (eGPU) 显卡的多种组合设置是可能的,每种设置都有自己的优点和缺点。
Xorg 在 eGPU 上渲染,PRIME 显示卸载到 iGPU
- 大多数使用 GPU 的程序在 eGPU 上开箱即用:
glxinfo
/glxgears
、eglinfo
/eglgears_x11
、NVENC
/NVDEC
(包括 OpenGL 互操作)。 - Xorg 仅在插入 eGPU 时启动。
- 连接到 eGPU 的显示器开箱即用,PRIME 显示 卸载可用于连接到 iGPU 的显示器(即笔记本电脑的内置屏幕)。
主要文章是 PRIME#反向 PRIME。NVIDIA 驱动程序文档 第 34 章:使用 RandR 1.4 卸载图形显示 中也对此进行了说明。
使用如下所示的 Xorg 配置代码段:
/etc/X11/xorg.conf.d/80-egpu-primary-igpu-offload.conf
Section "Device" Identifier "Device0" Driver "nvidia" BusID "PCI:26:16:3" # Edit according to lspci, translate from hex to decimal. Option "AllowExternalGpus" "True" # Required for proprietary NVIDIA driver. EndSection Section "Module" # Load modesetting module for the iGPU, which should show up in XrandR 1.4 as a provider. Load "modesetting" EndSection
1a:10.3
转换为 26:16:3
以用于 xorg.conf
代码段。ServerLayout
和 Screen
部分,因为这些是自动推断的。定义的第一个 Device
将被视为主设备。要验证此设置,请使用 xrandr --listproviders
,它应显示:
Providers: number : 2 Provider 0: id: 0x1b8 cap: 0x1, Source Output crtcs: 4 outputs: 4 associated providers: 0 name:NVIDIA-0 Provider 1: id: 0x1f3 cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 3 outputs: 5 associated providers: 0 name:modesetting
要输出到笔记本电脑的内置屏幕和/或连接到 iGPU 的其他显示器,可以使用 RandR 1.4 PRIME 显示 卸载,使用上面 xrandr --listproviders
输出中的名称:
xrandr --setprovideroutputsource modesetting NVIDIA-0 && xrandr --auto
xrandr --auto
是可选的,可以替换为任何基于 RandR 的显示配置工具。它的存在可以防止所有屏幕变黑的情况。您可能希望在显示管理器显示登录提示或桌面环境启动之前运行此命令,请参阅 xrandr#配置 和 xinit。
Vulkan 可能会独立于 Xorg 枚举 GPU,因此为了在此设置中运行例如 vkcube
,可能需要传递 --gpu_number 1
选项。或者,可以激活一个层来重新排序 GPU 枚举,效果相同:__NV_PRIME_RENDER_OFFLOAD=1 vkcube
或等效的 prime-run vkcube
。
/etc/optimus-manager/xorg/
中为您的模式和显卡添加 eGPU 的 BusId
,从而在 eGPU 上渲染。Xorg 在 iGPU 上渲染,PRIME 渲染卸载到 eGPU
- 程序默认在 iGPU 上渲染,但可以使用 PRIME 渲染 卸载在 eGPU 上渲染它们。
- 即使 eGPU 断开连接,Xorg 也会启动,但渲染/显示卸载在重新启动之前将无法工作。
- 连接到 iGPU 的显示器(即笔记本电脑的内置屏幕)开箱即用,PRIME 显示 卸载可用于连接到 eGPU 的显示器。
主要文章是 PRIME#PRIME GPU 卸载。NVIDIA 驱动程序文档 第 35 章:PRIME 渲染卸载 中也对此进行了说明。
对于许多独立显卡驱动程序,此模式应为默认模式,无需任何手动 Xorg 配置。如果这不起作用,或者您使用闭源 NVIDIA 驱动程序,请使用以下方法:
/etc/X11/xorg.conf.d/80-igpu-primary-egpu-offload.conf
Section "Device" Identifier "Device0" Driver "modesetting" EndSection Section "Device" Identifier "Device1" Driver "nvidia" BusID "PCI:26:16:3" # Edit according to lspci, translate from hex to decimal. Option "AllowExternalGpus" "True" # Required for proprietary NVIDIA driver. EndSection
要验证此设置,请使用 xrandr --listproviders
,它应显示:
$ xrandr --listproviders
Providers: number : 2 Provider 0: id: 0x47 cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 3 outputs: 5 associated providers: 0 name:modesetting Provider 1: id: 0x24a cap: 0x2, Sink Output crtcs: 4 outputs: 4 associated providers: 0 name:NVIDIA-G0
要在 eGPU 上渲染 some_program
,可以使用 PRIME 渲染 卸载:
- 对于闭源 NVIDIA 驱动程序:
$ __NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only __GLX_VENDOR_LIBRARY_NAME=nvidia some_program
- 对于闭源 NVIDIA 驱动程序(便捷封装器):
$ prime-run some_program
- 对于开源驱动程序:
$ DRI_PRIME=1 some_program
要输出到连接到 eGPU 的显示器,可以再次使用 RandR 1.4 PRIME 显示 卸载:
$ xrandr --setprovideroutputsource NVIDIA-G0 modesetting && xrandr --auto
NVIDIA 驱动程序 460.27.04+ 为组合渲染和显示卸载的特殊情况实现了一个优化:
- 增加了对“反向 PRIME 旁路”的支持,这是一种优化,可在渲染卸载应用程序全屏、未重定向且仅在给定的 NVIDIA 驱动的 PRIME 显示卸载输出上可见的情况下,绕过 PRIME 渲染卸载和 PRIME 显示卸载的带宽开销。当在 X 服务器中启用详细日志记录时,优化的使用情况会在 X 日志中报告。
用于 eGPU 的独立 Xorg 实例
主要文章是 nvidia-xrun#外部 GPU 设置。
Xorg 上 eGPU 的已知问题
- 大多数独立显卡 Xorg 驱动程序不支持热插拔:eGPU 需要在 Xorg 启动时插入。注销并重新登录应该足以重启 Xorg。
- 完全不支持热拔插:这样做会导致系统不稳定或直接冻结(如 NVIDIA 文档 中所承认的那样)。
Wayland
Wayland 对 eGPU(或通常是多个 GPU)的支持测试较少,但应该可以工作,甚至需要更少的手动配置。
请注意,Wayland 合成器需要显式的 GPU 热插拔支持,但大多数已经具有一定程度的支持:
- KDE 的 kwin:https://invent.kde.org/plasma/kwin/-/merge_requests/811
- GNOME 的 Mutter:https://gitlab.gnome.org/GNOME/mutter/-/issues/17, https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1562
- wlroots:https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/1278
对于开源驱动程序,DRI 卸载工作正常。
$ DRI_PRIME=1 some_program
一些项目,例如 all-ways-egpu,正在尝试为 Wayland 下的 GPU 选择提供更有效的方法。
热插拔 NVIDIA eGPU
在使用 Wayland 时,可以热插拔 eGPU 并使用 PRIME 功能。NVIDIA 已经为 dGPU 提供了出色的 PRIME 实现,并且它对 eGPU 的工作方式相同。
首先,您需要确保没有程序使用 NVIDIA 模块。EGL 程序倾向于每个程序使用 1MB dGPU 内存,即使它们在 iGPU 上运行,这可以在 nvidia-smi
中看到。为避免这种情况,请添加 __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json
作为 环境变量。最好的位置是 /etc/environment.d/50_mesa.conf
。
然后,卸载 NVIDIA 模块:
# rmmod nvidia_uvm # rmmod nvidia_drm # rmmod nvidia_modeset # rmmod nvidia
当 NVIDIA 模块不再加载时,您可以连接外部 GPU。当 GPU 初始化后,使用 modprobe nvidia-drm
命令或 modprobe nvidia-current-drm
重新加载 NVIDIA 模块。命名取决于模块的来源,无论是来自 NVIDIA 网站的驱动程序还是来自软件包管理器。在某些情况下(例如,对于 GIGABYTE AORUS GAMING BOX),eGPU 不适用于闭源模块,因此您可能需要加载开源模块:modprobe nvidia-current-open-drm
。
当模块成功加载后,prime 功能将工作,但由于我们设置了 __EGL_VENDOR_LIBRARY_FILENAMES
变量以使用 MESA,我们需要在启动程序之前添加 __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/10_nvidia.json
。完整字符串将如下所示:
__GLX_VENDOR_LIBRARY_NAME=nvidia __NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/10_nvidia.json %command%
对于 GNOME 用户,您可能需要修补 switcheroo-control,以将 __EGL_VENDOR_LIBRARY_FILENAMES
包含到环境变量列表中。这将允许程序通过右键单击并选择“使用独立显卡启动”自然地在 eGPU 上运行。但这超出了本文的范围。
热插拔 NVIDIA eGPU 并临时禁用 NVIDIA dGPU
如果您有 iGPU、NVIDIA dGPU 并想连接 NVIDIA eGPU,您会遇到冲突,无论您做什么,图形都只会在 dGPU 上渲染。要解决此问题,您需要临时禁用 dGPU,以便 NVIDIA 驱动程序不会注意到它。最好的方法是覆盖其驱动程序。
首先,您需要卸载 NVIDIA 驱动程序:
# rmmod nvidia_uvm # rmmod nvidia_drm # rmmod nvidia_modeset # rmmod nvidia
然后,您需要使用 driverctlAUR 实用程序覆盖 dGPU 驱动程序。在此示例中,0000:01:00.0 是 dGPU 的地址。可以使用 lspci
实用程序找到它。
# driverctl --nosave set-override 0000:01:00.0 vfio-pci
重要的是使用 --nosave
参数,以防止 driverctl 在启动时覆盖驱动程序。如果出现问题,这将很有用,简单的重启即可清除一切。
禁用 dGPU 后,您可以使用 modprobe nvidia-drm
加载内核模块,然后检查 nvidia-smi
是否显示 1 个或 2 个 GPU。
重新启用 dGPU 很棘手,因为它不直观。首先,卸载 NVIDIA 模块,拔下 eGPU,然后运行以下一系列命令:
# modprobe nvidia-current # driverctl --nosave unset-override 0000:01:00.0 # modprobe nvidia-current # driverctl --nosave unset-override 0000:01:00.0 # modprobe nvidia-current-modeset # modprobe nvidia-current-drm
奇怪的是,我们需要先运行前 2 个命令两次,否则它不会重新启用 dGPU。命令会报错一次,但这并不重要。