外接显卡
在搭载了雷电 3+ 或 USB4的设备上,可以通过显卡拓展坞连接一张桌面级的外接显卡(eGPU)。eGPU.io 是一个专门讨论外接显卡的社区论坛。尽管大多数时候仍需一些手动配置(如下),Linux 对外接显卡的支持相当不错。
安装[编辑 | 编辑源代码]
雷电[编辑 | 编辑源代码]
使用雷电接口的拓展坞在插入前可能首先需要经过设备认证(取决于 BIOS/UEFI 配置)。详见 Thunderbolt#User device authorization。如果成功插入,外接显卡将在 lspci
中显示。
$ lspci | grep -E 'VGA|3D'
00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 620 (rev 07) # 集成显卡 1a:10.3 VGA compatible controller: NVIDIA Corporation GP107 [GeForce GTX 1050] (rev a1) # 外接显卡
根据电脑的硬件和拓展坞的硬件情况,雷电接口会限制主机与外接显卡间的带宽。限制程度取决于 PCIe 通道数和封装的DMI互联接口(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)
驱动[编辑 | 编辑源代码]
您应该安装与您的外接显卡兼容的驱动程序:
成功安装后,lspci -k
应当显示显卡与驱动已经成功绑定:
$ lspci -k
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 驱动(无论使用雷电接口还是 USB4)可能会被设置为错误的 pcie_gen_gap 模式,然后回滚到 PCIe 1.1 的速率。这可能会导致性能严重降低。 可以通过调整模块参数(见内核模块#使用 /etc/modprobe.d/中的文件) 或传递内核参数来解决以上问题。
/etc/modprobe.d/amd-egpu-pcie-speed.conf
options amdgpu pcie_gen_cap=0x40000
这会将速率设置为 PCIe 3 模式。完整的参数选项见 amd_pcie.h。
显卡计算[编辑 | 编辑源代码]
在完成 #安装之后,像 GPGPU#CUDA 这样无需在屏幕上显示的纯计算工作,理论上无需额外配置即可使用。nvidia-smi 工具(由 nvidia-utils包 提供)在使用专有 NVIDIA 驱动时应该能正常运行。专有的 NVIDIA NVENC/NVDEC 也应该正常运行(不包括与 OpenGL 的互操作)。
在这种使用场景下,热插拔也应该受支持(对拔出支持取决于驱动程序)。不过,对于 NVIDIA 设备,使用 nvidia-persistenced
会导致热拔出时设备出现故障。
Xorg[编辑 | 编辑源代码]
通过一些额外配置,您可以将集成显卡(iGPU)和外接显卡(eGPU)结合起来使用。这样配置有其优点,但也会带来一些额外的问题。
Xorg 在外接显卡上渲染,PRIME 显示分载到集成显卡[编辑 | 编辑源代码]
- 大多数使用显卡的程序可以正常执行在外接显卡上:
glxinfo
/glxgears
,eglinfo
/eglgears_x11
,NVENC
/NVDEC
(包括与 OpenGL 的互操作)。 - Xorg 仅能在外接显卡接入后启动。
- 连接到外接显卡上的显示器开箱即用,而 PRIME显示分载适用于连接到集成显卡的显示器(例如笔记本内屏)。
有关这些内容,见 PRIME#将独立显卡作为主 GPU 和 PRIME#反向 PRIME。 同时,NVIDIA 官方驱动文档也有教程: Chapter 33. Offloading Graphics Display with 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" # 根据 lspci 填写,将十六进制转换为十进制。 Option "AllowExternalGpus" "True" # 专有 NVIDIA 驱动所需。 EndSection Section "Module" # 为集成显卡加载 modesetting 模块,其提供程序应当是 XrandR 1.4。 Load "modesetting" EndSection
xorg.conf
中,必须将形如 1a:10.3
的总线 ID转换为 26:16:3
。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
要输出到笔记本内屏及其他连接到集成显卡上的显示,可以使用 RandR 1.4 PRIME显示分载。请使用 xrandr --listproviders
输出的设备名:
xrandr --setprovideroutputsource modesetting NVIDIA-0 && xrandr --auto
xrandr --auto
是可选的命令,可以使用其他任何基于 RandR 的显示配置工具替代。这条命令只是防止出现屏幕全黑的情况。要在显示管理器弹出登录页面或启动桌面环境之前执行这条命令,见 Xrandr#Configuration 和 Xinit。
Vulkan 可能会自行枚举 Xorg 上的所有显卡,所以如果要在本配置下执行如 vkcube
这样的程序,可能需要传递参数 --gpu_number 1
。另外,也可以使用此参数以在枚举期间对显卡重新排序:__NV_PRIME_RENDER_OFFLOAD=1 vkcube
或者等效的 prime-run vkcube
。
BusID
放入位于 /etc/optimus-manager/xorg/
下的管理模式与显卡的配置文件中,就可以在外接显卡上渲染。Xorg 在集成显卡上渲染,PRIME 渲染分载到外接显卡[编辑 | 编辑源代码]
- 程序默认在集成显卡上渲染,但 PRIME 渲染分载可以使程序在外接显卡上渲染。
- Xorg 可以在未连接外接显卡时启动,但在连接外接显卡后,必须重启 Xorg 才能使用渲染与显示分载。
- 连接到集成显卡上的显示器(例如笔记本内屏)开箱即用,而 PRIME 显示分载适用于连接到外接显卡上的显示器。
详细内容见 PRIME#PRIME 显卡分载。NVIDIA 官方驱动文档中也有记录:Chapter 34. PRIME Render Offload。
对大多数独立显卡而言,此模式应当是默认模式,无需手动配置 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" # 根据 lspci 填写,将十六进制转换为十进制。 Option "AllowExternalGpus" "True" # 专有 NVIDIA 驱动所需。 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
要让某些程序在外接显卡上渲染,可以用以下方式启用 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
要输出到连接至外接显卡的显示器,还可以这样使用 RandR 1.4 PRIME 显示分载:
$ xrandr --setprovideroutputsource NVIDIA-G0 modesetting && xrandr --auto
NVIDIA 驱动版本 460.27.04+ 优化了在一些特定情形下对渲染和显示分载的结合支持:
- 添加了对 “反向 PRIME 绕行”(Reverse PRIME Bypass)的支持,这使得当某一渲染分载程序处于全屏,非重定向,且仅在给定的使用 NVIDIA 驱动的 PRIME 显示分载输出中显示时,可以绕过 PRIME 渲染分载和 PRIME 显示分载的带宽限制。当 X 服务器启用详细日志时,可以在 X 日志中找到此特性的使用情况。
在外接显卡上执行多个独立 Xorg 实例[编辑 | 编辑源代码]
详见 Nvidia-xrun#External GPU setup.
在 Xorg 上使用外接显卡的已知问题[编辑 | 编辑源代码]
- 大多数独立显卡的 Xorg 驱动不支持热插入:必须在启动 Xorg 前插入外接显卡。注销后重新登录即可重启 Xorg。
- 完全不支持热拔出:这样会导致系统不稳定或卡死(根据 NVIDIA 官方文档)。
Wayland[编辑 | 编辑源代码]
有关 Wayland 对外接显卡(或多显卡)支持程度的测试目前尚为数不多,不过理论上其相对于 Xorg 来说配置会更为便捷。
需要注意的是,Wayland 混成器尚无对显卡热插拔的明确支持,不过大多数混成器已经在某种程度上支持了:
- KDE's kwin: https://invent.kde.org/plasma/kwin/-/merge_requests/811
- GNOME's Mutter: https://gitlab.gnome.org/GNOME/mutter/-/issues/17, https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1562
- wl-roots: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/1278
使用开源驱动时,需要这样执行 DRI 分载:
$ DRI_PRIME=1 some_program
一些像 all-ways-egpu 这样的项目正致力于在 Wayland 下提供更为便捷的显卡切换方法。
热插拔 NVIDIA 外接显卡[编辑 | 编辑源代码]
Wayland 支持在使用 PRIME 时热插拔外接显卡。NVIDIA 独立显卡对 PRIME 的优秀支持同样适用于外接显卡。
首先,确保没有进程正在使用 NVIDIA 模块。每个 EGL 程序会占用 1MB 的独显显存,即使其运行在集成显卡上。可以通过 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
模块卸载完成后,就可以连接外接显卡。显卡初始化完毕后,使用 modprobe nvidia-drm
或 modprobe nvidia-current-drm
重新加载 NVIDIA 模块。使用哪条命令取决于模块的来源,例如从 NVIDIA 官网下载或是使用软件包管理器直接安装。在某些情况下(例如 GIGABYTE AORUS GAMING BOX)外接显卡可能不兼容专有驱动,因此需要使用开源驱动的命令: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
包含到环境变量中。这将允许程序原生运行在外接显卡上,不会出现鼠标错位,而且能“使用独立显卡启动”。不过,关于如何修补,就不在本篇文章的讨论范围之内了。
热插拔 NVIDIA 外接显卡,并临时停用 NVIDIA 独立显卡[编辑 | 编辑源代码]
如果您同时拥有集成显卡(iGPU)和 NVIDIA 独立显卡(dGPU),并且尝试连接 NVIDIA 外接显卡(eGPU),显卡间会产生冲突,这会导致只有独立显卡能够使用。要解决冲突,必须临时停用独立显卡,这样 NVIDIA 驱动就不会识别到它。最好的方法就是覆盖驱动。
首先,卸载 NVIDIA 驱动模块:
# rmmod nvidia_uvm # rmmod nvidia_drm # rmmod nvidia_modeset # rmmod nvidia
然后,使用 driverctlAUR 工具覆盖独立显卡驱动。在下面的例子中,使用 0000:01:00.0 代表独立显卡的地址。您设备的独立显卡地址可以使用 lspci
查看。
# driverctl --nosave set-override 0000:01:00.0 vfio-pci
建议使用参数 --nosave
,否则 driverctl 会在系统启动时覆盖驱动。这样,在出错的时候,仅需重启就可以恢复独立显卡。
独立显卡禁用后,就可以使用 modprobe nvidia-drm
加载内核模块,然后使用 nvidia-smi
检查其显示一张或两张显卡。
重新启动独立显卡有点麻烦,因为它很反直觉。首先,卸载 NVIDIA 模块,拔出外接显卡,然后执行以下命令:
# 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
前两个命令需要执行两次,这看起来尽管很奇怪,不过只有这样才能重新启动独立显卡。第一次执行命令时可能会报错,不过这并不重要。