Когда VBO быстрее, чем простые примитивы OpenGL (glBegin())?

После многих лет прослушивания об объектах Vertex Buffer Objects (VBO) я, наконец, решил поэкспериментировать с ними (очевидно, мои вещи обычно не критичны к производительности...)

Я опишу свой эксперимент ниже, но, если коротко, я наблюдаю неразличимую производительность между «простым» прямым режимом (glBegin()/glEnd()), массивом вершин (на стороне процессора) и VBO (на стороне графического процессора). режимы рендеринга. Я пытаюсь понять, почему это так, и при каких условиях я могу ожидать, что VBO значительно затмят своих примитивных (каламбур) предков.

Детали эксперимента

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

Для прямого рендеринга весь набор данных визуализируется в одном блоке glBegin()/glEnd() с циклом, содержащим по одному вызову glColor3fv() и glVertex3fv().

Для рендеринга массива вершин и VBO весь набор данных визуализируется одним вызовом glDrawArrays().

Затем я просто запускаю его на минуту или около того в узком цикле и измеряю средний FPS с помощью высокопроизводительного таймера.

Результаты производительности ##

Как упоминалось выше, производительность была одинаковой как на моем настольном компьютере (XP x64, 8 ГБ ОЗУ, 512 МБ Quadro 1700), так и на моем ноутбуке (XP32, 4 ГБ ОЗУ, 256 МБ Quadro NVS 110). Однако он масштабировался, как и ожидалось, с количеством баллов. Очевидно, я также отключил vsync.

Конкретные результаты запуска ноутбука (рендеринг с GL_POINTS):

glBegin()/glEnd():

  • 1К очков --> 603 FPS
  • 10 000 баллов --> 401 кадр/с
  • 100 000 баллов --> 97 кадров в секунду
  • 1 млн баллов --> 14 кадров в секунду

Массивы вершин (сторона процессора):

  • 1К очков --> 603 FPS
  • 10 000 баллов --> 402 кадр/с
  • 100 000 баллов --> 97 кадров в секунду
  • 1 млн баллов --> 14 кадров в секунду

Объекты буфера вершин (сторона графического процессора):

  • 1К очков --> 604 FPS
  • 10 000 баллов --> 399 кадров в секунду
  • 100 000 баллов --> 95 кадров в секунду
  • 1 млн баллов --> 14 кадров в секунду

Я визуализировал те же данные с помощью GL_TRIANGLE_STRIP и получил такие же неразличимые (хотя и медленнее, чем ожидалось, из-за дополнительной растеризации). Я тоже могу выложить эти номера, если кому надо. .

Вопросы)

  • Что дает?
  • Что мне нужно сделать, чтобы реализовать обещанный прирост производительности VBO?
  • Что мне не хватает?

person Drew Hall    schedule 10.01.2009    source источник
comment
Может быть, драйверы nVidia оптимизируют что-то за вашей спиной? Проблема в том, что невозможно проверить это изолированно...   -  person    schedule 10.01.2009
comment
Эта мысль пришла и мне. Я также подумал, что, возможно, Quadro против GeForce (то есть профессиональная карта против геймерской) может иметь какое-то отношение к этому.   -  person Drew Hall    schedule 11.01.2009
comment
Как они могут оптимизировать версию glBegin()/glEnd()? @Shy: Из любопытства, почему вы отредактировали вопрос? @Drew Hall: Не могли бы вы опубликовать где-нибудь программу или исходный код? Я хотел бы попробовать (и, возможно, понаблюдать за облаком минуту или две).   -  person aib    schedule 13.01.2009
comment
@aib: Извините, я бы хотел, но не могу опубликовать код. Я посмотрю, смогу ли я где-нибудь опубликовать исполняемый файл или хотя бы скриншот.   -  person Drew Hall    schedule 15.01.2009
comment
@Drew Hall: Неважно, в итоге я сам его построил :)   -  person aib    schedule 22.01.2009
comment
Вставьте код, который выполняет отрисовку — glBegin() и все, что происходит до glEnd() — и код, создающий VBO. Было бы неплохо добраться до сути этого, независимо от того, сколько ему лет.   -  person Will    schedule 14.04.2011
comment
Генерируется ли VBO один раз за кадр или один раз в начале программы? Я ожидал бы увидеть эти результаты, если бы вы перезагружали VBO (через glBufferData()) каждый кадр.   -  person OldPeculier    schedule 11.04.2012
comment
@OldPeculier: один раз, в начале программы.   -  person Drew Hall    schedule 11.04.2012


Ответы (5)


Оптимизация 3D-рендеринга зависит от множества факторов. обычно есть 4 узких места:

  • CPU (создание вершин, вызовы APU, все остальное)
  • Шина (передача CPU‹->GPU)
  • Vertex (вершинный шейдер поверх фиксированного выполнения конвейера функций)
  • Пиксель (заполнение, выполнение фрагментного шейдера и rops)

Ваш тест дает искаженные результаты, потому что у вас много ресурсов ЦП (и шины) при максимальной пропускной способности вершин или пикселей. VBO используются для снижения нагрузки на ЦП (меньше вызовов API, параллельных передачам ЦП DMA). Поскольку вы не привязаны к процессору, они не дают вам никакой выгоды. Это оптимизация 101. Например, в игре ЦП становится ценным, поскольку он необходим для других вещей, таких как ИИ и физика, а не только для выполнения множества вызовов API. Легко видеть, что запись данных вершины (например, 3 числа с плавающей запятой) непосредственно в указатель памяти выполняется намного быстрее, чем вызов функции, которая записывает в память 3 числа с плавающей запятой — по крайней мере, вы экономите циклы для вызова.

