とにかく書く

日々の雑感や知り得たことを、とにかく書いています

QEMU 上の Windows 7 で DirectX を使う (Intel 内蔵 GPU 共用)

QEMU 上の WindowsDirectX を使うゲームなどを起動すると DirectX の初期化に失敗しましたと表示されて起動できない。 DirectX を使うためには、以下2つがある。

  1. Virtio を使って DirectX を動かす (Virtio ドライバは Fedora から署名付きで公開されている)
  2. Intel 内蔵 GPUQEMU で使うようにして WindowsIntel グラフィックドライバをインストールする

今回は、後者を実施したためメモする。


問題

dxdiag を起動してディスプレイタブを見ると、DirectX がすべて「利用できません」になっていた。 デバイスマネージャで確認すると、ディスプレイドライバが、標準VGAディスプレイドライバになっている。 GPU-Z を起動して GPU を見ると、GPU の情報が何も表示されない。

環境

項目 内容
CPU Intel Core i5-8400
GPU1 Intel Core i5-8400 内蔵
GPU2 Nvidia GeForce GTX 960
マザーボード MSI Z370 GAMING PLUS
ブートローダ GRUB
ホストOS Arch Linux
ゲストOS Windows 7 (32bit版)

注:32ビット版は、Intel ドライバがインストールできないため64bit版を使う必要がある

Intel 内蔵 GPUQEMU と共用する

ここでは、以下の作業を行った。

  1. Nvidia GPU だけを使用していたので、Intel 内蔵 GPU も併用するようにした (指定したときだけ Nvidia GPU が使われる)
  2. Intel 内蔵 GPU の仮想 GPU を作成し、QEMU から GPU が共用できるようにした

Intel 内蔵 GPU をメインで使用する

当初、GPU としては Nvidia の外付け GPU しか使用していなかった。

$ lspci | grep VGA
02:00.0 VGA compatible controller: NVIDIA Corporation GM206 [GeForce GTX 960] (rev a1)
$ xrandr --listproviders
Providers: number : 1
Provider 0: id: 0x1b7 cap: 0x1, Source Output crtcs: 4 outputs: 9 associated providers: 0 name:NVIDIA-0

BIOS の設定にて、使用する GPU を PEG (PCI接続GPU) から IGD (CPU内蔵GPU) に変更した。 マザーボード上の Intel GPU に変えたため、ディスプレイケーブルを Nvidia GPU の端子からマザーボードの端子に挿し直さなければならない。

すると Intel 内蔵 GPUNvidia GPU が両方とも認識された。

$ spci | grep VGA
00:02.0 VGA compatible controller: Intel Corporation CoffeeLake-S GT2 [UHD Graphics 630]
02:00.0 VGA compatible controller: NVIDIA Corporation GM206 [GeForce GTX 960] (rev a1)

Intel 内蔵 GPUNvidia GPU を併用する

両方とも認識した状態であれば、必要なときに指定することで Nvidia GPU を適用してプログラムを動作させることができるようになる (NVIDIA Optimus)。

ただし、NVIDIA が提供するクローズドソースのドライバではなく、Nouveauドライバを使用する必要がある。そのため、クローズドソースドライバを削除した。

# pacman -Rs nvidia nvidia-utils lib32-nvidia-utils

Nouveau ドライバは、Intel 内蔵 GPU を使用するため、mesa をインストール済み。

カーネルモジュールとして nvidia を追加している場合は削除する必要がある。

/etc/mkinitcpio.conf
MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm kvmgt)
を
MODULES=(kvmgt)

カーネルイメージを再生して再起動した。

 # mkinitcpio -p linux
 # reboot

/usr/lib/modprobe.d/nvidia-utils.conf に blacklist Nouveau が書いてあったけど、nvidia ドライバのアンインストール時に自動的に削除されていた。

xrandr --listproviders の出力が modesetting (Intel) と nouveau (Nvidia) になった。

