関数リンク グラフの構築とコンパイル済みコードへのリンク
ここでは、シェーダーの関数リンク グラフ (FLG) を構築する方法と、これらのシェーダーをシェーダー ライブラリとリンクして、Direct3D ランタイムで使用できるシェーダー BLOB を生成する方法について説明します。
目的: 関数リンク グラフを構築し、コンパイルされたコードにリンクするには。
前提条件
C++ に習熟していることを前提としています。 また、グラフィックス プログラミングの概念に対する基礎的な知識も必要となります。
シェーダー ライブラリのパッケージ化についても想定しています。
完了までの時間: 30 分。
Instructions
1. 頂点シェーダーの関数リンク グラフを作成します。
D3DCreateFunctionLinkingGraph 関数を呼び出して、頂点シェーダーを表す関数リンク グラフ (ID3D11FunctionLinkingGraph) を作成します。
頂点シェーダーの入力パラメーターを定義するには、 D3D11_PARAMETER_DESC 構造体の配列を使用します。 Input-Assembler ステージは、入力パラメーターを頂点シェーダーにフィードします。 頂点シェーダーの入力パラメーターのレイアウトは、コンパイルされたコード内の頂点シェーダーのレイアウトと一致します。 入力パラメーターを定義した後、 ID3D11FunctionLinkingGraph::SetInputSignature メソッドを呼び出して、頂点シェーダーの入力ノード (ID3D11LinkingNode) を定義します。
ComPtr<ID3D11FunctionLinkingGraph> vertexShaderGraph;
DX::ThrowIfFailed(D3DCreateFunctionLinkingGraph(0, &vertexShaderGraph));
// Define the main input node which will be fed by the Input Assembler pipeline stage.
static const D3D11_PARAMETER_DESC vertexShaderInputParameters[] =
{
{"inputPos", "POSITION0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 3, D3D_INTERPOLATION_LINEAR, D3D_PF_IN, 0, 0, 0, 0},
{"inputTex", "TEXCOORD0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 2, D3D_INTERPOLATION_LINEAR, D3D_PF_IN, 0, 0, 0, 0},
{"inputNorm", "NORMAL0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 3, D3D_INTERPOLATION_LINEAR, D3D_PF_IN, 0, 0, 0, 0}
};
ComPtr<ID3D11LinkingNode> vertexShaderInputNode;
LinkingThrowIfFailed(vertexShaderGraph->SetInputSignature(vertexShaderInputParameters, ARRAYSIZE(vertexShaderInputParameters),
&vertexShaderInputNode), vertexShaderGraph.Get());
ID3D11FunctionLinkingGraph::CallFunction メソッドを呼び出して、メイン頂点シェーダー関数のノードを作成し、ID3D11FunctionLinkingGraph::P assValue を呼び出して、入力ノードからメイン頂点シェーダー関数のノードに値を渡します。
// Create a node for the main VertexFunction call using the output of the helper functions.
ComPtr<ID3D11LinkingNode> vertexFunctionCallNode;
LinkingThrowIfFailed(vertexShaderGraph->CallFunction("", shaderLibrary.Get(), "VertexFunction", &vertexFunctionCallNode),
vertexShaderGraph.Get());
// Define the graph edges from the input node and helper function nodes.
LinkingThrowIfFailed(vertexShaderGraph->PassValue(homogenizeCallNodeForPos.Get(), D3D_RETURN_PARAMETER_INDEX,
vertexFunctionCallNode.Get(), 0), vertexShaderGraph.Get());
LinkingThrowIfFailed(vertexShaderGraph->PassValue(vertexShaderInputNode.Get(), 1, vertexFunctionCallNode.Get(), 1),
vertexShaderGraph.Get());
LinkingThrowIfFailed(vertexShaderGraph->PassValue(homogenizeCallNodeForNorm.Get(), D3D_RETURN_PARAMETER_INDEX,
vertexFunctionCallNode.Get(), 2), vertexShaderGraph.Get());
頂点シェーダーの出力パラメーターを定義するには、 D3D11_PARAMETER_DESC 構造体の配列を使用します。 頂点シェーダーは、出力パラメーターをピクセル シェーダーにフィードします。 頂点シェーダーの出力パラメーターのレイアウトは、コンパイルされたコード内のピクセル シェーダーのレイアウトと一致します。 出力パラメーターを定義した後、 ID3D11FunctionLinkingGraph::SetOutputSignature メソッドを呼び出して、頂点シェーダーの出力ノード (ID3D11LinkingNode) を定義します。
// Define the main output node which will feed the Pixel Shader pipeline stage.
static const D3D11_PARAMETER_DESC vertexShaderOutputParameters[] =
{
{"outputTex", "TEXCOORD0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 2, D3D_INTERPOLATION_UNDEFINED, D3D_PF_OUT, 0, 0, 0, 0},
{"outputNorm", "NORMAL0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 3, D3D_INTERPOLATION_UNDEFINED, D3D_PF_OUT, 0, 0, 0, 0},
{"outputPos", "SV_POSITION", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 4, D3D_INTERPOLATION_UNDEFINED, D3D_PF_OUT, 0, 0, 0, 0}
};
ComPtr<ID3D11LinkingNode> vertexShaderOutputNode;
LinkingThrowIfFailed(vertexShaderGraph->SetOutputSignature(vertexShaderOutputParameters, ARRAYSIZE(vertexShaderOutputParameters),
&vertexShaderOutputNode), vertexShaderGraph.Get());
ID3D11FunctionLinkingGraph::P assValue を呼び出して、メイン頂点シェーダー関数のノードから出力ノードに値を渡します。
LinkingThrowIfFailed(vertexShaderGraph->PassValue(vertexFunctionCallNode.Get(), 0, vertexShaderOutputNode.Get(), 2),
vertexShaderGraph.Get());
LinkingThrowIfFailed(vertexShaderGraph->PassValue(vertexFunctionCallNode.Get(), 1, vertexShaderOutputNode.Get(), 0),
vertexShaderGraph.Get());
LinkingThrowIfFailed(vertexShaderGraph->PassValue(vertexFunctionCallNode.Get(), 2, vertexShaderOutputNode.Get(), 1),
vertexShaderGraph.Get());
ID3D11FunctionLinkingGraph::CreateModuleInstance メソッドを呼び出して、頂点シェーダー グラフを完成させます。
// Finalize the vertex shader graph.
ComPtr<ID3D11ModuleInstance> vertexShaderGraphInstance;
LinkingThrowIfFailed(vertexShaderGraph->CreateModuleInstance(&vertexShaderGraphInstance, nullptr), vertexShaderGraph.Get());
2. 頂点シェーダーをリンクする
D3DCreateLinker 関数を呼び出してリンカー (ID3D11Linker) を作成します。このリンカーを使用すると、「シェーダー ライブラリをパッケージ化する」で作成したシェーダー ライブラリのインスタンスを、前の手順で作成した頂点シェーダー グラフのインスタンスにリンクできます。 ID3D11Linker::UseLibrary メソッドを呼び出して、リンクに使用するシェーダー ライブラリを指定します。 ID3D11Linker::Link メソッドを呼び出して、シェーダー ライブラリを頂点シェーダー グラフにリンクし、コンパイルされた頂点シェーダー コードにアクセスするために使用できる ID3DBlob インターフェイスへのポインターを生成します。 次に、このコンパイル済みの頂点シェーダー コードを ID3D11Device::CreateVertexShader メソッドに渡して頂点シェーダー オブジェクトを作成し、 ID3D11Device::CreateInputLayout メソッドに渡して入力レイアウト オブジェクトを作成できます。
// Create a linker and hook up the module instance.
ComPtr<ID3D11Linker> linker;
DX::ThrowIfFailed(D3DCreateLinker(&linker));
DX::ThrowIfFailed(linker->UseLibrary(shaderLibraryInstance.Get()));
// Link the vertex shader.
ComPtr<ID3DBlob> errorBlob;
if (FAILED(linker->Link(vertexShaderGraphInstance.Get(), "main", ("vs" + m_shaderModelSuffix).c_str(), 0, &vertexShaderBlob,
&errorBlob)))
{
throw errorBlob;
}
ComPtr<ID3D11VertexShader> vertexShader;
DX::ThrowIfFailed(
device->CreateVertexShader(
vertexShaderBlob->GetBufferPointer(),
vertexShaderBlob->GetBufferSize(),
nullptr,
&vertexShader
)
);
context->VSSetShader(vertexShader.Get(), nullptr, 0);
D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
ComPtr<ID3D11InputLayout> inputLayout;
DX::ThrowIfFailed(device->CreateInputLayout(inputLayoutDesc, ARRAYSIZE(inputLayoutDesc), vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &inputLayout));
context->IASetInputLayout(inputLayout.Get());
3. ピクセル シェーダーの関数リンク グラフを作成します。
D3DCreateFunctionLinkingGraph 関数を呼び出して、ピクセル シェーダーを表す function-linking-graph (ID3D11FunctionLinkingGraph) を作成します。
ピクセル シェーダーの入力パラメーターを定義するには、 D3D11_PARAMETER_DESC 構造体の配列を使用します。 頂点シェーダー ステージは、入力パラメーターをピクセル シェーダーにフィードします。 ピクセル シェーダーの入力パラメーターのレイアウトは、コンパイルされたコード内のピクセル シェーダーのレイアウトと一致します。 入力パラメーターを定義した後、 ID3D11FunctionLinkingGraph::SetInputSignature メソッドを呼び出して、ピクセル シェーダーの入力ノード (ID3D11LinkingNode) を定義します。
ComPtr<ID3D11FunctionLinkingGraph> pixelShaderGraph;
DX::ThrowIfFailed(D3DCreateFunctionLinkingGraph(0, &pixelShaderGraph));
// Define the main input node which will be fed by the vertex shader pipeline stage.
static const D3D11_PARAMETER_DESC pixelShaderInputParameters[] =
{
{"inputTex", "TEXCOORD0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 2, D3D_INTERPOLATION_UNDEFINED, D3D_PF_IN, 0, 0, 0, 0},
{"inputNorm", "NORMAL0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 3, D3D_INTERPOLATION_UNDEFINED, D3D_PF_IN, 0, 0, 0, 0},
{"inputPos", "SV_POSITION", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 4, D3D_INTERPOLATION_UNDEFINED, D3D_PF_IN, 0, 0, 0, 0}
};
ComPtr<ID3D11LinkingNode> pixelShaderInputNode;
LinkingThrowIfFailed(pixelShaderGraph->SetInputSignature(pixelShaderInputParameters, ARRAYSIZE(pixelShaderInputParameters),
&pixelShaderInputNode), pixelShaderGraph.Get());
ID3D11FunctionLinkingGraph::CallFunction メソッドを呼び出して、メイン ピクセル シェーダー関数のノードを作成し、ID3D11FunctionLinkingGraph::P assValue を呼び出して、入力ノードから メイン ピクセル シェーダー関数のノードに値を渡します。
// Create a node for the main ColorFunction call and connect it to the pixel shader inputs.
ComPtr<ID3D11LinkingNode> colorValueNode;
LinkingThrowIfFailed(pixelShaderGraph->CallFunction("", shaderLibrary.Get(), "ColorFunction", &colorValueNode),
pixelShaderGraph.Get());
// Define the graph edges from the input node.
LinkingThrowIfFailed(pixelShaderGraph->PassValue(pixelShaderInputNode.Get(), 0, colorValueNode.Get(), 0),
pixelShaderGraph.Get());
LinkingThrowIfFailed(pixelShaderGraph->PassValue(pixelShaderInputNode.Get(), 1, colorValueNode.Get(), 1),
pixelShaderGraph.Get());
ピクセル シェーダーの出力パラメーターを定義するには、 D3D11_PARAMETER_DESC 構造体の配列を使用します。 ピクセル シェーダーは、出力パラメーターを Output-Merger ステージにフィードします。 出力パラメーターを定義した後、 ID3D11FunctionLinkingGraph::SetOutputSignature メソッドを呼び出してピクセル シェーダーの出力ノード (ID3D11LinkingNode) を定義し、 ID3D11FunctionLinkingGraph::P assValue を呼び出してピクセル シェーダー関数ノードから出力ノードに値を渡します。
// Define the main output node which will feed the Output Merger pipeline stage.
D3D11_PARAMETER_DESC pixelShaderOutputParameters[] =
{
{"outputColor", "SV_TARGET", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1, 4, D3D_INTERPOLATION_UNDEFINED, D3D_PF_OUT, 0, 0, 0, 0}
};
ComPtr<ID3D11LinkingNode> pixelShaderOutputNode;
LinkingThrowIfFailed(pixelShaderGraph->SetOutputSignature(pixelShaderOutputParameters, ARRAYSIZE(pixelShaderOutputParameters),
&pixelShaderOutputNode), pixelShaderGraph.Get());
LinkingThrowIfFailed(pixelShaderGraph->PassValue(fillAlphaCallNode.Get(), D3D_RETURN_PARAMETER_INDEX, pixelShaderOutputNode.Get(), 0),
pixelShaderGraph.Get());
ID3D11FunctionLinkingGraph::CreateModuleInstance メソッドを呼び出して、ピクセル シェーダー グラフを完成させます。
// Finalize the pixel shader graph.
ComPtr<ID3D11ModuleInstance> pixelShaderGraphInstance;
LinkingThrowIfFailed(pixelShaderGraph->CreateModuleInstance(&pixelShaderGraphInstance, nullptr), pixelShaderGraph.Get());
4. ピクセル シェーダーをリンクする
D3DCreateLinker 関数を呼び出してリンカー (ID3D11Linker) を作成します。このリンカーを使用すると、「シェーダー ライブラリのパッケージ化」で作成したシェーダー ライブラリのインスタンスを、前の手順で作成したピクセル シェーダー グラフのインスタンスにリンクできます。 ID3D11Linker::UseLibrary メソッドを呼び出して、リンクに使用するシェーダー ライブラリを指定します。 ID3D11Linker::Link メソッドを呼び出して、シェーダー ライブラリをピクセル シェーダー グラフにリンクし、コンパイルされたピクセル シェーダー コードにアクセスするために使用できる ID3DBlob インターフェイスへのポインターを生成します。 次に、このコンパイル済みピクセル シェーダー コードを ID3D11Device::CreatePixelShader メソッドに渡して、ピクセル シェーダー オブジェクトを作成できます。
// Create a linker and hook up the module instance.
ComPtr<ID3D11Linker> linker;
DX::ThrowIfFailed(D3DCreateLinker(&linker));
DX::ThrowIfFailed(linker->UseLibrary(shaderLibraryInstance.Get()));
// Link the pixel shader.
ComPtr<ID3DBlob> errorBlob;
if (FAILED(linker->Link(pixelShaderGraphInstance.Get(), "main", ("ps" + m_shaderModelSuffix).c_str(), 0, &pixelShaderBlob, &errorBlob)))
{
throw errorBlob;
}
ComPtr<ID3D11PixelShader> pixelShader;
DX::ThrowIfFailed(
device->CreatePixelShader(
pixelShaderBlob->GetBufferPointer(),
pixelShaderBlob->GetBufferSize(),
nullptr,
&pixelShader
)
);
context->PSSetShader(pixelShader.Get(), nullptr, 0);
まとめ
ID3D11FunctionLinkingGraph メソッドを使用して、頂点シェーダー グラフとピクセル シェーダー グラフを構築し、シェーダー構造をプログラムで指定しました。
これらのグラフ構造は、値を相互に渡すプリコンパイル済み関数呼び出しのシーケンスで構成されます。 FLG ノード (ID3D11LinkingNode) は、プリコンパイル済みライブラリ関数の入出力シェーダー ノードと呼び出しを表します。 関数呼び出しノードを登録する順序によって、呼び出しのシーケンスが定義されます。 最初に入力ノード (ID3D11FunctionLinkingGraph::SetInputSignature) と最後の出力ノード (ID3D11FunctionLinkingGraph::SetOutputSignature) を指定する必要があります。 FLG エッジは、あるノードから別のノードに値を渡す方法を定義します。 渡された値のデータ型は同じである必要があります。暗黙的な型変換はありません。 図形ルールとスウィズリング ルールは、HLSL の動作に従います。 値は、このシーケンスでのみ前方に渡すことができます。
また 、ID3D11Linker メソッドを使用して、シェーダー ライブラリをシェーダー グラフにリンクし、Direct3D ランタイムで使用するシェーダー BLOB を生成しました。
おめでとうございます。 これで、独自のアプリでシェーダー リンクを使用する準備ができました。
関連トピック