Revert of Replace GrResourceCache with GrResourceCache2. (patchset #7 id:120001 of...
authorbsalomon <bsalomon@google.com>
Fri, 14 Nov 2014 14:47:39 +0000 (06:47 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 14 Nov 2014 14:47:39 +0000 (06:47 -0800)
Reason for revert:
broken again

Original issue's description:
> Replace GrResourceCache with GrResourceCache2.
>
> BUG=skia:2889
>
> Committed: https://skia.googlesource.com/skia/+/66a450f21a3da174b7eed89a1d5fc8591e8b6ee6
>
> Committed: https://skia.googlesource.com/skia/+/407aa584d183c1bf314f5defd1cf0202e8a96c89

TBR=robertphillips@google.com
NOTREECHECKS=true
NOTRY=true
BUG=skia:2889

Review URL: https://codereview.chromium.org/726913002

24 files changed:
bench/GrResourceCacheBench.cpp
gyp/gpu.gyp
gyp/gpu.gypi
include/gpu/GrConfig.h
include/gpu/GrContext.h
include/gpu/GrGpuResource.h
include/gpu/GrUserConfig.h
include/gpu/SkGr.h
src/gpu/GrAADistanceFieldPathRenderer.h
src/gpu/GrContext.cpp
src/gpu/GrGpuResource.cpp
src/gpu/GrGpuResourceCacheAccess.h
src/gpu/GrPath.h
src/gpu/GrPathRange.h
src/gpu/GrResourceCache.cpp [new file with mode: 0644]
src/gpu/GrResourceCache.h [new file with mode: 0644]
src/gpu/GrResourceCache2.cpp
src/gpu/GrResourceCache2.h
src/gpu/GrStencilBuffer.cpp
src/gpu/GrTest.cpp
src/gpu/GrTexture.cpp
src/gpu/SkGr.cpp
tests/ResourceCacheTest.cpp
tests/SurfaceTest.cpp

index ef97ed89711c9472c2c06b9cec5dfb4f47ad8224..6d631ddb2c4b62f74420a8c32f5c9816f7012403 100644 (file)
@@ -13,6 +13,7 @@
 #include "GrGpuResource.h"
 #include "GrContext.h"
 #include "GrGpu.h"
+#include "GrResourceCache.h"
 #include "GrResourceCache2.h"
 #include "GrStencilBuffer.h"
 #include "GrTexture.h"
@@ -88,20 +89,22 @@ static void get_stencil(int i, int* w, int* h, int* s) {
 }
 
 static void get_texture_desc(int i, GrSurfaceDesc* desc) {
-    desc->fFlags = kRenderTarget_GrSurfaceFlag | kNoStencil_GrSurfaceFlag;
+    desc->fFlags = kRenderTarget_GrSurfaceFlag |
+        kNoStencil_GrSurfaceFlag;
     desc->fWidth  = i % 1024;
     desc->fHeight = i * 2 % 1024;
     desc->fConfig = static_cast<GrPixelConfig>(i % (kLast_GrPixelConfig + 1));
-    desc->fSampleCnt = ((i % 2) == 0) ? 0 : 4;
+    desc->fSampleCnt = i % 1 == 0 ? 0 : 4;
 }
 
-static void populate_cache(GrGpu* gpu, int resourceCount) {
+static void populate_cache(GrResourceCache* cache, GrGpu* gpu, int resourceCount) {
     for (int i = 0; i < resourceCount; ++i) {
         int w, h, s;
         get_stencil(i, &w, &h, &s);
         GrResourceKey key = GrStencilBuffer::ComputeKey(w, h, s);
         GrGpuResource* resource = SkNEW_ARGS(StencilResource, (gpu, i));
-        resource->cacheAccess().setContentKey(key);
+        cache->purgeAsNeeded(1, resource->gpuMemorySize());
+        cache->addResource(key, resource);
         resource->unref();
     }
 
@@ -110,7 +113,8 @@ static void populate_cache(GrGpu* gpu, int resourceCount) {
         get_texture_desc(i, &desc);
         GrResourceKey key =  TextureResource::ComputeKey(desc);
         GrGpuResource* resource = SkNEW_ARGS(TextureResource, (gpu, i));
-        resource->cacheAccess().setContentKey(key);
+        cache->purgeAsNeeded(1, resource->gpuMemorySize());
+        cache->addResource(key, resource);
         resource->unref();
     }
 }
@@ -194,24 +198,25 @@ protected:
         // Set the cache budget to be very large so no purging occurs.
         context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30);
 
+        GrResourceCache* cache = context->getResourceCache();
         GrResourceCache2* cache2 = context->getResourceCache2();
 
         // Make sure the cache is empty.
-        cache2->purgeAllUnlocked();
-        SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+        cache->purgeAllUnlocked();
+        SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
         GrGpu* gpu = context->getGpu();
 
         for (int i = 0; i < loops; ++i) {
-            SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+            SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
-            populate_cache(gpu, RESOURCE_COUNT);
+            populate_cache(cache, gpu, RESOURCE_COUNT);
 
             // Check that cache works.
             for (int k = 0; k < RESOURCE_COUNT; k += 33) {
                 check_cache_contents_or_die(cache2, k);
             }
-            cache2->purgeAllUnlocked();
+            cache->purgeAllUnlocked();
         }
     }
 
@@ -242,15 +247,16 @@ protected:
         // Set the cache budget to be very large so no purging occurs.
         context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30);
 
+        GrResourceCache* cache = context->getResourceCache();
         GrResourceCache2* cache2 = context->getResourceCache2();
 
         // Make sure the cache is empty.
-        cache2->purgeAllUnlocked();
-        SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+        cache->purgeAllUnlocked();
+        SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
         GrGpu* gpu = context->getGpu();
 
-        populate_cache(gpu, RESOURCE_COUNT);
+        populate_cache(cache, gpu, RESOURCE_COUNT);
 
         for (int i = 0; i < loops; ++i) {
             for (int k = 0; k < RESOURCE_COUNT; ++k) {
index 631945607dbd3b105b803ebff9a2e6df1203b93c..d40afe1a95affbed031beb554db41ed23b827d70 100644 (file)
           ],
         },
       }],
