aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2014-11-13 13:19:10 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-11-13 13:19:10 -0800
commit66a450f21a3da174b7eed89a1d5fc8591e8b6ee6 (patch)
tree97170b6b7e193001f9afbf6a99980dd355de2bda /src
parentbc97c9378bf8b89cc17280a2a04a5c3a9405e6ab (diff)
Replace GrResourceCache with GrResourceCache2.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/gpu/GrAADistanceFieldPathRenderer.h1
-rwxr-xr-xsrc/gpu/GrContext.cpp143
-rw-r--r--src/gpu/GrGpuResource.cpp33
-rw-r--r--src/gpu/GrGpuResourceCacheAccess.h19
-rw-r--r--src/gpu/GrPath.h1
-rw-r--r--src/gpu/GrPathRange.h1
-rw-r--r--src/gpu/GrResourceCache.cpp393
-rw-r--r--src/gpu/GrResourceCache.h251
-rw-r--r--src/gpu/GrResourceCache2.cpp300
-rw-r--r--src/gpu/GrResourceCache2.h203
-rw-r--r--src/gpu/GrStencilBuffer.cpp2
-rw-r--r--src/gpu/GrTest.cpp4
-rw-r--r--src/gpu/GrTexture.cpp1
-rw-r--r--src/gpu/SkGr.cpp1
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"