diff --git a/image/SurfaceCache.cpp b/image/SurfaceCache.cpp index 877893fd3c7b..543dd3a4142c 100644 --- a/image/SurfaceCache.cpp +++ b/image/SurfaceCache.cpp @@ -614,12 +614,29 @@ public: return false; } + template void CollectSizeOfSurfaces(nsTArray& aCounters, - MallocSizeOf aMallocSizeOf) + MallocSizeOf aMallocSizeOf, + Function&& aRemoveCallback) { CachedSurface::SurfaceMemoryReport report(aCounters, aMallocSizeOf); - for (auto iter = ConstIter(); !iter.Done(); iter.Next()) { + for (auto iter = mSurfaces.Iter(); !iter.Done(); iter.Next()) { NotNull surface = WrapNotNull(iter.UserData()); + + // We don't need the drawable surface for ourselves, but adding a surface + // to the report will trigger this indirectly. If the surface was + // discarded by the OS because it was in volatile memory, we should remove + // it from the cache immediately rather than include it in the report. + DrawableSurface drawableSurface; + if (!surface->IsPlaceholder()) { + drawableSurface = surface->GetDrawableSurface(); + if (!drawableSurface) { + aRemoveCallback(surface); + iter.Remove(); + continue; + } + } + const IntSize& size = surface->GetSurfaceKey().Size(); bool factor2Size = false; if (mFactor2Mode) { @@ -1073,6 +1090,8 @@ public: cache->Prune([this, &aAutoLock](NotNull aSurface) -> void { StopTracking(aSurface, /* aIsTracked */ true, aAutoLock); + // Individual surfaces must be freed outside the lock. + mCachedSurfacesDiscard.AppendElement(aSurface); }); } @@ -1165,7 +1184,8 @@ public: void CollectSizeOfSurfaces(const ImageKey aImageKey, nsTArray& aCounters, - MallocSizeOf aMallocSizeOf) + MallocSizeOf aMallocSizeOf, + const StaticMutexAutoLock& aAutoLock) { RefPtr cache = GetImageCache(aImageKey); if (!cache) { @@ -1173,7 +1193,12 @@ public: } // Report all surfaces in the per-image cache. - cache->CollectSizeOfSurfaces(aCounters, aMallocSizeOf); + cache->CollectSizeOfSurfaces(aCounters, aMallocSizeOf, + [this, &aAutoLock](NotNull aSurface) -> void { + StopTracking(aSurface, /* aIsTracked */ true, aAutoLock); + // Individual surfaces must be freed outside the lock. + mCachedSurfacesDiscard.AppendElement(aSurface); + }); } private: @@ -1544,9 +1569,13 @@ SurfaceCache::RemoveImage(const ImageKey aImageKey) /* static */ void SurfaceCache::PruneImage(const ImageKey aImageKey) { - StaticMutexAutoLock lock(sInstanceMutex); - if (sInstance) { - sInstance->PruneImage(aImageKey, lock); + nsTArray> discard; + { + StaticMutexAutoLock lock(sInstanceMutex); + if (sInstance) { + sInstance->PruneImage(aImageKey, lock); + sInstance->TakeDiscard(discard, lock); + } } } @@ -1568,12 +1597,16 @@ SurfaceCache::CollectSizeOfSurfaces(const ImageKey aImageKey, nsTArray& aCounters, MallocSizeOf aMallocSizeOf) { - StaticMutexAutoLock lock(sInstanceMutex); - if (!sInstance) { - return; - } + nsTArray> discard; + { + StaticMutexAutoLock lock(sInstanceMutex); + if (!sInstance) { + return; + } - return sInstance->CollectSizeOfSurfaces(aImageKey, aCounters, aMallocSizeOf); + sInstance->CollectSizeOfSurfaces(aImageKey, aCounters, aMallocSizeOf, lock); + sInstance->TakeDiscard(discard, lock); + } } /* static */ size_t