+      [ 'skia_resource_cache_mb_limit != 0', {
+        'defines': [
+          'GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT=<(skia_resource_cache_mb_limit)',
+        ],
+      }],
+      [ 'skia_resource_cache_count_limit != 0', {
+        'defines': [
+          'GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT=<(skia_resource_cache_count_limit)',
+        ],
+      }],
     ],
     'direct_dependent_settings': {
       'conditions': [
index 5095c44c5c101feeadc5ef4911902f8c110452f1..8eca40c3d31c4e6c4ed7a1731b84ce8983dba355 100644 (file)
       '<(skia_src_path)/gpu/GrRenderTarget.cpp',
       '<(skia_src_path)/gpu/GrReducedClip.cpp',
       '<(skia_src_path)/gpu/GrReducedClip.h',
+      '<(skia_src_path)/gpu/GrResourceCache.cpp',
+      '<(skia_src_path)/gpu/GrResourceCache.h',
       '<(skia_src_path)/gpu/GrResourceCache2.cpp',
       '<(skia_src_path)/gpu/GrResourceCache2.h',
       '<(skia_src_path)/gpu/GrStencil.cpp',
index d48ccd5dc6ff5de1d0a8d05d30c7a35c009afe80..e70c978fc000d8ffdb1d45fa2890c57380bf4180 100644 (file)
@@ -212,6 +212,24 @@ typedef unsigned __int64 uint64_t;
     #define GR_GEOM_BUFFER_MAP_THRESHOLD (1 << 15)
 #endif
 
+/**
+ * GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT gives a threshold (in megabytes) for the
+ * maximum size of the texture cache in vram. The value is only a default and
+ * can be overridden at runtime.
+ */
+#if !defined(GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT)
+    #define GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT 96
+#endif
+
+/**
+ * GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT specifies the maximum number of
+ * textures the texture cache can hold in vram. The value is only a default and
+ * can be overridden at runtime.
+ */
+#if !defined(GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT)
+    #define GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT 2048
+#endif
+
 /**
  * GR_STROKE_PATH_RENDERING controls whether or not the GrStrokePathRenderer can be selected
  * as a path renderer. GrStrokePathRenderer is currently an experimental path renderer.
index 3dbf7b3ea88d7080d5f96aef7dbce01f768a9e31..97acda1e795a4cc540525d65c805b5d3fd18c3c3 100644 (file)
@@ -33,6 +33,7 @@ class GrOvalRenderer;
 class GrPath;
 class GrPathRenderer;
 class GrResourceEntry;
+class GrResourceCache;
 class GrResourceCache2;
 class GrStencilBuffer;
 class GrTestTarget;
@@ -882,6 +883,7 @@ public:
     GrDrawTarget* getTextTarget();
     const GrIndexBuffer* getQuadIndexBuffer() const;
     GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; }
+    GrResourceCache* getResourceCache() { return fResourceCache; }
     GrResourceCache2* getResourceCache2() { return fResourceCache2; }
 
     // Called by tests that draw directly to the context via GrDrawTarget
@@ -946,6 +948,7 @@ private:
     const GrClipData*               fClip;  // TODO: make this ref counted
     GrDrawState*                    fDrawState;
 
+    GrResourceCache*                fResourceCache;
     GrResourceCache2*               fResourceCache2;
     GrFontCache*                    fFontCache;
     SkAutoTDelete<GrLayerCache>     fLayerCache;
@@ -959,6 +962,7 @@ private:
 
     // Set by OverbudgetCB() to request that GrContext flush before exiting a draw.
     bool                            fFlushToReduceCacheSize;
+
     GrAARectRenderer*               fAARectRenderer;
     GrOvalRenderer*                 fOvalRenderer;
 
@@ -999,6 +1003,8 @@ private:
                                     size_t rowBytes,
                                     bool filter);
 
+    GrTexture* createNewScratchTexture(const GrSurfaceDesc& desc);
+
     /**
      * These functions create premul <-> unpremul effects if it is possible to generate a pair
      * of effects that make a readToUPM->writeToPM->readToUPM cycle invariant. Otherwise, they
@@ -1009,9 +1015,9 @@ private:
 
     /**
      *  This callback allows the resource cache to callback into the GrContext
-     *  when the cache is still over budget after a purge.
+     *  when the cache is still overbudget after a purge.
      */
-    static void OverBudgetCB(void* data);
+    static bool OverbudgetCB(void* data);
 
     typedef SkRefCnt INHERITED;
 };
index 3c87117124d66d98178867ee6af7828d328c410f..5231b15f897cd86278443c257ee7b6ae0e90bb86 100644 (file)
@@ -16,6 +16,7 @@
 class GrContext;
 class GrGpu;
 class GrResourceCache2;
+class GrResourceCacheEntry;
 
 /**
  * Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
@@ -125,7 +126,7 @@ private:
 };
 
 /**
- * Base class for objects that can be kept in the GrResourceCache2.
+ * Base class for objects that can be kept in the GrResourceCache.
  */
 class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
 public:
@@ -256,6 +257,7 @@ private:
 
     uint32_t                fFlags;
 
+    GrResourceCacheEntry*   fCacheEntry;  // NULL if not in cache
     mutable size_t          fGpuMemorySize;
     const uint32_t          fUniqueID;
 
index 4ff95f73b5c79c156747dd77b5e0b027c0ae40aa..092ff9d8bcc480fd96b99fb6ac4f49a1698dc34b 100644 (file)
  */
 //#define GR_GEOM_BUFFER_MAP_THRESHOLD (1<<15)
 
+/**
+ * This gives a threshold in megabytes for the maximum size of the texture cache
+ * in vram. The value is only a default and can be overridden at runtime.
+ */
+//#define GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT 96
+
+/**
+ * This specifies the maximum number of textures the texture cache can hold
+ * in vram. The value is only a default and can be overridden at runtime.
+ */
+//#define GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT 2048
+
 #endif
index 8025c956efe185f6be81ffce43aa38e059c0f683..026525be5d37993cc5a8ba7e6539c96e81ceac45 100644 (file)
@@ -68,11 +68,6 @@ static inline GrColor SkColor2GrColorJustAlpha(SkColor c) {
 
 ////////////////////////////////////////////////////////////////////////////////
 
-// The cache listens for these messages to purge junk resources proactively.
-struct GrResourceInvalidatedMessage {
-    GrResourceKey key;
-};
-
 bool GrIsBitmapInCache(const GrContext*, const SkBitmap&, const GrTextureParams*);
 
 GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams*);
index c337016c0b4db13292e40a2d7398eba735892c60..10f0ebab93bb90065febf8ced2503504c94e4f64 100755 (executable)
@@ -15,7 +15,6 @@
 #include "GrRect.h"
 
 #include "SkChecksum.h"
-#include "SkTDynamicHash.h"
 
 class GrContext;
 class GrPlot;
index 80fdace9bab731f04b3756683efee8a163b90182..3a93404af17832b421c94bc3f8df1ed08cb81a73 100755 (executable)
@@ -25,6 +25,7 @@
 #include "GrOvalRenderer.h"
 #include "GrPathRenderer.h"
 #include "GrPathUtils.h"
+#include "GrResourceCache.h"
 #include "GrResourceCache2.h"
 #include "GrSoftwarePathRenderer.h"
 #include "GrStencilBuffer.h"
@@ -51,6 +52,9 @@
     #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
 #endif
 
+static const size_t MAX_RESOURCE_CACHE_COUNT = GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT;
+static const size_t MAX_RESOURCE_CACHE_BYTES = GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT * 1024 * 1024;
+
 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
 static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
 
@@ -99,6 +103,7 @@ GrContext::GrContext(const Options& opts) : fOptions(opts) {
     fClip = NULL;
     fPathRendererChain = NULL;
     fSoftwarePathRenderer = NULL;
+    fResourceCache = NULL;
     fResourceCache2 = NULL;
     fFontCache = NULL;
     fDrawBuffer = NULL;
@@ -125,8 +130,11 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
 void GrContext::initCommon() {
     fDrawState = SkNEW(GrDrawState);
 
+    fResourceCache = SkNEW_ARGS(GrResourceCache, (fGpu->caps(),
+                                                  MAX_RESOURCE_CACHE_COUNT,
+                                                  MAX_RESOURCE_CACHE_BYTES));
+    fResourceCache->setOverbudgetCallback(OverbudgetCB, this);
     fResourceCache2 = SkNEW(GrResourceCache2);
-    fResourceCache2->setOverBudgetCallback(OverBudgetCB, this);
 
     fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
 
@@ -152,6 +160,9 @@ GrContext::~GrContext() {
     }
 
     SkDELETE(fResourceCache2);
+    fResourceCache2 = NULL;
+    SkDELETE(fResourceCache);
+    fResourceCache = NULL;
     SkDELETE(fFontCache);
     SkDELETE(fDrawBuffer);
     SkDELETE(fDrawBufferVBAllocPool);
@@ -190,6 +201,8 @@ void GrContext::abandonContext() {
     fAARectRenderer->reset();
     fOvalRenderer->reset();
 
+    fResourceCache->purgeAllUnlocked();
+
     fFontCache->freeAll();
     fLayerCache->freeAll();
 }
@@ -208,6 +221,7 @@ void GrContext::freeGpuResources() {
     fAARectRenderer->reset();
     fOvalRenderer->reset();
 
+    fResourceCache->purgeAllUnlocked();
     fFontCache->freeAll();
     fLayerCache->freeAll();
     // a path renderer may be holding onto resources
@@ -216,12 +230,12 @@ void GrContext::freeGpuResources() {
 }
 
 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
-    if (resourceCount) {
-        *resourceCount = fResourceCache2->getResourceCount();
-    }
-    if (resourceBytes) {
-        *resourceBytes = fResourceCache2->getResourceBytes();
-    }
+  if (resourceCount) {
+    *resourceCount = fResourceCache->getCachedResourceCount();
+  }
+  if (resourceBytes) {
+    *resourceBytes = fResourceCache->getCachedResourceBytes();
+  }
 }
 
 GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
@@ -259,13 +273,12 @@ bool GrContext::isTextureInCache(const GrSurfaceDesc& desc,
 }
 
 void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
-    // TODO: Make GrStencilBuffers use the scratch mechanism rather than content keys.
     ASSERT_OWNED_RESOURCE(sb);
 
     GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(),
                                                             sb->height(),
                                                             sb->numSamples());
-    SkAssertResult(sb->cacheAccess().setContentKey(resourceKey));
+    fResourceCache->addResource(resourceKey, sb);
 }
 
 GrStencilBuffer* GrContext::findAndRefStencilBuffer(int width, int height, int sampleCnt) {
@@ -407,19 +420,25 @@ GrTexture* GrContext::createTexture(const GrTextureParams* params,
     }
 
     if (texture) {
-        if (texture->cacheAccess().setContentKey(resourceKey)) {
-            if (cacheKey) {
-                *cacheKey = resourceKey;
-            }
-        } else {
-            texture->unref();
-            texture = NULL;
+        fResourceCache->addResource(resourceKey, texture);
+
+        if (cacheKey) {
+            *cacheKey = resourceKey;
         }
     }
 
     return texture;
 }
 
+GrTexture* GrContext::createNewScratchTexture(const GrSurfaceDesc& desc) {
+    GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
+    if (!texture) {
+        return NULL;
+    }
+    fResourceCache->addResource(texture->cacheAccess().getScratchKey(), texture);
+    return texture;
+}
+
 GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexMatch match,
                                         bool calledDuringFlush) {
     // kNoStencil has no meaning if kRT isn't set.
@@ -454,6 +473,7 @@ GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexM
             }
             GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key, scratchFlags);
             if (resource) {
+                fResourceCache->makeResourceMRU(resource);
                 return static_cast<GrSurface*>(resource)->asTexture();
             }
 
@@ -476,19 +496,21 @@ GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexM
         desc.writable()->fFlags = origFlags;
     }
 
-    GrTexture* texture = fGpu->createTexture(*desc, NULL, 0);
+    GrTexture* texture = this->createNewScratchTexture(*desc);
     SkASSERT(NULL == texture || 
              texture->cacheAccess().getScratchKey() == GrTexturePriv::ComputeScratchKey(*desc));
     return texture;
 }
 
-void GrContext::OverBudgetCB(void* data) {
+bool GrContext::OverbudgetCB(void* data) {
     SkASSERT(data);
 
     GrContext* context = reinterpret_cast<GrContext*>(data);
 
     // Flush the InOrderDrawBuffer to possibly free up some textures
     context->fFlushToReduceCacheSize = true;
+
+    return true;
 }
 
 
@@ -500,16 +522,11 @@ GrTexture* GrContext::createUncachedTexture(const GrSurfaceDesc& descIn,
 }
 
 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
-    if (maxTextures) {
-        *maxTextures = fResourceCache2->getMaxResourceCount();
-    }
-    if (maxTextureBytes) {
-        *maxTextureBytes = fResourceCache2->getMaxResourceBytes();
-    }
+    fResourceCache->getLimits(maxTextures, maxTextureBytes);
 }
 
 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
-    fResourceCache2->setLimits(maxTextures, maxTextureBytes);
+    fResourceCache->setLimits(maxTextures, maxTextureBytes);
 }
 
 int GrContext::getMaxTextureSize() const {
@@ -1225,6 +1242,7 @@ void GrContext::flush(int flagsBitfield) {
     } else {
         fDrawBuffer->flush();
     }
+    fResourceCache->purgeAsNeeded();
     fFlushToReduceCacheSize = false;
 }
 
@@ -1728,11 +1746,15 @@ const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
 }
 
 void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResource* resource) {
-    resource->cacheAccess().setContentKey(resourceKey);
+    fResourceCache->addResource(resourceKey, resource);
 }
 
 GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resourceKey) {
-    return fResourceCache2->findAndRefContentResource(resourceKey);
+    GrGpuResource* resource = fResourceCache2->findAndRefContentResource(resourceKey);
+    if (resource) {
+        fResourceCache->makeResourceMRU(resource);
+    }
+    return resource;
 }
 
 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
@@ -1752,7 +1774,7 @@ void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
 ///////////////////////////////////////////////////////////////////////////////
 #if GR_CACHE_STATS
 void GrContext::printCacheStats() const {
-    fResourceCache2->printStats();
+    fResourceCache->printStats();
 }
 #endif
 
index be8ea0daf07f744a921b06a2b3684be1b3c9066e..f6f7282700a3d7e231ceab522d4e11933f595723 100644 (file)
@@ -18,8 +18,16 @@ static inline GrResourceCache2* get_resource_cache2(GrGpu* gpu) {
     return gpu->getContext()->getResourceCache2();
 }
 
+static inline GrResourceCache* get_resource_cache(GrGpu* gpu) {
+    SkASSERT(gpu);
+    SkASSERT(gpu->getContext());
+    SkASSERT(gpu->getContext()->getResourceCache());
+    return gpu->getContext()->getResourceCache();
+}
+
 GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
     : fGpu(gpu)
