Direct3D 10 Shader4.0 ID3D10Include の活用

引き続き HLSL/Effect のコンパイル周りの話です。
core API 側の Shader Compiler で #include に対応するには
ID3D10Include の準備が必要です。
これはもともと Direct3D9 の D3DX にあったもので、
機能も使い方もいっしょのようです。

ただ、D3DX10 の Shader Compiler API を使う分には内部で
勝手に include 処理をやってくれますし、下記エントリで書いた
ように D3DX 側 API を使った方が良いので、普通に使う分には
あまり気にする必要は無いかもしれません。
>・Direct3D 10 Shader4.0 APIによってコンパイラが違う

一応試してみました。

class fxInclude : public ID3D10Include {
public:
    fxInclude()
    {
    }
    ~fxInclude()
    {
    }
    virtual HRESULT __stdcall  Open(
                D3D10_INCLUDE_TYPE inctype,
                LPCSTR filename,
                LPCVOID parentdata,
                LPCVOID* ppdata,
                UINT* pbyte )
    {
        UINT   bsize= __FileSize( filename );
        void*  ptr= __Alloc( bsize );
        if( ptr ){
            if( __Load( ptr, filename, bsize ) ){
                *ppdata= ptr;
                *pbyte= bsize;
                return	S_OK;
            }
            __Free( ptr );
        }
        return	E_FAIL;
    }
    virtual HRESULT __stdcall  Close( LPCVOID ppdata )
    {
        __Free( const_cast( ppdata ) );
        return  S_OK;
    }
};

使っているところ。

ID3D10Blob* blobEffect= NULL;
ID3D10Blob* blobError= NULL;
fxInclude  incFunc;
D3D10CompileEffectFromMemory(
    memory,
    size,
    fxname,
    cpp_defines,// def
    &incFunc,	// inc
    0,		// HLSLflag
    0,		// FXflag
    &blobEffect,
    &blobError
);

#include の度にファイル名を持って callback されるので、
必要なメモリ領域を作ってあげるだけです。
不要になったら Close() を呼び出してくれます。

ID3D10Include を自前で用意する目的として考えられるのは、
include path 検索への対応でしょうか。

もしくは File にこだわらず、特定の include キーワードに
反応して別のコマンドを挿入したり pragma のように動作を
変えることも出来そうです。
自分で Effect のテキストを読み進める処理が不要なので、
意外に使えるかもしれません。

というわけで

 #include “output_disassemble”
 #include “output_preprocess”

と記述したシェーダーは、デバッグテスト用に disassemble や
preprocess 結果をファイルに書き出すようにしてみました。

テスト&デバッグ中は毎回出力して欲しいけど、完成した
シェーダーの場合は余計なファイルを作られても困ります。

今までは debug build の場合無条件に両方書き出していたので、
不要なファイルが多数生成されていました。これで、完成した
シェーダーは余計なことをしなくて済むようになります。
あまりきれいな方法じゃないけどちょっと便利になりました。