ZSortDisableテスト実装

Zソートをしないで、Window.draw系メソッドの中でDrawPrimitiveUPを直接実行する機能を追加してみた。
その状態でZソートをするようにしたらオブジェクト数は9500、しないようにしたら9700だった。
スクリプトは昨日の記録の記事と同じものだ。


スプライト構造体の書き込み・読み出しの省略及び、通常描画専用ロジックになるから計算量が激減するはずなのだが、ほとんど変わらないという結果だった。
計算量の減り方からすればもっと性能向上してもおかしくないのだが、それがほぼ同じというのは、別のところに原因があるからだ。
例えばGPUの描画速度の限界。
32*32pixelのデータを9000個も描けば、画面を640*480の画面を30回書き換えるほどの量になる。
ためしに16*16pixelの絵で実行してみたが、結果は変わらず。
うーむ・・・


そうなると考えられる可能性は、DrawPrimitiveUP時にハードウェアを駆動するのではなく溜め込むだけで、EndScene時に描画開始している、という感じか。
んで、ハードウェアの駆動完了待ちをしているのかもしれない。
なんとなく納得いかないけど。
とりあえず、描画ごとにBeginScene/EndSceneを実行してみたら死ぬほど遅くなった。
フォント描画のこともあってレンダーステートの設定にD3DXSpriteのBeginを使っているから、それのせいもあるのだろう。
なんしか、Rubyやライブラリのほうに時間がかかっているわけではないのなら、ハードウェアかDirectXボトルネックになっていると言うしかない。
しかしこれはよく考えてみると恐ろしい話だ。
なぜならRubyのプログラムが、ハードウェアがボトルネックになるほどの速度で動いているということだからだ。


実際、どんな感じで時間を食われているのか、システムタイマのカウントを表示しながら確認してみた。
約60000で60fpsの1フレーム分になる値だ。
オブジェクト数は8000。
通常のWindow.drawは1回で8前後。これはタイマ値取得にかかる時間も含まれるから、ほんとはもっと少ない。
Ruby処理全体は100000ちょい。
Window.loop内のdraw処理は2000〜4000。
Window.drawの実行時間と全体の時間で計算が合わない。
Window.drawの時間を全部見てみると、ところどころに2500前後の数字が出てくる。
Cの処理だから、RubyGCというわけではない。
そーするとこの妙な時間は、DirectXの関数呼び出しに時間がかかる場合がある、ということになる。
関数呼び出しごとにカウントを測って、やたら遅いタイミングのみ表示するようにしてみると、どうやらDrawPrimitiveUPの呼び出しのうち1/1000ぐらいが、異様に遅いことがわかった。
描画命令がある程度たまるとハードウェアに転送でもするようになっているのだろうか。
それにしても2500カウントってことは0.6msぐらい?なわけで、これは遅いにもほどがある。


まあ、Rubyで作る2Dゲームでスプライト1000とかも普通あり得ないわけで、1/1000の割合で遅くなったとしてもほとんど影響は無いはずだ。
例えばテクスチャをまとめる機能を作って、同じテクスチャからの描画が続く限りは1つの頂点バッファを使う、などにすれば速度は大幅に上がるかもしれない。
今回作ってみたやつもテスト実装だし、またそんなテスト実装を作って実験するのも面白い。
近いうちにネタとしてやってみよう。