Use GrResourceCache2 to service content key lookups
BUG=skia:2889
Review URL: https://codereview.chromium.org/707493002
diff --git a/src/core/SkTMultiMap.h b/src/core/SkTMultiMap.h
index 70076f0..1168ed6 100644
--- a/src/core/SkTMultiMap.h
+++ b/src/core/SkTMultiMap.h
@@ -102,6 +102,19 @@
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 83ef58f..6f9395b 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -255,20 +255,20 @@
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 @@
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 @@
}
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 64ee29b..ab24c54 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -84,10 +84,8 @@
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 @@
}
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 705cdea..b77acff 100644
--- a/src/gpu/GrGpuResource.cpp
+++ b/src/gpu/GrGpuResource.cpp
@@ -78,6 +78,24 @@
}
}
+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 @@
}
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 @@
}
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 9754d44..8eed4d4 100644
--- a/src/gpu/GrResourceCache.cpp
+++ b/src/gpu/GrResourceCache.cpp
@@ -49,7 +49,8 @@
}
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 @@
}
}
-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 @@
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 f6d064a..874f16a 100644
--- a/src/gpu/GrResourceCache.h
+++ b/src/gpu/GrResourceCache.h
@@ -140,12 +140,6 @@
*/
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 @@
*
* 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 6bc23a3..65e522a 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 @@
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 @@
if (!resource->getScratchKey().isNullScratch()) {
fScratchMap.remove(resource->getScratchKey(), resource);
}
+ if (const GrResourceKey* contentKey = resource->getContentKey()) {
+ fContentHash.remove(*contentKey);
+ }
--fCount;
}
@@ -43,6 +47,7 @@
SkASSERT(head != fResources.head());
}
SkASSERT(!fScratchMap.count());
+ SkASSERT(!fContentHash.count());
SkASSERT(!fCount);
}
@@ -89,3 +94,25 @@
}
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 a365a5a..9424c40 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 @@
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 @@
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 @@
};
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 2139540..72e8225 100644
--- a/src/gpu/GrTexture.cpp
+++ b/src/gpu/GrTexture.cpp
@@ -121,7 +121,10 @@
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);