1月15日(2009)


エフェクトによるコンスタントバッファの設定

エフェクト内のScalar型のグローバル変数を個別にCPUからセットするよりも、
コンスタントバッファとして構造体などの形でまとめてセットしたほうが、
パフォーマンスの面からも望ましいとマニュアルにも書いてあった。

事実、エフェクトにグローバル変数をセットするたびに、その変数に応じた
ID3D10EffectVariableを生成し、値をセットしなければならなくなる。
…であれば、1つのメモリの塊としてセットするようにしたほうが、構造体の
変更だけで済む。(ソース側、シェーダー側に同時に変更する必要はあるが…)

ただ、実装も一筋縄ではいかなかった…。

手順としては
  1. GetConstantBufferByName()からID3D10EffectConstantBufferインターフェースを取得
  2. コンスタントバッファとしてCreateBuffer()からID3D10Bufferインターフェースを取得
  3. ID3D10Buffer->Map()Unmap()でバッファを更新し、SetConstantBuffer()でセットする

なのだが、それぞれのプロセスで注意が必要だったりする。

まず、コンスタントバッファの取得についてだが、

// エフェクトファイル
struct ConstBuff {
    int a;
};
ConstBuff g_const_buff;

// ソースファイル
GetConstantBufferByName( "g_const_buff" );

だとNG。明確な理由はちょっと謎…。
なので、以下のようにするときちんと取得できる

// エフェクトファイル
struct ConstBuff {
    int a;
};
cbuffer CBuff {
    ConstBuff g_const_buff;
};

// ソースファイル
GetConstantBufferByName( "CBuff" );

とやると設定できる。
この関数はシェーダー内の変数名ではなく、cbuffer領域の名前(セマンティクス?)を
指定しなければならないようだ。


次にID3D10Bufferの生成。
D3D10_BUFFER_DESCの設定に注意が必要

D3D10_BUFFER_DESC	bd;
{
    bd.ByteWidth      = sizeof( ConstBuff ) + (16 - sizeof( ConstBuff ) % 16);
    bd.Usage          = D3D10_USAGE_DYNAMIC;
    bd.BindFlags      = D3D10_BIND_CONSTANT_BUFFER;
    bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    bd.MiscFlags      = 0;
}

例えば上記の例だと、ByteWidthは16バイトアライメントに合わせないとCreateBuffer()が失敗する。
UsageD3D10_USAGE_DYNAMICにしないと書き換えができない。
BindFlagsはコンスタントバッファとして使用するためD3D10_BINd_CONSTANT_BUFFER
CPUAccessFlagsは書き換えできるようにD3D10_CPU_ACCESS_WRITEを指定。


最後に、コンスタントバッファの更新。
まずMap()にはD3D10_MAP_WRITE_DISCARDを指定する。
D3D10_MAP_WRITEはワナ。マニュアル見ても書き換え目的でオッケーそうなんだけど
実際は失敗してしまう。
あとはバッファを更新し、SetConstantBuffer()すればオケ。



シェーダー内の構造体

構造体内のベクトルやマトリクスは16byteアライメントに従うので、
中途半端な位置にメンバとしてベクトルとか置くと、想像していたメモリ配置と
異なるので注意!!
最終更新:2009年01月15日 20:42
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。