シェーダー定数 (DirectX HLSL)

シェーダー モデル 4 では、シェーダー定数はメモリー内の 1 つまたは複数のバッファー リソースに格納されます。シェーダー定数は、定数バッファー (cbuffer) とテクスチャ バッファー (tbuffer) の 2 種類のバッファーに整理できます。定数バッファーは定数変数で使用するために最適化されていて、CPU からのアクセスでの遅延が少なく、頻繁に更新されるという特徴があります。このため、これらのリソースのサイズ、レイアウトおよびアクセスには制限が追加されます。テクスチャー バッファーは、テクスチャーのようにアクセスされ、任意にインデックス化されたデータに対するパフォーマンスが優れています。使用するリソースの種類に関係なく、アプリケーションが作成できる定数バッファーまたはテクスチャー バッファーの数に制限はありません。

定数バッファーまたはテクスチャー バッファーの宣言は、C での構造体の宣言に非常に似ています。register および packoffset の 2 つのキーワードが、レジスタ データまたはパッキング データを手動で割り当てるために追加されています。

BufferType [Name] [: register(b#)]

{

    VariableDeclaration [: packoffset(c#.xyzw)];

     ...

};

パラメーター

  • BufferType
    [in] バッファーのタイプ。

    バッファーのタイプ 説明
    cbuffer 定数バッファー
    tbuffer テクスチャー バッファー
  • Name
    [in] 一意のバッファー名を含む ASCII 文字列 (省略可能)。

  • register (b#)
    [in] 定数データを手動でパッキングするためのキーワード (省略可能)。定数バッファーでのみレジスタの中で定数をパックできます。開始レジスタは、レジスタ番号 (#) で指定します。

  • VariableDeclaration
    [in] 変数宣言。構造体メンバー宣言に似ています。HLSL 型またはエフェクト オブジェクトのいずれでも指定できます (テクスチャーまたはサンプラ オブジェクトを除く)。

  • packoffset(c#.xyzw)
    [in] 定数データを手動でパッキングするためのキーワード (省略可能)。任意の定数バッファーの中で定数をパックできます。レジスタ番号は (#) で指定します。xyzw スィズルを使用したサブコンポーネントのパッキングは、単一レジスタに格納可能な (レジスタ境界を越えない) サイズの定数で利用可能です。たとえば、float4 は、y 成分で始まる単一レジスタにパックすることはできません。それは、4 成分レジスタに格納できないためです。

解説 

定数バッファーを使用すると、複数のシェーダー定数をまとめて同時にコミットできます。それぞれのシェーダー定数を個別の呼び出しで別々にコミットすることがないので、シェーダー定数の更新に必要な帯域を少なくすることができます。

定数バッファーは、バッファーのようにアクセスできる特殊なバッファー リソースです。各定数バッファーには、最大 4096 のベクトルを設定でき、各ベクトルには最大 4 つの 32 ビット値を指定できます。パイプライン ステージごとに最大で 14 個の定数バッファーをバインドできます (2 つのスロットが内部用に別途予約されています)。

テクスチャー バッファーは、テクスチャーのようにアクセスできる特殊なバッファー リソースです。テクスチャー アクセスは (バッファー アクセスと比較して)、任意にインデックス化されたデータに対するパフォーマンスが優れています。パイプライン ステージごとに最大で 128 個のテクスチャー バッファーをバインドできます。

バッファー リソースは、シェーダー定数の設定時のオーバーヘッドを最小化するために設計されています。定数バッファーとテクスチャー バッファーの更新はエフェクト フレームワーク (「ID3D10Effect インターフェイス」を参照) で管理されていますが、Direct3D API を使用してバッファーを更新することもできます (「リソース データのコピーとアクセス (Direct3D 10)」を参照)。アプリケーションは、別のバッファー (たとえば、レンダー ターゲットまたはストリーム出力ターゲット) から定数バッファーにデータをコピーすることもできます。

D3D10 アプリケーションで定数バッファーを使用する方法の詳細については、「リソース タイプ (Direct3D 10)」および「バッファー リソースの作成 (Direct3D 10)」を参照してください。

D3D11 アプリケーションで定数バッファーを使用する方法の詳細については、「Direct3D 11 のバッファーの概要」および「方法: 定数バッファーの作成」を参照してください。

定数バッファーをパイプラインにバインドするうえで、ビューは不要です。しかし、テクスチャー バッファーはビューを必要とし、テクスチャー スロットにバインドする必要があります (またはエフェクトの使用時に SetTextureBuffer を使用してバインドする必要があります)。

定数データをパックするには、register (DirectX HLSL) または packoffset (DirectX HLSL) のいずれかのキーワードを使用します。

Direct3D 9 と Direct3D 10/11 の違い

Direct3D 9 でサポートされていた定数の自動割り当てでは、パッキングは実行されず、代わりに各変数を float4 レジスタのセットに割り当てていましたが、Direct3D 10 および Direct3D 11 では HLSL 定数変数はパッキング規則に従っています。

定数バッファーの編成

定数バッファーを使用すると、複数のシェーダー定数をまとめて同時にコミットできます。それぞれのシェーダー定数を個別の呼び出しで別々にコミットすることがないので、シェーダー定数の更新に必要な帯域を少なくすることができます。

定数バッファーを効率的に使用する最も良い方法は、それらの更新頻度に基づいて、シェーダー変数を定数バッファーに編成することです。これにより、アプリケーションにおいて、シェーダー定数の更新に必要な帯域幅を最小限に抑えることができます。たとえば、シェーダーで 2 つの定数バッファーを宣言し、それぞれのバッファーにあるデータをその更新頻度に基づいて分類し、整理します。オブジェクト単位の更新を必要とするデータ (ワールド行列など) は、オブジェクト別に更新できる定数バッファーにグループ化します。これにより、1 つのシーンを記述する、更新頻度が非常に低いと考えられるデータから分離されます。

 cbuffer myObject {            float4x4 matWorld;     float3   vObjectPosition;     int      arrayIndex; }   cbuffer myScene {     float3   vSunPosition;     float4x4 matView; }         

既定の定数バッファー

既定の定数バッファーには、$Global および $Param の 2 つがあります。グローバル スコープに配置した変数は、cbuffer の場合と同じパッキング方法を使用して $Global cbuffer に暗黙的に追加されます。エフェクト フレームワークの外部でシェーダーをコンパイルする場合は、関数のパラメーター リストにある均一パラメーターが $Param 定数バッファーに配置されます。エフェクト フレームワークの範囲でコンパイルする場合、すべての均一パラメーターはグローバル スコープで定義した変数に解決される必要があります。

次の例は、「Skinning10 サンプル」にあるもので、行列の配列で構成したテクスチャー バッファーです。

 tbuffer tbAnimMatrices {     matrix g_mTexBoneWorld[MAX_BONE_MATRICES]; };       

次の宣言例では、定数バッファーを特定のレジスタから開始するように手動で割り当てると共に、サブコンポーネントを指定して特定の要素をパックします。

 cbuffer MyBuffer : register(b3) {     float4 Element1 : packoffset(c0);     float1 Element2 : packoffset(c1);     float1 Element3 : packoffset(c1.y); }       

関連項目

シェーダー モデル 4