aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/GrResourceCacheBench.cpp79
-rw-r--r--include/gpu/GrContext.h2
-rw-r--r--include/gpu/GrGpuResource.h2
-rw-r--r--src/core/SkTMultiMap.h13
-rwxr-xr-xsrc/gpu/GrContext.cpp25
-rw-r--r--src/gpu/GrGpu.cpp9
-rw-r--r--src/gpu/GrGpuResource.cpp23
-rw-r--r--src/gpu/GrResourceCache.cpp32
-rw-r--r--src/gpu/GrResourceCache.h17
-rw-r--r--src/gpu/GrResourceCache2.cpp29
-rw-r--r--src/gpu/GrResourceCache2.h40
-rw-r--r--src/gpu/GrTexture.cpp5
-rw-r--r--tests/ResourceCacheTest.cpp254
13 files changed, 397 insertions, 133 deletions
diff --git a/bench/GrResourceCacheBench.cpp b/bench/GrResourceCacheBench.cpp
index 30d4cd410c..91c77fb589 100644
--- a/bench/GrResourceCacheBench.cpp
+++ b/bench/GrResourceCacheBench.cpp
@@ -6,13 +6,15 @@
* found in the LICENSE file.
*/
+#include "Benchmark.h"
+
#if SK_SUPPORT_GPU
-#include "Benchmark.h"
#include "GrGpuResource.h"
#include "GrContext.h"
#include "GrGpu.h"
#include "GrResourceCache.h"
+#include "GrResourceCache2.h"
#include "GrStencilBuffer.h"
#include "GrTexture.h"
#include "GrTexturePriv.h"
@@ -117,18 +119,18 @@ static void populate_cache(GrResourceCache* cache, GrGpu* gpu, int resourceCount
}
}
-static void check_cache_contents_or_die(GrResourceCache* cache, int k) {
+static void check_cache_contents_or_die(GrResourceCache2* cache, int k) {
// Benchmark find calls that succeed.
{
GrSurfaceDesc desc;
get_texture_desc(k, &desc);
GrResourceKey key = TextureResource::ComputeKey(desc);
- GrGpuResource* item = cache->find(key);
- if (NULL == item) {
+ SkAutoTUnref<GrGpuResource> item(cache->findAndRefContentResource(key));
+ if (!item) {
SkFAIL("cache add does not work as expected");
return;
}
- if (static_cast<TextureResource*>(item)->fID != k) {
+ if (static_cast<TextureResource*>(item.get())->fID != k) {
SkFAIL("cache add does not work as expected");
return;
}
@@ -137,12 +139,12 @@ static void check_cache_contents_or_die(GrResourceCache* cache, int k) {
int w, h, s;
get_stencil(k, &w, &h, &s);
GrResourceKey key = StencilResource::ComputeKey(w, h, s);
- GrGpuResource* item = cache->find(key);
- if (NULL == item) {
+ SkAutoTUnref<GrGpuResource> item(cache->findAndRefContentResource(key));
+ if (!item) {
SkFAIL("cache add does not work as expected");
return;
}
- if (static_cast<TextureResource*>(item)->fID != k) {
+ if (static_cast<TextureResource*>(item.get())->fID != k) {
SkFAIL("cache add does not work as expected");
return;
}
@@ -154,7 +156,7 @@ static void check_cache_contents_or_die(GrResourceCache* cache, int k) {
get_texture_desc(k, &desc);
desc.fHeight |= 1;
GrResourceKey key = TextureResource::ComputeKey(desc);
- GrGpuResource* item = cache->find(key);
+ SkAutoTUnref<GrGpuResource> item(cache->findAndRefContentResource(key));
if (item) {
SkFAIL("cache add does not work as expected");
return;
@@ -165,7 +167,7 @@ static void check_cache_contents_or_die(GrResourceCache* cache, int k) {
get_stencil(k, &w, &h, &s);
h |= 1;
GrResourceKey key = StencilResource::ComputeKey(w, h, s);
- GrGpuResource* item = cache->find(key);
+ SkAutoTUnref<GrGpuResource> item(cache->findAndRefContentResource(key));
if (item) {
SkFAIL("cache add does not work as expected");
return;
@@ -176,12 +178,11 @@ static void check_cache_contents_or_die(GrResourceCache* cache, int k) {
class GrResourceCacheBenchAdd : public Benchmark {
enum {
RESOURCE_COUNT = CACHE_SIZE_COUNT / 2,
- DUPLICATE_COUNT = CACHE_SIZE_COUNT / 4,
};
public:
virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
- return backend == kGPU_Backend;
+ return backend == kNonRendering_Backend;
}
protected:
@@ -190,18 +191,32 @@ protected:
}
virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
- GrGpu* gpu = canvas->getGrContext()->getGpu();
+ SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
+ if (NULL == context) {
+ return;
+ }
+ // 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.
+ cache->purgeAllUnlocked();
+ SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
+
+ GrGpu* gpu = context->getGpu();
for (int i = 0; i < loops; ++i) {
- GrResourceCache cache(gpu->caps(), CACHE_SIZE_COUNT, CACHE_SIZE_BYTES);
- populate_cache(&cache, gpu, DUPLICATE_COUNT);
- populate_cache(&cache, gpu, RESOURCE_COUNT);
+ SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
+
+ populate_cache(cache, gpu, RESOURCE_COUNT);
// Check that cache works.
for (int k = 0; k < RESOURCE_COUNT; k += 33) {
- check_cache_contents_or_die(&cache, k);
+ check_cache_contents_or_die(cache2, k);
}
- cache.purgeAllUnlocked();
+ cache->purgeAllUnlocked();
}
}
@@ -211,13 +226,12 @@ private:
class GrResourceCacheBenchFind : public Benchmark {
enum {
- RESOURCE_COUNT = (CACHE_SIZE_COUNT / 2) - 100,
- DUPLICATE_COUNT = 100
+ RESOURCE_COUNT = CACHE_SIZE_COUNT / 2,
};
public:
virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
- return backend == kGPU_Backend;
+ return backend == kNonRendering_Backend;
}
protected:
@@ -226,14 +240,27 @@ protected:
}
virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
- GrGpu* gpu = canvas->getGrContext()->getGpu();
- GrResourceCache cache(gpu->caps(), CACHE_SIZE_COUNT, CACHE_SIZE_BYTES);
- populate_cache(&cache, gpu, DUPLICATE_COUNT);
- populate_cache(&cache, gpu, RESOURCE_COUNT);
+ SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
+ if (NULL == context) {
+ return;
+ }
+ // 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.
+ cache->purgeAllUnlocked();
+ SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
+
+ GrGpu* gpu = context->getGpu();
+
+ populate_cache(cache, gpu, RESOURCE_COUNT);
for (int i = 0; i < loops; ++i) {
for (int k = 0; k < RESOURCE_COUNT; ++k) {
- check_cache_contents_or_die(&cache, k);
+ check_cache_contents_or_die(cache2, k);
}
}
}
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 2adc84211a..97acda1e79 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -897,7 +897,7 @@ public:
* called to check the cache for a SB that matches an RT's criteria.
*/
void addStencilBuffer(GrStencilBuffer* sb);
- GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt);
+ GrStencilBuffer* findAndRefStencilBuffer(int width, int height, int sampleCnt);
GrPathRenderer* getPathRenderer(
const SkPath& path,
diff --git a/include/gpu/GrGpuResource.h b/include/gpu/GrGpuResource.h
index 4ffe17e739..d3341d9bea 100644
--- a/include/gpu/GrGpuResource.h
+++ b/include/gpu/GrGpuResource.h
@@ -172,7 +172,7 @@ public:
*/
virtual size_t gpuMemorySize() const = 0;
- void setCacheEntry(GrResourceCacheEntry* cacheEntry) { fCacheEntry = cacheEntry; }
+ bool setCacheEntry(GrResourceCacheEntry* cacheEntry);
GrResourceCacheEntry* getCacheEntry() const { return fCacheEntry; }
bool isScratch() const;
diff --git a/src/core/SkTMultiMap.h b/src/core/SkTMultiMap.h
index 70076f0cad..1168ed6e91 100644
--- a/src/core/SkTMultiMap.h
+++ b/src/core/SkTMultiMap.h
@@ -102,6 +102,19 @@ public:
int count() const { return fCount; }
+#ifdef SK_DEBUG
+ // This is not particularly fast and only used for validation, so debug only.
+ int countForKey(const Key& key) const {
+ int count = 0;
+ ValueList* list = fHash.find(key);
+ while (list) {
+ list = list->fNext;
+ ++count;
+ }
+ return count;
+ }
+#endif
+
private:
SkTDynamicHash<ValueList, Key> fHash;
int fCount;
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 83ef58f3de..6f9395b5c3 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -255,20 +255,20 @@ GrTexture* GrContext::findAndRefTexture(const GrSurfaceDesc& desc,
const GrCacheID& cacheID,
const GrTextureParams* params) {
GrResourceKey resourceKey = GrTexturePriv::ComputeKey(fGpu, params, desc, cacheID);
- GrGpuResource* resource = fResourceCache->find(resourceKey);
+
+ GrGpuResource* resource = this->findAndRefCachedResource(resourceKey);
if (resource) {
- resource->ref();
+ SkASSERT(static_cast<GrSurface*>(resource)->asTexture());
return static_cast<GrSurface*>(resource)->asTexture();
- } else {
- return NULL;
}
+ return NULL;
}
bool GrContext::isTextureInCache(const GrSurfaceDesc& desc,
const GrCacheID& cacheID,
const GrTextureParams* params) const {
GrResourceKey resourceKey = GrTexturePriv::ComputeKey(fGpu, params, desc, cacheID);
- return fResourceCache->hasKey(resourceKey);
+ return fResourceCache2->hasContentKey(resourceKey);
}
void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
@@ -280,12 +280,9 @@ void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
fResourceCache->addResource(resourceKey, sb);
}
-GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
- int sampleCnt) {
- GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width,
- height,
- sampleCnt);
- GrGpuResource* resource = fResourceCache->find(resourceKey);
+GrStencilBuffer* GrContext::findAndRefStencilBuffer(int width, int height, int sampleCnt) {
+ GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width, height, sampleCnt);
+ GrGpuResource* resource = this->findAndRefCachedResource(resourceKey);
return static_cast<GrStencilBuffer*>(resource);
}
@@ -1755,8 +1752,10 @@ void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResour
}
GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resourceKey) {
- GrGpuResource* resource = fResourceCache->find(resourceKey);
- SkSafeRef(resource);
+ GrGpuResource* resource = fResourceCache2->findAndRefContentResource(resourceKey);
+ if (resource) {
+ fResourceCache->makeResourceMRU(resource);
+ }
return resource;
}
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 64ee29bde5..ab24c5447f 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -84,10 +84,8 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& desc,
bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
SkASSERT(NULL == rt->getStencilBuffer());
- GrStencilBuffer* sb =
- this->getContext()->findStencilBuffer(rt->width(),
- rt->height(),
- rt->numSamples());
+ SkAutoTUnref<GrStencilBuffer> sb(
+ this->getContext()->findAndRefStencilBuffer(rt->width(), rt->height(), rt->numSamples()));
if (sb) {
rt->setStencilBuffer(sb);
bool attached = this->attachStencilBufferToRenderTarget(sb, rt);
@@ -96,8 +94,7 @@ bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
}
return attached;
}
- if (this->createStencilBufferForRenderTarget(rt,
- rt->width(), rt->height())) {
+ if (this->createStencilBufferForRenderTarget(rt, rt->width(), rt->height())) {
// Right now we're clearing the stencil buffer here after it is
// attached to an RT for the first time. When we start matching
// stencil buffers with smaller color targets this will no longer
diff --git a/src/gpu/GrGpuResource.cpp b/src/gpu/GrGpuResource.cpp
index 705cdea424..b77acffc68 100644
--- a/src/gpu/GrGpuResource.cpp
+++ b/src/gpu/GrGpuResource.cpp
@@ -78,6 +78,24 @@ GrContext* GrGpuResource::getContext() {
}
}
+bool GrGpuResource::setCacheEntry(GrResourceCacheEntry* cacheEntry) {
+ // GrResourceCache never changes the cacheEntry once one has been added.
+ SkASSERT(NULL == cacheEntry || NULL == fCacheEntry);
+
+ fCacheEntry = cacheEntry;
+ if (this->wasDestroyed() || NULL == cacheEntry) {
+ return true;
+ }
+
+ if (!cacheEntry->key().isScratch()) {
+ if (!get_resource_cache2(fGpu)->didAddContentKey(this)) {
+ fCacheEntry = NULL;
+ return false;
+ }
+ }
+ return true;
+}
+
void GrGpuResource::notifyIsPurgable() const {
if (fCacheEntry && !this->wasDestroyed()) {
get_resource_cache(fGpu)->notifyPurgable(this);
@@ -92,6 +110,7 @@ void GrGpuResource::setScratchKey(const GrResourceKey& scratchKey) {
}
const GrResourceKey* GrGpuResource::getContentKey() const {
+ // Currently scratch resources have a cache entry in GrResourceCache with a scratch key.
if (fCacheEntry && !fCacheEntry->key().isScratch()) {
return &fCacheEntry->key();
}
@@ -99,8 +118,8 @@ const GrResourceKey* GrGpuResource::getContentKey() const {
}
bool GrGpuResource::isScratch() const {
- // Currently scratch resources have a cache entry in GrResourceCache with a scratch key.
- return NULL != fCacheEntry && fCacheEntry->key().isScratch();
+ SkASSERT(fScratchKey.isScratch());
+ return NULL == this->getContentKey() && !fScratchKey.isNullScratch();
}
uint32_t GrGpuResource::CreateUniqueID() {
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
index 9754d4467a..8eed4d4b7d 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -49,7 +49,8 @@ GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache,
}
GrResourceCacheEntry::~GrResourceCacheEntry() {
- fResource->setCacheEntry(NULL);
+ // We're relying on having the cache entry to remove this from GrResourceCache2's content hash.
+ // fResource->setCacheEntry(NULL);
fResource->unref();
}
@@ -185,26 +186,11 @@ void GrResourceCache::notifyPurgable(const GrGpuResource* resource) {
}
}
-GrGpuResource* GrResourceCache::find(const GrResourceKey& key) {
- // GrResourceCache2 is responsible for scratch resources.
- SkASSERT(!key.isScratch());
-
- GrAutoResourceCacheValidate atcv(this);
-
- GrResourceCacheEntry* entry = fCache.find(key);
- if (NULL == entry) {
- return NULL;
+bool GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resource) {
+ if (NULL != resource->getCacheEntry()) {
+ return false;
}
- // Make this resource MRU
- this->internalDetach(entry);
- this->attachToHead(entry);
-
- return entry->fResource;
-}
-
-void GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resource) {
- SkASSERT(NULL == resource->getCacheEntry());
// we don't expect to create new resources during a purge. In theory
// this could cause purgeAsNeeded() into an infinite loop (e.g.
// each resource destroyed creates and locks 2 resources and
@@ -213,12 +199,16 @@ void GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resou
GrAutoResourceCacheValidate atcv(this);
GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, resource));
- resource->setCacheEntry(entry);
+ if (!resource->setCacheEntry(entry)) {
+ SkDELETE(entry);
+ this->purgeAsNeeded();
+ return false;
+ }
this->attachToHead(entry);
fCache.insert(key, entry);
-
this->purgeAsNeeded();
+ return true;
}
void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountInc) {
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
index f6d064af39..874f16ac63 100644
--- a/src/gpu/GrResourceCache.h
+++ b/src/gpu/GrResourceCache.h
@@ -140,12 +140,6 @@ public:
*/
int getCachedResourceCount() const { return fEntryCount; }
- /**
- * Search for an entry with the same Key. If found, return it.
- * If not found, return null.
- */
- GrGpuResource* find(const GrResourceKey& key);
-
void makeResourceMRU(GrGpuResource*);
/** Called by GrGpuResources when they detects that they are newly purgable. */
@@ -157,14 +151,11 @@ public:
*
* 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.
*/
- void addResource(const GrResourceKey& key, GrGpuResource* resource);
-
- /**
- * 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 { return SkToBool(fCache.find(key)); }
+ bool addResource(const GrResourceKey& key, GrGpuResource* resource);
/**
* Notify the cache that the size of a resource has changed.
diff --git a/src/gpu/GrResourceCache2.cpp b/src/gpu/GrResourceCache2.cpp
index 6bc23a3096..65e522aafb 100644
--- a/src/gpu/GrResourceCache2.cpp
+++ b/src/gpu/GrResourceCache2.cpp
@@ -9,7 +9,6 @@
#include "GrResourceCache2.h"
#include "GrGpuResource.h"
-#include "SkRefCnt.h"
GrResourceCache2::~GrResourceCache2() {
this->releaseAll();
@@ -22,6 +21,8 @@ void GrResourceCache2::insertResource(GrGpuResource* resource) {
fResources.addToHead(resource);
++fCount;
if (!resource->getScratchKey().isNullScratch()) {
+ // TODO(bsalomon): Make this assertion possible.
+ // SkASSERT(!resource->isWrapped());
fScratchMap.insert(resource->getScratchKey(), resource);
}
}
@@ -32,6 +33,9 @@ void GrResourceCache2::removeResource(GrGpuResource* resource) {
if (!resource->getScratchKey().isNullScratch()) {
fScratchMap.remove(resource->getScratchKey(), resource);
}
+ if (const GrResourceKey* contentKey = resource->getContentKey()) {
+ fContentHash.remove(*contentKey);
+ }
--fCount;
}
@@ -43,6 +47,7 @@ void GrResourceCache2::abandonAll() {
SkASSERT(head != fResources.head());
}
SkASSERT(!fScratchMap.count());
+ SkASSERT(!fContentHash.count());
SkASSERT(!fCount);
}
@@ -89,3 +94,25 @@ GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey&
}
return SkSafeRef(fScratchMap.find(scratchKey, AvailableForScratchUse(false)));
}
+
+void GrResourceCache2::willRemoveContentKey(const GrGpuResource* resource) {
+ SkASSERT(resource);
+ SkASSERT(resource->getContentKey());
+ SkDEBUGCODE(GrGpuResource* res = fContentHash.find(*resource->getContentKey()));
+ SkASSERT(res == resource);
+
+ fContentHash.remove(*resource->getContentKey());
+}
+
+bool GrResourceCache2::didAddContentKey(GrGpuResource* resource) {
+ SkASSERT(resource);
+ SkASSERT(resource->getContentKey());
+
+ GrGpuResource* res = fContentHash.find(*resource->getContentKey());
+ if (NULL != res) {
+ return false;
+ }
+
+ fContentHash.add(resource);
+ return true;
+}
diff --git a/src/gpu/GrResourceCache2.h b/src/gpu/GrResourceCache2.h
index a365a5aec7..9424c40850 100644
--- a/src/gpu/GrResourceCache2.h
+++ b/src/gpu/GrResourceCache2.h
@@ -11,6 +11,7 @@
#include "GrGpuResource.h"
#include "GrResourceKey.h"
+#include "SkRefCnt.h"
#include "SkTInternalLList.h"
#include "SkTMultiMap.h"
@@ -28,6 +29,14 @@ public:
void removeResource(GrGpuResource*);
+ void willRemoveContentKey(const GrGpuResource*);
+
+ // 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 didAddContentKey(GrGpuResource*);
+
void abandonAll();
void releaseAll();
@@ -39,6 +48,24 @@ public:
kRequireNoPendingIO_ScratchFlag = 0x2,
};
GrGpuResource* findAndRefScratchResource(const GrResourceKey& scratchKey, uint32_t flags = 0);
+
+#ifdef SK_DEBUG
+ // This is not particularly fast and only used for validation, so debug only.
+ int countScratchEntriesForKey(const GrResourceKey& scratchKey) const {
+ SkASSERT(scratchKey.isScratch());
+ return fScratchMap.countForKey(scratchKey);
+ }
+#endif
+
+ GrGpuResource* findAndRefContentResource(const GrResourceKey& contentKey) {
+ SkASSERT(!contentKey.isScratch());
+ return SkSafeRef(fContentHash.find(contentKey));
+ }
+
+ bool hasContentKey(const GrResourceKey& contentKey) const {
+ SkASSERT(!contentKey.isScratch());
+ return SkToBool(fContentHash.find(contentKey));
+ }
private:
#ifdef SK_DEBUG
@@ -56,10 +83,21 @@ private:
};
typedef SkTMultiMap<GrGpuResource, GrResourceKey, ScratchMapTraits> ScratchMap;
+ struct ContentHashTraits {
+ static const GrResourceKey& GetKey(const GrGpuResource& r) {
+ return *r.getContentKey();
+ }
+
+ static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
+ };
+ typedef SkTDynamicHash<GrGpuResource, GrResourceKey, ContentHashTraits> ContentHash;
+
int fCount;
SkTInternalLList<GrGpuResource> fResources;
// This map holds all resources that can be used as scratch resources.
- ScratchMap fScratchMap;
+ ScratchMap fScratchMap;
+ // This holds all resources that have content keys.
+ ContentHash fContentHash;
};
#endif
diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp
index 21395409d6..72e82252dc 100644
--- a/src/gpu/GrTexture.cpp
+++ b/src/gpu/GrTexture.cpp
@@ -121,7 +121,10 @@ GrSurfaceOrigin resolve_origin(const GrSurfaceDesc& desc) {
GrTexture::GrTexture(GrGpu* gpu, bool isWrapped, const GrSurfaceDesc& desc)
: INHERITED(gpu, isWrapped, desc)
, fMipMapsStatus(kNotAllocated_MipMapsStatus) {
- this->setScratchKey(GrTexturePriv::ComputeScratchKey(desc));
+
+ if (!isWrapped) {
+ this->setScratchKey(GrTexturePriv::ComputeScratchKey(desc));
+ }
// only make sense if alloc size is pow2
fShiftFixedX = 31 - SkCLZ(fDesc.fWidth);
fShiftFixedY = 31 - SkCLZ(fDesc.fHeight);
diff --git a/tests/ResourceCacheTest.cpp b/tests/ResourceCacheTest.cpp
index 2827cbfd6d..24ecb949ca 100644
--- a/tests/ResourceCacheTest.cpp
+++ b/tests/ResourceCacheTest.cpp
@@ -65,11 +65,21 @@ class TestResource : public GrGpuResource {
public:
SK_DECLARE_INST_COUNT(TestResource);
- TestResource(GrGpu* gpu, size_t size = kDefaultSize)
+ TestResource(GrGpu* gpu)
: INHERITED(gpu, false)
, fCache(NULL)
, fToDelete(NULL)
- , fSize(size) {
+ , fSize(kDefaultSize) {
+ ++fNumAlive;
+ this->registerWithCache();
+ }
+
+ TestResource(GrGpu* gpu, const GrResourceKey& scratchKey)
+ : INHERITED(gpu, false)
+ , fCache(NULL)
+ , fToDelete(NULL)
+ , fSize(kDefaultSize) {
+ this->setScratchKey(scratchKey);
++fNumAlive;
this->registerWithCache();
}
@@ -108,52 +118,189 @@ private:
};
int TestResource::fNumAlive = 0;
-static void test_purge_invalidated(skiatest::Reporter* reporter, GrContext* context) {
+static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
+ SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
+ REPORTER_ASSERT(reporter, SkToBool(context));
+ if (NULL == context) {
+ return;
+ }
+ context->setResourceCacheLimits(5, 30000);
+ GrResourceCache* cache = context->getResourceCache();
+ SkDEBUGCODE(GrResourceCache2* cache2 = context->getResourceCache2();)
+ cache->purgeAllUnlocked();
+ SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
+
+ GrCacheID::Key keyData;
+ GrCacheID::Domain domain = GrResourceKey::ScratchDomain();
+ GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
+ GrResourceKey scratchKey(GrCacheID(domain, keyData), t, 0);
+
+ // Create two resources that have the same scratch key.
+ TestResource* a = new TestResource(context->getGpu(), scratchKey);
+ TestResource* b = new TestResource(context->getGpu(), scratchKey);
+ a->setSize(11);
+ b->setSize(12);
+ // Scratch resources are registered with GrResourceCache2 just by existing. There are 2.
+ SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
+
+ 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() ==
+ 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.
+ cache->purgeAllUnlocked();
+ REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
+ REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
+
+ // Unref but don't purge
+ a->unref();
+ b->unref();
+ REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
+ SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
+
+ // Purge again. This time resources should be purgable.
+ cache->purgeAllUnlocked();
+ REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
+ REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceCount());
+ SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));)
+}
+
+static void test_duplicate_content_key(skiatest::Reporter* reporter) {
+ SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
+ REPORTER_ASSERT(reporter, SkToBool(context));
+ if (NULL == context) {
+ return;
+ }
+ context->setResourceCacheLimits(5, 30000);
+ GrResourceCache* cache = context->getResourceCache();
+ cache->purgeAllUnlocked();
+ SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
+
GrCacheID::Domain domain = GrCacheID::GenerateDomain();
GrCacheID::Key keyData;
- keyData.fData64[0] = 5;
- keyData.fData64[1] = 18;
+ memset(&keyData, 0, sizeof(keyData));
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);
+ 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();
+ cache->purgeAllUnlocked();
+ a->setSize(10);
+ REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
+ REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
+
+ a->unref();
+ cache->purgeAllUnlocked();
+ REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceCount());
+ REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceBytes());
+ REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
+}
+
+static void test_purge_invalidated(skiatest::Reporter* reporter) {
+ SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
+ REPORTER_ASSERT(reporter, SkToBool(context));
+ if (NULL == context) {
+ return;
+ }
+
+ GrCacheID::Domain domain = GrCacheID::GenerateDomain();
+ GrCacheID::Key keyData;
+ memset(&keyData, 0, sizeof(keyData));
+
+ GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
+
+ keyData.fData64[0] = 1;
+ GrResourceKey key1(GrCacheID(domain, keyData), t, 0);
+ keyData.fData64[0] = 2;
+ GrResourceKey key2(GrCacheID(domain, keyData), t, 0);
+ keyData.fData64[0] = 3;
+ GrResourceKey key3(GrCacheID(domain, keyData), t, 0);
+
context->setResourceCacheLimits(5, 30000);
GrResourceCache* cache = context->getResourceCache();
+ GrResourceCache2* cache2 = context->getResourceCache2();
cache->purgeAllUnlocked();
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
- // Add two resources with the same key that delete each other from the cache when destroyed.
+ // Add three resources to the cache.
TestResource* a = new TestResource(context->getGpu());
TestResource* b = new TestResource(context->getGpu());
- cache->addResource(key, a);
- cache->addResource(key, b);
- // Circle back.
- a->setDeleteWhenDestroyed(cache, b);
- b->setDeleteWhenDestroyed(cache, a);
+ TestResource* c = new TestResource(context->getGpu());
+ cache->addResource(key1, a);
+ cache->addResource(key2, b);
+ cache->addResource(key3, c);
a->unref();
b->unref();
+ c->unref();
- // Add a third independent resource also with the same key.
- GrGpuResource* r = new TestResource(context->getGpu());
- cache->addResource(key, r);
- r->unref();
+ REPORTER_ASSERT(reporter, cache2->hasContentKey(key1));
+ REPORTER_ASSERT(reporter, cache2->hasContentKey(key2));
+ REPORTER_ASSERT(reporter, cache2->hasContentKey(key3));
- // Invalidate all three, all three should be purged and destroyed.
+ // Invalidate two of the three, they should be purged and destroyed.
REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
- const GrResourceInvalidatedMessage msg = { key };
- SkMessageBus<GrResourceInvalidatedMessage>::Post(msg);
+ const GrResourceInvalidatedMessage msg1 = { key1 };
+ SkMessageBus<GrResourceInvalidatedMessage>::Post(msg1);
+ const GrResourceInvalidatedMessage msg2 = { key2 };
+ SkMessageBus<GrResourceInvalidatedMessage>::Post(msg2);
+ cache->purgeAsNeeded();
+ REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
+ REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
+ REPORTER_ASSERT(reporter, !cache2->hasContentKey(key2));
+ REPORTER_ASSERT(reporter, cache2->hasContentKey(key3));
+
+ // Invalidate the third.
+ const GrResourceInvalidatedMessage msg3 = { key3 };
+ SkMessageBus<GrResourceInvalidatedMessage>::Post(msg3);
cache->purgeAsNeeded();
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
+ REPORTER_ASSERT(reporter, !cache2->hasContentKey(key3));
}
-static void test_cache_delete_on_destruction(skiatest::Reporter* reporter,
- GrContext* context) {
+static void test_cache_delete_on_destruction(skiatest::Reporter* reporter) {
+ SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
+ REPORTER_ASSERT(reporter, SkToBool(context));
+ if (NULL == context) {
+ return;
+ }
+
GrCacheID::Domain domain = GrCacheID::GenerateDomain();
GrCacheID::Key keyData;
- keyData.fData64[0] = 5;
- keyData.fData64[1] = 0;
+ memset(&keyData, 0, sizeof(keyData));
GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
- GrResourceKey key(GrCacheID(domain, keyData), t, 0);
+ keyData.fData64[0] = 1;
+ GrResourceKey key1(GrCacheID(domain, keyData), t, 0);
+
+ keyData.fData64[0] = 2;
+ GrResourceKey key2(GrCacheID(domain, keyData), t, 0);
{
context->setResourceCacheLimits(3, 30000);
@@ -163,15 +310,17 @@ static void test_cache_delete_on_destruction(skiatest::Reporter* reporter,
TestResource* a = new TestResource(context->getGpu());
TestResource* b = new TestResource(context->getGpu());
- cache->addResource(key, a);
- cache->addResource(key, b);
+ cache->addResource(key1, a);
+ cache->addResource(key2, b);
a->setDeleteWhenDestroyed(cache, b);
b->setDeleteWhenDestroyed(cache, a);
a->unref();
b->unref();
+
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
+
cache->purgeAllUnlocked();
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
}
@@ -180,10 +329,11 @@ static void test_cache_delete_on_destruction(skiatest::Reporter* reporter,
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());
- cache->addResource(key, a);
- cache->addResource(key, b);
+ cache->addResource(key1, a);
+ cache->addResource(key2, b);
a->setDeleteWhenDestroyed(cache, b);
b->setDeleteWhenDestroyed(cache, a);
@@ -192,13 +342,17 @@ static void test_cache_delete_on_destruction(skiatest::Reporter* reporter,
b->unref();
cache->deleteResource(a->getCacheEntry());
-
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
}
}
-static void test_resource_size_changed(skiatest::Reporter* reporter,
- GrContext* context) {
+static void test_resource_size_changed(skiatest::Reporter* reporter) {
+ SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
+ REPORTER_ASSERT(reporter, SkToBool(context));
+ if (NULL == context) {
+ return;
+ }
+
GrCacheID::Domain domain = GrCacheID::GenerateDomain();
GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
@@ -216,6 +370,7 @@ static void test_resource_size_changed(skiatest::Reporter* reporter,
{
context->setResourceCacheLimits(3, 30000);
GrResourceCache* cache = context->getResourceCache();
+ GrResourceCache2* cache2 = context->getResourceCache2();
cache->purgeAllUnlocked();
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
@@ -231,9 +386,12 @@ static void test_resource_size_changed(skiatest::Reporter* reporter,
REPORTER_ASSERT(reporter, 200 == cache->getCachedResourceBytes());
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
-
- static_cast<TestResource*>(cache->find(key2))->setSize(200);
- static_cast<TestResource*>(cache->find(key1))->setSize(50);
+ {
+ SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
+ find2->setSize(200);
+ SkAutoTUnref<TestResource> find1(static_cast<TestResource*>(cache2->findAndRefContentResource(key1)));
+ find1->setSize(50);
+ }
REPORTER_ASSERT(reporter, 250 == cache->getCachedResourceBytes());
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
@@ -243,22 +401,28 @@ static void test_resource_size_changed(skiatest::Reporter* reporter,
{
context->setResourceCacheLimits(2, 300);
GrResourceCache* cache = context->getResourceCache();
+ GrResourceCache2* cache2 = context->getResourceCache2();
cache->purgeAllUnlocked();
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
- TestResource* a = new TestResource(context->getGpu(), 100);
+ TestResource* a = new TestResource(context->getGpu());
+ a->setSize(100);
cache->addResource(key1, a);
a->unref();
- TestResource* b = new TestResource(context->getGpu(), 100);
+ TestResource* b = new TestResource(context->getGpu());
+ b->setSize(100);
cache->addResource(key2, b);
b->unref();
REPORTER_ASSERT(reporter, 200 == cache->getCachedResourceBytes());
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
- static_cast<TestResource*>(cache->find(key2))->setSize(201);
- REPORTER_ASSERT(reporter, !cache->hasKey(key1));
+ {
+ SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
+ find2->setSize(201);
+ }
+ REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
REPORTER_ASSERT(reporter, 201 == cache->getCachedResourceBytes());
REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
@@ -286,16 +450,12 @@ DEF_GPUTEST(ResourceCache, reporter, factory) {
test_cache(reporter, context, surface->getCanvas());
}
- // The below tests use a mock context.
- SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
- REPORTER_ASSERT(reporter, SkToBool(context));
- if (NULL == context) {
- return;
- }
-
- test_purge_invalidated(reporter, context);
- test_cache_delete_on_destruction(reporter, context);
- test_resource_size_changed(reporter, context);
+ // The below tests create their own mock contexts.
+ test_duplicate_content_key(reporter);
+ test_duplicate_scratch_key(reporter);
+ test_purge_invalidated(reporter);
+ test_cache_delete_on_destruction(reporter);
+ test_resource_size_changed(reporter);
}
#endif