Буферы - индексированные или прямые, чересстрочные или отдельные

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

Я ищу некоторые распространенные quidelines - некоторые случаи, когда одно или наоборот подходит лучше, но не все случаи легко разрешимы. Что нужно иметь в виду при выборе формата буфера вершин при нацеливании на производительность?

Ссылки на веб-ресурсы по этой теме также приветствуются.

Ответ 1

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

Индексированный и прямой рендеринг

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

Кроме того, вы, скорее всего, сохраните хранилище, индекс может быть как можно меньше (1 байт, 2 байт), и вы можете повторно использовать полную спецификацию вершин. Предположим, что вершина и все атрибуты содержат около 30 байтов данных, и вы делитесь этой вершиной над двумя слоями. При индексированном рендеринге (2 байтовых индекса) это будет стоить вам 2*index_size+attribute_size = 34 byte. При неиндексированном рендеринге это будет стоить вам 60 байт. Часто ваши вершины будут использоваться более двух раз.

Всегда ли рендеринг на основе индексов лучше? Нет, могут быть сценарии, где это хуже. Для очень простых приложений может оказаться нецелесообразным накладные расходы кода для создания модели данных на основе индексов. Кроме того, когда ваши атрибуты не распределяются по многоугольникам (например, обычный для полигона вместо per-vertex), скорее всего, не будет общего обмена вершинами, и IBO не даст преимущества, только накладные расходы.

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

чередование против неперемещающегося vs buffer per-attribute

Эта история немного более тонкая, и я думаю, что это сводится к взвешиванию некоторых свойств ваших атрибутов.

  • Interleaved может быть лучше, потому что все атрибуты будут близки друг к другу и, вероятно, будут в нескольких кешках памяти (возможно, даже в одном). Очевидно, что это может означать лучший результат. Однако в сочетании с рендерингом на основе индексирования ваш доступ к памяти в любом случае является довольно случайным, и преимущество может быть меньше, чем вы ожидали.
  • Знайте, какие атрибуты являются статическими и динамическими. Если у вас есть 5 атрибутов, из которых 2 полностью статичны, 1 изменяется каждые 15 минут и 2 каждые 10 секунд, подумайте о том, чтобы положить их в 2 или 3 отдельных буфера. Вы не хотите повторно загружать все 5 атрибутов каждый раз, когда эти 2 наиболее частое изменение.
  • Учитывайте, что атрибуты должны быть выровнены по 4 байтам. Поэтому вам может потребоваться время от времени чередовать еще один шаг. Предположим, у вас есть 1-байтовый атрибут vec3 и некоторый скалярный 1-байтовый атрибут, наивно для этого потребуется 8 байт. Вы можете получить много, объединив их в один vec4, что должно сократить использование до 4 байтов.
  • Воспроизведение с размером буфера, слишком большим буфером или слишком большим количеством небольших буферов может повлиять на производительность. Но это, вероятно, очень зависит от реализации оборудования, драйвера и OpenGL.

Ответ 2

Индексированный vs Прямой

Посмотрите, что вы получаете, индексируя. Каждая повторяющаяся вершина, т.е. Вершина с "гладким" перерывом, будет стоить вам меньше. Каждая особая вершина "ребра" будет стоить вам больше. Для данных, основанных на реальном мире и относительно плотных, одна вершина будет принадлежать многим треугольникам, и, следовательно, индексы ускорят ее. Для условно генерируемых произвольных данных прямой режим обычно будет лучше.

Индексированные буферы также добавляют дополнительные сложности к коду.

Interleaved vs Separate

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