+    , fCacheEntry(NULL)
     , fGpuMemorySize(kInvalidGpuMemorySize)
     , fUniqueID(CreateUniqueID())
     , fScratchKey(GrResourceKey::NullScratchKey())
@@ -32,7 +40,7 @@ GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
 }
 
 void GrGpuResource::registerWithCache() {
-    get_resource_cache2(fGpu)->resourceAccess().insertResource(this);
+    get_resource_cache2(fGpu)->insertResource(this);
 }
 
 GrGpuResource::~GrGpuResource() {
@@ -43,18 +51,16 @@ GrGpuResource::~GrGpuResource() {
 void GrGpuResource::release() { 
     if (fGpu) {
         this->onRelease();
-        get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
+        get_resource_cache2(fGpu)->removeResource(this);
         fGpu = NULL;
-        fGpuMemorySize = 0;
     }
 }
 
 void GrGpuResource::abandon() {
     if (fGpu) {
         this->onAbandon();
-        get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
+        get_resource_cache2(fGpu)->removeResource(this);
         fGpu = NULL;
-        fGpuMemorySize = 0;
     }
 }
 
@@ -74,17 +80,6 @@ GrContext* GrGpuResource::getContext() {
     }
 }
 
-void GrGpuResource::didChangeGpuMemorySize() const {
-    if (this->wasDestroyed()) {
-        return;
-    }
-
-    size_t oldSize = fGpuMemorySize;
-    SkASSERT(kInvalidGpuMemorySize != oldSize);
-    fGpuMemorySize = kInvalidGpuMemorySize;
-    get_resource_cache2(fGpu)->resourceAccess().didChangeGpuMemorySize(this, oldSize);
-}
-
 bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
     // Currently this can only be called once and can't be called when the resource is scratch.
     SkASSERT(!contentKey.isScratch());
@@ -97,7 +92,7 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
     fContentKey = contentKey;
     fContentKeySet = true;
 
-    if (!get_resource_cache2(fGpu)->resourceAccess().didSetContentKey(this)) {
+    if (!get_resource_cache2(fGpu)->didSetContentKey(this)) {
         fContentKeySet = false;
         return false;
     }
@@ -105,8 +100,8 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
 }
 
 void GrGpuResource::notifyIsPurgable() const {
-    if (!this->wasDestroyed()) {
-        get_resource_cache2(fGpu)->resourceAccess().notifyPurgable(this);
+    if (fCacheEntry && !this->wasDestroyed()) {
+        get_resource_cache(fGpu)->notifyPurgable(this);
     }
 }
 
index 7417a55a718bcadfefac8a6a084431ace8c9f98e..af5c05464bee057fcb0a9e234de31a9d15a3ae31 100644 (file)
@@ -28,6 +28,25 @@ public:
         return fResource->setContentKey(contentKey);
     }
 
+    /**
+     * Used by legacy cache to attach a cache entry. This is to be removed soon.
+     */
+    void setCacheEntry(GrResourceCacheEntry* cacheEntry) {
+        // GrResourceCache never changes the cacheEntry once one has been added.
+        SkASSERT(NULL == cacheEntry || NULL == fResource->fCacheEntry);
+        fResource->fCacheEntry = cacheEntry;
+    }
+
+    /**
+     * Is the resource in the legacy cache? This is to be removed soon.
+     */
+    bool isInCache() const { return SkToBool(fResource->fCacheEntry); }
+
+    /**
+     * Returns the cache entry for the legacy cache. This is to be removed soon.
+     */
+    GrResourceCacheEntry* getCacheEntry() const { return fResource->fCacheEntry; }
+
     /**
      * Is the resource currently cached as scratch? This means it has a valid scratch key and does
      * not have a content key.
index 394db6f5c2e1a7625afcf809ce09ac335a8129a1..a5719353905ec6e6837f20ed3606d65cade46d24 100644 (file)
@@ -9,6 +9,7 @@
 #define GrPath_DEFINED
 
 #include "GrGpuResource.h"
+#include "GrResourceCache.h"
 #include "SkPath.h"
 #include "SkRect.h"
 #include "SkStrokeRec.h"
index 5bfecb0a6859fc793cd5f6979cf1b119888fe895..dc8ce1d71b54980e36d700acd163ce0c2b2fae99 100644 (file)
@@ -9,6 +9,7 @@
 #define GrPathRange_DEFINED
 
 #include "GrGpuResource.h"
+#include "GrResourceCache.h"
 #include "SkRefCnt.h"
 #include "SkStrokeRec.h"
 #include "SkTArray.h"
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
new file mode 100644 (file)
index 0000000..a73d117
--- /dev/null
@@ -0,0 +1,393 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrResourceCache.h"
+#include "GrGpuResource.h"
+#include "GrGpuResourceCacheAccess.h"
+#include "GrTexturePriv.h"
+
+DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage);
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGpuResource::didChangeGpuMemorySize() const {
+    fGpuMemorySize = kInvalidGpuMemorySize;
+    if (this->cacheAccess().isInCache()) {
+        fCacheEntry->didChangeResourceSize();
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() {
+    static int32_t gNextType = 0;
+
+    int32_t type = sk_atomic_inc(&gNextType);
+    if (type >= (1 << 8 * sizeof(ResourceType))) {
+        SkFAIL("Too many Resource Types");
+    }
+
+    return static_cast<ResourceType>(type);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, GrGpuResource* resource)
+        : fResourceCache(resourceCache),
+          fResource(resource),
+          fCachedSize(resource->gpuMemorySize()) {
+    // we assume ownership of the resource, and will unref it when we die
+    SkASSERT(resource);
+    resource->ref();
+}
+
+GrResourceCacheEntry::~GrResourceCacheEntry() {
+    // We're relying on having the cache entry to remove this from GrResourceCache2's content hash.
+    // fResource->setCacheEntry(NULL);
+    fResource->unref();
+}
+
+#ifdef SK_DEBUG
+void GrResourceCacheEntry::validate() const {
+    SkASSERT(fResourceCache);
+    SkASSERT(fResource);
+    SkASSERT(fResource->cacheAccess().getCacheEntry() == this);
+    SkASSERT(fResource->gpuMemorySize() == fCachedSize);
+    fResource->validate();
+}
+#endif
+
+void GrResourceCacheEntry::didChangeResourceSize() {
+    size_t oldSize = fCachedSize;
+    fCachedSize = fResource->gpuMemorySize();
+    if (fCachedSize > oldSize) {
+        fResourceCache->didIncreaseResourceSize(this, fCachedSize - oldSize);
+    } else if (fCachedSize < oldSize) {
+        fResourceCache->didDecreaseResourceSize(this, oldSize - fCachedSize);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrResourceCache::GrResourceCache(const GrDrawTargetCaps* caps, int maxCount, size_t maxBytes)
+    : fMaxCount(maxCount)
+    , fMaxBytes(maxBytes)
+    , fCaps(SkRef(caps)) {
+#if GR_CACHE_STATS
+    fHighWaterEntryCount          = 0;
+    fHighWaterEntryBytes          = 0;
+#endif
+
+    fEntryCount                   = 0;
+    fEntryBytes                   = 0;
+
+    fPurging                      = false;
+
+    fOverbudgetCB                 = NULL;
+    fOverbudgetData               = NULL;
+}
+
+GrResourceCache::~GrResourceCache() {
+    GrAutoResourceCacheValidate atcv(this);
+
+    EntryList::Iter iter;
+
+    // Unlike the removeAll, here we really remove everything, including locked resources.
+    while (GrResourceCacheEntry* entry = fList.head()) {
+        GrAutoResourceCacheValidate atcv(this);
+
+        // remove from our llist
+        this->internalDetach(entry);
+
+        delete entry;
+    }
+}
+
+void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
+    if (maxResources) {
+        *maxResources = fMaxCount;
+    }
+    if (maxResourceBytes) {
+        *maxResourceBytes = fMaxBytes;
+    }
+}
+
+void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
+    bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
+
+    fMaxCount = maxResources;
+    fMaxBytes = maxResourceBytes;
+
+    if (smaller) {
+        this->purgeAsNeeded();
+    }
+}
+
+void GrResourceCache::internalDetach(GrResourceCacheEntry* entry) {
+    fList.remove(entry);
+    fEntryCount -= 1;
+    fEntryBytes -= entry->fCachedSize;
+}
+
+void GrResourceCache::attachToHead(GrResourceCacheEntry* entry) {
+    fList.addToHead(entry);
+
+    fEntryCount += 1;
+    fEntryBytes += entry->fCachedSize;
+
+#if GR_CACHE_STATS
+    if (fHighWaterEntryCount < fEntryCount) {
+        fHighWaterEntryCount = fEntryCount;
+    }
+    if (fHighWaterEntryBytes < fEntryBytes) {
+        fHighWaterEntryBytes = fEntryBytes;
+    }
+#endif
+}
+
+
+void GrResourceCache::makeResourceMRU(GrGpuResource* resource) {
+    GrResourceCacheEntry* entry = resource->cacheAccess().getCacheEntry();
+    if (entry) {
+        this->internalDetach(entry);
+        this->attachToHead(entry);
+    }
+}
+
+void GrResourceCache::notifyPurgable(const GrGpuResource* resource) {
+    // Remove scratch textures from the cache the moment they become purgeable if
+    // scratch texture reuse is turned off.
+    SkASSERT(resource->cacheAccess().getCacheEntry());
+    if (resource->cacheAccess().isScratch()) {
+        const GrResourceKey& key = resource->cacheAccess().getScratchKey();
+        if (key.getResourceType() == GrTexturePriv::ResourceType() &&
+            !fCaps->reuseScratchTextures() &&
+            !(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTarget_GrSurfaceFlag)) {
+            this->deleteResource(resource->cacheAccess().getCacheEntry());
+        }
+    }
+}
+
+bool GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resource) {
+    if (NULL != resource->cacheAccess().getCacheEntry()) {
+        return false;
+    }
+    
+    if (key.isScratch()) {
+        SkASSERT(resource->cacheAccess().isScratch());
+        SkASSERT(key == resource->cacheAccess().getScratchKey());
+    } else {
+        if (!resource->cacheAccess().setContentKey(key)) {
+            return false;
+        }
+    }
+
+    // we don't expect to create new resources during a purge. In theory
+    // this could cause purgeAsNeeded() into an infinite loop (e.g.
+    // each resource destroyed creates and locks 2 resources and
+    // unlocks 1 thereby causing a new purge).
+    SkASSERT(!fPurging);
+    GrAutoResourceCacheValidate atcv(this);
+
+    GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, resource));
+    resource->cacheAccess().setCacheEntry(entry);
+
+    this->attachToHead(entry);
+    this->purgeAsNeeded();
+    return true;
+}
+
+void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountInc) {
+    fEntryBytes += amountInc;
+    this->purgeAsNeeded();
+}
+
+void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountDec) {
+    fEntryBytes -= amountDec;
+#ifdef SK_DEBUG
+    this->validate();
+#endif
+}
+
+/**
+ * Destroying a resource may potentially trigger the unlock of additional
+ * resources which in turn will trigger a nested purge. We block the nested
+ * purge using the fPurging variable. However, the initial purge will keep
+ * looping until either all resources in the cache are unlocked or we've met
+ * the budget. There is an assertion in createAndLock to check against a
+ * resource's destructor inserting new resources into the cache. If these
+ * new resources were unlocked before purgeAsNeeded completed it could
+ * potentially make purgeAsNeeded loop infinitely.
+ *
+ * extraCount and extraBytes are added to the current resource totals to account
+ * for incoming resources (e.g., GrContext is about to add 10MB split between
+ * 10 textures).
+ */
+void GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) {
+    if (fPurging) {
+        return;
+    }
+
+    fPurging = true;
+
+    this->internalPurge(extraCount, extraBytes);
+    if (((fEntryCount+extraCount) > fMaxCount ||
+        (fEntryBytes+extraBytes) > fMaxBytes) &&
+        fOverbudgetCB) {
+        // Despite the purge we're still over budget. See if Ganesh can
+        // release some resources and purge again.
+        if ((*fOverbudgetCB)(fOverbudgetData)) {
+            this->internalPurge(extraCount, extraBytes);
+        }
+    }
+
+    fPurging = false;
+}
+
+void GrResourceCache::purgeInvalidated() {
+    // TODO: Implement this in GrResourceCache2.
+}
+
+void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) {
+    SkASSERT(entry->fResource->isPurgable());
+    // remove from our llist
+    this->internalDetach(entry);
+    delete entry;
+}
+
+void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) {
+    SkASSERT(fPurging);
+
+    bool withinBudget = false;
+    bool changed = false;
+
+    // The purging process is repeated several times since one pass
+    // may free up other resources
+    do {
+        EntryList::Iter iter;
+
+        changed = false;
+
+        // Note: the following code relies on the fact that the
+        // doubly linked list doesn't invalidate its data/pointers
+        // outside of the specific area where a deletion occurs (e.g.,
+        // in internalDetach)
+        GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart);
+
+        while (entry) {
+            GrAutoResourceCacheValidate atcv(this);
+
+            if ((fEntryCount+extraCount) <= fMaxCount &&
+                (fEntryBytes+extraBytes) <= fMaxBytes) {
+                withinBudget = true;
+                break;
+            }
+
+            GrResourceCacheEntry* prev = iter.prev();
+            if (entry->fResource->isPurgable()) {
+                changed = true;
+                this->deleteResource(entry);
+            }
+            entry = prev;
+        }
+    } while (!withinBudget && changed);
+}
+
+void GrResourceCache::purgeAllUnlocked() {
+    GrAutoResourceCacheValidate atcv(this);
+
+    // we can have one GrCacheable holding a lock on another
+    // so we don't want to just do a simple loop kicking each
+    // entry out. Instead change the budget and purge.
+
+    size_t savedMaxBytes = fMaxBytes;
+    int savedMaxCount = fMaxCount;
+    fMaxBytes = (size_t) -1;
+    fMaxCount = 0;
+    this->purgeAsNeeded();
+
+    fMaxBytes = savedMaxBytes;
+    fMaxCount = savedMaxCount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+size_t GrResourceCache::countBytes(const EntryList& list) {
+    size_t bytes = 0;
+
+    EntryList::Iter iter;
+
+    const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(list),
+                                                  EntryList::Iter::kTail_IterStart);
+
+    for ( ; entry; entry = iter.prev()) {
+        bytes += entry->resource()->gpuMemorySize();
+    }
+    return bytes;
+}
+
+static bool both_zero_or_nonzero(int count, size_t bytes) {
+    return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
+}
+
+void GrResourceCache::validate() const {
+    fList.validate();
+    SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes));
+
+    EntryList::Iter iter;
+
+    // check that the shareable entries are okay
+    const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fList),
+                                                  EntryList::Iter::kHead_IterStart);
+
+    int count = 0;
+    for ( ; entry; entry = iter.next()) {
+        entry->validate();
+        count += 1;
+    }
+    SkASSERT(count == fEntryCount);
+
+    size_t bytes = this->countBytes(fList);
+    SkASSERT(bytes == fEntryBytes);
+    SkASSERT(fList.countEntries() == fEntryCount);
+}
+#endif // SK_DEBUG
+
+#if GR_CACHE_STATS
+
+void GrResourceCache::printStats() {
+    int locked = 0;
+    int scratch = 0;
+
+    EntryList::Iter iter;
+
+    GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart);
+
+    for ( ; entry; entry = iter.prev()) {
+        if (!entry->fResource->isPurgable()) {
+            ++locked;
+        }
+        if (entry->fResource->cacheAccess().isScratch()) {
+            ++scratch;
+        }
+    }
+
+    float countUtilization = (100.f * fEntryCount) / fMaxCount;
+    float byteUtilization = (100.f * fEntryBytes) / fMaxBytes;
+
+    SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes);
+    SkDebugf("\t\tEntry Count: current %d (%d locked, %d scratch %.2g%% full), high %d\n",
+                fEntryCount, locked, scratch, countUtilization, fHighWaterEntryCount);
+    SkDebugf("\t\tEntry Bytes: current %d (%.2g%% full) high %d\n",
+                fEntryBytes, byteUtilization, fHighWaterEntryBytes);
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
new file mode 100644 (file)
index 0000000..80e4b3f
--- /dev/null
@@ -0,0 +1,251 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrResourceCache_DEFINED
+#define GrResourceCache_DEFINED
+
+#include "GrDrawTargetCaps.h"
+#include "GrResourceKey.h"
+#include "SkTMultiMap.h"
+#include "SkMessageBus.h"
+#include "SkTInternalLList.h"
+
+class GrGpuResource;
+class GrResourceCache;
+class GrResourceCacheEntry;
+
+
+// The cache listens for these messages to purge junk resources proactively.
+struct GrResourceInvalidatedMessage {
+    GrResourceKey key;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrResourceCacheEntry {
+public:
+    GrGpuResource* resource() const { return fResource; }
+
+    static uint32_t Hash(const GrGpuResource* resource) {
+        return static_cast<uint32_t>(reinterpret_cast<intptr_t>(resource));
+    }
+#ifdef SK_DEBUG
+    void validate() const;
+#else
+    void validate() const {}
+#endif
+
+    /**
+     *  Update the cached size for this entry and inform the resource cache that
+     *  it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize,
+     *  not directly from here.
+     */
+    void didChangeResourceSize();
+
+private:
+    GrResourceCacheEntry(GrResourceCache*, GrGpuResource*);
+    ~GrResourceCacheEntry();
+
+    GrResourceCache* fResourceCache;
+    GrGpuResource*   fResource;
+    size_t           fCachedSize;
+
+    // Linked list for the LRU ordering.
+    SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
+
+    friend class GrResourceCache;
+    friend class GrContext;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  Cache of GrGpuResource objects.
+ *
+ *  These have a corresponding GrResourceKey, built from 128bits identifying the
+ *  resource. Multiple resources can map to same GrResourceKey.
+ *
+ *  The cache stores the entries in a double-linked list, which is its LRU.
+ *  When an entry is "locked" (i.e. given to the caller), it is moved to the
+ *  head of the list. If/when we must purge some of the entries, we walk the
+ *  list backwards from the tail, since those are the least recently used.
+ *
+ *  For fast searches, we maintain a hash map based on the GrResourceKey.
+ *
+ *  It is a goal to make the GrResourceCache the central repository and bookkeeper
+ *  of all resources. It should replace the linked list of GrGpuResources that
+ *  GrGpu uses to call abandon/release.
+ */
+class GrResourceCache {
+public:
+    GrResourceCache(const GrDrawTargetCaps*, int maxCount, size_t maxBytes);
+    ~GrResourceCache();
+
+    /**
+     *  Return the current resource cache limits.
+     *
+     *  @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.
+     */
+    void getLimits(int* maxResources, size_t* maxBytes) const;
+
+    /**
+     *  Specify the resource cache limits. If the current cache exceeds either
+     *  of these, it will be purged (LRU) to keep the cache within these limits.
+     *
+     *  @param maxResources The maximum number of resources that can be held in
+     *                      the cache.
+     *  @param maxBytes     The maximum number of bytes of resource memory that
+     *                      can be held in the cache.
+     */
+    void setLimits(int maxResources, size_t maxResourceBytes);
+
+    /**
+     *  The callback function used by the cache when it is still over budget
+     *  after a purge. The passed in 'data' is the same 'data' handed to
+     *  setOverbudgetCallback. The callback returns true if some resources
+     *  have been freed.
+     */
+    typedef bool (*PFOverbudgetCB)(void* data);
+
+    /**
+     *  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. Note that the cache will attempt to purge any resources newly
+     *  freed by the callback.
+     */
+    void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
+        fOverbudgetCB = overbudgetCB;
+        fOverbudgetData = data;
+    }
+
+    /**
+     * Returns the number of bytes consumed by cached resources.
+     */
+    size_t getCachedResourceBytes() const { return fEntryBytes; }
+
+    /**
+     * Returns the number of cached resources.
+     */
+    int getCachedResourceCount() const { return fEntryCount; }
+
+    void makeResourceMRU(GrGpuResource*);
+
+    /** Called by GrGpuResources when they detects that they are newly purgable. */
+    void notifyPurgable(const GrGpuResource*);
+
+    /**
+     *  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.
+     *
+     *  This can fail if the key is already taken, or the resource is already in
+     *  the cache.
+     */
+    bool addResource(const GrResourceKey& key, GrGpuResource* resource);
+
+    /**
+     * Notify the cache that the size of a resource has changed.
+     */
+    void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
+    void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
+
+    /**
+     * Remove a resource from the cache and delete it!
+     */
+    void deleteResource(GrResourceCacheEntry* entry);
+
+    /**
+     * Removes every resource in the cache that isn't locked.
+     */
+    void purgeAllUnlocked();
+
+    /**
+     * 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. 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,
+     * 10MB across 10 textures is about to be added).
+     */
+    void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
+
+#ifdef SK_DEBUG
+    void validate() const;
+#else
+    void validate() const {}
+#endif
+
+#if GR_CACHE_STATS
+    void printStats();
+#endif
+
+private:
+    void internalDetach(GrResourceCacheEntry*);
+    void attachToHead(GrResourceCacheEntry*);
+    void purgeInvalidated();
+    void internalPurge(int extraCount, size_t extraBytes);
+#ifdef SK_DEBUG
+    static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
+#endif
+
+    // We're an internal doubly linked list
+    typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
+    EntryList                               fList;
+
+    // our budget, used in purgeAsNeeded()
+    int                                     fMaxCount;
+    size_t                                  fMaxBytes;
+
+    // our current stats, related to our budget
+#if GR_CACHE_STATS
+    int                                     fHighWaterEntryCount;
+    size_t                                  fHighWaterEntryBytes;
+#endif
+
+    int                                     fEntryCount;
+    size_t                                  fEntryBytes;
+
+    // prevents recursive purging
+    bool                                    fPurging;
+
+    PFOverbudgetCB                          fOverbudgetCB;
+    void*                                   fOverbudgetData;
+
+    SkAutoTUnref<const GrDrawTargetCaps>    fCaps;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+    class GrAutoResourceCacheValidate {
+    public:
+        GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
+            cache->validate();
+        }
+        ~GrAutoResourceCacheValidate() {
+            fCache->validate();
+        }
+    private:
+        GrResourceCache* fCache;
+    };
+#else
+    class GrAutoResourceCacheValidate {
+    public:
+        GrAutoResourceCacheValidate(GrResourceCache*) {}
+    };
+#endif
+
+#endif
index 109e815dacc9150d55af160cf46254c9ec517b46..83143d78185898c8ed0ed83420228019de1f9d42 100644 (file)
 #include "GrResourceCache2.h"
 #include "GrGpuResource.h"  
 
-#include "SkGr.h"
-#include "SkMessageBus.h"
-
-DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage);
-
-//////////////////////////////////////////////////////////////////////////////
-
 GrResourceKey& GrResourceKey::NullScratchKey() {
     static const GrCacheID::Key kBogusKey = { { {0} } };
     static GrCacheID kBogusID(ScratchDomain(), kBogusKey);
@@ -34,85 +27,26 @@ GrCacheID::Domain GrResourceKey::ScratchDomain() {
     return gDomain;
 }
 
-GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() {
-    static int32_t gNextType = 0;
-
-    int32_t type = sk_atomic_inc(&gNextType);
-    if (type >= (1 << 8 * sizeof(ResourceType))) {
-        SkFAIL("Too many Resource Types");
-    }
-
-    return static_cast<ResourceType>(type);
-}
-
 //////////////////////////////////////////////////////////////////////////////
 
-class GrResourceCache2::AutoValidate : ::SkNoncopyable {
-public:
-    AutoValidate(GrResourceCache2* cache) : fCache(cache) { cache->validate(); }
-    ~AutoValidate() { fCache->validate(); }
-private:
-    GrResourceCache2* fCache;
-};
-
- //////////////////////////////////////////////////////////////////////////////
-
-static const int kDefaultMaxCount = 2 * (1 << 10);
-static const size_t kDefaultMaxSize = 96 * (1 << 20);
-
-GrResourceCache2::GrResourceCache2()
-    : fMaxCount(kDefaultMaxCount)
-    , fMaxBytes(kDefaultMaxSize)
-#if GR_CACHE_STATS
-    , fHighWaterCount(0)
-    , fHighWaterBytes(0)
-#endif
-    , fCount(0)
-    , fBytes(0)
-    , fPurging(false)
-    , fNewlyPurgableResourceWhilePurging(false)
-    , fOverBudgetCB(NULL)
-    , fOverBudgetData(NULL) {
-}
-
 GrResourceCache2::~GrResourceCache2() {
     this->releaseAll();
 }
 
-void GrResourceCache2::setLimits(int count, size_t bytes) {
-    fMaxCount = count;
-    fMaxBytes = bytes;
-    this->purgeAsNeeded();
-}
-
 void GrResourceCache2::insertResource(GrGpuResource* resource) {
-    AutoValidate av(this);
-
     SkASSERT(resource);
     SkASSERT(!resource->wasDestroyed());
     SkASSERT(!this->isInCache(resource));
-    SkASSERT(!fPurging);
     fResources.addToHead(resource);
-    resource->ref();
-
     ++fCount;
-    SkDEBUGCODE(fHighWaterCount = SkTMax(fCount, fHighWaterCount));
-    fBytes += resource->gpuMemorySize();
-    SkDEBUGCODE(fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes));
     if (!resource->cacheAccess().getScratchKey().isNullScratch()) {
         // TODO(bsalomon): Make this assertion possible.
         // SkASSERT(!resource->isWrapped());
         fScratchMap.insert(resource->cacheAccess().getScratchKey(), resource);
     }
-    
-    this->purgeAsNeeded();
 }
 
 void GrResourceCache2::removeResource(GrGpuResource* resource) {
-    AutoValidate av(this);
-
-    --fCount;
-    fBytes -= resource->gpuMemorySize();
     SkASSERT(this->isInCache(resource));
     fResources.remove(resource);    
     if (!resource->cacheAccess().getScratchKey().isNullScratch()) {
@@ -121,16 +55,13 @@ void GrResourceCache2::removeResource(GrGpuResource* resource) {
     if (const GrResourceKey* contentKey = resource->cacheAccess().getContentKey()) {
         fContentHash.remove(*contentKey);
     }
+    --fCount;
 }
 
 void GrResourceCache2::abandonAll() {
-    AutoValidate av(this);
-
-    SkASSERT(!fPurging);
     while (GrGpuResource* head = fResources.head()) {
         SkASSERT(!head->wasDestroyed());
         head->abandon();
-        head->unref();
         // abandon should have already removed this from the list.
         SkASSERT(head != fResources.head());
     }
@@ -140,13 +71,9 @@ void GrResourceCache2::abandonAll() {
 }
 
 void GrResourceCache2::releaseAll() {
-    AutoValidate av(this);
-
-    SkASSERT(!fPurging);
     while (GrGpuResource* head = fResources.head()) {
         SkASSERT(!head->wasDestroyed());
         head->release();
-        head->unref();
         // release should have already removed this from the list.
         SkASSERT(head != fResources.head());
     }
@@ -172,16 +99,11 @@ private:
 
 GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey& scratchKey,
                                                            uint32_t flags) {
-    AutoValidate av(this);
-
-    SkASSERT(!fPurging);
     SkASSERT(scratchKey.isScratch());
 
-    GrGpuResource* resource;
     if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
-        resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
+        GrGpuResource* resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
         if (resource) {
-            this->makeResourceMRU(resource);
             return SkRef(resource);
         } else if (flags & kRequireNoPendingIO_ScratchFlag) {
             return NULL;
@@ -189,18 +111,11 @@ GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey&
         // TODO: fail here when kPrefer is specified, we didn't find a resource without pending io,
         // but there is still space in our budget for the resource.
     }
-    resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
-    if (resource) {
-        resource->ref();
-        this->makeResourceMRU(resource);
-    }
-    return resource;
+    return SkSafeRef(fScratchMap.find(scratchKey, AvailableForScratchUse(false)));
 }
 
 bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) {
-    SkASSERT(!fPurging);
     SkASSERT(resource);
-    SkASSERT(this->isInCache(resource));
     SkASSERT(resource->cacheAccess().getContentKey());
     SkASSERT(!resource->cacheAccess().getContentKey()->isScratch());
 
@@ -210,214 +125,5 @@ bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) {
     }
 
     fContentHash.add(resource);
-    this->validate();
     return true;
 }
-
-void GrResourceCache2::makeResourceMRU(GrGpuResource* resource) {
-    AutoValidate av(this);
-
-    SkASSERT(!fPurging);
-    SkASSERT(resource);
-    SkASSERT(this->isInCache(resource));
-    fResources.remove(resource);    
-    fResources.addToHead(resource);    
-}
-
-void GrResourceCache2::notifyPurgable(const GrGpuResource* resource) {
-    SkASSERT(resource);
-    SkASSERT(this->isInCache(resource));
-    SkASSERT(resource->isPurgable());
-
-    // We can't purge if in the middle of purging because purge is iterating. Instead record
-    // that additional resources became purgable.
-    if (fPurging) {
-        fNewlyPurgableResourceWhilePurging = true;
-        return;
-    }
-
-    // Purge the resource if we're over budget
-    bool overBudget = fCount > fMaxCount || fBytes > fMaxBytes;
-
-    // We should not be over budget here unless all resources are unpuragble.
-#ifdef SK_DEBUG
-    if (overBudget) {
-        ResourceList::Iter iter;
-        GrGpuResource* r = iter.init(fResources, ResourceList::Iter::kHead_IterStart);
-        for ( ; r; r = iter.next()) {
-            SkASSERT(r == resource || !r->isPurgable());
-        }
-    }
-#endif
-
-    // Also purge if the resource has neither a valid scratch key nor a content key.
-    bool noKey = !resource->cacheAccess().isScratch() &&
-                 (NULL == resource->cacheAccess().getContentKey());
-
-    if (overBudget || noKey) {
-        SkDEBUGCODE(int beforeCount = fCount;)
-        resource->unref();
-        SkASSERT(fCount == beforeCount - 1);
-    }
-
-    this->validate();
-}
-
-void GrResourceCache2::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
-    // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
-    SkASSERT(resource);
-    SkASSERT(this->isInCache(resource));
-
-    fBytes += resource->gpuMemorySize() - oldSize;
-    SkDEBUGCODE(fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes));
-
-    this->purgeAsNeeded();
-    this->validate();
-}
-
-void GrResourceCache2::internalPurgeAsNeeded() {
-    SkASSERT(!fPurging);
-    SkASSERT(!fNewlyPurgableResourceWhilePurging);
-    SkASSERT(fCount > fMaxCount || fBytes > fMaxBytes);
-
-    fPurging = true;
-
-    AutoValidate av(this); // Put this after setting fPurging so we're allowed to be over budget.
-
-    bool overBudget = true;
-    do {
-        fNewlyPurgableResourceWhilePurging = false;
-        ResourceList::Iter resourceIter;
-        GrGpuResource* resource = resourceIter.init(fResources,
-                                                    ResourceList::Iter::kTail_IterStart);
-
-        while (resource) {
-            GrGpuResource* prev = resourceIter.prev();
-            if (resource->isPurgable()) {
-                resource->unref();
-            }
-            resource = prev;
-            if (fCount <= fMaxCount && fBytes <= fMaxBytes) {
-                overBudget = false;
-                resource = NULL;
-            }
-        }
-
-        if (!fNewlyPurgableResourceWhilePurging && overBudget && fOverBudgetCB) {
-            // Despite the purge we're still over budget. Call our over budget callback.
-            (*fOverBudgetCB)(fOverBudgetData);
-        }
-    } while (overBudget && fNewlyPurgableResourceWhilePurging);
-
-    fNewlyPurgableResourceWhilePurging = false;
-    fPurging = false;
-}
-
-void GrResourceCache2::purgeAllUnlocked() {
-    SkASSERT(!fPurging);
-    SkASSERT(!fNewlyPurgableResourceWhilePurging);
-
-    fPurging = true;
-
-    AutoValidate av(this); // Put this after setting fPurging so we're allowed to be over budget.
-
-    do {
-        fNewlyPurgableResourceWhilePurging = false;
-        ResourceList::Iter resourceIter;
-        GrGpuResource* resource =
-            resourceIter.init(fResources, ResourceList::Iter::kTail_IterStart);
-
-        while (resource) {
-            GrGpuResource* prev = resourceIter.prev();
-            if (resource->isPurgable()) {
-                resource->unref();
-            } 
-            resource = prev;
-        }
-
-        if (!fNewlyPurgableResourceWhilePurging && fCount && fOverBudgetCB) {
-            (*fOverBudgetCB)(fOverBudgetData);
-        }
-    } while (fNewlyPurgableResourceWhilePurging);
-    fPurging = false;
-}
-
-#ifdef SK_DEBUG
-void GrResourceCache2::validate() const {
-    size_t bytes = 0;
-    int count = 0;
-    int locked = 0;
-    int scratch = 0;
-    int couldBeScratch = 0;
-    int content = 0;
-
-    ResourceList::Iter iter;
-    GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_IterStart);
-    for ( ; resource; resource = iter.next()) {
-        bytes += resource->gpuMemorySize();
-        ++count;
-
-        if (!resource->isPurgable()) {
-            ++locked;
-        }
-
-        if (resource->cacheAccess().isScratch()) {
-            SkASSERT(NULL == resource->cacheAccess().getContentKey());
-            ++scratch;
-            SkASSERT(fScratchMap.countForKey(resource->cacheAccess().getScratchKey()));
-        } else if (!resource->cacheAccess().getScratchKey().isNullScratch()) {
-            SkASSERT(NULL != resource->cacheAccess().getContentKey());
-            ++couldBeScratch;
-            SkASSERT(fScratchMap.countForKey(resource->cacheAccess().getScratchKey()));
-        }
-
-        if (const GrResourceKey* contentKey = resource->cacheAccess().getContentKey()) {
-            ++content;
-            SkASSERT(fContentHash.find(*contentKey) == resource);
-        }
-    }
-
-    SkASSERT(bytes == fBytes);
-    SkASSERT(count == fCount);
-#if GR_CACHE_STATS
-    SkASSERT(bytes <= fHighWaterBytes);
-    SkASSERT(count <= fHighWaterCount);
-#endif
-    SkASSERT(content == fContentHash.count());
-    SkASSERT(scratch + couldBeScratch == fScratchMap.count());
-
-    bool overBudget = bytes > fMaxBytes || count > fMaxCount;
-    SkASSERT(!overBudget || locked == count || fPurging);
-}
-#endif
-
-#if GR_CACHE_STATS
-void GrResourceCache2::printStats() const {
-    this->validate();
-
-    int locked = 0;
-    int scratch = 0;
-
-    ResourceList::Iter iter;
-    GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_IterStart);
-
-    for ( ; resource; resource = iter.next()) {
-        if (!resource->isPurgable()) {
-            ++locked;
-        }
-        if (resource->cacheAccess().isScratch()) {
-            ++scratch;
-        }
-    }
-
-    float countUtilization = (100.f * fCount) / fMaxCount;
-    float byteUtilization = (100.f * fBytes) / fMaxBytes;
-
-    SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes);
-    SkDebugf("\t\tEntry Count: current %d (%d locked, %d scratch %.2g%% full), high %d\n",
-                fCount, locked, scratch, countUtilization, fHighWaterCount);
-    SkDebugf("\t\tEntry Bytes: current %d (%.2g%% full) high %d\n",
-                fBytes, byteUtilization, fHighWaterBytes);
-}
-
-#endif
index 8b4d1d0e67564142ba05eb724c3ed7c001c6241d..1cc958799d44a538674cdb2573e368a8c058b8cd 100644 (file)
 #include "SkTMultiMap.h"
 
 /**
- * Manages the lifetime of all GrGpuResource instances.
- *
- * Resources may have optionally have two types of keys:
- *      1) A scratch key. This is for resources whose allocations are cached but not their contents.
- *         Multiple resources can share the same scratch key. This is so a caller can have two
- *         resource instances with the same properties (e.g. multipass rendering that ping pongs
- *         between two temporary surfaces. The scratch key is set at resource creation time and
- *         should never change. Resources need not have a scratch key.
- *      2) A content key. This key represents the contents of the resource rather than just its
- *         allocation properties. They may not collide. The content key can be set after resource
- *         creation. Currently it may only be set once and cannot be cleared. This restriction will
- *         be removed.
- * If a resource has neither key type then it will be deleted as soon as the last reference to it
- * is dropped. If a key has both keys the content key takes precedence.
+ *  Eventual replacement for GrResourceCache. Currently it simply holds a list
+ *  of all GrGpuResource objects for a GrContext. It is used to invalidate all
+ *  the resources when necessary.
  */
 class GrResourceCache2 {
 public:
-    GrResourceCache2();
+    GrResourceCache2() : fCount(0) {};
     ~GrResourceCache2();
 
-    /** Used to access functionality needed by GrGpuResource for lifetime management. */
-    class ResourceAccess;
-    ResourceAccess resourceAccess();
-
-    /**
-     * Sets the cache limits in terms of number of resources and max gpu memory byte size.
-     */
-    void setLimits(int count, size_t bytes);
-
-    /**
-     * Returns the number of cached resources.
-     */
-    int getResourceCount() const { return fCount; }
-
-    /**
-     * Returns the number of bytes consumed by cached resources.
-     */
-    size_t getResourceBytes() const { return fBytes; }
+    void insertResource(GrGpuResource*);
 
-    /**
-     * Returns the cached resources count budget.
-     */
-    int getMaxResourceCount() const { return fMaxCount; }
+    void removeResource(GrGpuResource*);
 
-    /**
-     * Returns the number of bytes consumed by cached resources.
-     */
-    size_t getMaxResourceBytes() const { return fMaxBytes; }
+    // This currently returns a bool and fails when an existing resource has a key that collides
+    // with the new content key. In the future it will null out the content key for the existing
+    // resource. The failure is a temporary measure taken because duties are split between two
+    // cache objects currently.
+    bool didSetContentKey(GrGpuResource*);
 
-    /**
-     * Abandons the backend API resources owned by all GrGpuResource objects and removes them from
-     * the cache.
-     */
     void abandonAll();
 
-    /**
-     * Releases the backend API resources owned by all GrGpuResource objects and removes them from
-     * the cache.
-     */
     void releaseAll();
 
     enum {
@@ -84,10 +46,6 @@ public:
         /** Will not return any resources that match but have pending IO. */
         kRequireNoPendingIO_ScratchFlag = 0x2,
     };
-
-    /**
-     * Find a resource that matches a scratch key.
-     */
     GrGpuResource* findAndRefScratchResource(const GrResourceKey& scratchKey, uint32_t flags = 0);
     
 #ifdef SK_DEBUG
@@ -98,80 +56,21 @@ public:
     }
 #endif
 
