Membuat grafik penautan fungsi dan menautkannya ke kode yang dikompilasi

Di sini kami menunjukkan kepada Anda cara membuat function-linking-graphs (FLG) untuk shader dan cara menautkan shader tersebut dengan pustaka shader untuk menghasilkan blob shader yang dapat digunakan runtime Direct3D.

Tujuan: Untuk membuat grafik penautan fungsi dan menautkannya ke kode yang dikompilasi.

Prasyarat

Kami berasumsi bahwa Anda terbiasa dengan C++. Anda juga memerlukan pengalaman dasar dengan konsep pemrograman grafis.

Kami juga berasumsi bahwa Anda melalui Pengemasan pustaka shader.

Waktu selesai: 30 menit.

Petunjuk

1. Buat grafik penautan fungsi untuk shader vertex.

Panggil fungsi D3DCreateFunctionLinkingGraph untuk membuat function-linking-graph (ID3D11FunctionLinkingGraph) untuk mewakili shader vertex.

Gunakan array struktur D3D11_PARAMETER_DESC untuk menentukan parameter input untuk shader vertex. Tahap Input-Assembler mengumpankan parameter input ke shader vertex. Tata letak parameter input vertex shader cocok dengan tata letak shader vertex dalam kode yang dikompilasi. Setelah Anda menentukan parameter input, panggil metode ID3D11FunctionLinkingGraph::SetInputSignature untuk menentukan simpul input (ID3D11LinkingNode) untuk shader vertex.

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

Panggil metode ID3D11FunctionLinkingGraph::CallFunction untuk membuat simpul untuk fungsi shader vertex utama dan lakukan panggilan ke ID3D11FunctionLinkingGraph::P assValue untuk meneruskan nilai dari simpul input ke simpul untuk fungsi shader verteks utama.

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

Gunakan array struktur D3D11_PARAMETER_DESC untuk menentukan parameter output untuk shader vertex. Shader vertex menyalurkan parameter outputnya ke shader piksel. Tata letak parameter output vertex shader cocok dengan tata letak shader piksel dalam kode yang dikompilasi. Setelah Anda menentukan parameter output, panggil metode ID3D11FunctionLinkingGraph::SetOutputSignature untuk menentukan simpul output (ID3D11LinkingNode) untuk shader vertex.

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

Lakukan panggilan ke ID3D11FunctionLinkingGraph::P assValue untuk meneruskan nilai dari simpul untuk fungsi shader vertex utama ke simpul output.

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

Panggil metode ID3D11FunctionLinkingGraph::CreateModuleInstance untuk menyelesaikan grafik shader vertex.

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

Panggil fungsi D3DCreateLinker untuk membuat linker (ID3D11Linker) yang dapat Anda gunakan untuk menautkan instans pustaka shader yang Anda buat di Mengemas pustaka shader dengan instans grafik shader vertex yang Anda buat di langkah sebelumnya. Panggil metode ID3D11Linker::UseLibrary untuk menentukan pustaka shader yang akan digunakan untuk penautan. Panggil metode ID3D11Linker::Link untuk menautkan pustaka shader dengan grafik shader vertex dan untuk menghasilkan pointer ke antarmuka ID3DBlob yang dapat Anda gunakan untuk mengakses kode shader vertex yang dikompilasi. Anda kemudian dapat meneruskan kode shader vertex yang dikompilasi ini ke metode ID3D11Device::CreateVertexShader untuk membuat objek shader vertex dan ke metode ID3D11Device::CreateInputLayout untuk membuat objek input-layout.

            // 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. Buat grafik penautan fungsi untuk shader piksel.

Panggil fungsi D3DCreateFunctionLinkingGraph untuk membuat function-linking-graph (ID3D11FunctionLinkingGraph) untuk mewakili shader piksel.

Gunakan array struktur D3D11_PARAMETER_DESC untuk menentukan parameter input untuk shader piksel. Tahap shader vertex mengumpankan parameter input ke shader piksel. Tata letak parameter input shader piksel cocok dengan tata letak shader piksel dalam kode yang dikompilasi. Setelah Anda menentukan parameter input, panggil metode ID3D11FunctionLinkingGraph::SetInputSignature untuk menentukan simpul input (ID3D11LinkingNode) untuk shader piksel.

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

Panggil metode ID3D11FunctionLinkingGraph::CallFunction untuk membuat simpul untuk fungsi shader piksel utama dan lakukan panggilan ke ID3D11FunctionLinkingGraph::P assValue untuk meneruskan nilai dari simpul input ke simpul untuk fungsi shader piksel utama.

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

Gunakan array struktur D3D11_PARAMETER_DESC untuk menentukan parameter output untuk shader piksel. Shader piksel menyalurkan parameter outputnya ke Tahap Output-Merger. Setelah Anda menentukan parameter output, panggil metode ID3D11FunctionLinkingGraph::SetOutputSignature untuk menentukan simpul output (ID3D11LinkingNode) untuk shader piksel dan lakukan panggilan ke ID3D11FunctionLinkingGraph::P assValue untuk meneruskan nilai dari simpul fungsi shader piksel ke simpul output.

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

Panggil metode ID3D11FunctionLinkingGraph::CreateModuleInstance untuk menyelesaikan grafik shader piksel.

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

Panggil fungsi D3DCreateLinker untuk membuat linker (ID3D11Linker) yang dapat Anda gunakan untuk menautkan instans pustaka shader yang Anda buat di Mengemas pustaka shader dengan instans grafik shader piksel yang Anda buat di langkah sebelumnya. Panggil metode ID3D11Linker::UseLibrary untuk menentukan pustaka shader yang akan digunakan untuk penautan. Panggil metode ID3D11Linker::Link untuk menautkan pustaka shader dengan grafik shader piksel dan untuk menghasilkan penunjuk ke antarmuka ID3DBlob yang dapat Anda gunakan untuk mengakses kode shader piksel yang dikompilasi. Anda kemudian dapat meneruskan kode shader piksel yang dikompilasi ini ke metode ID3D11Device::CreatePixelShader untuk membuat objek shader piksel.

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

Ringkasan

Kami menggunakan metode ID3D11FunctionLinkingGraph untuk membangun grafik vertex dan pixel shader dan untuk menentukan struktur shader secara terprogram.

Konstruksi grafik ini terdiri dari urutan panggilan fungsi yang telah dikompilasi sebelumnya yang meneruskan nilai satu sama lain. Simpul FLG (ID3D11LinkingNode) mewakili simpul shader input dan output dan pemanggilan fungsi pustaka yang telah dikompilasi sebelumnya. Urutan di mana Anda mendaftarkan node panggilan fungsi menentukan urutan pemanggilan. Anda harus menentukan simpul input (ID3D11FunctionLinkingGraph::SetInputSignature) terlebih dahulu dan simpul output terakhir (ID3D11FunctionLinkingGraph::SetOutputSignature). Tepi FLG menentukan bagaimana nilai diteruskan dari satu simpul ke simpul lainnya. Jenis data nilai yang diteruskan harus sama; tidak ada konversi jenis implisit. Aturan bentuk dan menggelepar mengikuti perilaku HLSL. Nilai hanya dapat diteruskan ke depan dalam urutan ini.

Kami juga menggunakan metode ID3D11Linker untuk menautkan pustaka shader dengan grafik shader dan untuk menghasilkan blob shader untuk digunakan oleh runtime Direct3D.

Selamat! Anda sekarang siap menggunakan penautan shader di aplikasi Anda sendiri.

Menggunakan penautan shader