コンシューマ系の組み込みハードと PC の Direct3D では、気をつけなければいけ
ない点が異なっています。思わぬボトルネックが発生します。
とあるメーカーが開発した PC 向けのタイトルのサンプルで、非常に動作が重い
ものがありました。しかもモデルデータのせいで処理が重いので、データを軽く
して欲しいとの話でした。またデータのせいで使えるビデオカードにも制約が
出てしまうとの指摘でした。
画面は 3D のフィールドを表示するシンプルな画面で、背景もキャラクタもごく
普通のモデルデータです。
ところが非常に要求スペックが高く、ためしに起動した PC では 1fps も出てい
ない状況でした。
大体予想がつきましたが、おそらく GPU ではなく CPU の方で処理が落ちている
のでしょう。見たところデータフォルダ内には細切れになったテクスチャが大量
に入っていました。
PC の場合、Direct3D の描画 API の呼び出し回数によって速度が大幅に変わります。
そのためエンジン設計の第一歩は Draw の回数を減らすことからです。
描画はできるだけまとめてばらばらのオブジェクトも一回で描画できるようにします。
Draw 呼び出しの内部ではマテリアルやレンダーステートを切り替えられないので、
マテリアルの数がそのまま描画回数の増加につながります。
テクスチャはできるだけシートにまとめ、マテリアルパラメータは可能ならば頂点
に埋め込みます。
マテリアルやシェーダーの切り替えも負荷になるので、切り替えを最小限にするため
には描画の前にソートしておく必要があります。
また ShaderModel3.0 や、ATI RADEON の ShaderModel2.0 では、ジオメトリ
インスタンシングを使うことができます。頂点ストリームにジオメトリやマテリアル
を書き込んでおくことで、一度の描画呼び出しで大量のオブジェクトを描画可能です。
つまり、描画時には必ずこのような描画を減らす工夫が必要だということです。
そうでないと描画呼び出し API の実行だけで CPU サイクルを消費してしまいます。
コンシューマ系の組み込みハードウエアでは、描画 API の Call はそれほど負荷に
ならず、テクスチャの変更もほとんどサイクル数を消費しないものがあります。
そのためつい同じような考えで描画パイプラインを設計してしまうと思わぬ
ボトルネックに苦しむことになります。
WindowsVista + Direct3D10 では、ステート等のバッファを VRAM 上に確保できる
など、より負荷を軽くするためのさまざまな工夫が施されているようです。
Draw 呼び出し回数の次に考えられる CPU のボトルネックはバッファの lock です。
例えばキャラクタのスキニング等で頂点バッファを lock して書き換えると、GPU
との同期待ちで CPU が無駄に待っている可能性があります。
シェーダーで演算すれば解決なのですが、どうしても CPU で書き込みを行う場合は
フレームバッファと同じように頂点バッファを複数持つ必要があります。頂点バッ
ファを POOL 化して、書き換えた頂点を発行するたびに使用するバッファを切り
替えていきます。
このあたりのボトルネックは、今では PIX 等の解析ツールを見れば一目瞭然で
しょう。