2014年09月19日
Metalのコードを読む前に知っておくと楽なこと
iOSのDeveloperサイトでは基本的なものから応用的なものまでいくつかのMetalのサンプルがダウンロードできるようになっています。
早速Metalを学習しようと一番基本的なサンプルを紐解いてみるも、以下のように沢山のクラスが登場します。
・MTLDevice
・MTLBuffer
・MTLTexture
・MTLCommandQueue
・MTLCommandBuffer
・MTLRenderCommandEncoder
・MTLLibrary
・MTLFunction
・MTLRenderPipelineState
主なものを列挙してみましたが、数が多いだけに前提知識無しでいきなりサンプルを読み進めるのは困難です。
そこで今回はこれらのクラスがレンダリング全体の流れの中でどのような役割を担っているか図で整理しながら紹介したいと思います。
ここで紹介する流れは複雑なサンプルであっても同じであるし、コードを書く際にも役立つものと考えております。
まず、具体的にAPIの説明に入る前に、ハードウェアとレンダリングの流れを説明します。
モデルデータやテクスチャなどのオブジェクトは「shared CPU/GPU memory buffer」上に格納されます。
CPUはアプリケーションの実行において様々な仕事を担当しますが、GPUへの命令を作成して渡してあげるのも役割の1つです。
GPUがレンダリング処理をするために必要なデータやプログラムをコマンドと言う形にまとめて、コマンドキューにプッシュします。
コマンドキューからポップされたコマンドをGPUが受け取り、レンダリング処理を行って画面に出力します。
以上が簡単なレンダリング処理のイメージです。
それでは各APIの役割について説明していきます。
MTLDevice
ハードウェア全体を司る、言わばボス的な存在です。
モデルデータを保持するバッファや、テクスチャ領域をメモリ上に確保したいときはこのMTLDeviceに依頼する形になります。
また、コマンドキュー(後述のMTLCommandQueue)の管理も担当しています。
MTLBuffer
モデルデータ(頂点データ)やその他レンダリングに必要なパラメータを記憶しておく領域。
CPUからもGPUからもアクセス可能。
MTLTexture
レンダリングに必要なテクスチャを管理するためのクラスです。
MTLCommandQueue
レンダリング(またはコンピューティング)コマンドをGPUに流すためのキュー。
GPUのタスクが空き次第プッシュされた順にコマンドが実行されます。
MTLCommandBuffer
上記MTLCommandQueueにプッシュするコマンド本体。
コマンドは主にGPUで実行されるシェーダプログラムやテクスチャ・頂点データのポインタ、その他のパラメータのポインタなどの情報で構成されます。
レンダリング用のMTLCommandBufferのオブジェクトを作成するには次のMTLRenderCommandEncoderを使用します。
また、このコマンドはGPUで処理が完了した際に、CPU側にコールバックが返るようになっています。
コマンドをプッシュしてからコールバックが返ってくるまではMTLBufferの内容をCPU側で書き換えないようにするのが競合を防ぐポイントです。
MTLRenderCommandEncoder
レンダリングコマンドを作成するための役割を持つクラスです。
MTLBufferやMTLTextureのオブジェクトのポインタや、以下で紹介するMTLRenderPipelineStateのオブジェクトを元にコマンドを生成します。
MTLLibrary ・ MTLFunction ・ MTLRenderPipelineState
これら3つはシェーダやカーネル関数のようなGPUで実行されるプログラムに関するものです。
OpenGLでは実行時にシェーダをコンパイルしていましたが、Metalではアプリのビルド時に一緒にコンパイルされ、ライブラリというファイルにひとまとめでバンドルされます。
そのライブラリにアプリからアクセスするためのクラスがMTLLibraryです。
ライブラリからバーテックスシェーダ・フラグメントシェーダ・カーネル関数を一つ一つ取り出したものがMTLFunctionのオブジェクトです。
これらの関数をレンダリングコマンドとして使うためにMTLRenderPipelineStateに持たせてMTLRenderCommandEncoderに渡します。
以上、主なクラスについて整理してみました。
Metalのサンプルを読み解く際やプログラムを書くときに、紹介した図を思い浮かべて各クラスの役割を思い出してみるとスムーズに進むかと思います。
早速Metalを学習しようと一番基本的なサンプルを紐解いてみるも、以下のように沢山のクラスが登場します。
・MTLDevice
・MTLBuffer
・MTLTexture
・MTLCommandQueue
・MTLCommandBuffer
・MTLRenderCommandEncoder
・MTLLibrary
・MTLFunction
・MTLRenderPipelineState
主なものを列挙してみましたが、数が多いだけに前提知識無しでいきなりサンプルを読み進めるのは困難です。
そこで今回はこれらのクラスがレンダリング全体の流れの中でどのような役割を担っているか図で整理しながら紹介したいと思います。
ここで紹介する流れは複雑なサンプルであっても同じであるし、コードを書く際にも役立つものと考えております。
まず、具体的にAPIの説明に入る前に、ハードウェアとレンダリングの流れを説明します。
モデルデータやテクスチャなどのオブジェクトは「shared CPU/GPU memory buffer」上に格納されます。
CPUはアプリケーションの実行において様々な仕事を担当しますが、GPUへの命令を作成して渡してあげるのも役割の1つです。
GPUがレンダリング処理をするために必要なデータやプログラムをコマンドと言う形にまとめて、コマンドキューにプッシュします。
コマンドキューからポップされたコマンドをGPUが受け取り、レンダリング処理を行って画面に出力します。
以上が簡単なレンダリング処理のイメージです。
それでは各APIの役割について説明していきます。
MTLDevice
ハードウェア全体を司る、言わばボス的な存在です。
モデルデータを保持するバッファや、テクスチャ領域をメモリ上に確保したいときはこのMTLDeviceに依頼する形になります。
また、コマンドキュー(後述のMTLCommandQueue)の管理も担当しています。
MTLBuffer
モデルデータ(頂点データ)やその他レンダリングに必要なパラメータを記憶しておく領域。
CPUからもGPUからもアクセス可能。
MTLTexture
レンダリングに必要なテクスチャを管理するためのクラスです。
MTLCommandQueue
レンダリング(またはコンピューティング)コマンドをGPUに流すためのキュー。
GPUのタスクが空き次第プッシュされた順にコマンドが実行されます。
MTLCommandBuffer
上記MTLCommandQueueにプッシュするコマンド本体。
コマンドは主にGPUで実行されるシェーダプログラムやテクスチャ・頂点データのポインタ、その他のパラメータのポインタなどの情報で構成されます。
レンダリング用のMTLCommandBufferのオブジェクトを作成するには次のMTLRenderCommandEncoderを使用します。
また、このコマンドはGPUで処理が完了した際に、CPU側にコールバックが返るようになっています。
コマンドをプッシュしてからコールバックが返ってくるまではMTLBufferの内容をCPU側で書き換えないようにするのが競合を防ぐポイントです。
MTLRenderCommandEncoder
レンダリングコマンドを作成するための役割を持つクラスです。
MTLBufferやMTLTextureのオブジェクトのポインタや、以下で紹介するMTLRenderPipelineStateのオブジェクトを元にコマンドを生成します。
MTLLibrary ・ MTLFunction ・ MTLRenderPipelineState
これら3つはシェーダやカーネル関数のようなGPUで実行されるプログラムに関するものです。
OpenGLでは実行時にシェーダをコンパイルしていましたが、Metalではアプリのビルド時に一緒にコンパイルされ、ライブラリというファイルにひとまとめでバンドルされます。
そのライブラリにアプリからアクセスするためのクラスがMTLLibraryです。
ライブラリからバーテックスシェーダ・フラグメントシェーダ・カーネル関数を一つ一つ取り出したものがMTLFunctionのオブジェクトです。
これらの関数をレンダリングコマンドとして使うためにMTLRenderPipelineStateに持たせてMTLRenderCommandEncoderに渡します。
以上、主なクラスについて整理してみました。
Metalのサンプルを読み解く際やプログラムを書くときに、紹介した図を思い浮かべて各クラスの役割を思い出してみるとスムーズに進むかと思います。