From 5de213210ef4f14e698c3fd970cf7e6c5b27c72d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 16 Oct 2009 09:55:28 +0200 Subject: Added caching of graphics effect source pixmaps to speed up effects. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an effect is applied repeatedly on the same source, just with varying parameters, we can save a lot by caching the source pixmaps. Reviewed-by: Bjørn Erik Nilsen --- src/gui/effects/qgraphicseffect.cpp | 19 ++++++++++++++++++- src/gui/effects/qgraphicseffect.h | 1 + src/gui/effects/qgraphicseffect_p.h | 12 +++++++++++- src/gui/graphicsview/qgraphicsitem.cpp | 27 +++++++++++++++++++++------ src/gui/graphicsview/qgraphicsitem_p.h | 11 +++++++++-- src/gui/graphicsview/qgraphicsscene.cpp | 5 +++++ src/gui/kernel/qwidget.cpp | 22 ++++++++++++++++++++++ src/gui/kernel/qwidget_p.h | 13 ++++++++++--- src/gui/painting/qbackingstore.cpp | 5 +++++ 9 files changed, 102 insertions(+), 13 deletions(-) diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index 91641b0..96d35b0 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -253,7 +253,24 @@ bool QGraphicsEffectSource::isPixmap() const */ QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset) const { - return d_func()->pixmap(system, offset); + Q_D(const QGraphicsEffectSource); + + QPixmap pm; + if (d->m_cachedSystem == system) + QPixmapCache::find(d->m_cacheKey, &pm); + + if (pm.isNull()) { + pm = d->pixmap(system, &d->m_cachedOffset); + d->m_cachedSystem = system; + + d->invalidateCache(); + d->m_cacheKey = QPixmapCache::insert(pm); + } + + if (offset) + *offset = d->m_cachedOffset; + + return pm; } /*! diff --git a/src/gui/effects/qgraphicseffect.h b/src/gui/effects/qgraphicseffect.h index c5d3ede..c89851e 100644 --- a/src/gui/effects/qgraphicseffect.h +++ b/src/gui/effects/qgraphicseffect.h @@ -87,6 +87,7 @@ private: friend class QGraphicsEffectPrivate; friend class QGraphicsScenePrivate; friend class QGraphicsItem; + friend class QGraphicsItemPrivate; friend class QWidget; friend class QWidgetPrivate; }; diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h index ff2fb85..8fb55d8 100644 --- a/src/gui/effects/qgraphicseffect_p.h +++ b/src/gui/effects/qgraphicseffect_p.h @@ -55,6 +55,8 @@ #include "qgraphicseffect.h" +#include + #include #include @@ -65,7 +67,7 @@ class QGraphicsEffectSourcePrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QGraphicsEffectSource) public: QGraphicsEffectSourcePrivate() : QObjectPrivate() {} - virtual ~QGraphicsEffectSourcePrivate() {} + virtual ~QGraphicsEffectSourcePrivate() { invalidateCache(); } virtual void detach() = 0; virtual QRectF boundingRect(Qt::CoordinateSystem system) const = 0; virtual QRect deviceRect() const = 0; @@ -77,9 +79,16 @@ public: virtual bool isPixmap() const = 0; virtual QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset = 0) const = 0; virtual void effectBoundingRectChanged() = 0; + void invalidateCache() const { QPixmapCache::remove(m_cacheKey); } + friend class QGraphicsScenePrivate; friend class QGraphicsItem; friend class QGraphicsItemPrivate; + +private: + mutable Qt::CoordinateSystem m_cachedSystem; + mutable QPoint m_cachedOffset; + mutable QPixmapCache::Key m_cacheKey; }; class Q_GUI_EXPORT QGraphicsEffectPrivate : public QObjectPrivate @@ -94,6 +103,7 @@ public: if (source) { flags |= QGraphicsEffect::SourceDetached; source->d_func()->detach(); + source->d_func()->invalidateCache(); delete source; } source = newSource; diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 45627f6..5153783 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2482,12 +2482,14 @@ void QGraphicsItem::setOpacity(qreal opacity) itemChange(ItemOpacityHasChanged, newOpacityVariant); // Update. - if (d_ptr->scene) + if (d_ptr->scene) { + d_ptr->invalidateGraphicsEffectsRecursively(); d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true, /*maybeDirtyClipPath=*/false, /*force=*/false, /*ignoreOpacity=*/true); + } if (d_ptr->isObject) emit static_cast(this)->opacityChanged(); @@ -4949,6 +4951,22 @@ int QGraphicsItemPrivate::depth() const /*! \internal */ +void QGraphicsItemPrivate::invalidateGraphicsEffectsRecursively() +{ + QGraphicsItemPrivate *itemPrivate = this; + do { + if (itemPrivate->graphicsEffect) { + itemPrivate->notifyInvalidated = 1; + + if (!itemPrivate->updateDueToGraphicsEffect) + static_cast(itemPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache(); + } + } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0)); +} + +/*! + \internal +*/ void QGraphicsItemPrivate::invalidateDepthRecursively() { if (itemDepth == -1) @@ -5280,11 +5298,7 @@ void QGraphicsItem::update(const QRectF &rect) return; // Make sure we notify effects about invalidated source. - QGraphicsItem *item = this; - do { - if (item->d_ptr->graphicsEffect) - item->d_ptr->notifyInvalidated = 1; - } while ((item = item->d_ptr->parent)); + d_ptr->invalidateGraphicsEffectsRecursively(); if (CacheMode(d_ptr->cacheMode) != NoCache) { // Invalidate cache. @@ -10721,6 +10735,7 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP } pixmapPainter.end(); + return pixmap; } diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 6550362..8fd1a75 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -177,6 +177,7 @@ public: wantsActive(0), holesInSiblingIndex(0), sequentialOrdering(1), + updateDueToGraphicsEffect(0), globalStackingOrder(-1), q_ptr(0) { @@ -221,6 +222,7 @@ public: bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false, bool ignoreDirtyBit = false, bool ignoreOpacity = false) const; int depth() const; + void invalidateGraphicsEffectsRecursively(); void invalidateDepthRecursively(); void resolveDepth(); void addChild(QGraphicsItem *child); @@ -502,6 +504,7 @@ public: quint32 wantsActive : 1; quint32 holesInSiblingIndex : 1; quint32 sequentialOrdering : 1; + quint32 updateDueToGraphicsEffect : 1; // Optional stacking order int globalStackingOrder; @@ -589,8 +592,11 @@ public: inline const QWidget *widget() const { return 0; } - inline void update() - { item->update(); } + inline void update() { + item->d_ptr->updateDueToGraphicsEffect = true; + item->update(); + item->d_ptr->updateDueToGraphicsEffect = false; + } inline void effectBoundingRectChanged() { item->prepareGeometryChange(); } @@ -619,6 +625,7 @@ public: QGraphicsItem *item; QGraphicsItemPaintInfo *info; + QTransform lastEffectTransform; }; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index a624b10..fc8ce8a 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -4569,6 +4569,11 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * else painter->setWorldTransform(*transformPtr); painter->setOpacity(opacity); + + if (sourced->lastEffectTransform != painter->worldTransform()) { + sourced->lastEffectTransform = painter->worldTransform(); + sourced->invalidateCache(); + } item->d_ptr->graphicsEffect->draw(painter, source); painter->setWorldTransform(restoreTransform); sourced->info = 0; diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index de08312..088197e 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -93,6 +93,7 @@ # include "qx11info_x11.h" #endif +#include #include #include #ifdef Q_WS_MAC @@ -1806,12 +1807,29 @@ QRegion QWidgetPrivate::clipRegion() const return r; } +void QWidgetPrivate::invalidateGraphicsEffectsRecursively() +{ + Q_Q(QWidget); + QWidget *w = q; + do { + if (w->graphicsEffect()) { + QWidgetEffectSourcePrivate *sourced = + static_cast(w->graphicsEffect()->source()->d_func()); + if (!sourced->updateDueToGraphicsEffect) + w->graphicsEffect()->source()->d_func()->invalidateCache(); + } + w = w->parentWidget(); + } while (w); +} + void QWidgetPrivate::setDirtyOpaqueRegion() { Q_Q(QWidget); dirtyOpaqueChildren = true; + invalidateGraphicsEffectsRecursively(); + if (q->isWindow()) return; @@ -5215,6 +5233,10 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP paintEngine->d_func()->systemClip = QRegion(); } else { context.painter = sharedPainter; + if (sharedPainter->worldTransform() != sourced->lastEffectTransform) { + sourced->invalidateCache(); + sourced->lastEffectTransform = sharedPainter->worldTransform(); + } sharedPainter->save(); sharedPainter->translate(offset); graphicsEffect->draw(sharedPainter, source); diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index f7c2712..a109f32 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -360,6 +360,7 @@ public: void setOpaque(bool opaque); void updateIsTranslucent(); bool paintOnScreen() const; + void invalidateGraphicsEffectsRecursively(); QRegion getOpaqueRegion() const; const QRegion &getOpaqueChildren() const; @@ -729,7 +730,7 @@ class QWidgetEffectSourcePrivate : public QGraphicsEffectSourcePrivate { public: QWidgetEffectSourcePrivate(QWidget *widget) - : QGraphicsEffectSourcePrivate(), m_widget(widget), context(0) + : QGraphicsEffectSourcePrivate(), m_widget(widget), context(0), updateDueToGraphicsEffect(false) {} inline void detach() @@ -742,7 +743,11 @@ public: { return m_widget; } inline void update() - { m_widget->update(); } + { + updateDueToGraphicsEffect = true; + m_widget->update(); + updateDueToGraphicsEffect = false; + } inline bool isPixmap() const { return false; } @@ -754,7 +759,7 @@ public: if (QWidget *parent = m_widget->parentWidget()) parent->update(); else - m_widget->update(); + update(); } inline const QStyleOption *styleOption() const @@ -769,6 +774,8 @@ public: QWidget *m_widget; QWidgetPaintContext *context; + QTransform lastEffectTransform; + bool updateDueToGraphicsEffect; }; inline QWExtra *QWidgetPrivate::extraData() const diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 7c07df8..3cd1402 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include "qgraphicssystem_p.h" @@ -540,6 +541,8 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up Q_ASSERT(widget->window() == tlw); Q_ASSERT(!rgn.isEmpty()); + widget->d_func()->invalidateGraphicsEffectsRecursively(); + if (widget->d_func()->paintOnScreen()) { if (widget->d_func()->dirty.isEmpty()) { widget->d_func()->dirty = rgn; @@ -615,6 +618,8 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd Q_ASSERT(widget->window() == tlw); Q_ASSERT(!rect.isEmpty()); + widget->d_func()->invalidateGraphicsEffectsRecursively(); + if (widget->d_func()->paintOnScreen()) { if (widget->d_func()->dirty.isEmpty()) { widget->d_func()->dirty = QRegion(rect); -- cgit v0.12