Ganesh resource cache changes
authorrobertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 31 Oct 2012 12:25:21 +0000 (12:25 +0000)
committerrobertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 31 Oct 2012 12:25:21 +0000 (12:25 +0000)
https://codereview.appspot.com/6784051/

git-svn-id: http://skia.googlecode.com/svn/trunk@6211 2bbb7eff-a529-9590-31e7-b0007b416f81

src/gpu/GrContext.cpp
src/gpu/GrResourceCache.cpp
src/gpu/GrResourceCache.h

index 900af8acbd78820d16b1a6a77ab742dde4d837a4..f7f6b0c0b7b131018558d88503c8e2b4b3e67742 100644 (file)
@@ -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<GrTexture*>(resource);
 }
 
index 89fce55f700209aacb93e32799bb74a49710e090..825b122bfaff145c3997a3da6aa0c689a8300311 100644 (file)
@@ -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<GrTFindUnreffedFunctor>(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",
index 7897b7ae47af4d948c1cbc0644500042d66b0541..4ee7015d11930262144a1ad1779114030296df8a 100644 (file)
@@ -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);