再び HLSL (Effect) のコンパイル関連です。
・Direct3D 10 Shader4.0 APIによってコンパイラが違う
で少々調べたので、もう少し説明してみます。
マニュアルに詳しく書かれていないこと、わかりにくいこと、
実際に試したことなどなどをメモしていきます。
API まとめ
・Compile 系 API HLSL/fx → Blob のバイトコード ID3D10Effect/D3D10CompileEffectFromMemory() ID3D10Shader/D3D10CompileShader() D3DX10/D3DX10CompileFromFile() D3DX10/D3DX10CompileFromMemory() D3DX10/D3DX10CompileFromResource() ・Create 系 API バイトコード → インターフェース ID3D10Device::CreateVertexShader() ID3D10Device::CreatePixelShader() ID3D10Device::CreateGeometryShader() ID3D10Device::CreateGeometryShaderWithStreamOutput() ID3D10Effect/D3D10CreateEffectFromMemory() ID3D10Effect/D3D10CreateEffectPoolFromMemory() D3DX10/D3DX10CreateEffectFromFile() D3DX10/D3DX10CreateEffectFromMemory() D3DX10/D3DX10CreateEffectFromResource() D3DX10/D3DX10CreateEffectPoolFromFile() D3DX10/D3DX10CreateEffectPoolFromMemory() D3DX10/D3DX10CreateEffectPoolFromResource() D3DX10/D3DX10CreateAsync~ ・Disassemble 系 API インターフェース → Blob の disassemble リスト ID3D10Shader/D3D10DisassembleShader() ID3D10Effect/D3D10DisassembleEffect() D3DX10/D3DX10DisassembleShader() D3DX10/D3DX10DisassembleEffect() ・Preprocessor 系 API HLSL/fx → Blob のテキスト ID3D10Shader/D3D10PreprocessShader() D3DX10/D3DX10PreprocessShaderFromFile() D3DX10/D3DX10PreprocessShaderFromMemory() D3DX10/D3DX10PreprocessShaderFromResource()
必要な機能がほとんどそろっています。fxc.exe はコマンド
ライン引数のパースだけで、あとは D3DX10 を呼び出している
だけのようです。
D3DX10 の D3DX10Create~ は HLSL からのコンパイルだけでなく、
コンパイル済みデータ(fxo)を受け取ることも出来ます。
Preprocessor は Include や Macro 等のテキスト処理を行い、
結果を返してくれる便利な関数です。まず、シェーダー
コンパイル時にマクロの適用がきちんと行われているか確認
することができます。
またシェーダーにこだわらず、script 系言語の汎用のテキスト
処理フィルタとして流用できるかもしれません。
ただ一旦パーサにかけたテキストを再構築して出力している
らしく、無駄な空白や空行が除去され各キーワードがスペース
区切りに置き換わっています。
わかりやすいし処理しやすいものの、#line 等のディレクティブも
失われてしまいます。
本当のプリプロセッサとして活用する場合は、エラー時の行番号
を求めることが出来ず、デバッグしづらくなるのが難点でしょう。
Disassemble/Preprocessor など Blob のテキストで返す API は
‘\0’ 終端でかつ、ID3D10Blob::GetBufferSize() が ‘\0’ を
含めたサイズを返す点に注意です。
例えばマニュアルの D3D10DisassembleEffect の説明には下記の
プログラム例が載っています。(下記はマニュアルからの引用)
LPCSTR commentString = NULL; ID3D10Blob* pIDisassembly = NULL; char* pDisassembly = NULL; if( pVSBuf ) { D3D10DisassembleEffect( (UINT*) l_pBlob_Effect->GetBufferPointer(), l_pBlob_Effect->GetBufferSize(), TRUE, commentString, &pIDisassembly ); if( pIDisassembly ) { FILE* pFile = fopen( "effect.htm", "w" ); if( pFile) { fputs( (char*)pIDisassembly->GetBufferPointer(), pFile ); fclose( pFile ); } } }
もしこれを次のように書くと、テキストファイルの終端に ‘\0’ が
含まれてしまいます。
(__Write は指定バイト数ファイルに書き込む仮想 API とする)
__Write( pIDisassembly->GetBufferPointer(), pIDisassembly->GetBufferSize() );
D3DX10CompileFromFile() は開始関数名の指定があるので、一見
Shader コンパイル専用の関数に見えます。実際は Effect(fx) の
コンパイルも可能です。この場合関数名 pFunctionName には NULL
を渡します。
Compile 系 API に渡す D3D10_SHADER_MACRO は、#define ~ に
相当する定義リストを渡すためのものです。この定義リストは
定義内容を文字列で渡す必要があり、かつ NULL 終端です。
マニュアルの D3D10_SHADER_MACRO の記述例では size [1] の配列を
使っていてこの NULL 終端が含まれていないので注意です。
以下マニュアルより引用
D3D10_SHADER_MACRO Shader_Macros[1] = { "zero", "0" };
実際に使う場合はこんな感じです。
D3D10_SHADER_MACRO Shader_Macros[]= { { "zero", "0" }, { "TEXLAYER", "2" }, { "POINTLIGHT", "8" }, { NULL, NULL }, };
HYPERでんち の方もいくつか更新しました。
・シェーダーの世代ごとの違い
・DirectX SDK バージョン一覧