外付け GPU
Thunderbolt 3 以上または USB4 を搭載したコンピュータは、GPU エンクロージャを使用して、デスクトップグレードの外付けグラフィックカード (eGPU) を接続できます。eGPU.io は購入者ガイドとコミュニティフォーラムのある優れたリソースです。ほとんどの動作モードでは、いくつかの手動設定 (以下に記載) が必要ですが、eGPU の Linux サポートは一般的に良好です。
目次
インストール
Thunderbolt
eGPU エンクロージャの Thunderbolt デバイスは、挿入した後にまず (BIOS/UEFI のファームウェア設定に基づいて) 認証する必要があるかもしれません。Thunderbolt#ユーザーデバイス認証 の指示に従ってください。それができたら、外付け GPU が lspci
に表示されるはずです:
$ lspci | grep -E 'VGA|3D'
00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 620 (rev 07) # 内部 GPU 1a:10.3 VGA compatible controller: NVIDIA Corporation GP107 [GeForce GTX 1050] (rev a1) # 外付け GPU
あなたのコンピュータ、コンピュータのファームウェア、そしてエンクロージャのファームウェアによっては、PCIe のレーン数と OPI のモードにより、Thunderbolt によってホスト <-> eGPU 間の帯域幅がある程度制限されます:
# 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
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 ドライバは、(Thunderbolt か USB4 のどちらか一方を使用している場合に) pcie_gen_cap オプションに間違った値を設定してしまい、その結果 PCIe gen 1.1 の速度にフォールバックしてパフォーマンスに大きな問題が発生する場合があることに注意してください。 この場合、適切な値をモジュールオプション (カーネルモジュール#/etc/modprobe.d/ 内のファイルを使う を参照) として、またはカーネルパラメータから設定することができます:
/etc/modprobe.d/amd-egpu-pcie-speed.conf
options amdgpu pcie_gen_cap=0x40000
この例では、PCIe gen 3 の速度を設定します。利用可能なオプションの完全なリストは amd_pcie.h で確認できます。
コンピューティングのみのワークロード
インストール作業を完了したら、何も描画する必要のない GPGPU#CUDA のようなコンピューティングのみのワークロードは追加の設定無しで機能するはずです。nvidia-smi ユーティリティ (nvidia-utils パッケージにあり) はプロプライエタリな NVIDIA ドライバで動作するはずです。プロプライエタリな Nvidia NVENC/NVDEC も動作するはずです (OpenGL interop 無しで)。
このようなユースケースではホットプラグも完全にサポートされているはずです。また、ホットアンプラグも可能なはずです (おそらく、使用するドライバに依ります)。Nvidia では、nvidia-persistenced
をアクティブ化していると、クリーンなホットアンプラグが妨害されると予想されます。
Xorg
内部 カード (iGPU) と外付けカード (eGPU) を組み合わせたセットアップには複数のバリエーションがあり、それぞれに長所と短所があります。
eGPU で Xorg を描画し、iGPU に PRIME ディスプレイオフロード
- GPU を使用するプログラムのほとんどは設定せずとも eGPU 上で動作します:
glxinfo
/glxgears
、eglinfo
/eglgears_x11
、NVENC
/NVDEC
(OpenGL interop を含む)。 - Xorg は、eGPU が挿入された状態でのみ起動します。
- eGPU に接続されているモニターは設定せずとも動作します。iGPU に接続されているモニター (つまり、ノート PC の画面) に対しては PRIME ディスプレイオフロードを使用できます。
主な記事は PRIME#ディスクリートカードをプライマリ GPU にする と PRIME#Reverse 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 の出力に応じて書き換えてください。また、16進数から10進数に変換してください。 Option "AllowExternalGpus" "True" # プロプライエタリな NVIDIA ドライバで必要です。 EndSection Section "Module" # iGPU 用の modesetting モジュールをロードします。modesetting は XrandR 1.4 でプロバイダとして表示されるはずです。 Load "modesetting" EndSection
このセットアップを検証するには、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 ディスプレイオフロードを使用することにより、iGPU に接続されているノート PC の内蔵ディスプレイと、同じく iGPU に接続されている他のモニタの一方/両方に出力することができます。上記の xrandr --listproviders
で出力されている名前を使用して、以下のようなコマンドを実行してください:
xrandr --setprovideroutputsource modesetting NVIDIA-0 && xrandr --auto
ディスプレイマネージャがログインプロンプトを表示する前や、デスクトップ環境が開始する前にこのコマンドを実行したい場合があるでしょう。これに関しては Xrandr#設定 と Xinit を見てください。
Vulkan は Xorg とは独立して GPU を列挙する場合があります。なので、この環境で vkcube
などを実行するには、--gpu_number 1
オプションを渡す必要があるかもしれません。または、__NV_PRIME_RENDER_OFFLOAD=1 vkcube
かそれと等価な prime-run vkcube
を使って、列挙中に GPU を並べ替えるレイヤーをアクティブ化しても、同じ効果があります。
iGPU で Xorg を描画し、eGPU に PRIME レンダーオフロード
- プログラムはデフォルトで iGPU 上で描画されますが、PRIME レンダーオフロードを使って eGPU 上で描画することもできます。
- Xorg は eGPU が接続されていなくても開始しますが、再起動しない限りレンダー/ディスプレイオフロードは機能しません。
- iGPU に接続されているモニタ (つまり、ノート PC の内蔵ディスプレイ) は設定せずとも動作します。eGPU に接続されているモニタに対しては PRIME ディスプレイオフロードを使用できます。
主な記事は PRIME#PRIME GPU オフロード です。また、NVIDIA ドライバのドキュメントの Chapter 34. PRIME Render Offload でも文書化されています。
多くのディスクリート GPU ドライバで、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 の出力に応じて書き換えてください。また、16進数から10進数に変換してください。 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 レンダーオフロードを使えば、some_program
を eGPU 上でレンダリングすることができます:
- プロプライエタリな 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 ディスプレイオフロードを使えば、eGPU に接続されたモニタに出力することができます:
$ xrandr --setprovideroutputsource NVIDIA-G0 modesetting && xrandr --auto
NVIDIA drivers 460.27.04+ では、レンダーオフロードとディスプレイオフロードを組み合わせた特殊なケースにおける最適化が実装されています:
- “Reverse PRIME Bypass” のサポートを追加しました。これは、レンダーオフロードされたアプリケーションがフルスクリーンで、リダイレクトされておらず、NVIDIA 駆動の PRIME ディスプレイオフロードされた出力でしか表示されない条件で発生する、PRIME レンダーオフロードと PRIME ディスプレイオフロードの帯域幅のオーバーヘッドを回避する最適化です。この最適化が使用されていることは、X サーバの verbose ログが有効化されている場合に X のログで報告されます。
eGPU に対しては別の Xorg インスタンスを使う
主な記事は Nvidia-xrun#External GPU setup[リンク切れ: セクションが存在しません] です。
Xorg 上での eGPU の既知の問題
- ホットプラグは、ほとんどのディスクリート GPU Xorg ドライバでサポートされていません: eGPU は Xorg の開始時に挿入されている必要があります。Xorg を再起動するには、一旦ログアウトして、再びログインし直すだけで十分なはずです。
- ホットアンプラグは全くサポートされていません: 動作中に外付け GPU を抜くとシステムが不安定になったり、完全にフリーズしたりします (Nvidia のドキュメントで確認されています)。
Wayland
eGPU (一般には複数 GPU) に対する Wayland のサポートはあまりテストされていませんが、少ない手動設定で動作するはずです。
注意点として、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
- wl-roots: 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 のプログラムは、たとえ iGPU で動作していても、1MB の dGPU メモリを使用する傾向にあります (このことは nvidia-smi
で確認できます)。dGPU メモリの使用を防ぐには、環境変数 __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 機能が利用できるようになっています。しかし、MESA を使うために __EGL_VENDOR_LIBRARY_FILENAMES
変数を設定しているので、プログラムの開始前に __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 を使用している場合は、__EGL_VENDOR_LIBRARY_FILENAMES
を環境変数リストに追加するために switcheroo-control にパッチを当てる必要があるかもしれません。こうすることで、右クリックのコンテキストメニューで "Launch using Dedicated Graphics Card" を選択することでプログラムを eGPU 上で実行できるようになります。しかし、これは記事で扱う事柄の範囲外です。
Nvidia eGPU をホットプラグ化し、Nvidia dGPU を一時的に無効化する
In case you have iGPU, Nvidia dGPU and want to connect Nvidia eGPU, you will encounter a conflict, where graphics renders only on dGPU, no matter what you do. To solve this, you need to temporarily disable dGPU, so Nvidia driver will not notice it. Best way to do that is to override its driver.
First, you need to unload Nvidia driver:
# rmmod nvidia_uvm # rmmod nvidia_drm # rmmod nvidia_modeset # rmmod nvidia
Then, you need to override dGPU driver with driverctlAUR utility. In this example, 0000:01:00.0 is address of dGPU. It can be found with lspci
utility.
# driverctl --nosave set-override 0000:01:00.0 vfio-pci
It is important to use --nosave
parameter, to prevent driverctl to override driver on boot. It is useful in case something goes wrong, simple reboot cleans everything.
When dGPU is disabled, you can load kernel modules with modprobe nvidia-drm
and then check if nvidia-smi
shows 1 or 2 GPUs.
Bringing dGPU back is tricky, because it is unintuitive. First, unload Nvidia modules, unplug eGPU and then run this series of commands:
# 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
It is strange that we need to run first 2 commands twice, but otherwise it will not bring back dGPU. Command will error once, but it is not critical.