HSPの3Dプラグイン、EASY3Dを使って、HLSLも使ってGPGPUができることは前の記事で確認したとおりである。
おさらいとして、GPGPUとはグラフィックボードのビデオメモリを変数に見立てGPUで計算をすることであり、CPUをはるかに凌ぐ計算速度が得られる技術である。


が、EASY3Dでやるには、そこには幾つかの欠点があった。

まず一番の問題点は、E3DCreateRenderTargetTexture で作成したレンダリング用バッファのデータをメインメモリへ転送できなかったことだ。
これではHSP標準命令などで初期値を作っても、それをVRAMに転送し、計算結果をまたHSPで使える形(ddimで初期化した変数など)に戻してくることができない。

流体力学やレイトレーシングのように、数値を色として画面に表示するのが目的なものは、意外と少ない。

そもそもEASY3Dは数値計算の用途で使うものではない・・


そこで今回、数値計算に特化した、それもGPGPUで処理高速化が簡単にできるようなプラグインを作ってみようと思い立った。


HSPSDKのサンプルとにらめっこしながらとりあえず即席で作ったプラグインが下の「エイチエスピーシェーダ HSPSHAD(仮)」だ。

http://sourceforge.jp/users/toropippi/pf/tyoukihokanko/files/?id=1570


実行すると
3つの倍精度浮動小数点の配列変数が作られる。
「cpua」
「cpub」
「gpua」
要素数は1024*1024*4。

まずHSP標準命令にてcpuaの各々の配列に適当な初期値が入る。
その初期値を元に
cpubとgpuaには、それぞれCPU、GPUで同じ処理をさせた結果が入る。

処理内容は
上下左右の配列から引っ張ってきた値の平均に1234.5678をかけて40で割るというもの。

1つの要素を計算して求めるのに参照箇所が4つもあるため、これはかなりメモリアクセスの速さが要求される処理だ。


ではGPUで何が起きているかみていこう。
GPUで計算するには、まずVRAMにcpuaのデータを転送する必要がある。
その命令が「SHADCPUtoGPU」である。

E3DCreateRenderTargetTexture で変数が作られ、そこにcpuaが代入されたような状態だ。

つぎに、GPU内で演算が始まる。ここでHLSLが読み出される。
HSPからはSHADCallUserShaderで命令をしているのみ。具体的な処理は全てHLSLのエフェクトファイルに記述する必要があるということだ。
こうして、上下左右の配列・・・1234.5678をかけて40で割る工程がここで行なわれた。


最後に演算結果の格納されているVRAMから、ddim で初期化されたメインメモリ上にある変数へと数値を転送する必要がある(ここが一番重要!!!)
その命令が「SHADGPUtoCPU」
こうして、CPUでは全然頭を使わないうちに、計算結果がメインメモリに格納できたわけだ。

このようにしてCPUとGPUそれぞれ処理した結果が2つともメモリに入ったわけだから、数値エラーがないか色分けして表示してみよう。
まぁ当然結果は同じ値!
ではなく、CPU→GPUにデータを渡す際に倍精度が単精度に直されてしまったので、よく見るとほんの僅かな誤差がある。
gpgpu02

でもどうでだろう!?GPGPUがお手軽になってきた気はしないか!


そして、いつもの癖で速度比較をしてみた。
倍精度と単精度ではまず4倍近く時間が変わってくるのでCPUの時間を4分の1にして見て欲しいが、やはりGPU処理が高速。
というかHSP標準命令が遅すぎるだけ・・
HSPの処理の部分をc++で処理させたら10倍以上早かった・・

そう考えると同じくらいの速度かと思うかもしれない、がGPGPUの本領発揮となるは、たくさんの変数、算術命令があり、そして膨大な量のメモリアクセスが発生する状況下である。


2012/11/26日現在、サンプルで公開しているのは、処理が1回しか行えないひどい有様であるが、これから様々な機能を付け加えていこうと思う。

誰でも、HSPでお手軽にGPGPUプログラミングのできる時代が来ると思うと、なんだかワクワクするね!



追記:
XP以前では、サンプル が動かない可能性があります。