前回の続き、ただし今回はWineを使わない
前回は、Apple純正の Game Porting Toolkit(GPTK)を使い倒しました。結論は「D3DMetalは速さを、Wineは遊べるかを決めている」で、公式の GPTK 4 は載せ替えでは動かせずに終わりました。
ただ、あのとき調べていて気づいたことがあります。GPTK 4 のうち、Wineが必要なのは「評価環境」だけなのです。dmgの中には、Wineをまったく使わない部分がありました。
そして公式リポジトリを覗いたら、予想外のものが入っていました。
apple/game-porting-toolkit に Claude Code / Codex / Gemini 向けのプラグインが入っていました。スキル24本とエージェント1本。ライセンスは Apache 2.0。このブログはClaude Codeで開発しているので、他人事ではありません😳
今回は、そのスキルの中身を読み、書かれている手順どおりにシェーダの変換を実際にやってみます。前回動かせなかったGPTK 4が、ここでは素直に動きます。
なお再現できることを重視して、コマンドと版とパスを全部載せています。長くなりますが、そのぶん手元で追えるはずです。
用語集
| 用語 | 平たく言うと |
|---|---|
| シェーダ | GPUの上で動く小さなプログラム。物の色や形をどう描くかを決めます。ゲームには何百本と入っています |
| HLSL | DirectX向けにシェーダを書く言語。人間が書くのはここ |
| DXIL | HLSLをコンパイルした中間表現。ゲームが配布時に持っているのは大抵この形です |
| Metal IR / AIR | Apple側の中間表現。DXILに対応するもの |
| metallib | Metalが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 の Mac | M4 ✓ |
| Game Porting Toolkit 4 | 4.0 beta 2 ✓ |
| macOS 27(新しいデバッグツールのため) | 26.5.2 ✗ |
| Xcode 27(エージェント向けMCPのため) | 26.5 ✗ |
つまりワークフロー全体はmacOS 27前提です。ただ、これから実演するシェーダ変換の部分は26のままで完結します。
24本のスキルには何が書いてあるのか
スキルは大きく2種類に分かれていました。
面白かったのは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 | → metallib | reflection |
|---|---|---|---|
| present_vs | 12,548 B | 12,168 B | 1,167 B |
| present_fs | 16,008 B | 13,272 B | 910 B |
| sprite_instanced_vs | 12,836 B | 11,864 B | 1,445 B |
| sprite_instanced_fs | 10,672 B | 10,152 B | 899 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)」「テーブル」という概念が、そのまま名前として残っています。4294967295 は 0xFFFFFFFF、つまり「未使用」の意味です。
★本当に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.hlsl と sprite_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.pkg を pkgutil --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 -c + xcrun metal(link)の両方。★Claude Codeへのプラグイン導入は実行していません(開発環境の設定変更を避けたため)。★公式が前提とする macOS 27 / Xcode 27 を満たしていないため、gpucapture / gpudebug と Metal 4 系スキルは未検証です。HLSL・スキルからの引用は Apache License 2.0 に基づく最小限の抜粋です。数値は2026年7月時点の実測で、版により変わります。