Создание графа связывания функций и связывание его с скомпилированным кодом
Здесь мы покажем, как создавать графы функции связи (FLG) для шейдеров и как связать эти шейдеры с библиотекой шейдеров для создания шейдерных блоков, которые может использовать среда выполнения Direct3D.
Цель: Создать граф связывания функций и связать его с скомпилированный код.
Необходимые условия
Предположим, что вы знакомы с C++. Вам также нужен базовый опыт работы с концепциями программирования графики.
Мы также предполагаем, что вы завершили упаковали библиотеку шейдеров.
время завершения: 30 минут.
Инструкции
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::PassValue, чтобы передавать значения из входного узла на узел для основной функции шейдера вершин.
// 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::PassValue, чтобы передать значения для основной функции шейдера вершин из узла в выходной узел.
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());
2. Связывание шейдера вершин
Вызовите функцию 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, чтобы создать граф с привязкой функций (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::PassValue, чтобы передать значения из входного узла в узел для основной функции шейдера пикселей.
// 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());
4. Связывание шейдера пикселей
Вызовите функцию 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.
Поздравляю! Теперь вы готовы использовать связывание шейдеров в собственных приложениях.
Связанные разделы