Alter resource cache and GrContext to (optionally) never reuse a scratch texture
authorrobertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 19 Jul 2013 16:51:46 +0000 (16:51 +0000)
committerrobertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 19 Jul 2013 16:51:46 +0000 (16:51 +0000)
https://codereview.chromium.org/19482004/

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

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

index 72cb2b3..64dbadf 100644 (file)
@@ -115,7 +115,6 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
     fDrawState = SkNEW(GrDrawState);
     fGpu->setDrawState(fDrawState);
 
-
     fTextureCache = SkNEW_ARGS(GrResourceCache,
                                (MAX_TEXTURE_CACHE_COUNT,
                                 MAX_TEXTURE_CACHE_BYTES));
@@ -399,11 +398,38 @@ GrTexture* GrContext::createTexture(const GrTextureParams* params,
     return texture;
 }
 
+static GrTexture* create_scratch_texture(GrGpu* gpu, 
+                                         GrResourceCache* textureCache, 
+                                         const GrTextureDesc& desc) {
+    GrTexture* texture = gpu->createTexture(desc, NULL, 0);
+    if (NULL != texture) {
+        GrResourceKey key = GrTexture::ComputeScratchKey(texture->desc());
+        // Adding a resource could put us overbudget. Try to free up the
+        // necessary space before adding it.
+        textureCache->purgeAsNeeded(1, texture->sizeInBytes());
+        // Make the resource exclusive so future 'find' calls don't return it
+        textureCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag);
+    }
+    return texture;
+}
+
 GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) {
-    GrTextureDesc desc = inDesc;
 
-    GrAssert((desc.fFlags & kRenderTarget_GrTextureFlagBit) ||
-             !(desc.fFlags & kNoStencil_GrTextureFlagBit));
+    GrAssert((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
+             !(inDesc.fFlags & kNoStencil_GrTextureFlagBit));
+
+    // Renderable A8 targets are not universally supported (e.g., not on ANGLE)
+    GrAssert(this->isConfigRenderable(kAlpha_8_GrPixelConfig) ||
+             !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
+             (inDesc.fConfig != kAlpha_8_GrPixelConfig));
+
+    if (!fGpu->caps()->reuseScratchTextures()) {
+        // If we're never recycling scratch textures we can
+        // always make them the right size
+        return create_scratch_texture(fGpu, fTextureCache, inDesc);
+    }
+
+    GrTextureDesc desc = inDesc;
 
     if (kApprox_ScratchTexMatch == match) {
         // bin by pow2 with a reasonable min
@@ -412,11 +438,6 @@ GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, Scra
         desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
     }
 
-    // Renderable A8 targets are not universally supported (e.g., not on ANGLE)
-    GrAssert(this->isConfigRenderable(kAlpha_8_GrPixelConfig) ||
-             !(desc.fFlags & kRenderTarget_GrTextureFlagBit) ||
-             (desc.fConfig != kAlpha_8_GrPixelConfig));
-
     GrResource* resource = NULL;
     int origWidth = desc.fWidth;
     int origHeight = desc.fHeight;
@@ -449,16 +470,7 @@ GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, Scra
         desc.fFlags = inDesc.fFlags;
         desc.fWidth = origWidth;
         desc.fHeight = origHeight;
-        GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
-        if (NULL != texture) {
-            GrResourceKey key = GrTexture::ComputeScratchKey(texture->desc());
-            // Adding a resource could put us overbudget. Try to free up the
-            // necessary space before adding it.
-            fTextureCache->purgeAsNeeded(1, texture->sizeInBytes());
-            // Make the resource exclusive so future 'find' calls don't return it
-            fTextureCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag);
-            resource = texture;
-        }
+        resource = create_scratch_texture(fGpu, fTextureCache, desc);
     }
 
     return static_cast<GrTexture*>(resource);
@@ -482,7 +494,13 @@ void GrContext::addExistingTextureToCache(GrTexture* texture) {
     // still be in the exclusive pile
     fTextureCache->makeNonExclusive(texture->getCacheEntry());
 
-    this->purgeCache();
+    if (fGpu->caps()->reuseScratchTextures()) {
+        this->purgeCache();
+    } else {
+        // When we aren't reusing textures we know this scratch texture
+        // will never be reused and would be just wasting time in the cache
+        fTextureCache->deleteResource(texture->getCacheEntry());
+    }
 }
 
 
@@ -497,7 +515,6 @@ void GrContext::unlockScratchTexture(GrTexture* texture) {
         fTextureCache->makeNonExclusive(texture->getCacheEntry());
         this->purgeCache();
     }
