DirectX shader linking error

191 views Asked by At

I recently heard about shader linking in DirectX, and decided to give it a go, following this MSDN tutorial, and seem to have it mostly working. However, it fails in the link stage, giving the error:

error X9214: ID3D11Linker::Link: failed to generate byte code

I get the same error for both the vertex shader and the pixel shader. Compiling the shader library, creating the graph, connecting the nodes and everything seems to work, but the linking still fails. I've been unable to find any details regarding the error code, and the error message isn't particularly helpful. The full relevant code is attached, I hope that someone can see what I'm doing wrong!

Linking.hlsl:

Texture2DArray inTexture : register(t0);
SamplerState samplerState : register(s0);

cbuffer CameraData : register(b0)
{
    float4x4 Model;
    float4x4 View;
    float4x4 Projection;
};

export void VertexFunction(inout float4 position, inout float2 uv)
{
    position = mul(position, Model);
    position = mul(position, View);
    position = mul(position, Projection);
}

export float4 SampleTexture(float2 uv)
{
    return inTexture.Sample(samplerState, float3(uv,0));
}

Shader compilation:

    //Compile shader to bytecode (exported functions)
    ID3DBlob* shaderBlob = nullptr;
    ID3DBlob* errorBlob = nullptr;
    HRESULT hr = D3DCompileFromFile(aPath.c_str(), NULL, NULL, NULL, 
        (std::string("lib") + Graphics::Shader::Linking::CShaderLibrary::ShaderModelSuffix).c_str(), D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, &shaderBlob, &errorBlob);
    ErrorCheck(hr, errorBlob);

    //Create shader library
    ID3D11Module* shaderLibrary = nullptr;
    hr = D3DLoadModule(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), &shaderLibrary);
    shaderBlob->Release();
    ErrorCheck(hr);

    //Create shader library instance
    ID3D11ModuleInstance *shaderLibraryInstance = nullptr;
    hr = shaderLibrary->CreateInstance("", &shaderLibraryInstance);
    ErrorCheck(hr);

    //Bind the resources, samplers and constant buffers
    hr = shaderLibraryInstance->BindResource(0, 0, 1);
    ErrorCheck(hr);
    hr = shaderLibraryInstance->BindSampler(0, 0, 1);
    ErrorCheck(hr);
    hr = shaderLibraryInstance->BindConstantBuffer(0, 0, 0);
    ErrorCheck(hr);

    return new Graphics::Shader::Linking::CShaderLibrary(*shaderLibrary,*shaderLibraryInstance);

Create the vertex shader from graph (its own function):

