diff options
author | reed <reed@chromium.org> | 2015-02-24 13:54:23 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-24 13:54:23 -0800 |
commit | 7eeba2587760a0802fd2b90765b4fd0e5e895375 (patch) | |
tree | dad9caa7dde038c52728034710c3d6d4926bfff2 | |
parent | 4b583ac54b92ad6e7685bdfa2b68e7dd11ba0d28 (diff) |
Notify resource caches when pixelref genID goes stale
patch from issue 954443002 at patchset 40001 (http://crrev.com/954443002#ps40001)
BUG=skia:
Review URL: https://codereview.chromium.org/950363002
-rw-r--r-- | bench/ImageCacheBench.cpp | 2 | ||||
-rw-r--r-- | src/core/SkBitmapCache.cpp | 69 | ||||
-rw-r--r-- | src/core/SkBitmapCache.h | 4 | ||||
-rw-r--r-- | src/core/SkMaskCache.cpp | 4 | ||||
-rw-r--r-- | src/core/SkPictureShader.cpp | 2 | ||||
-rw-r--r-- | src/core/SkPixelRef.cpp | 7 | ||||
-rw-r--r-- | src/core/SkResourceCache.cpp | 57 | ||||
-rw-r--r-- | src/core/SkResourceCache.h | 35 | ||||
-rw-r--r-- | src/core/SkYUVPlanesCache.cpp | 6 | ||||
-rw-r--r-- | tests/ImageCacheTest.cpp | 40 | ||||
-rw-r--r-- | tests/SkResourceCacheTest.cpp | 64 |
11 files changed, 250 insertions, 40 deletions
diff --git a/bench/ImageCacheBench.cpp b/bench/ImageCacheBench.cpp index 1160f9353d..75adc50dcb 100644 --- a/bench/ImageCacheBench.cpp +++ b/bench/ImageCacheBench.cpp @@ -15,7 +15,7 @@ public: intptr_t fValue; TestKey(intptr_t value) : fValue(value) { - this->init(&gGlobalAddress, sizeof(fValue)); + this->init(&gGlobalAddress, 0, sizeof(fValue)); } }; struct TestRec : public SkResourceCache::Rec { diff --git a/src/core/SkBitmapCache.cpp b/src/core/SkBitmapCache.cpp index 3af582232b..c411a1bd9d 100644 --- a/src/core/SkBitmapCache.cpp +++ b/src/core/SkBitmapCache.cpp @@ -10,6 +10,20 @@ #include "SkMipMap.h" #include "SkRect.h" +/** + * Use this for bitmapcache and mipmapcache entries. + */ +uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID) { + uint64_t sharedID = SkSetFourByteTag('b', 'm', 'a', 'p'); + return (sharedID << 32) | bitmapGenID; +} + +void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID) { + SkResourceCache::PostPurgeSharedID(SkMakeResourceCacheSharedIDForBitmap(bitmapGenID)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + SkBitmap::Allocator* SkBitmapCache::GetAllocator() { return SkResourceCache::GetAllocator(); } @@ -33,13 +47,13 @@ static unsigned gBitmapKeyNamespaceLabel; struct BitmapKey : public SkResourceCache::Key { public: - BitmapKey(uint32_t genID, SkScalar scaleX, SkScalar scaleY, const SkIRect& bounds) - : fGenID(genID) - , fScaleX(scaleX) - , fScaleY(scaleY) - , fBounds(bounds) + BitmapKey(uint32_t genID, SkScalar sx, SkScalar sy, const SkIRect& bounds) + : fGenID(genID) + , fScaleX(sx) + , fScaleY(sy) + , fBounds(bounds) { - this->init(&gBitmapKeyNamespaceLabel, + this->init(&gBitmapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), sizeof(fGenID) + sizeof(fScaleX) + sizeof(fScaleY) + sizeof(fBounds)); } @@ -49,8 +63,6 @@ public: SkIRect fBounds; }; -////////////////////////////////////////////////////////////////////////////////////////// - struct BitmapRec : public SkResourceCache::Rec { BitmapRec(uint32_t genID, SkScalar scaleX, SkScalar scaleY, const SkIRect& bounds, const SkBitmap& result) @@ -58,13 +70,10 @@ struct BitmapRec : public SkResourceCache::Rec { , fBitmap(result) {} - BitmapKey fKey; - SkBitmap fBitmap; - const Key& getKey() const SK_OVERRIDE { return fKey; } size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + fBitmap.getSize(); } - static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextBitmap) { + static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) { const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec); SkBitmap* result = (SkBitmap*)contextBitmap; @@ -72,6 +81,10 @@ struct BitmapRec : public SkResourceCache::Rec { result->lockPixels(); return SkToBool(result->getPixels()); } + +private: + BitmapKey fKey; + SkBitmap fBitmap; }; } // namespace @@ -86,7 +99,7 @@ bool SkBitmapCache::Find(const SkBitmap& src, SkScalar invScaleX, SkScalar invSc } BitmapKey key(src.getGenerationID(), invScaleX, invScaleY, get_bounds_from_bitmap(src)); - return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Visitor, result); + return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result); } void SkBitmapCache::Add(const SkBitmap& src, SkScalar invScaleX, SkScalar invScaleY, @@ -105,7 +118,7 @@ bool SkBitmapCache::Find(uint32_t genID, const SkIRect& subset, SkBitmap* result SkResourceCache* localCache) { BitmapKey key(genID, SK_Scalar1, SK_Scalar1, subset); - return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Visitor, result); + return CHECK_LOCAL(localCache, find, Find, key, BitmapRec::Finder, result); } bool SkBitmapCache::Add(uint32_t genID, const SkIRect& subset, const SkBitmap& result, @@ -125,11 +138,27 @@ bool SkBitmapCache::Add(uint32_t genID, const SkIRect& subset, const SkBitmap& r return true; } } + ////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +namespace { +static unsigned gMipMapKeyNamespaceLabel; + +struct MipMapKey : public SkResourceCache::Key { +public: + MipMapKey(uint32_t genID, const SkIRect& bounds) : fGenID(genID), fBounds(bounds) { + this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), + sizeof(fGenID) + sizeof(fBounds)); + } + + uint32_t fGenID; + SkIRect fBounds; +}; struct MipMapRec : public SkResourceCache::Rec { MipMapRec(const SkBitmap& src, const SkMipMap* result) - : fKey(src.getGenerationID(), 0, 0, get_bounds_from_bitmap(src)) + : fKey(src.getGenerationID(), get_bounds_from_bitmap(src)) , fMipMap(result) { fMipMap->attachToCacheAndRef(); @@ -142,7 +171,7 @@ struct MipMapRec : public SkResourceCache::Rec { const Key& getKey() const SK_OVERRIDE { return fKey; } size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + fMipMap->size(); } - static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextMip) { + static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) { const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec); const SkMipMap* mm = SkRef(rec.fMipMap); // the call to ref() above triggers a "lock" in the case of discardable memory, @@ -157,15 +186,16 @@ struct MipMapRec : public SkResourceCache::Rec { } private: - BitmapKey fKey; + MipMapKey fKey; const SkMipMap* fMipMap; }; +} const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmap& src, SkResourceCache* localCache) { - BitmapKey key(src.getGenerationID(), 0, 0, get_bounds_from_bitmap(src)); + MipMapKey key(src.getGenerationID(), get_bounds_from_bitmap(src)); const SkMipMap* result; - if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Visitor, &result)) { + if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) { result = NULL; } return result; @@ -184,4 +214,3 @@ const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* l } return mipmap; } - diff --git a/src/core/SkBitmapCache.h b/src/core/SkBitmapCache.h index ec8a6b803e..c54f96141c 100644 --- a/src/core/SkBitmapCache.h +++ b/src/core/SkBitmapCache.h @@ -14,6 +14,10 @@ class SkResourceCache; class SkMipMap; +uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID); + +void SkNotifyBitmapGenIDIsStale(uint32_t bitmapGenID); + class SkBitmapCache { public: /** diff --git a/src/core/SkMaskCache.cpp b/src/core/SkMaskCache.cpp index 02d355d4f1..b0399b114b 100644 --- a/src/core/SkMaskCache.cpp +++ b/src/core/SkMaskCache.cpp @@ -26,7 +26,7 @@ public: , fQuality(quality) , fRRect(rrect) { - this->init(&gRRectBlurKeyNamespaceLabel, + this->init(&gRRectBlurKeyNamespaceLabel, 0, sizeof(fSigma) + sizeof(fStyle) + sizeof(fQuality) + sizeof(fRRect)); } @@ -117,7 +117,7 @@ public: fSizes[2] = SkSize::Make(rects[0].x() - rects[1].x(), rects[0].y() - rects[1].y()); } - this->init(&gRectsBlurKeyNamespaceLabel, + this->init(&gRectsBlurKeyNamespaceLabel, 0, sizeof(fSigma) + sizeof(fStyle) + sizeof(fQuality) + sizeof(fSizes)); } diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp index 1453aee0a8..a32368b218 100644 --- a/src/core/SkPictureShader.cpp +++ b/src/core/SkPictureShader.cpp @@ -92,7 +92,7 @@ public: sizeof(fLocalMatrixStorage); // This better be packed. SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - &fPictureID) == keySize); - this->init(&gBitmapSkaderKeyNamespaceLabel, keySize); + this->init(&gBitmapSkaderKeyNamespaceLabel, 0, keySize); } private: diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp index c73c2f4b7d..a5d6c71778 100644 --- a/src/core/SkPixelRef.cpp +++ b/src/core/SkPixelRef.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkBitmapCache.h" #include "SkPixelRef.h" #include "SkThread.h" @@ -214,12 +215,18 @@ void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) { *fGenIDChangeListeners.append() = listener; } +// we need to be called *before* the genID gets changed or zerod void SkPixelRef::callGenIDChangeListeners() { // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID. if (fUniqueGenerationID) { for (int i = 0; i < fGenIDChangeListeners.count(); i++) { fGenIDChangeListeners[i]->onChange(); } + + // If we can flag the pixelref somehow whenever it was actually added to the cache, + // perhaps it would be nice to only call this notifier in that case. For now we always + // call it, since we don't know if it was cached or not. + SkNotifyBitmapGenIDIsStale(fGenerationID); } // Listeners get at most one shot, so whether these triggered or not, blow them away. fGenIDChangeListeners.deleteAll(); diff --git a/src/core/SkResourceCache.cpp b/src/core/SkResourceCache.cpp index 4ed889a0ab..9da90c45dc 100644 --- a/src/core/SkResourceCache.cpp +++ b/src/core/SkResourceCache.cpp @@ -6,12 +6,15 @@ */ #include "SkChecksum.h" -#include "SkResourceCache.h" +#include "SkMessageBus.h" #include "SkMipMap.h" #include "SkPixelRef.h" +#include "SkResourceCache.h" #include <stddef.h> +DECLARE_SKMESSAGEBUS_MESSAGE(SkResourceCache::PurgeSharedIDMessage) + // This can be defined by the caller's build system //#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE @@ -23,18 +26,22 @@ #define SK_DEFAULT_IMAGE_CACHE_LIMIT (2 * 1024 * 1024) #endif -void SkResourceCache::Key::init(void* nameSpace, size_t length) { +void SkResourceCache::Key::init(void* nameSpace, uint64_t sharedID, size_t length) { SkASSERT(SkAlign4(length) == length); // fCount32 and fHash are not hashed - static const int kUnhashedLocal32s = 2; - static const int kLocal32s = kUnhashedLocal32s + (sizeof(fNamespace) >> 2); + static const int kUnhashedLocal32s = 2; // fCache32 + fHash + static const int kSharedIDLocal32s = 2; // fSharedID_lo + fSharedID_hi + static const int kHashedLocal32s = kSharedIDLocal32s + (sizeof(fNamespace) >> 2); + static const int kLocal32s = kUnhashedLocal32s + kHashedLocal32s; SK_COMPILE_ASSERT(sizeof(Key) == (kLocal32s << 2), unaccounted_key_locals); SK_COMPILE_ASSERT(sizeof(Key) == offsetof(Key, fNamespace) + sizeof(fNamespace), namespace_field_must_be_last); fCount32 = SkToS32(kLocal32s + (length >> 2)); + fSharedID_lo = (uint32_t)sharedID; + fSharedID_hi = (uint32_t)(sharedID >> 32); fNamespace = nameSpace; // skip unhashed fields when computing the murmur fHash = SkChecksum::Murmur3(this->as32() + kUnhashedLocal32s, @@ -199,7 +206,9 @@ SkResourceCache::~SkResourceCache() { //////////////////////////////////////////////////////////////////////////////// -bool SkResourceCache::find(const Key& key, VisitorProc visitor, void* context) { +bool SkResourceCache::find(const Key& key, FindVisitor visitor, void* context) { + this->checkMessages(); + Rec* rec = fHash->find(key); if (rec) { if (visitor(*rec, context)) { @@ -226,6 +235,8 @@ static void make_size_str(size_t size, SkString* str) { static bool gDumpCacheTransactions; void SkResourceCache::add(Rec* rec) { + this->checkMessages(); + SkASSERT(rec); // See if we already have this key (racy inserts, etc.) Rec* existing = fHash->find(rec->getKey()); @@ -294,6 +305,24 @@ void SkResourceCache::purgeAsNeeded(bool forcePurge) { } } +void SkResourceCache::purgeSharedID(uint64_t sharedID) { + if (0 == sharedID) { + return; + } + + // go backwards, just like purgeAsNeeded, just to make the code similar. + // could iterate either direction and still be correct. + Rec* rec = fTail; + while (rec) { + Rec* prev = rec->fPrev; + if (rec->getKey().getSharedID() == sharedID) { +// SkDebugf("purgeSharedID id=%llx rec=%p\n", sharedID, rec); + this->remove(rec); + } + rec = prev; + } +} + size_t SkResourceCache::setTotalByteLimit(size_t newLimit) { size_t prevLimit = fTotalByteLimit; fTotalByteLimit = newLimit; @@ -304,6 +333,8 @@ size_t SkResourceCache::setTotalByteLimit(size_t newLimit) { } SkCachedData* SkResourceCache::newCachedData(size_t bytes) { + this->checkMessages(); + if (fDiscardableFactory) { SkDiscardableMemory* dm = fDiscardableFactory(bytes); return dm ? SkNEW_ARGS(SkCachedData, (bytes, dm)) : NULL; @@ -451,6 +482,14 @@ size_t SkResourceCache::getEffectiveSingleAllocationByteLimit() const { return limit; } +void SkResourceCache::checkMessages() { + SkTArray<PurgeSharedIDMessage> msgs; + fPurgeSharedIDInbox.poll(&msgs); + for (int i = 0; i < msgs.count(); ++i) { + this->purgeSharedID(msgs[i].fSharedID); + } +} + /////////////////////////////////////////////////////////////////////////////// #include "SkThread.h" @@ -537,7 +576,7 @@ void SkResourceCache::PurgeAll() { return get_cache()->purgeAll(); } -bool SkResourceCache::Find(const Key& key, VisitorProc visitor, void* context) { +bool SkResourceCache::Find(const Key& key, FindVisitor visitor, void* context) { SkAutoMutexAcquire am(gMutex); return get_cache()->find(key, visitor, context); } @@ -547,6 +586,12 @@ void SkResourceCache::Add(Rec* rec) { get_cache()->add(rec); } +void SkResourceCache::PostPurgeSharedID(uint64_t sharedID) { + if (sharedID) { + SkMessageBus<PurgeSharedIDMessage>::Post(PurgeSharedIDMessage(sharedID)); + } +} + /////////////////////////////////////////////////////////////////////////////// #include "SkGraphics.h" diff --git a/src/core/SkResourceCache.h b/src/core/SkResourceCache.h index 88ccb87ed8..b43572f4be 100644 --- a/src/core/SkResourceCache.h +++ b/src/core/SkResourceCache.h @@ -9,6 +9,8 @@ #define SkResourceCache_DEFINED #include "SkBitmap.h" +#include "SkMessageBus.h" +#include "SkTDArray.h" class SkCachedData; class SkDiscardableMemory; @@ -32,8 +34,12 @@ public: // must call this after your private data has been written. // nameSpace must be unique per Key subclass. + // sharedID == 0 means ignore this field : does not support group purging. // length must be a multiple of 4 - void init(void* nameSpace, size_t length); + void init(void* nameSpace, uint64_t sharedID, size_t length); + + void* getNamespace() const { return fNamespace; } + uint64_t getSharedID() const { return ((uint64_t)fSharedID_hi << 32) | fSharedID_lo; } // This is only valid after having called init(). uint32_t hash() const { return fHash; } @@ -52,6 +58,9 @@ public: private: int32_t fCount32; // local + user contents count32 uint32_t fHash; + // split uint64_t into hi and lo so we don't force ourselves to pad on 32bit machines. + uint32_t fSharedID_lo; + uint32_t fSharedID_hi; void* fNamespace; // A unique namespace tag. This is hashed. /* uint32_t fContents32[] */ @@ -80,6 +89,13 @@ public: friend class SkResourceCache; }; + // Used with SkMessageBus + struct PurgeSharedIDMessage { + PurgeSharedIDMessage(uint64_t sharedID) : fSharedID(sharedID) {} + + uint64_t fSharedID; + }; + typedef const Rec* ID; /** @@ -92,7 +108,7 @@ public: * true, then the Rec is considered "valid". If false is returned, the Rec will be considered * "stale" and will be purged from the cache. */ - typedef bool (*VisitorProc)(const Rec&, void* context); + typedef bool (*FindVisitor)(const Rec&, void* context); /** * Returns a locked/pinned SkDiscardableMemory instance for the specified @@ -109,12 +125,12 @@ public: * Returns true if the visitor was called on a matching Key, and the visitor returned true. * * Find() will search the cache for the specified Key. If no match is found, return false and - * do not call the VisitorProc. If a match is found, return whatever the visitor returns. + * do not call the FindVisitor. If a match is found, return whatever the visitor returns. * Its return value is interpreted to mean: * true : Rec is valid * false : Rec is "stale" -- the cache will purge it. */ - static bool Find(const Key& key, VisitorProc, void* context); + static bool Find(const Key& key, FindVisitor, void* context); static void Add(Rec*); static size_t GetTotalBytesUsed(); @@ -140,6 +156,8 @@ public: static SkCachedData* NewCachedData(size_t bytes); + static void PostPurgeSharedID(uint64_t sharedID); + /** * Call SkDebugf() with diagnostic information about the state of the cache */ @@ -169,12 +187,12 @@ public: * Returns true if the visitor was called on a matching Key, and the visitor returned true. * * find() will search the cache for the specified Key. If no match is found, return false and - * do not call the VisitorProc. If a match is found, return whatever the visitor returns. + * do not call the FindVisitor. If a match is found, return whatever the visitor returns. * Its return value is interpreted to mean: * true : Rec is valid * false : Rec is "stale" -- the cache will purge it. */ - bool find(const Key&, VisitorProc, void* context); + bool find(const Key&, FindVisitor, void* context); void add(Rec*); size_t getTotalBytesUsed() const { return fTotalBytesUsed; } @@ -198,6 +216,8 @@ public: */ size_t setTotalByteLimit(size_t newLimit); + void purgeSharedID(uint64_t sharedID); + void purgeAll() { this->purgeAsNeeded(true); } @@ -228,6 +248,9 @@ private: size_t fSingleAllocationByteLimit; int fCount; + SkMessageBus<PurgeSharedIDMessage>::Inbox fPurgeSharedIDInbox; + + void checkMessages(); void purgeAsNeeded(bool forcePurge = false); // linklist management diff --git a/src/core/SkYUVPlanesCache.cpp b/src/core/SkYUVPlanesCache.cpp index 69885fe46a..5ef89b6c19 100644 --- a/src/core/SkYUVPlanesCache.cpp +++ b/src/core/SkYUVPlanesCache.cpp @@ -5,8 +5,9 @@ * found in the LICENSE file. */ -#include "SkYUVPlanesCache.h" +#include "SkBitmapCache.h" #include "SkResourceCache.h" +#include "SkYUVPlanesCache.h" #define CHECK_LOCAL(localCache, localName, globalName, ...) \ ((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__)) @@ -23,7 +24,8 @@ struct YUVPlanesKey : public SkResourceCache::Key { YUVPlanesKey(uint32_t genID) : fGenID(genID) { - this->init(&gYUVPlanesKeyNamespaceLabel, sizeof(genID)); + this->init(&gYUVPlanesKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), + sizeof(genID)); } uint32_t fGenID; diff --git a/tests/ImageCacheTest.cpp b/tests/ImageCacheTest.cpp index a4cfa73989..45dee92a2f 100644 --- a/tests/ImageCacheTest.cpp +++ b/tests/ImageCacheTest.cpp @@ -14,8 +14,8 @@ static void* gGlobalAddress; struct TestingKey : public SkResourceCache::Key { intptr_t fValue; - TestingKey(intptr_t value) : fValue(value) { - this->init(&gGlobalAddress, sizeof(fValue)); + TestingKey(intptr_t value, uint64_t sharedID = 0) : fValue(value) { + this->init(&gGlobalAddress, sharedID, sizeof(fValue)); } }; struct TestingRec : public SkResourceCache::Rec { @@ -71,6 +71,38 @@ static void test_cache(skiatest::Reporter* reporter, SkResourceCache& cache, boo cache.setTotalByteLimit(0); } +static void test_cache_purge_shared_id(skiatest::Reporter* reporter, SkResourceCache& cache) { + for (int i = 0; i < COUNT; ++i) { + TestingKey key(i, i & 1); // every other key will have a 1 for its sharedID + cache.add(SkNEW_ARGS(TestingRec, (key, i))); + } + + // Ensure that everyone is present + for (int i = 0; i < COUNT; ++i) { + TestingKey key(i, i & 1); // every other key will have a 1 for its sharedID + intptr_t value = -1; + + REPORTER_ASSERT(reporter, cache.find(key, TestingRec::Visitor, &value)); + REPORTER_ASSERT(reporter, value == i); + } + + // Now purge the ones that had a non-zero sharedID (the odd-indexed ones) + cache.purgeSharedID(1); + + // Ensure that only the even ones are still present + for (int i = 0; i < COUNT; ++i) { + TestingKey key(i, i & 1); // every other key will have a 1 for its sharedID + intptr_t value = -1; + + if (i & 1) { + REPORTER_ASSERT(reporter, !cache.find(key, TestingRec::Visitor, &value)); + } else { + REPORTER_ASSERT(reporter, cache.find(key, TestingRec::Visitor, &value)); + REPORTER_ASSERT(reporter, value == i); + } + } +} + #include "SkDiscardableMemoryPool.h" static SkDiscardableMemoryPool* gPool; @@ -97,6 +129,10 @@ DEF_TEST(ImageCache, reporter) { SkResourceCache cache(SkDiscardableMemory::Create); test_cache(reporter, cache, false); } + { + SkResourceCache cache(defLimit); + test_cache_purge_shared_id(reporter, cache); + } } DEF_TEST(ImageCache_doubleAdd, r) { diff --git a/tests/SkResourceCacheTest.cpp b/tests/SkResourceCacheTest.cpp index 179e771ed8..626c837361 100644 --- a/tests/SkResourceCacheTest.cpp +++ b/tests/SkResourceCacheTest.cpp @@ -156,6 +156,14 @@ static void test_mipmapcache(skiatest::Reporter* reporter, SkResourceCache* cach mipmap = SkMipMapCache::AddAndRef(src, cache); REPORTER_ASSERT(reporter, mipmap); + + { + const SkMipMap* mm = SkMipMapCache::FindAndRef(src, cache); + REPORTER_ASSERT(reporter, mm); + REPORTER_ASSERT(reporter, mm == mipmap); + mm->unref(); + } + check_data(reporter, mipmap, 2, kInCache, kLocked); mipmap->unref(); @@ -173,6 +181,60 @@ static void test_mipmapcache(skiatest::Reporter* reporter, SkResourceCache* cach mipmap->unref(); } +static void test_mipmap_notify(skiatest::Reporter* reporter, SkResourceCache* cache) { + const int N = 3; + SkBitmap src[N]; + for (int i = 0; i < N; ++i) { + src[i].allocN32Pixels(5, 5); + src[i].setImmutable(); + SkMipMapCache::AddAndRef(src[i], cache)->unref(); + } + + for (int i = 0; i < N; ++i) { + const SkMipMap* mipmap = SkMipMapCache::FindAndRef(src[i], cache); + if (cache) { + // if cache is null, we're working on the global cache, and other threads might purge + // it, making this check fragile. + REPORTER_ASSERT(reporter, mipmap); + } + SkSafeUnref(mipmap); + + src[i].reset(); // delete the underlying pixelref, which *should* remove us from the cache + + mipmap = SkMipMapCache::FindAndRef(src[i], cache); + REPORTER_ASSERT(reporter, !mipmap); + } +} + +static void test_bitmap_notify(skiatest::Reporter* reporter, SkResourceCache* cache) { + const SkIRect subset = SkIRect::MakeWH(5, 5); + const int N = 3; + SkBitmap src[N], dst[N]; + for (int i = 0; i < N; ++i) { + src[i].allocN32Pixels(5, 5); + src[i].setImmutable(); + dst[i].allocN32Pixels(5, 5); + dst[i].setImmutable(); + SkBitmapCache::Add(src[i].getGenerationID(), subset, dst[i], cache); + } + + for (int i = 0; i < N; ++i) { + const uint32_t genID = src[i].getGenerationID(); + SkBitmap result; + bool found = SkBitmapCache::Find(genID, subset, &result, cache); + if (cache) { + // if cache is null, we're working on the global cache, and other threads might purge + // it, making this check fragile. + REPORTER_ASSERT(reporter, found); + } + + src[i].reset(); // delete the underlying pixelref, which *should* remove us from the cache + + found = SkBitmapCache::Find(genID, subset, &result, cache); + REPORTER_ASSERT(reporter, !found); + } +} + DEF_TEST(BitmapCache_discarded_bitmap, reporter) { SkResourceCache::DiscardableFactory factory = SkResourceCache::GetDiscardableFactory(); SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator(); @@ -219,4 +281,6 @@ DEF_TEST(BitmapCache_discarded_bitmap, reporter) { REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache)); test_mipmapcache(reporter, cache); + test_bitmap_notify(reporter, cache); + test_mipmap_notify(reporter, cache); } |