変数の構文

HLSL 変数を宣言するには、次の構文規則を使用します。

[Storage_Class][Type_Modifier] Type Name[Index] [: Semantic] [: Packoffset] [: Register];[注釈][= Initial_Value]

パラメーター

Storage_Class

変数スコープと有効期間に関するコンパイラ ヒントを提供するオプションのストレージ クラス修飾子。修飾子は任意の順序で指定できます。

説明
extern グローバル変数をシェーダーへの外部入力としてマークします。これは、すべてのグローバル変数の既定のマーキングです。 static と組み合わせることはできません。
nointerpolation 頂点シェーダーの出力をピクセル シェーダーに渡す前に補間しないでください。
正確 変数に適用される正確なキーワード (keyword)により、その変数に割り当てられた値を生成するために使用される計算は次のように制限されます。
  • 個別の操作は個別に保持されます。 たとえば、mul 操作と add 操作が狂った操作に融合されている可能性がある場合、 正確に 操作を強制的に分離します。 代わりに、mad 組み込み関数を明示的に使用する必要があります。
  • 操作の順序は維持されます。 パフォーマンスを向上させるために命令の順序がシャッフルされた可能性がある場合は、 正確に コンパイラが書き込まれた順序を保持します。
  • IEEE の安全でない操作は制限されています。 コンパイラが NaN (数値ではなく) と INF (無限) の値を考慮しない高速な算術演算を使用した可能性がある場合、 正確には 、NaN と INF 値に関する IEEE 要件が強制的に尊重されます。 正確でないと、これらの最適化と数学的演算は IEEE の安全ではありません。
  • 変数の 精度 を修飾しても、変数を使用する操作は 正確になりません。 precise、正確に修飾された変数に割り当てられた値に寄与する演算にのみ反映されるため、目的の計算を正確に行うことは難しい場合があるため、シェーダー出力を宣言する場所(構造体フィールド上にあるか、出力パラメーター上にあるか、エントリ関数の戻り値の型か)を直接正確にマークすることをお勧めします。 このように最適化を制御する機能は、累積精度差の違いによって最終的な結果に影響を与える可能性がある最適化を無効にすることで、変更された出力変数の結果の不変性を維持します。 テセレーション用のシェーダーで水密パッチの継ぎ目を維持したり、複数のパスに対して深度値を照合したりする場合に便利です。 サンプル コード:
    HLSLmatrix g_mWorldViewProjection;
    void メイン(float3 InPos : Position, out precise float4 OutPos : SV_Position)
    {
    操作は正確です。これは、正確なパラメーター OutPos に寄与するためです
    OutPos = mul( float4( InPos, 1.0 ), g_mWorldViewProjection );
    }
shared 効果間で共有する変数をマークします。これはコンパイラのヒントです。
groupshared コンピューティング シェーダーのスレッド グループ共有メモリの変数をマークします。 D3D10 では、グループ共有ストレージ クラスを持つすべての変数の最大合計サイズは 16 kb で、D3D11 では最大サイズは 32 kb です。 例を参照してください。
static ローカル変数を 1 回初期化し、関数呼び出し間で保持されるようにマークします。 宣言に初期化子が含まれていない場合、値は 0 に設定されます。 static とマークされたグローバル変数は、アプリケーションには表示されません。
uniform シェーダーの実行全体でデータが一定である変数 (頂点シェーダーのマテリアル カラーなど) をマークします。既定では、グローバル変数は 一様 と見なされます。
volatile 頻繁に変更される変数をマークします。これはコンパイラのヒントです。 このストレージ クラス修飾子は、ローカル変数にのみ適用されます。
メモ: HLSL コンパイラは現在、このストレージ クラス修飾子を無視しています。

Type_Modifier

オプションの variable-type 修飾子。

説明
const シェーダーで変更できない変数をマークするため、変数宣言で初期化する必要があります。 グローバル変数は既定で const と見なされます (コンパイラに /Gec フラグを指定することで、この動作を抑制します)。
row_major 1 つの行に 4 つのコンポーネントを格納する変数をマークして、1 つの定数レジスタに格納できるようにします。
column_major 行列演算を最適化するために、1 つの列に 4 つのコンポーネントを格納する変数をマークします。

注意

型修飾子の値を指定しない場合、コンパイラは既定値として column_major を使用します。

Type

データ型 (DirectX HLSL) に記載されている任意の HLSL 型

Name[Index]

シェーダー変数を一意に識別する ASCII 文字列。 省略可能な配列を定義するには、配列サイズに インデックス を使用します。これは正の整数 = 1 です。

セマンティック

オプションのパラメーター使用法情報。シェーダーの入力と出力をリンクするためにコンパイラによって使用されます。 頂点シェーダーとピクセル シェーダーには、いくつかの定義済みの セマンティクス があります。 コンパイラは、グローバル変数またはシェーダーに渡されるパラメーターで宣言されていない限り、セマンティクスを無視します。

