Apple Silicon Mac · Windowsゲーム互換 · 多層変換

MacでWindowsゲームが動かない理由

答えは「翻訳が一段ずつ積み上がるから」

Apple Silicon 以降、MacでWindowsのゲームを動かすのは「翻訳を一枚かませば済む」話ではなくなった。CPUの命令、Windowsのシステムコール、描画、動画、音声 ― それぞれ別々の翻訳層を通り、しかも層が縦に積み上がる。層が増えるほど、絵や音が「継ぎ目」で落ちる。この Case Notes がなぜ何本も存在するのか、その地図を先に描いておく。

x86 → arm64 · DirectX → Vulkan → Metal · GDI · DirectDraw · DirectShow → GStreamer · wined3d · DXVK · MoltenVK

Apple Siliconで二つの互換手段を失った

Apple が Mac のチップを Intel から自社設計(Apple Silicon)へ切り替えたとき、Windowsゲームを動かす素直な道が二本とも塞がった。

ひとつは CPUの命令セットが変わったこと。Windowsの exe は x86 という命令で書かれているが、Apple Silicon は ARM という別系統で、そのままでは 一命令も実行できない。もうひとつは 退路の消滅だ。Intel Mac 時代には二つの逃げ道があった ― Windows向けの命令を変換する Rosetta と、Mac に Windows を直接入れる Boot Camp。だが Rosetta は Intel *Mac* アプリを動かすための仕組みで Windows の exe は対象外。Boot Camp は Apple Silicon で廃止された。

Rosetta で変換する

x86 Windows exe → ✕

Rosetta 2 が変換するのは Intel 版の *Mac* アプリだけ。Windows の実行ファイルは形式そのものが違い、対象外。

Windows を入れて動かす

Boot Camp → ✕ 廃止

MacにWindowsを直接インストールして切り替える Boot Camp は、Apple Silicon 世代では提供されなくなった。

「そのまま動かす」も「Windowsを入れる」も塞がった。残るのは 翻訳して動かす道だけ ― そしてその翻訳は、一枚では終わらない。

WineとRosettaがAPIと命令を別々に変換する

ゲームを動かす土台になるのが Wine だ。ただし、これは「一枚の翻訳」ではなく、すでに二重になっている。

Wine は、WindowsをインストールせずにWindowsアプリを動かす互換レイヤーで、ゲームが呼ぶWindowsのシステムコール(API)を macOS の API へ翻訳する。エミュレーターではなく「翻訳者」なので、ここまでは一段。だがゲームの中身は依然 x86 の命令のまま。ARM の Mac で走らせるには、その命令自体を ARM へ変換する層がもう一枚要る。APIの翻訳(Wine)と命令の変換、この時点で翻訳は二枚重なっている。

DirectXからMetalまで描画命令を三段階で変換する

画面に一枚の絵が出るまでが、いちばん長い。Windowsゲームは DirectX で描くが、macOSにDirectXは無い。だから絵は何度も別のAPIに載せ替えられる。

1
DirectX
ゲームが描く
2
DXVK / wined3d
Direct3D を受ける
3
Vulkan
中間API
4
MoltenVK
Vulkan→Metal
5
Metal
GPUが描く
DirectXの命令は DXVK で Vulkan に、Vulkan は MoltenVK で Apple の Metal に、と順に載せ替わってようやくGPUに届く(古いゲームでは DXVK を使わず wined3d が同じ役割を担う別ルートもある)。一枚の絵のために、翻訳が三段以上重なる。

古いAPIは描画経路をさらに分岐させる

やっかいなのは、ビジュアルノベルが今も現役なのに、中身は2000年代のAPIを引きずっている点だ。新しい翻訳鎖の 外側を通る古い経路が、タイトルごとに混ざる。

2000年代の2D描画

GDI / DirectDraw

DirectXより古い描画の仕組み。今の Direct3D→Metal の鎖とは別経路で処理され、Mac上では別の壊れ方をする。

古い動画再生

DirectShow / VMR

OPやロゴのムービーを再生する旧世代フレームワーク。Wineでは GStreamer などを経由し、映像・音声・同期がそれぞれ別々に翻訳される。

層が読めない

エンジン名では決まらない

同じ「動画が黒い」でも、通っている層はタイトルごとに違う。だから エンジンの名前だけでは、どの翻訳が壊れたのか特定できない。

Windowsゲームが画面へ届くまでの五つの層

一枚の絵、一つの音、一枚のサムネイル ― それが画面に届くまでに、これだけの層を通り抜ける。

01
Windowsゲーム x86 の命令 / DirectX / 古い描画・動画API
02
Wine(Swingby Wine) Windows API → macOS API の翻訳層
03
命令変換 + 描画変換 x86→ARM / DirectX→(DXVK / wined3d)→Vulkan
04
MoltenVK Vulkan → Metal の翻訳
05
Metal / macOS ようやく画面に絵が出る

↑ どの層も単体では正しい。壊れるのは、いつも層と層の「継ぎ目」

互換性問題は変換層の継ぎ目で起きる

各層は単体では動く。だが翻訳が積み上がると、継ぎ目でフレームが画面に出なくなる ― 絵が黒くなる、映像は流れるのに音だけ消える、描いているのに真っ黒、メニューが真っ白になる。この Case Notes は、その一つひとつの継ぎ目を解体した記録だ。

継ぎ目 · D3D9 / wined3d

CMVSのセーブ画像が黒い

Present後に失われるフレームを、GetBackBuffer + LockRectへ供給した記録。

CASE を読む →
継ぎ目 · 動画と音声

winegstreamerで動画の音だけ途切れる

映像が続く一方で音声だけ約1秒途切れる現象を、multiqueueの上限とA/Vインターリーブまで切り分けた記録。

CASE を読む →
継ぎ目 · DirectX→Metal

DXVKでD3D9の画面が黒い

DXVKの固定機能シェーダでbinding 16が未bindになる条件を、DrawPrimitiveUPの入力まで追って修正した記録。

CASE を読む →
継ぎ目 · 副作用

CatSystem2で動画OFFにするとメニューが消える

CatSystem2で動画再生経路のON/OFF差分を比較し、採用運用と残課題を分けた記録。

CASE を読む →
継ぎ目 · OSの実行許可

Wineを更新すると旧作が起動しない

Wine更新後に旧作が起動しなくなった現象を、file-backed mmapのEXEC付与順序まで切り分けた記録。

CASE を読む →
継ぎ目 · Metal と OpenGL の同居

Artemisで動画だけが白いまま映らない

DirectDrawの前面描画ビューがMetal表示の背後に隠れる原因を切り分け、Metal上へ表示した記録。

CASE を読む →
継ぎ目 · D3D11 / DXVK

DXVKでD3D11のセーブ画像が黒い

非ゼロのswapchain buffer要求が拒否される原因を、DXVKのGetImageまで追った記録。

CASE を読む →
継ぎ目 · PE署名検証

imagehlpのPE署名検証が通らない

署名の照合が通らない原因を、DigestLevelフラグと計算範囲まで追って修正した記録。

CASE を読む →