diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-09-26 19:28:27 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-09-26 19:28:27 +0000 |
commit | baed71fbfeee030184af74eb7e8622e99952bbf8 (patch) | |
tree | 302255f55dcca8c05167d1d6c700deaff2c099f9 /src/core/SkGlyphCache.cpp | |
parent | 97b4b67ee79b094ea6ec84071d4a233177f9c7bc (diff) |
add counting to Globals, and refactor some for clarity
BUG=
Review URL: https://codereview.chromium.org/24447003
git-svn-id: http://skia.googlecode.com/svn/trunk@11484 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkGlyphCache.cpp')
-rw-r--r-- | src/core/SkGlyphCache.cpp | 298 |
1 files changed, 144 insertions, 154 deletions
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp index 538c9682f5..9dd235c111 100644 --- a/src/core/SkGlyphCache.cpp +++ b/src/core/SkGlyphCache.cpp @@ -8,6 +8,7 @@ #include "SkGlyphCache.h" +#include "SkGlyphCache_Globals.h" #include "SkGraphics.h" #include "SkPaint.h" #include "SkPath.h" @@ -20,6 +21,20 @@ bool gSkSuppressFontCachePurgeSpew; +// Returns the shared globals +static SkGlyphCache_Globals& getSharedGlobals() { + // we leak this, so we don't incur any shutdown cost of the destructor + static SkGlyphCache_Globals* gGlobals = SkNEW_ARGS(SkGlyphCache_Globals, + (SkGlyphCache_Globals::kYes_UseMutex)); + return *gGlobals; +} + +// Returns the TLS globals (if set), or the shared globals +static SkGlyphCache_Globals& getGlobals() { + SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS(); + return tls ? *tls : getSharedGlobals(); +} + /////////////////////////////////////////////////////////////////////////////// #ifdef RECORD_HASH_EFFICIENCY @@ -397,108 +412,38 @@ void SkGlyphCache::invokeAndRemoveAuxProcs() { /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -#ifndef SK_DEFAULT_FONT_CACHE_LIMIT - #define SK_DEFAULT_FONT_CACHE_LIMIT (2 * 1024 * 1024) -#endif - #include "SkThread.h" -class SkGlyphCache_Globals { -public: - enum UseMutex { - kNo_UseMutex, // thread-local cache - kYes_UseMutex // shared cache - }; - - SkGlyphCache_Globals(UseMutex um) { - fHead = NULL; - fTotalMemoryUsed = 0; - fFontCacheLimit = SK_DEFAULT_FONT_CACHE_LIMIT; - fMutex = (kYes_UseMutex == um) ? SkNEW(SkMutex) : NULL; - } - - ~SkGlyphCache_Globals() { - SkGlyphCache* cache = fHead; - while (cache) { - SkGlyphCache* next = cache->fNext; - SkDELETE(cache); - cache = next; - } - - SkDELETE(fMutex); - } - - SkMutex* fMutex; - SkGlyphCache* fHead; - size_t fTotalMemoryUsed; - -#ifdef SK_DEBUG - void validate() const; -#else - void validate() const {} -#endif - - size_t getFontCacheLimit() const { return fFontCacheLimit; } - size_t setFontCacheLimit(size_t limit); - void purgeAll(); // does not change budget - - // can return NULL - static SkGlyphCache_Globals* FindTLS() { - return (SkGlyphCache_Globals*)SkTLS::Find(CreateTLS); - } - - static SkGlyphCache_Globals& GetTLS() { - return *(SkGlyphCache_Globals*)SkTLS::Get(CreateTLS, DeleteTLS); - } - - static void DeleteTLS() { SkTLS::Delete(CreateTLS); } - -private: - size_t fFontCacheLimit; - - static void* CreateTLS() { - return SkNEW_ARGS(SkGlyphCache_Globals, (kNo_UseMutex)); - } - - static void DeleteTLS(void* ptr) { - SkDELETE((SkGlyphCache_Globals*)ptr); - } -}; - -size_t SkGlyphCache_Globals::setFontCacheLimit(size_t newLimit) { +size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { static const size_t minLimit = 256 * 1024; if (newLimit < minLimit) { newLimit = minLimit; } - - size_t prevLimit = fFontCacheLimit; - fFontCacheLimit = newLimit; - - size_t currUsed = fTotalMemoryUsed; - if (currUsed > newLimit) { - SkAutoMutexAcquire ac(fMutex); - SkGlyphCache::InternalFreeCache(this, currUsed - newLimit); - } + + SkAutoMutexAcquire ac(fMutex); + + size_t prevLimit = fCacheSizeLimit; + fCacheSizeLimit = newLimit; + this->internalPurge(); return prevLimit; } -void SkGlyphCache_Globals::purgeAll() { +int SkGlyphCache_Globals::setCacheCountLimit(int newCount) { + if (newCount < 0) { + newCount = 0; + } + SkAutoMutexAcquire ac(fMutex); - SkGlyphCache::InternalFreeCache(this, fTotalMemoryUsed); + + int prevCount = fCacheCountLimit; + fCacheCountLimit = newCount; + this->internalPurge(); + return prevCount; } -// Returns the shared globals -static SkGlyphCache_Globals& getSharedGlobals() { - // we leak this, so we don't incur any shutdown cost of the destructor - static SkGlyphCache_Globals* gGlobals = SkNEW_ARGS(SkGlyphCache_Globals, - (SkGlyphCache_Globals::kYes_UseMutex)); - return *gGlobals; -} - -// Returns the TLS globals (if set), or the shared globals -static SkGlyphCache_Globals& getGlobals() { - SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS(); - return tls ? *tls : getSharedGlobals(); +void SkGlyphCache_Globals::purgeAll() { + SkAutoMutexAcquire ac(fMutex); + this->internalPurge(fTotalMemoryUsed); } void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), @@ -509,7 +454,7 @@ void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), globals.validate(); - for (cache = globals.fHead; cache != NULL; cache = cache->fNext) { + for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) { if (proc(cache, context)) { break; } @@ -540,9 +485,9 @@ SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, globals.validate(); - for (cache = globals.fHead; cache != NULL; cache = cache->fNext) { + for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) { if (cache->fDesc->equals(*desc)) { - cache->detach(&globals.fHead); + globals.internalDetachCache(cache); goto FOUND_IT; } } @@ -572,16 +517,11 @@ FOUND_IT: AutoValidate av(cache); - if (proc(cache, context)) { // stay detached - if (insideMutex) { - SkASSERT(globals.fTotalMemoryUsed >= cache->fMemoryUsed); - globals.fTotalMemoryUsed -= cache->fMemoryUsed; - } - } else { // reattach + if (!proc(cache, context)) { // need to reattach if (insideMutex) { - cache->attachToHead(&globals.fHead); + globals.internalAttachCacheToHead(cache); } else { - AttachCache(cache); + globals.attachCacheToHead(cache); } cache = NULL; } @@ -592,30 +532,23 @@ void SkGlyphCache::AttachCache(SkGlyphCache* cache) { SkASSERT(cache); SkASSERT(cache->fNext == NULL); - SkGlyphCache_Globals& globals = getGlobals(); - SkAutoMutexAcquire ac(globals.fMutex); + getGlobals().attachCacheToHead(cache); +} - globals.validate(); - cache->validate(); +/////////////////////////////////////////////////////////////////////////////// - // if we have a fixed budget for our cache, do a purge here - { - size_t allocated = globals.fTotalMemoryUsed + cache->fMemoryUsed; - size_t budgeted = globals.getFontCacheLimit(); - if (allocated > budgeted) { - (void)InternalFreeCache(&globals, allocated - budgeted); - } - } +void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { + SkAutoMutexAcquire ac(fMutex); - cache->attachToHead(&globals.fHead); - globals.fTotalMemoryUsed += cache->fMemoryUsed; + this->validate(); + cache->validate(); - globals.validate(); + this->internalAttachCacheToHead(cache); + this->internalPurge(); } -/////////////////////////////////////////////////////////////////////////////// - -SkGlyphCache* SkGlyphCache::FindTail(SkGlyphCache* cache) { +SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const { + SkGlyphCache* cache = fHead; if (cache) { while (cache->fNext) { cache = cache->fNext; @@ -624,63 +557,92 @@ SkGlyphCache* SkGlyphCache::FindTail(SkGlyphCache* cache) { return cache; } -#ifdef SK_DEBUG -void SkGlyphCache_Globals::validate() const { - size_t computed = 0; +size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) { + this->validate(); - const SkGlyphCache* head = fHead; - while (head != NULL) { - computed += head->fMemoryUsed; - head = head->fNext; + size_t bytesNeeded = 0; + if (fTotalMemoryUsed > fCacheSizeLimit) { + bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit; + } + bytesNeeded = SkMax32(bytesNeeded, minBytesNeeded); + if (bytesNeeded) { + // no small purges! + bytesNeeded = SkMax32(bytesNeeded, fTotalMemoryUsed >> 2); } - if (fTotalMemoryUsed != computed) { - printf("total %d, computed %d\n", (int)fTotalMemoryUsed, (int)computed); + int countNeeded = 0; + if (fCacheCount > fCacheCountLimit) { + countNeeded = fCacheCount - fCacheCountLimit; + // no small purges! + countNeeded = SkMax32(countNeeded, fCacheCount >> 2); } - SkASSERT(fTotalMemoryUsed == computed); -} -#endif -size_t SkGlyphCache::InternalFreeCache(SkGlyphCache_Globals* globals, - size_t bytesNeeded) { - globals->validate(); + // early exit + if (!countNeeded && !bytesNeeded) { + return 0; + } size_t bytesFreed = 0; - int count = 0; - - // don't do any "small" purges - size_t minToPurge = globals->fTotalMemoryUsed >> 2; - if (bytesNeeded < minToPurge) - bytesNeeded = minToPurge; + int countFreed = 0; - SkGlyphCache* cache = FindTail(globals->fHead); - while (cache != NULL && bytesFreed < bytesNeeded) { + // we start at the tail and proceed backwards, as the linklist is in LRU + // order, with unimportant entries at the tail. + SkGlyphCache* cache = this->internalGetTail(); + while (cache != NULL && + (bytesFreed < bytesNeeded || countFreed < countNeeded)) { SkGlyphCache* prev = cache->fPrev; bytesFreed += cache->fMemoryUsed; + countFreed += 1; - cache->detach(&globals->fHead); + this->internalDetachCache(cache); SkDELETE(cache); cache = prev; - count += 1; } - SkASSERT(bytesFreed <= globals->fTotalMemoryUsed); - globals->fTotalMemoryUsed -= bytesFreed; - globals->validate(); + this->validate(); #ifdef SPEW_PURGE_STATUS - if (count && !gSkSuppressFontCachePurgeSpew) { + if (countFreed && !gSkSuppressFontCachePurgeSpew) { SkDebugf("purging %dK from font cache [%d entries]\n", - (int)(bytesFreed >> 10), count); + (int)(bytesFreed >> 10), countFreed); } #endif return bytesFreed; } +void SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) { + SkASSERT(NULL == cache->fPrev && NULL == cache->fNext); + if (fHead) { + fHead->fPrev = cache; + cache->fNext = fHead; + } + fHead = cache; + + fCacheCount += 1; + fTotalMemoryUsed += cache->fMemoryUsed; +} + +void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) { + SkASSERT(fCacheCount > 0); + fCacheCount -= 1; + fTotalMemoryUsed -= cache->fMemoryUsed; + + if (cache->fPrev) { + cache->fPrev->fNext = cache->fNext; + } else { + fHead = cache->fNext; + } + if (cache->fNext) { + cache->fNext->fPrev = cache->fPrev; + } + cache->fPrev = cache->fNext = NULL; +} + /////////////////////////////////////////////////////////////////////////////// #ifdef SK_DEBUG + void SkGlyphCache::validate() const { #ifdef SK_DEBUG_GLYPH_CACHE int count = fGlyphArray.count(); @@ -694,6 +656,22 @@ void SkGlyphCache::validate() const { } #endif } + +void SkGlyphCache_Globals::validate() const { + size_t computedBytes = 0; + int computedCount = 0; + + const SkGlyphCache* head = fHead; + while (head != NULL) { + computedBytes += head->fMemoryUsed; + computedCount += 1; + head = head->fNext; + } + + SkASSERT(fTotalMemoryUsed == computedBytes); + SkASSERT(fCacheCount == computedCount); +} + #endif /////////////////////////////////////////////////////////////////////////////// @@ -702,15 +680,27 @@ void SkGlyphCache::validate() const { #include "SkTypefaceCache.h" size_t SkGraphics::GetFontCacheLimit() { - return getSharedGlobals().getFontCacheLimit(); + return getSharedGlobals().getCacheSizeLimit(); } size_t SkGraphics::SetFontCacheLimit(size_t bytes) { - return getSharedGlobals().setFontCacheLimit(bytes); + return getSharedGlobals().setCacheSizeLimit(bytes); } size_t SkGraphics::GetFontCacheUsed() { - return getSharedGlobals().fTotalMemoryUsed; + return getSharedGlobals().getTotalMemoryUsed(); +} + +int SkGraphics::GetFontCacheCountLimit() { + return getSharedGlobals().getCacheCountLimit(); +} + +int SkGraphics::SetFontCacheCountLimit(int count) { + return getSharedGlobals().setCacheCountLimit(count); +} + +int SkGraphics::GetFontCacheCountUsed() { + return getSharedGlobals().getCacheCountUsed(); } void SkGraphics::PurgeFontCache() { @@ -720,13 +710,13 @@ void SkGraphics::PurgeFontCache() { size_t SkGraphics::GetTLSFontCacheLimit() { const SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS(); - return tls ? tls->getFontCacheLimit() : 0; + return tls ? tls->getCacheSizeLimit() : 0; } void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { if (0 == bytes) { SkGlyphCache_Globals::DeleteTLS(); } else { - SkGlyphCache_Globals::GetTLS().setFontCacheLimit(bytes); + SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes); } } |