$ xrandr --listproviders
Providers: number : 2
Provider 0: id: 0x46 cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 3 outputs: 5 associated providers: 1 name:modesetting
Provider 1: id: 0xaf cap: 0x7, Source Output, Sink Output, Source Offload crtcs: 4 outputs: 5 associated providers: 1 name:nouveau

環境変数 DRI_PRIME=1 をセットしたときだけ NvidiaGPUを使うことができるようになる。 (指定しないと常に Intel 内蔵 GPU が使われる。)

 $ glxinfo | grep "OpenGL renderer"
OpenGL renderer string: Mesa Intel(R) UHD Graphics 630 (CFL GT2)
 $ DRI_PRIME=1 glxinfo | grep "OpenGL renderer" 
OpenGL renderer string: NV126

NV126 は Nouveau のコードネーム

Intel 内蔵 GPUQEMU で共用する

Intel 内蔵 GPU は、Intel GVT-g によって仮想マシンに仮想GPUを見せることで内蔵 GPU を共用する。

カーネルパラメータに i915.enabel_gvt=1 i915.enable_guc=0 gvt=1 intel_iommu=on を追加する。

/etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="その他の設定 i915.enable_guc=0 i915.enable_gvt=1 intel_iommu=on"
# grub-mkconfig -o /boot/grub/grub.cfg
# reboot

Intel 内蔵 GPUPCI アドレスを確認する。

$ lspci | grep VGA
00:02.0 VGA compatible controller: Intel Corporation CoffeeLake-S GT2 [UHD Graphics 630]
02:00.0 VGA compatible controller: NVIDIA Corporation GM206 [GeForce GTX 960] (rev a1)

ここでは、0000:00:02.0 がアドレスになる。

作成できる仮想 GPU (vGPU) のタイプを確認する。

 # GVT_PCI=0000\:00\:02.0
 # ls /sys/bus/pci/devices/$GVT_PCI/mdev_supported_types/
i915-GVTg_V5_4  i915-GVTg_V5_8

各タイプの意味は description の中に書かれている。

 # sudo cat /sys/bus/pci/devices/$GVT_PCI/mdev_supported_types/i915-GVTg_V5_4/description 
low_gm_size: 128MB
high_gm_size: 512MB
fence: 4
resolution: 1920x1200
weight: 4

vGUI の GUID を uuidgen コマンドで生成し、環境変数 GVT_GUID にセットする。vGPU のタイプも GVT_TYPE にセットしておく。

GVT_PCI=0000\:00\:02.0
GVT_GUID=$(uuidgen)
GVT_TYPE=i915-GVTg_V5_4

vGPU を作成する。ただ、この操作は sudo ではできず、su で root にならないとパーミッションがないと言われた。

 # echo "$GVT_GUID" > "/sys/bus/pci/devices/$GVT_PCI/mdev_supported_types/$GVT_TYPE/create"

後述のオプションをつけて qemu を起動すると、 failed to open /dev/vfio/11: Permission denied と言われたので、読み書き可能にした。

 # chmod 666 /dev/vfio/11

-device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:00:02.0/17562a86-9d15-4a38-9217-a1c66809eb8d,rombar=0 をつけて qemu を起動した。環境変数は毎回セットするのが面倒なので、絶対パスにした。

$ qemu-system-x86_64 -enable-kvm -m 3G -net nic -net user -drive file=/mnt/QEMU/Win7,format=raw,index=0,media=disk -cpu host,hv-time,hv-relaxed,hv-vapic,hv-spinlocks=0x1fff,hv-runtime -machine accel=kvm -device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:00:02.0/17562a86-9d15-4a38-9217-a1c66809eb8d,rombar=0 -display sdl,gl=on

QEMU 上で GPU-Z を起動すると、無事に Intel 内蔵 GPU が読み込まれていることを確認できた。(32ビットOSだったので、Intel グラフィックドライバはインストールできなかった…。)

付録 (Vertio で対処する)

当初、Vertio で Direct Xを動かそうとしていた。 しかし、Fedora のドライバでは、今日時点ではすでに Windows 8 以降でないとインストールできない。 そのため、Windows 7 での Virtio の適用はやめ、GTX-d 共用を実施することとした。