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