Metal はApple A7以降を搭載したiOS機器、およびOS X El Capitan以降が動作する一部のMacコンピュータで利用可能な、GPU を利用可能にする機能。
以下、wikiより。
2017年10月時点でのMetal及びMetal2対応Macコンピュータは以下の通り[2]。
- iMac(Late 2012 以降)
- MacBook(Early 2015 以降)
- MacBook Pro(Mid 2012 以降)
- MacBook Air(Mid 2012 以降)
- Mac mini(Late 2012 以降)
- Mac Pro(Late 2013 以降)
- Mac Pro(Mid 2010 以降)でMetalをサポートするGPU(Nvidia Kepler以降、ATI Graphics Core Next以降)を搭載したもの
MetalはWWDC 2014にて発表され、iOS 8で初めて導入された[3]。
MetalはC++11をベースとした新しいシェーディング言語、Metal Shading Language(MSL)を利用する。
Metal Shading Language での実装例
#include <CoreImage/CoreImage.h> extern "C" { namespace coreimage { float4 do_nothing(sample_t s) { return s; } } }
Core Image Kernel Language での実装例
kernel vec4 do_nothing(__sample s) { return s.rgba; }
Color Kernel の特性
- 戻り値の型は
vec4
(Core Image Kernel Language)またはfloat4
(Metal Shading Language)で、出力画像のピクセルカラーを返します。 - 0個以上の入力画像を使用する場合があります。各入力画像は次のパラメータで表される。__sample(Core Image Kernel Language)または sample_t(Metal Shading Language)。これらは、vec4型の画素(Core Image Kernel Language)または float(Metal Shading Language)で扱うことができる。
Creating a General Kernel in Swift
guard let url = Bundle.main.url(forResource: "default", withExtension: "metallib"), let data = try? Data(contentsOf: url) else { fatalError("Unable to get metallib") } guard let generalKernel = try? CIKernel(functionName: "myKernel", fromMetalLibraryData: data) else { fatalError("Unable to create CIKernel from myKernel") }
詳細は、init(functionName:fromMetalLibraryData:) を参照。
カーネルの作成
最初のステップは、デフォルトのMetalライブラリーを表す Data オブジェクトを作成する。これをXcodeでビルドし、default.metallib として、url.Bundle メソッドでロードする。
コンパイラとリンカーのオプションの指定
MSLをのシェーダー言語として使用するには、Xcodeでプロジェクトのターゲットの[Build Settings ]タブにあるいくつかのオプションを指定する必要があります。指定する必要がある最初のオプションは、Other Metal Compiler Flags オプションの ”-fcikernel” フラグです。2つ目は、user-defined に、MTLLINKER_FLAGS キーで “-cikernel” を追加する。
CIKernel の呼び出し方
import UIKit class MyFilter: CIFilter { private let kernel: CIColorKernel @objc dynamic var inputImage : CIImage? override init() { let url = Bundle.main.url(forResource: "default", withExtension: "metallib")! let data = try! Data(contentsOf: url) kernel = try! CIColorKernel(functionName: "myColor", fromMetalLibraryData: data) super.init() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override var outputImage: CIImage? { guard let inputImage = inputImage else {return nil} return kernel.apply(extent: inputImage.extent, arguments: [inputImage]) } }
Metal Shading Language Specification
Metal Shading Language Specification – Apple Developer
MSL Vector 型
// .xyzw または .rgba で各要素にアクセスできる。 int4 test = int4(0, 1, 2, 3); int a = test.x; // a = 0 int b = test.y; // b = 1 int c = test.z; // c = 2 int d = test.w; // d = 3 int e = test.r; // e = 0 int f = test.g; // f = 1 int g = test.b; // g = 2 int h = test.a; // h = 3 //xyzw の並びで 複数の要素にアクセスできる float4 c; c.xyzw = float4(1.0f, 2.0f, 3.0f, 4.0f); c.z = 1.0f; c.xy = float2(3.0f, 4.0f); c.xyz = float3(3.0f, 4.0f, 5.0f); // 順列 float4 pos = float4(1.0f, 2.0f, 3.0f, 4.0f); float4 swiz = pos.wzyx; // swiz = (4.0f, 3.0f, 2.0f, 1.0f) float4 dup = pos.xxyy; // dup = (1.0f, 1.0f, 2.0f, 2.0f) // 代入 float4 pos = float4(1.0f, 2.0f, 3.0f, 4.0f); // pos = (5.0, 2.0, 3.0, 6.0) pos.xw = float2(5.0f, 6.0f); // pos = (8.0, 2.0, 3.0, 7.0) pos.wx = float2(7.0f, 8.0f); // pos = (3.0, 5.0, 9.0, 7.0) pos.xyz = float3(3.0f, 5.0f, 9.0f);
MSL Matrix 型
halfnxm // n x m 16bit floating point
floatnxm // n x m 32bit floating point
float4x4 m; // This sets the 2nd column to all 2.0. m[1] = float4(2.0f); // This sets the 1st element of the 1st column to 1.0. m[0][0] = 1.0f; // This sets the 4th element of the 3rd column to 3.0. m[2][3] = 3.0f;
カスタムフィルターの作成
カスタムフィルター
class CIKernel
カスタムCore Imageフィルターの作成に使用されるGPUベースの画像処理ルーチン。
class CIColorKernel
カスタムCore Imageフィルターの作成に使用される、画像の色情報のみを処理するGPUベースの画像処理ルーチン。
class CIWarpKernel
カスタムCore Imageフィルターの作成に使用される、画像内のジオメトリ情報のみを処理するGPUベースの画像処理ルーチン。
class CIBlendKernel
2つの画像をブレンドするために最適化されたGPUベースの画像処理ルーチン。
class CISampler
フィルターカーネルによる処理のためにピクセルサンプルを取得するオブジェクト。