次の方法で共有


関数リンク グラフの構築とコンパイル済みコードへのリンク

ここでは、シェーダーの関数リンク グラフ (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());

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());

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 を生成しました。

おめでとうございます。 これで、独自のアプリでシェーダー リンクを使用する準備ができました。

シェーダー リンクの使用