person starmole    schedule 10.01.2009
comment
Насколько я понимаю, Vertex Arrays (GL 1.1) использовались для снижения нагрузки на ЦП (минимизация вызовов функций), в то время как VBO, построенные на этом, также снижали активность шины. Я думал, что мой эксперимент будет привязан к шине (или процессору для простого рисования glBegin()), но, похоже, я ошибался. Можете ли вы прокомментировать? Спасибо! - person Drew Hall; 10.01.2009
comment
vbos снизит активность шины только в том случае, если ваша геометрия статична, то есть повторно используется в кадрах. также убедитесь, что вы отмечаете их запись только в этом случае. дальнейшее чтение: developer.nvidia.com/object/using_VBOs.html - person starmole; 14.01.2009
comment
@starmole: отличная ссылка. Я пометил VBO как STATIC_DRAW, но не пометил их как WRITE_ONLY (я не использовал glMapBuffer()). Я внесу изменения и посмотрю, что произойдет. Спасибо за совет! - person Drew Hall; 14.01.2009
comment
@starmole: я пробовал отображать как WRITE_ONLY (на самом деле пробовал все три режима) безрезультатно. Выполнил быструю карту/удаление карты сразу после glBufferData — правильно ли я сделал? До сих пор в замешательстве... :( - person Drew Hall; 14.01.2009
comment
@Дрю Холл: и результаты были? (увидев этот вопрос только что, сразу подумалось, что это классическая ошибка VBO, не отмеченная как статическая отрисовка) - person Will; 28.01.2011
comment
@Will: Без разницы, как бы я не устанавливал флаги. Я до сих пор не решил этот вопрос, поэтому до сих пор не принял ответ. - person Drew Hall; 28.01.2011
comment
@Дрю Холл: странно. Вот некоторые другие эмпирические меры в игровом движке, который оценивает переход от массивов вершин к VBO: noreferrer">glest.org/glest_board/index.php?topic=6260.msg65644#msg65644 - person Will; 28.01.2011

Может не хватать нескольких вещей:

  1. Это дикое предположение, но карта вашего ноутбука может вообще не выполнять такую ​​операцию (т. е. эмулировать ее).

  2. Вы копируете данные в память графического процессора (через glBufferData(GL_ARRAY_BUFFER с параметром GL_STATIC_DRAW или GL_DYNAMIC_DRAW) или используете указатель на основной (не графический) массив в памяти? (для этого требуется копировать его каждый кадр, и поэтому производительность низкая)

  3. Вы передаете индексы в качестве другого буфера, отправляемого через параметры glBufferData и GL_ELEMENT_ARRAY_BUFFER?

Если эти три вещи выполнены, прирост производительности будет большим. Для Python (v/pyOpenGl) это примерно в 1000 раз быстрее на массивах больше пары 100 элементов, C++ до 5 раз быстрее, но на массивах 50k-10m вершин.

Вот результаты моих тестов для c++ (Core2Duo/8600GTS):

 pts   vbo glb/e  ratio
 100  3900  3900   1.00
  1k  3800  3200   1.18
 10k  3600  2700   1.33
100k  1500   400   3.75
  1m   213    49   4.34
 10m    24     5   4.80

Таким образом, даже при 10 м вершинах это была нормальная частота кадров, а при использовании glB/e она была вялой.

person Slava V    schedule 14.02.2009

Читая Красную книгу, я помню отрывок, в котором говорилось, что VBO, возможно, быстрее в зависимости от аппаратного обеспечения. Некоторые аппаратные средства оптимизируют их, а другие нет. Возможно, что ваше оборудование не делает.

person Will Mc    schedule 13.01.2009
comment
Спасибо. Трудно понять, как хранение данных на карте не всегда будет быстрее (даже без значительной дополнительной оптимизации в драйвере), но я думаю, что у меня проблемы с привязкой моего кода к шине. - person Drew Hall; 14.01.2009
comment
@Will Mc (снова): Также трудно представить, что Nvidia не будет где-то рядом с передовыми с точки зрения реализации оптимизации VBO. Кажется более вероятным, что они (также) нашли способ оптимизировать прямой путь ко мне. - person Drew Hall; 14.01.2009

14Mpoints/s — это не так много. Это подозрительно. Можем ли мы увидеть полный код, выполняющий рисование, а также инициализацию? (сравните эти 14М/с с 240М/с (!), которые получает Слава Вишняков). Еще более подозрительно, что она падает до 640 КБ/с при отрисовке 1 КБ (по сравнению с его 3,8 МБ/с, которая в любом случае выглядит ограниченной ~3800 SwapBuffers).

Могу поспорить, что тест измеряет не то, что вы думаете.

person Bahbar    schedule 19.11.2009

Предполагая, что я это правильно помню, мой учитель OpenGL, который хорошо известен в сообществе OpenGL, сказал, что они быстрее работают со статической геометрией, которая будет рендериться много времени в типичной игре, это будут столы, стулья и небольшие статические объекты.

person Community    schedule 13.01.2009