【问题标题】:Input Assembler - Vertex Shader Linkage error输入汇编器 - 顶点着色器链接错误
【发布时间】:2019-06-26 08:34:06
【问题描述】:

我正在尝试使用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 & Device,但仍然出现同样的错误。

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

我尝试过使用不同的设备和 DeviceContext,但仍然是同样的错误。


我一直在尝试许多不同的方法来让它发挥作用。 这就是我的渲染函数目前的样子

更新日期:2019 年 2 月 18 日

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]

【问题讨论】:

  • 在您单步执行此代码时,哪一行正在生成调试输出?可能您的渲染代码的另一部分还存在其他一些状态,但上面的特定代码实际上应该按照 DirectX 工具包 tutorial 工作。有关状态 SpriteBatch 使用的完整列表,请参阅 wiki
  • 问题似乎是在绘制立方体时发生错误。 spriteBatch 函数似乎导致着色器链接器错误。 g_pImmediateContext-&gt;DrawIndexed(36, 0, 0);此行出现错误。
  • 在绘制立方体时,是否设置了所有需要的状态?您可能缺少匹配立方体所需的输入布局或顶点着色器。
  • 在渲染中没有精灵绘制函数的情况下,立方体可以很好地绘制:spriteBatch-&gt;Begin(); spriteFont-&gt;DrawString(spriteBatch.get(), L"TEXT PLACEHOLDER", XMFLOAT2(1.0f, 1.0f)); spriteBatch-&gt;End(); 这会删除设置/状态,因此需要再次设置输入布局和顶点缓冲区。我也将一些状态转移到了渲染函数中。虽然这有效,但 FPS 似乎下降了。在场景中有两个立方体时,深度缓冲区似乎停止工作,其中立方体 2 似乎总是与立方体 1 重叠。
  • 是的,你需要在绘制之前设置所有需要的状态。上面文档的链接列出了SpriteBatch 更改的所有状态,其中包括任何绘图都需要的输入布局和顶点着色器。一般来说,您不应该假设设置了任何状态,并且在帧的开头设置了渲染目标和视口/剪刀。然后在每次绘制调用之前,您可以更改所需的任何状态。旧版ID3DXFont 所做的“捕获和恢复”状态非常缓慢。

标签: c++ directx directxtk


【解决方案1】:

TL;DR:在调用Draw之前,您需要在每帧设置立方体的输入布局、顶点着色器和像素着色器。

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

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

您的评论包括导致您首先将其注释掉的调试设备错误。很明显,您的错误实际上是您在没有将 D3D11_BUFFER_DESC.BindFlags 设置为 D3D11_BIND_VERTEX_BUFFER 的情况下为 VB 调用 CreateBuffer 的地方。

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

通过调用SpriteFont::Begin/End 更改的确切状态记录在wiki 中。特别是,它改变了输入布局和顶点着色器。您的“立方体绘图”代码依赖于这些状态在每帧之间保持不变,这实际上只适用于微不足道的情况。

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

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

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

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

DirectX Tool Kit 包含许多帮助程序,例如 CommonStateEffects,以使其更易于管理,但您仍然必须确保设置了您所依赖的 all 状态。

状态管理

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

DirectX Tool Kit 等实用程序库中的状态管理实际上有三种基本策略:

  1. 捕获并恢复所有状态。这就是已弃用的 D3DX9 库中的旧版 Direct3D 9 时代 ID3DXFont 代码所做的。在 Direct3D 9 中,这最初是通过运行时跟踪当前状态来实现的。专门引入了“PURE”设备来尝试消除这种开销,因此添加了状态块作为尝试使其工作的一种方式。 Direct3D 11 中的状态向量也相当大,并且运行时不以同样的方式支持“状态块”。总的来说,这种方法非常易于使用,但速度并不快。

  2. 设置所有需要的状态,之后清除使用的状态。另一种选择是每次使用任何辅助函数(如SpriteBatch::Begin)时设置所有状态,然后在调用SpriteBatch::End 时清除它使用的任何状态值。这种方法在概念上也很简单,因为没有挥之不去的副作用,但在实践中也很慢,因为设置 null 状态有很多额外的调用。

  3. 设置所需状态,让稍后绘制清理状态。这是 DirectX Tool Kit 使用的选项。我设置了我需要绘制的状态,然后不管它。如果在帧结束之前调用我的代码后还有更多绘图要做,则需要设置它们。在实践中,DirectX Tool Kit 中的助手只使用了基本所有绘图共有的标准状态,但如果您不知道这种行为,您肯定会遇到一些奇怪的交互。例如,如果您在调用SpriteBatch 之前设置了几何着色器,那么当您调用End 时会发生奇怪的事情。我假设如果您使用的东西超出了通常的 VS/PS 组合,您在调用我的代码之前清除了它。我在 wiki 上记录了每个助手使用的所有状态,实际上这是性能和可预测行为之间的良好平衡,尽管它有时会让人感到困惑。

Direct3D 11 与 Direct3D 12 的注意事项

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

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

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

【讨论】:

  • 我'认为'我已经设法让 SpriteFont 正常工作,但在尝试渲染我设置的立方体时似乎会导致错误。我已经移动了某些代码部分以查看它们的顺序,但我似乎无法完全解决它。
  • 在调用 Draw* 获取多维数据集代码之前,请确保已设置 all 状态。
  • 我很确定我在Draw* 代码之前设置了所有状态。我已经在我的第一篇文章中发布了我的渲染函数,代码中的 cmets 似乎会导致问题。
  • 不,您注释掉了对IASetVertexBuffers 的调用,这是问题所在。您也没有设置OMSetBlendStateOMSetDepthStencilState。进行清除时,每帧调用 OMSetRenderTargetsRSSetViewports 也是一个好习惯。
  • 我听取了您的建议并尝试设置所有状态(我希望如此)。但我仍然收到错误/警告。我已经用更新的代码和错误再次更新了我的第一篇文章。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-11
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 2017-12-14
  • 1970-01-01
相关资源
最近更新 更多