Help us understand the problem. What is going on with this article?

[iOS]MetalでGPUコンピューティング(8) MTLComputeCommandEncoder

More than 3 years have passed since last update.

この記事は、Metal Advent Calendar2016の12日目です。

これまで、MetalのGPUコンピューティングについて解説記事を書いてきました。
[iOS] MetalでGPUコンピューティング (1) 最小限のコードの記述と特性の把握
[iOS] MetalでGPUコンピューティング (2) 群知能
[iOS] MetalでGPUコンピューティング (3) MTLDevice
[iOS] MetalでGPUコンピューティング (4) MTKView
[iOS] MetalでGPUコンピューティング (5) MTLLibrary
[iOS] MetalでGPUコンピューティング (6) MTLCommandQueue
[iOS] MetalでGPUコンピューティング (7) MTLCommandBuffer

本記事では、前回に引き続きAppleが提供するサンプルコードの解説を行います。

扱うサンプルコードは、前回と同じライフゲームのアプリ、MetalGameOfLifeです。
MetalGameOfLife

IMG_5933.PNG
(実行画面)

今回は、サンプルコード内のMTLComputeCommandEncoderについて解説を行います。
MTLComputeCommandEncoderはGPUによる並列コンピューティング用の設定や関数をエンコーディングするためのメソッドの集合体です。

MTLComputeCommandEncoderはクラスではなくプロトコルです。
MTLComputeCommandEncoderのオブジェクト(エンコーダー)は、MTLCommandBufferのオブジェクト(コマンドバッファ)により生成されます。そして、エンコーダーによってエンコードされたコンピューティング用のコマンドはコマンドバッファに格納されます。

エンコーディングは、MTLCommandBufferオブジェクトの生成の都度行われます。

繰り返しになるのですが、このサンプルコードは、主に以下のファイルで構成されています。

AAPLRender.h
AAPLRender.m
AAPLViewController.h
AAPLViewController.m
Sharder.metal

このうち、AAPLRender.mには並列コンピューティング及び描画のCPU側のロジックが、Shader.metalには頂点シェーダー、フラグメントシェーダー、GPUコンピューティング用のシェーダーが書かれています。

ここからは、サンプルコード内におけるMTLComputeCommandEncoderの使用箇所を解説していきます。
AAPLRender.mに以下の記述があります。MTLCommandBufferのcomputeCommandEncoderメソッドによりエンコーダーが生成されています。この記述は毎フレームごとに呼ばれる箇所にあります。

AAPLRender.m
id<MTLComputeCommandEncoder> commandEncoder = [commandBuffer computeCommandEncoder];

また、以下のコードでは、MTLComputePipelineStateのオブクジェクトをエンコーダーに設定しています。MTLComputePipelineStateのオブジェクトは、シェーダー内に記述されたこれから実行されるコンピューティング用の関数を含んでいます。

AAPLRender.m
[commandEncoder setComputePipelineState:self.simulationPipelineState];

以下のコードでは、エンコーダーに使用するリソースの指定を行なっています。リソースはシェーダー内の関数の引数として渡されます。

AAPLRender.m
[commandEncoder setTexture:readTexture atIndex:0];
[commandEncoder setTexture:writeTexture atIndex:1];
[commandEncoder setSamplerState:self.samplerState atIndex:0];

上記では、関数へのインプット用のテクスチャ、アウトプット用のテクスチャ、サンプラーが渡されています。テクスチャ、サンプラーにはそれぞれ識別用にインデックスを振ります。バッファを用いて数値データを渡したい場合も、同様にインデックスを振ります。
この辺り、詳細は後の記事で紹介したいと思います。

以下のコードでは、GPUのスレッド及びスレッドグループ数の指定を行い、並列コンピューティング用の関数を、スレッドグループ及びスレッドグループ内のスレッド用にエンコードします。

AAPLRender.m
MTLSize threadsPerThreadgroup = MTLSizeMake(16, 16, 1);
MTLSize threadgroupCount = MTLSizeMake(ceil((float)self.gridSize.width / threadsPerThreadgroup.width), ceil((float)self.gridSize.height / threadsPerThreadgroup.height), 1);
...
[commandEncoder dispatchThreadgroups:threadgroupCount threadsPerThreadgroup:threadsPerThreadgroup];                                    

スレッド及びスレッドグループに関しては後の記事で詳細を解説したいと思います。

以下では、endEncodingメソッドによりエンコーダーからのコマンドが完了したことを宣言しています。この宣言があると、これ以上エンコーダーを使用することはできなくなります。

AAPLRender.m
[commandEncoder endEncoding];

サンプルコード内には毎フレーム必ず呼ばれる箇所の記述もありますが、画面をタップした際に実行される箇所もあります。そこでは異なるMTLComputePipelineStateオブジェクトを指定し、異なるコンピューティング用の関数を指定しています。

AAPLRender.m
[commandEncoder setComputePipelineState:self.activationPipelineState];
[commandEncoder setTexture:writeTexture atIndex:0];
[commandEncoder setBytes:cellPositions length:byteCount atIndex:0];
[commandEncoder dispatchThreadgroups:threadgroupCount threadsPerThreadgroup:threadsPerThreadgroup];

このように、MTLComputeCommandEncoderはコマンドバッファに対して各種のコマンドをエンコードする役割を担っています。

今回はライフゲームのサンプルコード内におけるMTLCommandQueueの解説を行いました。
次回以降、さらに他の箇所についての解説を行なっていきます。

yuky_az
「ヒトとAIの共生」がミッションの会社、SAI-Lab株式会社の代表取締役。 東北大学大学院理学研究科修了。理学博士(物理学)。 著書に「はじめてのディープラーニング」、「No.1スクール講師陣による 世界一受けたいiPhoneアプリ開発の授業」。オンライン教育プラットフォームUdemyで、2万人近くを指導する人気講師。
https://sai-lab.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away