diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index fd1f2a11e6..e68bbb13f4 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -482,11 +482,7 @@ void GrRenderTargetContext::drawGlyphRunList(const GrClip* clip, } const SkMatrix& drawMatrix(viewMatrix.localToDevice()); - if (blob != nullptr && blob->canReuse(blobPaint, blurRec, drawMatrix, drawOrigin)) { - // Reusing the blob. Move it to the front of LRU cache. - textBlobCache->makeMRU(blob.get()); - } else { - // Build or Rebuild the GrTextBlob + if (blob == nullptr || !blob->canReuse(blobPaint, blurRec, drawMatrix, drawOrigin)) { if (blob != nullptr) { // We have to remake the blob because changes may invalidate our masks. // TODO we could probably get away with reuse most of the time if the pointer is unique, diff --git a/src/gpu/text/GrTextBlobCache.cpp b/src/gpu/text/GrTextBlobCache.cpp index 988ef81c7c..a7647be0cc 100644 --- a/src/gpu/text/GrTextBlobCache.cpp +++ b/src/gpu/text/GrTextBlobCache.cpp @@ -26,20 +26,30 @@ GrTextBlobCache::makeCachedBlob(const SkGlyphRunList& glyphRunList, const GrText const SkMatrix& viewMatrix) { sk_sp cacheBlob(GrTextBlob::Make(glyphRunList, viewMatrix)); cacheBlob->setupKey(key, blurRec, glyphRunList.paint()); - SkAutoMutexExclusive lock{fMutex}; + SkAutoSpinlock lock{fSpinLock}; this->internalAdd(cacheBlob); glyphRunList.temporaryShuntBlobNotifyAddedToCache(fMessageBusID); return cacheBlob; } -sk_sp GrTextBlobCache::find(const GrTextBlob::Key& key) const { - SkAutoMutexExclusive lock{fMutex}; - const auto* idEntry = fBlobIDCache.find(key.fUniqueID); - return idEntry ? idEntry->find(key) : nullptr; +sk_sp GrTextBlobCache::find(const GrTextBlob::Key& key) { + SkAutoSpinlock lock{fSpinLock}; + const BlobIDCacheEntry* idEntry = fBlobIDCache.find(key.fUniqueID); + if (idEntry == nullptr) { + return nullptr; + } + + sk_sp blob = idEntry->find(key); + GrTextBlob* blobPtr = blob.get(); + if (blobPtr != nullptr && blobPtr != fBlobList.head()) { + fBlobList.remove(blobPtr); + fBlobList.addToHead(blobPtr); + } + return blob; } void GrTextBlobCache::remove(GrTextBlob* blob) { - SkAutoMutexExclusive lock{fMutex}; + SkAutoSpinlock lock{fSpinLock}; this->internalRemove(blob); } @@ -56,18 +66,8 @@ void GrTextBlobCache::internalRemove(GrTextBlob* blob) { } } -void GrTextBlobCache::makeMRU(GrTextBlob* blob) { - SkAutoMutexExclusive lock{fMutex}; - if (fBlobList.head() == blob) { - return; - } - - fBlobList.remove(blob); - fBlobList.addToHead(blob); -} - void GrTextBlobCache::freeAll() { - SkAutoMutexExclusive lock{fMutex}; + SkAutoSpinlock lock{fSpinLock}; fBlobIDCache.reset(); fBlobList.reset(); fCurrentSize = 0; @@ -79,7 +79,7 @@ void GrTextBlobCache::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) { } void GrTextBlobCache::purgeStaleBlobs() { - SkAutoMutexExclusive lock{fMutex}; + SkAutoSpinlock lock{fSpinLock}; this->internalPurgeStaleBlobs(); } @@ -106,12 +106,12 @@ void GrTextBlobCache::internalPurgeStaleBlobs() { } size_t GrTextBlobCache::usedBytes() const { - SkAutoMutexExclusive lock{fMutex}; + SkAutoSpinlock lock{fSpinLock}; return fCurrentSize; } bool GrTextBlobCache::isOverBudget() const { - SkAutoMutexExclusive lock{fMutex}; + SkAutoSpinlock lock{fSpinLock}; return fCurrentSize > fSizeBudget; } diff --git a/src/gpu/text/GrTextBlobCache.h b/src/gpu/text/GrTextBlobCache.h index 3b2588696d..1e6dd9e02b 100644 --- a/src/gpu/text/GrTextBlobCache.h +++ b/src/gpu/text/GrTextBlobCache.h @@ -25,15 +25,13 @@ public: sk_sp makeCachedBlob(const SkGlyphRunList& glyphRunList, const GrTextBlob::Key& key, const SkMaskFilterBase::BlurRec& blurRec, - const SkMatrix& viewMatrix) SK_EXCLUDES(fMutex); + const SkMatrix& viewMatrix) SK_EXCLUDES(fSpinLock); - sk_sp find(const GrTextBlob::Key& key) const SK_EXCLUDES(fMutex); + sk_sp find(const GrTextBlob::Key& key) SK_EXCLUDES(fSpinLock); - void remove(GrTextBlob* blob) SK_EXCLUDES(fMutex); + void remove(GrTextBlob* blob) SK_EXCLUDES(fSpinLock); - void makeMRU(GrTextBlob* blob) SK_EXCLUDES(fMutex); - - void freeAll() SK_EXCLUDES(fMutex); + void freeAll() SK_EXCLUDES(fSpinLock); struct PurgeBlobMessage { PurgeBlobMessage(uint32_t blobID, uint32_t contextUniqueID) @@ -45,11 +43,11 @@ public: static void PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID); - void purgeStaleBlobs() SK_EXCLUDES(fMutex); + void purgeStaleBlobs() SK_EXCLUDES(fSpinLock); - size_t usedBytes() const SK_EXCLUDES(fMutex); + size_t usedBytes() const SK_EXCLUDES(fSpinLock); - bool isOverBudget() const SK_EXCLUDES(fMutex); + bool isOverBudget() const SK_EXCLUDES(fSpinLock); private: friend class GrTextBlobTestingPeer; @@ -75,24 +73,24 @@ private: SkSTArray<1, sk_sp> fBlobs; }; - void internalPurgeStaleBlobs() SK_REQUIRES(fMutex); + void internalPurgeStaleBlobs() SK_REQUIRES(fSpinLock); - void internalAdd(sk_sp blob) SK_REQUIRES(fMutex); - void internalRemove(GrTextBlob* blob) SK_REQUIRES(fMutex); + void internalAdd(sk_sp blob) SK_REQUIRES(fSpinLock); + void internalRemove(GrTextBlob* blob) SK_REQUIRES(fSpinLock); - void internalCheckPurge(GrTextBlob* blob = nullptr) SK_REQUIRES(fMutex); + void internalCheckPurge(GrTextBlob* blob = nullptr) SK_REQUIRES(fSpinLock); static const int kDefaultBudget = 1 << 22; - mutable SkMutex fMutex; - TextBlobList fBlobList SK_GUARDED_BY(fMutex); - SkTHashMap fBlobIDCache SK_GUARDED_BY(fMutex); - size_t fSizeBudget SK_GUARDED_BY(fMutex); - size_t fCurrentSize SK_GUARDED_BY(fMutex) {0}; + mutable SkSpinlock fSpinLock; + TextBlobList fBlobList SK_GUARDED_BY(fSpinLock); + SkTHashMap fBlobIDCache SK_GUARDED_BY(fSpinLock); + size_t fSizeBudget SK_GUARDED_BY(fSpinLock); + size_t fCurrentSize SK_GUARDED_BY(fSpinLock) {0}; // In practice 'messageBusID' is always the unique ID of the owning GrContext const uint32_t fMessageBusID; - SkMessageBus::Inbox fPurgeBlobInbox SK_GUARDED_BY(fMutex); + SkMessageBus::Inbox fPurgeBlobInbox SK_GUARDED_BY(fSpinLock); }; #endif diff --git a/tests/TextBlobCacheTest.cpp b/tests/TextBlobCacheTest.cpp index 83d3928ba5..c02a9d188d 100644 --- a/tests/TextBlobCacheTest.cpp +++ b/tests/TextBlobCacheTest.cpp @@ -55,7 +55,7 @@ static void setup_always_evict_atlas(GrDirectContext* dContext) { class GrTextBlobTestingPeer { public: static void SetBudget(GrTextBlobCache* cache, size_t budget) { - SkAutoMutexExclusive lock{cache->fMutex}; + SkAutoSpinlock lock{cache->fSpinLock}; cache->fSizeBudget = budget; cache->internalCheckPurge(); }