Index: src/gpu/GrContext.cpp |
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp |
index d0f3cc56713226f7f432f6dbd4a90c19d6e94526..a722eed88ac5cac8a663adbe9f7fc14ac1d6315d 100755 |
--- a/src/gpu/GrContext.cpp |
+++ b/src/gpu/GrContext.cpp |
@@ -70,25 +70,6 @@ static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4; |
#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) |
-GrTexture* GrAutoScratchTexture::detach() { |
- if (NULL == fTexture) { |
- return NULL; |
- } |
- GrTexture* texture = fTexture; |
- fTexture = NULL; |
- |
- // This GrAutoScratchTexture has a ref from lockAndRefScratchTexture, which we give up now. |
- // The cache also has a ref which we are lending to the caller of detach(). When the caller |
- // lets go of the ref and the ref count goes to 0 internal_dispose will see this flag is |
- // set and re-ref the texture, thereby restoring the cache's ref. |
- SkASSERT(!texture->unique()); |
- texture->texturePriv().setFlag((GrTextureFlags) GrTexture::kReturnToCache_FlagBit); |
- texture->unref(); |
- SkASSERT(texture->getCacheEntry()); |
- |
- return texture; |
-} |
- |
// Glorified typedef to avoid including GrDrawState.h in GrContext.h |
class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {}; |
@@ -153,7 +134,8 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) { |
fDrawState = SkNEW(GrDrawState); |
fGpu->setDrawState(fDrawState); |
- fResourceCache = SkNEW_ARGS(GrResourceCache, (MAX_RESOURCE_CACHE_COUNT, |
+ fResourceCache = SkNEW_ARGS(GrResourceCache, (fGpu->caps(), |
+ MAX_RESOURCE_CACHE_COUNT, |
MAX_RESOURCE_CACHE_BYTES)); |
fResourceCache->setOverbudgetCallback(OverbudgetCB, this); |
fResourceCache2 = SkNEW(GrResourceCache2); |
@@ -446,9 +428,6 @@ GrTexture* GrContext::createTexture(const GrTextureParams* params, |
} |
if (texture) { |
- // Adding a resource could put us overbudget. Try to free up the |
- // necessary space before adding it. |
- fResourceCache->purgeAsNeeded(1, texture->gpuMemorySize()); |
fResourceCache->addResource(resourceKey, texture); |
if (cacheKey) { |
@@ -459,157 +438,71 @@ GrTexture* GrContext::createTexture(const GrTextureParams* params, |
return texture; |
} |
-static GrTexture* create_scratch_texture(GrGpu* gpu, |
- GrResourceCache* resourceCache, |
- const GrTextureDesc& desc) { |
- GrTexture* texture = gpu->createTexture(desc, NULL, 0); |
- if (texture) { |
- GrResourceKey key = GrTexturePriv::ComputeScratchKey(texture->desc()); |
- // Adding a resource could put us overbudget. Try to free up the |
- // necessary space before adding it. |
- resourceCache->purgeAsNeeded(1, texture->gpuMemorySize()); |
- // Make the resource exclusive so future 'find' calls don't return it |
- resourceCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag); |
+GrTexture* GrContext::createNewScratchTexture(const GrTextureDesc& desc) { |
+ GrTexture* texture = fGpu->createTexture(desc, NULL, 0); |
+ if (!texture) { |
+ return NULL; |
} |
+ fResourceCache->addResource(texture->getScratchKey(), texture); |
+ texture->fIsScratch = GrGpuResource::kYes_IsScratch; |
return texture; |
} |
-GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) { |
+GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match, |
+ bool calledDuringFlush) { |
+ // kNoStencil has no meaning if kRT isn't set. |
SkASSERT((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || |
!(inDesc.fFlags & kNoStencil_GrTextureFlagBit)); |
- // Renderable A8 targets are not universally supported (e.g., not on ANGLE) |
- SkASSERT(this->isConfigRenderable(kAlpha_8_GrPixelConfig, inDesc.fSampleCnt > 0) || |
- !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || |
- (inDesc.fConfig != kAlpha_8_GrPixelConfig)); |
+ // Make sure caller has checked for renderability if kRT is set. |
+ SkASSERT(!(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || |
+ this->isConfigRenderable(inDesc.fConfig, inDesc.fSampleCnt > 0)); |
- if (!fGpu->caps()->reuseScratchTextures() && |
- !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit)) { |
- // If we're never recycling this texture we can always make it the right size |
- return create_scratch_texture(fGpu, fResourceCache, inDesc); |
- } |
- |
- GrTextureDesc desc = inDesc; |
+ SkTCopyOnFirstWrite<GrTextureDesc> desc(inDesc); |
- if (kApprox_ScratchTexMatch == match) { |
- // bin by pow2 with a reasonable min |
- static const int MIN_SIZE = 16; |
- desc.fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc.fWidth)); |
- desc.fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc.fHeight)); |
- } |
- |
- GrGpuResource* resource = NULL; |
- int origWidth = desc.fWidth; |
- int origHeight = desc.fHeight; |
- |
- do { |
- GrResourceKey key = GrTexturePriv::ComputeScratchKey(desc); |
- // Ensure we have exclusive access to the texture so future 'find' calls don't return it |
- resource = fResourceCache->find(key, GrResourceCache::kHide_OwnershipFlag); |
- if (resource) { |
- resource->ref(); |
- break; |
- } |
- if (kExact_ScratchTexMatch == match) { |
- break; |
- } |
- // We had a cache miss and we are in approx mode, relax the fit of the flags. |
- |
- // We no longer try to reuse textures that were previously used as render targets in |
- // situations where no RT is needed; doing otherwise can confuse the video driver and |
- // cause significant performance problems in some cases. |
- if (desc.fFlags & kNoStencil_GrTextureFlagBit) { |
- desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit; |
- } else { |
- break; |
+ if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrTextureFlagBit)) { |
+ GrTextureFlags origFlags = desc->fFlags; |
+ if (kApprox_ScratchTexMatch == match) { |
+ // bin by pow2 with a reasonable min |
+ static const int MIN_SIZE = 16; |
+ GrTextureDesc* wdesc = desc.writable(); |
+ wdesc->fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc->fWidth)); |
+ wdesc->fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc->fHeight)); |
} |
- } while (true); |
- |
- if (NULL == resource) { |
- desc.fFlags = inDesc.fFlags; |
- desc.fWidth = origWidth; |
- desc.fHeight = origHeight; |
- resource = create_scratch_texture(fGpu, fResourceCache, desc); |
- } |
- |
- return static_cast<GrTexture*>(resource); |
-} |
- |
-void GrContext::addExistingTextureToCache(GrTexture* texture) { |
- |
- if (NULL == texture) { |
- return; |
- } |
- |
- // This texture should already have a cache entry since it was once |
- // attached |
- SkASSERT(texture->getCacheEntry()); |
- |
- // Conceptually, the cache entry is going to assume responsibility |
- // for the creation ref. Assert refcnt == 1. |
- // Except that this also gets called when the texture is prematurely |
- // abandoned. In that case the ref count may be > 1. |
- // SkASSERT(texture->unique()); |
+ do { |
+ GrResourceKey key = GrTexturePriv::ComputeScratchKey(*desc); |
+ GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key, |
+ calledDuringFlush); |
+ if (resource) { |
+ fResourceCache->makeResourceMRU(resource); |
+ return static_cast<GrTexture*>(resource); |
+ } |
- if (fGpu->caps()->reuseScratchTextures() || texture->asRenderTarget()) { |
- // Since this texture came from an AutoScratchTexture it should |
- // still be in the exclusive pile. Recycle it. |
- fResourceCache->makeNonExclusive(texture->getCacheEntry()); |
- 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 |
- fResourceCache->makeNonExclusive(texture->getCacheEntry()); |
- fResourceCache->deleteResource(texture->getCacheEntry()); |
- } |
-} |
+ if (kExact_ScratchTexMatch == match) { |
+ break; |
+ } |
+ // We had a cache miss and we are in approx mode, relax the fit of the flags. |
+ |
+ // We no longer try to reuse textures that were previously used as render targets in |
+ // situations where no RT is needed; doing otherwise can confuse the video driver and |
+ // cause significant performance problems in some cases. |
+ if (desc->fFlags & kNoStencil_GrTextureFlagBit) { |
+ desc.writable()->fFlags = desc->fFlags & ~kNoStencil_GrTextureFlagBit; |
+ } else { |
+ break; |
+ } |
-void GrContext::unlockScratchTexture(GrTexture* texture) { |
- if (texture->wasDestroyed()) { |
- if (texture->getCacheEntry()->key().isScratch()) { |
- // This texture was detached from the cache but the cache still had a ref to it but |
- // not a pointer to it. This will unref the texture and delete its resource cache |
- // entry. |
- delete texture->getCacheEntry(); |
- } |
- return; |
- } |
+ } while (true); |
- ASSERT_OWNED_RESOURCE(texture); |
- SkASSERT(texture->getCacheEntry()); |
- |
- // If this is a scratch texture we detached it from the cache |
- // while it was locked (to avoid two callers simultaneously getting |
- // the same texture). |
- if (texture->getCacheEntry()->key().isScratch()) { |
- if (fGpu->caps()->reuseScratchTextures() || texture->asRenderTarget()) { |
- fResourceCache->makeNonExclusive(texture->getCacheEntry()); |
- this->purgeCache(); |
- } else if (texture->unique()) { |
- // Only the cache now knows about this texture. Since we're never |
- // reusing scratch textures (in this code path) it would just be |
- // wasting time sitting in the cache. |
- fResourceCache->makeNonExclusive(texture->getCacheEntry()); |
- fResourceCache->deleteResource(texture->getCacheEntry()); |
- } else { |
- // In this case (there is still a non-cache ref) but we don't really |
- // want to readd it to the cache (since it will never be reused). |
- // Instead, give up the cache's ref and leave the decision up to |
- // addExistingTextureToCache once its ref count reaches 0. For |
- // this to work we need to leave it in the exclusive list. |
- texture->texturePriv().setFlag((GrTextureFlags) GrTexture::kReturnToCache_FlagBit); |
- // Give up the cache's ref to the texture |
- texture->unref(); |
- } |
+ desc.writable()->fFlags = origFlags; |
} |
-} |
-void GrContext::purgeCache() { |
- if (fResourceCache) { |
- fResourceCache->purgeAsNeeded(); |
- } |
+ GrTexture* texture = this->createNewScratchTexture(*desc); |
+ SkASSERT(NULL == texture || |
+ texture->getScratchKey() == GrTexturePriv::ComputeScratchKey(*desc)); |
+ return texture; |
} |
bool GrContext::OverbudgetCB(void* data) { |
@@ -1349,6 +1242,7 @@ void GrContext::flush(int flagsBitfield) { |
} else { |
fDrawBuffer->flush(); |
} |
+ fResourceCache->purgeAsNeeded(); |
fFlushToReduceCacheSize = false; |
} |
@@ -1941,7 +1835,6 @@ const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture, |
} |
void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResource* resource) { |
- fResourceCache->purgeAsNeeded(1, resource->gpuMemorySize()); |
fResourceCache->addResource(resourceKey, resource); |
} |