跳转到内容

外接显卡

来自 Arch Linux 中文维基

在搭载了雷电 3+USB4的设备上,可以通过显卡拓展坞连接一张桌面级的外接显卡(eGPU)。eGPU.io 是一个专门讨论外接显卡的社区论坛。尽管大多数时候仍需一些手动配置(如下),Linux 对外接显卡的支持相当不错。

注意:对于搭载了 USB4 的笔记本,其传输速率一般被设置为最小值(20 Gbit/s)。可以手动将其设置得更高(40,80 或更高)来获取更佳的体验。如果您的拓展坞使用雷电接口,可以启用笔记本的 USB4 模式来达到相同效果。

安装[编辑 | 编辑源代码]

雷电[编辑 | 编辑源代码]

使用雷电接口的拓展坞在插入前可能首先需要经过设备认证(取决于 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#将独立显卡作为主 GPUPRIME#反向 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 使用十进制的总线 ID,但大多数工具使用十六进制。在 xorg.conf 中,必须将形如 1a:10.3 的总线 ID转换为 26:16:3
提示:在更新的 Xorg 中,无需指定 ServerLayoutScreen 项,这些项将会被自动推断。 第一个定义的 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#ConfigurationXinit

Vulkan 可能会自行枚举 Xorg 上的所有显卡,所以如果要在本配置下执行如 vkcube 这样的程序,可能需要传递参数 --gpu_number 1。另外,也可以使用此参数以在枚举期间对显卡重新排序:__NV_PRIME_RENDER_OFFLOAD=1 vkcube 或者等效的 prime-run vkcube

提示:在笔记本上使用 optimus-manager 时,仅需将外接显卡的 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#配置应用程序使用 GPU 渲染

附注: 也许应该在专门的页面探讨这些问题,而不是在这里。(在 Talk:外接显卡 中讨论)

要让某些程序在外接显卡上渲染,可以用以下方式启用 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 的命名也稍有不同。

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 混成器尚无对显卡热插拔的明确支持,不过大多数混成器已经在某种程度上支持了:

使用开源驱动时,需要这样执行 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-drmmodprobe 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

前两个命令需要执行两次,这看起来尽管很奇怪,不过只有这样才能重新启动独立显卡。第一次执行命令时可能会报错,不过这并不重要。