注意書き

本サイトでは、アフィリエイト広告およびGoogleアドセンスを利用しています。

wineコンテナでGPUを使う

インフラストラクチャ

以前の記事までは、仮想マシンにGPUを使わせるという話でしたが、今回はUbuntu 24.04が動いているホストPCで、Dockerコンテナ側でGPUを使いたい!という話を書きます。基本的に動作環境は以前と同様にAMDのStrixHaloシリーズでやっていますが、NVIDIA Geforce RTX3060でも動いていました。

スポンサーリンク

やりたいこと&動機

仮想マシンにGPU接続も面白かったですが、それができるならばコンテナでもやってみたくなるのが私という人間です。そもそも Dockerを用いると CUDA 環境は簡単にコンテナ側で作れる時代ですし、それならWineでもと思うのです。とくにホスト環境をひどく汚しそうなものはコンテナ内に押し込んでおきたいですよね(まさにCUDA環境… Wineも試行錯誤するとそうなると思っています)

Wineとは

このページに辿り着く人は Wineは既に知っていることと思います。が念のため軽く説明しておきます。 Wine は「Wine Is Not an Emulator」で、WindowsのGUIアプリケーションをLinux環境で直接実行できる互換レイヤーを提供するものです。Windows APIの処理などをその場オンザフライで変換しながら動作するので、仮想マシンと比べると動作が軽量となっています。

この記事を書いている時点では Wine 11.0 が出たところで、私もこのバージョンを使っています。

コンテナに押し込めたい

既に記載していますが、Wineの環境は試行錯誤しながら作り上げていくことが必要な気がしています。また周辺のモジュールを組み合わせたり、特定のWindowsアプリ用の設定など、色々作業しているとホストの環境をかなり汚していきそうな印象があります。そこで、コンテナの中に押し込めてしまい、ホストの環境はクリーンな状態のままにしたいのです。

GPUを使いたい

本ブログをこれまでも見ている人はよく知っていると思うのですが、私は DirectX12やらVulkanやらグラフィックスAPIを触る機会が多いです。これらのAPIをコンテナの内側から触っていきたい欲求もありました。

Wine + Proton + DXVK などを組み合わせると Linux 環境でも DirectX12 (D3D12) アプリが動くと見かけて、それなら自分も作ってみるかと作業を始めてみた次第です。

そういえば、SteamDeck では Protonを使ってゲームアプリを動かしていたんでしたね。 Steam OSもまたベースはLinux系(Archlinux)ですし、このソフトウェアの構成でD3D12なアプリが動くというのは時代としても安定してきたのかなと思います。

Wine+Proton+DXVK入りコンテナを作る

それではコンテナイメージを作っていきます。ベースはUbuntu 24.04を使うとして、必要なパッケージやファイルをコンテナの中にセットアップしていきます。詳細な説明は割愛しますが、公式ページで配布されているアーカイブを取得して、環境内に展開するなどをしています。

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

ARG DXVK_VER=2.7.1
ARG VKD3D_PROTON_VER=3.0
ARG WINE_VER=11.0.0.0~noble-1

ENV WINEPREFIX=/wineprefix

