Название: График, оптимизация paintEvent Отправлено: qaz0 от Март 04, 2016, 14:48 Есть нестандартный график, сделанный на базе QWidget. Рисует процесс в динамике. Работать будет на слабой машине и с отрисовкой там все плохо. Так что требуется максимально облегчить отрисовку.
В итоговом варианте отрисовка разбита на несколько составляющих: PaintS - для вывода осей, координатной сетки и прочих элементов, если изменилась метка repaintS (изменились min или max значения графика); PaintD - для вывода графика, если изменилась метка repaintD (появились новые данные). Выглядит как-то так. Код: QPixmap ImageS, ImageD; Когда есть изменения, рисует в QPixmap. В конце отрисовки выводит эти самые QPixmap на экран. С QImage (QImage::Format_ARGB32_Premultiplied) работает медленне. Рисовать напрямую медленнее - приходится каждый раз рисовать и PaintS(), и PaintD(), а это долго. Была мысль запихнуть сгенерированный ImageS на задний план: Код: QPalette pal = palette(); Код: QLabel *LabelBackGround; Код: //painter->drawPixmap(X, Y, ImageS); Почему не помогает такая схема (вероятно, из-за схемы вызова paintEvent при наложении виджитов)? И какие могут быть мысли по оптимизации (кроме прореживания отрисовки)? ??? Название: Re: График, оптимизация paintEvent Отправлено: Bepec от Март 04, 2016, 14:53 А зачем вам аж два pixmap, при этом с прозрачностью? И почему они пересоздаются при каждой отрисовке?
Название: Re: График, оптимизация paintEvent Отправлено: Racheengel от Март 04, 2016, 14:56 qwt не подходит Вам?
как то лет 10 назад на слабой машине с его помощью удалось сделать быстрый график. Название: Re: График, оптимизация paintEvent Отправлено: Racheengel от Март 04, 2016, 14:58 Кстати, почему использутся QPixmap, а не QImage?
Название: Re: График, оптимизация paintEvent Отправлено: qaz0 от Март 04, 2016, 15:11 А зачем вам аж два pixmap, при этом с прозрачностью? И почему они пересоздаются при каждой отрисовке? Тоже так подумал и пробовалКод: ImageD = ImageS; qwt не подходит Вам? Люблю стандартные решения, но нет. График немного нестардартный. Да и qwt далеко не так быстро рисует, как хочелось бы.как то лет 10 назад на слабой машине с его помощью удалось сделать быстрый график. Кстати, почему использутся QPixmap, а не QImage? Проигрывает 8% в скорости отрисовки.Название: Re: График, оптимизация paintEvent Отправлено: Igors от Март 04, 2016, 15:20 "Рисовать в буфер быстрее" уже давно стало легендой, сейчас это имеет смысл только для неизменяемого background'а. В Вашем случае это отрисовка осей, но и то неясно - может тех осей там с гулькин нос. Попробуйте все рисовать на экран, без затей
Название: Re: График, оптимизация paintEvent Отправлено: qaz0 от Март 04, 2016, 15:25 "Рисовать в буфер быстрее" уже давно стало легендой, сейчас это имеет смысл только для неизменяемого background'а. В Вашем случае это отрисовка осей, но и то неясно - может тех осей там с гулькин нос. Попробуйте все рисовать на экран, без затей С прямой отрисовки все и начиналось. А оси - это как раз тяжелая отрисовка. Там штрихи под каждое значение, текст к нему, координатная сетка. Так что 30% времени при переходе на отрисовку в буфер все же выигрывается.Название: Re: График, оптимизация paintEvent Отправлено: qaz0 от Март 04, 2016, 15:54 Да, проверил еще раз.
Вариант 1. Код: if (repaintD) Код: if (repaintD) Название: Re: График, оптимизация paintEvent Отправлено: Igors от Март 04, 2016, 15:58 С прямой отрисовки все и начиналось. А оси - это как раз тяжелая отрисовка. Там штрихи под каждое значение, текст к нему, координатная сетка. Так что 30% времени при переходе на отрисовку в буфер все же выигрывается. Если утекло много воды (с тех пор как начиналось) то есть смысл перепроверить. Еще возможность - рисовать адаптивно, напр только новые точки, но так редко устраивает (обычно не удается затереть старые). А так видимо Вы достигли потолка. Вроде бы идея проста, разумна, логична и многобещающа. Сейчас то что считается "прямым" = рисование в QImage (по крайней мере на большинстве платформ). С этой точки зрения понятно что какие-то "замесы с еще буферами" серьезного ускорения не обещаютНазвание: Re: График, оптимизация paintEvent Отправлено: qaz0 от Март 04, 2016, 16:17 Если утекло много воды (с тех пор как начиналось) то есть смысл перепроверить. Еще возможность - рисовать адаптивно, напр только новые точки, но так редко устраивает (обычно не удается затереть старые). А так видимо Вы достигли потолка. Когда писал про напрямую, подразумевалось сразу на экран. Там медленно получается из-за громоздкой отрисовки осей и координатной сетки. А рисование в 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% быстрее.Сейчас то что считается "прямым" = рисование в QImage (по крайней мере на большинстве платформ). С этой точки зрения понятно что какие-то "замесы с еще буферами" серьезного ускорения не обещают Насчет "рисовать адаптивно" как раз сегодня попробовал. Там минимум еще 32% выигрыш по времени. Работает классно, но это очень напоминает костыль. Название: Re: График, оптимизация paintEvent Отправлено: Racheengel от Март 04, 2016, 16:36 Вариант 1 выигрывает 8% по скорости работы (да, это неколько прогонов, а не 1). Необъяснимо, но факт. Если целевая машина старая, то скорее всего она не поддерживает SSE команды. Таким образом, заполнение памяти реализовано тупо побайтовым копированием. Если целевая машина еще и дешевая, то скорее всего и объем кэша минимальный. Так что этим может все объясняться. Название: Re: График, оптимизация paintEvent Отправлено: Racheengel от Март 04, 2016, 16:39 Насчет "рисовать адаптивно" как раз сегодня попробовал. Там минимум еще 32% выигрыш по времени. Работает классно, но это очень напоминает костыль. 32% это очень кошерно :) В данном случае это не костыль, а оптимизация :) Название: Re: График, оптимизация paintEvent Отправлено: Igors от Март 04, 2016, 17:21 Еще такой вариант - рисовать буфер в др нитке(ах) сразу как данные приходят
Название: Re: График, оптимизация paintEvent Отправлено: qaz0 от Март 04, 2016, 17:47 Еще такой вариант - рисовать буфер в др нитке(ах) сразу как данные приходят Так не получится 100%. Поток приема данных работает приближенно к реалтайму. Поток отрисовки - по остаточному принципу. Пусть лучше будут тормоза в отрисовке, чем переполнение и сброс входного аппаратного буфера. Название: Re: График, оптимизация paintEvent Отправлено: qaz0 от Март 04, 2016, 17:53 Я, честно говоря, надеялся, что кто-нибудь подскажет можно ли (и если да, то как) засунуть статическое изображени в фон так, чтобы его отрисовка вызывалась только при изменении фона (а не когда в виджите поверх вызывался paintevent). А для отрисовки динамической части графика вызывалась перерисовка только измененной части (что-то вроде void QWidget::update ( const QRect & rect ) ).
Название: Re: График, оптимизация paintEvent Отправлено: Racheengel от Март 04, 2016, 18:00 Я, честно говоря, надеялся, что кто-нибудь подскажет можно ли (и если да, то как) засунуть статическое изображени в фон так, чтобы его отрисовка вызывалась только при изменении фона (а не когда в виджите поверх вызывался paintevent). А для отрисовки динамической части графика вызывалась перерисовка только измененной части (что-то вроде void QWidget::update ( const QRect & rect ) ). Когда вызовется paintevent, то будет перерисовано все, что находится под виджетом, хоть фон, хоть другие виджеты. Поэтому непонятно, что здесь можно выиграть. Посмотрите на Qt::WA_NoSystemBackground и Qt::WA_OpaquePaintEvent, может с их помощью что-то улучшится. Цитировать Qt::WA_NoSystemBackground Indicates that the widget has no background, i.e. when the widget receives paint events, the background is not automatically repainted. Название: Re: График, оптимизация paintEvent Отправлено: Igors от Март 04, 2016, 18:13 Я, честно говоря, надеялся, что кто-нибудь подскажет можно ли (и если да, то как) засунуть статическое изображени в фон так, чтобы его отрисовка вызывалась только при изменении фона (а не когда в виджите поверх вызывался paintevent). А толку? Будет перерисовываться так или иначе, хоть с OpaquePaintEvent хоть нет, разница лишь в каком месте. Да и вывод готового буфера - крохи, на которых не сэкономить. А для отрисовки динамической части графика вызывалась перерисовка только измененной части (что-то вроде void QWidget::update ( const QRect & rect ) ). Это в лучшем случае адаптивное рисование которое упоминалось выше. Вообще надо менять подход. Если клиент не в состоянии купить себе даже приличное железо - то за софт он точно не заплатит. Так чего для него стараться? Вы все добросовестно проверили. Нет возможности сделать быстрее - значит ее нет. Название: Re: График, оптимизация paintEvent Отправлено: Old от Март 04, 2016, 20:56 Почему не помогает такая схема (вероятно, из-за схемы вызова paintEvent при наложении виджитов)? И какие могут быть мысли по оптимизации (кроме прореживания отрисовки)? ??? Проблема скорее всего в том, как вы все рисуете. Вы бы показали, как вы выводите оси и сам график.Сейчас графики легко прорисовывают старшие модели микроконтроллеров, не говоря уже о дестопах. Название: Re: График, оптимизация paintEvent Отправлено: Bepec от Март 04, 2016, 22:16 А в чём проблема то? вызывайте update с нужными вам координатами и отрисовывайте только обновившуюся область, там все данные для этого есть, в paintEvent.
Но самая закавыка в том, что возможно у вас громоздкое рисование, или плохо оптимизированное. А именно эту часть у вас занимает "/*...*/". Так что можно только гадать. PS при приложении тестового проектика я бы поковырялся. Название: Re: График, оптимизация paintEvent Отправлено: qaz0 от Март 05, 2016, 19:41 Нет возможности сделать быстрее - значит ее нет. Железо довольно приличное: 520МГц arm. А написанный код практически всегда можно оптимизировать :)Проблема скорее всего в том, как вы все рисуете. Но самая закавыка в том, что возможно у вас громоздкое рисование, или плохо оптимизированное. Отрисовка действительно громоздкая, но только в части расчета осей (которая вызывается редко). Реализовано там все на 2 функциях: drawLine и drawText. Плюс определенное количество алгебраических вычислений, чтобы циферки на осях были круглые и текст стоял рядом. В отрисовке самого графика setClipRect для установки границы линий графика, евклидово преобразование точек из физической величины в пиксели на экране и drawLine в цикле. Простейший минимум, без которого не обойтись.А в чём проблема то? вызывайте update с нужными вам координатами и отрисовывайте только обновившуюся область, там все данные для этого есть, в paintEvent. Проблема была в непонимании, что именно запихнуть в paintEvent для того, чтобы потом вызывать update или repaint не для всего виджита, а для его части. Ну не совать же туда все расчеты и выводы drawLine+drawText. Ответом оказалось, что туда надо поместить вывод на экран буфера на базе QPixmap, и вызов update/repaint с параметрами зоны перерисовки прекрасно понимает, что не надо рисовать весь виджит заново.В итоге описанный вызов перерисовки изменил ситуацию полностью - среднее время отрисовки стало меньше в 10 раз. И потратить на расчет+вывод новых значений 5ms как-то совсем не жалко. Резюмируя, вся загвоздка была не в рисовании в буфер - там все оказалось неплохо, а непосредственно в выводе этого буфера на экран. Благодарю всех отписавшихся. |