効果シェーダーのリンク設定

Direct2D では、複数のエフェクト グラフ レンダリング パスを 1 つのパスに結合する、効果シェーダー リンクと呼ばれる最適化が使用されます。

効果シェーダーのリンクの概要

エフェクト シェーダー のリンクの最適化は、HLSL シェーダー リンクの上に構築されます。Direct3D 11.2 機能では、事前コンパイル済みのシェーダー関数をリンクすることで、ピクセルシェーダーと頂点シェーダーを実行時に生成できます。 次の図は、効果グラフでの効果シェーダー のリンクの概念を示しています。 最初の図は、4 つのレンダリング変換を含む一般的な Direct2D 効果グラフを示しています。 シェーダー リンクを使用しない場合、各変換はレンダリング パスを使用し、中間サーフェスを必要とします。合計で、このグラフには 4 つのパスと 3 つの中間が必要です。

シェーダー リンクなしでグラフを変換する: 4 つのパスと 3 つの中間。

2 番目の図は、各レンダリング変換がリンク可能な関数バージョンに置き換えられたのと同じ効果グラフを示しています。 Direct2D は、グラフ全体をリンクし、中間者を必要とせずに 1 回のパスで実行できます。 これにより、GPU の実行時間が大幅に短縮され、GPU メモリのピーク消費量が減少する可能性があります。

シェーダー リンク付きの変換グラフ: 1 パス、0 中間。

 

エフェクト シェーダーのリンクは、エフェクト内の個々の変換に対して動作します。つまり、1 つの効果を持つグラフでも、その効果に複数の有効な変換がある場合は、シェーダー リンクの恩恵を受ける可能性があります。

効果シェーダーのリンクの使用

効果を使用する Direct2D アプリケーションを構築する場合は、効果シェーダーのリンクを利用するために何もする必要はありません。 Direct2D は効果グラフを自動的に分析して、各変換をリンクする最適な方法を決定します。

効果作成者は、効果シェーダーのリンクをサポートする方法で効果を実装する責任があります。詳細については、以下の 「シェーダー のリンクと互換性のあるカスタム効果の作成 」セクションを参照してください。 すべての組み込み効果では、シェーダー のリンクがサポートされています。

Direct2D では、隣接するレンダリング変換が有益な状況でのみリンクされます。 2 つの変換をリンクするかどうかを決定する際には、複数の要因が考慮されます。 たとえば、ピクセル シェーダーのみをリンクできるため、いずれかの変換で頂点シェーダーまたはコンピューティング シェーダーが使用されている場合、シェーダーのリンクは実行されません。 また、シェーダー リンクと互換性のある効果が作成されていない場合、周囲の変換はリンクされません。

このようなリンクの危険性が存在する場合、Direct2D は危険に隣接する変換をリンクしませんが、グラフの残りの部分をリンクしようとします。

リンクの危険性を持つ変換グラフ:2パス、1中間。

シェーダー のリンクと互換性のあるカスタム効果の作成

独自のカスタム Direct2D 効果を作成する場合は、その変換で効果シェーダーのリンクがサポートされていることを確認する必要があります。 これには、以前のカスタム効果の実装方法から若干の変更が必要です。 カスタム効果内の変換でシェーダー リンクがサポートされていない場合、Direct2D はエフェクト グラフ内のそれに隣接する変換とリンクしません。

