OpenGL лучше использовать пакетный розыгрыш или иметь статические VBO - PullRequest
18 голосов
/ 24 сентября 2011

Что предпочтительнее с точки зрения эффективности (или с другой точки зрения, если это важно)?

Положение
Приложение OpenGL, которое рисует много линий в разных позициях каждый кадр (60 кадров в секунду). Допустим, есть 10 строк. Или 100 000 строк. Будет ли другой ответ?

  • # 1 Иметь статическое VBO, которое никогда не меняется, содержащее 2 вершины линии

Каждый кадр будет иметь один вызов glDrawArrays для каждой линии для рисования, и между ними будут матричные преобразования для позиционирования нашей одной строки

  • # 2 Обновление VBO с данными для всех строк каждого кадра

Каждый кадр будет иметь один колл-вызов

1 Ответ

28 голосов
/ 24 сентября 2011

Второй невероятно эффективнее.

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

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

При использовании современного видеооборудования на довольно большой полосе пропускания передача нескольких потоков является тривиальной. Они предназначены для быстрого перемещения тонны данных, это побочный эффект работы. Обновление вершинных буферов - это именно то, что они делают часто и быстро. Если мы предположим, что у каждого по 32 байта (позиция и цвет float4), 100000 линейных сегментов меньше 6 МБ, а PCIe 2.0 x16 - около 8 ГБ / с, я полагаю.

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

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

В качестве очень ясного примера рассмотрим лучший вариант для # 1: набор преобразований не вызывает дополнительных вычислений, а драйвер буферизует усердно и идеально. Чтобы нарисовать 100000 линий, вам нужно:

  • 100000 матричных наборов (в системной памяти)
  • 100000 вызовов набора матриц с накладными расходами вызовов функций (для видеодрайвера, копирование матрицы в буфер)
  • 100000 матриц, скопированных в ОЗУ видео, выполненных за один прием
  • 100000 звонков на линии

Только накладные расходы на вызов функции приведут к уничтожению производительности.

С другой стороны, пакетирование включает в себя:

  • 100000 точечных вычислений и наборов в оперативной памяти системы
  • 1 VBO скопировать в видео RAM. Это будет большой кусок, но один непрерывный кусок, и обе стороны знают, чего ожидать. С ним можно хорошо обращаться.
  • 1 матричный набор вызовов
  • 1 матричная копия в видео ОЗУ
  • 1 розыгрыш

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

1

for (i = 0; i < 100000; ++i)
{
    matrix = calcMatrix(i);
    setMatrix(matrix);
    drawLines(1, vbo);
}

(теперь разверните это)

* 2 * тысяча сорок-девять:
matrix = calcMatrix();
setMatrix(matrix);
for (i = 0; i < 100000; ++i)
{
    localVBO[i] = point[i];
}
setVBO(localVBO);
drawLines(100000, vbo);
...