前回の続き、ただし今回はWineを使わない

スポンサーリンク

前回は、Apple純正の Game Porting Toolkit(GPTK)を使い倒しました。結論は「D3DMetalは速さを、Wineは遊べるかを決めている」で、公式の GPTK 4 は載せ替えでは動かせずに終わりました。

ただ、あのとき調べていて気づいたことがあります。GPTK 4 のうち、Wineが必要なのは「評価環境」だけなのです。dmgの中には、Wineをまったく使わない部分がありました。

そして公式リポジトリを覗いたら、予想外のものが入っていました。

Appleが、AIコーディングエージェント用のスキルを配っていた
apple/game-porting-toolkitClaude Code / Codex / Gemini 向けのプラグインが入っていました。スキル24本とエージェント1本。ライセンスは Apache 2.0
このブログはClaude Codeで開発しているので、他人事ではありません😳

今回は、そのスキルの中身を読み、書かれている手順どおりにシェーダの変換を実際にやってみます。前回動かせなかったGPTK 4が、ここでは素直に動きます。

なお再現できることを重視して、コマンドと版とパスを全部載せています。長くなりますが、そのぶん手元で追えるはずです。

用語集

用語平たく言うと
シェーダGPUの上で動く小さなプログラム。物の色や形をどう描くかを決めます。ゲームには何百本と入っています
HLSLDirectX向けにシェーダを書く言語。人間が書くのはここ
DXILHLSLをコンパイルした中間表現。ゲームが配布時に持っているのは大抵この形です
Metal IR / AIRApple側の中間表現。DXILに対応するもの
metallibMetalがGPUに渡せる形にまとまったファイル。今回の変換のゴール
エントリポイントシェーダの入口になる関数名(今回は MainVS MainFS)。あとでこれが効いてきます
reflection「このシェーダはどんな入力を欲しがっているか」の一覧。プログラム側が値を渡すときの手がかりになります
エージェントスキルAIコーディングエージェントに読ませる手順書。「この作業のときはこう進めろ」を文書で渡す仕組みです

Appleがエージェント用のスキルを配り始めた

まずリポジトリを取ってきます。

git clone --depth 1 https://github.com/apple/game-porting-toolkit.git
項目実測
規模22 MB
初回コミット4f42344 / 2026-06-07(WWDC当日)
ライセンスApache License 2.0
中身.claude-plugin/ game-porting-skills/ samples/ docs/ metal-cpp

Appleは「プルリクエストは受け付けていない」と明記しています。配布はするが共同開発はしない、という姿勢です。

公式が挙げている前提はこうでした。手元の環境は、後ろ2つを満たしていません

前提手元
Apple silicon の MacM4 ✓
Game Porting Toolkit 44.0 beta 2 ✓
macOS 27(新しいデバッグツールのため)26.5.2 ✗
Xcode 27(エージェント向けMCPのため)26.5 ✗

つまりワークフロー全体はmacOS 27前提です。ただ、これから実演するシェーダ変換の部分は26のままで完結します。

24本のスキルには何が書いてあるのか

スキルは大きく2種類に分かれていました。

24本のスキルは2種類に分かれている Expert skills(専門知識) 「これはこう書く」を教える15本 translating-to-metal4-api(545行) D3D12 / Vulkan / Metal3 → Metal4 の対訳表 using-game-controller(447行) XInput / DirectInput からの移行 compiling-with-metal-shaderconverter ★今回使うのがこれ ほか MetalFX・同期・リソース管理・デバッグ Workflow skills(進め方) 移植の段取りそのものを決める9本 porting-methodology(361行) 全体の方法論 discover → plan-goal → start-milestone → execute → validate → status → handoff ★セッションをまたいで状態を保存すると明記 =「AIが何日もかけて移植を進める」前提の設計 合計およそ4,000行。ほかに porting-assistant というエージェント定義が1本

面白かったのはWorkflow skillsのほうです。discover(調べる)→ plan-goal(目標を立てる)→ start-milestone(区切りを始める)→ execute(進める)→ validate(検証する)→ handoff(引き継ぐ)と並んでいて、セッションをまたいで状態を保存すると書かれています。

これは「AIエージェントが何日もかけてゲームを移植する」ことを前提に設計されているということです。人間が読むドキュメントを整備した、という話ではありません。

導入手順(と、今回あえて実行しなかった理由)

公式が案内している導入方法はこうです。

# Claude Code
/plugin marketplace add apple/game-porting-toolkit
/plugin install game-porting-skills@game-porting-toolkit

# Codex CLI
codex plugin marketplace add https://github.com/apple/game-porting-toolkit
codex plugin add game-porting-skills@game-porting-toolkit

ローカルにクローン済みなら、パスを渡す形でも登録できます。

