Freigeben über


Erstellen eines Funktionsverknüpfungsdiagramms und Verknüpfen mit kompiliertem Code

Hier zeigen wir Ihnen, wie Sie FlGs (Function-Linking-Graphs) für Shader erstellen und diese Shader mit einer Shaderbibliothek verknüpfen, um Shaderblobs zu erzeugen, die die Direct3D-Runtime verwenden kann.

Ziel: Erstellen eines Funktionsverknüpfungsdiagramms und Verknüpfen mit kompiliertem Code.

Voraussetzungen

Es wird davon ausgegangen, dass Sie mit C+ vertraut sind. Sie müssen außerdem mit den grundlegenden Konzepten der Grafikprogrammierung vertraut sein.

Wir gehen auch davon aus, dass Sie das Verpacken einer Shaderbibliothek durchlaufen haben.

Dauer: 30 Minuten.

Anweisungen

1. Erstellen Sie einen Funktionsverknüpfungsgraphen für den Vertex-Shader.

Rufen Sie die D3DCreateFunctionLinkingGraph-Funktion auf, um einen Funktionsverknüpfungsgraph (ID3D11FunctionLinkingGraph) zu erstellen, der den Vertexshader darstellt.

Verwenden Sie ein Array von D3D11_PARAMETER_DESC Strukturen, um die Eingabeparameter für den Vertexshader zu definieren. Die Input-Assembler Stage speist die Eingabeparameter an den Vertexshader ein. Das Layout der Eingabeparameter des Vertexshaders stimmt mit dem Layout des Vertexshaders im kompilierten Code überein. Nachdem Sie die Eingabeparameter definiert haben, rufen Sie die ID3D11FunctionLinkingGraph::SetInputSignature-Methode auf, um den Eingabeknoten (ID3D11LinkingNode) für den Vertexshader zu definieren.

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

Rufen Sie die ID3D11FunctionLinkingGraph::CallFunction-Methode auf, um einen Knoten für die Standard Vertexshaderfunktion zu erstellen, und rufen Sie ID3D11FunctionLinkingGraph::P assValue auf, um Werte vom Eingabeknoten an den Knoten für die Standard Vertexshaderfunktion zu übergeben.

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

Verwenden Sie ein Array von D3D11_PARAMETER_DESC Strukturen, um die Ausgabeparameter für den Vertexshader zu definieren. Der Vertex-Shader speist seine Ausgabeparameter an den Pixelshader ein. Das Layout der Ausgabeparameter des Vertexshaders stimmt mit dem Layout des Pixelshaders im kompilierten Code überein. Nachdem Sie die Ausgabeparameter definiert haben, rufen Sie die ID3D11FunctionLinkingGraph::SetOutputSignature-Methode auf, um den Ausgabeknoten (ID3D11LinkingNode) für den Vertexshader zu definieren.

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

Führen Sie Aufrufe von ID3D11FunctionLinkingGraph::P assValue durch, um Werte vom Knoten für die Standard Vertexshaderfunktion an den Ausgabeknoten zu übergeben.

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

Rufen Sie die ID3D11FunctionLinkingGraph::CreateModuleInstance-Methode auf, um das Vertexshaderdiagramm abzuschließen.

            // Finalize the vertex shader graph.
            ComPtr<ID3D11ModuleInstance> vertexShaderGraphInstance;
            LinkingThrowIfFailed(vertexShaderGraph->CreateModuleInstance(&vertexShaderGraphInstance, nullptr), vertexShaderGraph.Get());

Rufen Sie die Funktion D3DCreateLinker auf, um einen Linker (ID3D11Linker) zu erstellen, mit dem Sie die instance der Shaderbibliothek verknüpfen können, die Sie unter Verpacken einer Shaderbibliothek erstellt haben, mit dem instance des Vertexshaderdiagramms, das Sie im vorherigen Schritt erstellt haben. Rufen Sie die ID3D11Linker::UseLibrary-Methode auf, um die Shaderbibliothek anzugeben, die für die Verknüpfung verwendet werden soll. Rufen Sie die ID3D11Linker::Link-Methode auf, um die Shaderbibliothek mit dem Vertexshaderdiagramm zu verknüpfen und einen Zeiger auf die ID3DBlob-Schnittstelle zu erzeugen, mit der Sie auf den kompilierten Vertexshadercode zugreifen können. Anschließend können Sie diesen kompilierten Vertexshadercode an die ID3D11Device::CreateVertexShader-Methode übergeben, um das Vertex-Shaderobjekt zu erstellen, und an die ID3D11Device::CreateInputLayout-Methode , um das input-layout-Objekt zu erstellen.

            // 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. Erstellen Sie ein Funktionsverknüpfungsdiagramm für den Pixelshader.

Rufen Sie die Funktion D3DCreateFunctionLinkingGraph auf, um ein Funktionsverknüpfungsdiagramm (ID3D11FunctionLinkingGraph) zu erstellen, das den Pixelshader darstellt.