-    /**
-     * Find a resource that matches a content key.
-     */
     GrGpuResource* findAndRefContentResource(const GrResourceKey& contentKey) {
         SkASSERT(!contentKey.isScratch());
-        GrGpuResource* resource = fContentHash.find(contentKey);
-        if (resource) {
-            resource->ref();
-            this->makeResourceMRU(resource);
-        }
-        return resource;
+        return SkSafeRef(fContentHash.find(contentKey));
     }
 
-    /**
-     * Query whether a content key exists in the cache.
-     */
     bool hasContentKey(const GrResourceKey& contentKey) const {
         SkASSERT(!contentKey.isScratch());
         return SkToBool(fContentHash.find(contentKey));
     }
 
-    /** Purges all resources that don't have external owners. */
-    void purgeAllUnlocked();
-
-    /**
-     * The callback function used by the cache when it is still over budget after a purge. The
-     * passed in 'data' is the same 'data' handed to setOverbudgetCallback.
-     */
-    typedef void (*PFOverBudgetCB)(void* data);
-
-    /**
-     * 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. Note that the cache will attempt to purge
-     * any resources newly freed by the callback.
-     */
-    void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) {
-        fOverBudgetCB = overBudgetCB;
-        fOverBudgetData = data;
-    }
-
-#if GR_GPU_STATS
-    void printStats() const;
-#endif
-
 private:
-    ///////////////////////////////////////////////////////////////////////////
-    /// @name Methods accessible via ResourceAccess
-    ////
-    void insertResource(GrGpuResource*);
-    void removeResource(GrGpuResource*);
-    void notifyPurgable(const GrGpuResource*);
-    void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize);
-    bool didSetContentKey(GrGpuResource*);
-    void makeResourceMRU(GrGpuResource*);
-    /// @}
-
-    void purgeAsNeeded() {
-        if (fPurging || (fCount <= fMaxCount && fBytes < fMaxBytes)) {
-            return;
-        }
-        this->internalPurgeAsNeeded();
-    }
-
-    void internalPurgeAsNeeded();
-
 #ifdef SK_DEBUG
     bool isInCache(const GrGpuResource* r) const { return fResources.isInList(r); }
-    void validate() const;
-#else
-    void validate() const {}
 #endif
 
-    class AutoValidate;
-
     class AvailableForScratchUse;
 
     struct ScratchMapTraits {
@@ -192,86 +91,12 @@ private:
     };
     typedef SkTDynamicHash<GrGpuResource, GrResourceKey, ContentHashTraits> ContentHash;
 
-    typedef SkTInternalLList<GrGpuResource> ResourceList;
-
-    ResourceList                        fResources;
+    int                                 fCount;
+    SkTInternalLList<GrGpuResource>     fResources;
     // This map holds all resources that can be used as scratch resources.
     ScratchMap                          fScratchMap;
     // This holds all resources that have content keys.
     ContentHash                         fContentHash;
