月別アーカイブ: 2007年7月

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 での実験も忘れないようにします。

Direct3D 10 ビデオカードの違いはわからない

Direct3D10 になって「caps がなくなった」のは大きな特徴のひとつです。
MS の DX10 ppt スライド等でも何度も出てきており、メリットとして強調
しています。

従来メーカー毎に、ビデオカードごとに、さらにはドライバごとに対応機能も
能力もばらばらなのが当たり前でした。

新しいビデオカードを手に入れたなら、まずは caps を調べます。
対応するサーフェースフォーマットを調べて、テクスチャサイズの制限を調べて、
使えるブレンドモードを調べて、、次に各種パフォーマンスと
やることがたくさんありました。

DirectX API のすべての機能が最初から使えるビデオカードなど無いので、
手に入れてから見たことがない機能が enable されていたりすると
妙に嬉しかったりするわけです。(←それは一部のマニアだけです)

nVIDIA と ATI の2強になってからは手間が大幅に減りましたが、このような
能力の差はかなりの開発の負担となります。結局どれでも動く当たり障りの
無い機能しか使えないし、動作確認もばかになりません。

Direct3D10 ではこの負担を減らすために、機能はどのビデオカードでも
同じように使えることが前提となりました。なので、caps が廃止された
ことの本当の意味は

 caps によって機能の違いを調べる必要が無い

ということです。

実際に RADEON HD2900XT を使ってみました。
caps が違ったり機能が違ったり、列挙の値が違ったりすることも全く無くて、
普段使ってる GeForce8800GTS と一見何も変わりません。今までのように API
を使う上での違いが全く見えません。ちょっとさびしいくらいです。

これは API から見えないだけで本当はハードの特性は異なっており、
機能ではなく速度面で調査する段階になったらかなりの個性が見えてくる
はずです。

だけどそのような違いも一見ドライバレベルで隠蔽されていて、おそらく下位
モデルで試しても全く同じなのでしょう。

プログラムの開発上は機能的な差がなくなりましたが、パフォーマンスを維持
するならある程度の機能的取捨選択のノウハウは必要になると考えられます。

一見違いが無くても、下位モデルでは一部機能がソフトウエア実装だったり
使えるリソースが大幅に減っていたりする可能性が十分考えられるからです。

これらの可能性があるとしても機能的な違いが開発側から見えないということは、
開発が楽になることの裏返しとして、
実はその選択をユーザー側に押し付けているだけなのかもしれません。

アプリケーション側での選択の余地が減った代わりに、ユーザーが自分で
パフォーマンスが足りなければ機能を落として、またはより良いハードを購入
して対処しなければならないからです。

作る側としてはそうならないよう、努力を忘れないよう、
肝に銘じておきます。

D3D10 ConstantBuffer のアクセス補足など

以前こちらで ConstantBuffer を書き換える方法を調べました。
D3D10 ConstantBuffer の更新方法
書き忘れがあったので補足します。
ID3D10Effect 自体は内部で (2) の方法、つまり

  ID3D10Device::UpdateSubresource()

を使っているようです。なぜかというと、ID3D10Effect で作成した Effect から
内部の ConstantBuffer を参照して DESC を見ると D3D10_USAGE_DEFAULT で
作られているからです。
なので、ConstantBuffer の書き換えは UpdateSubresource() が標準的な
使い方なのかもしれません。

だけど、ConstantBuffer に直接アクセスしている唯一のサンプル
HLSLWithoutFX10 では Map()/Unmap() を使っているんですよね。

長かったですが、ようやく方針も固まって、周辺ライブラリとかツールとか
できてきたので実際の描画実験に手を出せそうです。
リソース管理とかシェーダーの管理、パラメータのリンク方法、スクリプト、
データフォーマットなどかなり遠回りしました。非常に時間がかかってます。
DXUT は使わず、D3DX もテクスチャローダーだけ使っています。

fx は使ってますが、ID3DEffect から ID3D10Shader を取り出して、あとは
直接管理することにしました。この方法だと内部に無駄な ID3D10Buffer が
たくさん出来ているので、最終的には直接 ID3D~Shader を生成するつもりです。