1なぜこの構成なのか — 最終的に分かった結論
VM に vBIOS を渡さないと GPU はコード 43 になりました (実測)。HDMI 音声に GOP ROM を付けても付けなくても結果は同じでした。
同じスロットの USB コントローラには、NanoKVM のキーボードが載っていました。丸ごと渡すとホストが KVM から操作できなくなるため、機能を個別に指定します。
AMD の内蔵 GPU は VM を止めたあと初期化されず、次の起動でコード 43 になります。Windows のシャットダウン時に GPU を無効化し、起動時に有効化し直すと、繰り返しても OK でした。
SPICE で見えるのは QXL の画面だけです。GPU の仮想モニタを同時に有効にすると、SPICE エージェントが混乱してマウスが動かなくなります。
① vBIOS とコード 43 (詳細を見る)
- 内蔵 GPU には
/sys/bus/pci/devices/…/romがありません。AMD のファームウェアは vBIOS を ACPI の VFCT テーブルに入れているので、そこから取り出します (extract-vbios-from-vfct.py・16,896 バイト・先頭が55 AA)。 - VM には
hostpci0: …,romfile=ファイル名で渡します。ファイルは/usr/share/kvm/に置く必要があります (ファイル名だけ指定できる)。 - 実測: vBIOS あり → コード 0 / vBIOS なし (他は同じ) → コード 43。
- 途中で「HDMI 音声に AMDGopDriver.rom を付ける」方法も試しましたが、結果に影響しませんでした。最初のコード 43 の本当の原因は、直前の BSOD で GPU が汚れていたことと考えられます。
③ AMD リセットバグの詳細 (詳細を見る)
- 症状: ホストを起動したあとの 最初の VM 起動だけ正常。VM を止めて起動し直すとコード 43。
- PVE の起動ログに
failed to reset PCI device … Inappropriate ioctl for deviceと出ます。GPU が FLR (機能単位のリセット) に対応していないためで、VM の起動は続きます (害のないメッセージ)。 - 有効だった方法: ゲストの シャットダウンスクリプト で GPU を無効化 → 次の起動の スタートアップタスク で有効化 (コード 22 を検知)。
qm shutdown/qm reboot/ Windows の再起動、いずれの繰り返しでも OK。 - 限界: 強制停止 (qm stop)・クラッシュ・BSOD ではスクリプトが走らず、次の起動はコード 43。その状態からは、正常な停止・起動を繰り返しても戻りません。ホストの再起動で戻ります。
- 高速スタートアップ (休止状態を使うシャットダウン) はスクリプトを走らせないことがあるため
powercfg /hibernate offにしています。
④ SPICE のマウスが効かなくなる原因 (詳細を見る)
- 古い SPICE エージェントは「モニタの付いたディスプレイが 2 種類以上ある」と、画面レイアウトを管理しなくなり、マウスの位置変換が壊れます。パススルーした GPU の仮想モニタ (AMD vDisplay) がこれに当たります。ログ (
C:\Windows\Temp\vdagent.log) に#qxls 1 #others 1と出ていたら該当です。 - 修正は上流で 2024 年 8 月に入っています (「モニタが接続されていないディスプレイを無視する」)。この手順では、その修正を含むコミュニティ版 (nefarius/vd_agent 0.13.0) を使います。
- ただし GPU の仮想モニタが 有効 だと (たとえデスクトップに使っていなくても) 数えられてしまうので、SPICE モードでは 無効化 します。
- 古い「SPICE Guest Tools」のエージェントが同居すると、2 つのエージェントが同じ通信ポートを取り合ってカーソルが消えます。古い方のサービス
vdserviceは無効化します。 - モード切替のたびに
spice-agentサービスを再起動するのは、エージェントが画面の組み合わせを起動時にしか読み直さないためです。
Blender はなぜ遅くなり、「GPU fast」でなぜ速くなるのか
遅いのは 3D の計算ではなく、絵を SPICE の画面 (QXL) に渡す部分です。Blender の 3D ビューの描画自体は約 0.01 ms でした。
SPICE の画面 (QXL) は「表示専用」で、描画の機能がありません。Windows のデスクトップ合成 (dwm.exe) は、GPU ではなく ソフトウェア描画 (Microsoft Basic Render Driver) で動きます。GPU が描いた絵は毎フレーム、別のアダプタを経由して合成側に渡されます。Vulkan や DirectX の「flip 方式」の表示では、この受け渡しが非常に遅く、1 回約 105 ms / 百万画素かかりました。
OpenGL は、ウィンドウを作った画面のドライバで決まります。QXL の画面で作ると Windows 標準の OpenGL 1.1 になり、Blender は「OpenGL 4.3 以上が必要」と言って起動できません。そのため、普通に使うと遅い Vulkan しか選べませんでした。
GPU の画面で OpenGL のウィンドウを作ると、AMD の OpenGL 4.6 ドライバが使われます。そのあとデスクトップを SPICE に戻しても AMD のままで、従来の方式 (blt) の表示は同じ QXL の画面でも約 7 ms で済みました。新しく開いたウィンドウも同様でした。
これを自動化したのが「Blender (GPU fast)」です。表示を GPU 側にする → Blender 起動 → メインループが動いたら目印のファイル (
blender-ready.pyが作る) を確認 → SPICE に戻す、という流れです。
ストリームモード (Moonlight) で速い理由と、接続前に切り替える理由 (詳細を見る)
- ストリームモードではデスクトップそのものが GPU の仮想モニタ上にあるので、合成も描画も GPU で完結します (画面更新は約 3 ms)。映像は GPU のエンコーダ (AMF) で圧縮して PC に送ります。
- Sunshine は接続のたびに使えるエンコーダを探し直し、その「後」に接続時のコマンド (表示モード切替) を実行します。QXL だけの画面で探すと GPU が見えず、CPU の
libx264になります。GPU の画面が有効なときに探すとh264_amf/hevc_amf/av1_amfが見つかります。このため、PC のスクリプトで先にストリームモードにしてから Moonlight を起動します。 - Moonlight でセッションを終了 (Ctrl+Alt+Shift+Q) すると、Sunshine が「アプリ終了時のコマンド」(SPICE モードへ) を実行します。プロセスを強制終了した場合は実行されないことがあります。
2測定結果
| 条件 (Blender 5.2.2) | 画面 | 全パネル描画+表示の 1 回あたり |
|---|---|---|
| SPICE モード・Vulkan (普通に起動) | 1692x1073 | 約 222 ms |
| 同・小さいウィンドウ | 1280x720 / 1024x576 / 900x600 | 約 119 / 84 / 77 ms |
| 3D ビューの描画のみ (表示なし) | — | 約 0.01 ms |
| 全パネルの描画 (表示なし) | — | 約 1.1〜1.4 ms |
| GPU fast (OpenGL を先に GPU 側で起動 → SPICE に戻す) | 1692x1073 | 約 7 ms (新規ウィンドウも約 7 ms) |
| ストリームモード・OpenGL | 1920x1080 | 約 3 ms |
| ストリームモード・Vulkan | 1920x1080 | 約 19.5 ms |
Blender を使わない DirectX 11 のテスト (詳細を見る)
| 表示先 / 方式 | 640x400 | 900x600 | 1692x1000 |
|---|---|---|---|
| GPU で描いて QXL の画面のウィンドウへ (flip 方式) | 34 ms | 62 ms | 183 ms |
| 同 (従来の blt 方式) | 3.9 ms | 9.7 ms | 25〜275 ms (ばらつき大) |
| GPU 自身の画面のウィンドウへ | 0.1〜0.4 ms | ||
| (参考) ソフトウェア描画 (WARP) を QXL へ | 10.9 ms | 26.6 ms | 45.5 ms |
GPU のメモリから CPU への読み戻しは約 8 GB/s で、メモリ帯域や IOMMU が原因ではありませんでした。
その他: FINAL FANTASY XV ベンチマーク (標準画質) はスコア約 2000、GPU 使用率 約 70% (ユーザー報告)。Unity の簡単なシーン (キューブ 1 個) は遅延なく表示。
3トラブルシューティング
| 症状 | 考えられる原因 | 確認と対処 |
|---|---|---|
| コード 43 (ドライバ導入直後・ホスト起動直後) | vBIOS (romfile) が渡っていない / 直前の強制停止・BSOD で GPU が汚れている | qm showcmd VMID --pretty | grep vfio-pci に romfile=/usr/share/kvm/….rom があるか。無ければ ./02-add-gpu-to-vm.sh をやり直す。あれば VM を止めてホスト再起動→ VM 起動 |
| コード 43 (VM を止めて起動し直した後) | シャットダウンスクリプトが走っていない (強制停止・高速スタートアップ・スクリプト未登録) | VM で Get-Content C:\ProgramData\gpu-reset-fix\log.txt に shutdown: disabling GPU があるか。無ければ install-all.ps1 を再実行し、gpedit.msc でシャットダウンスクリプトを確認。ホスト再起動で復旧 |
ホスト再起動後も amdgpu が GPU を使っている | vfio が initramfs に入っていない / vfio.conf の id が違う |
lsinitramfs /boot/initrd.img-$(uname -r) | grep vfio で vfio-pci.ko が出るか。/etc/initramfs-tools/modules に 3 行あるか。dmesg | grep -i vfio。01-setup-vfio.sh をもう一度実行して再起動 |
qm start がエラー / VM が起動しない | GPU がまだ vfio-pci でない / 別の VM が GPU を使っている |
lspci -nnk -s GPU_ADDR。GPU は 1 台の VM にしか渡せません |
| ホスト再起動で BIOS の青い画面で止まる | 機種の BIOS 機能 (検証に使ったミニ PC で確認) | ホストの画面 (KVM) で Continue boot / Always continue boot を選ぶ |
| NanoKVM などのキーボードが効かなくなった | KVM が載っている USB コントローラ (.3 など) を VM に渡した |
hostpci には .0 と .1 だけを指定する (All Functions を使わない) |
| SPICE のマウスが効かない・カーソルが消える | 古い SPICE エージェント / 2 つのエージェントが同居 / GPU の仮想モニタが有効 | C:\Windows\Temp\vdagent.log の最後が log_version::0.13.0.0 と #others 0 か。違えば install-spice-agent.ps1 と schtasks /run /tn GpuMode-spice |
| SPICE の画面が黒いまま | ストリームモードのまま (Moonlight を強制終了した等) | ssh WINUSER@VM_IP schtasks /run /tn GpuMode-spice。ログイン 25 秒後にも自動で戻る |
| Blender が「OpenGL 4.3 以上」と出て起動しない | SPICE の画面 (QXL) で OpenGL を作ろうとしている | 「Blender (GPU fast)」で起動する。または --gpu-backend vulkan (遅いが動く) |
| Blender が数秒待たされる | SPICE モードで Vulkan 起動している | いったん Blender を閉じて「Blender (GPU fast)」で開き直す |
| 「Blender (GPU fast)」で Blender が出ない | Blender の場所が変わった・主ループの目印が出ない | C:\ProgramData\gpu-reset-fix\launcher.log を見る (Blender not found / blender main loop ready: False) |
| Windows Update のあと青い画面 / GPU が変 | 古い AMD ドライバが自動で入った | VM を止めてホスト再起動 → 起動 → install-amd-driver.ps1 |
| Moonlight の映像が真っ黒・帯状に崩れる | (推定) クライアント PC が GPU の無い仮想マシンで、ソフトウェアデコード・描画になっている | GPU のある実機 PC の Moonlight で試す。この環境では実機 PC で正常に表示されました |
| Sunshine の PIN 送信で CSRF Protection Error | 別の PC のブラウザは、許可リストに無いと拒否される | .\install-sunshine.ps1 -SkipInstall -AllowedOrigin https://開いたアドレス:47990 |
ペアリングが Incorrect PIN / 409 … already exists | PIN の入力違い・古い途中状態が残っている | VM で Sunshine サービスを再起動 → Moonlight で追加し直す (Moonlight の登録を消す場合は PC のレジストリ HKCU\Software\Moonlight Game Streaming Project\Moonlight\hosts) |
配信が CPU エンコード (libx264) になる | ストリームモードになる前に Moonlight が接続した | Start-Blender-Stream.cmd を使う。Sunshine のログ (C:\Program Files\Sunshine\config\sunshine.log) の Found H.264 encoder を確認 |
4試して駄目だった方法 (結論として採用しなかったもの)
| 方法 | 結果 |
|---|---|
echo 1 > /sys/bus/pci/devices/…/reset で GPU をリセット | 失敗 (Inappropriate ioctl for device)。同じバスの他の機能がホストで使用中のため |
VM 停止中にホストの amdgpu を GPU に付けて初期化し、vfio に戻す | 失敗 (PSP firmware loading failed)。ホストはフリーズせず vfio に戻せたが、初期化の役には立たなかった |
| バス上の全機能 (USB を含む) を vfio に渡して、バス全体をリセット | NanoKVM のキーボードが載る USB を失うため不採用 (試していません) |
| vendor-reset などのカーネルモジュール | 試していません |
| HDMI 音声に UEFI GOP ROM (AMDGopDriver.rom) を付ける | 不要。付けても付けなくても同じ結果 |
| QXL を無効にして GPU の仮想モニタだけにする (常時) | OpenGL は GPU で動くが SPICE が黒くなる → 「ストリームモード」としてだけ採用 |
| QXL と GPU の仮想モニタを同時に有効 (拡張) | GPU 側の画面は速いが、SPICE にはその画面が映らず、SPICE のマウスも壊れる |
| QXL と GPU の仮想モニタを「複製」 | Windows が拒否 (SetDisplayConfig エラー 87) |
| Windows の「グラフィックの設定 → 高パフォーマンス」を Blender に設定して OpenGL を GPU に | QXL が主画面のままでは効かない (OpenGL は起動できない) |
| RDP で使う | 動作はするが、操作が遅い (ユーザーの感想)。SPICE を優先 |
Sunshine の画面取得を capture = wgc に変更 | サービスとして動かすと使えない (0x80070424) |
| Sunshine をサービスではなくユーザーのセッションで起動 | 接続時の表示モード切替コマンドが error 5 で失敗 |
カーネルオプション amd_iommu=on | 不要 (カーネルが Unknown option と表示)。BIOS の IOMMU 設定だけでよい。iommu=pt は性能のために付ける |
| AMD のインストーラを VM で直接実行 | 「AMD 製品ではない」と判定されることがあるため、ドライバだけ取り出して pnputil で導入する方式にした |
5変更される設定の一覧 (透明性のために)
/etc/modprobe.d/vfio.conf(新規)/etc/modules・/etc/initramfs-tools/modules(3 行追加)/etc/default/grub(iommu=pt追加)- initramfs の再生成
/usr/share/kvm/vbios_….rom(新規)- VM の設定 (
hostpci0/1) - バックアップ:
/root/gpu-passthrough-backup-…
- AMD ディスプレイドライバ (
pnputil) - OpenSSH サーバー・ファイアウォール規則
- SPICE エージェント 0.13.0 / 旧
vdserviceを無効化 - グループポリシーのシャットダウンスクリプト
- タスク: GpuResetFix-Startup / GpuMode-spice / GpuMode-stream / GpuMode-spice-onlogon
- 高速スタートアップ (休止) を無効
C:\ProgramData\gpu-reset-fix\・デスクトップのショートカット- (任意) Sunshine サービス・apps.json・sunshine.conf
- SSH 鍵 (
~\.ssh\id_ed25519) - (任意) Moonlight (
%LOCALAPPDATA%\Programs\Moonlight) とペアリング情報 (レジストリ) - (任意)
Start-Blender-Streamスクリプト - 一時的な
C:\amd-extract(終わったら削除してよい)
6ログと確認コマンド
| 見たいもの | どこ / コマンド |
|---|---|
| GPU のリセット対策の動き | VM: C:\ProgramData\gpu-reset-fix\log.txt |
| 表示モードの切替 | VM: C:\ProgramData\gpu-reset-fix\mode.log (done: の行に、いまのモニタ構成が出る) |
| 「GPU fast」ショートカットの動き | VM: C:\ProgramData\gpu-reset-fix\launcher.log |
| SPICE エージェント | VM: C:\Windows\Temp\vdagent.log (#qxls 1 #others 0 が正常) |
| Sunshine | VM: C:\Program Files\Sunshine\config\sunshine.log |
| GPU の状態 (VM) | Get-PnpDevice -Class Display | Format-Table FriendlyName,Status |
| GPU の状態 (ホスト) | lspci -nnk -s GPU_ADDR |
| VM に渡った設定 | qm showcmd VMID --pretty | grep -A2 vfio-pci |
| VM の画面だけ取りたいとき | ホスト: echo "screendump /tmp/s.ppm" | qm monitor VMID (SPICE や noVNC が固まっていても取れる) |
7未検証・制限
- 確認したのは AMD Phoenix1 (Radeon 760M) の内蔵 GPU だけです。他の AMD 内蔵 GPU でも考え方は同じですが、デバイス ID・vBIOS・ドライバの INF は変わります。NVIDIA / Intel の GPU は対象外です。
- 起動方式は GRUB のみ確認しました。
proxmox-boot-tool(systemd-boot) の環境では、スクリプトは設定せずに案内を表示します。 - GPU は VM 1 台にだけ渡せます。ホストで GPU を使うことはできなくなります。
- Unity での確認は、キューブ 1 個の簡単なシーンだけです。大きなシーンでの性能は測っていません。
- RDP 上での GPU 描画、Windows 10 ゲスト、複数ユーザーでの利用は確認していません。
- 「Blender (GPU fast)」の実際のダブルクリック操作は、制限付き権限のタスクと実際のショートカットで確認しました。SPICE の黒い画面の見え方は、手元の環境での目視確認が必要です。
- Blender のバージョンが変わると、インストール先 (
C:\Program Files\Blender Foundation\Blender x.y) は自動で探しますが、起動オプションの挙動が変わる可能性があります。
8安全面の注意
- ダウンロードするもの (SPICE エージェント・Sunshine) は、スクリプトが SHA-256 と署名を確認してからインストールします。AMD ドライバはあなたが AMD の公式ページから入手してください。
- SSH 鍵の秘密鍵 (
id_ed25519) は他人に渡さないでください。VM に登録するのは公開鍵 (.pub) です。 - Sunshine の Web UI のパスワードは、画面で入力します (ファイルには残りません)。Sunshine と SSH は LAN の中だけで使い、インターネットに公開しないでください。
- スクリプトの一部は管理者権限や SYSTEM 権限で動きます。内容は
files\vmのテキストファイルで読めます。
9用語集
| 用語 | 意味 |
|---|---|
| PCI パススルー | PC の部品 (ここでは GPU) を、ホストではなく VM に直接つなぐ仕組み。VM はその部品を専用で使えます |
| IOMMU (AMD-Vi) | パススルーに必要な CPU の機能。BIOS で有効にします |
| vfio-pci | 部品をホストのドライバから切り離して、VM に渡せる状態にする Linux のドライバ |
| vBIOS / VFCT | GPU のビデオ BIOS。内蔵 GPU では ACPI の VFCT テーブルから取り出します |
| リセットバグ / FLR | AMD の GPU は VM を止めたあとにリセットされず、次の起動でコード 43 になる問題。FLR は PCI のリセット機能で、この GPU は非対応 |
| コード 43 | Windows のデバイス マネージャーで「デバイスが問題を報告したため停止」の意味。このときは GPU が初期化できていません |
| SPICE / QXL | VM の画面をネットワーク越しに見るための仕組み (SPICE) と、その仮想ディスプレイ (QXL) |
| vd_agent (SPICE エージェント) | VM の中で動き、マウスの位置合わせ・解像度・クリップボードを SPICE と連携するソフト |
| Sunshine / Moonlight | PC の画面を GPU で圧縮して LAN で送る仕組み (Sunshine=送る側 / Moonlight=見る側) |
| AMF | AMD GPU の動画エンコーダ機能 |
| OpenGL / Vulkan / DirectX | 3D 描画の API。Blender は OpenGL と Vulkan に対応しています |
| DWM | Windows のデスクトップ合成 (dwm.exe)。すべてのウィンドウをまとめて 1 枚の画面にします |
| GPU の仮想モニタ (AMD vDisplay) | モニタが無くても GPU が自分で作る、仮想のモニタ。ストリームモードで使います |