Compartilhar via


Construir um grafo de vinculação de função e vinculá-lo ao código compilado

Aqui, mostramos como construir FLGs (function-linking-graphs) para sombreadores e como vincular esses sombreadores a uma biblioteca de sombreadores para produzir blobs de sombreador que o runtime do Direct3D pode usar.

Objetivo: Para construir um grafo de vinculação de função e vinculá-lo ao código compilado.

Pré-requisitos

Partimos do princípio de que você conhece C++. Você também precisa ter experiência básica com conceitos de programação de elementos gráficos.

Também pressupomos que você passou por Empacotar uma biblioteca de sombreadores.

Tempo de conclusão: 30 minutos.

Instruções

1. Construa um grafo de vinculação de função para o sombreador de vértice.

Chame a função D3DCreateFunctionLinkingGraph para criar um grafo de vinculação de função (ID3D11FunctionLinkingGraph) para representar o sombreador de vértice.

Use uma matriz de estruturas D3D11_PARAMETER_DESC para definir os parâmetros de entrada para o sombreador de vértice. O Estágio Input-Assembler alimenta os parâmetros de entrada para o sombreador de vértice. O layout dos parâmetros de entrada do sombreador de vértice corresponde ao layout do sombreador de vértice no código compilado. Depois de definir os parâmetros de entrada, chame o método ID3D11FunctionLinkingGraph::SetInputSignature para definir o nó de entrada (ID3D11LinkingNode) para o sombreador de vértice.

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

Chame o método ID3D11FunctionLinkingGraph::CallFunction para criar um nó para a função de sombreador de vértice main e fazer chamadas para ID3D11FunctionLinkingGraph::P assValue para passar valores do nó de entrada para o nó da função de sombreador de vértice main.

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

Use uma matriz de estruturas de D3D11_PARAMETER_DESC para definir os parâmetros de saída para o sombreador de vértice. O sombreador de vértice alimenta seus parâmetros de saída para o sombreador de pixel. O layout dos parâmetros de saída do sombreador de vértice corresponde ao layout do sombreador de pixel no código compilado. Depois de definir os parâmetros de saída, chame o método ID3D11FunctionLinkingGraph::SetOutputSignature para definir o nó de saída (ID3D11LinkingNode) para o sombreador de vértice.

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

Faça chamadas para ID3D11FunctionLinkingGraph::P assValue para passar valores do nó para a função de sombreador de vértice main para o nó de saída.

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

Chame o método ID3D11FunctionLinkingGraph::CreateModuleInstance para finalizar o grafo de sombreador de vértice.

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

Chame a função D3DCreateLinker para criar um vinculador (ID3D11Linker) que você pode usar para vincular a instância da biblioteca de sombreador que você criou em Empacotando uma biblioteca de sombreadores com a instância do grafo de sombreador de vértice que você criou na etapa anterior. Chame o método ID3D11Linker::UseLibrary para especificar a biblioteca de sombreador a ser usada para vinculação. Chame o método ID3D11Linker::Link para vincular a biblioteca de sombreadores ao grafo de sombreador de vértice e produzir um ponteiro para a interface ID3DBlob que você pode usar para acessar o código de sombreador de vértice compilado. Em seguida, você pode passar esse código de sombreador de vértice compilado para o método ID3D11Device::CreateVertexShader para criar o objeto sombreador de vértice e para o método ID3D11Device::CreateInputLayout para criar o objeto de layout de entrada.

            // 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. Construa um grafo de vinculação de função para o sombreador de pixel.

Chame a função D3DCreateFunctionLinkingGraph para criar um grafo de vinculação de função (ID3D11FunctionLinkingGraph) para representar o sombreador de pixel.

Use uma matriz de estruturas de D3D11_PARAMETER_DESC para definir os parâmetros de entrada para o sombreador de pixel. O estágio do sombreador de vértice alimenta os parâmetros de entrada para o sombreador de pixel. O layout dos parâmetros de entrada do sombreador de pixel corresponde ao layout do sombreador de pixel no código compilado. Depois de definir os parâmetros de entrada, chame o método ID3D11FunctionLinkingGraph::SetInputSignature para definir o nó de entrada (ID3D11LinkingNode) para o sombreador de pixel.

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

Chame o método ID3D11FunctionLinkingGraph::CallFunction para criar um nó para a função de sombreador de pixel main e fazer chamadas para ID3D11FunctionLinkingGraph::P assValue para passar valores do nó de entrada para o nó da função de sombreador de pixel main.

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

Use uma matriz de estruturas de D3D11_PARAMETER_DESC para definir os parâmetros de saída para o sombreador de pixel. O sombreador de pixel alimenta seus parâmetros de saída para o Estágio de Fusão de Saída. Depois de definir os parâmetros de saída, chame o método ID3D11FunctionLinkingGraph::SetOutputSignature para definir o nó de saída (ID3D11LinkingNode) para o sombreador de pixel e faça chamadas para ID3D11FunctionLinkingGraph::P assValue para passar valores de um nó de função de sombreador de pixel para o nó de saída.

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

Chame o método ID3D11FunctionLinkingGraph::CreateModuleInstance para finalizar o grafo do sombreador de pixel.

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

Chame a função D3DCreateLinker para criar um vinculador (ID3D11Linker) que você pode usar para vincular a instância da biblioteca de sombreador que você criou em Empacotar uma biblioteca de sombreadores com a instância do grafo de sombreador de pixel que você criou na etapa anterior. Chame o método ID3D11Linker::UseLibrary para especificar a biblioteca de sombreador a ser usada para vinculação. Chame o método ID3D11Linker::Link para vincular a biblioteca de sombreadores com o grafo do sombreador de pixel e produzir um ponteiro para a interface ID3DBlob que você pode usar para acessar o código do sombreador de pixel compilado. Em seguida, você pode passar esse código de sombreador de pixel compilado para o método ID3D11Device::CreatePixelShader para criar o objeto sombreador de pixel.

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

Resumo

Usamos os métodos ID3D11FunctionLinkingGraph para construir os grafos de sombreador de vértice e pixel e especificar a estrutura do sombreador programaticamente.

Essas construções de grafo consistem em sequências de chamadas de função pré-compiladas que passam valores uns para os outros. Nós FLG (ID3D11LinkingNode) representam nós de sombreador de entrada e saída e invocações de funções de biblioteca pré-compiladas. A ordem na qual você registra os nós de chamada de função define a sequência de invocações. Você deve especificar o nó de entrada (ID3D11FunctionLinkingGraph::SetInputSignature) primeiro e o nó de saída último (ID3D11FunctionLinkingGraph::SetOutputSignature). As bordas FLG definem como os valores são passados de um nó para outro. Os tipos de dados de valores passados devem ser os mesmos; não há conversão de tipo implícito. Regras de forma e swizzling seguem o comportamento HLSL. Os valores só podem ser passados para frente nesta sequência.

Também usamos métodos ID3D11Linker para vincular a biblioteca de sombreadores com os grafos de sombreador e produzir blobs de sombreador para o runtime do Direct3D a ser usado.

Parabéns! Agora você está pronto para usar a vinculação de sombreador em seus próprios aplicativos.

Usando a vinculação do sombreador