diff options
author | bsalomon <bsalomon@google.com> | 2014-11-13 13:19:10 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-13 13:19:10 -0800 |
commit | 66a450f21a3da174b7eed89a1d5fc8591e8b6ee6 (patch) | |
tree | 97170b6b7e193001f9afbf6a99980dd355de2bda /src | |
parent | bc97c9378bf8b89cc17280a2a04a5c3a9405e6ab (diff) |
Replace GrResourceCache with GrResourceCache2.
BUG=skia:2889
Review URL: https://codereview.chromium.org/716143004
Diffstat (limited to 'src')
-rwxr-xr-x | src/gpu/GrAADistanceFieldPathRenderer.h | 1 | ||||
-rwxr-xr-x | src/gpu/GrContext.cpp | 143 | ||||
-rw-r--r-- | src/gpu/GrGpuResource.cpp | 33 | ||||
-rw-r--r-- | src/gpu/GrGpuResourceCacheAccess.h | 19 | ||||
-rw-r--r-- | src/gpu/GrPath.h | 1 | ||||
-rw-r--r-- | src/gpu/GrPathRange.h | 1 | ||||
-rw-r--r-- | src/gpu/GrResourceCache.cpp | 393 | ||||
-rw-r--r-- | src/gpu/GrResourceCache.h | 251 | ||||
-rw-r--r-- | src/gpu/GrResourceCache2.cpp | 300 | ||||
-rw-r--r-- | src/gpu/GrResourceCache2.h | 203 | ||||
-rw-r--r-- | src/gpu/GrStencilBuffer.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrTest.cpp | 4 | ||||
-rw-r--r-- | src/gpu/GrTexture.cpp | 1 | ||||
-rw-r--r-- | src/gpu/SkGr.cpp | 1 |
14 files changed, 553 insertions, 800 deletions
diff --git a/src/gpu/GrAADistanceFieldPathRenderer.h b/src/gpu/GrAADistanceFieldPathRenderer.h index 10f0ebab93..c337016c0b 100755 --- a/src/gpu/GrAADistanceFieldPathRenderer.h +++ b/src/gpu/GrAADistanceFieldPathRenderer.h @@ -15,6 +15,7 @@ #include "GrRect.h" #include "SkChecksum.h" +#include "SkTDynamicHash.h" class GrContext; class GrPlot; diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 3a93404af1..9a180ee653 100755 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -25,7 +25,6 @@ #include "GrOvalRenderer.h" #include "GrPathRenderer.h" #include "GrPathUtils.h" -#include "GrResourceCache.h" #include "GrResourceCache2.h" #include "GrSoftwarePathRenderer.h" #include "GrStencilBuffer.h" @@ -52,9 +51,6 @@ #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0 #endif -static const size_t MAX_RESOURCE_CACHE_COUNT = GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT; -static const size_t MAX_RESOURCE_CACHE_BYTES = GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT * 1024 * 1024; - static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15; static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; @@ -66,20 +62,6 @@ static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4; // Glorified typedef to avoid including GrDrawState.h in GrContext.h class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {}; -class GrContext::AutoCheckFlush { -public: - AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); } - - ~AutoCheckFlush() { - if (fContext->fFlushToReduceCacheSize) { - fContext->flush(); - } - } - -private: - GrContext* fContext; -}; - GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, const Options* opts) { GrContext* context; @@ -103,13 +85,11 @@ GrContext::GrContext(const Options& opts) : fOptions(opts) { fClip = NULL; fPathRendererChain = NULL; fSoftwarePathRenderer = NULL; - fResourceCache = NULL; fResourceCache2 = NULL; fFontCache = NULL; fDrawBuffer = NULL; fDrawBufferVBAllocPool = NULL; fDrawBufferIBAllocPool = NULL; - fFlushToReduceCacheSize = false; fAARectRenderer = NULL; fOvalRenderer = NULL; fViewMatrix.reset(); @@ -130,11 +110,8 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) { void GrContext::initCommon() { fDrawState = SkNEW(GrDrawState); - fResourceCache = SkNEW_ARGS(GrResourceCache, (fGpu->caps(), - MAX_RESOURCE_CACHE_COUNT, - MAX_RESOURCE_CACHE_BYTES)); - fResourceCache->setOverbudgetCallback(OverbudgetCB, this); fResourceCache2 = SkNEW(GrResourceCache2); + fResourceCache2->setOverBudgetCallback(OverBudgetCB, this); fFontCache = SkNEW_ARGS(GrFontCache, (fGpu)); @@ -160,9 +137,6 @@ GrContext::~GrContext() { } SkDELETE(fResourceCache2); - fResourceCache2 = NULL; - SkDELETE(fResourceCache); - fResourceCache = NULL; SkDELETE(fFontCache); SkDELETE(fDrawBuffer); SkDELETE(fDrawBufferVBAllocPool); @@ -201,8 +175,6 @@ void GrContext::abandonContext() { fAARectRenderer->reset(); fOvalRenderer->reset(); - fResourceCache->purgeAllUnlocked(); - fFontCache->freeAll(); fLayerCache->freeAll(); } @@ -221,7 +193,6 @@ void GrContext::freeGpuResources() { fAARectRenderer->reset(); fOvalRenderer->reset(); - fResourceCache->purgeAllUnlocked(); fFontCache->freeAll(); fLayerCache->freeAll(); // a path renderer may be holding onto resources @@ -230,12 +201,12 @@ void GrContext::freeGpuResources() { } void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { - if (resourceCount) { - *resourceCount = fResourceCache->getCachedResourceCount(); - } - if (resourceBytes) { - *resourceBytes = fResourceCache->getCachedResourceBytes(); - } + if (resourceCount) { + *resourceCount = fResourceCache2->getResourceCount(); + } + if (resourceBytes) { + *resourceBytes = fResourceCache2->getResourceBytes(); + } } GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget, @@ -273,12 +244,13 @@ bool GrContext::isTextureInCache(const GrSurfaceDesc& desc, } void GrContext::addStencilBuffer(GrStencilBuffer* sb) { + // TODO: Make GrStencilBuffers use the scratch mechanism rather than content keys. ASSERT_OWNED_RESOURCE(sb); GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(), sb->height(), sb->numSamples()); - fResourceCache->addResource(resourceKey, sb); + SkAssertResult(sb->cacheAccess().setContentKey(resourceKey)); } GrStencilBuffer* GrContext::findAndRefStencilBuffer(int width, int height, int sampleCnt) { @@ -420,25 +392,19 @@ GrTexture* GrContext::createTexture(const GrTextureParams* params, } if (texture) { - fResourceCache->addResource(resourceKey, texture); - - if (cacheKey) { - *cacheKey = resourceKey; + if (texture->cacheAccess().setContentKey(resourceKey)) { + if (cacheKey) { + *cacheKey = resourceKey; + } + } else { + texture->unref(); + texture = NULL; } } return texture; } -GrTexture* GrContext::createNewScratchTexture(const GrSurfaceDesc& desc) { - GrTexture* texture = fGpu->createTexture(desc, NULL, 0); - if (!texture) { - return NULL; - } - fResourceCache->addResource(texture->cacheAccess().getScratchKey(), texture); - return texture; -} - GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexMatch match, bool calledDuringFlush) { // kNoStencil has no meaning if kRT isn't set. @@ -473,7 +439,6 @@ GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexM } GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key, scratchFlags); if (resource) { - fResourceCache->makeResourceMRU(resource); return static_cast<GrSurface*>(resource)->asTexture(); } @@ -496,21 +461,17 @@ GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexM desc.writable()->fFlags = origFlags; } - GrTexture* texture = this->createNewScratchTexture(*desc); + GrTexture* texture = fGpu->createTexture(*desc, NULL, 0); SkASSERT(NULL == texture || texture->cacheAccess().getScratchKey() == GrTexturePriv::ComputeScratchKey(*desc)); return texture; } -bool GrContext::OverbudgetCB(void* data) { +void GrContext::OverBudgetCB(void* data) { + // Flush the InOrderDrawBuffer to possibly free up some textures SkASSERT(data); - GrContext* context = reinterpret_cast<GrContext*>(data); - - // Flush the InOrderDrawBuffer to possibly free up some textures - context->fFlushToReduceCacheSize = true; - - return true; + context->flush(); } @@ -522,11 +483,16 @@ GrTexture* GrContext::createUncachedTexture(const GrSurfaceDesc& descIn, } void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const { - fResourceCache->getLimits(maxTextures, maxTextureBytes); + if (maxTextures) { + *maxTextures = fResourceCache2->getMaxResourceCount(); + } + if (maxTextureBytes) { + *maxTextureBytes = fResourceCache2->getMaxResourceBytes(); + } } void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) { - fResourceCache->setLimits(maxTextures, maxTextureBytes); + fResourceCache2->setLimits(maxTextures, maxTextureBytes); } int GrContext::getMaxTextureSize() const { @@ -582,9 +548,8 @@ void GrContext::clear(const SkIRect* rect, SkASSERT(renderTarget); AutoRestoreEffects are; - AutoCheckFlush acf(this); GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this); - GrDrawTarget* target = this->prepareToDraw(NULL, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(NULL, &are); if (NULL == target) { return; } @@ -716,8 +681,7 @@ void GrContext::drawRect(const GrPaint& paint, } AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(&paint, &are); if (NULL == target) { return; } @@ -827,8 +791,7 @@ void GrContext::drawRectToRect(const GrPaint& paint, const SkRect& localRect, const SkMatrix* localMatrix) { AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(&paint, &are); if (NULL == target) { return; } @@ -891,10 +854,9 @@ void GrContext::drawVertices(const GrPaint& paint, const uint16_t indices[], int indexCount) { AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope + GrDrawTarget::AutoReleaseGeometry geo; - GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(&paint, &are); if (NULL == target) { return; } @@ -954,8 +916,7 @@ void GrContext::drawRRect(const GrPaint& paint, } AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(&paint, &are); if (NULL == target) { return; } @@ -981,8 +942,7 @@ void GrContext::drawDRRect(const GrPaint& paint, } AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(&paint, &are); GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target); @@ -1014,8 +974,7 @@ void GrContext::drawOval(const GrPaint& paint, } AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(&paint, &are); if (NULL == target) { return; } @@ -1102,8 +1061,7 @@ void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const GrStrok SkPoint pts[2]; if (path.isLine(pts)) { AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(&paint, &are); if (NULL == target) { return; } @@ -1139,8 +1097,7 @@ void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const GrStrok // the writePixels that uploads to the scratch will perform a flush so we're // OK. AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(&paint, &are); if (NULL == target) { return; } @@ -1242,8 +1199,6 @@ void GrContext::flush(int flagsBitfield) { } else { fDrawBuffer->flush(); } - fResourceCache->purgeAsNeeded(); - fFlushToReduceCacheSize = false; } bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, @@ -1363,7 +1318,7 @@ bool GrContext::writeSurfacePixels(GrSurface* surface, // drawing a rect to the render target. // The bracket ensures we pop the stack if we wind up flushing below. { - GrDrawTarget* drawTarget = this->prepareToDraw(NULL, NULL, NULL); + GrDrawTarget* drawTarget = this->prepareToDraw(NULL, NULL); GrDrawTarget::AutoGeometryAndStatePush agasp(drawTarget, GrDrawTarget::kReset_ASRInit, &matrix); GrDrawState* drawState = drawTarget->drawState(); @@ -1543,8 +1498,7 @@ void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) { SkASSERT(renderTarget); ASSERT_OWNED_RESOURCE(renderTarget); AutoRestoreEffects are; - AutoCheckFlush acf(this); - GrDrawTarget* target = this->prepareToDraw(NULL, &are, &acf); + GrDrawTarget* target = this->prepareToDraw(NULL, &are); if (NULL == target) { return; } @@ -1562,7 +1516,7 @@ void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe // Since we're going to the draw target and not GPU, no need to check kNoFlush // here. - GrDrawTarget* target = this->prepareToDraw(NULL, NULL, NULL); + GrDrawTarget* target = this->prepareToDraw(NULL, NULL); if (NULL == target) { return; } @@ -1581,9 +1535,7 @@ void GrContext::flushSurfaceWrites(GrSurface* surface) { //////////////////////////////////////////////////////////////////////////////// -GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, - AutoRestoreEffects* are, - AutoCheckFlush* acf) { +GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, AutoRestoreEffects* are) { // All users of this draw state should be freeing up all effects when they're done. // Otherwise effects that own resources may keep those resources alive indefinitely. SkASSERT(0 == fDrawState->numColorStages() && 0 == fDrawState->numCoverageStages() && @@ -1596,7 +1548,6 @@ GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, ASSERT_OWNED_RESOURCE(fRenderTarget.get()); if (paint) { SkASSERT(are); - SkASSERT(acf); are->set(fDrawState); fDrawState->setFromPaint(*paint, fViewMatrix, fRenderTarget.get()); #if GR_DEBUG_PARTIAL_COVERAGE_CHECK @@ -1696,7 +1647,7 @@ void GrContext::setupDrawBuffer() { } GrDrawTarget* GrContext::getTextTarget() { - return this->prepareToDraw(NULL, NULL, NULL); + return this->prepareToDraw(NULL, NULL); } const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { @@ -1746,15 +1697,11 @@ const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture, } void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResource* resource) { - fResourceCache->addResource(resourceKey, resource); + resource->cacheAccess().setContentKey(resourceKey); } GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resourceKey) { - GrGpuResource* resource = fResourceCache2->findAndRefContentResource(resourceKey); - if (resource) { - fResourceCache->makeResourceMRU(resource); - } - return resource; + return fResourceCache2->findAndRefContentResource(resourceKey); } void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { @@ -1774,7 +1721,7 @@ void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { /////////////////////////////////////////////////////////////////////////////// #if GR_CACHE_STATS void GrContext::printCacheStats() const { - fResourceCache->printStats(); + fResourceCache2->printStats(); } #endif diff --git a/src/gpu/GrGpuResource.cpp b/src/gpu/GrGpuResource.cpp index f6f7282700..be8ea0daf0 100644 --- a/src/gpu/GrGpuResource.cpp +++ b/src/gpu/GrGpuResource.cpp @@ -18,16 +18,8 @@ static inline GrResourceCache2* get_resource_cache2(GrGpu* gpu) { return gpu->getContext()->getResourceCache2(); } -static inline GrResourceCache* get_resource_cache(GrGpu* gpu) { - SkASSERT(gpu); - SkASSERT(gpu->getContext()); - SkASSERT(gpu->getContext()->getResourceCache()); - return gpu->getContext()->getResourceCache(); -} - GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped) : fGpu(gpu) - , fCacheEntry(NULL) , fGpuMemorySize(kInvalidGpuMemorySize) , fUniqueID(CreateUniqueID()) , fScratchKey(GrResourceKey::NullScratchKey()) @@ -40,7 +32,7 @@ GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped) } void GrGpuResource::registerWithCache() { - get_resource_cache2(fGpu)->insertResource(this); + get_resource_cache2(fGpu)->resourceAccess().insertResource(this); } GrGpuResource::~GrGpuResource() { @@ -51,16 +43,18 @@ GrGpuResource::~GrGpuResource() { void GrGpuResource::release() { if (fGpu) { this->onRelease(); - get_resource_cache2(fGpu)->removeResource(this); + get_resource_cache2(fGpu)->resourceAccess().removeResource(this); fGpu = NULL; + fGpuMemorySize = 0; } } void GrGpuResource::abandon() { if (fGpu) { this->onAbandon(); - get_resource_cache2(fGpu)->removeResource(this); + get_resource_cache2(fGpu)->resourceAccess().removeResource(this); fGpu = NULL; + fGpuMemorySize = 0; } } @@ -80,6 +74,17 @@ GrContext* GrGpuResource::getContext() { } } +void GrGpuResource::didChangeGpuMemorySize() const { + if (this->wasDestroyed()) { + return; + } + + size_t oldSize = fGpuMemorySize; + SkASSERT(kInvalidGpuMemorySize != oldSize); + fGpuMemorySize = kInvalidGpuMemorySize; + get_resource_cache2(fGpu)->resourceAccess().didChangeGpuMemorySize(this, oldSize); +} + bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) { // Currently this can only be called once and can't be called when the resource is scratch. SkASSERT(!contentKey.isScratch()); @@ -92,7 +97,7 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) { fContentKey = contentKey; fContentKeySet = true; - if (!get_resource_cache2(fGpu)->didSetContentKey(this)) { + if (!get_resource_cache2(fGpu)->resourceAccess().didSetContentKey(this)) { fContentKeySet = false; return false; } @@ -100,8 +105,8 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) { } void GrGpuResource::notifyIsPurgable() const { - if (fCacheEntry && !this->wasDestroyed()) { - get_resource_cache(fGpu)->notifyPurgable(this); + if (!this->wasDestroyed()) { + get_resource_cache2(fGpu)->resourceAccess().notifyPurgable(this); } } diff --git a/src/gpu/GrGpuResourceCacheAccess.h b/src/gpu/GrGpuResourceCacheAccess.h index af5c05464b..7417a55a71 100644 --- a/src/gpu/GrGpuResourceCacheAccess.h +++ b/src/gpu/GrGpuResourceCacheAccess.h @@ -29,25 +29,6 @@ public: } /** - * Used by legacy cache to attach a cache entry. This is to be removed soon. - */ - void setCacheEntry(GrResourceCacheEntry* cacheEntry) { - // GrResourceCache never changes the cacheEntry once one has been added. - SkASSERT(NULL == cacheEntry || NULL == fResource->fCacheEntry); - fResource->fCacheEntry = cacheEntry; - } - - /** - * Is the resource in the legacy cache? This is to be removed soon. - */ - bool isInCache() const { return SkToBool(fResource->fCacheEntry); } - - /** - * Returns the cache entry for the legacy cache. This is to be removed soon. - */ - GrResourceCacheEntry* getCacheEntry() const { return fResource->fCacheEntry; } - - /** * Is the resource currently cached as scratch? This means it has a valid scratch key and does * not have a content key. */ diff --git a/src/gpu/GrPath.h b/src/gpu/GrPath.h index a571935390..394db6f5c2 100644 --- a/src/gpu/GrPath.h +++ b/src/gpu/GrPath.h @@ -9,7 +9,6 @@ #define GrPath_DEFINED #include "GrGpuResource.h" -#include "GrResourceCache.h" #include "SkPath.h" #include "SkRect.h" #include "SkStrokeRec.h" diff --git a/src/gpu/GrPathRange.h b/src/gpu/GrPathRange.h index dc8ce1d71b..5bfecb0a68 100644 --- a/src/gpu/GrPathRange.h +++ b/src/gpu/GrPathRange.h @@ -9,7 +9,6 @@ #define GrPathRange_DEFINED #include "GrGpuResource.h" -#include "GrResourceCache.h" #include "SkRefCnt.h" #include "SkStrokeRec.h" #include "SkTArray.h" diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp deleted file mode 100644 index a73d11703d..0000000000 --- a/src/gpu/GrResourceCache.cpp +++ /dev/null @@ -1,393 +0,0 @@ - -/* - * Copyright 2010 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrResourceCache.h" -#include "GrGpuResource.h" -#include "GrGpuResourceCacheAccess.h" -#include "GrTexturePriv.h" - -DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage); - -/////////////////////////////////////////////////////////////////////////////// - -void GrGpuResource::didChangeGpuMemorySize() const { - fGpuMemorySize = kInvalidGpuMemorySize; - if (this->cacheAccess().isInCache()) { - fCacheEntry->didChangeResourceSize(); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { - static int32_t gNextType = 0; - - int32_t type = sk_atomic_inc(&gNextType); - if (type >= (1 << 8 * sizeof(ResourceType))) { - SkFAIL("Too many Resource Types"); - } - - return static_cast<ResourceType>(type); -} - -/////////////////////////////////////////////////////////////////////////////// - -GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, GrGpuResource* resource) - : fResourceCache(resourceCache), - fResource(resource), - fCachedSize(resource->gpuMemorySize()) { - // we assume ownership of the resource, and will unref it when we die - SkASSERT(resource); - resource->ref(); -} - -GrResourceCacheEntry::~GrResourceCacheEntry() { - // We're relying on having the cache entry to remove this from GrResourceCache2's content hash. - // fResource->setCacheEntry(NULL); - fResource->unref(); -} - -#ifdef SK_DEBUG -void GrResourceCacheEntry::validate() const { - SkASSERT(fResourceCache); - SkASSERT(fResource); - SkASSERT(fResource->cacheAccess().getCacheEntry() == this); - SkASSERT(fResource->gpuMemorySize() == fCachedSize); - fResource->validate(); -} -#endif - -void GrResourceCacheEntry::didChangeResourceSize() { - size_t oldSize = fCachedSize; - fCachedSize = fResource->gpuMemorySize(); - if (fCachedSize > oldSize) { - fResourceCache->didIncreaseResourceSize(this, fCachedSize - oldSize); - } else if (fCachedSize < oldSize) { - fResourceCache->didDecreaseResourceSize(this, oldSize - fCachedSize); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -GrResourceCache::GrResourceCache(const GrDrawTargetCaps* caps, int maxCount, size_t maxBytes) - : fMaxCount(maxCount) - , fMaxBytes(maxBytes) - , fCaps(SkRef(caps)) { -#if GR_CACHE_STATS - fHighWaterEntryCount = 0; - fHighWaterEntryBytes = 0; -#endif - - fEntryCount = 0; - fEntryBytes = 0; - - fPurging = false; - - fOverbudgetCB = NULL; - fOverbudgetData = NULL; -} - -GrResourceCache::~GrResourceCache() { - GrAutoResourceCacheValidate atcv(this); - - EntryList::Iter iter; - - // Unlike the removeAll, here we really remove everything, including locked resources. - while (GrResourceCacheEntry* entry = fList.head()) { - GrAutoResourceCacheValidate atcv(this); - - // remove from our llist - this->internalDetach(entry); - - delete entry; - } -} - -void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{ - if (maxResources) { - *maxResources = fMaxCount; - } - if (maxResourceBytes) { - *maxResourceBytes = fMaxBytes; - } -} - -void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) { - bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes); - - fMaxCount = maxResources; - fMaxBytes = maxResourceBytes; - - if (smaller) { - this->purgeAsNeeded(); - } -} - -void GrResourceCache::internalDetach(GrResourceCacheEntry* entry) { - fList.remove(entry); - fEntryCount -= 1; - fEntryBytes -= entry->fCachedSize; -} - -void GrResourceCache::attachToHead(GrResourceCacheEntry* entry) { - fList.addToHead(entry); - - fEntryCount += 1; - fEntryBytes += entry->fCachedSize; - -#if GR_CACHE_STATS - if (fHighWaterEntryCount < fEntryCount) { - fHighWaterEntryCount = fEntryCount; - } - if (fHighWaterEntryBytes < fEntryBytes) { - fHighWaterEntryBytes = fEntryBytes; - } -#endif -} - - -void GrResourceCache::makeResourceMRU(GrGpuResource* resource) { - GrResourceCacheEntry* entry = resource->cacheAccess().getCacheEntry(); - if (entry) { - this->internalDetach(entry); - this->attachToHead(entry); - } -} - -void GrResourceCache::notifyPurgable(const GrGpuResource* resource) { - // Remove scratch textures from the cache the moment they become purgeable if - // scratch texture reuse is turned off. - SkASSERT(resource->cacheAccess().getCacheEntry()); - if (resource->cacheAccess().isScratch()) { - const GrResourceKey& key = resource->cacheAccess().getScratchKey(); - if (key.getResourceType() == GrTexturePriv::ResourceType() && - !fCaps->reuseScratchTextures() && - !(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTarget_GrSurfaceFlag)) { - this->deleteResource(resource->cacheAccess().getCacheEntry()); - } - } -} - -bool GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resource) { - if (NULL != resource->cacheAccess().getCacheEntry()) { - return false; - } - - if (key.isScratch()) { - SkASSERT(resource->cacheAccess().isScratch()); - SkASSERT(key == resource->cacheAccess().getScratchKey()); - } else { - if (!resource->cacheAccess().setContentKey(key)) { - return false; - } - } - - // we don't expect to create new resources during a purge. In theory - // this could cause purgeAsNeeded() into an infinite loop (e.g. - // each resource destroyed creates and locks 2 resources and - // unlocks 1 thereby causing a new purge). - SkASSERT(!fPurging); - GrAutoResourceCacheValidate atcv(this); - - GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, resource)); - resource->cacheAccess().setCacheEntry(entry); - - this->attachToHead(entry); - this->purgeAsNeeded(); - return true; -} - -void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountInc) { - fEntryBytes += amountInc; - this->purgeAsNeeded(); -} - -void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountDec) { - fEntryBytes -= amountDec; -#ifdef SK_DEBUG - this->validate(); -#endif -} - -/** - * Destroying a resource may potentially trigger the unlock of additional - * resources which in turn will trigger a nested purge. We block the nested - * purge using the fPurging variable. However, the initial purge will keep - * looping until either all resources in the cache are unlocked or we've met - * the budget. There is an assertion in createAndLock to check against a - * resource's destructor inserting new resources into the cache. If these - * new resources were unlocked before purgeAsNeeded completed it could - * potentially make purgeAsNeeded loop infinitely. - * - * extraCount and extraBytes are added to the current resource totals to account - * for incoming resources (e.g., GrContext is about to add 10MB split between - * 10 textures). - */ -void GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) { - if (fPurging) { - return; - } - - fPurging = true; - - this->internalPurge(extraCount, extraBytes); - if (((fEntryCount+extraCount) > fMaxCount || - (fEntryBytes+extraBytes) > fMaxBytes) && - fOverbudgetCB) { - // Despite the purge we're still over budget. See if Ganesh can - // release some resources and purge again. - if ((*fOverbudgetCB)(fOverbudgetData)) { - this->internalPurge(extraCount, extraBytes); - } - } - - fPurging = false; -} - -void GrResourceCache::purgeInvalidated() { - // TODO: Implement this in GrResourceCache2. -} - -void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) { - SkASSERT(entry->fResource->isPurgable()); - // remove from our llist - this->internalDetach(entry); - delete entry; -} - -void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) { - SkASSERT(fPurging); - - bool withinBudget = false; - bool changed = false; - - // The purging process is repeated several times since one pass - // may free up other resources - do { - EntryList::Iter iter; - - changed = false; - - // Note: the following code relies on the fact that the - // doubly linked list doesn't invalidate its data/pointers - // outside of the specific area where a deletion occurs (e.g., - // in internalDetach) - GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart); - - while (entry) { - GrAutoResourceCacheValidate atcv(this); - - if ((fEntryCount+extraCount) <= fMaxCount && - (fEntryBytes+extraBytes) <= fMaxBytes) { - withinBudget = true; - break; - } - - GrResourceCacheEntry* prev = iter.prev(); - if (entry->fResource->isPurgable()) { - changed = true; - this->deleteResource(entry); - } - entry = prev; - } - } while (!withinBudget && changed); -} - -void GrResourceCache::purgeAllUnlocked() { - GrAutoResourceCacheValidate atcv(this); - - // we can have one GrCacheable holding a lock on another - // so we don't want to just do a simple loop kicking each - // entry out. Instead change the budget and purge. - - size_t savedMaxBytes = fMaxBytes; - int savedMaxCount = fMaxCount; - fMaxBytes = (size_t) -1; - fMaxCount = 0; - this->purgeAsNeeded(); - - fMaxBytes = savedMaxBytes; - fMaxCount = savedMaxCount; -} - -/////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_DEBUG -size_t GrResourceCache::countBytes(const EntryList& list) { - size_t bytes = 0; - - EntryList::Iter iter; - - const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(list), - EntryList::Iter::kTail_IterStart); - - for ( ; entry; entry = iter.prev()) { - bytes += entry->resource()->gpuMemorySize(); - } - return bytes; -} - -static bool both_zero_or_nonzero(int count, size_t bytes) { - return (count == 0 && bytes == 0) || (count > 0 && bytes > 0); -} - -void GrResourceCache::validate() const { - fList.validate(); - SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes)); - - EntryList::Iter iter; - - // check that the shareable entries are okay - const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fList), - EntryList::Iter::kHead_IterStart); - - int count = 0; - for ( ; entry; entry = iter.next()) { - entry->validate(); - count += 1; - } - SkASSERT(count == fEntryCount); - - size_t bytes = this->countBytes(fList); - SkASSERT(bytes == fEntryBytes); - SkASSERT(fList.countEntries() == fEntryCount); -} -#endif // SK_DEBUG - -#if GR_CACHE_STATS - -void GrResourceCache::printStats() { - int locked = 0; - int scratch = 0; - - EntryList::Iter iter; - - GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart); - - for ( ; entry; entry = iter.prev()) { - if (!entry->fResource->isPurgable()) { - ++locked; - } - if (entry->fResource->cacheAccess().isScratch()) { - ++scratch; - } - } - - float countUtilization = (100.f * fEntryCount) / fMaxCount; - float byteUtilization = (100.f * fEntryBytes) / fMaxBytes; - - SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); - SkDebugf("\t\tEntry Count: current %d (%d locked, %d scratch %.2g%% full), high %d\n", - fEntryCount, locked, scratch, countUtilization, fHighWaterEntryCount); - SkDebugf("\t\tEntry Bytes: current %d (%.2g%% full) high %d\n", - fEntryBytes, byteUtilization, fHighWaterEntryBytes); -} - -#endif - -/////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h deleted file mode 100644 index 80e4b3f1e4..0000000000 --- a/src/gpu/GrResourceCache.h +++ /dev/null @@ -1,251 +0,0 @@ - -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrResourceCache_DEFINED -#define GrResourceCache_DEFINED - -#include "GrDrawTargetCaps.h" -#include "GrResourceKey.h" -#include "SkTMultiMap.h" -#include "SkMessageBus.h" -#include "SkTInternalLList.h" - -class GrGpuResource; -class GrResourceCache; -class GrResourceCacheEntry; - - -// The cache listens for these messages to purge junk resources proactively. -struct GrResourceInvalidatedMessage { - GrResourceKey key; -}; - -/////////////////////////////////////////////////////////////////////////////// - -class GrResourceCacheEntry { -public: - GrGpuResource* resource() const { return fResource; } - - static uint32_t Hash(const GrGpuResource* resource) { - return static_cast<uint32_t>(reinterpret_cast<intptr_t>(resource)); - } -#ifdef SK_DEBUG - void validate() const; -#else - void validate() const {} -#endif - - /** - * Update the cached size for this entry and inform the resource cache that - * it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize, - * not directly from here. - */ - void didChangeResourceSize(); - -private: - GrResourceCacheEntry(GrResourceCache*, GrGpuResource*); - ~GrResourceCacheEntry(); - - GrResourceCache* fResourceCache; - GrGpuResource* fResource; - size_t fCachedSize; - - // Linked list for the LRU ordering. - SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry); - - friend class GrResourceCache; - friend class GrContext; -}; - -/////////////////////////////////////////////////////////////////////////////// - -/** - * Cache of GrGpuResource objects. - * - * These have a corresponding GrResourceKey, built from 128bits identifying the - * resource. Multiple resources can map to same GrResourceKey. - * - * The cache stores the entries in a double-linked list, which is its LRU. - * When an entry is "locked" (i.e. given to the caller), it is moved to the - * head of the list. If/when we must purge some of the entries, we walk the - * list backwards from the tail, since those are the least recently used. - * - * For fast searches, we maintain a hash map based on the GrResourceKey. - * - * It is a goal to make the GrResourceCache the central repository and bookkeeper - * of all resources. It should replace the linked list of GrGpuResources that - * GrGpu uses to call abandon/release. - */ -class GrResourceCache { -public: - GrResourceCache(const GrDrawTargetCaps*, int maxCount, size_t maxBytes); - ~GrResourceCache(); - - /** - * Return the current resource cache limits. - * - * @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. - */ - void getLimits(int* maxResources, size_t* maxBytes) const; - - /** - * Specify the resource cache limits. If the current cache exceeds either - * of these, it will be purged (LRU) to keep the cache within these limits. - * - * @param maxResources The maximum number of resources that can be held in - * the cache. - * @param maxBytes The maximum number of bytes of resource memory that - * can be held in the cache. - */ - void setLimits(int maxResources, size_t maxResourceBytes); - - /** - * The callback function used by the cache when it is still over budget - * after a purge. The passed in 'data' is the same 'data' handed to - * setOverbudgetCallback. The callback returns true if some resources - * have been freed. - */ - typedef bool (*PFOverbudgetCB)(void* data); - - /** - * 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. Note that the cache will attempt to purge any resources newly - * freed by the callback. - */ - void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) { - fOverbudgetCB = overbudgetCB; - fOverbudgetData = data; - } - - /** - * Returns the number of bytes consumed by cached resources. - */ - size_t getCachedResourceBytes() const { return fEntryBytes; } - - /** - * Returns the number of cached resources. - */ - int getCachedResourceCount() const { return fEntryCount; } - - void makeResourceMRU(GrGpuResource*); - - /** Called by GrGpuResources when they detects that they are newly purgable. */ - void notifyPurgable(const GrGpuResource*); - - /** - * Add the new resource to the cache (by creating a new cache entry based - * on the provided key and resource). - * - * Ownership of the resource is transferred to the resource cache, - * which will unref() it when it is purged or deleted. - * - * This can fail if the key is already taken, or the resource is already in - * the cache. - */ - bool addResource(const GrResourceKey& key, GrGpuResource* resource); - - /** - * Notify the cache that the size of a resource has changed. - */ - void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc); - void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec); - - /** - * Remove a resource from the cache and delete it! - */ - void deleteResource(GrResourceCacheEntry* 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. 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, - * 10MB across 10 textures is about to be added). - */ - void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0); - -#ifdef SK_DEBUG - void validate() const; -#else - void validate() const {} -#endif - -#if GR_CACHE_STATS - void printStats(); -#endif - -private: - void internalDetach(GrResourceCacheEntry*); - void attachToHead(GrResourceCacheEntry*); - void purgeInvalidated(); - void internalPurge(int extraCount, size_t extraBytes); -#ifdef SK_DEBUG - static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list); -#endif - - // We're an internal doubly linked list - typedef SkTInternalLList<GrResourceCacheEntry> EntryList; - EntryList fList; - - // our budget, used in purgeAsNeeded() - int fMaxCount; - size_t fMaxBytes; - - // our current stats, related to our budget -#if GR_CACHE_STATS - int fHighWaterEntryCount; - size_t fHighWaterEntryBytes; -#endif - - int fEntryCount; - size_t fEntryBytes; - - // prevents recursive purging - bool fPurging; - - PFOverbudgetCB fOverbudgetCB; - void* fOverbudgetData; - - SkAutoTUnref<const GrDrawTargetCaps> fCaps; -}; - -/////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_DEBUG - class GrAutoResourceCacheValidate { - public: - GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) { - cache->validate(); - } - ~GrAutoResourceCacheValidate() { - fCache->validate(); - } - private: - GrResourceCache* fCache; - }; -#else - class GrAutoResourceCacheValidate { - public: - GrAutoResourceCacheValidate(GrResourceCache*) {} - }; -#endif - -#endif diff --git a/src/gpu/GrResourceCache2.cpp b/src/gpu/GrResourceCache2.cpp index 83143d7818..109e815dac 100644 --- a/src/gpu/GrResourceCache2.cpp +++ b/src/gpu/GrResourceCache2.cpp @@ -10,6 +10,13 @@ #include "GrResourceCache2.h" #include "GrGpuResource.h" +#include "SkGr.h" +#include "SkMessageBus.h" + +DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage); + +////////////////////////////////////////////////////////////////////////////// + GrResourceKey& GrResourceKey::NullScratchKey() { static const GrCacheID::Key kBogusKey = { { {0} } }; static GrCacheID kBogusID(ScratchDomain(), kBogusKey); @@ -27,26 +34,85 @@ GrCacheID::Domain GrResourceKey::ScratchDomain() { return gDomain; } +GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { + static int32_t gNextType = 0; + + int32_t type = sk_atomic_inc(&gNextType); + if (type >= (1 << 8 * sizeof(ResourceType))) { + SkFAIL("Too many Resource Types"); + } + + return static_cast<ResourceType>(type); +} + ////////////////////////////////////////////////////////////////////////////// +class GrResourceCache2::AutoValidate : ::SkNoncopyable { +public: + AutoValidate(GrResourceCache2* cache) : fCache(cache) { cache->validate(); } + ~AutoValidate() { fCache->validate(); } +private: + GrResourceCache2* fCache; +}; + + ////////////////////////////////////////////////////////////////////////////// + +static const int kDefaultMaxCount = 2 * (1 << 10); +static const size_t kDefaultMaxSize = 96 * (1 << 20); + +GrResourceCache2::GrResourceCache2() + : fMaxCount(kDefaultMaxCount) + , fMaxBytes(kDefaultMaxSize) +#if GR_CACHE_STATS + , fHighWaterCount(0) + , fHighWaterBytes(0) +#endif + , fCount(0) + , fBytes(0) + , fPurging(false) + , fNewlyPurgableResourceWhilePurging(false) + , fOverBudgetCB(NULL) + , fOverBudgetData(NULL) { +} + GrResourceCache2::~GrResourceCache2() { this->releaseAll(); } +void GrResourceCache2::setLimits(int count, size_t bytes) { + fMaxCount = count; + fMaxBytes = bytes; + this->purgeAsNeeded(); +} + void GrResourceCache2::insertResource(GrGpuResource* resource) { + AutoValidate av(this); + SkASSERT(resource); SkASSERT(!resource->wasDestroyed()); SkASSERT(!this->isInCache(resource)); + SkASSERT(!fPurging); fResources.addToHead(resource); + resource->ref(); + ++fCount; + SkDEBUGCODE(fHighWaterCount = SkTMax(fCount, fHighWaterCount)); + fBytes += resource->gpuMemorySize(); + SkDEBUGCODE(fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes)); if (!resource->cacheAccess().getScratchKey().isNullScratch()) { // TODO(bsalomon): Make this assertion possible. // SkASSERT(!resource->isWrapped()); fScratchMap.insert(resource->cacheAccess().getScratchKey(), resource); } + + this->purgeAsNeeded(); } void GrResourceCache2::removeResource(GrGpuResource* resource) { + AutoValidate av(this); + + --fCount; + fBytes -= resource->gpuMemorySize(); SkASSERT(this->isInCache(resource)); fResources.remove(resource); if (!resource->cacheAccess().getScratchKey().isNullScratch()) { @@ -55,13 +121,16 @@ void GrResourceCache2::removeResource(GrGpuResource* resource) { if (const GrResourceKey* contentKey = resource->cacheAccess().getContentKey()) { fContentHash.remove(*contentKey); } - --fCount; } void GrResourceCache2::abandonAll() { + AutoValidate av(this); + + SkASSERT(!fPurging); while (GrGpuResource* head = fResources.head()) { SkASSERT(!head->wasDestroyed()); head->abandon(); + head->unref(); // abandon should have already removed this from the list. SkASSERT(head != fResources.head()); } @@ -71,9 +140,13 @@ void GrResourceCache2::abandonAll() { } void GrResourceCache2::releaseAll() { + AutoValidate av(this); + + SkASSERT(!fPurging); while (GrGpuResource* head = fResources.head()) { SkASSERT(!head->wasDestroyed()); head->release(); + head->unref(); // release should have already removed this from the list. SkASSERT(head != fResources.head()); } @@ -99,11 +172,16 @@ private: GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey& scratchKey, uint32_t flags) { + AutoValidate av(this); + + SkASSERT(!fPurging); SkASSERT(scratchKey.isScratch()); + GrGpuResource* resource; if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) { - GrGpuResource* resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); + resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); if (resource) { + this->makeResourceMRU(resource); return SkRef(resource); } else if (flags & kRequireNoPendingIO_ScratchFlag) { return NULL; @@ -111,11 +189,18 @@ GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey& // TODO: fail here when kPrefer is specified, we didn't find a resource without pending io, // but there is still space in our budget for the resource. } - return SkSafeRef(fScratchMap.find(scratchKey, AvailableForScratchUse(false))); + resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false)); + if (resource) { + resource->ref(); + this->makeResourceMRU(resource); + } + return resource; } bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) { + SkASSERT(!fPurging); SkASSERT(resource); + SkASSERT(this->isInCache(resource)); SkASSERT(resource->cacheAccess().getContentKey()); SkASSERT(!resource->cacheAccess().getContentKey()->isScratch()); @@ -125,5 +210,214 @@ bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) { } fContentHash.add(resource); + this->validate(); return true; } + +void GrResourceCache2::makeResourceMRU(GrGpuResource* resource) { + AutoValidate av(this); + + SkASSERT(!fPurging); + SkASSERT(resource); + SkASSERT(this->isInCache(resource)); + fResources.remove(resource); + fResources.addToHead(resource); +} + +void GrResourceCache2::notifyPurgable(const GrGpuResource* resource) { + SkASSERT(resource); + SkASSERT(this->isInCache(resource)); + SkASSERT(resource->isPurgable()); + + // We can't purge if in the middle of purging because purge is iterating. Instead record + // that additional resources became purgable. + if (fPurging) { + fNewlyPurgableResourceWhilePurging = true; + return; + } + + // Purge the resource if we're over budget + bool overBudget = fCount > fMaxCount || fBytes > fMaxBytes; + + // We should not be over budget here unless all resources are unpuragble. +#ifdef SK_DEBUG + if (overBudget) { + ResourceList::Iter iter; + GrGpuResource* r = iter.init(fResources, ResourceList::Iter::kHead_IterStart); + for ( ; r; r = iter.next()) { + SkASSERT(r == resource || !r->isPurgable()); + } + } +#endif + + // Also purge if the resource has neither a valid scratch key nor a content key. + bool noKey = !resource->cacheAccess().isScratch() && + (NULL == resource->cacheAccess().getContentKey()); + + if (overBudget || noKey) { + SkDEBUGCODE(int beforeCount = fCount;) + resource->unref(); + SkASSERT(fCount == beforeCount - 1); + } + + this->validate(); +} + +void GrResourceCache2::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) { + // SkASSERT(!fPurging); GrPathRange increases size during flush. :( + SkASSERT(resource); + SkASSERT(this->isInCache(resource)); + + fBytes += resource->gpuMemorySize() - oldSize; + SkDEBUGCODE(fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes)); + + this->purgeAsNeeded(); + this->validate(); +} + +void GrResourceCache2::internalPurgeAsNeeded() { + SkASSERT(!fPurging); + SkASSERT(!fNewlyPurgableResourceWhilePurging); + SkASSERT(fCount > fMaxCount || fBytes > fMaxBytes); + + fPurging = true; + + AutoValidate av(this); // Put this after setting fPurging so we're allowed to be over budget. + + bool overBudget = true; + do { + fNewlyPurgableResourceWhilePurging = false; + ResourceList::Iter resourceIter; + GrGpuResource* resource = resourceIter.init(fResources, + ResourceList::Iter::kTail_IterStart); + + while (resource) { + GrGpuResource* prev = resourceIter.prev(); + if (resource->isPurgable()) { + resource->unref(); + } + resource = prev; + if (fCount <= fMaxCount && fBytes <= fMaxBytes) { + overBudget = false; + resource = NULL; + } + } + + if (!fNewlyPurgableResourceWhilePurging && overBudget && fOverBudgetCB) { + // Despite the purge we're still over budget. Call our over budget callback. + (*fOverBudgetCB)(fOverBudgetData); + } + } while (overBudget && fNewlyPurgableResourceWhilePurging); + + fNewlyPurgableResourceWhilePurging = false; + fPurging = false; +} + +void GrResourceCache2::purgeAllUnlocked() { + SkASSERT(!fPurging); + SkASSERT(!fNewlyPurgableResourceWhilePurging); + + fPurging = true; + + AutoValidate av(this); // Put this after setting fPurging so we're allowed to be over budget. + + do { + fNewlyPurgableResourceWhilePurging = false; + ResourceList::Iter resourceIter; + GrGpuResource* resource = + resourceIter.init(fResources, ResourceList::Iter::kTail_IterStart); + + while (resource) { + GrGpuResource* prev = resourceIter.prev(); + if (resource->isPurgable()) { + resource->unref(); + } + resource = prev; + } + + if (!fNewlyPurgableResourceWhilePurging && fCount && fOverBudgetCB) { + (*fOverBudgetCB)(fOverBudgetData); + } + } while (fNewlyPurgableResourceWhilePurging); + fPurging = false; +} + +#ifdef SK_DEBUG +void GrResourceCache2::validate() const { + size_t bytes = 0; + int count = 0; + int locked = 0; + int scratch = 0; + int couldBeScratch = 0; + int content = 0; + + ResourceList::Iter iter; + GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_IterStart); + for ( ; resource; resource = iter.next()) { + bytes += resource->gpuMemorySize(); + ++count; + + if (!resource->isPurgable()) { + ++locked; + } + + if (resource->cacheAccess().isScratch()) { + SkASSERT(NULL == resource->cacheAccess().getContentKey()); + ++scratch; + SkASSERT(fScratchMap.countForKey(resource->cacheAccess().getScratchKey())); + } else if (!resource->cacheAccess().getScratchKey().isNullScratch()) { + SkASSERT(NULL != resource->cacheAccess().getContentKey()); + ++couldBeScratch; + SkASSERT(fScratchMap.countForKey(resource->cacheAccess().getScratchKey())); + } + + if (const GrResourceKey* contentKey = resource->cacheAccess().getContentKey()) { + ++content; + SkASSERT(fContentHash.find(*contentKey) == resource); + } + } + + SkASSERT(bytes == fBytes); + SkASSERT(count == fCount); +#if GR_CACHE_STATS + SkASSERT(bytes <= fHighWaterBytes); + SkASSERT(count <= fHighWaterCount); +#endif + SkASSERT(content == fContentHash.count()); + SkASSERT(scratch + couldBeScratch == fScratchMap.count()); + + bool overBudget = bytes > fMaxBytes || count > fMaxCount; + SkASSERT(!overBudget || locked == count || fPurging); +} +#endif + +#if GR_CACHE_STATS +void GrResourceCache2::printStats() const { + this->validate(); + + int locked = 0; + int scratch = 0; + + ResourceList::Iter iter; + GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_IterStart); + + for ( ; resource; resource = iter.next()) { + if (!resource->isPurgable()) { + ++locked; + } + if (resource->cacheAccess().isScratch()) { + ++scratch; + } + } + + float countUtilization = (100.f * fCount) / fMaxCount; + float byteUtilization = (100.f * fBytes) / fMaxBytes; + + SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); + SkDebugf("\t\tEntry Count: current %d (%d locked, %d scratch %.2g%% full), high %d\n", + fCount, locked, scratch, countUtilization, fHighWaterCount); + SkDebugf("\t\tEntry Bytes: current %d (%.2g%% full) high %d\n", + fBytes, byteUtilization, fHighWaterBytes); +} + +#endif diff --git a/src/gpu/GrResourceCache2.h b/src/gpu/GrResourceCache2.h index 1cc958799d..8b4d1d0e67 100644 --- a/src/gpu/GrResourceCache2.h +++ b/src/gpu/GrResourceCache2.h @@ -17,27 +17,65 @@ #include "SkTMultiMap.h" /** - * Eventual replacement for GrResourceCache. Currently it simply holds a list - * of all GrGpuResource objects for a GrContext. It is used to invalidate all - * the resources when necessary. + * Manages the lifetime of all GrGpuResource instances. + * + * Resources may have optionally have two types of keys: + * 1) A scratch key. This is for resources whose allocations are cached but not their contents. + * Multiple resources can share the same scratch key. This is so a caller can have two + * resource instances with the same properties (e.g. multipass rendering that ping pongs + * between two temporary surfaces. The scratch key is set at resource creation time and + * should never change. Resources need not have a scratch key. + * 2) A content key. This key represents the contents of the resource rather than just its + * allocation properties. They may not collide. The content key can be set after resource + * creation. Currently it may only be set once and cannot be cleared. This restriction will + * be removed. + * If a resource has neither key type then it will be deleted as soon as the last reference to it + * is dropped. If a key has both keys the content key takes precedence. */ class GrResourceCache2 { public: - GrResourceCache2() : fCount(0) {}; + GrResourceCache2(); ~GrResourceCache2(); - void insertResource(GrGpuResource*); + /** Used to access functionality needed by GrGpuResource for lifetime management. */ + class ResourceAccess; + ResourceAccess resourceAccess(); - void removeResource(GrGpuResource*); + /** + * Sets the cache limits in terms of number of resources and max gpu memory byte size. + */ + void setLimits(int count, size_t bytes); - // This currently returns a bool and fails when an existing resource has a key that collides - // with the new content key. In the future it will null out the content key for the existing - // resource. The failure is a temporary measure taken because duties are split between two - // cache objects currently. - bool didSetContentKey(GrGpuResource*); + /** + * Returns the number of cached resources. + */ + int getResourceCount() const { return fCount; } + + /** + * Returns the number of bytes consumed by cached resources. + */ + size_t getResourceBytes() const { return fBytes; } + + /** + * Returns the cached resources count budget. + */ + int getMaxResourceCount() const { return fMaxCount; } + /** + * Returns the number of bytes consumed by cached resources. + */ + size_t getMaxResourceBytes() const { return fMaxBytes; } + + /** + * Abandons the backend API resources owned by all GrGpuResource objects and removes them from + * the cache. + */ void abandonAll(); + /** + * Releases the backend API resources owned by all GrGpuResource objects and removes them from + * the cache. + */ void releaseAll(); enum { @@ -46,6 +84,10 @@ public: /** Will not return any resources that match but have pending IO. */ kRequireNoPendingIO_ScratchFlag = 0x2, }; + + /** + * Find a resource that matches a scratch key. + */ GrGpuResource* findAndRefScratchResource(const GrResourceKey& scratchKey, uint32_t flags = 0); #ifdef SK_DEBUG @@ -56,21 +98,80 @@ public: } #endif + /** + * Find a resource that matches a content key. + */ GrGpuResource* findAndRefContentResource(const GrResourceKey& contentKey) { SkASSERT(!contentKey.isScratch()); - return SkSafeRef(fContentHash.find(contentKey)); + GrGpuResource* resource = fContentHash.find(contentKey); + if (resource) { + resource->ref(); + this->makeResourceMRU(resource); + } + return resource; } + /** + * Query whether a content key exists in the cache. + */ bool hasContentKey(const GrResourceKey& contentKey) const { SkASSERT(!contentKey.isScratch()); return SkToBool(fContentHash.find(contentKey)); } + /** Purges all resources that don't have external owners. */ + void purgeAllUnlocked(); + + /** + * The callback function used by the cache when it is still over budget after a purge. The + * passed in 'data' is the same 'data' handed to setOverbudgetCallback. + */ + typedef void (*PFOverBudgetCB)(void* data); + + /** + * 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. Note that the cache will attempt to purge + * any resources newly freed by the callback. + */ + void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) { + fOverBudgetCB = overBudgetCB; + fOverBudgetData = data; + } + +#if GR_GPU_STATS + void printStats() const; +#endif + private: + /////////////////////////////////////////////////////////////////////////// + /// @name Methods accessible via ResourceAccess + //// + void insertResource(GrGpuResource*); + void removeResource(GrGpuResource*); + void notifyPurgable(const GrGpuResource*); + void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize); + bool didSetContentKey(GrGpuResource*); + void makeResourceMRU(GrGpuResource*); + /// @} + + void purgeAsNeeded() { + if (fPurging || (fCount <= fMaxCount && fBytes < fMaxBytes)) { + return; + } + this->internalPurgeAsNeeded(); + } + + void internalPurgeAsNeeded(); + #ifdef SK_DEBUG bool isInCache(const GrGpuResource* r) const { return fResources.isInList(r); } + void validate() const; +#else + void validate() const {} #endif + class AutoValidate; + class AvailableForScratchUse; struct ScratchMapTraits { @@ -91,12 +192,86 @@ private: }; typedef SkTDynamicHash<GrGpuResource, GrResourceKey, ContentHashTraits> ContentHash; - int fCount; - SkTInternalLList<GrGpuResource> fResources; + typedef SkTInternalLList<GrGpuResource> ResourceList; + + ResourceList fResources; // This map holds all resources that can be used as scratch resources. ScratchMap fScratchMap; // This holds all resources that have content keys. ContentHash fContentHash; + + // our budget, used in purgeAsNeeded() + int fMaxCount; + size_t fMaxBytes; + +#if GR_CACHE_STATS + int fHighWaterCount; + size_t fHighWaterBytes; +#endif + + // our current stats, related to our budget + int fCount; + size_t fBytes; + + // prevents recursive purging + bool fPurging; + bool fNewlyPurgableResourceWhilePurging; + + PFOverBudgetCB fOverBudgetCB; + void* fOverBudgetData; + }; +class GrResourceCache2::ResourceAccess { +private: + ResourceAccess(GrResourceCache2* cache) : fCache(cache) { } + ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { } + ResourceAccess& operator=(const ResourceAccess&); // unimpl + + /** + * Insert a resource into the cache. + */ + void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); } + + /** + * Removes a resource from the cache. + */ + void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); } + + /** + * Called by GrGpuResources when they detects that they are newly purgable. + */ + void notifyPurgable(const GrGpuResource* resource) { fCache->notifyPurgable(resource); } + + /** + * Called by GrGpuResources when their sizes change. + */ + void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) { + fCache->didChangeGpuMemorySize(resource, oldSize); + } + + /** + * Called by GrGpuResources when their content keys change. + * + * This currently returns a bool and fails when an existing resource has a key that collides + * with the new content key. In the future it will null out the content key for the existing + * resource. The failure is a temporary measure taken because duties are split between two + * cache objects currently. + */ + bool didSetContentKey(GrGpuResource* resource) { return fCache->didSetContentKey(resource); } + + // No taking addresses of this type. + const ResourceAccess* operator&() const; + ResourceAccess* operator&(); + + GrResourceCache2* fCache; + + friend class GrGpuResource; // To access all the proxy inline methods. + friend class GrResourceCache2; // To create this type. +}; + +inline GrResourceCache2::ResourceAccess GrResourceCache2::resourceAccess() { + return ResourceAccess(this); +} + #endif diff --git a/src/gpu/GrStencilBuffer.cpp b/src/gpu/GrStencilBuffer.cpp index b288415301..16b0150a4d 100644 --- a/src/gpu/GrStencilBuffer.cpp +++ b/src/gpu/GrStencilBuffer.cpp @@ -13,8 +13,6 @@ #include "GrResourceCache2.h" void GrStencilBuffer::transferToCache() { - SkASSERT(!this->cacheAccess().isInCache()); - this->getGpu()->getContext()->addStencilBuffer(this); } diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp index 611059ae4c..528698478a 100644 --- a/src/gpu/GrTest.cpp +++ b/src/gpu/GrTest.cpp @@ -9,7 +9,7 @@ #include "GrTest.h" #include "GrInOrderDrawBuffer.h" -#include "GrResourceCache.h" +#include "GrResourceCache2.h" void GrTestTarget::init(GrContext* ctx, GrDrawTarget* target) { SkASSERT(!fContext); @@ -38,7 +38,7 @@ void GrContext::setMaxTextureSizeOverride(int maxTextureSizeOverride) { } void GrContext::purgeAllUnlockedResources() { - fResourceCache->purgeAllUnlocked(); + fResourceCache2->purgeAllUnlocked(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp index 58bbeaae42..9f700c7556 100644 --- a/src/gpu/GrTexture.cpp +++ b/src/gpu/GrTexture.cpp @@ -9,7 +9,6 @@ #include "GrContext.h" #include "GrDrawTargetCaps.h" #include "GrGpu.h" -#include "GrResourceCache.h" #include "GrTexture.h" #include "GrTexturePriv.h" diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index affbd956b0..a86ee60317 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -12,7 +12,6 @@ #include "SkMessageBus.h" #include "SkPixelRef.h" #include "SkTextureCompressor.h" -#include "GrResourceCache.h" #include "GrGpu.h" #include "effects/GrDitherEffect.h" #include "GrDrawTargetCaps.h" |