From 2332a74bbeef2c7bd6885d8af7f0df1fa1c79cf2 Mon Sep 17 00:00:00 2001 From: Mark Furneaux Date: Tue, 27 May 2014 17:40:25 -0400 Subject: [PATCH] Add persistent disk cache for library pixmaps I'll reference #4379 When viewing the library with album covers visible, the covers load very slowly the first time as they have to wait on the tagreaders. If I scroll down the library, it takes minutes for the tagreader to catch up. The nice thing is that the pixmaps are cached. However, once Clementine is restarted, the whole process has to happen again. This patch adds a persistent disk cache in the form of a QNetworkDiskCache to store the pixmaps on disk and load them into the QPixmapCache as required. I've noted literally night and day performance improvements, not only when scrolling through the library. There is much better interface responsiveness when searching, and I no longer see the no_cover_icon temporarily anymore. --- src/library/librarymodel.cpp | 38 ++++++++++++++++++++++++++++++++++++ src/library/librarymodel.h | 7 ++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/library/librarymodel.cpp b/src/library/librarymodel.cpp index 3e048da67..3bfa9750c 100644 --- a/src/library/librarymodel.cpp +++ b/src/library/librarymodel.cpp @@ -21,7 +21,10 @@ #include #include +#include #include +#include +#include #include #include #include @@ -37,6 +40,7 @@ #include "core/database.h" #include "core/logging.h" #include "core/taskmanager.h" +#include "core/utilities.h" #include "covers/albumcoverloader.h" #include "playlist/songmimedata.h" #include "smartplaylists/generator.h" @@ -58,6 +62,7 @@ const char* LibraryModel::kSmartPlaylistsSettingsGroup = "SerialisedSmartPlaylists"; const int LibraryModel::kSmartPlaylistsVersion = 4; const int LibraryModel::kPrettyCoverSize = 32; +const qint64 LibraryModel::kIconCacheSize = 100000000; //~100MB typedef QFuture RootQueryFuture; typedef QFutureWatcher RootQueryWatcher; @@ -84,6 +89,7 @@ LibraryModel::LibraryModel(LibraryBackend* backend, Application* app, album_icon_(":/icons/22x22/x-clementine-album.png"), playlists_dir_icon_(IconLoader::Load("folder-sound")), playlist_icon_(":/icons/22x22/x-clementine-albums.png"), + icon_cache_(new QNetworkDiskCache(this)), init_task_id_(-1), use_pretty_covers_(false), show_dividers_(true) { @@ -100,6 +106,10 @@ LibraryModel::LibraryModel(LibraryBackend* backend, Application* app, connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)), SLOT(AlbumArtLoaded(quint64, QImage))); + icon_cache_->setCacheDirectory( + Utilities::GetConfigPath(Utilities::Path_CacheRoot) + "/pixmapcache"); + icon_cache_->setMaximumCacheSize(LibraryModel::kIconCacheSize); + no_cover_icon_ = QPixmap(":nocover.png") .scaled(kPrettyCoverSize, kPrettyCoverSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); @@ -454,6 +464,20 @@ QVariant LibraryModel::AlbumIcon(const QModelIndex& index) { return cached_pixmap; } + // Try to load it from the disk cache + QIODevice* cache; + cache = icon_cache_->data(QUrl(cache_key)); + if (cache != 0) { + QImage cached_pixmap; + if (cached_pixmap.load(cache, "XPM")) { + delete cache; + qLog(Debug) << "Loading pixmap from disk..."; + QPixmapCache::insert(cache_key, QPixmap::fromImage(cached_pixmap)); + return QPixmap::fromImage(cached_pixmap); + } + delete cache; + } + // Maybe we're loading a pixmap already? if (pending_cache_keys_.contains(cache_key)) { return no_cover_icon_; @@ -488,6 +512,20 @@ void LibraryModel::AlbumArtLoaded(quint64 id, const QImage& image) { QPixmapCache::insert(cache_key, QPixmap::fromImage(image)); } + // if not already in the disk cache + if (icon_cache_->data(QUrl(cache_key)) == 0) { + qLog(Debug) << "Caching new pixmap..."; + QNetworkCacheMetaData* item_metadata = new QNetworkCacheMetaData(); + item_metadata->setSaveToDisk(true); + item_metadata->setUrl(QUrl(cache_key)); + QIODevice* cache = icon_cache_->prepare(*item_metadata); + if (cache != 0) { + image.save(cache, "XPM"); + icon_cache_->insert(cache); + } + delete item_metadata; + } + const QModelIndex index = ItemToIndex(item); emit dataChanged(index, index); } diff --git a/src/library/librarymodel.h b/src/library/librarymodel.h index 302f8ace7..3b7a5cef6 100644 --- a/src/library/librarymodel.h +++ b/src/library/librarymodel.h @@ -20,6 +20,7 @@ #include #include +#include #include "libraryitem.h" #include "libraryquery.h" @@ -47,7 +48,8 @@ class LibraryModel : public SimpleTreeModel { Q_ENUMS(GroupBy); public: - LibraryModel(LibraryBackend* backend, Application* app, QObject* parent = nullptr); + LibraryModel(LibraryBackend* backend, Application* app, + QObject* parent = nullptr); ~LibraryModel(); static const char* kSmartPlaylistsMimeType; @@ -55,6 +57,7 @@ class LibraryModel : public SimpleTreeModel { static const char* kSmartPlaylistsArray; static const int kSmartPlaylistsVersion; static const int kPrettyCoverSize; + static const qint64 kIconCacheSize; enum Role { Role_Type = Qt::UserRole + 1, @@ -279,6 +282,8 @@ signals: QIcon playlists_dir_icon_; QIcon playlist_icon_; + QNetworkDiskCache* icon_cache_; + int init_task_id_; bool use_pretty_covers_;