⚠ 今回はこの導入を実行していません
プラグインの登録は開発環境の設定を書き換える行為です。普段の作業に使っている環境なので、記事のために触るのは避けました。
代わりにクローンしたスキルを直接読み、そこに書かれた手順を自分の手で実行しています。以下でやっていることは、エージェントにスキルを読ませた場合とまったく同じ内容です。

実演:スキルの手順どおりにシェーダを変換する

使うのは compiling-with-metal-shaderconverter(110行+参照3本)です。このスキルは手順が段階的に書かれているので、そのままなぞります。

Step 1:ツールを用意する(インストールせずに)

Metal Shader Converter は GPTK 4 の dmg に .pkg で入っています。普通に入れると /usr/local/bin に配置されますが、展開するだけで使えます。管理者権限も要りません。

pkgutil --expand-full "/Volumes/Game Porting Toolkit 4.0 beta 2/Metal Shader Converter 4.0 beta 2.pkg" msc_pkg

MSC="msc_pkg/MetalShaderConverter.pkg/Payload/usr/local/bin/metal-shaderconverter"
chmod +x "$MSC"
"$MSC" --version
metal-irconverter version: 4.0.1
Default triple: air64-apple-macosx15.0.0

GPTK 4 の変換器が、macOS 26 の上で普通に起動しました。前回あれだけ苦労したのが嘘のようです😅

ついでに、展開先には man ページとヘッダも入っています。

msc_pkg/MetalShaderConverter.pkg/Payload/usr/local/share/man/man1/metal-shaderconverter.1
msc_pkg/MetalShaderConverter.pkg/Payload/usr/local/include/metal_irconverter/

Step 2:変換元のDXILを用意する

スキルには「metal-shaderconverter はDXILしか受け取らない。HLSLはまずDXCでコンパイルせよ」と書かれています。

ただ今回はDXCが要りません。GPTK 4 のサンプル(gptk-sample)に、コンパイル済みのDXILが4本入っているからです。

gptk-sample/Cache/present_vs.dxil            12,548 B
gptk-sample/Cache/present_fs.dxil            16,008 B
gptk-sample/Cache/sprite_instanced_vs.dxil   12,836 B
gptk-sample/Cache/sprite_instanced_fs.dxil   10,672 B

元のHLSLは gptk-sample/06 - ShaderConversion/ にあります。present.hlsl の冒頭はこんな形でした(Apache 2.0)。

struct FrameData
{
    float4x4 projectionMx;
    float    maxEDRValue;
    float    brightness;
    float    currentEDRBias;
};

ConstantBuffer<FrameData> frameData : register(b0, space0);
Texture2D<float4> inTexture : register(t0, space1);
SamplerState samp : register(s0, space2);

DirectXらしい register(b0, space0) の書き方が見えます。この「レジスタに割り当てる」という考え方をMetal側にどう持っていくかが、変換器の仕事の中心です。

Step 3:変換する

スキルは「バインドするコードを書くならreflectionも一緒に出せ」と勧めているので、そうします。

for f in *.dxil; do
  b="${f%.dxil}"
  "$MSC" "$f" -o "$b.metallib" --output-reflection-file "$b.json"
done
シェーダDXIL→ metallibreflection
present_vs12,548 B12,168 B1,167 B
present_fs16,008 B13,272 B910 B
sprite_instanced_vs12,836 B11,864 B1,445 B
sprite_instanced_fs10,672 B10,152 B899 B

4本すべて成功。しかも一瞬でした。reflection の中身はこうです。

{
  "EntryPoint": "MainVS",
  "ShaderType": "Vertex",
  "ShaderID": "7395964894968409886",
  "TopLevelArgumentBuffer": [
    { "Type": "CBV",   "Size": 8, "Slot": 0,          "EltOffset": 0 },
    { "Type": "Table", "Size": 8, "Slot": 4294967295, "EltOffset": 8 }
  ]
}

DirectXの「定数バッファ(CBV)」「テーブル」という概念が、そのまま名前として残っています。42949672950xFFFFFFFF、つまり「未使用」の意味です。

★本当にMetalが読めるのかを、自分で確かめる

ここでいったん立ち止まりました。前回、「動いた」と「D3DMetalで動いた」が別物だったので、同じ轍は踏みたくありません。

file コマンドは MetalLib executable (MacOS), version 1.2.7 と言っています。でもそれはファイルの見た目がそれらしいという話で、GPUが受け付けるかは別です。

そこで、実機のGPUに読ませて関数を列挙する小さなSwiftを書きました

import Metal
import Foundation

let device = MTLCreateSystemDefaultDevice()!
print("GPU: \(device.name)")

