fDrawState = SkNEW(GrDrawState);
fGpu->setDrawState(fDrawState);
-
fTextureCache = SkNEW_ARGS(GrResourceCache,
(MAX_TEXTURE_CACHE_COUNT,
MAX_TEXTURE_CACHE_BYTES));
return texture;
}
+static GrTexture* create_scratch_texture(GrGpu* gpu,
+ GrResourceCache* textureCache,
+ const GrTextureDesc& desc) {
+ GrTexture* texture = gpu->createTexture(desc, NULL, 0);
+ if (NULL != texture) {
+ GrResourceKey key = GrTexture::ComputeScratchKey(texture->desc());
+ // Adding a resource could put us overbudget. Try to free up the
+ // necessary space before adding it.
+ textureCache->purgeAsNeeded(1, texture->sizeInBytes());
+ // Make the resource exclusive so future 'find' calls don't return it
+ textureCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag);
+ }
+ return texture;
+}
+
GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) {
- GrTextureDesc desc = inDesc;
- GrAssert((desc.fFlags & kRenderTarget_GrTextureFlagBit) ||
- !(desc.fFlags & kNoStencil_GrTextureFlagBit));
+ GrAssert((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
+ !(inDesc.fFlags & kNoStencil_GrTextureFlagBit));
+
+ // Renderable A8 targets are not universally supported (e.g., not on ANGLE)
+ GrAssert(this->isConfigRenderable(kAlpha_8_GrPixelConfig) ||
+ !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
+ (inDesc.fConfig != kAlpha_8_GrPixelConfig));
+
+ if (!fGpu->caps()->reuseScratchTextures()) {
+ // If we're never recycling scratch textures we can
+ // always make them the right size
+ return create_scratch_texture(fGpu, fTextureCache, inDesc);
+ }
+
+ GrTextureDesc desc = inDesc;
if (kApprox_ScratchTexMatch == match) {
// bin by pow2 with a reasonable min
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;
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);
// 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());
+ }
}
fTextureCache->makeNonExclusive(texture->getCacheEntry());
this->purgeCache();
}
-
}
void GrContext::purgeCache() {
}
void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
- if (maxResources) {
+ if (NULL != maxResources) {
*maxResources = fMaxCount;
}
- if (maxResourceBytes) {
+ if (NULL != maxResourceBytes) {
*maxResourceBytes = fMaxBytes;
}
}
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) {
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);
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;
}
* @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;
* @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
/**
* 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;
* 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
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();
/**
* 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,
// 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;
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) {