Ассемблер прямого ввода X — ошибка компоновки вершинных шейдеров

#c #shader #directx #hlsl

#c #шейдер #directx #hlsl

Вопрос:

Я изучаю Direct X и пытаюсь нарисовать базовый треугольник на экране. У меня есть простой вершинный шейдер и пиксельный шейдер.

Вершинный шейдер:

 float4 main( float2 pos : POSITION) : SV_Position
{
    return float4(pos.x,pos.y,0.0f,1.0f);
}
 

Пиксельный шейдер:

 float4 main() : SV_Target
{
    return float4(1.0f,1.0f,1.0f,1.0f);
}
 

При запуске программы я получаю ошибку привязки между входным ассемблером и вершинным шейдером:

 Error: ID3D11DeviceContext::Draw: 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.
 

Мой код рендеринга:

 void renderer_draw_triangle()
{
    struct vertex
    {
        float x;
        float y;
    };

    const struct vertex vertices[] =
        {
            {0.0f, 0.5f},
            {0.5f, -0.5f},
            {-0.5f, -0.5f},
        };

    const UINT stride = sizeof(struct vertex);
    const UINT offset = 0u;

    ID3D11Buffer *vertex_buffer;
    D3D11_BUFFER_DESC bd = {
        .BindFlags = D3D11_BIND_VERTEX_BUFFER,
        .Usage = D3D11_USAGE_IMMUTABLE,
        .CPUAccessFlags = 0u,
        .MiscFlags = 0u,
        .ByteWidth = sizeof(vertices),
        .StructureByteStride = stride};
    D3D11_SUBRESOURCE_DATA sd = {.pSysMem = vertices};

    CHECK_ERROR(device->lpVtbl->CreateBuffer(device, amp;bd, amp;sd, amp;vertex_buffer));
    context->lpVtbl->IASetVertexBuffers(context, 0u, 1u, amp;vertex_buffer, amp;stride, amp;offset);

    ID3D11VertexShader *vertexShader;
    ID3DBlob *blob;
    CHECK_DX_ERROR(D3DReadFileToBlob(L"../Engine/build/shaders/VertexShader.cso", amp;blob));
    CHECK_DX_ERROR(device->lpVtbl->CreateVertexShader(device, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), NULL, amp;vertexShader));

    context->lpVtbl->VSSetShader(context, vertexShader, NULL, 0u);

    ID3D11PixelShader *pixelShader;
    CHECK_DX_ERROR(D3DReadFileToBlob(L"../Engine/build/shaders/PixelShader.cso", amp;blob));
    CHECK_DX_ERROR(device->lpVtbl->CreatePixelShader(device, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), NULL, amp;pixelShader));

    context->lpVtbl->PSSetShader(context, pixelShader, NULL, 0u);

    ID3D11InputLayout *input_layout;
    const D3D11_INPUT_ELEMENT_DESC inputs[] =
        {
            {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        };

    CHECK_DX_ERROR(device->lpVtbl->CreateInputLayout(device, inputs, ASIZE(inputs), blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), amp;input_layout));

    CHECK_DX_ERROR(context->lpVtbl->IASetInputLayout(context, input_layout));

    context->lpVtbl->OMSetRenderTargets(context, 1u, amp;target, NULL);

    context->lpVtbl->IASetPrimitiveTopology(context, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    D3D11_VIEWPORT vp = {.Width = 800, .Height = 600, .MinDepth = 0, .MaxDepth = 1, .TopLeftX = 0, .TopLeftY = 0};
    context->lpVtbl->RSSetViewports(context, 1u, amp;vp);

    CHECK_DX_ERROR(context->lpVtbl->Draw(context, ASIZE(vertices), 0u));
}
 

В нем говорится, что он не может найти семантику во входном слое, но я перечитал код миллион раз и не могу понять, что происходит не так. Семантика, очевидно, находится в массиве описания входного элемента. Я почти уверен, что входной слой привязан правильно. Кто-нибудь может помочь?

