| 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);
|
| }
|
|
|
|
|