DX11エフェクトシステム作成 Part3 変数情報取得

コンパイルしたシェーダバイナリコードから使用されている変数の情報を取得します。ただしEffects11のような複雑(詳細)な情報ではなく必要最小限の情報のみ扱います。


シェーダにおける変数

行列などの変数の扱い方は、定数バッファが採用されたことで大きく変わっています。以前(DX9とか)は、少ない定数レジスタを効率よく使用するために不要な変数が削除されるため、値の更新が面倒でした。定数バッファでは容量に余裕があるため、不要な変数は削除されず、値の更新が簡単です(構造体をそのままコピーできる)。
D3DXのエフェクトは以前の面倒な変数の更新をやってくれていましたが、定数バッファによって必要性が薄れたような気がします(SDKから外された理由?)。

取得する変数情報は、リソース(定数バッファ、テクスチャ、サンプラ)に割り当てられたスロット番号のみになります。ちなみに、定数バッファ単位で未使用なものは割り当てから除外されます。

リソースへのスロット番号の割り当て仕様

基本的な割り当て
シェーダで利用されているものにだけスロット番号が割り当て。定義順に0番から割り当て(仕様?)。

// 定数バッファ、テクスチャ、SamplerState
cbuffer CB
{
    変数定義
};
Texture2D txDiffuse;//テクスチャ
SamplerState samLinear;//サンプラ
register()で番号指定
register定義を使用することでスロット番号を明示的に割り当てることが可能。

cbuffer CB : register( b0 )//スロット0に割り当て
{
    変数定義
};
Texture2D txDiffuse : register( t2 );
SamplerState samLinear : register( s5 );
register有無の混合
registerでスロット番号指定した場合、使用の有無にかかわらず番号が予約される。registerなしのリソースは、予約されていない番号が割り当てられる。

// registersがあるとシェーダ関数での使用の有無にかかわらず予約
// registerなしの場合予約されていない空き番号が割り当て
// テクスチャやSamplerStateでも同様
cbuffer CB1 //register(b2)に割り当て
{
    変数
};
cbuffer CB2 : register( b0 )
{
    変数	
};
cbuffer CB3 : register( b1 )
{
    変数
};
配列定義
定数バッファは配列不可。それ以外のリソースは配列定義できるが、利用に制限あり。

Texture2D txDiffuse[3];
//定数バッファは配列不可

この場合
txDiffuse[0] txDiffuse[1] txDiffuse[2]
という個別の変数として扱われる。ただしスロット番号は連続した番号が使用の有無にかかわらず割り当てられる。例として[1]が未使用でも[0]に0番、[2]に2番の割り当て。
もう一つ制限として、テクスチャなどのリソース変数は配列の添字に変数を使用できない。

cbufferなしの変数定義
自動的に定数バッファが割り当てられる。現環境では”$Grobals”という定数バッファが作成されている。それと未使用の変数でも削除されない。

float4 variable;
  ↓
cbuffer $Grobal
{
    float4 variable;
};

シェーダ変数の情報取得

コンパイルされたシェーダバイナリコードからID3D11ShaderReflectionインターフェイスを作成、取得。

HRESULT hr = D3DReflect( bincode, codesize,//コンパイルで得られたバイナリコード
                         IID_ID3D11ShaderReflection, (void**)&ref.ptr);
                       // dxguid.libのリンクが必要

// シェーダ情報取得
D3D11_SHADER_DESC shd_desc;
hr = ref->GetDesc( &shd_desc );
シェーダ入力パラメータ情報取得
for(UINT ip=0;ip<shd_desc.InputParameters;++ip){
    D3D11_SIGNATURE_PARAMETER_DESC desc;//入力パラメータ情報
    hr = ref->GetInputParameterDesc(ip, &desc);
}
割り当てられたスロット番号取得
for(UINT ip=0;ip<shd_desc.BoundResources;++ip){
    D3D11_SHADER_INPUT_BIND_DESC desc;
    hr = ref->GetResourceBindingDesc(ip, &desc);
    // desc.BindPointが割り当てられたスロット番号
    switch(desc.Type){
    case D3D_SIT_CBUFFER:
        //定数バッファ
        break;
    case D3D_SIT_TEXTURE:
        //テクスチャ
        break;
    case D3D_SIT_SAMPLER:
        //サンプラ
        break;
    }
}
定数バッファの変数定義詳細

不要かもしれない。
ID3D11ShaderReflectionからID3D11ShaderReflectionConstantBuffer、ID3D11ShaderReflectionVariableを取得して変数定義の詳細が得られる。


サンプルプログラム

エフェクトシステム作成 Part3 変数情報取得

“DX11エフェクトシステム作成 Part3 変数情報取得” をダウンロード dx11Effect2.zip – 409 回のダウンロード – 57 KB

今回作成した追加機能
シェーダ入力とリソースのスロット番号情報をパス情報に追加。単純な構造体の配列のみ。ID3D11ShaderReflectionで得られる情報を事前に取得しておく。

// シェーダ入力
struct ShaderInputDesc
{
    const Char* pSema; // セマンティクス
    Uint32 idxSema     // セマンティクスIndex
                       // TEXCOORD0←この数字
};

// シェーダリソース
struct ResourceDesc
{
    const Char* pName; // 名前
    Uint32 idxBind     // スロット番号
    Uint32 numBind;
    Uint32 idxDesc;    // サンプラ専用 定義index シェーダ内に定義
};

// シェーダ情報
struct ShaderDesc
{
    const void* pCode;
    Uint32 sizeCode;
    const ShaderInputDesc* aInput; // シェーダ入力配列
    Uint32 numInput;
    const ResourceDesc* aCBuffer;  // 定数バッファ配列
    Uint32 numCBuffer;
    const ResourceDesc* aTexture;  // テクスチャ配列
    Uint32 numTexture;
    const ResourceDesc* aSampler;  // サンプラ配列
    Uint32 numSampler;
};
サンプラ定義について
サンプラステートの定義を

// サンプラステート
SamplerState samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressV = CLAMP;
    AddressW = CLAMP;
};

のようできるので、サンプラの設定を行うように見えますがシェーダにそのような機能はありません。定義内容は無視されます。自分で指定されたスロット番号にID3D11SamplerStateを設定する必要があります。今回作成しているエフェクトシステムは、この定義内容を保持取得できるようにしています。その時の取得するための情報がResourceDesc::idxDesc。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

認証:数字を入力してください(必須) * Time limit is exhausted. Please reload CAPTCHA.