Если мои позиции вершин являются общими, а мои нормали и UV — нет (для сохранения жестких краев и тому подобного), можно ли использовать не чередующиеся буферы в DirectX11 для решения этого представления памяти, чтобы я мог использовать с ним индексный буфер ? Или я должен придерживаться дублированных позиций вершин в чередующемся буфере?
И есть ли проблемы с производительностью между чередующимися и не чередующимися буферами вершин? Спасибо!
Есть несколько способов. Я опишу самый простой.
Просто создайте отдельные вершинные буферы:
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 МБ каждая? Мы не знаем
Это все зависит от вас, чтобы решить. Но помните: бесплатных конфет нет. Если вы обнаружите, что экономия памяти стоит потери производительности, сделайте это. Профиль и сравнить, чтобы быть уверенным.
Надеюсь, это поможет как-то. Удачного кодирования! знак равно
Interleaved / Separate будет в основном влиять на вашу стадию Input Assembler (сторона GPU).
Идеальный сценарий для Interleaved — это когда ваша буферная память идеально подходит для ввода вершинного шейдера. Таким образом, ваш входной ассемблер может просто получить данные.
В этом случае вы будете в полном порядке с чередованием, даже если тестирование выполняется с большой моделью (две версии одних и тех же данных, одно чередование, одно отдельное), запрос TimeStamp не выявил каких-либо существенных различий (некоторые довольно минимальные обработка вершин и базовый пиксельный шейдер).
Теперь наличие отдельных буферов значительно упрощает настройку, если вы используете свою геометрию в разных контекстах.
Допустим, у вас есть Position / Normals / UV (как в вашем случае).
Теперь у вас также есть шейдер в конвейере, который требует только Position (Shadow Map был бы довольно хорошим примером).
С помощью отдельных буферов вы можете просто создать новый входной макет, который содержит только положение, и вместо этого связать этот буфер. Ваш этап IA должен только
загрузить этот буфер. Лучше всего вы даже можете сделать это динамически, используя шейдерное отражение.
Если вы связываете данные с чередованием, вы будете иметь некоторые издержки из-за того, что они должны загружаться с ходу.
Когда я тестировал это, у меня было около 20% прироста с использованием Separate вместо Interleaved, что может быть вполне прилично, но, поскольку этот тип обработки может в значительной степени зависеть от архитектуры, не принимайте это как должное (NVidia 740M для тестирования).
Проще говоря, профилируйте (много) и проверьте, что дает вам лучший баланс между загрузкой вашего GPU и CPU.
Также обратите внимание, что накладные расходы от Input Assembler уменьшатся от сложности вашего шейдера. Если вы примените некоторые тяжелые вычисления + добавите немного тесселяции + немного приличного затенения, разница во времени между чередованным / не чередующимся будет постепенно становиться бессмысленной.
Вы должны придерживаться чередующихся буферов. Любой другой метод потребует некоторой формы косвенного обращения к вашему недублированному буферу позиции, что будет стоить вам производительности и эффективности кэширования.