Verwenden Sie ein Array von D3D11_PARAMETER_DESC Strukturen, um die Eingabeparameter für den Pixelshader zu definieren. Die Vertexshaderphase leitet die Eingabeparameter an den Pixelshader. Das Layout der Eingabeparameter des Pixelshaders stimmt mit dem Layout des Pixelshaders im kompilierten Code überein. Nachdem Sie die Eingabeparameter definiert haben, rufen Sie die ID3D11FunctionLinkingGraph::SetInputSignature-Methode auf, um den Eingabeknoten (ID3D11LinkingNode) für den Pixelshader zu definieren.

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

Rufen Sie die ID3D11FunctionLinkingGraph::CallFunction-Methode auf, um einen Knoten für die Standard Pixelshaderfunktion zu erstellen, und rufen Sie ID3D11FunctionLinkingGraph::P assValue auf, um Werte vom Eingabeknoten an den Knoten für die Standard Pixelshaderfunktion zu übergeben.

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

Verwenden Sie ein Array von D3D11_PARAMETER_DESC Strukturen, um die Ausgabeparameter für den Pixelshader zu definieren. Der Pixelshader speist seine Ausgabeparameter in die Output-Merger-Phase ein. Nachdem Sie die Ausgabeparameter definiert haben, rufen Sie die ID3D11FunctionLinkingGraph::SetOutputSignature-Methode auf, um den Ausgabeknoten (ID3D11LinkingNode) für den Pixelshader zu definieren, und rufen Sie ID3D11FunctionLinkingGraph::P assValue auf, um Werte von einem Pixelshaderfunktionsknoten an den Ausgabeknoten zu übergeben.

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

Rufen Sie die ID3D11FunctionLinkingGraph::CreateModuleInstance-Methode auf, um das Pixelshaderdiagramm abzuschließen.

            // Finalize the pixel shader graph.
            ComPtr<ID3D11ModuleInstance> pixelShaderGraphInstance;
            LinkingThrowIfFailed(pixelShaderGraph->CreateModuleInstance(&pixelShaderGraphInstance, nullptr), pixelShaderGraph.Get());

Rufen Sie die Funktion D3DCreateLinker auf, um einen Linker (ID3D11Linker) zu erstellen, mit dem Sie die instance der Shaderbibliothek verknüpfen können, die Sie unter Verpacken einer Shaderbibliothek erstellt haben, mit dem instance des Pixelshaderdiagramms, das Sie im vorherigen Schritt erstellt haben. Rufen Sie die ID3D11Linker::UseLibrary-Methode auf, um die Shaderbibliothek anzugeben, die für die Verknüpfung verwendet werden soll. Rufen Sie die ID3D11Linker::Link-Methode auf, um die Shaderbibliothek mit dem Pixelshaderdiagramm zu verknüpfen und einen Zeiger auf die ID3DBlob-Schnittstelle zu erstellen, mit der Sie auf den kompilierten Pixelshadercode zugreifen können. Anschließend können Sie diesen kompilierten Pixelshadercode an die ID3D11Device::CreatePixelShader-Methode übergeben, um das Pixelshader-Objekt zu erstellen.

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

Zusammenfassung

Wir haben die ID3D11FunctionLinkingGraph-Methoden verwendet, um die Vertex- und Pixelshaderdiagramme zu konstruieren und die Shaderstruktur programmgesteuert anzugeben.

Diese Graphkonstruktionen bestehen aus Sequenzen von vorkompilierten Funktionsaufrufen, die Werte aneinander übergeben. FLG-Knoten (ID3D11LinkingNode) stellen Eingabe- und Ausgabeshaderknoten und Aufrufe von vorkompilierten Bibliotheksfunktionen dar. Die Reihenfolge, in der Sie die Funktionsaufrufknoten registrieren, definiert die Reihenfolge der Aufrufe. Sie müssen zuerst den Eingabeknoten (ID3D11FunctionLinkingGraph::SetInputSignature) und den Ausgabeknoten (ID3D11FunctionLinkingGraph::SetOutputSignature) angeben. FLG-Kanten definieren, wie Werte von einem Knoten an einen anderen übergeben werden. Die Datentypen der übergebenen Werte müssen identisch sein. es gibt keine implizite Typkonvertierung. Shape- und Swizzlingregeln folgen dem HLSL-Verhalten. Werte können nur in dieser Sequenz vorwärts übergeben werden.

Außerdem haben wir ID3D11Linker-Methoden verwendet, um die Shaderbibliothek mit den Shadergraphen zu verknüpfen und Shaderblobs für die Direct3D-Runtime zu erstellen.

Herzlichen Glückwunsch! Sie können jetzt Shaderverknüpfungen in Ihren eigenen Apps verwenden.

Verwenden der Shaderverknüpfung