-
 }
 
 void GrContext::purgeCache() {
index 00b2d51..03a4e89 100644 (file)
@@ -88,10 +88,10 @@ GrResourceCache::~GrResourceCache() {
 }
 
 void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
-    if (maxResources) {
+    if (NULL != maxResources) {
         *maxResources = fMaxCount;
     }
-    if (maxResourceBytes) {
+    if (NULL != maxResourceBytes) {
         *maxResourceBytes = fMaxBytes;
     }
 }
@@ -196,10 +196,6 @@ GrResource* GrResourceCache::find(const GrResourceKey& key, uint32_t ownershipFl
     return entry->fResource;
 }
 
-bool GrResourceCache::hasKey(const GrResourceKey& key) const {
-    return NULL != fCache.find(key);
-}
-
 void GrResourceCache::addResource(const GrResourceKey& key,
                                   GrResource* resource,
                                   uint32_t ownershipFlags) {
@@ -302,6 +298,17 @@ void GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) {
     fPurging = false;
 }
 
+void GrResourceCache::deleteResource(GrResourceEntry* entry) {
+    GrAssert(1 == entry->fResource->getRefCnt());
+
+    // remove from our cache
+    fCache.remove(entry->key(), entry);
+
+    // remove from our llist
+    this->internalDetach(entry);
+    delete entry;
+}
+
 void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) {
     SkASSERT(fPurging);
 
@@ -333,13 +340,7 @@ void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) {
             GrResourceEntry* prev = iter.prev();
             if (1 == entry->fResource->getRefCnt()) {
                 changed = true;
-
-                // remove from our cache
-                fCache.remove(entry->key(), entry);
-
-                // remove from our llist
-                this->internalDetach(entry);
-                delete entry;
+                this->deleteResource(entry);
             }
             entry = prev;
         }
index b27219e..679780a 100644 (file)
@@ -222,7 +222,7 @@ public:
      *  @param maxResource If non-null, returns maximum number of resources
      *                     that can be held in the cache.
      *  @param maxBytes    If non-null, returns maximum number of bytes of
-     *                         gpu memory that can be held in the cache.
+     *                     gpu memory that can be held in the cache.
      */
     void getLimits(int* maxResources, size_t* maxBytes) const;
 
@@ -235,7 +235,7 @@ public:
      *  @param maxBytes     The maximum number of bytes of resource memory that
      *                      can be held in the cache.
      */
-    void setLimits(int maxResource, size_t maxResourceBytes);
+    void setLimits(int maxResources, size_t maxResourceBytes);
 
     /**
      *  The callback function used by the cache when it is still over budget
@@ -248,8 +248,8 @@ public:
     /**
      *  Set the callback the cache should use when it is still over budget
      *  after a purge. The 'data' provided here will be passed back to the
-     *  callback. The cache will attempt to purge any resources newly freed
-     *  by the callback.
+     *  callback. Note that the cache will attempt to purge any resources newly 
+     *  freed by the callback.
      */
     void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
         fOverbudgetCB = overbudgetCB;
@@ -301,7 +301,7 @@ public:
      * Determines if the cache contains an entry matching a key. If a matching
      * entry exists but was detached then it will not be found.
      */
-    bool hasKey(const GrResourceKey& key) const;
+    bool hasKey(const GrResourceKey& key) const { return NULL != fCache.find(key); }
 
     /**
      * Hide 'entry' so that future searches will not find it. Such
@@ -318,6 +318,11 @@ public:
     void makeNonExclusive(GrResourceEntry* entry);
 
     /**
+     * Remove a resource from the cache and delete it!
+     */
+    void deleteResource(GrResourceEntry* entry);
+
+    /**
      * Removes every resource in the cache that isn't locked.
      */
     void purgeAllUnlocked();
@@ -325,7 +330,9 @@ public:
     /**
      * Allow cache to purge unused resources to obey resource limitations
      * Note: this entry point will be hidden (again) once totally ref-driven
-     * cache maintenance is implemented
+     * cache maintenance is implemented. Note that the overbudget callback
+     * will be called if the initial purge doesn't get the cache under
+     * its budget.
      *
      * extraCount and extraBytes are added to the current resource allocation
      * to make sure enough room is available for future additions (e.g,
@@ -358,29 +365,29 @@ private:
 
     // We're an internal doubly linked list
     typedef SkTInternalLList<GrResourceEntry> EntryList;
-    EntryList    fList;
+    EntryList      fList;
 
 #if GR_DEBUG
     // These objects cannot be returned by a search
-    EntryList    fExclusiveList;
+    EntryList      fExclusiveList;
 #endif
 
     // our budget, used in purgeAsNeeded()
-    int fMaxCount;
-    size_t fMaxBytes;
+    int            fMaxCount;
+    size_t         fMaxBytes;
 
     // our current stats, related to our budget
 #if GR_CACHE_STATS
-    int fHighWaterEntryCount;
-    size_t fHighWaterEntryBytes;
-    int fHighWaterClientDetachedCount;
-    size_t fHighWaterClientDetachedBytes;
+    int            fHighWaterEntryCount;
+    size_t         fHighWaterEntryBytes;
+    int            fHighWaterClientDetachedCount;
+    size_t         fHighWaterClientDetachedBytes;
 #endif
 
-    int fEntryCount;
-    size_t fEntryBytes;
-    int fClientDetachedCount;
-    size_t fClientDetachedBytes;
+    int            fEntryCount;
+    size_t         fEntryBytes;
+    int            fClientDetachedCount;
+    size_t         fClientDetachedBytes;
 
     // prevents recursive purging
     bool           fPurging;
index d7b9992..ec5b821 100644 (file)
@@ -289,7 +289,15 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
 
     fDstReadInShaderSupport = kNone_FBFetchType != fFBFetchType;
 
+#if 0
+    // This has to be temporarily disabled. On Android it causes the texture
+    // usage to become front loaded and the OS kills the process. It can
+    // be re-enabled once the more dynamic (ref-driven) cache clearing
+    // system is in place.
     fReuseScratchTextures = kARM_GrGLVendor != ctxInfo.vendor();
+#else
+    fReuseScratchTextures = true;
+#endif
 
     // Enable supported shader-related caps
     if (kDesktop_GrGLBinding == binding) {