カスタム効果作成者は、いくつかの主要な概念と要件に注意する必要があります。

  • エフェクト インターフェイスの実装に変更はありません

    ID2D1DrawTransform などのさまざまな効果インターフェイスを実装するコードを変更する必要はありません。

  • シェーダーの完全な関数バージョンとエクスポート関数バージョンの両方を提供する

    Direct2D でリンク可能なエフェクトのシェーダーのエクスポート関数バージョンを指定する必要があります。 さらに、元の完全なシェーダーも引き続き提供する必要があります。これは、グラフ内の特定のリンクにシェーダー リンクを適用するかどうかに応じて、Direct2D が実行時に適切なシェーダー バージョンを選択するためです。

    変換でフル ピクセル シェーダー BLOB のみが提供される場合 ( ID2D1EffectContext::LoadPixelShader 経由)、隣接する変換にはリンクされません。

  • ヘルパー関数

    Direct2D には 、HLSL ヘルパー関数 と、シェーダーの完全な関数バージョンとエクスポート関数バージョンの両方が自動的に生成されるマクロが用意されています。 これらのヘルパーは d2d1effecthelpers.hlsli にあります。 さらに、HLSL コンパイラ (FXC) を使用すると、エクスポート関数シェーダーを完全なシェーダーのプライベート フィールドに挿入できます。 この方法では、シェーダーを 1 回だけ作成し、両方のバージョンを同時に Direct2D に渡す必要があります。 d2d1effecthelpers.hlsli と FXC コンパイラの両方が Windows SDK の一部として含まれています。

    ヘルパー関数:

    また、以下の 「エクスポート関数の仕様 」で説明されている仕様が満たされている限り、各シェーダーの 2 つのバージョンを手動で作成し、2 回コンパイルすることもできます。

  • ピクセル シェーダーのみ

    Direct2D では、コンピューティング シェーダーまたは頂点シェーダーのリンクはサポートされていません。 ただし、効果で頂点シェーダーとピクセル シェーダーの両方を使用している場合でも、ピクセル シェーダーの出力はリンクできます。

  • 単純サンプリングと複雑なサンプリング

    シェーダー関数のリンクは、1 つのピクセル シェーダー パスの出力を後続のピクセル シェーダー パスの入力に接続することによって機能します。 これは、消費するピクセル シェーダーが計算を実行するために 1 つの入力値のみを必要とする場合にのみ可能です。この値は通常、頂点シェーダーによって出力されるテクスチャ座標で入力テクスチャをサンプリングすることによって取得されます。 このようなピクセル シェーダーは、単純なサンプリングを実行すると言います。

    グレースケール変換は、単純なサンプリングの例です。特定の出力ピクセルの値は、対応する入力ピクセルの値にのみ依存します。

    ガウス ぼかしなどの一部のピクセル シェーダーは、単一のサンプルではなく、複数の入力サンプルからの出力を計算します。 このようなピクセル シェーダーは、複雑なサンプリングを実行すると言います。

    ガウスぼかしは、複雑なサンプリングの例です。中央出力ピクセルの値は、複数の入力ピクセルに依存します。

    単純な入力を持つシェーダー関数のみが、別のシェーダー関数によって入力を提供できます。 複雑な入力を含むシェーダー関数には、サンプリングする入力テクスチャを指定する必要があります。 つまり、Direct2D は複雑な入力を持つシェーダーを先行タスクにリンクしません。

    Direct2D HLSL ヘルパーを使用する場合は、シェーダーで複合入力と単純入力のどちらを使用するかを HLSL で指定する必要があります。

リンク互換効果シェーダーの例

D2D ヘルパーを使用して、次のコード スニペットは、単純なリンクと互換性のある効果シェーダーを表します。

#define D2D_INPUT_COUNT 1
#define D2D_INPUT0_SIMPLE
#include “d2d1effecthelpers.hlsli”

D2D_PS_ENTRY(LinkingCompatiblePixelShader)
{
    float4 input = D2DGetInput(0);
    input.rgb *= input.a;
    return input;
}          

この短い例では、関数パラメーターが宣言されていないこと、各入力の入力数と型がエントリ関数の前に宣言されていること、 D2DGetInput を呼び出すことによって入力が取得されること、ヘルパー ファイルが含まれる前にプリプロセッサ ディレクティブを定義する必要があることに注意してください。

リンク互換シェーダーは、通常のシングルパス ピクセル シェーダーとエクスポート シェーダー関数の両方を提供する必要があります。 D2D_PS_ENTRY マクロを使用すると、シェーダー コンパイル スクリプトと組み合わせて使用すると、これらの各コードを同じコードから生成できます。

完全なシェーダーをコンパイルすると、マクロは次のコードに展開されます。このコードには D2D 効果互換の入力シグネチャがあります。

Texture2D<float4> InputTexture0;
SamplerState InputSampler0;

float4 LinkingCompatiblePixelShader(
    float4 pos   : SV_POSITION,
    float4 posScene : SCENE_POSITION,
    float4 uv0  : TEXCOORD0
    ) : SV_Target
    {
        float4 input = InputTexture0.Sample(InputSampler0, uv0.xy);
        input.rgb *= input.a;
        return input;
    }    

同じコードのエクスポート関数バージョンをコンパイルすると、次のコードが生成されます。

// Shader function version
export float4 LinkingCompatiblePixelShader_Function(
    float4 input0 : INPUT0)
    {
        input.rgb *= input.a;
        return input;
    }      

テクスチャ入力は、通常は Texture2D のサンプリングによって取得され、関数入力 (input0) に置き換えられていることに注意してください。

リンクと互換性のある効果を記述するために必要な操作の詳細な説明については、 カスタム効果のチュートリアルDirect2D カスタム画像効果のサンプルを参照してください。

互換性のあるシェーダーのリンクをコンパイルする

リンク可能にするには、D2D に渡されるピクセル シェーダー BLOB に、シェーダーの完全な関数バージョンとエクスポート関数バージョンの両方が含まれている必要があります。 これは、コンパイルされたエクスポート関数をD3D_BLOB_PRIVATE_DATA領域に埋め込むことで実現されます。

シェーダーが D2D ヘルパー関数を使用して作成される場合は、コンパイル時に D2D コンパイル ターゲットを定義する必要があります。 コンパイルターゲットの型はD2D_FULL_SHADERされ、D2D_FUNCTIONされます。

リンクと互換性のあるエフェクト シェーダーのコンパイルは、次の 2 つの手順で行います。

注意

