hi .. doing some profiling with valgrind/massif, i noticed that a large amount of start up processing and memory usage is spent in parsing SVGs. surprise! ;)
i introduced a KPixmapCache for on-disk caching to help prevent the need to render from the source SVG over and over. i was able to squeeze ~1MB of RAM usage out by doing that. but we can be even better .... right now what is kicking us in the teeth is accessing embedded hints in the SVG file. turns out they are SUCH a great idea after all ;) at least not when we don't cache them, resulting in unecessary parsing of the SVG. in particular, those include: hint-apply-color-scheme - checked every time setImagePath is called hint-*-margin - checked whenever PanelSvg::updateSizes is called additionally, the following methods kill us: Svg::hasElement (mostly called from PanelSvg::hasElementPrefix) Svg::elementSize Svg::elementRect i decided to try tackling the first one, hint-apply-color-scheme, by caching that in the global config file.. turns out this help us avoid creating the renderer in a huge number of cases. in fact, with the attached patch applied, after the first run only PanelSvg cause us to hit createRenderer method. just getting rid of the embedded hints isn't going to help us any: elementSize, elementRect and hasElement will still trigger unecessary createRenderer() calls. so i'm thinking that it might make sense to keep a cache of some sort for all these parameters so that we only end up opening the SVG files to do new rendering. one outstanding issue will be clearing the disk and parameter caches when the theme is updated on disk but not changed in the config. before i go any further with this approach: any thoughts, ideas, inspirations? -- Aaron J. Seigo humru othro a kohnu se GPG Fingerprint: 8B8B 2209 0C6F 7C47 B1EA EE75 D6B7 2EB1 A7F1 DB43 KDE core developer sponsored by Qt Software
Index: theme.h =================================================================== --- theme.h (revision 871491) +++ theme.h (working copy) @@ -179,6 +179,19 @@ */ bool useGlobalSettings() const; + /** + * Tries to load pixmap with the specified key from cache. + * @return true when pixmap was found and loaded from cache, false otherwise + **/ + bool findInCache(const QString &key, QPixmap &pix); + + /** + * Insert specified pixmap into the cache. + * If the cache already contains pixmap with the specified key then it is + * overwritten. + **/ + void insertIntoCache(const QString& key, const QPixmap& pix); + Q_SIGNALS: /** * Emitted when the user changes the theme. SVGs should be reloaded at Index: svg.cpp =================================================================== --- svg.cpp (revision 871491) +++ svg.cpp (working copy) @@ -22,15 +22,15 @@ #include <QDir> #include <QMatrix> #include <QPainter> -#include <QPixmapCache> #include <QSharedData> +#include <KColorScheme> +#include <KConfigGroup> #include <KDebug> +#include <KIconEffect> +#include <KGlobalSettings> #include <KSharedPtr> #include <KSvgRenderer> -#include <KColorScheme> -#include <KIconEffect> -#include <KGlobalSettings> #include "theme.h" @@ -77,8 +77,17 @@ eraseRenderer(); } - void setImagePath(const QString &imagePath, Svg *q) + bool setImagePath(const QString &imagePath, Svg *q) { + bool isThemed = !QDir::isAbsolutePath(imagePath); + if (isThemed == themed && + ((themed && themePath == imagePath) || + (!themed && path == imagePath))) { + return false; + } + + bool updateNeeded = !path.isEmpty() || !themePath.isEmpty(); + if (themed) { QObject::disconnect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged())); @@ -86,7 +95,7 @@ q, SLOT(colorsChanged())); } - themed = !QDir::isAbsolutePath(imagePath); + themed = isThemed; path.clear(); themePath.clear(); @@ -96,38 +105,22 @@ q, SLOT(themeChanged())); // check if svg wants colorscheme applied - createRenderer(); - applyColors = renderer->elementExists("hint-apply-color-scheme"); + checkApplyColorHint(); if (applyColors && !Theme::defaultTheme()->colorScheme()) { QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorsChanged())); } - + } else if (!QFile::exists(path)) { + path = imagePath; } else { - path = imagePath; - - if (!QFile::exists(path)) { - kDebug() << "file '" << path << "' does not exist!"; - } + kDebug() << "file '" << path << "' does not exist!"; } - } - void removeFromCache() { - if (ids.isEmpty()) { - return; - } - - foreach (const QString &id, ids) { - QPixmapCache::remove(id); - } - - ids.clear(); + return updateNeeded; } QPixmap findInCache(const QString &elementId, const QSizeF &s = QSizeF()) { - createRenderer(); - QSize size; if (elementId.isEmpty() || multipleImages) { size = s.toSize(); @@ -153,7 +146,8 @@ QPixmap p; - if (QPixmapCache::find(id, p)) { + Theme *theme = Theme::defaultTheme(); + if (theme->findInCache(id, p)) { //kDebug() << "found cached version of " << id; return p; } else { @@ -168,6 +162,7 @@ p.fill(Qt::transparent); QPainter renderPainter(&p); + createRenderer(); if (elementId.isEmpty()) { renderer->render(&renderPainter); } else { @@ -179,15 +174,11 @@ // Apply current color scheme if the svg asks for it if (applyColors) { QImage itmp = p.toImage(); - KIconEffect::colorize( - itmp, Theme::defaultTheme()->color(Theme::BackgroundColor), 1.0); + KIconEffect::colorize(itmp, theme->color(Theme::BackgroundColor), 1.0); p = p.fromImage(itmp); } - if (!QPixmapCache::insert(id, p)) { - //kDebug() << "pixmap cache is too small for inserting" << id << "of size" << s; - } - + theme->insertIntoCache(id, p); return p; } @@ -201,24 +192,26 @@ path = Plasma::Theme::defaultTheme()->imagePath(themePath); } - QHash<QString, SharedSvgRenderer::Ptr>::const_iterator it = renderers.find(path); + QHash<QString, SharedSvgRenderer::Ptr>::const_iterator it = s_renderers.find(path); - if (it != renderers.end()) { + if (it != s_renderers.end()) { //kDebug() << "gots us an existing one!"; renderer = it.value(); } else { renderer = new SharedSvgRenderer(path); - renderers[path] = renderer; + s_renderers[path] = renderer; } - size = renderer->defaultSize(); + if (size.isNull()) { + size = renderer->defaultSize(); + } } void eraseRenderer() { if (renderer && renderer.count() == 2) { // this and the cache reference it; and boy is this not thread safe ;) - renderers.erase(renderers.find(path)); + s_renderers.erase(s_renderers.find(path)); } renderer = 0; @@ -260,6 +253,19 @@ return renderer->matrixForElement(elementId); } + void checkApplyColorHint() + { + KConfigGroup cg(KGlobal::config(), "SvgHints"); + QString cgKey = themePath + "-hint-apply-color-scheme"; + if (cg.hasKey(cgKey)) { + applyColors = cg.readEntry(cgKey, false); + } else { + createRenderer(); + applyColors = renderer->elementExists("hint-apply-color-scheme"); + cg.writeEntry(cgKey, applyColors); + } + } + void themeChanged() { if (!themed) { @@ -272,14 +278,12 @@ return; } - removeFromCache(); path = newPath; //delete d->renderer; we're a KSharedPtr eraseRenderer(); // check if new theme svg wants colorscheme applied - createRenderer(); - applyColors = renderer->elementExists("hint-apply-color-scheme"); + checkApplyColorHint(); if (applyColors && !Theme::defaultTheme()->colorScheme()) { QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), q, SLOT(colorsChanged())); @@ -297,13 +301,12 @@ return; } - removeFromCache(); eraseRenderer(); emit q->repaintNeeded(); } Svg *q; - static QHash<QString, SharedSvgRenderer::Ptr> renderers; + static QHash<QString, SharedSvgRenderer::Ptr> s_renderers; SharedSvgRenderer::Ptr renderer; QString themePath; QString path; @@ -314,7 +317,7 @@ bool applyColors; }; -QHash<QString, SharedSvgRenderer::Ptr> SvgPrivate::renderers; +QHash<QString, SharedSvgRenderer::Ptr> SvgPrivate::s_renderers; Svg::Svg(QObject *parent) : QObject(parent), @@ -371,14 +374,16 @@ void Svg::resize(const QSizeF &size) { - d->createRenderer(); d->size = size; } void Svg::resize() { - d->createRenderer(); - d->size = d->renderer->defaultSize(); + if (d->renderer) { + d->size = d->renderer->defaultSize(); + } else { + d->size = QSizeF(); + } } QSize Svg::elementSize(const QString &elementId) const @@ -393,6 +398,10 @@ bool Svg::hasElement(const QString &elementId) const { + if (d->path.isNull() && d->themePath.isNull()) { + return false; + } + d->createRenderer(); return d->renderer->elementExists(elementId); } @@ -415,6 +424,10 @@ bool Svg::isValid() const { + if (d->path.isNull() && d->themePath.isNull()) { + return false; + } + d->createRenderer(); return d->renderer->isValid(); } @@ -431,9 +444,10 @@ void Svg::setImagePath(const QString &svgFilePath) { - d->setImagePath(svgFilePath, this); - d->eraseRenderer(); - emit repaintNeeded(); + if (d->setImagePath(svgFilePath, this)) { + d->eraseRenderer(); + emit repaintNeeded(); + } } QString Svg::imagePath() const Index: theme.cpp =================================================================== --- theme.cpp (revision 871491) +++ theme.cpp (working copy) @@ -25,15 +25,17 @@ #include <QX11Info> #endif -#include <KWindowSystem> #include <KColorScheme> +#include <KComponentData> #include <KConfigGroup> #include <KDebug> #include <KGlobal> +#include <KGlobalSettings> +#include <KPixmapCache> #include <KSelectionWatcher> #include <KSharedConfig> #include <KStandardDirs> -#include <KGlobalSettings> +#include <KWindowSystem> #include "private/packages_p.h" @@ -56,6 +58,7 @@ defaultWallpaperSuffix(DEFAULT_WALLPAPER_SUFFIX), defaultWallpaperWidth(DEFAULT_WALLPAPER_WIDTH), defaultWallpaperHeight(DEFAULT_WALLPAPER_HEIGHT), + pixmapCache(0), locolor(false), compositingActive(KWindowSystem::compositingActive()), isDefault(false), @@ -102,6 +105,7 @@ QString defaultWallpaperSuffix; int defaultWallpaperWidth; int defaultWallpaperHeight; + KPixmapCache *pixmapCache; #ifdef Q_WS_X11 KSelectionWatcher *compositeWatch; @@ -466,6 +470,24 @@ return d->useGlobal; } +bool Theme::findInCache(const QString &key, QPixmap &pix) +{ + if (!d->pixmapCache) { + d->pixmapCache = new KPixmapCache(KGlobal::mainComponent().componentName()); + } + + return d->pixmapCache->find(key, pix); } +void Theme::insertIntoCache(const QString& key, const QPixmap& pix) +{ + if (!d->pixmapCache) { + d->pixmapCache = new KPixmapCache(KGlobal::mainComponent().componentName()); + } + + d->pixmapCache->insert(key, pix); +} + +} + #include <theme.moc>
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Plasma-devel mailing list Plasma-devel@kde.org https://mail.kde.org/mailman/listinfo/plasma-devel