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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: График, оптимизация paintEvent  (Прочитано 10768 раз)
qaz0
Гость
« : Март 04, 2016, 14:48 »

Есть нестандартный график, сделанный на базе QWidget. Рисует процесс в динамике. Работать будет на слабой машине и с отрисовкой там все плохо. Так что требуется максимально облегчить отрисовку.

В итоговом варианте отрисовка разбита на несколько составляющих:
PaintS - для вывода осей, координатной сетки и прочих элементов, если изменилась метка repaintS (изменились min или max значения графика);
PaintD - для вывода графика, если изменилась метка repaintD (появились новые данные).
Выглядит как-то так.

Код:
QPixmap ImageS, ImageD;
bool repaintS, repaintD;
void PaintS(QPainter *painter) {/*...*/}
void PaintD(QPainter *painter) {/*...*/}
void paintEvent(QPaintEvent *)
{
   QPainter *painter;
   painter = new QPainter(this);
   PaintAll(painter);
   delete painter;
}
void PaintAll(QPainter *painter)
{
   if (repaintS)
   {
      repaintS = false;
      ImageS = QPixmap(W, H);
      ImageS.fill(Qt::transparent);
      QPainter painterS(&ImageS);
      PaintS(&painterS);
   }
   if (repaintD)
   {
      repaintD = false;
      ImageD = QPixmap(W, H);
      ImageD.fill(Qt::transparent);
      QPainter painterD(&ImageD);
      PaintD(&painterD);
   }
   painter->drawPixmap(X, Y, ImageS);
   painter->drawPixmap(X, Y, ImageD);
}

Когда есть изменения, рисует в QPixmap. В конце отрисовки выводит эти самые QPixmap на экран.
С QImage (QImage::Format_ARGB32_Premultiplied) работает медленне. Рисовать напрямую медленнее - приходится каждый раз рисовать и PaintS(), и PaintD(), а это долго.

Была мысль запихнуть сгенерированный ImageS на задний план:
Код:
QPalette pal = palette();
pal.setBrush(QPalette::Window, QBrush(ImageS));
setPalette(pal);
Или засунуть сгенерированный ImageS в другой виджит позади текущего:
Код:
QLabel *LabelBackGround;
LabelBackGround->setPixmap(ImageS);
И забыть про необходимость его отрисовки:
Код:
//painter->drawPixmap(X, Y, ImageS);
Стало работать немного медленнее. В обоих случаях.

Почему не помогает такая схема (вероятно, из-за схемы вызова paintEvent при наложении виджитов)? И какие могут быть мысли по оптимизации (кроме прореживания отрисовки)?  Непонимающий
Записан
Bepec
Гость
« Ответ #1 : Март 04, 2016, 14:53 »

А зачем вам аж два pixmap, при этом с прозрачностью? И почему они пересоздаются при каждой отрисовке?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #2 : Март 04, 2016, 14:56 »

qwt не подходит Вам?
как то лет 10 назад на слабой машине с его помощью удалось сделать быстрый график.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #3 : Март 04, 2016, 14:58 »

Кстати, почему использутся QPixmap, а не QImage?
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
qaz0
Гость
« Ответ #4 : Март 04, 2016, 15:11 »

А зачем вам аж два pixmap, при этом с прозрачностью? И почему они пересоздаются при каждой отрисовке?
Тоже так подумал и пробовал
Код:
ImageD = ImageS;
//
painter->drawPixmap(X, Y, ImageS);
//painter->drawPixmap(X, Y, ImageD);
Вроде бы идея проста, разумна, логична и многобещающа. В душе не понимаю, почему при прогоне это не работало быстрее. Прозрачность оставлена, чтобы сохранять фон под виджитом того же цвета, который установлен в родительском фрейме. А, что прозрачность сильно тормозит?

qwt не подходит Вам?
как то лет 10 назад на слабой машине с его помощью удалось сделать быстрый график.
Люблю стандартные решения, но нет. График немного нестардартный. Да и qwt далеко не так быстро рисует, как хочелось бы.

Кстати, почему использутся QPixmap, а не QImage?
Проигрывает 8% в скорости отрисовки.


Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Март 04, 2016, 15:20 »

"Рисовать в буфер быстрее" уже давно стало легендой, сейчас это имеет смысл только для неизменяемого background'а. В Вашем случае это отрисовка осей, но и то неясно - может тех осей там с гулькин нос. Попробуйте все рисовать на экран, без затей
Записан
qaz0
Гость
« Ответ #6 : Март 04, 2016, 15:25 »