//Create the vertex shader graph;
    ID3D11FunctionLinkingGraph* vertexShaderGraph = nullptr;
    HRESULT result = D3DCreateFunctionLinkingGraph(0, &vertexShaderGraph);

    EffectHelper::ErrorCheck(result);

    //Define the vertex shader input layout
    static const D3D11_PARAMETER_DESC vertexInputParameters[] =
    {
        { "inputPos", "POSITION0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1,4,D3D_INTERPOLATION_LINEAR, D3D_PF_IN,0,0,0,0 },
        { "inputUV", "TEXCOORD0", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1,2,D3D_INTERPOLATION_LINEAR,D3D_PF_IN,0,0,0,0}
    };

    //Create the vertex input node. This will be used by the input assembler
    ID3D11LinkingNode* vertexInputNode = nullptr;
    result = vertexShaderGraph->SetInputSignature(vertexInputParameters, ARRAYSIZE(vertexInputParameters), &vertexInputNode);
    EffectHelper::ErrorCheck(result, vertexShaderGraph);

    //Create the vertex function node. This will be sent the data from the input node.
    ID3D11LinkingNode* vertexFunctionNode = nullptr;
    result = vertexShaderGraph->CallFunction("", &myLibrary, "VertexFunction", &vertexFunctionNode);
    EffectHelper::ErrorCheck(result, vertexShaderGraph);

    //Pass the value from the input node to the vertex function node (for future info, remember that all function arguments have to be assigned).
    result = vertexShaderGraph->PassValue(vertexInputNode, 0, vertexFunctionNode, 0);
    EffectHelper::ErrorCheck(result, vertexShaderGraph);

    result = vertexShaderGraph->PassValue(vertexInputNode, 1, vertexFunctionNode, 1);
    EffectHelper::ErrorCheck(result, vertexShaderGraph);

    //Define the output layout for the vertex function
    static const D3D11_PARAMETER_DESC vertexShaderOutputParameters[] =
    {
        { "outputUV","TEXCOORD0",D3D_SVT_FLOAT, D3D_SVC_VECTOR,1,2,D3D_INTERPOLATION_UNDEFINED,D3D_PF_OUT,0,0,0,0 },
        { "outputPosition", "SV_POSITION", D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1,4,D3D_INTERPOLATION_UNDEFINED, D3D_PF_OUT, 0,0,0,0}
    };

    //Create the vertex output node
    ID3D11LinkingNode* vertexShaderOutputNode = nullptr;
    result = vertexShaderGraph->SetOutputSignature(vertexShaderOutputParameters, ARRAYSIZE(vertexShaderOutputParameters), &vertexShaderOutputNode);
    EffectHelper::ErrorCheck(result, vertexShaderGraph);

    //Pass the value from the function node to the output node
    result = vertexShaderGraph->PassValue(vertexFunctionNode, 0, vertexShaderOutputNode, 1);
    EffectHelper::ErrorCheck(result, vertexShaderGraph);
    result = vertexShaderGraph->PassValue(vertexFunctionNode, 1, vertexShaderOutputNode, 0);
    EffectHelper::ErrorCheck(result, vertexShaderGraph);

    //Finalize the the vertex shader graph
    ID3D11ModuleInstance* vertexShaderGraphInstance = nullptr;
    result = vertexShaderGraph->CreateModuleInstance(&vertexShaderGraphInstance, nullptr);
    EffectHelper::ErrorCheck(result, vertexShaderGraph);

    //Create a linker
    ID3D11Linker* linker = nullptr;
    result = D3DCreateLinker(&linker);
    EffectHelper::ErrorCheck(result);

    //Hook up the shader library instance
    result = linker->UseLibrary(&myLibraryInstance);
    EffectHelper::ErrorCheck(result);

    //Link the vertex shader. This looks mostly normal, frankly. Interesting. TODO: Something goes wrong here. What? #HelpfulError
    ID3DBlob* vertexShaderBlob = nullptr;
    ID3DBlob* errorBlob = nullptr;
    //Error occurs here
    result = linker->Link(vertexShaderGraphInstance, "main", (std::string("vs") + ShaderModelSuffix).c_str(), 0, &vertexShaderBlob, &errorBlob);
    EffectHelper::ErrorCheck(result, errorBlob);

    //Create the vertex shader. Business as usual?
    ID3D11VertexShader* vertexShader = nullptr;
    result = MasterSingleton::GetInstance().Get3DEngine().GetFramework().GetDevice().CreateVertexShader(
        vertexShaderBlob->GetBufferPointer(),vertexShaderBlob->GetBufferSize(),nullptr,&vertexShader);
    EffectHelper::ErrorCheck(result);

Create the pixel shader from graph (also its own function):

//Create pixel shader graph
    ID3D11FunctionLinkingGraph* pixelShaderGraph = nullptr;
    HRESULT result = D3DCreateFunctionLinkingGraph(0, &pixelShaderGraph);
    EffectHelper::ErrorCheck(result);

    //Define the pixel shader input layout (will be fed by vertex shader layout)
    static const D3D11_PARAMETER_DESC pixelInputDesc[] =
    {
        {"inputUV","TEXCOORD0",D3D_SVT_FLOAT, D3D_SVC_VECTOR, 1,2,D3D_INTERPOLATION_UNDEFINED,D3D_PF_IN,0,0,0,0},
        {"inputPosition","SV_POSITION",D3D_SVT_FLOAT,D3D_SVC_VECTOR,1,4,D3D_INTERPOLATION_UNDEFINED, D3D_PF_IN,0,0,0,0}
    };

    //Create pixel shader input node
    ID3D11LinkingNode* pixelInputNode = nullptr;
    result = pixelShaderGraph->SetInputSignature(pixelInputDesc, ARRAYSIZE(pixelInputDesc), &pixelInputNode);
    EffectHelper::ErrorCheck(result, pixelShaderGraph);

    //Create texture sample function node
    ID3D11LinkingNode* textureSampleFunctionNode = nullptr;
    result = pixelShaderGraph->CallFunction("", &myLibrary, "SampleTexture", &textureSampleFunctionNode);
    EffectHelper::ErrorCheck(result, pixelShaderGraph);

    //Pass value from input node to texture sample node
    result = pixelShaderGraph->PassValue(pixelInputNode, 0, textureSampleFunctionNode, 0);
    EffectHelper::ErrorCheck(result, pixelShaderGraph);

    //Define the output parameters from the pixel shader
    D3D11_PARAMETER_DESC outputParameterDesc[]=
    {
        {"outputColor","SV_TARGET",D3D_SVT_FLOAT,D3D_SVC_VECTOR,1,4,D3D_INTERPOLATION_UNDEFINED,D3D_PF_OUT,0,0,0,0}
    };

    //Set the output node (using the signature)
    ID3D11LinkingNode* pixelOutputNode = nullptr;
    result = pixelShaderGraph->SetOutputSignature(outputParameterDesc, ARRAYSIZE(outputParameterDesc), &pixelInputNode);
    EffectHelper::ErrorCheck(result, pixelShaderGraph);

    //Finalize the pixel shader graph
    ID3D11ModuleInstance *pixelShaderInstance = nullptr;
    result = pixelShaderGraph->CreateModuleInstance(&pixelShaderInstance, nullptr);
    EffectHelper::ErrorCheck(result, pixelShaderGraph);

    //Create a linker and hook up to library instance
    ID3D11Linker *linker = nullptr;
    result = D3DCreateLinker(&linker);
    EffectHelper::ErrorCheck(result);

    //Set library to use
    result = linker->UseLibrary(&myLibraryInstance);
    EffectHelper::ErrorCheck(result);

    //Link the pixel shader
    ID3DBlob* shaderBlob;
    ID3DBlob* errorBlob;
    //And also here
    result = linker->Link(pixelShaderInstance, "main", (std::string("ps") + ShaderModelSuffix).c_str(), 0, &shaderBlob, &errorBlob);
    EffectHelper::ErrorCheck(result, errorBlob);

    //Compile the pixel shader
    ID3D11PixelShader* pixelShader = nullptr;
    result = MasterSingleton::GetInstance().Get3DEngine().GetFramework().GetDevice().CreatePixelShader(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), nullptr, &pixelShader);
    EffectHelper::ErrorCheck(result);
0

There are 0 answers