Как лучше организовать постоянные буферы - PullRequest
0 голосов
/ 22 апреля 2020

У меня возникли проблемы, когда я не могу понять, как организовать постоянные буферы в очень простом c движке D3D11, который я делаю.

Мой главный вопрос: где происходит наибольшее снижение производительности? При использовании Map / Unmap для обновления данных буфера или при связывании самих cbuffers?

В настоящий момент я выбираю следующие две реализации для своего рода класса "shader-wrapper":

Содержит массив из 14 ID3D11Buffer * s

class VertexShader
{
...

public:
    Bind(context)
    {
        // Bind all 14 buffers at once
        context->VSSetConstantBuffers(0, 14, &m_ppCBuffers[0]);
        context->VSSetShader(pVS, nullptr, 0);
    }

    // Set the data for a buffer in a particular slot
    SetData(slot, size, pData)
    {
        D3D11_MAPPED_SUBRESOURCE mappedBuffer = {};
        context->Map(buffers[slot], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedBuffer);
        memcpy(mappedBuffer.pData, pData, size);
        context->Unmap(buffers[slot], 0);
    }


private:
    ID3D11Buffer*       buffers[14];
    ID3D11VertexShader* pVS;
}

При таком подходе шейдер связывает все cbuffers в одной партии из 14. Если шейдер имеет cbuffers, зарегистрированные в b0, b1, b3 массив будет выглядеть -> [cb | cb | 0 | cb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0]

Обертка Constant Buffer, которая знает, как связать себя

class VertexShader
{
...

public:
    Bind(context)
    {
        // all the buffers bind themselves
        for(auto cb : bufferMap)
            cb->Bind(context);

        context->VSSetShader(pVS, nullptr, 0);
    }

    // Set the data for a buffer with a particular ID
    SetData(std::string, size, pData)
    {
        // table lookup into bufferMap, then Map/Unmap
    }


private:
    std::unordered_map<std::string, ConstantBuffer*> bufferMap;
    ID3D11VertexShader* pVS;
}

Этот подход будет содержать «ConstantBuffers» в таблице ha sh, каждый из которых будет знать, к какому слоту он привязан и как связать себя с конвейером. Мне бы пришлось вызывать VSSetConstantBuffers () индивидуально для каждого cbuffer, поскольку ID3D11Buffer * s больше не будет смежным, но организация более дружелюбная и имеет немного меньше потраченного пространства.

Как бы вы обычно организовывали отношения между CBuffers, Shaders, SRV, et c? Не ищу универсального решения, но некоторые общие советы и вещи, о которых можно узнать больше от людей, которые, я надеюсь, более опытны, чем я

Кроме того, если @Chuck Walbourn увидит это, я фанат вашей работы и используя DXTK / WiCTextureLoader для этого проекта!

Спасибо.

1 Ответ

0 голосов
/ 23 апреля 2020

Постоянные буферы были главной особенностью Direct3D 10, поэтому один из лучших докладов на эту тему был возвращен на Gamefest 2007:

Windows в Reality: получение максимальной отдачи от Графика Direct3D 10 в ваших играх

См. Также Почему обновление постоянных буферов может быть мучительно медленным? (NVIDIA)

Первоначально предполагалось, что CB будут организованы по частоте обновления: что-то вроде одного CB для материала, который установлен «на уровень», другого для материала «на кадр», другого для «за объект», еще один «за проход» и т. д. c. Следовательно, предполагается, что если вы изменили какую-либо часть CB, вы собирались загрузить все это. Пропускная способность между процессором и графическим процессором является настоящим узким местом.

Чтобы этот подход был эффективным, вам, в основном, необходимо настроить все ваши шейдеры на использование одной и той же схемы. Это может быть трудно управляемым, особенно когда так много современных систем материалов основано на искусстве.

Другой подход к CB - использовать их как динамический c VB для подачи частиц, когда вы заполняете их короткими Выжившие константы, отправьте работу, а затем сбросьте вещь в каждом кадре. Этот подход в основном то, что люди делают для DirectX 12 во многих случаях. Проблема в том, что без возможности обновлять части CB, это слишком медленно. Дополнительные функции «частичного обновления буфера и смещения буфера» в DirectX 11.1 были способом заставить эту работу работать. Тем не менее, эта функция не поддерживается в Windows 7 и является «необязательной» в более новых версиях Windows, так что вы чтобы использовать его, необходимо поддерживать два кодовых пути.

TL; DR: технически можно связать сразу несколько CB, но главное, чтобы размер отдельного файла был небольшим для которые часто меняются. Также предположим, что любое изменение в CB потребует обновления всего графического процессора каждый раз, когда вы меняете его.

...