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

D3D10/DX10 D3D10_FILTER の新機能

D3D10_FILTER にはものすごく長いシンボルが定義されています。
例えばこんなの
  D3D10_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR
タイピングの困難さとかソースコードの折り返しやみやすさの問題とかは
おいといて、これらのシンボルを見ていると COMPARISON とつくものが
一通り増えていることがわかります。
msdn D3D10_FILTER

どうやら従来 nVIDIA の GPU にだけ搭載されていた Shadow Map 用の
ハードウエア機能が一般化されて D3D の標準機能に昇格したものと思われます。
nVIDIA Shadow Map は GeForce3 から搭載されたもので、depth 値を比較して
同時にフィルタリングをしてくれました。
いわゆる PCF の 4サンプル分までがバイリニアフィルタリングつきで
低コストで得られます。
PCF によるソフトシャドウは一般的なテクスチャフィルタは使えず
膨大なサンプリングが必要なので、ある程度ハードウエアで稼げるのはお得です。

この D3D10_FILTER の比較付きサンプリングを行うためには、
HLSL の専用命令 texture.SampleCmp() や texture.SampleCmpLevelZero()
を使う必要があります。サンプリングした結果を比較し、結果の bool 値が
フィルタリング対象となるわけです。

マニュアルをよく読むと使えるフォーマットに制限があるようです。
R32_FLOAT_X8X24_TYPELESS, R32_FLOAT, R24_UNORM_X8_TYPELESS, R16_UNORM
やっぱりまだこれらの命令は depth 値専用でしょうか。

まだ D3D10 上では試していないので、影描画に着手するあたりにはいろいろ
実験してみます。

以前 RADEON HD 2900XT でも Direct3D9 で作った nVIDIA Shadow Map の
影描画プログラムが、そのまま通ってしまうことをこちらで書きました。
D3D10/DX10 RADEON HD2900XT

RADEON X1900 世代ではバイリニア用サンプラを使った depth 値の同時
4 sample までがハードウエアサポートで、それ以降の比較やフィルタリング
はシェーダー実装する必要がありました。D3D10 の機能として採用された
おかげで nVIDIAと完全に同等の機能が使用可能になったのではないかと
考えられます。

ちなみに D3D10_FILTER の最後には D3D10_FILTER_TEXT_1BIT という特殊な
シンボルが定義されています。
フォントのための専用テクスチャフォーマット用らしいですね。
D3D10 からついた 1bit フォーマットのテクスチャで使うものと思われます。
デバッグ用フォントのフォーマットとして使えるならメモリ効率も良くて
お得ですね。

D3D10/DX10 Effect と CBufferの関係

Effect Interface内情報の続きです。
ID3D10Effect は内部で必要な ConstantBuffer を生成しパラメータを保持
しています。cbuffer 宣言で明示的に ConstantBuffer を指定することが
できますが、実際に生成されているバッファは宣言した cbuffer の数よりも
1つ多いようです。
調べてみると ‘$Globals’ という暗黙の CBuffer が作られており、おそらく
cbuffer 宣言無しに定義した global 変数が $Globals 扱いになるのでしょう。
ID3D10Effect の CBuffer は ID3D10EffectConstantBuffer 経由で取り出せます。

例えば作成済み D3D10Effect の ie1 から、cbuffer LMaterial の IBuffer
(ConstantBuffer) を参照するには次のようになります。

ID3D10Effect* ie1; // input
ID3D10Buffer* ib1= NULL; // output
ID3D10EffectConstantBuffer* cf1= ie1->GetConstantBufferByName( “LMaterial” );
cf1->GetConstantBuffer( &ib1 );

このとき ib1 は Get によって AddRef() されており参照カウンタ値は 2 です。
自前で用意した CBuffer を与えるとどうなるでしょうか。

ID3D10Effect のインスタンスを 2つ用意し、ie1 に ie2 の CBuffer を設定して
みました。

ID3D10Effect* ie1; // input
ID3D10Effect* ie2; // input
ID3D10EffectConstantBuffer* cf1= ie1->GetConstantBufferByName( “LMaterial” );
ID3D10EffectConstantBuffer* cf2= ie2->GetConstantBufferByName( “LMaterial” );
ID3D10Buffer* ib1= NULL;
ID3D10Buffer* ib2= NULL;
cf1->GetConstantBuffer( &ib1 );
cf2->GetConstantBuffer( &ib2 );
cf1->SetConstantBuffer( &1b2 ); // ie1 ← ie2

ここで ib1, ib2 それぞれの参照カウンタを見ると 1 と 3 になっています。
つまり ie1 側の CBuffer は事実上解放されており、ie2 側の CBuffer が
共有されていることが参照カウンタの増加から分かります。

ID3D10Shader を使わずとも ID3D10Effect だけでバッファの共有管理を自前で
行うことができそうです。

D3D10/DX10 Effect Interface内情報

D3D10 では D3D9 と違い、Effect (fx) API は D3DX ではなく D3D10 に
含まれています。インターフェースは ID3D10Effect で、シェーダーの
コンパイルや fx に含まれる各種変数やステート情報へのアクセスなどが
できるようになっています。