-
-    // our budget, used in purgeAsNeeded()
-    int                                 fMaxCount;
-    size_t                              fMaxBytes;
-
-#if GR_CACHE_STATS
-    int                                 fHighWaterCount;
-    size_t                              fHighWaterBytes;
-#endif
-
-    // our current stats, related to our budget
-    int                                 fCount;
-    size_t                              fBytes;
-
-    // prevents recursive purging
-    bool                                fPurging;
-    bool                                fNewlyPurgableResourceWhilePurging;
-
-    PFOverBudgetCB                      fOverBudgetCB;
-    void*                               fOverBudgetData;
-
 };
 
-class GrResourceCache2::ResourceAccess {
-private:
-    ResourceAccess(GrResourceCache2* cache) : fCache(cache) { }
-    ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { }
-    ResourceAccess& operator=(const ResourceAccess&); // unimpl
-
-    /**
-     * Insert a resource into the cache.
-     */
-    void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); }
-
-    /**
-     * Removes a resource from the cache.
-     */
-    void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); }
-
-    /**
-     * Called by GrGpuResources when they detects that they are newly purgable.
-     */
-    void notifyPurgable(const GrGpuResource* resource) { fCache->notifyPurgable(resource); }
-
-    /**
-     * Called by GrGpuResources when their sizes change.
-     */
-    void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
-        fCache->didChangeGpuMemorySize(resource, oldSize);
-    }
-
-    /**
-     * Called by GrGpuResources when their content keys change.
-     *
-     * This currently returns a bool and fails when an existing resource has a key that collides
-     * with the new content key. In the future it will null out the content key for the existing
-     * resource. The failure is a temporary measure taken because duties are split between two
-     * cache objects currently.
-     */
-    bool didSetContentKey(GrGpuResource* resource) { return fCache->didSetContentKey(resource); }
-
-    // No taking addresses of this type.
-    const ResourceAccess* operator&() const;
-    ResourceAccess* operator&();
-
-    GrResourceCache2* fCache;
-
-    friend class GrGpuResource; // To access all the proxy inline methods.
-    friend class GrResourceCache2; // To create this type.
-};
-
-inline GrResourceCache2::ResourceAccess GrResourceCache2::resourceAccess() {
-    return ResourceAccess(this);
-}
-
 #endif
