Буферы без чередования вершин DirectX11

Если мои позиции вершин являются общими, а мои нормали и UV — нет (для сохранения жестких краев и тому подобного), можно ли использовать не чередующиеся буферы в DirectX11 для решения этого представления памяти, чтобы я мог использовать с ним индексный буфер ? Или я должен придерживаться дублированных позиций вершин в чередующемся буфере?

И есть ли проблемы с производительностью между чередующимися и не чередующимися буферами вершин? Спасибо!

2

Решение

Как

Есть несколько способов. Я опишу самый простой.

Просто создайте отдельные вершинные буферы:

ID3D11Buffer* positions;
ID3D11Buffer* texcoords;
ID3D11Buffer* normals;

Создание входных элементов макета, увеличение InputSlot член для каждого компонента:

{ "POSITION",  0,  DXGI_FORMAT_R32G32B32_FLOAT,  0, 0,                            D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD",  0,  DXGI_FORMAT_R32G32_FLOAT,     1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL",    0,  DXGI_FORMAT_R32G32B32_FLOAT,  2, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
//  ^
// InputSlot

Привязать буферы к их слотам (лучше всего за один выстрел):

ID3D11Buffer** vbs = {positions, texcoords, normals};
unsigned int strides[] = { /*strides go here*/ };
unsigned int offsets [] = { /*offsets go here*/ };
m_Context->IASetVertexBuffers(0, 3, vbs, strides, offsets );

Нарисуй как обычно.
Вам не нужно менять код HLSL (HLSL будет думать, так как он имеет один буфер).

Обратите внимание, что фрагменты кода были написаны на лету и могут содержать ошибки.

Изменить: вы можете улучшить этот подход, комбинируя буферы по частоте обновления: если texcoords а также normals никогда не менялся, объединяй их.

По производительности

Это все о местность ссылок: чем ближе данные, тем быстрее доступ.

Чередующийся буфер, в большинстве случаев, обеспечивает (безусловно) большую производительность для стороны графического процессора (т.е. рендеринг): для каждой вершины каждый атрибут находится рядом друг с другом. Но отдельные буферы обеспечивают более быстрый доступ к процессору: массивы являются смежными, каждая следующая информация находится рядом с предыдущей.

Итак, в целом проблемы производительности зависят от того, как часто вы пишете в буферы. Если вашим ограничивающим фактором является запись в CPU, придерживайтесь отдельных буферов. Если нет, перейдите на один.

Как ты узнаешь? Только один путь — профиль. Как на стороне процессора, так и на стороне GPU (через графический отладчик / профилировщик от производителя вашего GPU).

Другие факторы

Рекомендуется ограничить число операций записи в ЦП, поэтому, если вы обнаружите, что ограничены обновлением буфера, вам, вероятно, необходимо пересмотреть свой подход. Нужно ли обновлять буфер каждого кадра, если у нас 500 кадров в секунду? Пользователь не увидит разницы, если вы уменьшите частоту обновления буфера до 30-60 раз в секунду (отсоедините обновление буфера от обновления кадра). Таким образом, если ваша стратегия обновления разумна, вы, вероятно, никогда не будете ограничены ЦП, и лучший подход — это классическое чередование.

Вы также можете подумать о перепроектировании вашего конвейера данных или даже как-то подготовить данные в автономном режиме (мы называем это «выпечкой»), поэтому вам не нужно будет справляться с не чередующимися буферами. Это будет вполне разумно.

Уменьшить объем памяти или увеличить производительность?

Соотношение памяти к производительности. Это вечный вопрос. Двойная память, чтобы воспользоваться преимуществами чередования? Или нет?

Ответ … «это зависит». Вы программируете новый CryEngine, ориентируясь на топовые графические процессоры с гигабайтами памяти? Или вы программируете для встраиваемых систем мобильной платформы, где ресурсы памяти медленны и ограничены? 1 мегабайт памяти стоит хлопот вообще? Или у вас огромные модели по 100 МБ каждая? Мы не знаем

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

Надеюсь, это поможет как-то. Удачного кодирования! знак равно

10

Другие решения

Interleaved / Separate будет в основном влиять на вашу стадию Input Assembler (сторона GPU).

Идеальный сценарий для Interleaved — это когда ваша буферная память идеально подходит для ввода вершинного шейдера. Таким образом, ваш входной ассемблер может просто получить данные.

В этом случае вы будете в полном порядке с чередованием, даже если тестирование выполняется с большой моделью (две версии одних и тех же данных, одно чередование, одно отдельное), запрос TimeStamp не выявил каких-либо существенных различий (некоторые довольно минимальные обработка вершин и базовый пиксельный шейдер).

Теперь наличие отдельных буферов значительно упрощает настройку, если вы используете свою геометрию в разных контекстах.

Допустим, у вас есть Position / Normals / UV (как в вашем случае).

Теперь у вас также есть шейдер в конвейере, который требует только Position (Shadow Map был бы довольно хорошим примером).

С помощью отдельных буферов вы можете просто создать новый входной макет, который содержит только положение, и вместо этого связать этот буфер. Ваш этап IA должен только
загрузить этот буфер. Лучше всего вы даже можете сделать это динамически, используя шейдерное отражение.

Если вы связываете данные с чередованием, вы будете иметь некоторые издержки из-за того, что они должны загружаться с ходу.

Когда я тестировал это, у меня было около 20% прироста с использованием Separate вместо Interleaved, что может быть вполне прилично, но, поскольку этот тип обработки может в значительной степени зависеть от архитектуры, не принимайте это как должное (NVidia 740M для тестирования).

Проще говоря, профилируйте (много) и проверьте, что дает вам лучший баланс между загрузкой вашего GPU и CPU.

Также обратите внимание, что накладные расходы от Input Assembler уменьшатся от сложности вашего шейдера. Если вы примените некоторые тяжелые вычисления + добавите немного тесселяции + немного приличного затенения, разница во времени между чередованным / не чередующимся будет постепенно становиться бессмысленной.

1

Вы должны придерживаться чередующихся буферов. Любой другой метод потребует некоторой формы косвенного обращения к вашему недублированному буферу позиции, что будет стоить вам производительности и эффективности кэширования.

0
По вопросам рекламы [email protected]