From 209a1143a1a26935578d45c7f86dc6f9aa2eb1a6 Mon Sep 17 00:00:00 2001 From: "robertphillips@google.com" Date: Wed, 31 Oct 2012 12:25:21 +0000 Subject: [PATCH] Ganesh resource cache changes https://codereview.appspot.com/6784051/ git-svn-id: http://skia.googlecode.com/svn/trunk@6211 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/gpu/GrContext.cpp | 17 ++++------ src/gpu/GrResourceCache.cpp | 68 +++++++++++++++++++++++++++++-------- src/gpu/GrResourceCache.h | 38 +++++++++++++++++---- 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 900af8acbd..f7f6b0c0b7 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -236,7 +236,7 @@ void GrContext::addStencilBuffer(GrStencilBuffer* sb) { GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(), sb->height(), sb->numSamples()); - fTextureCache->create(resourceKey, sb); + fTextureCache->addResource(resourceKey, sb); } GrStencilBuffer* GrContext::findStencilBuffer(int width, int height, @@ -378,7 +378,7 @@ GrTexture* GrContext::createTexture( } if (NULL != texture) { - fTextureCache->create(resourceKey, texture); + fTextureCache->addResource(resourceKey, texture); } return texture; @@ -407,7 +407,8 @@ GrTexture* GrContext::lockScratchTexture(const GrTextureDesc& inDesc, do { GrResourceKey key = GrTexture::ComputeKey(fGpu, NULL, desc, cacheData, true); - resource = fTextureCache->find(key); + // Ensure we have exclusive access to the texture so future 'find' calls don't return it + resource = fTextureCache->find(key, GrResourceCache::kHide_OwnershipFlag); // if we miss, relax the fit of the flags... // then try doubling width... then height. if (NULL != resource || kExact_ScratchTexMatch == match) { @@ -443,18 +444,12 @@ GrTexture* GrContext::lockScratchTexture(const GrTextureDesc& inDesc, texture->desc(), cacheData, true); - fTextureCache->create(key, texture); + // Make the resource exclusive so future 'find' calls don't return it + fTextureCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag); resource = texture; } } - // If the caller gives us the same desc twice we don't want to return the - // same texture the second time (unless it was previously released). So - // make it exclusive to hide it from future searches. - if (NULL != resource) { - fTextureCache->makeExclusive(resource->getCacheEntry()); - } - return static_cast(resource); } diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp index 89fce55f70..825b122bfa 100644 --- a/src/gpu/GrResourceCache.cpp +++ b/src/gpu/GrResourceCache.cpp @@ -94,7 +94,7 @@ GrResourceCache::~GrResourceCache() { fCache.remove(entry->fKey, entry); // remove from our llist - this->internalDetach(entry, false); + this->internalDetach(entry); delete entry; } @@ -121,11 +121,11 @@ void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) { } void GrResourceCache::internalDetach(GrResourceEntry* entry, - bool clientDetach) { + BudgetBehaviors behavior) { fList.remove(entry); // update our stats - if (clientDetach) { + if (kIgnore_BudgetBehavior == behavior) { fClientDetachedCount += 1; fClientDetachedBytes += entry->resource()->sizeInBytes(); @@ -139,20 +139,24 @@ void GrResourceCache::internalDetach(GrResourceEntry* entry, #endif } else { + GrAssert(kAccountFor_BudgetBehavior == behavior); + fEntryCount -= 1; fEntryBytes -= entry->resource()->sizeInBytes(); } } void GrResourceCache::attachToHead(GrResourceEntry* entry, - bool clientReattach) { + BudgetBehaviors behavior) { fList.addToHead(entry); // update our stats - if (clientReattach) { + if (kIgnore_BudgetBehavior == behavior) { fClientDetachedCount -= 1; fClientDetachedBytes -= entry->resource()->sizeInBytes(); } else { + GrAssert(kAccountFor_BudgetBehavior == behavior); + fEntryCount += 1; fEntryBytes += entry->resource()->sizeInBytes(); @@ -167,16 +171,40 @@ void GrResourceCache::attachToHead(GrResourceEntry* entry, } } -GrResource* GrResourceCache::find(const GrResourceKey& key) { +// This functor just searches for an entry with only a single ref (from +// the texture cache itself). Presumably in this situation no one else +// is relying on the texture. +class GrTFindUnreffedFunctor { +public: + bool operator()(const GrResourceEntry* entry) const { + return 1 == entry->resource()->getRefCnt(); + } +}; + +GrResource* GrResourceCache::find(const GrResourceKey& key, uint32_t ownershipFlags) { GrAutoResourceCacheValidate atcv(this); - GrResourceEntry* entry = fCache.find(key); + GrResourceEntry* entry = NULL; + + if (ownershipFlags & kNoOtherOwners_OwnershipFlag) { + GrTFindUnreffedFunctor functor; + + entry = fCache.find(key, functor); + } else { + entry = fCache.find(key); + } + if (NULL == entry) { return NULL; } - this->internalDetach(entry, false); - this->attachToHead(entry, false); + if (ownershipFlags & kHide_OwnershipFlag) { + this->makeExclusive(entry); + } else { + // Make this resource MRU + this->internalDetach(entry); + this->attachToHead(entry); + } return entry->fResource; } @@ -185,7 +213,9 @@ bool GrResourceCache::hasKey(const GrResourceKey& key) const { return NULL != fCache.find(key); } -void GrResourceCache::create(const GrResourceKey& key, GrResource* resource) { +void GrResourceCache::addResource(const GrResourceKey& key, + GrResource* resource, + uint32_t ownershipFlags) { GrAssert(NULL == resource->getCacheEntry()); // we don't expect to create new resources during a purge. In theory // this could cause purgeAsNeeded() into an infinite loop (e.g. @@ -197,19 +227,26 @@ void GrResourceCache::create(const GrResourceKey& key, GrResource* resource) { GrResourceEntry* entry = SkNEW_ARGS(GrResourceEntry, (key, resource)); resource->setCacheEntry(entry); - this->attachToHead(entry, false); + this->attachToHead(entry); fCache.insert(key, entry); #if GR_DUMP_TEXTURE_UPLOAD GrPrintf("--- add resource to cache %p, count=%d bytes= %d %d\n", entry, fEntryCount, resource->sizeInBytes(), fEntryBytes); #endif + + if (ownershipFlags & kHide_OwnershipFlag) { + this->makeExclusive(entry); + } + } void GrResourceCache::makeExclusive(GrResourceEntry* entry) { GrAutoResourceCacheValidate atcv(this); - this->internalDetach(entry, true); + // When scratch textures are detached (to hide them from future finds) they + // still count against the resource budget + this->internalDetach(entry, kIgnore_BudgetBehavior); fCache.remove(entry->key(), entry); #if GR_DEBUG @@ -238,7 +275,10 @@ void GrResourceCache::makeNonExclusive(GrResourceEntry* entry) { #endif if (entry->resource()->isValid()) { - attachToHead(entry, true); + // Since scratch textures still count against the cache budget even + // when they have been removed from the cache, re-adding them doesn't + // alter the budget information. + attachToHead(entry, kIgnore_BudgetBehavior); fCache.insert(entry->key(), entry); } else { this->removeInvalidResource(entry); @@ -290,7 +330,7 @@ void GrResourceCache::purgeAsNeeded() { fCache.remove(entry->key(), entry); // remove from our llist - this->internalDetach(entry, false); + this->internalDetach(entry); #if GR_DUMP_TEXTURE_UPLOAD GrPrintf("--- ~resource from cache %p [%d %d]\n", diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h index 7897b7ae47..4ee7015d11 100644 --- a/src/gpu/GrResourceCache.h +++ b/src/gpu/GrResourceCache.h @@ -220,20 +220,41 @@ public: */ size_t getCachedResourceBytes() const { return fEntryBytes; } + // For a found or added resource to be completely exclusive to the caller + // both the kNoOtherOwners and kHide flags need to be specified + enum OwnershipFlags { + kNoOtherOwners_OwnershipFlag = 0x1, // found/added resource has no other owners + kHide_OwnershipFlag = 0x2 // found/added resource is hidden from future 'find's + }; + /** * Search for an entry with the same Key. If found, return it. * If not found, return null. + * If ownershipFlags includes kNoOtherOwners and a resource is returned + * then that resource has no other refs to it. + * If ownershipFlags includes kHide and a resource is returned then that + * resource will not be returned from future 'find' calls until it is + * 'freed' (and recycled) or makeNonExclusive is called. + * For a resource to be completely exclusive to a caller both kNoOtherOwners + * and kHide must be specified. */ - GrResource* find(const GrResourceKey& key); + GrResource* find(const GrResourceKey& key, + uint32_t ownershipFlags = 0); /** - * Create a new cache entry, based on the provided key and resource, and - * return it. + * Add the new resource to the cache (by creating a new cache entry based + * on the provided key and resource). * * Ownership of the resource is transferred to the resource cache, * which will unref() it when it is purged or deleted. + * + * If ownershipFlags includes kHide, subsequent calls to 'find' will not + * return 'resource' until it is 'freed' (and recycled) or makeNonExclusive + * is called. */ - void create(const GrResourceKey&, GrResource*); + void addResource(const GrResourceKey& key, + GrResource* resource, + uint32_t ownershipFlags = 0); /** * Determines if the cache contains an entry matching a key. If a matching @@ -278,8 +299,13 @@ public: #endif private: - void internalDetach(GrResourceEntry*, bool); - void attachToHead(GrResourceEntry*, bool); + enum BudgetBehaviors { + kAccountFor_BudgetBehavior, + kIgnore_BudgetBehavior + }; + + void internalDetach(GrResourceEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior); + void attachToHead(GrResourceEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior); void removeInvalidResource(GrResourceEntry* entry); -- 2.34.1