for path in CommandLine.arguments.dropFirst() {
    let data = try Data(contentsOf: URL(fileURLWithPath: path))
    // ★ファイル名で渡さず、バイト列から読ませる=ゲームが実行時にロードするのと同じ経路
    let lib = try data.withUnsafeBytes { raw -> MTLLibrary in
        let dd = DispatchData(bytes: UnsafeRawBufferPointer(raw))
        return try device.makeLibrary(data: dd as __DispatchData)
    }
    for n in lib.functionNames.sorted() {
        let fn = lib.makeFunction(name: n)!
        print("  \(n)  type=\(fn.functionType.rawValue)")
    }
}
swiftc -O verify_metallib.swift -o verify_metallib
./verify_metallib *.metallib
GPU: Apple M4
  ✅ present_vs.metallib          — MainVS  type=1   (頂点シェーダ)
  ✅ present_fs.metallib          — MainFS  type=2   (フラグメントシェーダ)
  ✅ sprite_instanced_vs.metallib — MainVS  type=1
  ✅ sprite_instanced_fs.metallib — MainFS  type=2
ここがこの記事でいちばん確かな部分です
ファイル形式が正しそうに見えるだけでなく、実機のM4のドライバが受け取り、頂点シェーダ・フラグメントシェーダとして種別まで判別できたということです。
わざと ファイルパスではなくバイト列(DispatchData)から読ませているのもポイントで、ゲームが実行時にロードするのと同じ経路を通しています。

複数シェーダをまとめる2つの方法と、名前が消える罠

ゲームにはシェーダが何百本と入ります。1回の変換で1つのmetallibしか出ないので、まとめる必要があります。スキルの参照ドキュメントには2つの方法が書かれていました。

方法①:merge(できたものを詰め合わせる)

xcrun metal-pack present_vs.metallib present_fs.metallib \
                 sprite_instanced_vs.metallib sprite_instanced_fs.metallib \
                 -o combined.metallib

4本 → 46,536 B(単純合計の47,456 Bより少し小さい)。ところが中身を確認したら、こうなっていました。

./verify_metallib combined.metallib

  combined.metallib — 関数 4個: MainFS, MainVS, __MainFS_1, __MainVS_1
★名前が勝手に変わる
present.hlslsprite_instanced.hlslどちらも MainVS / MainFS というエントリポイント名を使っているため、後から入ったほうが __MainVS_1 にリネームされました。
名前で引く前提のコードは、まとめた瞬間に壊れます。まとめる前にエントリポイント名を揃えるか、変換時に --rename-entry-point で分けておく必要があります。

方法②:link(オブジェクトにしてから繋ぐ)

"$MSC" -c present_vs.dxil -o present_vs.o      # 11,456 B
"$MSC" -c present_fs.dxil -o present_fs.o      # 13,840 B
xcrun metal present_vs.o present_fs.o -o linked.metallib
linked.metallib — 関数 2個: MainFS, MainVS   (21,576 B・リネームなし)

こちらはリネームされていません。ただしこの組み合わせでは名前が衝突していないだけなので、link なら安全と言い切ることはできません。そこは確かめていません。

スキルによると、mergeは「単純だがシェーダをまたいだ最適化はされない」、linkは「Metalのリンカがシェーダをまたいで最適化できる」という違いがあるそうです。

GPTK 3と4の差は、シェーダ変換器にも出ているのか

前回は D3DMetal の3→4比較ができませんでした。シェーダ変換器のほうなら比べられるはず、と思って見てみました。

出所libmetalirconverter.dylib
GPTK 3.0-3 同梱29,513,088 B
GPTK 4.0 beta 2 同梱30,532,928 B
単体CLI(4.0 beta 2)metal-irconverter version: 4.0.1
⚠ ここは比較になりきっていません
3.0側のdylibからは版を示す文字列を取り出せませんでしたstrings で該当なし)。したがって「4.0.1 対 ?」であって、版の対比にはなっていません。
確実なのは約1MB増えたという事実だけです。同じDXILを3系の変換器に通して結果を比べる、という機能面のA/Bも、3系にはCLIが同梱されていないため実施できませんでした。

再現手順まとめ

ここまでを、上から順に実行すれば再現できる形にまとめます。

# 0) 前提
#    Apple silicon Mac / macOS 14 以降 / Xcode(swiftc と xcrun のため)
#    Game Porting Toolkit 4 の dmg(Apple Developer から。無料アカウントで可)

# 1) スキルを取ってくる
git clone --depth 1 https://github.com/apple/game-porting-toolkit.git
ls game-porting-toolkit/game-porting-skills/skills/     # 24本

# 2) dmgをマウントして、変換器をインストールせずに展開
hdiutil attach Game_Porting_Toolkit_4.0_beta_2.dmg -readonly -nobrowse -mountpoint /tmp/gptk4
pkgutil --expand-full "/tmp/gptk4/Metal Shader Converter 4.0 beta 2.pkg" msc_pkg
MSC="$PWD/msc_pkg/MetalShaderConverter.pkg/Payload/usr/local/bin/metal-shaderconverter"
chmod +x "$MSC" && "$MSC" --version