# 基本ツール + X11関連最小 + wine前提の依存(64bit)
RUN apt-get update && apt-get install -y --no-install-recommends \
      ca-certificates curl wget gnupg locales \
      xauth zstd tar cabextract winbind \
      fontconfig fonts-noto-cjk \
      unzip util-linux \
      x11-xserver-utils \
      mesa-vulkan-drivers libvulkan1 vulkan-tools \
      libgl1 libegl1 libx11-6 libxext6 libxrender1 libxrandr2 libxcursor1 \
      libxcomposite1 libxfixes3 libxdamage1 libxi6 libxkbcommon0 libxcb1 \
      libfreetype6 libdbus-1-3 psmisc \
    && rm -rf /var/lib/apt/lists/*

## 32bit
RUN dpkg --add-architecture i386
RUN apt-get update && apt-get install -y --no-install-recommends \
            mesa-vulkan-drivers:i386 libvulkan1:i386 \
            libgl1:i386 libx11-6:i386 libxext6:i386 \
            libxrender1:i386 libxrandr2:i386 libxcursor1:i386 \
            libxcomposite1:i386 libxfixes3:i386 libxdamage1:i386 \
            libxi6:i386 libxkbcommon0:i386  libxcb1:i386 \
            libfreetype6:i386  libdbus-1-3:i386 \
        && rm -rf /var/lib/apt/lists/*
RUN fc-cache -fv

# 日本語ロケール生成
RUN sed -i 's/^# \(ja_JP.UTF-8\)/\1/' /etc/locale.gen && \
    locale-gen
ENV LANG=ja_JP.UTF-8
ENV LC_ALL=ja_JP.UTF-8

# WineHQ (Ubuntu 24.04 noble)
RUN mkdir -pm755 /etc/apt/keyrings && \
    wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key && \
    wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/noble/winehq-noble.sources && \
    apt-get update && \
    apt-get install -y --install-recommends winehq-stable-amd64=${WINE_VER}

# ---- DXVK / vkd3d-proton をイメージに同梱 ----
RUN set -eux; \
    mkdir -p /opt/dxvk /opt/vkd3d-proton; \
    cd /tmp; \
    curl -L -o dxvk.tar.gz "https://github.com/doitsujin/dxvk/releases/download/v${DXVK_VER}/dxvk-${DXVK_VER}.tar.gz"; \
    tar -xzf dxvk.tar.gz; \
    cp -a "dxvk-${DXVK_VER}/." /opt/dxvk/; \
    curl -L -o vkd3d.tar.zst "https://github.com/HansKristian-Work/vkd3d-proton/releases/download/v${VKD3D_PROTON_VER}/vkd3d-proton-${VKD3D_PROTON_VER}.tar.zst"; \
    tar --use-compress-program='zstd -d' -xf vkd3d.tar.zst; \
    cp -a "vkd3d-proton-${VKD3D_PROTON_VER}/." /opt/vkd3d-proton/; \
    rm -rf /tmp/*

# --- WINEPREFIXを用意  ---
RUN mkdir -p "${WINEPREFIX}"

ENTRYPOINT ["/bin/bash"]

このDockerfileからイメージを作っておきます。

docker build -t wine-sample-simple .

GPU をコンテナに引き渡す

IntelやAMDの環境でコンテナにGPUデバイスを引き渡すには、”/dev/dri” あたりをバインドマウントして渡すことで実現できます。注意点としてはデバイスにアクセスするためのグループには注意が必要ということです。

ひとまず、”win-apps” というディレクトリには Windows アプリケーションを置くとして、”wineprefix” というディレクトリには Wine の環境ファイル群を置くものとして、以下のようなコマンドでコンテナを起動します。

docker run -it -e DISPLAY="${DISPLAY}" -e LANG=ja_JP.UTF-8 -e LC_ALL=ja_JP.UTF-8 \
  -e WINE_X11_NO_MITSHM=1 -v /dev/shm:/dev/shm  \
  -v /tmp/.X11-unix:/tmp/.X11-unix:ro -v $HOME/.Xauthority:/xauth:ro -e XAUTHORITY=/xauth \
  -v /usr/share/vulkan/icd.d:/usr/share/vulkan/icd.d:ro   \
  -v /usr/share/vulkan/implicit_layer.d:/usr/share/vulkan/implicit_layer.d:ro \
  -v /usr/share/vulkan/explicit_layer.d:/usr/share/vulkan/explicit_layer.d:ro \
  -v ./wineprefix:/wineprefix -v ./win-apps:/win-apps \
  --user $(id -u):$(id -g) \
  --device=/dev/dri 
  --device=/dev/kfd \
  --group-add video --group-add render \
    wine-sample-simple

ひとまずコンテナ内のシェルに入ったところで、vulkaninfo コマンドを実行してみます。抜粋になりますが、GPU[0],GPU[1]が認識されており、最初のものがホスト環境で使っているGPUが見えています。省略していますが、Vulkanで利用可能な拡張機能なども列挙できています。

root@3c67e612fc8c:/# vulkaninfo --summary

Devices:
========
GPU0:
	apiVersion         = 1.4.305
	driverVersion      = 25.0.7
	vendorID           = 0x1002
	deviceID           = 0x1586
	deviceType         = PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
	deviceName         = AMD Radeon 8060S (RADV GFX1151)
	driverID           = DRIVER_ID_MESA_RADV
	driverName         = radv
	driverInfo         = Mesa 25.0.7-0ubuntu0.24.04.2
GPU1:
	apiVersion         = 1.4.305
	driverVersion      = 0.0.1
	vendorID           = 0x10005
	deviceID           = 0x0000
	deviceType         = PHYSICAL_DEVICE_TYPE_CPU
	deviceName         = llvmpipe (LLVM 20.1.2, 256 bits)
	driverID           = DRIVER_ID_MESA_LLVMPIPE
	driverName         = llvmpipe
	driverInfo         = Mesa 25.0.7-0ubuntu0.24.04.2 (LLVM 20.1.2)

NVIDIA Docker Runtime が導入済みなら、/dev/driを引き渡すのではなく、 “–gpus all” の引数オプションで対応が可能です。

コンテナ内からvkcubeを動かす

protonなどはD3D12の命令をVulkanの命令に翻訳するものです。ということで、まずはコンテナの中からVulkanを用いた描画がうまく行くかをみてみます。ここでは標準的に入ってくるであろう vkcube を用いて確認をします。 そして実行した結果が以下の通りです。ホストのウィンドウシステム上に コンテナ側で実行したVulkanプログラムの結果が表示されたので、うまく動作していることがわかります。

ここではVulkanのみ確認しましたが、glxgearsを準備するとOpenGLの描画も確認ができます。コンテナの中から OpenGLのアプリも動きます

Wineの環境を作る

コンテナの中でWINEPREFIXの場所に、仮想的なWindows環境を作っていきます。まず wineboot –init を実行して必要なものをインストール・準備していきます。

wineboot  --init

このコマンドを実行すると、マウントした wineprefix の場所に色々なファイルができあがります。たとえば、drive_c は Windows環境としてのCドライブ(の中身)になります。そのため、このディレクトリ以下にファイルを配置すれば、Windows環境として自然な形になります。

続いて、簡単にメモ帳あたりを動かしてみましょう。以下のコマンドを実行すると、一応 Windowsメモ帳が起動するのですが、日本語フォントなどはうまく表示されません。

# wine notepad.exe

フォントについては以下のようなレジストリファイルを作って、設定します。これが適用されると、先程うまく表示されなかったメニューなどは表示されるようになります。

REGEDIT4

[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes]
"MS Shell Dlg"="Noto Sans CJK JP"
"MS Shell Dlg 2"="Noto Sans CJK JP"
"Tahoma"="Noto Sans CJK JP"
"Arial"="Noto Sans CJK JP"
"MS UI Gothic"="Noto Sans CJK JP"
wine regedit   wine-jp-fonts.reg 

DirectX12用に設定を続ける

ここまでできると、一部の DirectX11 のアプリケーションなどは動いたりします。しかし、自分の作成した DirectX12 (D3D12) のアプリケーションはまだ動かないため、作業を続けます。

DXVK,Protonのものを使うよう設定を変える

以下のようなコマンドを実行して、ファイルのコピーと protonのセットアップを行います。

cp -vf /opt/dxvk/x64/*.dll "${WINEPREFIX}/drive_c/windows/system32/"
cp -vf /opt/dxvk/x32/*.dll "${WINEPREFIX}/drive_c/windows/syswow64/"
chmod +x "/opt/vkd3d-proton/setup_vkd3d_proton.sh"
"/opt/vkd3d-proton/setup_vkd3d_proton.sh" install --prefix "${WINEPREFIX}"

次に以下のようなレジストリファイルを作成し、適用します。

REGEDIT4

[HKEY_CURRENT_USER\Software\Wine\DllOverrides]
"dxgi"="native,builtin"
"d3d11"="native,builtin"
"d3d12"="native,builtin"
"d3d12core"="native,builtin"
wine regedit dx12-overrides.reg

こうするとようやくD3D12アプリケーションが起動します。以下は私が勉強用に作っていたD3D12サンプルプログラムです。”wine DrawModel.exe” という感じでの起動コマンドになりますが、このexeの場所をカレントに指定して起動するようにしています。

exeの位置から相対パスで、リソースファイルを読むようなプログラムのため、配置に苦戦しました。素直にexe配下にリソース用のフォルダを配置し、そこから読むような構造のほうがよかったなとおもっています。

インストーラーがあるようなもの

StreetFighter6 Benchmark が zip 形式でインストーラー配布されていたので、これを動かしてみましょう。wineの環境で使えるように展開し、 先程の win-apps/StreetFighter6_Benchmark に用意しておきます。そして、以下のようなコマンドでインストーラーを起動して、wine環境Cドライブにインストールします。

cd /win-apps/StreetFighter6_Benchmark
wine setup.exe 

インストールが終わったら起動してみます。普通の Windows 環境ならばスタートのメニューから選んで起動するのですが、ここでは wine 環境でのエクスプローラーを以下で起動し、exeを直接実行することにしてみます。

wine expolorer

しかし、アプリは起動するものの、ベンチマークを取るまで行かずに、クラッシュしてしまうという残念な結果になりました。ログを眺めていたら、サウンドデバイス関連でエラーが報告されていたので、これを解決すれば・・・とも思いましたが、グラフィックスメインのため、ここまでにしています。

まとめ

ここまでで簡単なアプリケーションならWine,Proton,DXVKなどを用いてLinux環境上でも何やら動くところまでできました。しかもコンテナ内に雑多なものは閉じるので、ホスト環境への影響は軽微にすることができました。

色々と手間だったり試行錯誤をしたのは、Wine,DXVKなどで環境のインストール先の所有権問題というところでしょうか。dockerコマンドでコンテナを起動するとき、ユーザーIDやらグループやらの設定が付与されているところがポイントです。

コメント

タイトルとURLをコピーしました