输入汇编器-顶点着色器链接错误

时间:2019-02-01 18:15:47

标签: c++ directx directxtk

我正在尝试使用SpriteFontSpriteBatch在DX11项目中渲染文本。

在添加代码之前,一切正常,但是在未注释代码的情况下,出现以下错误,并且没有任何显示。

D3D11 ERROR: ID3D11DeviceContext::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]
D3D11 ERROR: ID3D11DeviceContext::DrawIndexed: Input Assembler - Vertex Shader linkage error: Signatures between stages are incompatible. The input stage requires Semantic/Index (POSITION,0) as input, but it is not provided by the output stage. [ EXECUTION ERROR #342: DEVICE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND]
D3D11 ERROR: ID3D11DeviceContext::DrawIndexed: Input Assembler - Vertex Shader linkage error: Signatures between stages are incompatible. The input stage requires Semantic/Index (NORMAL,0) as input, but it is not provided by the output stage. [ EXECUTION ERROR #342: DEVICE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND]

我尝试更改DeviceContext和设备,但仍然是相同的错误。

    //Draw Text
    g_spriteBatch = std::make_unique<SpriteBatch>(g_pImmediateContext);
    g_spriteFont = std::make_unique<SpriteFont>(g_pd3dDevice1, L"Data\\game_font.spritefont");

    //Render Text
    g_spriteBatch->Begin();
    //g_spriteFont->DrawString(g_spriteBatch.get(), L"Score: 0", XMFLOAT2(0,0), DirectX::Colors::White);
    g_spriteBatch->End();

我尝试使用不同的Device和DeviceContext,但仍然是相同的错误。


我一直在尝试许多不同的方法来使其正常工作。 这就是我目前的渲染功能的样子

已更新:18/02/2019

void Render() {

    float backgroundColour[] = { 0.0f, 0.1f, 0.5f, 0.0f };
    g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, backgroundColour);
    g_pImmediateContext->ClearDepthStencilView(g_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

    g_pImmediateContext->IASetInputLayout(g_pVertexLayout);
    g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    g_pImmediateContext->RSSetState(g_rasterState);
    g_pImmediateContext->OMSetDepthStencilState(g_depthStencilState, 0);
    g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
    g_pImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);

    UINT stride = sizeof(SimpleVertex);
    UINT offset = 0;

    g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
    g_pImmediateContext->Draw(3, 0);
    //g_pImmediateContext->DrawIndexed(36, 0, 0);

    //Draw Text
    spriteBatch->Begin();
    spriteFont->DrawString(spriteBatch.get(), L"Test", DirectX::XMFLOAT2(0, 0), DirectX::Colors::White);
    spriteBatch->End();

    //Present our back buffer to the front buffer
    g_pSwapChain->Present(0, NULL);

}

运行项目时,出现以下错误 D3D11 ERROR: ID3D11DeviceContext::IASetVertexBuffers: A Buffer trying to be bound to slot 0 did not have the appropriate bind flag set at creation time to allow the Buffer to be bound as a VertexBuffer. [ STATE_SETTING ERROR #238: IASETVERTEXBUFFERS_INVALIDBUFFER]

这是存储tri数据并​​设置索引/顶点缓冲区的代码

    SimpleVertex vertices[] =
    {           
        SimpleVertex(-0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f),
        SimpleVertex( 0.0f,  0.5f, 1.0f, 1.0f, 0.0f, 0.0f),
        SimpleVertex( 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f),
    };

    D3D11_BUFFER_DESC bd = {};
    ZeroMemory(&bd, sizeof(bd));
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( SimpleVertex ) * ARRAYSIZE(vertices);
    bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = 0;
    bd.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = vertices;
    hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
    if (FAILED(hr))
    {
        printf("Failed ro Create Vertex Buffer.");
        return hr;
    }

我已将D3D11_BIND_INDEX_BUFFER更改为D3D11_BIND_VERTEX_BUFFER,并且发生相同的错误。

在此之后,还会产生以下警告。

D3D11 WARNING: ID3D11DeviceContext::Draw: Vertex Buffer at the input vertex slot 0 is not big enough for what the Draw*() call expects to traverse. This is OK, as reading off the end of the Buffer is defined to return 0. However the developer probably did not intend to make use of this behavior.  [ EXECUTION WARNING #356: DEVICE_DRAW_VERTEX_BUFFER_TOO_SMALL]

D3D11 WARNING: ID3D11DeviceContext::Draw: The size of the Constant Buffer at slot 0 of the Vertex Shader unit is too small (64 bytes provided, 192 bytes, at least, expected). This is OK, as out-of-bounds reads are defined to return 0. It is also possible the developer knows the missing data will not be used anyway. This is only a problem if the developer actually intended to bind a sufficiently large Constant Buffer for what the shader expects.  [ EXECUTION WARNING #351: DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL]

D3D11 WARNING: ID3D11DeviceContext::Draw: Input vertex slot 0 has stride 24 which is less than the minimum stride logically expected from the current Input Layout (32 bytes). This is OK, as hardware is perfectly capable of reading overlapping data. However the developer probably did not intend to make use of this behavior.  [ EXECUTION WARNING #355: DEVICE_DRAW_VERTEX_BUFFER_STRIDE_TOO_SMALL]

1 个答案:

答案 0 :(得分:0)

TL; DR::需要在调用Draw之前每帧设置多维数据集的输入布局,顶点着色器和像素着色器。

具体来说,您忘记设置代码注释掉时忘记设置顶点缓冲区:

// >>> Set vertex buffer
//g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
  

您的注释中包含您收到的Debug Device错误,该错误首先导致您将其注释掉。很明显,您的错误实际上是您在不将CreateBuffer设置为D3D11_BUFFER_DESC.BindFlags的情况下调用VB的D3D11_BIND_VERTEX_BUFFER的地方。

在每次调用Draw*之前,您需要设置该抽奖所需的任何状态。

wiki记录了通过调用SpriteFont::Begin/End更改的确切状态。特别是,它会更改输入布局和顶点着色器。您的“多维数据集绘制”代码依靠这些状态在每个帧之间保持不变,这实际上仅在平凡的情况下有效。

在每个渲染帧的开始,您应该:

  • 清除渲染目标和/或深度模板缓冲区
  • 调用OMSetRenderTargets设置您的主要渲染目标
  • 致电RSSetViewports设置视口状态

然后在每次调用Draw*之前设置您使用的所有状态。对于简单的3D立方体图形,至少包括:

  • 渲染目标视图,深度模板视图,视口(在简单情况下,可以在帧的开始处设置一次)
  • BlendState,DepthStencilState,RasterizerState
  • 输入布局
  • 任何常量缓冲区,像素着色器,顶点着色器以及任何必需的SamplerState或Shader资源。

DirectX Tool Kit包括CommonStateEffects之类的许多助手,以使其更易于管理,但是您仍然必须确保 all 声明自己依靠。

状态管理

状态管理是Direct3D编程的基本要求,并且对性能尤为重要。在任何给定时间调用Draw*时,都需要在渲染管线上设置该绘制所需的所有状态,但您确实希望最大程度地减少更改状态以提高性能的次数。

实用程序库(例如 DirectX Tool Kit )中确实存在用于状态管理的三种基本策略:

  1. 捕获并恢复所有状态。这是已弃用的ID3DXFont库中的Direct3D 9时代的传统D3DX9代码的作用。在Direct3D 9中,这最初是通过运行时跟踪当前状态的事实来实现的。专门引入了“ PURE”设备以尝试消除这种开销,因此添加了状态块作为尝试使其工作的方式。 Direct3D 11中的状态向量也很大,并且运行时不以相同的方式支持“状态块”。总体而言,这种方法超级易于使用,但永远不会很快。

  2. 设置所有必需状态,然后清除使用状态。另一种选择是每次使用SpriteBatch::Begin之类的任何辅助功能时都设置所有状态,然后在调用SpriteBatch::End时清除其使用的任何状态值。从概念上讲,这种方法再简单不过了,因为它没有挥之不去的副作用,但是在实践中它也很慢,因为有很多额外的调用来设置空状态。

  3. 设置所需状态,稍后让我们绘制清理状态。这是 DirectX Tool Kit 使用的选项。我设置需要绘制的状态,然后不理会它。如果在框架结尾之前调用我的代码后还有其他工作要做,则需要进行设置。实际上, DirectX Tool Kit 中的助手只使用了基本上所有图形都通用的标准状态,但是如果您不知道这种行为,则肯定会得到一些奇怪的交互。例如,如果在调用SpriteBatch之前已设置了Geometry Shader,则在调用End时会发生奇怪的事情。我假设,如果您使用的不是常规的VS / PS组合,则在调用我的代码之前先清除它。我在Wiki上记录了每个助手所使用的所有状态,并且在实践中,即使有时确实会使人们感到困惑,但这还是性能和可预测行为的良好平衡。

Direct3D 11与Direct3D 12注释

在Direct3D 11中,在调用Present时在帧末尾设置的任何状态仍会在下一帧的开始处设置,因此您会看到一些较早的教程在开始前先设置了一些状态渲染循环并假定保持不变。对于Direct3D 12,在Present中完全重置了状态,这是不正确的。因此,养成每帧设置所有状态的习惯要好得多。验证您是否正确执行此操作的一种方法是在每个帧ClearState之后立即调用Present,尽管您可能只想在Debug版本中执行此操作,否则浪费时间,否则在正确编写的程序中

在Direct3D 11中,调用RSSetViewports来设置视口也会将剪切剪刀矩形初始化为相同的值。在Direct3D 12中,您需要通过调用RSSetScissorRects来明确地执行此操作,否则最终会出现一个(0,0,0,0)剪切矩形,该矩形会剪切掉所有内容。

有关这些基本渲染循环的示例,请参见GitHub