0
\$\begingroup\$

I'm new to HLSL and have been struggling with this problem for a while and I can't figure it out. I'm getting the below error a number of times in the debug window:

D3D11 ERROR: ID3D10Device::DrawIndexed: Input Assembler - Vertex Shader linkage error: Signatures between stages are incompatible. Semantic 'TEXCOORD' is defined for mismatched hardware registers between the output stage and input stage. [ EXECUTION ERROR #343: DEVICE_SHADER_LINKAGE_REGISTERINDEX]

VS_NORMALMAP_INPUT:

struct VS_NORMALMAP_INPUT
{
    float3 Pos     : POSITION;
    float3 Normal  : NORMAL;
    float3 Tangent : TANGENT;
    float2 UV      : TEXCOORD;
};

Vertex Shader:

VS_LIGHTING_OUTPUT LightingTransformTex(VS_NORMALMAP_INPUT vIn)
{
    VS_LIGHTING_OUTPUT vOut;

    // Use world matrix passed from C++ to transform the input model vertex position into world space
    float4 modelPos = float4(vIn.Pos, 1.0f); // Promote to 1x4 so we can multiply by 4x4 matrix, put 1.0 in 4th element for a point (0.0 for a vector)
    float4 worldPos = mul(modelPos, WorldMatrix);
    vOut.WorldPos = worldPos.xyz;

    // Use camera matrices to further transform the vertex from world space into view space (camera's point of view) and finally into 2D "projection" space for rendering
    float4 viewPos = mul(worldPos, ViewMatrix);
    vOut.ProjPos = mul(viewPos, ProjMatrix);

    // Transform the vertex normal from model space into world space (almost same as first lines of code above)
    float4 modelNormal = float4(vIn.Normal, 0.0f); // Set 4th element to 0.0 this time as normals are vectors
    vOut.Tangent = vIn.Tangent;
    vOut.WorldNormal = mul(modelNormal, WorldMatrix).xyz;

    // Pass texture coordinates (UVs) on to the pixel shader, the vertex shader doesn't need them
    vOut.UV = vIn.UV;

    return vOut;
}

Input Layout:

bool CModel::Load( const string& fileName, ID3D10EffectTechnique* exampleTechnique, bool tangents /*= false*/ ) // The commented out bit is the default parameter (can't write it here, only in the declaration)
{
    // Release any existing geometry in this object
    ReleaseResources();

    // Use CImportXFile class (from another application) to load the given file. The import code is wrapped in the namespace 'gen'
    gen::CImportXFile mesh;
    if (mesh.ImportFile( fileName.c_str() ) != gen::kSuccess)
    {
        return false;
    }

    // Get first sub-mesh from loaded file
    gen::SSubMesh subMesh;
    if (mesh.GetSubMesh( 0, &subMesh, tangents ) != gen::kSuccess)
    {
        return false;
    }


    // Create vertex element list & layout. We need a vertex layout to say what data we have per vertex in this model (e.g. position, normal, uv, etc.)
    // In previous projects the element list was a manually typed in array as we knew what data we would provide. However, as we can load models with
    // different vertex data this time we need flexible code. The array is built up one element at a time: ask the import class if it loaded normals, 
    // if so then add a normal line to the array, then ask if it loaded UVS...etc
    unsigned int numElts = 0;
    unsigned int offset = 0;
    // Position is always required
    m_VertexElts[numElts].SemanticName = "POSITION";   // Semantic in HLSL (what is this data for)
    m_VertexElts[numElts].SemanticIndex = 0;           // Index to add to semantic (a count for this kind of data, when using multiple of the same type, e.g. TEXCOORD0, TEXCOORD1)
    m_VertexElts[numElts].Format = DXGI_FORMAT_R32G32B32_FLOAT; // Type of data - this one will be a float3 in the shader. Most data communicated as though it were colours
    m_VertexElts[numElts].AlignedByteOffset = offset;  // Offset of element from start of vertex data (e.g. if we have position (float3), uv (float2) then normal, the normal's offset is 5 floats = 5*4 = 20)
    m_VertexElts[numElts].InputSlot = 0;               // For when using multiple vertex buffers (e.g. instancing - an advanced topic)
    m_VertexElts[numElts].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA; // Use this value for most cases (only changed for instancing)
    m_VertexElts[numElts].InstanceDataStepRate = 0;                     // --"--
    offset += 12;
    ++numElts;
    // Repeat for each kind of vertex data
    if (subMesh.hasNormals)
    {
        m_VertexElts[numElts].SemanticName = "NORMAL";
        m_VertexElts[numElts].SemanticIndex = 0;
        m_VertexElts[numElts].Format = DXGI_FORMAT_R32G32B32_FLOAT;
        m_VertexElts[numElts].AlignedByteOffset = offset;
        m_VertexElts[numElts].InputSlot = 0;
        m_VertexElts[numElts].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA;
        m_VertexElts[numElts].InstanceDataStepRate = 0;
        offset += 12;
        ++numElts;
    }
    if (subMesh.hasTangents)
    {
        m_VertexElts[numElts].SemanticName = "TANGENT";
        m_VertexElts[numElts].SemanticIndex = 0;
        m_VertexElts[numElts].Format = DXGI_FORMAT_R32G32B32_FLOAT;
        m_VertexElts[numElts].AlignedByteOffset = offset;
        m_VertexElts[numElts].InputSlot = 0;
        m_VertexElts[numElts].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA;
        m_VertexElts[numElts].InstanceDataStepRate = 0;
        offset += 12;
        ++numElts;
    }
    if (subMesh.hasTextureCoords)
    {
        m_VertexElts[numElts].SemanticName = "TEXCOORD";
        m_VertexElts[numElts].SemanticIndex = 0;
        m_VertexElts[numElts].Format = DXGI_FORMAT_R32G32_FLOAT;
        m_VertexElts[numElts].AlignedByteOffset = offset;
        m_VertexElts[numElts].InputSlot = 0;
        m_VertexElts[numElts].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA;
        m_VertexElts[numElts].InstanceDataStepRate = 0;
        offset += 8;
        ++numElts;
    }
    if (subMesh.hasVertexColours)
    {
        m_VertexElts[numElts].SemanticName = "COLOR";
        m_VertexElts[numElts].SemanticIndex = 0;
        m_VertexElts[numElts].Format = DXGI_FORMAT_R8G8B8A8_UNORM; // A RGBA colour with 1 byte (0-255) per component
        m_VertexElts[numElts].AlignedByteOffset = offset;
        m_VertexElts[numElts].InputSlot = 0;
        m_VertexElts[numElts].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA;
        m_VertexElts[numElts].InstanceDataStepRate = 0;
        offset += 4;
        ++numElts;
    }
    m_VertexSize = offset;

    // Given the vertex element list, pass it to DirectX to create a vertex layout. We also need to pass an example of a technique that will
    // render this model. We will only be able to render this model with techniques that have the same vertex input as the example we use here
    D3D10_PASS_DESC PassDesc;
    exampleTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    Device->CreateInputLayout( m_VertexElts, numElts, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_VertexLayout );


    // Create the vertex buffer and fill it with the loaded vertex data
    m_NumVertices = subMesh.numVertices;
    D3D10_BUFFER_DESC bufferDesc;
    bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    bufferDesc.Usage = D3D10_USAGE_DEFAULT; // Not a dynamic buffer
    bufferDesc.ByteWidth = m_NumVertices * m_VertexSize; // Buffer size
    bufferDesc.CPUAccessFlags = 0;   // Indicates that CPU won't access this buffer at all after creation
    bufferDesc.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA initData; // Initial data
    initData.pSysMem = subMesh.vertices;   
    if (FAILED( Device->CreateBuffer( &bufferDesc, &initData, &m_VertexBuffer )))
    {
        return false;
    }

Any advice to help diagnose this problem will be much appreciated. I apologize if I provided to much code.

\$\endgroup\$
6
  • \$\begingroup\$ Please post the code for the VS, the InputLayout, and VS_BASIC_INPUT and remove all other code. \$\endgroup\$
    – Jon
    Apr 2, 2015 at 1:57
  • \$\begingroup\$ I made the changes you requested but I didn't give VS_BASIC_INPUT because the problem only started when I added the LightingTransformTex vertex shader. \$\endgroup\$ Apr 2, 2015 at 2:27
  • \$\begingroup\$ Please confirm that you are creating per-mesh input layouts. \$\endgroup\$
    – Jon
    Apr 2, 2015 at 2:32
  • \$\begingroup\$ Yes I am I think. \$\endgroup\$ Apr 2, 2015 at 2:34
  • \$\begingroup\$ Please list the VertexFormats used by all meshes. i.e. VertexPositionNormalTexture. Do they all use the same one? \$\endgroup\$
    – Jon
    Apr 2, 2015 at 2:38

1 Answer 1

0
\$\begingroup\$

All the meshes are loading in from .x files by the CModel class

Loading them means parsing all of the binary data into Vertex/Index buffers. While filling those Vertex buffers, it is creating a specific type of vertex; i.e. VertexPositionNormalTexture. When you draw any mesh, you are feeding the IA VertexPositionNormalTexture's.

Please confirm that you are creating per-mesh input layouts.
Yes I am I think.

By using per-mesh InputLayouts, the IA cannot find them in the right place/order. In all cases, the InputLayout should match exactly what the IA will be fed; you cannot omit them here. In other words, the IA always sees the entire vertex.

The VS can, then, pick and choose semantics out of the assembled input to use. If the VS only asks for Position and Normal, the IA will skip over the unused data and arrive at the same register, for the same semantic, every time.

struct VertexPositionNormalTexture
{
public:
    VertexPositionNormalTexture();
    static const int ElementCount = 3;
    static const D3D11_INPUT_ELEMENT_DESC InputElements[ElementCount];
    Vector3 Position;   //R1
    Vector3 Normal;     //R2
    Vector2 UV;         //R3
};
InputLayout (out-of-order)
{
    { "POSITION", 0, ... }, //R1
    { "UV", 0, ... },       //R2
    { "NORMAL", 0, ... },   //R3
};
InputLayout (mismatch and/or out-of-order)
{
    { "POSITION", 0, ... }, //R1
    { "UV", 0, ... },       //R2
};

If the IA didn't complain, this would happen (each {} is an input to the VS):

{Position, Normal}, {UV, Position}, {Normal, UV}, {Position, Normal}, etc.

Thanks for the explanation. Do you suggest I hard code the InputLayout for each mesh?

I suggest you determine which vertex format the .x compiler defaults to and just use it directly. When creating the input layout:

CreateInputLayout(VertexPositionNormalTexture::InputElements, VertexPositionNormalTexture::ElementCount, ...);
\$\endgroup\$
4
  • \$\begingroup\$ Thanks for the explanation. Do you suggest I hard code the InputLayout for each mesh? \$\endgroup\$ Apr 2, 2015 at 2:48
  • \$\begingroup\$ One additional comment regarding the "if (subMesh.hasNormals)" lines. These may still be necessary, but will only be used to determine which shader(s) to bind. In that way, you can filter what you need out of the same vertex declaration, per-shader. You may need different shaders for "NonTextured", "Textured", "TexturedAndLit", etc., because you don't need/use the normals, unless you are lighting. \$\endgroup\$
    – Jon
    Apr 2, 2015 at 3:08
  • \$\begingroup\$ I usually include a spare float4 in my vertices just to pass in miscellaneous information like "bool HasTexture". For example, in my PS, if Flags.x == 1, I sample, otherwise I return a solid color. Flags can mean anything for any vertex and, so, comes in handy often. You could also sort this into DrawAllTextured then DrawAllNonTextured on the CPU but, by adding Flags, I can reuse the same shader. Cheers! \$\endgroup\$
    – Jon
    Apr 2, 2015 at 3:14
  • \$\begingroup\$ Really helpful, I will incorporate that into my program. Have a good one! \$\endgroup\$ Apr 2, 2015 at 3:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .