Hyper-VでGPU(GPU-PV)を利用する方法 (Windows 10以降編)

## `Windows Server 2025`にて正式サポート

[https://techcommunity.microsoft.com/t5/windows-server-news-and-best/the-future-of-windows-server-hyper-v-is-bright/ba-p/4074940](https://techcommunity.microsoft.com/t5/windows-server-news-and-best/the-future-of-windows-server-hyper-v-is-bright/ba-p/4074940)

`Windows Server 2025`にて、`GPU-P`は正式にサポートされるようになるようです。

こちらで紹介している有効化手順は正式サポート以前のものになります。

正式な手順は異なる可能性があります。

正式な手順は公式のドキュメントを確認してください。

ただし、こちらの手順では、公式的にはサポートされないハードウェア構成でも使用可能かもしれません。

## はじめに

**この記事は、[Hyper-VでGPU(3Dアクセラレーション)を利用する方法 Windows 10以降編 (GPU-P)](https://qiita.com/Hyper-W/items/3a2c7ff1d983deb80070)のリメイク版です。元の記事は引用されたりしていますが、手順の簡略化など変更が多くなったため、作成し直しています。**

この記事の`Ubuntu`版は、[ここ](https://qiita.com/Hyper-W/items/5ddfc93891f7b620da8a)です。

`Hyper-V`で、`GPU`を利用する方法として現在[公式](https://docs.microsoft.com/ja-jp/windows-server/virtualization/hyper-v/plan/plan-for-gpu-acceleration-in-windows-server)では、DDAとRemoteFXが案内されていますが、RemoteFXは[脆弱性](https://www.atmarkit.co.jp/ait/articles/2008/12/news006.html)により、更新で無効化されました。

`DDA`は、`Windows 10`では利用できず、`Windows Server 2019`はサポート対象であるにも関わらず、動かないようです。

つまり、現在公式資料にある方法では`Hyper-V`で`GPU`を利用出来ない状態です。

しかし、公式資料には現状、利用方法は存在しませんが`RemoteFX`に変わる技術として、`GPU`の準仮想化技術である`GPU-PV`(`Para Virtualization`)、そして、その準仮想化`GPU`のリソースの分割設定を行う`GPU-P`(`Partitioning`)が利用可能です。

既に、`Windows Sandbox`の仮想`GPU`、[`Azure`](https://azure.microsoft.com/ja-jp/blog/power-your-azure-gpu-workstations-with-flexible-gpu-partitioning/)で利用されているようです。

又、`Windows 10 (21H1)`以降の`WSL2`では同様の技術を用いて、`Nvidia`製`GPU`を用いる`CUDA`プログラミングが、`WSL2`上やそれをバックエンドとして利用する`Docker`で可能になりました。

最近では、[`Azure Stack HCI`](https://learn.microsoft.com/ja-jp/azure-stack/hci/manage/partition-gpu)でも、サポートされている`GPU`は限られますが、利用可能なようです(この記事の手順を利用すれば非対応`GPU`でも利用可能な可能性があります)。

既に利用されているということは、`Windows`に実装されているということです。

実際に、`Powershell`で`Hyper-V`に関するコマンドを調べると、下記のようなコマンドで、

```Powershell
Get-Command -module Hyper-V
```

下記のような結果が得られます。

```Powershell
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
                (前略)
Cmdlet          Add-VMGpuPartitionAdapter                          2.0.0.0    Hyper-V
                (中略)
Cmdlet          Get-VMGpuPartitionAdapter                          2.0.0.0    Hyper-V
                (中略)
Cmdlet          Remove-VMGpuPartitionAdapter                       2.0.0.0    Hyper-V
                (中略)
Cmdlet          Set-VMGpuPartitionAdapter                          2.0.0.0    Hyper-V
                (後略)
```

上記のように既に実装されています。

`Get-Help`コマンドで調べると構文は出てきますが、説明はまだ公式サポートされていないので、出てきません(`Powershell 7`以降で実行すると更に詳しい構文が出てきます)。

この記事では、仮想`GPU`の割り当てから、`GPU`ドライバーの適用を手動で行う手順を紹介していますが、この手順を簡略化すプロジェクト[Easy-GPU-PV](https://github.com/jamesstringerparsec/Easy-GPU-PV)も存在します。

このプロジェクトでは、折角の仮想`GPU`を利用して内部的には高フレームレートが出ているのにも関わらず、`Hyper-V`の仮想マシン接続では、カクカクになるという問題(`RDP`ベースの拡張セッションモードでは多少マシではあるが...)に対処するために[`Parsec`](https://parsec.app/)というリモートデスクトップを用いたセットアップまで自動で行っています。

`Parsec`が不要な場合は、この手順が参考になるかと思います。

## 目次

- [`Windows Server 2025`にて正式サポート](#windows-server-2025にて正式サポート)
- [はじめに](#はじめに)
- [目次](#目次)
- [動作確認環境](#動作確認環境)
- [仮想マシンで、仮想`GPU`を利用できるようにする](#仮想マシンで仮想gpuを利用できるようにする)
  - [チェックポイントの無効化](#チェックポイントの無効化)
  - [仮想`GPU`の割り当て方法](#仮想gpuの割り当て方法)
    - [`GPU Partition Adapter`の割り当て](#gpu-partition-adapterの割り当て)
      - [マルチ`GPU`環境での割り当てについて](#マルチgpu環境での割り当てについて)
    - [仮想`GPU`のリソース設定](#仮想gpuのリソース設定)
  - [仮想マシンに準仮想`GPU`のドライバーを追加する方法](#仮想マシンに準仮想gpuのドライバーを追加する方法)
    - [親マシン上にある`GPU`ドライバーの保存場所の確認](#親マシン上にあるgpuドライバーの保存場所の確認)
    - [仮想マシンへのドライバーコピー](#仮想マシンへのドライバーコピー)
    - [(`Nvidia`製`GPU`限定) 仮想マシンで`CUDA API`を利用可能にする](#nvidia製gpu限定-仮想マシンでcuda-apiを利用可能にする)
- [仮想`GPU`の確認](#仮想gpuの確認)
- [`CUDA API`の動作確認](#cuda-apiの動作確認)
- [GPU Partition Adapterの削除](#gpu-partition-adapterの削除)
- [`Windows 10`以外の子マシンでの動作確認(Windows系のみ)](#windows-10以外の子マシンでの動作確認windows系のみ)
  - [`Windows 10 (21H1)`の親マシンでの検証](#windows-10-21h1の親マシンでの検証)
  - [`Windows 11 (21H2)`の親マシンでの検証](#windows-11-21h2の親マシンでの検証)
  - [(暫定)検証結果](#暫定検証結果)
- [その他参考](#その他参考)

## 動作確認環境

- 親マシン

```yml
OS: Windows 10
Version: 2004
GPU: Nvidia Geforce GTX 1070(固定)
```

- 子マシン

```yml
OS: Windows 10
Version: 2004
VM Generation : Gen 2
```

リメイク版で、修正された手順にて利用している親環境は、下記の通りです。

割り当てる物理`GPU`のデバイスファイルパス名の確認やドライバーを親マシンから持ってくる部分でのみ利用しております。

- 親マシン

```yml
OS: Windows 11
Version: 22H2
GPU: Nvidia Geforce RTX 3080
```

## 仮想マシンで、仮想`GPU`を利用できるようにする

**注意**
**この機能は、公式にサポートされていない方法です。なにか問題が起きても自己責任です。**

### チェックポイントの無効化

まず、チェックポイントを適用・削除する必要があります。

これは、`GPU-PV`ではチェックポイントがサポートされておらず、有効化するためにはチェックポイントを無効化する必要があるためです。

そのため、自動チェックポイントを使っている場合は無効に、チェックポイントが既に存在する場合は、チェックポイントの削除または適用を、チェックポイントを利用しないことが必要です。

### 仮想`GPU`の割り当て方法

この項目での設定は、シングル`GPU`環境の場合、[この`bat`ファイル](https://github.com/Hyper-W/Hyper-V_GPU-PV-Single/blob/Qiita-GPU-PV/Hyper-V_GPU-PV-Single.bat)により一括実行可能です。

この`bat`ファイルはダブルクリックで、実行すると`UAC`で管理者権限に昇格し、仮想マシン名を聞いてくるので、設定したい仮想マシンの名前をシングルクォート(`'`)で囲み指定すると、一括で実行されます。

#### `GPU Partition Adapter`の割り当て

まずは、先程の`GPU Partitioning`関連のコマンドを利用して仮想マシンに`GPU Partition Adapter`を仮想マシンに割り当て、リソースの設定などを行います。

`Powershell`を**管理者権限**で実行して、下記コマンドを実行します。

まずは、仮想マシンに`GPU Partition Adapter`を割り当てます。

下記コマンドでは、親マシンのタスクマネージャー等で、`GPU 0`として認識されている`GPU`が仮想`GPU`として割り当てられます。

マルチ`GPU`環境で指定したい`GPU`がある場合は、下記のコマンドは実行せずに以降で紹介するコマンドを実行して下さい。

```Powershell
Add-VMGpuPartitionAdapter -VMName "仮想マシン名"
```

##### マルチ`GPU`環境での割り当てについて

マルチ`GPU`環境で`GPU 0`として、認識される`GPU`以外を割り当てたい場合、`-InstancePath`オプションで、親マシンの`Windows`で認識されるデバイスファイルパス名を指定することで`GPU`を明示的に指定することが可能になります。

このオプションは`Windows 10`のあるいはそのバージョンによっては利用できない可能性があります。

もし、利用できなかった場合は、利用したい`GPU`が、タスクマネージャー上で、`GPU 0`として認識するように、他の`GPU`を無効化する等して下さい。

マルチ`GPU`環境で、割り当てたいデバイスファイルパス名を確認する方法は下記の通りです。

```Powershell
Get-VMHostPartitionableGpu | Format-Table Name
```

下記のような結果が、返ってきます(マルチ`GPU`環境の場合、複数返ってきます)。

```Powershell
Name
----
デバイスファイルパス名
```

ここで、帰ってきた値を用いて、先程のコマンドを実行します。

```Powershell
Add-VMGpuPartitionAdapter -VMName "仮想マシン名" -InstancePath "デバイスファイルパス名"
```

#### 仮想`GPU`のリソース設定

仮想`GPU`のリソースを設定します。

物理`GPU`の全てのリソースを割り当てる場合は、以下のようなコマンドを実行します。

```Powershell
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -Passthru
```

もし、リソースを調整したい場合は、下記のようにすると明示的にパラメーターを指定できます。

```Powershell
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MinPartitionVRAM 80000000 -MaxPartitionVRAM 100000000 -OptimalPartitionVRAM 100000000 -MinPartitionEncode 80000000 -MaxPartitionEncode 100000000 -OptimalPartitionEncode 100000000 -MinPartitionDecode 80000000 -MaxPartitionDecode 100000000 -OptimalPartitionDecode 100000000 -MinPartitionCompute 80000000 -MaxPartitionCompute 100000000 -OptimalPartitionCompute 100000000
```

その他リソースを仮想マシンに設定します。

```Powershell
Set-VM -GuestControlledCacheTypes $true -VMName "仮想マシン名"

Set-VM -LowMemoryMappedIoSpace 1GB -VMName "仮想マシン名"

Set-VM –HighMemoryMappedIoSpace 32GB –VMName "仮想マシン名"
```

### 仮想マシンに準仮想`GPU`のドライバーを追加する方法

上記の設定で既に、仮想マシンから仮想`GPU`は見えていますが、この時点でまだ動作はしていません。

仮想マシンに、ドライバーを追加する必要があります。

この時、物理マシンに`GPU`ドライバーをインストールする場合と同じように、仮想マシンにドライバーをインストールしようとしてもできません。

この`GPU`は、通常の`GPU`とは異なる準仮想化`GPU`です。

ドライバーをインストールしても、タスクマネージャーに表示されなかったり、`GPU`の一部のステータスを確認することができません。

そのため、ドライバーをインストールするためには、親マシンからドライバーをコピーする必要があります(そのため、`NvidiaのRTX VSR`などの設定を行うことができず、利用できません)。

**[この仮想マシンにドライバーを追加する手順](#仮想マシンに準仮想gpuのドライバーを追加する方法)は、親マシンの`GPU`ドライバーを更新する度に行う必要があります。**

#### 親マシン上にある`GPU`ドライバーの保存場所の確認

`Powershell`で、下記コマンドを実行します。

```Powershell
Get-CimInstance -ClassName Win32_VideoController -Property * | Format-Table InstalledDisplayDrivers
```

以下のような結果が、返ってきます。

```Powershell
InstalledDisplayDrivers
-----------------------
C:\Windows\System32\DriverStore\FileRepository\nv_dispi.inf_amd64_50916785244854f2\nvldumdx.dll,C:\Windows\System32\DriverStore\FileRepository\…
```

この環境での利用している`GPU`ドライバーを保存しているフォルダは、`C:\Windows\System32\DriverStore\FileRepository\nv_dispi.inf_amd64_50916785244854f2\`であることがわかります。

#### 仮想マシンへのドライバーコピー

このドライバーのフォルダを仮想マシンの`C:\Windows\System32\HostDriverStore\FileRepository\`に配置して下さい。

この手順を初めて行う場合、仮想マシンに`HostDriverStore`は存在しないと思われます。

そのため、`C:\Windows\System32`内に`HostDriverStore`フォルダを作成し、その中に`FileRepository`を作成し、更にその中に先程確認したドライバーのフォルダ(今回の場合、`nv_dispi.inf_amd64_50916785244854f2`)をコピーします。

コピーの方法は、`Pro`以上のエディション限定の拡張セッションや`RDP`によるコピペ(権限の問題で一旦デスクトップ等にコピーする必要があると思われます)、`SSH Server`を有効にしての`scp`コマンドや`sftp`コマンドによるコピー、仮想マシンの仮想ハードディスクを親マシンにマウントしてコピー等々様々な方法がありますが、好きな方法でコピーして下さい。

#### (`Nvidia`製`GPU`限定) 仮想マシンで`CUDA API`を利用可能にする

上記までの手順で、仮想`GPU`は利用可能になりましたが、`AI`プログラミング等で用いられる`CUDA API`は利用できません(`nvidia-smi`コマンドも実行できません)。

これを利用可能にするためには、親マシンから、仮想マシンに追加でファイルをコピーする必要があります。

親マシンの`C:\Windows\System32\nvapi64.dll`を子マシンへ同じパスとなるようにコピーします。

コピーの方法は先程と同様に、お好きな方法をご利用下さい。

## 仮想`GPU`の確認

これで、次に仮想マシンを起動すると、GPUを認識し、利用できるようになりました。

![GPU-P_Enable.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/cfd9b1c5-ae47-2063-f889-c7ebd45611a9.jpeg)

`Windows Terminal`は`3D`アクセラレーションが有効でないと透過されないので`3D`アクセラレーションが利用できている事がわかると思います。

![GPU-P_Disable.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/09d1e702-0f7d-3f32-3ad2-bbc1bb2beb26.jpeg)

上は認識していない時です。

ゲーム(ベンチマーク)でも、認識しました。

![GPU-P_PSO2ベンチ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/5b8c8066-74c4-4016-fdf5-4713704204a8.jpeg)

![GPU-P_FFベンチ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/ab71a36b-6ef2-8e57-a032-eebf0fbb6d00.jpeg)

PSO2ベンチとFFベンチを回しました。

CPUの割当は4コア、メモリは固定8GB、可変`vhdx`(`SSD`上)です(ドラクエベンチは起動しませんでした)。

親で計測した時よりもかなり落ちていますが、リソースが制限されている事、親マシンと子マシンでリソースを共有している事を考えるとこんなものかという感じですね。

それでも、やや快適なので仮想マシン接続の問題を解消できれば、それなりに使えるようになるものと考えられます。

## `CUDA API`の動作確認

仮想マシンに`Visual Studio 2019`と、`CUDA`をインストールして`deviceQuery`をビルドしました。

`CUDA`のインストールも出来ましたし、`deviceQuery`のビルドも成功して実行すると以下のように認識していたので`CUDA API`も使えると思われます。

![GPU-P_CUDA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/82ebb3f8-175e-fc46-8a57-1c817a6ffae7.png)

![GPU-P_CUDA2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/85626aa1-78b3-4485-2eff-5e75a8c40a26.png)

## GPU Partition Adapterの削除

**管理者権限のPowershell**で、以下のコマンドを実行します。

```Powershell
Remove-VMGpuPartitionAdapter -VMName "仮想マシン名"
```

削除すると、チェックポイントも再び使用可能になります。

`GPU`ドライバーの削除等は、別途手動で行って下さい。

## `Windows 10`以外の子マシンでの動作確認(Windows系のみ)

`Windows 8.1`(`Gen 2 VM`): 以下のように認識はしますが,動作はしません。(`GPU Partition Adapter`を追加すると、以下のように`USB`のようなリムーバブルデバイスとして表示されます。アンマウントすると`GPU`を認識しなくなり,`3D`アクセラレーションが利用できなくなります。)

![GPU-P_Windows8.1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/0e6cb9d3-507d-c159-6da3-1b982ef440ce.jpeg)

`Hyper-V Server 2019`(`Gen 2 VM`): 同様に認識はしますが、動作はしません。

`Windows Server 2019` デスクトップエクスペリエンス(`Gen 2 VM`):Hyper-V Server 2019と同じ。

`Windows 7`(`Gen 1 VM`):認識も動作はしません.(第一世代仮想マシンは認識すらしない?)

### `Windows 10 (21H1)`の親マシンでの検証

`Windows Server 2022` デスクトップエクスペリエンス(`Gen 2 VM`): `Windows 10`と同様に正常に動作。

![GPU-P-WS0222.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/5035daba-27a8-8146-1f7a-dac05bb3e751.png)

`Windows 11 21H2` 正式版(`Gen 2 VM`): Windows 10と同様に正常に動作.

![GPU-P-W11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743928/df97b0e4-5e8c-1192-1efa-a522c795cf23.png)

### `Windows 11 (21H2)`の親マシンでの検証

Hyper-Vの構成バージョンは10.0です(それまでに動いたもののみで検証)。

`Windows 10 21H1`(`Gen 2 VM`): 今までと同様に動作。

`Windows 11 21H2`(`Gen 2 VM`): 今までと同様に動作。

`Windows Server 2022` デスクトップエクスペリエンス(`Gen 2 VM`): 今までと同様に動作。

### (暫定)検証結果

- `Windows 10`のどこかのバージョン以上のバージョンの仮想マシンであれば、動作
- `Windows Server LTSC`の場合は、`Windows Server 2022`以降の仮想マシンでなければ動作しない(サポート終了の`SAC`は不明)
- サポートされている親マシンの`OS`と仮想マシンの`OS`の組み合わせであれば、バージョンが異なっていても動作

## その他参考

- [Windows11上でGPU有効な仮想Windows11を動かす](https://qiita.com/botter99/items/c0022ed1906a74decc37)
- [dxgkrnl_ubuntu](https://github.com/brokeDude2901/dxgkrnl_ubuntu)