2008/09/12(金)にゅーふれーむわーくの悩み2

はてブ数 2008/09/12 15:52 計算機な日記::ソフト作りつーさ

今日はアマゾンのペリカンはこないのか……。まぁ僻地だしなぁ。

さて、昨日(?)の続き。

「VertexBufferはLockしっぱなしにしておいて」を試してみたが、DrawPrimitivesなんか呼び出す前からFPSが下がる。DrawPrimitivesを複数回呼び出すのはそんなでもないっぽい。これは推測なのだけども……VertexBuffer.Lock は C++ だったらポインタが返ってくるところを、C#だとGraphicStreamを通すかArrayで取得するかしかなくて、Lockの際にでデータの変換(マーシャリング)が挟まって、それがボトルネックになっているのかなぁ、なんて勘ぐっている。もしそうだったとして、速度にどうしても満足いかないのならどうしようもない。素直にManagedDirectXを諦めるしかないだろう。結局C++かよ!

まぁ、気を取り直して……VertexBuffer更新の最善手を探索してみようか。まず、Lock()のArrayが戻るオーバーロードの方。vertexBuffer.Lock() / Unlock()するだけで60FPSに下がる。取得した配列を変更することによるFPSの低下はほとんどなし。でもまだ、SetTextureとか呼んでないので、これに加えて9000回のSetTextureを追加してみると48FPS。とはいえ、大量に弾をばらまくような場合は大抵前に書いたテクスチャと同じであることが多いから、そういう場合は呼び出しをスキップすることを考え、SetTextureは30回程度にすると57FPS。ようやく、Spriteに追いついてきた。

GraphicStream の方はLock/Unlockのみで80FPSで4頂点*9000回のWriteすると20FPSくらいまで下がる。9000個*4頂点*PositionColoredTexturedって単純に考えたら1秒あたり77MBのメモリを処理しなきゃなんないってこと? くぎゅー

Worldへの代入はとてつもなく遅いので、座標変換はCPUで計算した変換先の値を直接頂点バッファへ書き込むことにする。じゃあ、VertexはTransformedColoredTexturedのがいいかといわれるとそうでもなくて……Lock時間は当然のように、VertexBufferのサイズに比例してトロくなるようだ。つまり、PositionColoredTexturedよりパラメータの多いTransformedColoredTexturedのが遅かった(なんてこと!)。また、ライブラリとした際にはバッファサイズをどのくらいにするか(今は36000頂点ぴったり)とかいう問題もある……今のところは、まだ何も考えないでよいSpriteに軍配が上がっている感じであるなぁ。うーん。……というか、Sprite.Transform に突っ込んだ行列ってCPUで処理されてんのかな。それとも、Sprite用のエフェクトプログラムが使われ、かつ、ネイティブ処理だから速いのかな? でも、それだったらWorldへの代入が遅い理由もよくわかんないよね。うーん。でもまぁ、Spriteは十分に速いと思う。

さて……少し制約を課して、VertexをPositionTexturedにしてみる。色指定がなくなるぶんLockに掛かる時間は減る。ただ、任意指定値でのアルファブレンドができなくなる。当然、フェードインフェードアウトとかもできなくなる。それは嫌なので、RenderState.SourceBlendとかにBlendFactorを使うようにする。RGBチャンネルごとにブレンド率を独立で指定できるようになる(どうでもいい)。色乗算はできないが半透明描画はできるようになる。しかして、これではテクスチャのアルファチャンネルが無視されてしまうので抜き色コピーができない。というわけで、AlphaTestEnableをTrueにして、Alphaチャンネルが0のピクセルに関しては捨てることにする。これで抜き色は使えるようになる。BlendFactorを弄れば、アルファブレンドも可能。結果としてFPSは+5くらい。うわ、ビミョー。しかも、よく考えたら、Blend弄れないから、加算合成とかできないじゃん。はいはい、廃案廃案。

そろそろ、「やっぱり素直にSprite使うのがいいんでないかしら」という結論に至りそうではある。VertexBufferのロックがとろいんだから、エフェクトプログラムなんか書く以前の問題だよねぇ……

ココロさん、お茶飲んでないで教えてよー とか言って……くぎゅー。全然進みません。Sprite使うかぁ……。