Название: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 09:03 Задача обычная - рисовать попиксельно кучу данных в реальном времени в виде графиков, с поддержкой увеличения/уменьшения масштаба.
Для решения этой задачи я выбрал следующий путь. Отдельный поток владеет двумя пиксмапами, один из которых использует для текущего рисования, а другой пиксмап с отрисованными данными используется ГУИ потоком для отображения. После очередного этапа рисования пиксмапы меняются и ГУИ отображает новые данные. Сейчас у меня наблюдаеца эффект мерцания, что может быть вызвано рассинхронизацией данных в пиксмапах (я не аккуратно рисую, чисто в качестве теста). Меня волнует вопрос производительности - правильно ли я сделал, что выбрал такой подход вообще и QPixmap для попиксельного рисования в частности (вместо QImage)? Пытаюсь анализировать все что известно об этих классах и вот что получается (согласно документации): - QPixmap.drawPoint медленнее чем QImage.setPixel - QPixmap.drawPoint на стороне сервера, QImage.setPixel на стороне клиента - Защищенный swap( ptr1, ptr2 ) быстрее QPixmap.fromImage получается, что QImage пикселы рисовать быстрее, но при этом преобразование в QPixmap очень медленное. Так что опять не могу решить вопрос - что быстрее: 1) рисовать пикселы в QImage, а затем ковертировать их в QPixmap с отправкой на сервер или 2) Рисовать сразу на стороне сервера в QPixmap вроде бы медленными drawPoint? Поделитесь пожалуйста опытом и направьте на путь истинный =) Спасибо! Что быстрее: 500000 drawPoint или 500000 setPixel + один fromImage? Название: Re: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 09:34 простейший тест показал, что рисование 500000 через image.setPixel + pPixmap->convertFromImage _значительно_ быстрее чем рисование 350000 через painter.drawPoint.
так что считаю, что вопрос решен в пользу QImage пока кто-то не докажет иное =) пс. тему неправильно назвал - не QPixmap vs. QImage, а QPainter vs. QImage Название: Re: QPixmap vs. QImage Отправлено: GreatSnake от Сентябрь 02, 2011, 09:43 Здесь целая куча ньюансов:
* QPixmap хранится на стороне Xserver-a в случае X11 и на стороне GDI в случае винды * QImage хранится на стороне клиента * при любом композинге в QPixmap-е на стороне клиента требуется гнать его содержимое из Xserver/GDI в клиент и потом обратно * рендеринг в QImage обычно делается силами CPU, хотя может и можно как-то используя GPU * в Qt по-умолчанию включен backing-store - все QWidget::paintEvent()'s сначала отрисовываюся в double-buffer QImage и уже после этого изменённая часть double-buffer-а копируется непосредственно в окно. Исходя из всего этого для твоих целей оптимальнее всего изпользовать QImage и вообще не использовать QPixmap. В paintEvent() делать копирование из готового QImage. Использовать QPixmap-ы, имхо, следует только в случае статических изображений. Рекомендуется к обязательному прочтению Qt Graphics and Performance (http://labs.qt.nokia.com/2009/12/16/qt-graphics-and-performance-an-overview/) Название: Re: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 09:50 Здесь целая куча ньюансов: * QPixmap хранится на стороне Xserver-a в случае X11 и на стороне GDI в случае винды * QImage хранится на стороне клиента * при любом композинге в QPixmap-е на стороне клиента требуется гнать его содержимое из Xserver/GDI в клиент и потом обратно * рендеринг в QImage обычно делается силами CPU, хотя может и можно как-то используя GPU * в Qt по-умолчанию включен backing-store - все QWidget::paintEvent()'s сначала отрисовываюся в double-buffer QImage и уже после этого изменённая часть double-buffer-а копируется непосредственно в окно. Исходя из всего этого для твоих целей оптимальнее всего изпользовать QImage и вообще не использовать QPixmap. В paintEvent() делать копирование из готового QImage. Использовать QPixmap-ы, имхо, следует только в случае статических изображений. спасибо! Название: Re: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 10:31 Исходя из всего этого для твоих целей оптимальнее всего изпользовать QImage и вообще не использовать QPixmap. В paintEvent() делать копирование из готового QImage. тогда еще такой вопрос. Оптимален ли такой подход: Код: class workerThread: public QThread { Покритикуйте этот псевдокод пожалуйста. Можно ли сделать проще, быстрее и красивее? Название: Re: QPixmap vs. QImage Отправлено: GreatSnake от Сентябрь 02, 2011, 10:42 Не вижу вообще смысла в использовании QPixmap.
Код
Название: Re: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 10:55 Не вижу вообще смысла в использовании QPixmap. Код
действительно, про drawImage я забыл =) Название: Re: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 11:01 Еще один глупый вопрос. Правильно ли я понимаю, что никаких утечек памяти в коде ниже нет?
Код
GetImage вернет копию объекта, который при последующем GetImage будет правильно уничтожен благодаря механизму подсчета ссылок? Название: Re: QPixmap vs. QImage Отправлено: GreatSnake от Сентябрь 02, 2011, 11:07 А какие здесь могут быть утечки, если делается простое копирование ???
Название: Re: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 11:15 А какие здесь могут быть утечки, если делается простое копирование ??? нет, утечек не может быть. это я на всякий случай спросил =) просто хотел уточнить, какое именно копирование происходит. скажем, есть статический объект, которому периодически присваиваются другие объекты. как реализован оператор = для QImage? предположу, что создается новый объект с непустым счетчиком ссылок, а у старого объекта счетчик ссылок обнуляется и объект удаляется. не происходит же прямое копирование "значение в значение"? Название: Re: QPixmap vs. QImage Отправлено: Igors от Сентябрь 02, 2011, 11:21 Непонятно с синхронизацией - как paintEvent (которое может прийти в любой момент) узнает что mIimage обновлен? И что делать если еще нет?
По поводу QPainter/QPixmap. Если возиться с пикселями/коипозицией то все ясно - нужно использовать QImage. Но мне непонятно а что с др "рисованием" - в первую очередь с выводом текста и с clip регионами. В случае QPixmap этим занимается OC, но что в случае если QImage используется как QPaintDevice? Qt рисует вместо ОС? Это непросто и может быть не быстро. Спасибо Название: Re: QPixmap vs. QImage Отправлено: navrocky от Сентябрь 02, 2011, 11:32 По поводу QPainter/QPixmap. Если возиться с пикселями/коипозицией то все ясно - нужно использовать QImage. Но мне непонятно а что с др "рисованием" - в первую очередь с выводом текста и с clip регионами. В случае QPixmap этим занимается OC, но что в случае если QImage используется как QPaintDevice? Qt рисует вместо ОС? Это непросто и может быть не быстро. Да, в этом случае используется встроенный растровый движок. Но не факт, что это не быстро. Это может быть быстрее, т.к. в случае пиксмапа используется слишком жирная прослойка в виде иксов.Название: Re: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 11:33 Непонятно с синхронизацией - как paintEvent (которое может прийти в любой момент) узнает что mIimage обновлен? И что делать если еще нет? По поводу QPainter/QPixmap. Если возиться с пикселями/коипозицией то все ясно - нужно использовать QImage. Но мне непонятно а что с др "рисованием" - в первую очередь с выводом текста и с clip регионами. В случае QPixmap этим занимается OC, но что в случае если QImage используется как QPaintDevice? Qt рисует вместо ОС? Это непросто и может быть не быстро. Спасибо либо я не понял вопроса, либо мне кажется ответ очевидным: дополнительно к слоту (принудительное дерганье paintEvent) имеем: Код: void QPlotter::paintEvent( QPaintEvent * pEvent ) { и никаких проблем с синхронизайицей. проверено на практике. скорость отрисовки полумиллиона точек просто аццкая =))) Название: Re: QPixmap vs. QImage Отправлено: SASA от Сентябрь 02, 2011, 12:01 Отдельный поток владеет двумя пиксмапами, один из которых использует для текущего рисования, а другой пиксмап с отрисованными данными используется ГУИ потоком для отображения. А как вы рисуете в потоке? И если не рисуете - зачем потоки?Название: Re: QPixmap vs. QImage Отправлено: once_again_abc от Сентябрь 02, 2011, 12:36 Отдельный поток владеет двумя пиксмапами, один из которых использует для текущего рисования, а другой пиксмап с отрисованными данными используется ГУИ потоком для отображения. А как вы рисуете в потоке? И если не рисуете - зачем потоки?как обычно через QPainter/QPixmap. две пиксмапы для того, чтобы в одной рисовать, а другую отдать потоку ГУИ для отображения. когда цикл отрисовки закончился - посменять пиксмапы местами, если первая пиксмапа еще не занята ГУИ, иначе ждем когда ГУИ закончит рисование и тогда уже меняем. и так далее в бесконечном цикле. но это было раньше =) сейчас все намного проще и лушче - как обсуждается в этом топике. Название: Re: QPixmap vs. QImage Отправлено: GreatSnake от Сентябрь 02, 2011, 12:56 Непонятно с синхронизацией - как paintEvent (которое может прийти в любой момент) узнает что mIimage обновлен? И что делать если еще нет? m_Image - текущее результирующее изображение, предназначенное для отображения. Отображается таким какое есть. В каждом потоке своё изображение, которое копируется в результирующее изображение по мере готовности. paintEvent() не должен знать про степень готовности m_Image. Имея в каждом потоке свой m_Image можно не беспокоиться насчёт синхронизации :)Название: Re: QPixmap vs. QImage Отправлено: Igors от Сентябрь 02, 2011, 14:36 m_Image - текущее результирующее изображение, предназначенное для отображения. Отображается таким какое есть. В каждом потоке своё изображение, которое копируется в результирующее изображение по мере готовности. paintEvent() не должен знать про степень готовности m_Image. Имея в каждом потоке свой m_Image можно не беспокоиться насчёт синхронизации :) Хорошо, пусть "что-то изменилось", и нужно показать новый имедж. Каким образом Вы скажете нитке (рисующей в QPixmap или QImage) что нужно заняться рисованием? И как остановить ее когда отрисовано? Не вижу этого в приведенных фрагментах кода.Ладно, допустим как-то сказали и вызвали update. Но ведь paintEvent может прийти раньше чем нитка займется рисованием - она вернет старый имедж. Откуда возьмете следующий update? Так что про "степень готовности" главная нитка должна знать, иначе какие-то обновления не будут отображаться. Да, в этом случае используется встроенный растровый движок. Но не факт, что это не быстро. Это может быть быстрее, т.к. в случае пиксмапа используется слишком жирная прослойка в виде иксов. Ладно, будет минутка - проверю :)Название: Re: QPixmap vs. QImage Отправлено: Авварон от Сентябрь 02, 2011, 15:45 Вопрос к размышлению - зачем туи мьютексы?
Присваивание (то есть свап) кутешных шаред классов - атомарная операция, насколько мне известно. Название: Re: QPixmap vs. QImage Отправлено: Igors от Сентябрь 02, 2011, 19:06 Вопрос к размышлению - зачем туи мьютексы? Это дает только что N ниток могут одновременно читать (и расшаривать) такую переменную - но не спасает от crash если запись и чтение выполняются параллельно.Присваивание (то есть свап) кутешных шаред классов - атомарная операция, насколько мне известно. Поизучал маленько (аттач). Результат на OSX меня удивил: - прямой вывод на экран - менее 1 сек - вывод в QPixmap а потом на экран - 12 сек - вывод в QImage потом на экран - тоже примерно 12 сек Отключал финальный вывод (drawImage, drawPixmap), ну минус пол-секунды. Профайлер показывает что во всех случаях используется одна и та же Qt Engine. Вывод текста позорно медленный, все съедается на извлечении glyph(ов) - вернее на защищающей эту операцию блокировке. Еще одной неожиданностью оказалось что repaint вовсе не перерисовывает немедленно. Похоже что он засылает в очередь сообщение UpdateRequest (не путать с update). В любом случае repaint не зовет paintEvent сам, нужен processEvents Возможно это "только текст" и "только OSX" - у меня нет оснований обобщать Название: Re: QPixmap vs. QImage Отправлено: nike1987 от Сентябрь 14, 2011, 18:40 У меня наверное схожий вопрос автора, необходимо загружать на сцену(QGraphicsScene) довольно-таки увесистые изображения и периодически обновлять их.Сей час работает схема Qimage.load + Qpixmap.convertFromImage.Возможно ли ускорить как-то добавление изображения на сцену?Для добавления использую стандартную функцию сцены addPixmap().
|