index 16b0150a4d45ba7000ee26bb2c2f8e7d4f348e22..b288415301162bdc020846e4a2a406b48151ba82 100644 (file)
@@ -13,6 +13,8 @@
 #include "GrResourceCache2.h"
 
 void GrStencilBuffer::transferToCache() {
+    SkASSERT(!this->cacheAccess().isInCache());
+
     this->getGpu()->getContext()->addStencilBuffer(this);
 }
 
index 528698478a140e7de011249fb606199ddcf48d78..611059ae4cfae79edb02bdea8b5ae7c1d5c2178f 100644 (file)
@@ -9,7 +9,7 @@
 #include "GrTest.h"
 
 #include "GrInOrderDrawBuffer.h"
-#include "GrResourceCache2.h"
+#include "GrResourceCache.h"
 
 void GrTestTarget::init(GrContext* ctx, GrDrawTarget* target) {
     SkASSERT(!fContext);
@@ -38,7 +38,7 @@ void GrContext::setMaxTextureSizeOverride(int maxTextureSizeOverride) {
 }
 
 void GrContext::purgeAllUnlockedResources() {
-    fResourceCache2->purgeAllUnlocked();
+    fResourceCache->purgeAllUnlocked();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
index 9f700c7556ae853bfa78b505ecbe272de6fcd7e5..58bbeaae425c6ef43dbd52b05526b4f5099b9a56 100644 (file)
@@ -9,6 +9,7 @@
 #include "GrContext.h"
 #include "GrDrawTargetCaps.h"
 #include "GrGpu.h"
+#include "GrResourceCache.h"
 #include "GrTexture.h"
 #include "GrTexturePriv.h"
 
index a86ee6031701cd1d6ec863251b271127eef775bd..affbd956b099e2ec3dff2814a7267146ae1986a2 100644 (file)
@@ -12,6 +12,7 @@
 #include "SkMessageBus.h"
 #include "SkPixelRef.h"
 #include "SkTextureCompressor.h"
+#include "GrResourceCache.h"
 #include "GrGpu.h"
 #include "effects/GrDitherEffect.h"
 #include "GrDrawTargetCaps.h"
index 6f51d30766b2ee4f80fe9fb2f1b3a685aea090c3..7cebddb0ccd607d8c83ec9bf47db647b495e237c 100644 (file)
 #include "GrContext.h"
 #include "GrContextFactory.h"
 #include "GrGpu.h"
+#include "GrResourceCache.h"
 #include "GrResourceCache2.h"
 #include "SkCanvas.h"
-#include "SkGr.h"
-#include "SkMessageBus.h"
 #include "SkSurface.h"
 #include "Test.h"
 
@@ -68,6 +67,7 @@ public:
     SK_DECLARE_INST_COUNT(TestResource);
     TestResource(GrGpu* gpu)
         : INHERITED(gpu, false)
+        , fCache(NULL)
         , fToDelete(NULL)
         , fSize(kDefaultSize) {
         ++fNumAlive;
@@ -76,6 +76,7 @@ public:
 
     TestResource(GrGpu* gpu, const GrResourceKey& scratchKey)
         : INHERITED(gpu, false)
+        , fCache(NULL)
         , fToDelete(NULL)
         , fSize(kDefaultSize) {
         this->setScratchKey(scratchKey);
@@ -85,7 +86,11 @@ public:
 
     ~TestResource() {
         --fNumAlive;
-        SkSafeUnref(fToDelete);
+        if (fToDelete) {
+            // Breaks our little 2-element cycle below.
+            fToDelete->setDeleteWhenDestroyed(NULL, NULL);
+            fCache->deleteResource(fToDelete->cacheAccess().getCacheEntry());
+        }
         this->release();
     }
 
@@ -96,13 +101,15 @@ public:
 
     static int NumAlive() { return fNumAlive; }
 
-    void setUnrefWhenDestroyed(TestResource* resource) {
-        SkRefCnt_SafeAssign(fToDelete, resource);
+    void setDeleteWhenDestroyed(GrResourceCache* cache, TestResource* resource) {
+        fCache = cache;
+        fToDelete = resource;
     }
 
 private:
     size_t onGpuMemorySize() const SK_OVERRIDE { return fSize; }
 
+    GrResourceCache* fCache;
     TestResource* fToDelete;
     size_t fSize;
     static int fNumAlive;
@@ -111,61 +118,6 @@ private:
 };
 int TestResource::fNumAlive = 0;
 
-static void test_no_key(skiatest::Reporter* reporter) {
-    SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
-    REPORTER_ASSERT(reporter, SkToBool(context));
-    if (NULL == context) {
-        return;
-    }
-    context->setResourceCacheLimits(10, 30000);
-    GrResourceCache2* cache2 = context->getResourceCache2();
-    cache2->purgeAllUnlocked();
-    SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
-
-    // Create a bunch of resources with no keys
-    TestResource* a = new TestResource(context->getGpu());
-    TestResource* b = new TestResource(context->getGpu());
-    TestResource* c = new TestResource(context->getGpu());
-    TestResource* d = new TestResource(context->getGpu());
-    a->setSize(11);
-    b->setSize(12);
-    c->setSize(13);
-    d->setSize(14);
-
-    REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
-    REPORTER_ASSERT(reporter, 4 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
-                              d->gpuMemorySize() == cache2->getResourceBytes());
-
-    // Should be safe to purge without deleting the resources since we still have refs.
-    cache2->purgeAllUnlocked();
-    REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
-
-    // Since the resources have neither content nor scratch keys, delete immediately upon unref.
-
-    a->unref();
-    REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
-    REPORTER_ASSERT(reporter, 3 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() ==
-                              cache2->getResourceBytes());
-
-    c->unref();
-    REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
-    REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
-                              cache2->getResourceBytes());
-
-    d->unref();
-    REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
-    REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache2->getResourceBytes());
-
-    b->unref();
-    REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
-    REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
-}
-
 static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
     SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
     REPORTER_ASSERT(reporter, SkToBool(context));
@@ -173,9 +125,10 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
         return;
     }
     context->setResourceCacheLimits(5, 30000);
-    GrResourceCache2* cache2 = context->getResourceCache2();
-    cache2->purgeAllUnlocked();
-    SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+    GrResourceCache* cache = context->getResourceCache();
+    SkDEBUGCODE(GrResourceCache2* cache2 = context->getResourceCache2();)
+    cache->purgeAllUnlocked();
+    SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
     GrCacheID::Key keyData;
     memset(&keyData, 0, sizeof(keyData));
@@ -189,16 +142,30 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
     a->setSize(11);
     b->setSize(12);
     // Scratch resources are registered with GrResourceCache2 just by existing. There are 2.
-    REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
-    REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+
+    REPORTER_ASSERT(reporter, cache->addResource(scratchKey, a));
+
+    SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
+
+    // Can't add the same resource twice.
+    REPORTER_ASSERT(reporter, !cache->addResource(scratchKey, a));
+    REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
+    REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getCachedResourceBytes());
+    SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
+
+    // Add a second with the same key.
+    REPORTER_ASSERT(reporter, cache->addResource(scratchKey, b));
+    REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
-                              cache2->getResourceBytes());
+                              cache->getCachedResourceBytes());
+    REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
+    SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
 
     // Our refs mean that the resources are non purgable.
-    cache2->purgeAllUnlocked();
+    cache->purgeAllUnlocked();
     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
-    REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+    REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
 
     // Unref but don't purge
     a->unref();
@@ -207,9 +174,9 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
 
     // Purge again. This time resources should be purgable.
-    cache2->purgeAllUnlocked();
+    cache->purgeAllUnlocked();
     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
-    REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
+    REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceCount());
     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));)
 }
 
@@ -220,9 +187,9 @@ static void test_duplicate_content_key(skiatest::Reporter* reporter) {
         return;
     }
     context->setResourceCacheLimits(5, 30000);
-    GrResourceCache2* cache2 = context->getResourceCache2();
-    cache2->purgeAllUnlocked();
-    SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+    GrResourceCache* cache = context->getResourceCache();
+    cache->purgeAllUnlocked();
+    SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
     GrCacheID::Domain domain = GrCacheID::GenerateDomain();
     GrCacheID::Key keyData;
