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());
2. Vincular o sombreador de vértice
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());
4. Vincular o sombreador de pixel
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.
Tópicos relacionados