建構函式連結圖形並將其連結至已編譯的程式碼

在這裡,我們將示範如何建構著色器的 function-linking-graphs (FLG) ,以及如何將這些著色器連結至著色器程式庫,以產生 Direct3D 執行時間可以使用的著色器 Blob。

目的: 建構 function-linking-graph,並將其連結至已編譯的程式碼。

必要條件

我們假設您熟悉 C++。 您還需要圖形程式設計概念的基本經驗。

我們也假設您已完成 封裝著色器程式庫

完成時間: 30 分鐘。

指示

1.建構頂點著色器的函式連結圖形。

呼叫 D3DCreateFunctionLinkingGraph 函式,以建立 function-linking-graph (ID3D11FunctionLinkingGraph) 來代表頂點著色器。

使用 D3D11_PARAMETER_DESC 結構的陣列來定義頂點著色器的輸入參數。 輸入組合器階段會將輸入參數饋送至頂點著色器。 頂點著色器的輸入參數配置符合已編譯器代碼中頂點著色器的版面配置。 定義輸入參數之後,請呼叫 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 結構的陣列來定義圖元著色器的輸出參數。 圖元著色器會將其輸出參數饋送至 輸出合併階段。 定義輸出參數之後,請呼叫 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。

恭喜! 您現在已準備好在自己的應用程式中使用著色器連結。

使用著色器連結