読者です 読者をやめる 読者になる 読者になる

n-yoda's blog

主にUnity3Dに関するあんまり技術的じゃないメモ的な何かを書いています。

Metal Shading Language コンパイラの使い方

Metal

OS X El CapitanからいよいよMacでもMetalが使えるようになりました。 良い機会なので、次にグラフィックスやGPGPU関連の実装が必要になったときはMetalを使ってみようと思い、 とりあえずHello World的なものを書いて入門してみました。 https://github.com/n-yoda/metal-without-xcode

ちょっとしたプログラムのためにIDEでプロジェクトを作ることに何故か抵抗を覚えるので、 コマンドラインで全てを済ませようとした結果、 シェーダーのコンパイルに関してあまり良いドキュメントが無かったので覚書きを以下にまとめておきます。

(追記 15/11/10)普通にドキュメントがありました↓ https://developer.apple.com/library/ios/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Dev-Technique/Dev-Technique.html

ちなみに、以下はシェーダーを事前にコンパイルしておく場合の話です。 実行時にコンパイルする場合はnewLibraryWithSource:options:error:を参照。

XCodeを使う場合

公式のサンプルコード をダウンロードしてビルドすればわかりますが、プロジェクト内に.metalファイルを置いておけば、勝手にコンパイルしてくれます。 シェーダーを使う際はnewDefaultLibrary: で読み込めます。

id <MTLDevice> device = ...;
id <MTLLibrary> = [device newDefaultLibrary]; 

コマンドラインコンパイルしたい場合

公式のサンプルをxcodebuildコマンドでビルドして出力を見て調べたので、あまり意味は理解していませんが、以下で動きました。

1. PATHを通す

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/usr/bin

以下にコンパイラが入っているので、PATHを通しておくと良いでしょう。 Metal and C++11 に書いてあるように、Metalのシェーディング言語はほぼC++11なので実態はLLVM/Clangです

2. コンパイル

ソース名をshaders.metalとして、それをコンパイルしてshaders.airを出力します。

metal -std=osx-metal1.1 -o shaders.air shaders.metal

ソースに.metal以外の拡張子を付けたい場合*1 は「-x metal」を追加して、

metal -std=osx-metal1.1 -o shaders.air -x metal shaders.cpp

のようにします。 ソース中でC++とMetalを判別して処理を分けたい場合は、

#ifdef __METAL_VERSION__

が使えるみたいですが、公式のドキュメントは見つけていません*2

その他オプションは Compiler Options を参照。また、Clangで使えるオプションはそのまま使えるみたいですが良くわかりません。

3. アーカイブ

複数の.air(今回は1つ)をアーカイブして.metal-arを作ります。

metal-ar r shaders.metal-ar shaders.air 

4. ライブラリの生成

.metal-arから.metallibを生成します。

metallib -o shaders.metallib shaders.metal-ar

5. ライブラリの読み込み

シェーダーを使う際は newLibraryWithFile:error: で読み込みます。

id <MTLDevice> device = ...;
NSError *error = nil;
id <MTLLibrary> lib = [device newLibraryWithFile: @"shaders.metallib" error:&error];
if (!lib) {
    NSLog(@"Failed to load library. error %@", error);
}

*1:出力結果の拡張子を変えたい場合は「-arch air64 -emit-llvm -c」を付けると良いかも?

*2:simd/simd.h辺りを読むとそう見えます