glBegin(mode) - в чем подвох?

Писали класс по отрисовке примитивов (не мешей! и т.д.) - линий, точек, треугольников. И столкнулись с такой проблемой Smile реализация на основе ogl.

провели тест:

1) метод в лоб

for (int i=0; i<10000; ++i)

{

    vec2 p = vec2(rand(1024), rand(768));

    glBegin(point);

    glVertex2f(p.x, p.y);

    glColor4U(color);

    glEnd()

}

 

2) более логичный метод (как нам казалось)

for (int i=0; i<10000; ++i)

{

    array_p[i] = vec2(rand(1024), rand(768));

}

glVertexPointer(..., array_p);

glDrawArray(point, 0, array_p.size())

(код схематичен)

и тут фпс для 1 был выше чем для 2 (порядка на 20%)

вопрос: почему? Smile это связано с каким-то кешированием у видяхи?

Последняя правка: пн, 19/11/2012 - 14:31
Submitted by MaxImuS on

Комментарии

В первом случае всё берётся с потолка, а во втором много всего, что нужно проверить.

Submitted by AndyArt on
AndyArt wrote:

В первом случае всё берётся с потолка, а во втором много всего, что нужно проверить.

Сам хоть понял, что сказал? Так как троллинг тут не уместен.

Submitted by MaxImuS on

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

Во втором случае создается массив 10000 элементов в оперативной памяти, который перемещать в кэш процессора смысла нет

Submitted by Nort on

Maximus, чесно, думал описать суть проблемы в развёрнутом виде с примерами. Но, ты такой человек, что и это высмеял бы. Не удивительно, что здесь боятся что-то обсуждать, делиться идеями и что-то спрашивать. 

Submitted by AndyArt on

ОК, поскольку способ с VBO должен быть очевидно быстрее (банально DIP'ов 1 а не 10000), капитан очевидность советует проверить:

1. вбо создан "dynamic" и лочится как "write-only", т.е. что гпу не делает ненужной фигни

2. проверить это на нескольких разных железках -- может быть паталогия одного конкретного драйвера

Ну и как вариант показать код второго варианта если оно не секретно -- вдруг какая очевидная фигня :) 

Submitted by BLK Dragon on

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

Submitted by Otinagi on
BLK Dragon wrote:

ОК, поскольку способ с VBO должен быть очевидно быстрее (банально DIP'ов 1 а не 10000), капитан очевидность советует проверить:

1. вбо создан "dynamic" и лочится как "write-only", т.е. что гпу не делает ненужной фигни

2. проверить это на нескольких разных железках -- может быть паталогия одного конкретного драйвера

Ну и как вариант показать код второго варианта если оно не секретно -- вдруг какая очевидная фигня :) 

В этом примере нет вбо - простой draw из памяти (аля  DPUP). На тему самого вбо - мы создали масивчик на 1 000 000 точек и запихнули их в статик-вбо - фпс зарулил glBegin/glEnd в разы! Что еще раз доказало - "даешь вбо" (с)! Smile

Но только мы начинаем динамический менять геометрию - вбо начинает проигрывать, по не понятным нам причинам (динамик, только запись) на всех девайсах (7700, 8500, 210) где тестили.

А в примере, который я привел - идет противостояние 10 000 glBegin/glEnd vs 1 glDrawArray.

Код второго варианта ничем не отличается от примера - только если юзали vector, то ресайзили его до нужного размера.

Submitted by MaxImuS on
Nort wrote:

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

Во втором случае создается массив 10000 элементов в оперативной памяти, который перемещать в кэш процессора смысла нет

В этом что-то есть, но хз, все-таки 10 000 dpup (аля d3d) против 1 dpup. Будем исследовать дальше.

Submitted by MaxImuS on
Otinagi wrote:

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

Надо будет почитать старые умные книжки Smile

Submitted by MaxImuS on
MaxImuS wrote:
Otinagi wrote:

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

Надо будет почитать старые умные книжки Smile

Вообще-то тут проблема в гпу/драйверах.

Т.е. можно для надёжности запустить втюн и померять куда цпу-время уходит. Есть уверенное предположение, что время уходит в ДЛЛ дривера видюхи Smile

Вообще странно, у нас в двежке 2д штуки примерно так рисуюся (всё батчится, группируется по слоям и текстурам и потом несколькими драв-коллами рендерится), так оно шустро всё, реально десятки тысяч штук можно рисовать; разве что на пейси через ДХ не через ГЛ.

 

