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

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

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

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

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

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

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

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

Результаты работы ##

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

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

glBegin()/glEnd():

  • 1K pts → 603 FPS
  • 10K pts → 401 FPS
  • 100K pts → 97 FPS
  • 1M pts → 14 FPS

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

  • 1K pts → 603 FPS
  • 10K pts → 402 FPS
  • 100K pts → 97 FPS
  • 1M pts → 14 FPS

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

  • 1K pts → 604 FPS
  • 10K pts → 399 FPS
  • 100K pts → 95 FPS
  • 1M pts → 14 FPS

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

Вопрос (ы)

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

Ответ 1

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

  • CPU (создание вершин, вызовы APU, все остальное)
  • Шина (передача CPU ↔ GPU)
  • Вершина (вершинный шейдер над выполнением конвейера с фиксированной функцией)
  • Пиксель (заполнение, выполнение шейдера фрагментов и ротации)

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

Ответ 2

Там может быть несколько недостатков:

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

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

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

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

Вот мои результаты теста для С++ (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 она была вялой.

Ответ 3

В качестве дополнительной заметки:
"Прямой режим" (glBegin/glEnd) не поддерживается:

OpenGLES. OpenGL 3.x.

Итак, если вы когда-либо планируете переносить свое приложение на мобильную платформу (например, iPhone) даже не привыкнуть к нему.

Я преподаю OpenGL в университете, и слайд, объясняющий glBegin/glEnd, имеет большую красную рамку вокруг с добавочным жирным заголовком "НЕ ИСПОЛЬЗУЙТЕ".

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

Ответ 4

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

Ответ 5

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

Я бы оценил тест, не измеряя, что, по вашему мнению, он измеряет.

Ответ 6

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