在搭載了雷電 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
前兩個命令需要執行兩次,這看起來儘管很奇怪,不過只有這樣才能重新啟動獨立顯卡。第一次執行命令時可能會報錯,不過這並不重要。