diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index d403854661..0bf36e61c0 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -436,6 +436,7 @@ private: DECL_GFX_PREF(Live, "image.animated.resume-from-last-displayed", ImageAnimatedResumeFromLastDisplayed, bool, false); DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024); DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500); + DECL_GFX_PREF(Once, "image.cache.entry_timeout", ImageCacheEntryTimeout, int32_t, 15000); DECL_GFX_PREF(Live, "image.decode-immediately.enabled", ImageDecodeImmediatelyEnabled, bool, false); DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, true); DECL_GFX_PREF(Live, "image.infer-src-animation.threshold-ms", ImageInferSrcAnimationThresholdMS, uint32_t, 2000); diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index bb850172e3..b94f73e693 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -936,9 +936,9 @@ VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams, BackendTy // are scaled repeatedly (a rather common scenario) that can quickly exhaust // the cache. // Similar to max image size calculations, this has a max cap and size check. - // max cap = 8000 (pixels); size check = 5% of cache + // max cap = 8000 (pixels); size check = 10% of cache int32_t maxDimension = 8000; - int32_t maxCacheElemSize = (gfxPrefs::ImageMemSurfaceCacheMaxSizeKB() * 1024) / 20; + int32_t maxCacheElemSize = (gfxPrefs::ImageMemSurfaceCacheMaxSizeKB() * 1024) / 10; bool bypassCache = bool(aParams.flags & FLAG_BYPASS_SURFACE_CACHE) || // Refuse to cache animated images: diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index 8b1a5f03de..7d07f92cf6 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -1087,7 +1087,6 @@ imgLoader::CreateNewProxyForRequest(imgRequest* aRequest, class imgCacheExpirationTracker final : public nsExpirationTracker { - enum { TIMEOUT_SECONDS = 10 }; public: imgCacheExpirationTracker(); @@ -1096,10 +1095,46 @@ protected: }; imgCacheExpirationTracker::imgCacheExpirationTracker() - : nsExpirationTracker(TIMEOUT_SECONDS * 1000, + : nsExpirationTracker(gfxPrefs::ImageCacheEntryTimeout(), "imgCacheExpirationTracker") { } +static bool +ShouldKeepRecentlyUsedAssetInCache(imgCacheEntry* aEntry) +{ + RefPtr request = aEntry->GetRequest(); + if (!request) { + return false; + } + + const char* mimeType = request->GetMimeType(); + if (!mimeType) { + return false; + } + + // Keep small, frequently reused static image assets warm a bit longer. + if (!nsCRT::strcmp(mimeType, IMAGE_SVG_XML) || + !nsCRT::strcmp(mimeType, IMAGE_JPG) || + !nsCRT::strcmp(mimeType, IMAGE_JPEG) || + !nsCRT::strcmp(mimeType, IMAGE_ICO) || + !nsCRT::strcmp(mimeType, IMAGE_PNG) || + !nsCRT::strcmp(mimeType, IMAGE_WEBP)) { + // XXX: Should we make these configurable too? + const uint32_t kMaxWarmAssetBytes = 128 * 1024; // <= 128 kiB entries only + const uint32_t kRecentUseGraceSeconds = 60; // keep warm for 60 s + + if (aEntry->GetDataSize() <= kMaxWarmAssetBytes) { + uint32_t now = SecondsFromPRTime(PR_Now()); + uint32_t touched = aEntry->GetTouchedTime(); + if (now >= touched && (now - touched) <= kRecentUseGraceSeconds) { + return true; + } + } + } + + return false; +} + void imgCacheExpirationTracker::NotifyExpired(imgCacheEntry* entry) { @@ -1107,6 +1142,12 @@ imgCacheExpirationTracker::NotifyExpired(imgCacheEntry* entry) // mechanism doesn't. RefPtr kungFuDeathGrip(entry); + if (ShouldKeepRecentlyUsedAssetInCache(entry)) { + entry->Touch(); + entry->Loader()->VerifyCacheSizes(); + return; + } + if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) { RefPtr req = entry->GetRequest(); if (req) { diff --git a/image/imgLoader.h b/image/imgLoader.h index 8fee429e45..23ae95b948 100644 --- a/image/imgLoader.h +++ b/image/imgLoader.h @@ -152,6 +152,7 @@ public: private: // methods friend class imgLoader; friend class imgCacheQueue; + friend class imgCacheExpirationTracker; void Touch(bool updateTime = true); void UpdateCache(int32_t diff = 0); void SetEvicted(bool evict) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 9609d814ff..5f04312b54 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4262,12 +4262,18 @@ pref("image.animated.decode-on-demand.batch-size", 6); // advancing when out of view. pref("image.animated.resume-from-last-displayed", true); +// Image cache prefs: Restart required for changes. + // The maximum size, in bytes, of the decoded images we cache -pref("image.cache.size", 5242880); +pref("image.cache.size", 26214400); // A weight, from 0-1000, to place on time when comparing to size. // Size is given a weight of 1000 - timeweight. -pref("image.cache.timeweight", 500); +pref("image.cache.timeweight", 650); + +// Time in ms before unproxied entries in the in-memory image cache are +// considered for eviction by the expiration tracker. +pref("image.cache.entry_timeout", 15000); // Decode all images automatically on load, ignoring our normal heuristics. pref("image.decode-immediately.enabled", false); @@ -4314,7 +4320,7 @@ pref("image.mem.decode_bytes_at_a_time", 16384); // Minimum timeout for expiring unused images from the surface cache, in // milliseconds. This controls how long we store cached temporary surfaces. -pref("image.mem.surfacecache.min_expiration_ms", 60000); // 60s +pref("image.mem.surfacecache.min_expiration_ms", 180000); // 180s // Maximum size for the surface cache, in kilobytes. pref("image.mem.surfacecache.max_size_kb", 1048576); // 1GB @@ -4331,7 +4337,7 @@ pref("image.mem.surfacecache.size_factor", 4); // surface cache on memory pressure, a discard factor of 2 means to discard half // of the data, and so forth. The default should be a good balance for desktop // and laptop systems, where we never discard visible images. -pref("image.mem.surfacecache.discard_factor", 1); +pref("image.mem.surfacecache.discard_factor", 2); // How many threads we'll use for multithreaded decoding. If < 0, will be // automatically determined based on the system's number of cores.