альтернативы рисования qpainter (низкая производительность на Mac)

#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. И еще, вы могли бы кэшировать путь, так что это было бы намного быстрее после первого рисования.