Packoffset

シェーダー定数を手動でパッキングするためのオプションのキーワード (keyword)。 「packoffset (DirectX HLSL)」を参照してください。

登録

シェーダー変数を特定のレジスタに手動で割り当てる場合のオプションのキーワード (keyword)。 「register (DirectX HLSL)」を参照してください。

注釈

グローバル変数に添付された、文字列の形式の省略可能なメタデータ。 注釈は効果フレームワークによって使用され、HLSL では無視されます。構文の詳細については、 注釈構文に関するページを参照してください。

Initial_Value

省略可能な初期値。値の数は 、Type のコンポーネントの数と一致する必要があります。 extern とマークされた各グローバル変数は、リテラル値で初期化する必要があります。static とマークされた各変数は、定数で初期化する必要があります。

静的または extern とマークされていないグローバル変数は、シェーダーにコンパイルされません。 コンパイラはグローバル変数の既定値を自動的に設定せず、最適化で使用することはできません。 この種類のグローバル変数を初期化するには、リフレクションを使用してその値を取得し、その値を定数バッファーにコピーします。 たとえば、ID3D11ShaderReflection::GetVariableByName メソッドを使用して変数を取得し、ID3D11ShaderReflectionVariable::GetDesc メソッドを使用してシェーダー変数の説明を取得し、D3D11_SHADER_VARIABLE_DESC構造体の DefaultValue メンバーから初期値を取得できます。 値を定数バッファーにコピーするには、バッファーが CPU 書き込みアクセス (D3D11_CPU_ACCESS_WRITE) で作成されていることを確認する必要があります。 定数バッファーを作成する方法の詳細については、「 方法: 定数バッファーを作成する」を参照してください。

効果フレームワークを使用して、初期値の反映と設定を自動的に処理することもできます。 たとえば、 ID3DX11EffectPass::Apply メソッドを使用できます。

シェーダー変数宣言の例をいくつか次に示します。

float fVar;
float4 color;
float fVar = 3.1f;

int iVar[3];

int iVar[3] = {1,2,3};

uniform float4 position : SV_POSITION; 
const float4 lightDirection = {0,0,1};
      

グループ共有

HLSL を使用すると、コンピューティング シェーダーのスレッドは共有メモリを介して値を交換できます。 HLSL は GroupMemoryBarrierWithGroupSync などのバリア プリミティブを提供し、シェーダー内の共有メモリへの読み取りと書き込みの正しい順序を確保し、データ競合を回避します。

注意

ハードウェアはグループ内のスレッド (反りまたはウェーブフロント) を実行します。また、同じグループに属するスレッドの同期のみが正しい場合は、バリア同期を省略してパフォーマンスを向上させることができます。 ただし、次の理由により、この省略は強くお勧めしません。

  • この省略により、移植不可能なコードが発生します。これは一部のハードウェアでは機能しない可能性があり、通常は小さなグループでスレッドを実行するソフトウェア ラスタライザーでは機能しません。
  • この省略によって実現できるパフォーマンスの向上は、すべてのスレッド バリアの使用と比較して軽微です。

Direct3D 10 では、 グループ共有への書き込み時にスレッドの同期がないため、各スレッドは書き込み用の配列内の 1 つの場所に制限されます。 SV_GroupIndexシステム値を使用して、2 つのスレッドが競合しないように書き込むときにこの配列にインデックスを作成します。 読み取りでは、すべてのスレッドが読み取り用の配列全体にアクセスできます。

struct GSData
{
    float4 Color;
    float Factor;
}

groupshared GSData data[5*5*1];

[numthreads(5,5,1)]
void main( uint index : SV_GroupIndex )
{
    data[index].Color = (float4)0;
    data[index].Factor = 2.0f;
    GroupMemoryBarrierWithGroupSync();
    ...
}

梱包

レジスタ境界を越えるのを防ぐのに十分な大きさのベクターとスカラーのサブコンポーネントをパックします。 たとえば、これらはすべて有効です。

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

梱包タイプを混在させることはできません。

レジスタ キーワード (keyword)と同様に、packoffset はターゲット固有にすることができます。 サブコンポーネントパッキングは packoffset キーワード (keyword)でのみ使用でき、レジスタ キーワード (keyword)では使用できません。 cbuffer 宣言内では、Direct3D 10 ターゲットのレジスタ キーワード (keyword)は無視されます。これは、クロスプラットフォームの互換性を確保するためです。

パックされた要素が重複する可能性があり、コンパイラはエラーや警告を表示しません。 この例では、Element2 と Element3 が Element1.x および Element1.y と重なります。

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

packoffset を使用するサンプルは、 HLSLWithoutFX10 サンプルです

変数 (DirectX HLSL)