@@ -230,42 +197,30 @@ static void test_duplicate_content_key(skiatest::Reporter* reporter) {
     GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
     GrResourceKey key(GrCacheID(domain, keyData), t, 0);
     
+
     // Create two resources that we will attempt to register with the same content key.
     TestResource* a = new TestResource(context->getGpu());
     TestResource* b = new TestResource(context->getGpu());
     a->setSize(11);
     b->setSize(12);
-    
-    // Can't set the same content key on two resources.
-    REPORTER_ASSERT(reporter, a->cacheAccess().setContentKey(key));
-    REPORTER_ASSERT(reporter, !b->cacheAccess().setContentKey(key));
-
-    // Still have two resources because b is still reffed.
-    REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
-                              cache2->getResourceBytes());
+    REPORTER_ASSERT(reporter, cache->addResource(key, a));
+    // Can't add the same or another resource with the same key.
+    REPORTER_ASSERT(reporter, !cache->addResource(key, a));
+    REPORTER_ASSERT(reporter, !cache->addResource(key, b));
+    REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
+    REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getCachedResourceBytes());
     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
 
     b->unref();
-    // Now b should be gone.
-    REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache2->getResourceBytes());
-    REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
-
-    cache2->purgeAllUnlocked();
-    REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache2->getResourceBytes());
+    cache->purgeAllUnlocked();
+    a->setSize(10);
+    REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
 
-    // Drop the ref on a but it isn't immediately purged as it still has a valid scratch key.
     a->unref();
-    REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache2->getResourceBytes());
-    REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
-
-    cache2->purgeAllUnlocked();
-    REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
+    cache->purgeAllUnlocked();
+    REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceCount());
+    REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceBytes());
     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
 }
 
@@ -290,17 +245,18 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
     GrResourceKey key3(GrCacheID(domain, keyData), t, 0);
     
     context->setResourceCacheLimits(5, 30000);
+    GrResourceCache* cache = context->getResourceCache();
     GrResourceCache2* cache2 = context->getResourceCache2();
-    cache2->purgeAllUnlocked();
-    SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+    cache->purgeAllUnlocked();
+    SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
     // Add three resources to the cache.
     TestResource* a = new TestResource(context->getGpu());
     TestResource* b = new TestResource(context->getGpu());
     TestResource* c = new TestResource(context->getGpu());
-    a->cacheAccess().setContentKey(key1);
-    b->cacheAccess().setContentKey(key2);
-    c->cacheAccess().setContentKey(key3);
+    cache->addResource(key1, a);
+    cache->addResource(key2, b);
+    cache->addResource(key3, c);
     a->unref();
     b->unref();
     c->unref();
@@ -315,8 +271,8 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
     SkMessageBus<GrResourceInvalidatedMessage>::Post(msg1);
     const GrResourceInvalidatedMessage msg2 = { key2 };
     SkMessageBus<GrResourceInvalidatedMessage>::Post(msg2);
+    cache->purgeAsNeeded();
 #if 0 // Disabled until reimplemented in GrResourceCache2.
-    cache2->purgeAsNeeded();
     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
     REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
     REPORTER_ASSERT(reporter, !cache2->hasContentKey(key2));
@@ -326,19 +282,14 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
     // Invalidate the third.
     const GrResourceInvalidatedMessage msg3 = { key3 };
     SkMessageBus<GrResourceInvalidatedMessage>::Post(msg3);
+    cache->purgeAsNeeded();
 #if 0 // Disabled until reimplemented in GrResourceCache2.
-    cache2->purgeAsNeeded();
     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
     REPORTER_ASSERT(reporter, !cache2->hasContentKey(key3));
 #endif
-
-    cache2->purgeAllUnlocked();
-    REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
-    REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
-    REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
 }
 
-static void test_cache_chained_purge(skiatest::Reporter* reporter) {
+static void test_cache_delete_on_destruction(skiatest::Reporter* reporter) {
     SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
     REPORTER_ASSERT(reporter, SkToBool(context));
     if (NULL == context) {
@@ -358,34 +309,44 @@ static void test_cache_chained_purge(skiatest::Reporter* reporter) {
 
     {
         context->setResourceCacheLimits(3, 30000);
-        GrResourceCache2* cache2 = context->getResourceCache2();
-        cache2->purgeAllUnlocked();
-        SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+        GrResourceCache* cache = context->getResourceCache();
+        cache->purgeAllUnlocked();
+        SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
         TestResource* a = new TestResource(context->getGpu());
         TestResource* b = new TestResource(context->getGpu());
-        a->cacheAccess().setContentKey(key1);
-        b->cacheAccess().setContentKey(key2);
-
-        // Make a cycle
-        a->setUnrefWhenDestroyed(b);
-        b->setUnrefWhenDestroyed(a);
+        cache->addResource(key1, a);
+        cache->addResource(key2, b);
 
-        REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
+        a->setDeleteWhenDestroyed(cache, b);
+        b->setDeleteWhenDestroyed(cache, a);
 
         a->unref();
         b->unref();
 
         REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
 
-        cache2->purgeAllUnlocked();
-        REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
+        cache->purgeAllUnlocked();
+        REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
+    }
+    {
+        context->setResourceCacheLimits(3, 30000);
+        GrResourceCache* cache = context->getResourceCache();
+        cache->purgeAllUnlocked();
+        SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
-        // Break the cycle
-        a->setUnrefWhenDestroyed(NULL);
-        REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
+        TestResource* a = new TestResource(context->getGpu());
+        TestResource* b = new TestResource(context->getGpu());
+        cache->addResource(key1, a);
+        cache->addResource(key2, b);
+
+        a->setDeleteWhenDestroyed(cache, b);
+        b->setDeleteWhenDestroyed(cache, a);
 
-        cache2->purgeAllUnlocked();
+        a->unref();
+        b->unref();
+
+        cache->deleteResource(a->cacheAccess().getCacheEntry());
         REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
     }
 }
@@ -413,20 +374,23 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
     // Test changing resources sizes (both increase & decrease).
     {
         context->setResourceCacheLimits(3, 30000);
+        GrResourceCache* cache = context->getResourceCache();
         GrResourceCache2* cache2 = context->getResourceCache2();
-        cache2->purgeAllUnlocked();
-        SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+        cache->purgeAllUnlocked();
+        SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
         TestResource* a = new TestResource(context->getGpu());
-        a->cacheAccess().setContentKey(key1);
+        a->setSize(100); // Test didChangeGpuMemorySize() when not in the cache.
+        cache->addResource(key1, a);
         a->unref();
 
         TestResource* b = new TestResource(context->getGpu());
-        b->cacheAccess().setContentKey(key2);
+        b->setSize(100);
+        cache->addResource(key2, b);
         b->unref();
 
-        REPORTER_ASSERT(reporter, 200 == cache2->getResourceBytes());
-        REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+        REPORTER_ASSERT(reporter, 200 == cache->getCachedResourceBytes());
+        REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
         {
             SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
             find2->setSize(200);
@@ -434,29 +398,30 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
             find1->setSize(50);
         }
 
-        REPORTER_ASSERT(reporter, 250 == cache2->getResourceBytes());
-        REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+        REPORTER_ASSERT(reporter, 250 == cache->getCachedResourceBytes());
+        REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
     }
 
     // Test increasing a resources size beyond the cache budget.
     {
         context->setResourceCacheLimits(2, 300);
+        GrResourceCache* cache = context->getResourceCache();
         GrResourceCache2* cache2 = context->getResourceCache2();
-        cache2->purgeAllUnlocked();
-        SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
+        cache->purgeAllUnlocked();
+        SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
 
         TestResource* a = new TestResource(context->getGpu());
         a->setSize(100);
-        a->cacheAccess().setContentKey(key1);
+        cache->addResource(key1, a);
         a->unref();
 
         TestResource* b = new TestResource(context->getGpu());
         b->setSize(100);
-        b->cacheAccess().setContentKey(key2);
+        cache->addResource(key2, b);
         b->unref();
 
-        REPORTER_ASSERT(reporter, 200 == cache2->getResourceBytes());
-        REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
+        REPORTER_ASSERT(reporter, 200 == cache->getCachedResourceBytes());
+        REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
 
         {
             SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
@@ -464,8 +429,8 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
         }
         REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
 
-        REPORTER_ASSERT(reporter, 201 == cache2->getResourceBytes());
-        REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
+        REPORTER_ASSERT(reporter, 201 == cache->getCachedResourceBytes());
+        REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
     }
 }
 
@@ -491,11 +456,10 @@ DEF_GPUTEST(ResourceCache, reporter, factory) {
     }
 
     // The below tests create their own mock contexts.
-    test_no_key(reporter);
     test_duplicate_content_key(reporter);
     test_duplicate_scratch_key(reporter);
     test_purge_invalidated(reporter);
-    test_cache_chained_purge(reporter);
+    test_cache_delete_on_destruction(reporter);
     test_resource_size_changed(reporter);
 }
 
index 1913fcb1467cb6d53e7f73d16f55fe3688927a91..69c8b845ece6227761d900a1944b9d08f3a8aee0 100644 (file)
@@ -321,6 +321,33 @@ static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter
 }
 
 #if SK_SUPPORT_GPU
+static void TestSurfaceInCache(skiatest::Reporter* reporter,
+                               SurfaceType surfaceType,
+                               GrContext* context) {
+    context->freeGpuResources();
+    int resourceCount;
+
+    context->getResourceCacheUsage(&resourceCount, NULL);
+    REPORTER_ASSERT(reporter, 0 == resourceCount);
+    SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
+    // Note: the stencil buffer is always cached, so kGpu_SurfaceType uses
+    // one cached resource, and kGpuScratch_SurfaceType uses two.
+    int expectedCachedResources = surfaceType == kGpuScratch_SurfaceType ? 2 : 1;
+    context->getResourceCacheUsage(&resourceCount, NULL);
+    REPORTER_ASSERT(reporter, expectedCachedResources == resourceCount);
+
+    // Verify that all the cached resources are locked in cache.
+    context->freeGpuResources();
+    context->getResourceCacheUsage(&resourceCount, NULL);
+    REPORTER_ASSERT(reporter, expectedCachedResources == resourceCount);
+
+    // Verify that all the cached resources are unlocked upon surface release
+    surface.reset(0);
+    context->freeGpuResources();
+    context->getResourceCacheUsage(&resourceCount, NULL);
+    REPORTER_ASSERT(reporter, 0 == resourceCount);
+}
+
 static void Test_crbug263329(skiatest::Reporter* reporter,
                              SurfaceType surfaceType,
                              GrContext* context) {
@@ -426,6 +453,8 @@ DEF_GPUTEST(Surface, reporter, factory) {
             }
             GrContext* context = factory->get(glCtxType);
             if (context) {
+                TestSurfaceInCache(reporter, kGpu_SurfaceType, context);
+                TestSurfaceInCache(reporter, kGpuScratch_SurfaceType, context);
                 Test_crbug263329(reporter, kGpu_SurfaceType, context);
                 Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
                 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);