実用化可能かはおいておいて、Stage3DでGPGPUを使うことを考えてみた。
そもそもFlashでGPUが利用可能に、という話を知った時からやってみたいと思っていたもの。
今回は考え方のお話。
まずGPGPUとはなにか、という話から。
ご存じのとおりGPUは画像処理を専門に行うハードウェアで、ディスプレイのドット1つ1つの色を計算する、といった大量の要素に対して同じ計算をすることにハードウェア的に特化している。
すなわち多くの演算装置(コア)を持たせて同時に計算実行させようというわけだ。
昔はこのディスプレイ出力もある程度計算式が決まっていたので、ハードウェア自体に組み込まれた固定機能シェーダであったが、10年ほど前から表現の幅を広めて自由に出力処理できるようにプログラマブルシェーダへ移行した。
これは画像出力の方法をソフトウェア的にプログラミングできる方式だ。
また、近年に入り、クロック周波数の向上が打ち止め傾向にあるCPUと比べて、3Dゲーム等への需要からGPUの性能は飛躍的に向上し、単純にクロック周波数*コア数で考えるとCPUを大きくしのぐ計算能力(TFLOPSのオーダー。数年内にPFLOPSに達する見込みだとか)をもつようになった。
もちろんこれは画像処理に特化した話であり、CPUに搭載されている分岐予測だとかアウトオブオーダー機構といったものがGPUの各コアにはなく、普通のプログラムには向いていない。
だが多数のデータに対して同じような計算を行うことに関してはCPUよりめちゃくちゃ速いので、これを画像処理ではなく、汎用計算に使おうというのがGPGPU (General Purpose computing on Graphics Processing Units)だ。
ではFlashのStage3Dで使える機能からどのようにすればGPGPUが可能か考えてみよう。
レンダリングパイプラインは
頂点を渡す→各頂点に対してvertexシェーダで頂点を計算→ラスタライズ→各ピクセルに対してfragmentシェーダで色を計算(テクスチャ貼り付け)→ディスプレイ、Texture、BitmapDataのどれかに出力
となっている。
まず出力だが、このパイプラインでCPU側で取得可能なのは、出力された画面の色情報のみなのである。
また、ディスプレイ出力から色の取得はできず、GPUのテクスチャをCPUで読むこともできないため、BitmapDataに出力してそこから色をとる以外方法がないのが現状だ。
次に入力は、Vertexシェーダがプログラマブルなので頂点に対して自由に計算できるが、計算結果はラスタライズされてFragmentシェーダに渡されてしまう。 これではBitmapDataのどこにほしい情報があるのかわからなくなってしまう。
そこでテクスチャを入力に使うのが一般的なようだ。
頂点を画面の4隅にぴったりと設定して三角形2つで矩形を作り、そこにテクスチャをはりつければ、各ピクセルはテクスチャの各ピクセルカラーを入力として参照することができるのでそれに対して自由に計算を行うことができ、出力した画像からもピクセルによって位置が特定できる。
つまり、
テクスチャの各ピクセルにデータを与え、GPUに送る→fragmentシェーダでテクスチャを読み込み、計算する→BitmapDataに出力する
という流れでピクセル数ぶんの計算をGPUで行うことができる。
ところが具体的に実装することを考えると、いくつかの難点もある。
出力されたBitmapDataから色を得ることができるが、 BitmapDataのgetPixcelに類するメソッドはピクセルのアルファ値が0xFF以外の時には正しいRGBを取ることができない。
ActionScriptのバグとしか思えないこの仕様のせいで、各ピクセルのアルファは0xFFに固定せざるをえない。
ということは1ピクセルに持たせ、1ピクセルから得ることができる情報は24ビットに減ってしまう。
使うときは覚悟しとけよ、とリファレンスにかいてあるくらいで実際に1024*1024ピクセルのdrawToBitmapDataをしてみるとなかなかに重い。
配列に格納する方法としてBitmapDataにgetVectorというメソッドがあるが、これも大きなデータに対しては重くなってしまう。
精度の問題は範囲や用途を限定することで吸収することができる。
速度の問題は主に転送処理の部分であり、テクスチャサイズ(データ数)にのみ依存する。よって転送がネックにならないほど演算処理の方に時間がかかる計算ならば充分にGPGPUの効果を発揮できると思う。
次回は実際に実装した簡単なデモをつくってみる。
Author:9ballsyn
ActionScriptについて
最近はMolehill