Комментарии:

1. У вас нет ввода в ваш пиксельный шейдер. Это, вероятно, решило бы float4 main(float4 pos) : SV_Target проблему. Обычно для отправки данных из вершинного шейдера в пиксельный шейдер используется структура, определенная в .hlsli файле, который включен обоими шейдерами.

Ответ №1:

POSITION является устаревшим именем Direct3D 9 и SV_Position является семантическим Direct3D 10 . Вы можете использовать любой из них, но вы должны быть последовательными.

IOW: если вы используете SV_Position в шейдере (что предпочтительнее), то вам нужно использовать SV_Position в D3D11_INPUT_ELEMENT_DESC структуре макета ввода.

Комментарии:

1. Это все еще не работает. Вместо того, чтобы указывать, что семантическая ПОЗИЦИЯ не найдена, говорится, что семантическая SV_Position не найдена.

Ответ №2:

Оказывается, мне пришлось создать пиксельный шейдер перед вершинным шейдером. Я не совсем уверен, почему, но это работает.

 void renderer_draw_triangle()
{
    struct vertex
    {
        float x;
        float y;
    };

    const struct vertex vertices[] =
        {
            {0.0f, 0.5f},
            {0.5f, -0.5f},
            {-0.5f, -0.5f},
        };

    const UINT stride = sizeof(struct vertex);
    const UINT offset = 0u;

    ID3D11Buffer *vertex_buffer;
    D3D11_BUFFER_DESC bd = {
        .BindFlags = D3D11_BIND_VERTEX_BUFFER,
        .Usage = D3D11_USAGE_IMMUTABLE,
        .CPUAccessFlags = 0u,
        .MiscFlags = 0u,
        .ByteWidth = sizeof(vertices),
        .StructureByteStride = stride};
    D3D11_SUBRESOURCE_DATA sd = {.pSysMem = vertices};

    CHECK_ERROR(device->lpVtbl->CreateBuffer(device, amp;bd, amp;sd, amp;vertex_buffer));
    context->lpVtbl->IASetVertexBuffers(context, 0u, 1u, amp;vertex_buffer, amp;stride, amp;offset);

    ID3DBlob *blob;

    ID3D11PixelShader *pixelShader;
    CHECK_DX_ERROR(D3DReadFileToBlob(L"../Engine/build/shaders/PixelShader.cso", amp;blob));
    CHECK_DX_ERROR(device->lpVtbl->CreatePixelShader(device, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), NULL, amp;pixelShader));
    
    context->lpVtbl->PSSetShader(context, pixelShader, NULL, 0u);

    ID3D11VertexShader *vertexShader;
    CHECK_DX_ERROR(D3DReadFileToBlob(L"../Engine/build/shaders/VertexShader.cso", amp;blob));
    CHECK_DX_ERROR(device->lpVtbl->CreateVertexShader(device, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), NULL, amp;vertexShader));

    context->lpVtbl->VSSetShader(context, vertexShader, NULL, 0u);

    ID3D11InputLayout *input_layout;
    const D3D11_INPUT_ELEMENT_DESC inputs[] =
        {
            {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        };

    CHECK_DX_ERROR(device->lpVtbl->CreateInputLayout(device, inputs, ASIZE(inputs), blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), amp;input_layout));

    CHECK_DX_ERROR(context->lpVtbl->IASetInputLayout(context, input_layout));

    context->lpVtbl->OMSetRenderTargets(context, 1u, amp;target, NULL);

    context->lpVtbl->IASetPrimitiveTopology(context, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    D3D11_VIEWPORT vp = {.Width = 800, .Height = 600, .MinDepth = 0, .MaxDepth = 1, .TopLeftX = 0, .TopLeftY = 0};
    context->lpVtbl->RSSetViewports(context, 1u, amp;vp);

    CHECK_DX_ERROR(context->lpVtbl->Draw(context, ASIZE(vertices), 0u));
}