"Рисовать в буфер быстрее" уже давно стало легендой, сейчас это имеет смысл только для неизменяемого background'а. В Вашем случае это отрисовка осей, но и то неясно - может тех осей там с гулькин нос. Попробуйте все рисовать на экран, без затей
С прямой отрисовки все и начиналось. А оси - это как раз тяжелая отрисовка. Там штрихи под каждое значение, текст к нему, координатная сетка. Так что 30% времени при переходе на отрисовку в буфер все же выигрывается.
Записан
qaz0
Гость
« Ответ #7 : Март 04, 2016, 15:54 »

Да, проверил еще раз.
Вариант 1.
Код:
   if (repaintD)
   {
      repaintD = false;
      ImageD = QPixmap(W, H);
      ImageD.fill(Qt::transparent);
      QPainter painterD(&ImageD);
      PaintD(&painterD);
   }
   painter->drawPixmap(X, Y, ImageS);
   painter->drawPixmap(X, Y, ImageD);
Вариант 2.
Код:
   if (repaintD)
   {
      repaintD = false;
      ImageD = ImageS;
      QPainter painterD(&ImageD);
      PaintD(&painterD);
   }
   //painter->drawPixmap(X, Y, ImageS);
   painter->drawPixmap(X, Y, ImageD);
Вариант 1 выигрывает 8% по скорости работы (да, это неколько прогонов, а не 1). Необъяснимо, но факт. И сгенерировать новый QPixmap надо, и закрасить его вместо того, чтобы просто скопировать. И вывести 2 QPixmap вместо 1. Но тем не менее.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Март 04, 2016, 15:58 »

С прямой отрисовки все и начиналось. А оси - это как раз тяжелая отрисовка. Там штрихи под каждое значение, текст к нему, координатная сетка. Так что 30% времени при переходе на отрисовку в буфер все же выигрывается.
Если утекло много воды (с тех пор как начиналось) то есть смысл перепроверить. Еще возможность - рисовать адаптивно, напр только новые точки, но так редко устраивает (обычно не удается затереть старые). А так видимо Вы достигли потолка.

Вроде бы идея проста, разумна, логична и многобещающа.
Сейчас то что считается "прямым" = рисование в QImage (по крайней мере на большинстве платформ). С этой точки зрения понятно что какие-то "замесы с еще буферами" серьезного ускорения не обещают
Записан
qaz0
Гость
« Ответ #9 : Март 04, 2016, 16:17 »

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

Сейчас то что считается "прямым" = рисование в QImage (по крайней мере на большинстве платформ). С этой точки зрения понятно что какие-то "замесы с еще буферами" серьезного ускорения не обещают
Когда писал про напрямую, подразумевалось сразу на экран. Там медленно получается из-за громоздкой отрисовки осей и координатной сетки. А рисование в QImage тоже пробовалось, причем на всякий случай с разным форматом хранения данных enum QImage::Format. "QImage is designed and optimized for I/O, and for direct pixel access and manipulation, while QPixmap is designed and optimized for showing images on screen." QPixmap в итоге на экран выводится на 8% быстрее.

Насчет "рисовать адаптивно" как раз сегодня попробовал. Там минимум еще 32% выигрыш по времени. Работает классно, но это очень напоминает костыль.
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #10 : Март 04, 2016, 16:36 »

Вариант 1 выигрывает 8% по скорости работы (да, это неколько прогонов, а не 1). Необъяснимо, но факт.

Если целевая машина старая, то скорее всего она не поддерживает SSE команды. Таким образом, заполнение памяти реализовано тупо побайтовым копированием. Если целевая машина еще и дешевая, то скорее всего и объем кэша минимальный. Так что этим может все объясняться.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #11 : Март 04, 2016, 16:39 »

Насчет "рисовать адаптивно" как раз сегодня попробовал. Там минимум еще 32% выигрыш по времени. Работает классно, но это очень напоминает костыль.

32% это очень кошерно Улыбающийся В данном случае это не костыль, а оптимизация Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Март 04, 2016, 17:21 »

Еще такой вариант - рисовать буфер в др нитке(ах) сразу как данные приходят
Записан
qaz0
Гость
« Ответ #13 : Март 04, 2016, 17:47 »

Еще такой вариант - рисовать буфер в др нитке(ах) сразу как данные приходят
Так не получится 100%. Поток приема данных работает приближенно к реалтайму. Поток отрисовки - по остаточному принципу. Пусть лучше будут тормоза в отрисовке, чем переполнение и сброс входного аппаратного буфера.
Записан
qaz0
Гость
« Ответ #14 : Март 04, 2016, 17:53 »

Я, честно говоря, надеялся, что кто-нибудь подскажет можно ли  (и если да, то как) засунуть статическое изображени в фон так, чтобы его отрисовка вызывалась только при изменении фона (а не когда в виджите поверх вызывался paintevent). А для отрисовки динамической части графика вызывалась перерисовка только измененной части (что-то вроде void QWidget::update ( const QRect & rect ) ).
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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