#c #performance #qt #macos #paint
#c #Производительность #qt #macos #Краски
Вопрос:
У меня есть класс, который отображает данные формы сигнала аудиофайлов в QWidget (смотрите Скриншот виджета ниже, тогда я все еще использовал градиент, что приводило к снижению производительности).
Аудиоданные отображаются в paintEvent непосредственно в виджете с использованием нескольких вызовов QPainter::drawLine
(минимальное количество вызовов QWidget::drawLine
эквивалентно ширине виджета => по крайней мере, одна строка для каждой координаты x). Хотя этот подход довольно хорошо работает в Windows (paintEvent в полноэкранном режиме занимает около ~ 4 мс), производительность в 4-5 раз хуже, когда программа запускается под macOS.
Производительность рисования важна для плавной прокрутки отображаемых данных.
Итак, мой вопрос в том, знает ли кто-нибудь более быструю альтернативу QPainter.DrawLine для рисования линий (решения, зависящие от платформы, могут быть приемлемыми, если их можно использовать в paintEvent), или есть способ ускорить прокрутку, какую-то буферизацию и т.д.?
Ответ №1:
Текущая версия (4.7.x) Qt использует для рисования графическую базу Core. Как вы уже выяснили, иногда это может быть медленным. В Windows используется программный рендерер, который обладает действительно хорошей производительностью.
Мое предложение состоит в том, чтобы не рисовать на переданном painter непосредственно в вашем событии рисования. Вместо этого создайте область рисования, QImage
того же размера, что и ваш виджет, и нарисуйте на ней. При этом будет использоваться программный рендерер, который намного быстрее. Затем при необходимости нанесите QImage
на painter.
Комментарии:
1. мы используем qt 4.4, я уже пробовал сначала нарисовать данные на QPixmap, а затем пиксельное изображение на виджете, но ускорение было незначительным (QPainter:: DrawLine не был заметно быстрее при рисовании на pixmap)
2. Я помню, что QPixmap отличается от QImage тем, что QPixmap использует «ускоренный» сервер платформы. В OS X это означает, что это все еще основная графика. Использование QImage гарантирует, что вы используете программный рендерер.
3. @smerlin QPixmap оптимизирован для отображения изображений на экране, в то время как QImage оптимизирован для ввода-вывода. Если вы используете QPixmap для рисования линий, то это будет медленнее.
4. использование QImage с
QImage::Format_ARGB32_Premultiplied
привело к действительно хорошей производительности 😉
Ответ №2:
Используйте OpenGL и QGLWidget, если хотите рисовать действительно быстро.
Комментарии:
1. простой вывод из
QGLWidget
вместоQWidget
не сработал, поскольку множество событий рисования просто не были перенаправлены в виджет, кроме того, приложение просто вылетает на macOS с сообщением об ошибке следующего содержания: «Необходимо создать QApplication перед QPaintDevice», в то время как у меня, очевидно, уже есть экземпляр QApplication.2. Кроме того, я сомневаюсь, что простое переключение на OpenGL ничего не ускорит, поскольку данные, которые я рисую, изменяют каждый кадр, и эти данные все равно приходится загружать на видеокарту практически в каждом кадре ?!
3. Если вы используете QGLWidget, вам нужно нарисовать изображение с помощью OpenGL API. Довольно легко нарисовать простую ломаную линию, как на вашем рисунке. И да, когда ваши данные меняются каждый кадр, данные перемещаются каждый кадр в память видеокарты, но объем данных в вашем случае должен быть настолько мал, что это не будет проблемой. И фактическое рисование будет очень быстрым.
4. в документации qt говорится, что рисование 2D-данных с помощью QGLWidget все еще должно выполняться с помощью QPainter.
5. Я не знал об этом. Хотя я думаю, что в документации говорится, что возможно использовать QPainter, а не о том, что его следует использовать. Я не использовал QPainter с QGLWidget, поэтому я не знаю, какая разница в производительности существует между использованием QPainter или OpenGL API.
Ответ №3:
Вы могли бы создать QPainterPath и нарисовать его вместо повторного вызова функции DrawLine. И еще, вы могли бы кэшировать путь, так что это было бы намного быстрее после первого рисования.