Submitted by BLK Dragon on

Были ли попытки проанализировать происходящее с помощью отладочного инструментария от производителя видеокарты? Мне кажется, это может пролить свет на происходящее.

GL не является моим основным API, но могут быть несколько источников подобных чудес:

1. Существует несколько способов передачи данных между приложением и видеокартой. И если второй случай - это гаранторованное копирование всего массива, возможно - несколько, в зависимоти от реализации драйвера + скорее всего, выделение памяти (опять же, одно или несколько), то в первом случае есть вероятность, что данные для отрисовки сразу попадут в ring buffer. Т.е. никаких выделений памяти и копирований не будет.

2. Я не понимаю, каков формат вершины и сколько потоков данных во втором случае. Если для позиции и для цвета - разные массивы, и узкое место - IA - тогда все дело именно в двух потоках (каждый отдельный массив - -20% произовдительности IA ).

Честно говоря, вообще непонятно, что в данном примере узкое место: CPU или какая-то часть GPU. А может быть, как сказал предыдущий оратор, дело вообще в кривой реализации драйвером одного из подходов как заведомо более медленного. Идеальное решение - аналог DirectX динамического буфера с флагом Discard при маппинге (затрудняюсь на вскидку назвать аналог на GL). Тогда не будет лишних копирований, возможно не будет даже лишних выделений памяти.

Submitted by imixer on

Да, попытки были. Пользовали gDEBugger, но правда, еще не до конца разобрался в нем. Вот например, в том же perfhud я видел затраченное время на выполнение каждой гапи операции, что довало возможность сразу навскидку определить узкое место. Тут же пока я ничего не нашел такого. Если кто знает - буду благодарен за подсказку.

Да, забыл указать, что во втором случае два массива (позиция, цвет) - виноват.

Спасибо за подсказки - возмем на вооружение.

Чуть позже просто напишу чистый тест данной проблемы, т.к. все это дело тестилось на игровом движке - может что-то в нем тормозит процесс.

Submitted by MaxImuS on
MaxImuS wrote:

Писали класс по отрисовке примитивов (не мешей! и т.д.) - линий, точек, треугольников. И столкнулись с такой проблемой Smile реализация на основе ogl.

провели тест:

1) метод в лоб

for (int i=0; i<10000; ++i)

{

    vec2 p = vec2(rand(1024), rand(768));

    glBegin(point);

    glVertex2f(p.x, p.y);

    glColor4U(color);

    glEnd()

}

В OpenGL: SuperBible указывается что если вы рисуете через glBegin/glEnd, то их нужно выносить за луп. Так как они довольно медленные.

Submitted by AlexB.hpp on

создаешь свои точки, кидаешь в шейдер. glBegin/glEnd давно в графе deprecated

Имхо вобще 2 разных варианта вывода геометрии:
1 Буфер под обьекты оздается каждый кадр (OGL за тебя это делает, использует внутренние кэши, и ещё хз что)
2. Буфер под обекты подготавливается ранее и потом выводится (возможно ты создаеш VBO под вершины каждый кадр, поэтому и тормозит)

По факту 2й вариант никак не может быть медленнее.

Submitted by Relyer on
Relyer wrote:

Имхо вобще 2 разных варианта вывода геометрии:
1 Буфер под обьекты оздается каждый кадр (OGL за тебя это делает, использует внутренние кэши, и ещё хз что)
2. Буфер под обекты подготавливается ранее и потом выводится (возможно ты создаеш VBO под вершины каждый кадр, поэтому и тормозит)

По факту 2й вариант никак не может быть медленнее.

Вообще-то Игорь (imixer) сказал как вариант1 может быть быстрее -- если все данные сразу пишутся в command-buffer GPU. Правда в такую возможность на пейси верится с трудом -- слишком уж хорошо должен быть написан драйвер.

OGL VBO вообще такая штука странная, из опыта как пользователя (софт типа modo, Mari), оно часто не только тормозит но ещё и крашится, причём не на самых плохих видюхах.

Submitted by BLK Dragon on

Чтобы сделать тест более чистым, надо убрать из замеров рандомы, 20.000 разндомов всетаки, а какова реализация на нижнем уровне одному богу известно.

Submitted by Denis on

GameDev.by