diff options
author | bsalomon <bsalomon@google.com> | 2014-09-30 06:02:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-30 06:02:23 -0700 |
commit | 3d398c876440deaab39bbf2a9b881c337e6dc8d4 (patch) | |
tree | b38c23d2b6742c9d515dd2b19a1cf8fca49a16f0 /src/gpu/GrContext.cpp | |
parent | c0eb9b9818462471f5fc1c47fa549c6052d8bbae (diff) | |
download | skia-3d398c876440deaab39bbf2a9b881c337e6dc8d4.tar.gz |
GrResourceCache2 manages scratch texture.
BUG=skia:
R=robertphillips@google.com
Author: bsalomon@google.com
Review URL: https://codereview.chromium.org/608883003
Diffstat (limited to 'src/gpu/GrContext.cpp')
-rwxr-xr-x | src/gpu/GrContext.cpp | 207 |
1 files changed, 54 insertions, 153 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 46a5576b1..de34f2355 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 {}; @@ -459,157 +440,77 @@ 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); +bool GrContext::createNewScratchTexture(const GrTextureDesc& desc) { + SkAutoTUnref<GrTexture> texture(fGpu->createTexture(desc, NULL, 0)); + if (!texture) { + return false; } - return texture; + fResourceCache->addResource(texture->getScratchKey(), texture); + texture->fIsScratch = GrIORef::kYes_IsScratch; + return true; } GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) { + // 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)); - - 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; - - 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; + // Make sure caller has checked for renderability if kRT is set. + SkASSERT(!(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || + this->isConfigRenderable(inDesc.fConfig, inDesc.fSampleCnt > 0)); + + SkTCopyOnFirstWrite<GrTextureDesc> desc(inDesc); + + // There is a regression here in that when reuseScratchTextures is false, the texture won't be + // freed when its ref and io counts reach zero. TODO: Make GrResourceCache2 free scratch + // resources immediately after it is the sole owner and reuseScratchTextures is false. + 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); - } + do { + GrResourceKey key = GrTexturePriv::ComputeScratchKey(*desc); + GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key); + if (resource) { + fResourceCache->makeResourceMRU(resource); + return static_cast<GrTexture*>(resource); + } - return static_cast<GrTexture*>(resource); -} + 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::addExistingTextureToCache(GrTexture* texture) { + } while (true); - if (NULL == texture) { - return; + desc.writable()->fFlags = origFlags; } - // 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()); - - 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()); - } -} - -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; - } - - 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(); - } + if (!this->createNewScratchTexture(*desc)) { + return NULL; } -} -void GrContext::purgeCache() { - if (fResourceCache) { - fResourceCache->purgeAsNeeded(); - } + // If we got here then we didn't find a cached texture, but we just added one. + GrResourceKey key = GrTexturePriv::ComputeScratchKey(*desc); + GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key); + SkASSERT(resource); + return static_cast<GrTexture*>(resource); } bool GrContext::OverbudgetCB(void* data) { |