従来どおり個別の VertexShader / GeometryShader / PixelShader も
扱うことができ、こちらは Shader インターフェースとしてまとめられています。
・ID3D10GeometryShader
・ID3D10PixelShader
・ID3D10VertexShader

D3D10Effect から各種シェーダーを直接取り出す手順はこんな感じになりました。

// vertex shader
D3D10Effect* ieffect; // input
D3D10VertexShader* ivsh= NULL; // output
D3D10EffectTechnique* itechnique= ieffect->GetTechniqueByName( “Main” );
D3D10EffectPass* ipass= itechnique->GetPassByIndex( 0 );
if( ipass->IsValid() ){
 D3D10_PASS_SHADER_DESC shdesc;
 ipass->GetVertexShaderDesc( &shdesc );
 ID3D10EffectShaderVariable* ishadervar= shdesc.pShaderVariable;
 if( ishadervar->IsValid() ){
  ishadervar->GetVertexShader( shdesc.ShaderIndex, &ivsh );
 }
}

これは technique Main の Pass0 の VertexShader を参照しています。
このとき、得られた D3D10VertexShader の参照カウンタが増加するので、
不要になったら ivsh には Release() が必要です。

それに対して D3D10EffectShaderVariable 等、Reflection 系のアクセス
インターフェースは COM ではないので参照カウンタがありません。
ID3D10ShaderReflectionVariable 等も全く同じです。
D3D10 では最初はこの辺の区別がつきづらく、慣れるまで少々分かりにくく
なりました。

ここでちょっとはまった注意点として GeometryShader があります。
というのは、Effect(fx) 内部で GeometryShader に NULL を設定していても
ipass->GetGeometryShaderDesc() が成功して D3D10EffectShaderVariable* を
参照できてしまうからです。IsValid() も通過します。
どうやら内部で static の NULL object を用意しているらしく、
GeometryShader に NULL を設定した場合はどの D3D10Effect でも全く同じ
D3D10EffectShaderVariable のアドレスが返ってきました。
D3D10EffectShaderVariable::GetGeometryShader() では NULL が返るので、
このことが分かっていれば全く問題はありません。

shader からさらに D3D10ShaderReflection を取得するには次のようになります。

ID3D10EffectShaderVariable* ishadervar; // input
ID3D10ShaderReflection* iref= NULL; // output
D3D10_EFFECT_SHADER_DESC efsdesc;
ishadervar->GetShaderDesc( &efsdesc );
D3D10ReflectionShader( efsdesc.pBytecode, efsdesc.BytecodeLength, &iref );

Reflection 等から変数の要素1つ1つ調べるには ~Variable から ~Type を
取得して調べていきます。
例えば Effect なら D3D10EffectType があり、Shader なら
D3D10ShaderReflectionType を使います。
Variable が構造体なら、さらに GetMemberTypeByIndex() 等で内部の
メンバー情報を参照していく必要があるようです。

もちろん変数名等を使って Effect が管理するバッファに値を格納するだけなら
Reflection とか考えずに
 GetVariableByName() → AsVector() → SetFloatVector()
とか使えば良いので簡単です。
だけど D3D9 と違って StateManager とか使わずに API だけでもきちんと
全情報にアクセスできるみたいなので、Effect 内の管理に頼らないで
パラメータ管理自前で乗っ取っても大丈夫そうです。
そういえば、変数名でなく取得したハンドルでのアクセス方法は
なくなっているみたいですね。

EMOBILE EM・ONE 3D Box のゲーム

久しぶりに 3D Box を起動したら
「ゲーム」の引き出しにコンテンツがいっぱい入っていて驚きました。
・「右脳鍛錬ウノタン」判断力、集中力
・「どこでも英会話」1~8
合わせて10本あります。(2007/07/01現在)
EMOBILE コンテンツダウンロード

これらはダウンロード可能なファイルになっていてそれぞれ 2.5M~3MByte
ほどです。形式は見慣れた CAB ファイルで、一般のアプリケーション同様
インストールできます。
一度インストールすればスタートメニューのプログラムから実行できます。
やっぱり普通のソフトです。

数が多いけれど分割ダウンロードでは無いようです。
1つ1つ個別のソフトで、単体で起動できるしインストールするたびに
アイコンが増えていきます。

3D Box ではストリームのムービーだけでなく、このようなアプリケーション
の配信も行っているんですね。ちょっと得した気分です。

W-ZERO3[es] Linux (2) mini SD

Readme-ja.txt を参考に miniSD を mount してみました。
内蔵キーボードで長いデバイス名を打つのは大変なので省略しています。

$ mknod /dev/sd b 254 1
$ mkdir /mnt/sd
$ mount /dev/sd /mnt/sd
$ df

Filesystem Size Used Available Use% Mounted on
/dev/sd 1.9G 256.0k 1.9G 0% /mnt/sd

SD にリダイレクトして書き込み → umount → PCで読み出し
等も普通にできました。

$ dmesg