2008/09/11(木)にゅーふれーむわーくの悩み
もし音ゲを作ったら、内部処理60fpsはやっぱ足りない気がする。判定はともかく、音出しは音が最悪16ms遅れるわけで、少し音ゲ遊んでる人には「なんかズレてる?」ってのはまぁバレる。というか、俺だったらバレる。気持ちよくなくなるし。内部処理を増やそうとすると、描画を実行するタイミングとか測るのが難しい。やっぱりスレッド2本立てでやるべきなのかなぁ、とかいろいろ考えちゃう。しかしてマルチスレッドプログラミングは大変だ。
そんなこんなで、新SDK作りが全然進まない。DirectXってスレッドセーフなのかな。てか、.NETのスレッドはソフトウェアスレッドらしい、Win32ネイティブなスレッドとの関係もいまいちよくわかんない。こういうことってサークルにも相談できる相手はいなくて、これからどうしたらいいのかなぁ。
最近ようやく、Direct3Dのプロジェクション行列とかビュー行列の役割とちょっとおかしい使い方がわかった。
先輩曰く「スプライトを使うより自前でポリゴン作って描画した方が速い」らしい。新SDKの設計を考え直すべく、今日自分のとこでいろいろ実験してみたんだけど、スプライトを使う方が速い。まぁ、言語が違うからっていうのもあるのかもしれないけれど(その先輩はC++、私はC#)、「SetTextureやSetSouceStreamは遅い」のを理由に、「同じものをたくさん描画」するときは、もしかしたらポリゴンの方が有利なシーンもあるのかな? ……とも思う。少なくともうちの環境では、Transformedな頂点バッファで毎回頂点バッファを作り直すよりは、World行列をごにょった方が速い。当たり前。でまぁ、testscene.cs:いろいろやってみたんだけど……。うーん……。それでもSpriteのが速い。
Transformedの方は何か根本的な勘違いをしていて、本来はシーン中で描画しようとする頂点をすべてまとめてバッファにWriteしないといけないと思うんだけど、今回「あるゲーム用」じゃなくて、ライブラリとしてプログラムを書いてるからどうしていいのかわからない。もしやるとしたら、ライブラリ描画APIにバッチのような機能をつけて、何を描くのか記憶しておいてから、いざ描く段階でまとめて頂点を用意して、だーっと流し込む……ってことだよなぁ、これ。しかも、やっぱ回転とか拡縮はVertexShader使いたいし、テクスチャのUV座標だって毎回同じとこが使える訳じゃないから、PositionColoredTextured を使ったとしても、描画命令をバッファリングして云々しなきゃいけないように思う。4頂点*XYZRGBAUVとテクスチャのハンドルかぁ? エフェクトプログラムを自分で書いて複数ストリーム使えるようにしてってのも考えられなくもないけど、結局それぞれ異なるUV座標ストリームを誰がどうやって管理するのか。現状でPositionの3Dの方も、Spriteに負けてるので、DrawPrimitivesの回数も減らさないといけないはず。Worldへの代入なくしたら、なんか140FPS出てるなぁ……VertexShader使うなってこと? うーん……というか、これがたぶんSpriteの中の人がやってくれてることなんだけど、自前でやったからといって、あんまり速くなるとは考えにくいなぁ……。
そんなことより、もっと描画に制限つけて深度テストで落ちるピクセルを増やした方がいいのか。でも、アルファブレンドがあるから結局後ろから描いたらZテストなんか生きないし、アルファブレンド指定のテクスチャだけ後から描くとか結果違っちゃうじゃん!だし。うー……
メソッドコールのオーバーヘッドもよくわかんなくなってきた。なんかメソッドコール1つネスト増やしただけで3FPSも落ちるし。と思ったら増やしても落ちないAPIもあるし。いったいどうなってんの最適化! 特にメソッドのインライン展開。インライン化やJITを指定したいなぁ^^;; もはや俺は何のためにC#を使っているのか。いやメモリ管理しなくていいから超楽です。その他リソース管理も忘れてもいい設計にしよう。
ぐー……。
あぁだから、Drawメソッド内では、VertexBufferはLockしっぱなしにしておいて、描画命令が呼ばれるたびWriteして……どっちみちテクスチャはどっかに記憶しておかなきゃいかんのか。まぁ、最後にSprite.End()じゃないけどまとめて描けばいいのか。座標計算が全部CPUになるけど、GPUのPixelShaderにはがんばってもらえるし……うーん。つまり、SoftwareVertexProcessingですね、わかります。FPS半分しか出ないやい。