вторник, 17 января 2012 г.

Сколько стоит полигон.

Закончились новогодние праздники, теперь время нагонять упущенное, потому в этот раз мы поговорим о производительности, но не нашей а рендера :)

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


Так как суть тестирования определить стоимость вызова команды рисования относительно количества выводимых полигонов, то использовался только вершинный буфер, запись в буфер глубины, тест глубины и запись в буфер цвета были отключены. Замер времени производился с использованием прецизионного таймера, предоставляемого расширением ARB_timer_query.
Для уменьшения стоимости бинда буферов VBO было использовано VAO (ARB_vertex_array_object). Так как рисование VBO происходит асинхронно, то, чтоб не было наложения результатов, перед каждым тестом выполнялось принудительное завершение очереди команд посредством glFlush.

Вот собственно результаты тестов:

По оси X отложено количество полигонов, по оси Y - время выполнения команды в миллисекундах. Красной линией обозначена отрисовка всей геометрии посредством одного вызова, зеленой - отдельный вызов на каждый полигон.

Как видно с графиков, при отрисовке геометрии одним пакетом мы получаем существенный выигрыш в производительности, и тем больше, чем больше полигонов мы выводим за один раз. Так, отрисовка 260к полигонов за один раз оказывается более чем в 20 раз быстрее отрисовки отдельных полигонов и примерно эквивалентно выводу 14к полигонов. Тоесть один бинд буфера VBO с отрисовкой одного полигона примерно эквивалентен отрисовке 64 полигонов (абсолютные значения всех  цифр имеют смысл только на GT520). Другими словами, если у вас стоит выбор - вывести лишние полигоны или сэкономить за счет разбивки геометрии на более мелкие куски, то вспомните этот график.

Итак, мы остановились на том, что лучше группировать мелкую геометрию в пакеты по 64 полигона, давайте проверим правильны ли наши выводы:

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

Так же хочу напомнить что в статье шла речь только о стоимости команды отрисовки (почему нельзя выводить каждый полигон отдельно), что актуально при выводе текста, частиц, элементов GUI и прочей примитивной геометрии. На практике, к этой стоимости добавляется еще и стоимость растеризации полигона, которая зависит так же от сложности шейдера, от количества растеризируемых пикселей, от размера текстур, от пропускной способности памяти и множества других факторов, которые существенно могут подкорректировать эти результаты, вплоть до того, что вывод лишнего полигона с шейдером окажется существенно дороже сотни команд рисования по пол-микросекунды каждая. В таких случаях стараются разделить геометрическую сложность сцены и шейдера, для чего придуманы такие технологии как Early-Z pass, Deferred Shading и прочие, но это тема уже другой статьи.

3 комментария:

  1. Большое спасибо за статью(да и за весь блог, в общем). Увы, сейчас почти нет времени на OpenGL, так что стараюсь хотя бы читать что-то по теме, если не программировать. Меня в этой теме очень интересует батчинг GUI, пока что самую лучшую реализацию видел в MyGUI. Увы, в исходниках слишком уж хитро все накручено с абстрактным рендером, я так и не смог полностью разобраться. Может у тебя получится, если есть, конечно, желание туда смотреть :)

    ОтветитьУдалить
  2. Статья по GUI будет в ближайшее время, пока думаю что что будет следующим - закончить цикл статей по зависимости производительности от переключения состояний (бинд буферов VBO/VBA, бинд текстур, бинд шейдеров и передача юниформ) или вводить их попарно - батчинг+GUI, бинд VBO+инстансинг, шейдера/юниформы+материалы.

    Ну а по GUI - я выкладывал демку, там я количество батчей свел до 3-х штук на ~700 контролов без потери функциональности (каждый контрол можно перемещать, делать невидимым, менять размер, цвет, обрабатывать события и обновлять содержимое):
    http://file.qip.ru/get/DJ97yGDd/GUI_2.html
    Как это сделано - можешь либо поковырять исходники VBOMesh, либо жди статью :Р

    ОтветитьУдалить
  3. P.S. Вообще я жду пока ты закончишь свое GUI чтоб прикрутить к нему свой рендер :)
    У меня контролов пока очень мало и они пока очень примитивно сделаны, фактически у меня только эффективный рендер и пару контролов для демки :)

    ОтветитьУдалить