Visual Studio を使用して効果をコンパイルする場合は、FXC コマンドの両方を実行するバッチ ファイルを作成し、コンパイル ステップの前に実行されるカスタム ビルド ステップとしてこのバッチ ファイルを実行する必要があります。

 

手順 1: エクスポート関数をコンパイルする

fxc /T <shadermodel> <MyShaderFile>.hlsl /D D2D_FUNCTION /D D2D_ENTRY=<entry> /Fl <MyShaderFile>.fxlib           

シェーダーのエクスポート関数バージョンをコンパイルするには、次のフラグを FXC に渡す必要があります。

フラグ 説明
/T <ShaderModel> [FXC 構文] で定義されている適切なピクセル シェーダー プロファイルに ShaderModel> を設定<します。 これは、"HLSL シェーダー リンク" の下に一覧表示されているプロファイルのいずれかである必要があります。
<MyShaderFile.hlsl> MyShaderFile> を HLSL ファイルの名前に設定<します。
/D D2D_FUNCTION この定義は、シェーダーのエクスポート関数バージョンをコンパイルするように FXC に指示します。
/D D2D_ENTRY=<entry> entry> を、D2D_PS_ENTRY マクロ内で定義した HLSL エントリ ポイントの名前設定<します。
/Fl <MyShaderFile.fxlib> MyShaderfile> を、シェーダーのエクスポート関数バージョンを格納する場所に設定<します。 .fxlib 拡張機能は、識別を容易にするためだけであることに注意してください。

手順 2: 完全なシェーダーをコンパイルし、エクスポート関数を埋め込む

fxc /T ps_<shadermodel> <MyShaderFile>.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=<entry> /E <entry> /setprivate <MyShaderFile>.fxlib /Fo <MyShader>.cso /Fh <MyShader>.h           

エクスポート バージョンが埋め込まれたシェーダーの完全なバージョンをコンパイルするには、次のフラグを FXC に渡す必要があります。

フラグ 説明
/T <ShaderModel> [FXC 構文] で定義されている適切なピクセル シェーダー プロファイルに ShaderModel> を設定<します。 これは、手順 1 で指定したリンク プロファイルに対応するピクセル シェーダー プロファイルである必要があります。
<MyShaderFile.hlsl> MyShaderFile> を HLSL ファイルの名前に設定<します。
/D D2D_FULL_SHADER この定義は、シェーダーの完全なバージョンをコンパイルするように FXC に指示します。
/D D2D_ENTRY=<entry> entry> を、D2D_PS_ENTRY() マクロ内で定義した HLSL エントリ ポイントの名前に設定<します。
/E <エントリ> entry> を、D2D_PS_ENTRY() マクロ内で定義した HLSL エントリ ポイントの名前に設定<します。
/setprivate <MyShaderFile.fxlib> この引数は、手順 1 で生成されたエクスポート関数シェーダーをD3D_BLOB_PRIVATE_DATA領域に埋め込むよう FXC に指示します。
/Fo <MyShader.cso> MyShader> を、コンパイル済みの最終的な組み合わせシェーダーを格納する場所に設定<します。
/Fh <MyShader.h> MyShader> を、最終的な結合ヘッダーを格納する場所に設定<します。

エクスポート関数の仕様

D2D で提供されるヘルパーを使用せずに互換性のあるエフェクト シェーダーを作成することは可能ですが、推奨されません。 完全なシェーダーとエクスポート関数の入力シグネチャの両方が D2D 仕様に準拠するように注意する必要があります。

完全シェーダーの仕様は、以前のバージョンの Windows と同じです。 簡単に言うと、ピクセル シェーダーの入力パラメーターは、エフェクト入力ごとにSV_POSITION、SCENE_POSITION、1 つの TEXCOORD である必要があります。

エクスポート関数の場合、関数は float4 を返す必要があり、その入力は次のいずれかの型である必要があります。

  • 単純な入力

    float4 d2d_inputN : INPUTN         
    

    単純な入力の場合、D2D は入力テクスチャとシェーダー関数の間に Sample 関数を挿入するか、別のシェーダー関数の出力によって入力が提供されます。

  • 複雑な入力

    float4 d2d_uvN  : TEXCOORDN                
    

    複雑な入力の場合、D2D は、Windows 8ドキュメントで説明されているようにテクスチャ座標のみを渡します。

  • Output location (出力場所)

    float4 d2d_posScene : SCENE_POSITION                
    

    定義できるSCENE_POSITION入力は 1 つだけです。 このパラメーターは、リンクされたシェーダーごとに 1 つの関数しか使用できないので、必要な場合にのみ含める必要があります。

D2D はセマンティクスを検査して関数をリンクする方法を決定するため、セマンティクスは上記のように定義する必要があります。 いずれかの関数入力が上記のいずれかの型と一致しない場合、関数はシェーダー リンクのために拒否されます。

HLSL ヘルパー

ID3D11Linker インターフェイス

ID3D11FunctionLinkingGraph インターフェイス