mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
perf: reduce repainting in animations
By profiling qTox using perf I discovered, that NotificationIcon::updateGradient takes significant amount of CPU time even though qTox is idle and no one is typing. This commit fixes: 1) correctly determine visibility of NotificationIcon 2) only invalidate boundingRect in fixed intervals 3) apply the same fixes to Spinner since it has the same problem
This commit is contained in:
parent
6a10abf1b3
commit
3c58b992c6
|
@ -50,11 +50,6 @@ void Broken::setWidth(qreal width)
|
||||||
Q_UNUSED(width)
|
Q_UNUSED(width)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Broken::visibilityChanged(bool visible)
|
|
||||||
{
|
|
||||||
Q_UNUSED(visible)
|
|
||||||
}
|
|
||||||
|
|
||||||
qreal Broken::getAscent() const
|
qreal Broken::getAscent() const
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
|
@ -33,7 +33,6 @@ public:
|
||||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
|
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
|
||||||
QWidget* widget) override;
|
QWidget* widget) override;
|
||||||
void setWidth(qreal width) override;
|
void setWidth(qreal width) override;
|
||||||
void visibilityChanged(bool visible) override;
|
|
||||||
qreal getAscent() const override;
|
qreal getAscent() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -30,13 +30,12 @@ NotificationIcon::NotificationIcon(QSize Size)
|
||||||
{
|
{
|
||||||
pmap = PixmapCache::getInstance().get(Style::getImagePath("chatArea/typing.svg"), size);
|
pmap = PixmapCache::getInstance().get(Style::getImagePath("chatArea/typing.svg"), size);
|
||||||
|
|
||||||
updateTimer = new QTimer(this);
|
// Timer for the animation, if the Widget is not redrawn, no paint events will
|
||||||
updateTimer->setInterval(1000 / 30);
|
// arrive and the timer will not be restarted, so this stops automatically
|
||||||
updateTimer->setSingleShot(false);
|
updateTimer.setInterval(1000 / framerate);
|
||||||
|
updateTimer.setSingleShot(true);
|
||||||
|
|
||||||
updateTimer->start();
|
connect(&updateTimer, &QTimer::timeout, this, &NotificationIcon::updateGradient);
|
||||||
|
|
||||||
connect(updateTimer, &QTimer::timeout, this, &NotificationIcon::updateGradient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF NotificationIcon::boundingRect() const
|
QRectF NotificationIcon::boundingRect() const
|
||||||
|
@ -54,6 +53,10 @@ void NotificationIcon::paint(QPainter* painter, const QStyleOptionGraphicsItem*
|
||||||
painter->fillRect(QRect(0, 0, size.width(), size.height()), grad);
|
painter->fillRect(QRect(0, 0, size.width(), size.height()), grad);
|
||||||
painter->drawPixmap(0, 0, size.width(), size.height(), pmap);
|
painter->drawPixmap(0, 0, size.width(), size.height(), pmap);
|
||||||
|
|
||||||
|
if (!updateTimer.isActive()) {
|
||||||
|
updateTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
Q_UNUSED(option)
|
Q_UNUSED(option)
|
||||||
Q_UNUSED(widget)
|
Q_UNUSED(widget)
|
||||||
}
|
}
|
||||||
|
@ -70,10 +73,12 @@ qreal NotificationIcon::getAscent() const
|
||||||
|
|
||||||
void NotificationIcon::updateGradient()
|
void NotificationIcon::updateGradient()
|
||||||
{
|
{
|
||||||
|
// Update for next frame
|
||||||
alpha += 0.01;
|
alpha += 0.01;
|
||||||
|
|
||||||
if (alpha + dotWidth >= 1.0)
|
if (alpha + dotWidth >= 1.0) {
|
||||||
alpha = 0.0;
|
alpha = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
grad = QLinearGradient(QPointF(-0.5 * size.width(), 0), QPointF(3.0 / 2.0 * size.width(), 0));
|
grad = QLinearGradient(QPointF(-0.5 * size.width(), 0), QPointF(3.0 / 2.0 * size.width(), 0));
|
||||||
grad.setColorAt(0, Qt::lightGray);
|
grad.setColorAt(0, Qt::lightGray);
|
||||||
|
@ -82,6 +87,7 @@ void NotificationIcon::updateGradient()
|
||||||
grad.setColorAt(qMin(1.0, alpha + dotWidth), Qt::lightGray);
|
grad.setColorAt(qMin(1.0, alpha + dotWidth), Qt::lightGray);
|
||||||
grad.setColorAt(1, Qt::lightGray);
|
grad.setColorAt(1, Qt::lightGray);
|
||||||
|
|
||||||
if (scene() && isVisible())
|
if (scene() && isVisible()) {
|
||||||
scene()->invalidate(sceneBoundingRect());
|
scene()->invalidate(sceneBoundingRect());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,7 @@
|
||||||
|
|
||||||
#include <QLinearGradient>
|
#include <QLinearGradient>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
#include <QTimer>
|
||||||
class QTimer;
|
|
||||||
|
|
||||||
class NotificationIcon : public ChatLineContent
|
class NotificationIcon : public ChatLineContent
|
||||||
{
|
{
|
||||||
|
@ -42,10 +41,12 @@ private slots:
|
||||||
void updateGradient();
|
void updateGradient();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr int framerate = 30; // 30Hz
|
||||||
|
|
||||||
QSize size;
|
QSize size;
|
||||||
QPixmap pmap;
|
QPixmap pmap;
|
||||||
QLinearGradient grad;
|
QLinearGradient grad;
|
||||||
QTimer* updateTimer = nullptr;
|
QTimer updateTimer;
|
||||||
|
|
||||||
qreal dotWidth = 0.2;
|
qreal dotWidth = 0.2;
|
||||||
qreal alpha = 0.0;
|
qreal alpha = 0.0;
|
||||||
|
|
|
@ -26,14 +26,18 @@
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QVariantAnimation>
|
#include <QVariantAnimation>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
Spinner::Spinner(const QString& img, QSize Size, qreal speed)
|
Spinner::Spinner(const QString& img, QSize Size, qreal speed)
|
||||||
: size(Size)
|
: size(Size)
|
||||||
, rotSpeed(speed)
|
, rotSpeed(speed)
|
||||||
{
|
{
|
||||||
pmap = PixmapCache::getInstance().get(img, size);
|
pmap = PixmapCache::getInstance().get(img, size);
|
||||||
|
|
||||||
timer.setInterval(1000 / 30); // 30Hz
|
// Timer for the animation, if the Widget is not redrawn, no paint events will
|
||||||
timer.setSingleShot(false);
|
// arrive and the timer will not be restarted, so this stops automatically
|
||||||
|
timer.setInterval(1000 / framerate);
|
||||||
|
timer.setSingleShot(true);
|
||||||
|
|
||||||
blendAnimation = new QVariantAnimation(this);
|
blendAnimation = new QVariantAnimation(this);
|
||||||
blendAnimation->setStartValue(0.0);
|
blendAnimation->setStartValue(0.0);
|
||||||
|
@ -56,14 +60,17 @@ void Spinner::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, Q
|
||||||
{
|
{
|
||||||
painter->setClipRect(boundingRect());
|
painter->setClipRect(boundingRect());
|
||||||
|
|
||||||
QTransform trans = QTransform()
|
QTransform trans = QTransform().rotate(curRot)
|
||||||
.rotate(QTime::currentTime().msecsSinceStartOfDay() / 1000.0 * rotSpeed)
|
|
||||||
.translate(-size.width() / 2.0, -size.height() / 2.0);
|
.translate(-size.width() / 2.0, -size.height() / 2.0);
|
||||||
painter->setOpacity(alpha);
|
painter->setOpacity(alpha);
|
||||||
painter->setTransform(trans, true);
|
painter->setTransform(trans, true);
|
||||||
painter->setRenderHint(QPainter::SmoothPixmapTransform);
|
painter->setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
painter->drawPixmap(0, 0, pmap);
|
painter->drawPixmap(0, 0, pmap);
|
||||||
|
|
||||||
|
if (!timer.isActive()) {
|
||||||
|
timer.start(); // update bounding rectangle for next frame
|
||||||
|
}
|
||||||
|
|
||||||
Q_UNUSED(option)
|
Q_UNUSED(option)
|
||||||
Q_UNUSED(widget)
|
Q_UNUSED(widget)
|
||||||
}
|
}
|
||||||
|
@ -73,14 +80,6 @@ void Spinner::setWidth(qreal width)
|
||||||
Q_UNUSED(width)
|
Q_UNUSED(width)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spinner::visibilityChanged(bool visible)
|
|
||||||
{
|
|
||||||
if (visible)
|
|
||||||
timer.start();
|
|
||||||
else
|
|
||||||
timer.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
qreal Spinner::getAscent() const
|
qreal Spinner::getAscent() const
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
@ -88,6 +87,12 @@ qreal Spinner::getAscent() const
|
||||||
|
|
||||||
void Spinner::timeout()
|
void Spinner::timeout()
|
||||||
{
|
{
|
||||||
if (scene())
|
// Use global time, so the animations are synced
|
||||||
|
float angle = QTime::currentTime().msecsSinceStartOfDay() / 1000.0f * rotSpeed;
|
||||||
|
// limit to the range [0.0 - 360.0]
|
||||||
|
curRot = remainderf(angle, 360.0f);
|
||||||
|
|
||||||
|
if (scene()) {
|
||||||
scene()->invalidate(sceneBoundingRect());
|
scene()->invalidate(sceneBoundingRect());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,16 +37,17 @@ public:
|
||||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
|
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
|
||||||
QWidget* widget) override;
|
QWidget* widget) override;
|
||||||
void setWidth(qreal width) override;
|
void setWidth(qreal width) override;
|
||||||
void visibilityChanged(bool visible) override;
|
|
||||||
qreal getAscent() const override;
|
qreal getAscent() const override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void timeout();
|
void timeout();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr int framerate = 30; // 30Hz
|
||||||
QSize size;
|
QSize size;
|
||||||
QPixmap pmap;
|
QPixmap pmap;
|
||||||
qreal rotSpeed;
|
qreal rotSpeed;
|
||||||
|
qreal curRot;
|
||||||
QTimer timer;
|
QTimer timer;
|
||||||
qreal alpha = 0.0;
|
qreal alpha = 0.0;
|
||||||
QVariantAnimation* blendAnimation;
|
QVariantAnimation* blendAnimation;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user