Direct3D 10 Streamと同時Resource

Vertex として Stream で読み込んでいる Buffer を、
ShaderResourceView で同時にランダムアクセスすることができました。
これはいいね、使えそう。

可能
・Stream + ShaderResourceView

不可能
・StreamOutput + ShaderResourceView
・StreamOutput + StreamInput

これらのパラメータ組み合わせは D3D10_CREATE_DEVICE_DEBUG 時は
かなり細かくチェックしてくれて詳細な説明とともにエラーが出ます。

若干気をつけないといけないのはパラメータ設定の順番です。

IASetVertex BufA
SOSetTarget BufB
Draw

IASetVertex BufB
SOSetTarget BufC
Draw

SOSetTarget NULL

一見問題ないように見えますが、2つ目の IASetVertex BufB では、
BufB がまだ StreamOutput 対象だからだめだと怒られます。

先に SOSetTarget BufC を設定しなおして BufB を切り離すか、
間に SOSetTarget NULL が必要となります。

IASetVertex BufA
SOSetTarget BufB
Draw

SOSetTarget BufC
IASetVertex BufB
Draw

SOSetTarget NULL

同様のことは ShaderResource や StreamInput 側にも言えます。
特に Stream の 2~3 番目に設定された Buffer は NULL による解放を
を忘れがちなので、あとから StreamOutput の Target にしようとすると
エラーです。

ミスを無くすためには Set 系には毎回こまめに NULL を入れた方が
いいようです。

それにしても Direct3D10 + ShaderModel4.0 は、
こうしなければいけないっていう変な制限が少なく、
Buffer やら InstanceID とか組み合わせたり、
結構自由に考えたとおりに動いてくれるのが気持ちいいですね。
(速度や効率はおいといて)

Direct3D 10 8bit IndexBuffer

d3d10.h (June2007) を見ると、
D3D10_16BIT_INDEX_STRIP_CUT_VALUE や
D3D10_32BIT_INDEX_STRIP_CUT_VALUE と一緒に、
D3D10_8BIT_INDEX_STRIP_CUT_VALUE なるシンボルが定義してあります。
これだけみるとなんだか 8bit IndexBuffer が使えそうです。

ID3D10Device::IASetIndexBuffer
マニュアルにはだめ (16bit or 32bit) と明記されてますが、さすが
Unified Shader だなと思って R8_UINT を試してみました。

結果はだめでディスプレイドライバがハングアップし、ドライバリセットが
かかります。
画面にプリミティブ形状は出るので、一応中で変換するのか
またはハード上バッファは読めるが API で禁止しているのかわかりません。
追求はしておりません。

Shader が自分で Buffer を読み進めれば似たようなことはできるのですが。

STRIP_CUT_VALUE は Strip 中にプリミティブの区切りを指定する特殊な
Index 値です。D3D9 までは頂点を同じ座標に何度も重ね書きすることで
Jump してましたが D3D10 では扱いが簡単になりました。

Direct3D 10 HLSL(fx) の書き方とサイズ

HLSL で記述した Effect(fx) ファイルには複数の technique を記述して
おくことができます。
またそれぞれの technique は複数の pass を含めることができるので、
1つの Effect ファイルにはたくさんのシェーダーが入っている可能性があります。

その記述方法としては、例えばこんな感じになります。

———————————————————————
technique10 Main
{
  pass P0
  {
    SetVertexShader( CompileShader( vs_4_0, VS_Main() ) );
    SetGeometryShader( CompileShader( gs_4_0, GS_Main() ) );
    SetPixelShader( CompileShader( ps_4_0, PS_Main() ) );
  }
}

technique10 Animation
{
  pass P0
  {
    SetVertexShader( CompileShader( vs_4_0, VS_Animation() ) );
    SetGeometryShader( CompileShader( gs_4_0, GS_Main() ) );
    SetPixelShader( CompileShader( ps_4_0, PS_Main() ) );
  }
}
———————————————————————

ここで technique Main と Animation の違いは VertexShader だけです。
Direct3D10 の fx_4_0 では、GeometryShader と PixelShader を
あらかじめコンパイルしておいて下記のように記述することができます。

———————————————————————
GeometryShader gs_main= CompileShader( gs_4_0, GS_Main() );
PixelShader ps_main= CompileShader( ps_4_0, PS_Main() );

technique10 Main
{
  pass P0
  {
    SetVertexShader( CompileShader( vs_4_0, VS_Main() ) );
    SetGeometryShader( gs_main );
    SetPixelShader( ps_main );
  }
}

technique10 Animation
{
  pass P0
  {
    SetVertexShader( CompileShader( vs_4_0, VS_Animation() ) );
    SetGeometryShader( gs_main );
    SetPixelShader( ps_main );
  }
}
———————————————————————

この両者やってることは変わらないのに、下の方がコンパイルした後のバイナリ
サイズでちょうど重複するシェーダーの分だけ小さくなります。
おそらくコンパイル時間も短縮されているのでしょう。
technique 間のシェーダー流用は多いし、コードもだんだん複雑に長くなって
きているので、この辺しっかり注意して書いた方がよさそうですね。

D3D10 DrawIndexedInstanced()後

非常に情けない話です。
D3D10 DrawIndexedInstanced()が
で書いた DrawIndexedInstanced() のオフセットの問題は、やっぱりこちらの
プログラムが原因でした。
D3D10 Device の wrapper で StartIndexLocation を StartInstanceLocation と
間違って記述していました。

DrawInstanced() の StartInstanceLocation と同じようにしっかり意図通り動作
しております。申し訳ありません。

●VertexShader に対する入力データのまとめ

・VertexStream
  ・頂点単位入力
  ・インスタンス単位入力

・ShaderResourceView / tbuffer
  ・Random Access (ld,sampler)

・ConstantBuffer (cbuffer)
  ・Random Access (cレジスタ)

Direct3D 10 大はまり tbuffer

なぜか shader (4.0) の tbuffer がうまく動きません。
これはかなり はまり ました。
Texture など他に ShaderResource を使わない状態での
tbuffer または Buffer 宣言で、
最初のベクトルしか読み出せない症状が発生します。
例えば

tbuffer ColorData
{
 float4 color0;
 float4 color1;
 float4 color2;
};

と宣言し、
color0 = { 1, 0, 0, 1 } (赤)
color1 = { 1, 1, 0, 1 } (黄色)
color2 = { 0, 1, 0, 1 } (緑)
のようにパラメータを設定したとします。

VS または PS で color1 を読み出してもなぜか color0 の値「赤」が
表示されてしまいます。

これは ShaderResource にして
Buffer
のように宣言して Load を使っても同じでした。

使い方の問題だと思っておかしいおかしいと散々悩むこと丸一日。
ふと Reference Driver で試すとちゃんと黄色になるではありませんか。
もしやと思って、RADEON HD 2900XT で走らせるとこちらも「黄色」!!
これは参りました。

ちなみにそれまで使っていたのは
GeForce8800GTS + ForceWare 158.24
(2007/07/22 現在の公式最新版) です。

たまたま BETA 版ドライバが 2007/07/11 に出ていたので

BETA 版 ForceWare 163.11

に入れ替えたら、、きちんと黄色です!

以前 88 の BETA 版ドライバで懲りていたので、
入れ替えを控えていたのですよ。
Reference での実験も忘れないようにします。