# 3) サンプル同梱のDXILを持ってくる(DXCは不要)
cp "/tmp/gptk4/gptk-sample/Cache/"*.dxil .

# 4) 変換(reflectionも出す)
for f in *.dxil; do b="${f%.dxil}"; "$MSC" "$f" -o "$b.metallib" --output-reflection-file "$b.json"; done

# 5) ★実機のGPUで読めるか検証
swiftc -O verify_metallib.swift -o verify_metallib
./verify_metallib *.metallib

# 6) まとめる(どちらか)
xcrun metal-pack *.metallib -o combined.metallib             # merge
"$MSC" -c a.dxil -o a.o; xcrun metal a.o b.o -o linked.metallib   # link

# 7) 後片付け
hdiutil detach /tmp/gptk4

検証用のSwiftは前述のものをそのまま verify_metallib.swift として保存すれば動きます。

限界:macOS 26では試せないもの

正直に書いておきます。今回できたのは24本のうち1本ぶんです。

対象手元でできたか
compiling-with-metal-shaderconverter◯ 実演できた(この記事の中身)
using-gpucapture / using-gpudebug macOS 27 のツールが前提
Metal 4 系(translating-to-metal4-api ほか5本) Metal 4 バックエンドは macOS 27 以降で既定オン。読むだけ
porting-* ワークフロー9本 移植する実プロジェクトが無いと回せない
プラグインとしての導入 開発環境の設定を変えるため見送り

それでも「今日この環境で、GPTK 4 の一部が確かに動いた」という事実は残りました。前回まったく動かせなかったことを思うと、これは前進です。

まとめ

  • AppleがAIコーディングエージェント向けのスキルを配り始めていました。Claude Code / Codex / Gemini 向けに、スキル24本+エージェント1本。Apache 2.0、初回コミットはWWDC当日
  • ワークフロー系9本は「セッションをまたいで状態を保存する」と明記されています。人間向けの資料ではなく、AIが何日もかけて移植を進める前提の設計でした
  • Metal Shader Converter 4.0.1 は、macOS 26 のままWine無しで動きます。しかも pkgutil --expand-full で展開すればインストールも管理者権限も不要
  • DXIL 4本すべてが metallib に変換でき、実機のM4が読み込みました。頂点/フラグメントの種別まで判別できています
  • まとめると名前が変わります。同じ MainVS を持つシェーダを metal-pack で詰めると __MainVS_1 にリネームされ、名前で引くコードは壊れます
  • GPTK 3と4の変換器の比較は、約1MB増えたという事実止まり。3系から版を取り出せず、機能面のA/Bも実施できませんでした
  • できたのは24本のうち1本ぶん。残りはmacOS 27待ちです

今回いちばん考えさせられたのは、スキルの内容そのものよりも「Appleが自社ツールの使い方をAIエージェント向けに書いて配り始めた」という事実のほうでした。移植という、これまで人が何ヶ月もかけていた作業を、そういう単位で渡そうとしている。

そして前回と合わせて見ると、面白い対比になっています。人が触る部分(ストアを開く、日本語を読む)はまだ動かないのに、AIに渡す部分の整備は先に進んでいるのです😅

それでは、今回はここまで。最後までありがとうございました😊

【実測環境】Apple M4 / macOS 26.5.2 (25F84) / RAM 32GB / Xcode 26.5 (17F42)。スキルは github.com/apple/game-porting-toolkit--depth 1 でクローン(コミット 4f42344 / 2026-06-07 / 22MB / Apache License 2.0)。変換器は Game Porting Toolkit 4.0 beta 2 同梱の Metal Shader Converter 4.0 beta 2.pkgpkgutil --expand-full で展開して使用(metal-irconverter version: 4.0.1 / default triple air64-apple-macosx15.0.0)。★pkgはシステムにインストールしていません。変換元は gptk-sample/Cache/ 同梱の既成DXIL 4本で、DXCによるHLSL→DXILのコンパイルは行っていません。metallibの検証は自作の Swift(MTLDevice.makeLibrary(data:)DispatchData を渡す形)で関数名と functionType を列挙。結合は xcrun metal-pack(merge)と metal-shaderconverter -cxcrun metal(link)の両方。★Claude Codeへのプラグイン導入は実行していません(開発環境の設定変更を避けたため)。★公式が前提とする macOS 27 / Xcode 27 を満たしていないため、gpucapture / gpudebug と Metal 4 系スキルは未検証です。HLSL・スキルからの引用は Apache License 2.0 に基づく最小限の抜粋です。数値は2026年7月時点の実測で、版により変わります。