Russian Qt Forum
Сентябрь 27, 2024, 16:22 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: OpenGL и рисование графиков  (Прочитано 14817 раз)
Dimchansky
Гость
« : Февраль 27, 2006, 17:29 »

Последние дни занимался тем, чтобы добиться максимальных скоростей при отрисовке сигналов, состоящих из 132072 (=2^17) точек. Вообщем точек много, а скорости мало.
Рисовать средствами GDI - тормоза по-определению. Просто на виджетах рисовать с использованием QPainter в методе void paintEvent(QPaintEvent *event) - фактически тот же GDI, тока что обернут в хорошую упаковку. В Qt4 появилась заманчивая фича - рисовать с использованием вкусного QPainter на виджете OpenGL. При этом гарантируется попиксельный эквивалент, как если бы рисовали на обычном виджете. Ну и как и в Qt3 можно рисовать на виджете OpenGL с использованием хардкода непосредственным вызовом функций OpenGL в методе void paintGL(). Это самое быстрое.
Результаты отрисовки зашумленной синусоиды из 2^17 точек, которая на каждом этапе генерируется вызовом (медленных) функций sin и сдивается по фазе, на Athlon 3000+, GF6600GT(код собирался в release на VS2003, кадры считались fraps'ом, сглаживания отключены):

1. Отрисовка на виджете OpenGL в методе void paintGL() c использованием OpenGL функций типа glVertex2d - 50-52 fps
2. Отрисовка на виджете OpenGL в методе void paintGL() c использованием QPainter - 39-40 fps
3. Отрисовка на виджете OpenGL в методе void paintEvent(QPaintEvent *event) c использованием QPainter - 24 fps
4. Отрисовка на обычном виджете в методе void paintEvent(QPaintEvent *event) c использованием QPainter - fraps'ом, ес-но, не замерить, но на глаз кадров 10, вообщем значительно медленнее, чем OpenGL.

Меня больше удивила разница в пп.2 и 3. Видимо, в п. 3 всё рисуется иначе, чем в п.2, фактически , как на обычном виджете, а потом результирующей картинкой, видимо, отсылается в OpenGL.
Разница между пп.1 и 2 была ожидаема, хочешь вкусного QPainter - плати кадрами.
Конечно, если сигнал бы генерировался иначе, например, просто псевдошум быстрый из boost, то fps бы подрос, мне кажется кадров на 10 в среднем. (надо будет проверить) Но вот меня ещё не оставляют смутные сомнения, что код в п.1 можно ускорить используя glList.. Но надо копать, а лень.
п.1 перспективен в плане производительности. Но я вот думаю, что если железо, из которого будет тянуться сигнал, быдет выдавать не более 10 сигналов такой длины, то п.2 устроит более чем. Почему ещё не хочется лезть в дебри п.1 - прийдётся основательно разобраться с OpenGL на низком уровне, в п.2. за меня это сделает вкусная обёртка. Короче, сижу как буриданов осёл.
А быть может есть библиотеки под Qt, которые уже рисуют графики используя чистый OpenGL? Я не нашёл.

кросспост
Записан
SLiDER
Гость
« Ответ #1 : Февраль 27, 2006, 18:24 »

А можно полюбопытствовать у вас разрешение экрана монитора по горизонтали какое? На кой ляд вам 132072 точек выводить? Я конечно понимаю что хочется быстрой графики, особенно когда ее нужно много (у нас заказчики требуют, ну нравятся им всякие свистелки-перделки красивые, даже если они ни какой, реальной, информации оператору не дают, как сказал тут недавно один полковник: "Это нам надо что бы оператор не заснул на посту !!!" :shock: ). НО, пытаться на 1280 точках отобразить 132072, это уже перебор, интерполяцией данных должен не виджет заниматься а специально написанный для этого класс, учитывающий всю специфику отображаемого сигнала.
Опять, же не подумайте что я против быстрых виджетов для вывода графиков, самому по зарез нужны. Может я в чем-то не прав ? Крутой развейте мои сомнения. Крутой
А кроме Qwt, виджетов для вывода графиков, нужного мне уровня функциональности, я ни где не нашел. Самим писать как то времени нет и по непосредственному профилю дел выше крыши, так что, пока, Qwt терпим, только под четверкой он такой тормоз стал, что ой-ой-ой.  Грустный
Записан
Dimchansky
Гость
« Ответ #2 : Февраль 27, 2006, 18:42 »

Цитата: "SLiDER"
А можно полюбопытствовать у вас разрешение экрана монитора по горизонтали какое? На кой ляд вам 132072 точек выводить?Грустный


Задача стоит так. Разрешение экрана XxY (X,Y<=1024). Точек в сигнале может быть 16<=N<=132072. Выводить сигнал нужно как весь целиком, так и отдельную его часть, которая может состоять из малого числа точек. Т.е. вопрос, на кой ляд выводить всё это число точек, не стоит. Стоит вопрос, каким образом вывести все эти точки на экран c максимальным перформансом и чтобы не произошло визуальной потери информации (пички), в том числе и искажения.
Я думал над процеживанием точек, на разбиение по группам, но пока не глубоко.. К тому же меня пугают логарифмические варианты шкал. Ну потом все эти хитрые трюки должны в real-time занимать меньше времени.
А вот перформанс варанта п.1 по сравнению с п.4 (qwt именно этот случай) меня более чем устраивает. Буду очень рад, если удастся его ускорит за счёт хитрых алгоритмов процеживания точек.
Потом, за счёт использования OpenGL, появляется часть процессорного свободного времени, которую можно потратить на внутреннюю математику сигналов, вместо просчёта отрисовываемого сигнала. Т.е. общий перформанс только должен вырасти.
Подскажете работающие идеи "процеживания"?
Записан
Dendy
Гость
« Ответ #3 : Февраль 27, 2006, 20:13 »

Если визуальная часть < 1024, то и обрабатьІвать нужно не более такого количества точек. То-бишь отсеять точки по X-координате, которьІе рисуются в один пиксель.

СамьІй простой способ - найти точку в массиве, соответствующую рисующемуся пикселю с учётом смещения и масштаба. Например, вот она: 51536.87. Дробная потому что при пропорциях мьІ попали между точек. Теперь интерполируем координату Y пропорционально между значениями 51536 и 51537:

Код:
y = y[51536]*0.87 + y[51537]*0.13;


Можно взять точек ещё меньше, чем ширина екрана и рисовать их с помощью кривьІх Безье (можно вообще в отдельном потоке, как в примере Мандельброт).

Рисование на обьІчном окне будет бьІстрее OpenGL хотя бьІ потому, что окно обновляется только в нужньІх местах и только когда нужно. На OpenGL оно обновляется непрерьІвно и везде, а так как в твоём случае часть времени одной итерации лихо уходит на загрузку проца - тьІ не только непрерьІвно грузишь видеокарту, но и процессор. В случае с софтварньІм рисованием - получишь небольшую единоразовую задержку (в отдельном потоке) только при обновлении визуальной части графика.
Записан
Dimchansky
Гость
« Ответ #4 : Февраль 27, 2006, 21:04 »

Цитата: "Dendy"
Если визуальная часть < 1024, то и обрабатьІвать нужно не более такого количества точек. То-бишь отсеять точки по X-координате, которьІе рисуются в один пиксель.

СамьІй простой способ - найти точку в массиве, соответствующую рисующемуся пикселю с учётом смещения и масштаба. Например, вот она: 51536.87. Дробная потому что при пропорциях мьІ попали между точек. Теперь интерполируем координату Y пропорционально между значениями 51536 и 51537:

Код:
y = y[51536]*0.87 + y[51537]*0.13;


Можно взять точек ещё меньше, чем ширина екрана и рисовать их с помощью кривьІх Безье (можно вообще в отдельном потоке, как в примере Мандельброт).


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

Цитата: "Dendy"
Рисование на обьІчном окне будет бьІстрее OpenGL хотя бьІ потому, что окно обновляется только в нужньІх местах и только когда нужно. На OpenGL оно обновляется непрерьІвно и везде, а так как в твоём случае часть времени одной итерации лихо уходит на загрузку проца - тьІ не только непрерьІвно грузишь видеокарту, но и процессор. В случае с софтварньІм рисованием - получишь небольшую единоразовую задержку (в отдельном потоке) только при обновлении визуальной части графика.


А вот тут уже простите, но как говорил маэстро Станиславский: НЕ ВЕРЮ!
Во-первых, в случае с QGLWidget ровно таким же образом используется двойная буферизация, как и с QWidget.
Во-вторых, в случае с QGLWidget я не теряю времени CPU на пересчёт координат сигнала в координаты экрана, я просто говорю OpenGL окно трансформации и фактически копирую напрямую массив точек, а всё остальное делает уже видеокарта.
В-третьих, практика пока показывает обратное тому, о чём Вы говорите: п.4 - значительно уступает пп.1-2.

Я провёл ещё эксперимент. Сделал просто генерацию шума, вместо обсчёта синусоиды. fps по пп.1-2 выросли и сравнялись на 60. В случае с QWidget fps тоже вырос, но визуально значительно уступает варианту с OpenGL.

Итого имеем:
1. чистый OpenGL уделывает QPainter на простом QWidget.
2. обёрнутый в QPainter OpenGL уделывает QPainter на простом QWidget.
3. Читаем trolltech: It is now possible to open a QPainter on a QGLWidget as if it were a normal QWidget. One huge benefit from this is that we utilize the high performance of OpenGL for most drawing operations, such as transformations and pixmap drawing. Это значит, что, по крайней мере, п.2 в моих рисованиях сигналов не должен уступать по сокрости обычному виджету, не говоря, про чистый OpenGL. Ну может быть при ресайзинге будет чуть уступать. Но я не думаю, что пользователь при просмотре сигнала будет непрерывно менять размеры окна, если он не больной какой. Улыбающийся

Единственное, что с multi-threading'ом в OpenGL не всё тривиально, тут можно посомневаться в расспараллеливании работы и общей производительности.
Но уж никак нельзя сомневаться в том, что два процессора выполнят работу быстрее, чем один.

Вообще, простите, но не согласен с Вами по всем пунктам. Улыбающийся
Записан
SLiDER
Гость
« Ответ #5 : Февраль 28, 2006, 00:39 »

Цитата: "Dimchansky"
Подскажете работающие идеи "процеживания"?

Как я, собственно, уже говорил, все очень сильно зависит от специфики выводимого вами сигнала. Для "визуального усиления" интерисующих вас артефактов может потребоваться и совсем уж не тривиальная обработка самого сигнала, начиная от банального усреднения и заканчивая, например медианной фильтрацией.
Приведу простой но в тоже время показательный (ИМХО) пример. Допустим у вас есть некая последовательность сигнальных отсчетов и вам нужно обнаружить в ней некий набор спектральных пиков. Как это сделать? Самый тупой способ построить ДПФ, он то точно покажет все пики, но жутко медленно. Второй вариант БПФ, очень быстро, но как правильно подобрать разрешающую способность, да и привязка к степени двойки не очень удобна. Можно попробовать строить не спектр, а СПМ. Есть огромное множество различных алгоритмов, но все очень сильно зависят от свойств анализируемого сигнала, например, для чисто гармонических нет ни чего лучше MUSIC.
При выводе очень большого колличества точек спектра, очень часто, достаточно просто суммировать стоящие рядом, превращая их в один отсчет соответствующей мощности. Если же речь идет о визуальном анализе во временной области то тут задача по сложнее, надо понимать что за сигнал и что конкретно вы хотите в нем увидеть.
Но прошу заметить что при выводе 132072 точек одномерной зашумленной синусоиды в область меньшую 1024 пикселов вы по любому потеряете более 99% информации. Так что без предварительной специализированной обработки ни как не обойтись, иначе даже от самого быстрого графического виджета не будет ни какого толку.
Записан
Dimchansky
Гость
« Ответ #6 : Февраль 28, 2006, 01:04 »

Цитата: "SLiDER"
Как я, собственно, уже говорил, все очень сильно зависит от специфики выводимого вами сигнала.
Так что без предварительной специализированной обработки ни как не обойтись, иначе даже от самого быстрого графического виджета не будет ни какого толку.


Дело в том, что на входе может быть абсолютно произвольный сигнал, заранее не известно, какой именно.
Поэтому меня терзают смутные сомнения, как бы предобработка и вывод меньшего числа точек не был эквивалентен "тупой" пересылке всех точек в OpenGL.
Тем более, что скорость отрисовки на сигналах предельной длины довольно высока с использованием чистого OpenGL, впрочем и обернутого в QPainter тоже.
Словом буду пытаться дальше. А пока причешу код.
Записан
Dendy
Гость
« Ответ #7 : Февраль 28, 2006, 17:20 »

На счёт бьІстродействия QPainter имелось в виду конечно же перерисовка по собьІтиям, а не скорость рисования одного кадра. Бесспорно при рисовании одного кадра верх всегда будет за аппаратно ускоренной графикой. Но в случае с QPainter будет разгрузка процессорного времени до следующего собьІтия перерисовки.

Всё же не совсем понятно зачем нужна обработка избьІточной информации. Ведь график - ето просто визуальное представление для глаз человека. Должна бьІть видна общая форма сигнала и наличие шумов, а более точная картинка - при увеличении масштаба.

Возможно вам нужно подумать над гистограмньІм представлением - когда большое количество отсчётов графика интегрируются в показатель плотности.
Записан
Dimchansky
Гость
« Ответ #8 : Февраль 28, 2006, 17:35 »

Цитата: "Dendy"
Всё же не совсем понятно зачем нужна обработка избьІточной информации. Ведь график - ето просто визуальное представление для глаз человека. Должна бьІть видна общая форма сигнала и наличие шумов, а более точная картинка - при увеличении масштаба.

Возможно вам нужно подумать над гистограмньІм представлением - когда большое количество отсчётов графика интегрируются в показатель плотности.


Я поэтому пытаюсь выяснить, как мне лучше построить программу: процеживать сигнал и скармливать его потом в OpenGL или просто отсылать его безо всяких процеживаний в OpenGL.
Мне важно не то, что бедная видеокарта будет греться, мне важно, чтобы CPU отдыхал как можно больше, чтобы он тратил больше времени на нужные мне вычисления и не занимался вместо этого отрисовкой.
Буду я гистограмить/процеживать громадный сигнал или не буду, в любом случае мне проще потом результат плюнуть в OpenGL. Или я не прав?
Пока что меня терзают сомнения в целесообразности процеживания - ведь этим будет заниматься CPU. Сигнал с огромным кол-вом точек уже есть - это свершившийся факт. Надо попробовать процедить, практика покажет.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.109 секунд. Запросов: 21.