スレッド

DXRubyの描画部分だけ別スレッドにしてみた。
実際には、スプライト構造体の編集→描画処理という感じだから、描画処理中に構造体が編集されてしまってはまずい。
スクリプトのメソッドを座標更新と描画に分けて、描画処理をしている間に座標更新ができるようにした。
DrawPrimitiveUPを使うと描画中に時間が食われてしまって、構造体が使える時間が減ってしまうから、とりあえずテクスチャ決め撃ち版でDrawPrimitiveを使ってまとめて転送するようにした。
これなら、一通りの処理が終わって時間のかかるPresent時にはスプライト構造体は変更できるようになっているはずだ。
ちなみにRuby1.9.1ではネイティブスレッドがどーこーでよくわからないので、スレッド関連は1.8.7で実験している。


結果としては、1コアのデスクトップでは性能が下がり、2コアのノートでは若干速くなった。
これが意味するところは、DirectXAPIで時間を食われている部分は、CPUがフル稼働しているということだ。
ハードウェア待ちをしているなら1コアでも速くなる。
しかしCPUがフル稼働する状態というのは、何をしているのか。
ビデオメモリに対しての書き込みならメモリのウェイトがかなり入るはずだし、GPUとのやりとりでも同じだ。
DirectX側でなんらかのソフト処理をしている、ということか。
データ量に比例して遅くなっているみたいだから、頂点関連の処理をソフトでやっているのだろう。
考えられる可能性としては、頂点データの変換みたいな感じだ。
たとえばDirectX的にはTRIANGLEFANで作ったデータだが、GPUに渡すときにはTRIANGLELISTに変換しないといけない、とか。
ためしてみよう。


DXRuby1.0.3のソースの、4頂点TRIANGLEFANだったのを、6頂点TRIANGLELISTに変更してみた。
そしたらなんと、Ruby1.9.1/30fpsで動かしてDXRuby1.0.3では9600個だったのが、11500個動くようになったではないか。
これは・・・w
どうやらボトルネックはメモリ帯域ではなく、DirectXのソフト処理だったのだ。
AGPx8だと理論上2.1GB/secの帯域があるはずだから、おかしいなーとは思っていた。
頂点が多い分だけ1ポリゴンスプライトには負けるが、テクスチャ周りで妥協しなくてよくなるからこっちのほうがよい。


話が逸れてしまったが結局のところ、I/O絡みではなく純粋にCPUの処理が追いつかない場合はスレッドを作っても1コアでは意味が無い。
DXRubyのターゲットはもちろん1コアだから、1コアで遅くなるような修正はしない。
っていうかTRIANGLELIST・・・盲点だった。
そうなると逆にTRIANGLEFANとかの存在意義がよくわからなく。