Revert of Replace GrResourceCache with GrResourceCache2. (patchset #6 id:100001 of https://codereview.chromium.org/716143004/)
Reason for revert: Breaking stuff Original issue's description: > Replace GrResourceCache with GrResourceCache2. > > BUG=skia:2889 > > Committed: https://skia.googlesource.com/skia/+/66a450f21a3da174b7eed89a1d5fc8591e8b6ee6 TBR=robertphillips@google.com NOTREECHECKS=true NOTRY=true BUG=skia:2889 Review URL: https://codereview.chromium.org/715333003
This commit is contained in:
parent
66a450f21a
commit
f21dab9540
@ -13,6 +13,7 @@
|
||||
#include "GrGpuResource.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "GrResourceCache2.h"
|
||||
#include "GrStencilBuffer.h"
|
||||
#include "GrTexture.h"
|
||||
@ -88,20 +89,22 @@ static void get_stencil(int i, int* w, int* h, int* s) {
|
||||
}
|
||||
|
||||
static void get_texture_desc(int i, GrSurfaceDesc* desc) {
|
||||
desc->fFlags = kRenderTarget_GrSurfaceFlag | kNoStencil_GrSurfaceFlag;
|
||||
desc->fFlags = kRenderTarget_GrSurfaceFlag |
|
||||
kNoStencil_GrSurfaceFlag;
|
||||
desc->fWidth = i % 1024;
|
||||
desc->fHeight = i * 2 % 1024;
|
||||
desc->fConfig = static_cast<GrPixelConfig>(i % (kLast_GrPixelConfig + 1));
|
||||
desc->fSampleCnt = ((i % 2) == 0) ? 0 : 4;
|
||||
desc->fSampleCnt = i % 1 == 0 ? 0 : 4;
|
||||
}
|
||||
|
||||
static void populate_cache(GrGpu* gpu, int resourceCount) {
|
||||
static void populate_cache(GrResourceCache* cache, GrGpu* gpu, int resourceCount) {
|
||||
for (int i = 0; i < resourceCount; ++i) {
|
||||
int w, h, s;
|
||||
get_stencil(i, &w, &h, &s);
|
||||
GrResourceKey key = GrStencilBuffer::ComputeKey(w, h, s);
|
||||
GrGpuResource* resource = SkNEW_ARGS(StencilResource, (gpu, i));
|
||||
resource->cacheAccess().setContentKey(key);
|
||||
cache->purgeAsNeeded(1, resource->gpuMemorySize());
|
||||
cache->addResource(key, resource);
|
||||
resource->unref();
|
||||
}
|
||||
|
||||
@ -110,7 +113,8 @@ static void populate_cache(GrGpu* gpu, int resourceCount) {
|
||||
get_texture_desc(i, &desc);
|
||||
GrResourceKey key = TextureResource::ComputeKey(desc);
|
||||
GrGpuResource* resource = SkNEW_ARGS(TextureResource, (gpu, i));
|
||||
resource->cacheAccess().setContentKey(key);
|
||||
cache->purgeAsNeeded(1, resource->gpuMemorySize());
|
||||
cache->addResource(key, resource);
|
||||
resource->unref();
|
||||
}
|
||||
}
|
||||
@ -194,24 +198,25 @@ protected:
|
||||
// Set the cache budget to be very large so no purging occurs.
|
||||
context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30);
|
||||
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
|
||||
// Make sure the cache is empty.
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
GrGpu* gpu = context->getGpu();
|
||||
|
||||
for (int i = 0; i < loops; ++i) {
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
populate_cache(gpu, RESOURCE_COUNT);
|
||||
populate_cache(cache, gpu, RESOURCE_COUNT);
|
||||
|
||||
// Check that cache works.
|
||||
for (int k = 0; k < RESOURCE_COUNT; k += 33) {
|
||||
check_cache_contents_or_die(cache2, k);
|
||||
}
|
||||
cache2->purgeAllUnlocked();
|
||||
cache->purgeAllUnlocked();
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,15 +247,16 @@ protected:
|
||||
// Set the cache budget to be very large so no purging occurs.
|
||||
context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30);
|
||||
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
|
||||
// Make sure the cache is empty.
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
GrGpu* gpu = context->getGpu();
|
||||
|
||||
populate_cache(gpu, RESOURCE_COUNT);
|
||||
populate_cache(cache, gpu, RESOURCE_COUNT);
|
||||
|
||||
for (int i = 0; i < loops; ++i) {
|
||||
for (int k = 0; k < RESOURCE_COUNT; ++k) {
|
||||
|
10
gyp/gpu.gyp
10
gyp/gpu.gyp
@ -63,6 +63,16 @@
|
||||
],
|
||||
},
|
||||
}],
|
||||
[ 'skia_resource_cache_mb_limit != 0', {
|
||||
'defines': [
|
||||
'GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT=<(skia_resource_cache_mb_limit)',
|
||||
],
|
||||
}],
|
||||
[ 'skia_resource_cache_count_limit != 0', {
|
||||
'defines': [
|
||||
'GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT=<(skia_resource_cache_count_limit)',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'conditions': [
|
||||
|
@ -136,6 +136,8 @@
|
||||
'<(skia_src_path)/gpu/GrRenderTarget.cpp',
|
||||
'<(skia_src_path)/gpu/GrReducedClip.cpp',
|
||||
'<(skia_src_path)/gpu/GrReducedClip.h',
|
||||
'<(skia_src_path)/gpu/GrResourceCache.cpp',
|
||||
'<(skia_src_path)/gpu/GrResourceCache.h',
|
||||
'<(skia_src_path)/gpu/GrResourceCache2.cpp',
|
||||
'<(skia_src_path)/gpu/GrResourceCache2.h',
|
||||
'<(skia_src_path)/gpu/GrStencil.cpp',
|
||||
|
@ -212,6 +212,24 @@ typedef unsigned __int64 uint64_t;
|
||||
#define GR_GEOM_BUFFER_MAP_THRESHOLD (1 << 15)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT gives a threshold (in megabytes) for the
|
||||
* maximum size of the texture cache in vram. The value is only a default and
|
||||
* can be overridden at runtime.
|
||||
*/
|
||||
#if !defined(GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT)
|
||||
#define GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT 96
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT specifies the maximum number of
|
||||
* textures the texture cache can hold in vram. The value is only a default and
|
||||
* can be overridden at runtime.
|
||||
*/
|
||||
#if !defined(GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT)
|
||||
#define GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT 2048
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GR_STROKE_PATH_RENDERING controls whether or not the GrStrokePathRenderer can be selected
|
||||
* as a path renderer. GrStrokePathRenderer is currently an experimental path renderer.
|
||||
|
@ -33,6 +33,7 @@ class GrOvalRenderer;
|
||||
class GrPath;
|
||||
class GrPathRenderer;
|
||||
class GrResourceEntry;
|
||||
class GrResourceCache;
|
||||
class GrResourceCache2;
|
||||
class GrStencilBuffer;
|
||||
class GrTestTarget;
|
||||
@ -882,6 +883,7 @@ public:
|
||||
GrDrawTarget* getTextTarget();
|
||||
const GrIndexBuffer* getQuadIndexBuffer() const;
|
||||
GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; }
|
||||
GrResourceCache* getResourceCache() { return fResourceCache; }
|
||||
GrResourceCache2* getResourceCache2() { return fResourceCache2; }
|
||||
|
||||
// Called by tests that draw directly to the context via GrDrawTarget
|
||||
@ -946,6 +948,7 @@ private:
|
||||
const GrClipData* fClip; // TODO: make this ref counted
|
||||
GrDrawState* fDrawState;
|
||||
|
||||
GrResourceCache* fResourceCache;
|
||||
GrResourceCache2* fResourceCache2;
|
||||
GrFontCache* fFontCache;
|
||||
SkAutoTDelete<GrLayerCache> fLayerCache;
|
||||
@ -957,6 +960,9 @@ private:
|
||||
GrIndexBufferAllocPool* fDrawBufferIBAllocPool;
|
||||
GrInOrderDrawBuffer* fDrawBuffer;
|
||||
|
||||
// Set by OverbudgetCB() to request that GrContext flush before exiting a draw.
|
||||
bool fFlushToReduceCacheSize;
|
||||
|
||||
GrAARectRenderer* fAARectRenderer;
|
||||
GrOvalRenderer* fOvalRenderer;
|
||||
|
||||
@ -983,9 +989,10 @@ private:
|
||||
void setupDrawBuffer();
|
||||
|
||||
class AutoRestoreEffects;
|
||||
class AutoCheckFlush;
|
||||
/// Sets the paint and returns the target to draw into. The paint can be NULL in which case the
|
||||
/// draw state is left unmodified.
|
||||
GrDrawTarget* prepareToDraw(const GrPaint*, AutoRestoreEffects*);
|
||||
GrDrawTarget* prepareToDraw(const GrPaint*, AutoRestoreEffects*, AutoCheckFlush*);
|
||||
|
||||
void internalDrawPath(GrDrawTarget* target, bool useAA, const SkPath& path,
|
||||
const GrStrokeInfo& stroke);
|
||||
@ -996,6 +1003,8 @@ private:
|
||||
size_t rowBytes,
|
||||
bool filter);
|
||||
|
||||
GrTexture* createNewScratchTexture(const GrSurfaceDesc& desc);
|
||||
|
||||
/**
|
||||
* These functions create premul <-> unpremul effects if it is possible to generate a pair
|
||||
* of effects that make a readToUPM->writeToPM->readToUPM cycle invariant. Otherwise, they
|
||||
@ -1006,9 +1015,9 @@ private:
|
||||
|
||||
/**
|
||||
* This callback allows the resource cache to callback into the GrContext
|
||||
* when the cache is still over budget after a purge.
|
||||
* when the cache is still overbudget after a purge.
|
||||
*/
|
||||
static void OverBudgetCB(void* data);
|
||||
static bool OverbudgetCB(void* data);
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
@ -16,6 +16,7 @@
|
||||
class GrContext;
|
||||
class GrGpu;
|
||||
class GrResourceCache2;
|
||||
class GrResourceCacheEntry;
|
||||
|
||||
/**
|
||||
* Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
|
||||
@ -125,7 +126,7 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for objects that can be kept in the GrResourceCache2.
|
||||
* Base class for objects that can be kept in the GrResourceCache.
|
||||
*/
|
||||
class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
|
||||
public:
|
||||
@ -256,6 +257,7 @@ private:
|
||||
|
||||
uint32_t fFlags;
|
||||
|
||||
GrResourceCacheEntry* fCacheEntry; // NULL if not in cache
|
||||
mutable size_t fGpuMemorySize;
|
||||
const uint32_t fUniqueID;
|
||||
|
||||
|
@ -19,4 +19,16 @@
|
||||
*/
|
||||
//#define GR_GEOM_BUFFER_MAP_THRESHOLD (1<<15)
|
||||
|
||||
/**
|
||||
* This gives a threshold in megabytes for the maximum size of the texture cache
|
||||
* in vram. The value is only a default and can be overridden at runtime.
|
||||
*/
|
||||
//#define GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT 96
|
||||
|
||||
/**
|
||||
* This specifies the maximum number of textures the texture cache can hold
|
||||
* in vram. The value is only a default and can be overridden at runtime.
|
||||
*/
|
||||
//#define GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT 2048
|
||||
|
||||
#endif
|
||||
|
@ -68,11 +68,6 @@ static inline GrColor SkColor2GrColorJustAlpha(SkColor c) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The cache listens for these messages to purge junk resources proactively.
|
||||
struct GrResourceInvalidatedMessage {
|
||||
GrResourceKey key;
|
||||
};
|
||||
|
||||
bool GrIsBitmapInCache(const GrContext*, const SkBitmap&, const GrTextureParams*);
|
||||
|
||||
GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams*);
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "GrRect.h"
|
||||
|
||||
#include "SkChecksum.h"
|
||||
#include "SkTDynamicHash.h"
|
||||
|
||||
class GrContext;
|
||||
class GrPlot;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "GrOvalRenderer.h"
|
||||
#include "GrPathRenderer.h"
|
||||
#include "GrPathUtils.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "GrResourceCache2.h"
|
||||
#include "GrSoftwarePathRenderer.h"
|
||||
#include "GrStencilBuffer.h"
|
||||
@ -51,6 +52,9 @@
|
||||
#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;
|
||||
|
||||
@ -62,6 +66,20 @@ 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;
|
||||
@ -85,11 +103,13 @@ 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();
|
||||
@ -110,8 +130,11 @@ 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));
|
||||
|
||||
@ -137,6 +160,9 @@ GrContext::~GrContext() {
|
||||
}
|
||||
|
||||
SkDELETE(fResourceCache2);
|
||||
fResourceCache2 = NULL;
|
||||
SkDELETE(fResourceCache);
|
||||
fResourceCache = NULL;
|
||||
SkDELETE(fFontCache);
|
||||
SkDELETE(fDrawBuffer);
|
||||
SkDELETE(fDrawBufferVBAllocPool);
|
||||
@ -175,6 +201,8 @@ void GrContext::abandonContext() {
|
||||
fAARectRenderer->reset();
|
||||
fOvalRenderer->reset();
|
||||
|
||||
fResourceCache->purgeAllUnlocked();
|
||||
|
||||
fFontCache->freeAll();
|
||||
fLayerCache->freeAll();
|
||||
}
|
||||
@ -193,6 +221,7 @@ void GrContext::freeGpuResources() {
|
||||
fAARectRenderer->reset();
|
||||
fOvalRenderer->reset();
|
||||
|
||||
fResourceCache->purgeAllUnlocked();
|
||||
fFontCache->freeAll();
|
||||
fLayerCache->freeAll();
|
||||
// a path renderer may be holding onto resources
|
||||
@ -201,12 +230,12 @@ void GrContext::freeGpuResources() {
|
||||
}
|
||||
|
||||
void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
|
||||
if (resourceCount) {
|
||||
*resourceCount = fResourceCache2->getResourceCount();
|
||||
}
|
||||
if (resourceBytes) {
|
||||
*resourceBytes = fResourceCache2->getResourceBytes();
|
||||
}
|
||||
if (resourceCount) {
|
||||
*resourceCount = fResourceCache->getCachedResourceCount();
|
||||
}
|
||||
if (resourceBytes) {
|
||||
*resourceBytes = fResourceCache->getCachedResourceBytes();
|
||||
}
|
||||
}
|
||||
|
||||
GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
|
||||
@ -244,13 +273,12 @@ 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());
|
||||
SkAssertResult(sb->cacheAccess().setContentKey(resourceKey));
|
||||
fResourceCache->addResource(resourceKey, sb);
|
||||
}
|
||||
|
||||
GrStencilBuffer* GrContext::findAndRefStencilBuffer(int width, int height, int sampleCnt) {
|
||||
@ -392,19 +420,25 @@ GrTexture* GrContext::createTexture(const GrTextureParams* params,
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
if (texture->cacheAccess().setContentKey(resourceKey)) {
|
||||
if (cacheKey) {
|
||||
*cacheKey = resourceKey;
|
||||
}
|
||||
} else {
|
||||
texture->unref();
|
||||
texture = NULL;
|
||||
fResourceCache->addResource(resourceKey, texture);
|
||||
|
||||
if (cacheKey) {
|
||||
*cacheKey = resourceKey;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@ -439,6 +473,7 @@ GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexM
|
||||
}
|
||||
GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key, scratchFlags);
|
||||
if (resource) {
|
||||
fResourceCache->makeResourceMRU(resource);
|
||||
return static_cast<GrSurface*>(resource)->asTexture();
|
||||
}
|
||||
|
||||
@ -461,17 +496,21 @@ GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexM
|
||||
desc.writable()->fFlags = origFlags;
|
||||
}
|
||||
|
||||
GrTexture* texture = fGpu->createTexture(*desc, NULL, 0);
|
||||
GrTexture* texture = this->createNewScratchTexture(*desc);
|
||||
SkASSERT(NULL == texture ||
|
||||
texture->cacheAccess().getScratchKey() == GrTexturePriv::ComputeScratchKey(*desc));
|
||||
return texture;
|
||||
}
|
||||
|
||||
void GrContext::OverBudgetCB(void* data) {
|
||||
// Flush the InOrderDrawBuffer to possibly free up some textures
|
||||
bool GrContext::OverbudgetCB(void* data) {
|
||||
SkASSERT(data);
|
||||
|
||||
GrContext* context = reinterpret_cast<GrContext*>(data);
|
||||
context->flush();
|
||||
|
||||
// Flush the InOrderDrawBuffer to possibly free up some textures
|
||||
context->fFlushToReduceCacheSize = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -483,16 +522,11 @@ GrTexture* GrContext::createUncachedTexture(const GrSurfaceDesc& descIn,
|
||||
}
|
||||
|
||||
void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
|
||||
if (maxTextures) {
|
||||
*maxTextures = fResourceCache2->getMaxResourceCount();
|
||||
}
|
||||
if (maxTextureBytes) {
|
||||
*maxTextureBytes = fResourceCache2->getMaxResourceBytes();
|
||||
}
|
||||
fResourceCache->getLimits(maxTextures, maxTextureBytes);
|
||||
}
|
||||
|
||||
void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
|
||||
fResourceCache2->setLimits(maxTextures, maxTextureBytes);
|
||||
fResourceCache->setLimits(maxTextures, maxTextureBytes);
|
||||
}
|
||||
|
||||
int GrContext::getMaxTextureSize() const {
|
||||
@ -548,8 +582,9 @@ 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);
|
||||
GrDrawTarget* target = this->prepareToDraw(NULL, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -681,7 +716,8 @@ void GrContext::drawRect(const GrPaint& paint,
|
||||
}
|
||||
|
||||
AutoRestoreEffects are;
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are);
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -791,7 +827,8 @@ void GrContext::drawRectToRect(const GrPaint& paint,
|
||||
const SkRect& localRect,
|
||||
const SkMatrix* localMatrix) {
|
||||
AutoRestoreEffects are;
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are);
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -854,9 +891,10 @@ void GrContext::drawVertices(const GrPaint& paint,
|
||||
const uint16_t indices[],
|
||||
int indexCount) {
|
||||
AutoRestoreEffects are;
|
||||
GrDrawTarget::AutoReleaseGeometry geo;
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope
|
||||
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are);
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -916,7 +954,8 @@ void GrContext::drawRRect(const GrPaint& paint,
|
||||
}
|
||||
|
||||
AutoRestoreEffects are;
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are);
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -942,7 +981,8 @@ void GrContext::drawDRRect(const GrPaint& paint,
|
||||
}
|
||||
|
||||
AutoRestoreEffects are;
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are);
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf);
|
||||
|
||||
GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
|
||||
|
||||
@ -974,7 +1014,8 @@ void GrContext::drawOval(const GrPaint& paint,
|
||||
}
|
||||
|
||||
AutoRestoreEffects are;
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are);
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -1061,7 +1102,8 @@ void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const GrStrok
|
||||
SkPoint pts[2];
|
||||
if (path.isLine(pts)) {
|
||||
AutoRestoreEffects are;
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are);
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -1097,7 +1139,8 @@ 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;
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are);
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget* target = this->prepareToDraw(&paint, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -1199,6 +1242,8 @@ 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,
|
||||
@ -1318,7 +1363,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);
|
||||
GrDrawTarget* drawTarget = this->prepareToDraw(NULL, NULL, NULL);
|
||||
GrDrawTarget::AutoGeometryAndStatePush agasp(drawTarget, GrDrawTarget::kReset_ASRInit,
|
||||
&matrix);
|
||||
GrDrawState* drawState = drawTarget->drawState();
|
||||
@ -1498,7 +1543,8 @@ void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
|
||||
SkASSERT(renderTarget);
|
||||
ASSERT_OWNED_RESOURCE(renderTarget);
|
||||
AutoRestoreEffects are;
|
||||
GrDrawTarget* target = this->prepareToDraw(NULL, &are);
|
||||
AutoCheckFlush acf(this);
|
||||
GrDrawTarget* target = this->prepareToDraw(NULL, &are, &acf);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -1516,7 +1562,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);
|
||||
GrDrawTarget* target = this->prepareToDraw(NULL, NULL, NULL);
|
||||
if (NULL == target) {
|
||||
return;
|
||||
}
|
||||
@ -1535,7 +1581,9 @@ void GrContext::flushSurfaceWrites(GrSurface* surface) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, AutoRestoreEffects* are) {
|
||||
GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint,
|
||||
AutoRestoreEffects* are,
|
||||
AutoCheckFlush* acf) {
|
||||
// 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() &&
|
||||
@ -1548,6 +1596,7 @@ GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, AutoRestoreEffects*
|
||||
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
|
||||
@ -1647,7 +1696,7 @@ void GrContext::setupDrawBuffer() {
|
||||
}
|
||||
|
||||
GrDrawTarget* GrContext::getTextTarget() {
|
||||
return this->prepareToDraw(NULL, NULL);
|
||||
return this->prepareToDraw(NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
|
||||
@ -1697,11 +1746,15 @@ const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
|
||||
}
|
||||
|
||||
void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResource* resource) {
|
||||
resource->cacheAccess().setContentKey(resourceKey);
|
||||
fResourceCache->addResource(resourceKey, resource);
|
||||
}
|
||||
|
||||
GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resourceKey) {
|
||||
return fResourceCache2->findAndRefContentResource(resourceKey);
|
||||
GrGpuResource* resource = fResourceCache2->findAndRefContentResource(resourceKey);
|
||||
if (resource) {
|
||||
fResourceCache->makeResourceMRU(resource);
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
||||
@ -1721,7 +1774,7 @@ void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#if GR_CACHE_STATS
|
||||
void GrContext::printCacheStats() const {
|
||||
fResourceCache2->printStats();
|
||||
fResourceCache->printStats();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -18,8 +18,16 @@ 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())
|
||||
@ -32,7 +40,7 @@ GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
|
||||
}
|
||||
|
||||
void GrGpuResource::registerWithCache() {
|
||||
get_resource_cache2(fGpu)->resourceAccess().insertResource(this);
|
||||
get_resource_cache2(fGpu)->insertResource(this);
|
||||
}
|
||||
|
||||
GrGpuResource::~GrGpuResource() {
|
||||
@ -43,18 +51,16 @@ GrGpuResource::~GrGpuResource() {
|
||||
void GrGpuResource::release() {
|
||||
if (fGpu) {
|
||||
this->onRelease();
|
||||
get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
|
||||
get_resource_cache2(fGpu)->removeResource(this);
|
||||
fGpu = NULL;
|
||||
fGpuMemorySize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GrGpuResource::abandon() {
|
||||
if (fGpu) {
|
||||
this->onAbandon();
|
||||
get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
|
||||
get_resource_cache2(fGpu)->removeResource(this);
|
||||
fGpu = NULL;
|
||||
fGpuMemorySize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,17 +80,6 @@ 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());
|
||||
@ -97,7 +92,7 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
|
||||
fContentKey = contentKey;
|
||||
fContentKeySet = true;
|
||||
|
||||
if (!get_resource_cache2(fGpu)->resourceAccess().didSetContentKey(this)) {
|
||||
if (!get_resource_cache2(fGpu)->didSetContentKey(this)) {
|
||||
fContentKeySet = false;
|
||||
return false;
|
||||
}
|
||||
@ -105,8 +100,8 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
|
||||
}
|
||||
|
||||
void GrGpuResource::notifyIsPurgable() const {
|
||||
if (!this->wasDestroyed()) {
|
||||
get_resource_cache2(fGpu)->resourceAccess().notifyPurgable(this);
|
||||
if (fCacheEntry && !this->wasDestroyed()) {
|
||||
get_resource_cache(fGpu)->notifyPurgable(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,25 @@ public:
|
||||
return fResource->setContentKey(contentKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define GrPath_DEFINED
|
||||
|
||||
#include "GrGpuResource.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkStrokeRec.h"
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define GrPathRange_DEFINED
|
||||
|
||||
#include "GrGpuResource.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkStrokeRec.h"
|
||||
#include "SkTArray.h"
|
||||
|
393
src/gpu/GrResourceCache.cpp
Normal file
393
src/gpu/GrResourceCache.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
251
src/gpu/GrResourceCache.h
Normal file
251
src/gpu/GrResourceCache.h
Normal file
@ -0,0 +1,251 @@
|
||||
|
||||
/*
|
||||
* 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
|
@ -10,13 +10,6 @@
|
||||
#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);
|
||||
@ -34,85 +27,26 @@ 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()) {
|
||||
@ -121,16 +55,13 @@ 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());
|
||||
}
|
||||
@ -140,13 +71,9 @@ 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());
|
||||
}
|
||||
@ -172,16 +99,11 @@ 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)) {
|
||||
resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
|
||||
GrGpuResource* resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
|
||||
if (resource) {
|
||||
this->makeResourceMRU(resource);
|
||||
return SkRef(resource);
|
||||
} else if (flags & kRequireNoPendingIO_ScratchFlag) {
|
||||
return NULL;
|
||||
@ -189,18 +111,11 @@ 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.
|
||||
}
|
||||
resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
|
||||
if (resource) {
|
||||
resource->ref();
|
||||
this->makeResourceMRU(resource);
|
||||
}
|
||||
return resource;
|
||||
return SkSafeRef(fScratchMap.find(scratchKey, AvailableForScratchUse(false)));
|
||||
}
|
||||
|
||||
bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) {
|
||||
SkASSERT(!fPurging);
|
||||
SkASSERT(resource);
|
||||
SkASSERT(this->isInCache(resource));
|
||||
SkASSERT(resource->cacheAccess().getContentKey());
|
||||
SkASSERT(!resource->cacheAccess().getContentKey()->isScratch());
|
||||
|
||||
@ -210,214 +125,5 @@ 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
|
||||
|
@ -17,65 +17,27 @@
|
||||
#include "SkTMultiMap.h"
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
class GrResourceCache2 {
|
||||
public:
|
||||
GrResourceCache2();
|
||||
GrResourceCache2() : fCount(0) {};
|
||||
~GrResourceCache2();
|
||||
|
||||
/** Used to access functionality needed by GrGpuResource for lifetime management. */
|
||||
class ResourceAccess;
|
||||
ResourceAccess resourceAccess();
|
||||
void insertResource(GrGpuResource*);
|
||||
|
||||
/**
|
||||
* Sets the cache limits in terms of number of resources and max gpu memory byte size.
|
||||
*/
|
||||
void setLimits(int count, size_t bytes);
|
||||
void removeResource(GrGpuResource*);
|
||||
|
||||
/**
|
||||
* Returns the number of cached resources.
|
||||
*/
|
||||
int getResourceCount() const { return fCount; }
|
||||
// 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 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 {
|
||||
@ -84,10 +46,6 @@ 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
|
||||
@ -98,80 +56,21 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Find a resource that matches a content key.
|
||||
*/
|
||||
GrGpuResource* findAndRefContentResource(const GrResourceKey& contentKey) {
|
||||
SkASSERT(!contentKey.isScratch());
|
||||
GrGpuResource* resource = fContentHash.find(contentKey);
|
||||
if (resource) {
|
||||
resource->ref();
|
||||
this->makeResourceMRU(resource);
|
||||
}
|
||||
return resource;
|
||||
return SkSafeRef(fContentHash.find(contentKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
@ -192,86 +91,12 @@ private:
|
||||
};
|
||||
typedef SkTDynamicHash<GrGpuResource, GrResourceKey, ContentHashTraits> ContentHash;
|
||||
|
||||
typedef SkTInternalLList<GrGpuResource> ResourceList;
|
||||
|
||||
ResourceList fResources;
|
||||
int fCount;
|
||||
SkTInternalLList<GrGpuResource> 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
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "GrResourceCache2.h"
|
||||
|
||||
void GrStencilBuffer::transferToCache() {
|
||||
SkASSERT(!this->cacheAccess().isInCache());
|
||||
|
||||
this->getGpu()->getContext()->addStencilBuffer(this);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "GrTest.h"
|
||||
|
||||
#include "GrInOrderDrawBuffer.h"
|
||||
#include "GrResourceCache2.h"
|
||||
#include "GrResourceCache.h"
|
||||
|
||||
void GrTestTarget::init(GrContext* ctx, GrDrawTarget* target) {
|
||||
SkASSERT(!fContext);
|
||||
@ -38,7 +38,7 @@ void GrContext::setMaxTextureSizeOverride(int maxTextureSizeOverride) {
|
||||
}
|
||||
|
||||
void GrContext::purgeAllUnlockedResources() {
|
||||
fResourceCache2->purgeAllUnlocked();
|
||||
fResourceCache->purgeAllUnlocked();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "GrContext.h"
|
||||
#include "GrDrawTargetCaps.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "GrTexture.h"
|
||||
#include "GrTexturePriv.h"
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "SkMessageBus.h"
|
||||
#include "SkPixelRef.h"
|
||||
#include "SkTextureCompressor.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "GrGpu.h"
|
||||
#include "effects/GrDitherEffect.h"
|
||||
#include "GrDrawTargetCaps.h"
|
||||
|
@ -10,10 +10,9 @@
|
||||
#include "GrContext.h"
|
||||
#include "GrContextFactory.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrResourceCache.h"
|
||||
#include "GrResourceCache2.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkMessageBus.h"
|
||||
#include "SkSurface.h"
|
||||
#include "Test.h"
|
||||
|
||||
@ -68,6 +67,7 @@ public:
|
||||
SK_DECLARE_INST_COUNT(TestResource);
|
||||
TestResource(GrGpu* gpu)
|
||||
: INHERITED(gpu, false)
|
||||
, fCache(NULL)
|
||||
, fToDelete(NULL)
|
||||
, fSize(kDefaultSize) {
|
||||
++fNumAlive;
|
||||
@ -76,6 +76,7 @@ public:
|
||||
|
||||
TestResource(GrGpu* gpu, const GrResourceKey& scratchKey)
|
||||
: INHERITED(gpu, false)
|
||||
, fCache(NULL)
|
||||
, fToDelete(NULL)
|
||||
, fSize(kDefaultSize) {
|
||||
this->setScratchKey(scratchKey);
|
||||
@ -85,7 +86,11 @@ public:
|
||||
|
||||
~TestResource() {
|
||||
--fNumAlive;
|
||||
SkSafeUnref(fToDelete);
|
||||
if (fToDelete) {
|
||||
// Breaks our little 2-element cycle below.
|
||||
fToDelete->setDeleteWhenDestroyed(NULL, NULL);
|
||||
fCache->deleteResource(fToDelete->cacheAccess().getCacheEntry());
|
||||
}
|
||||
this->release();
|
||||
}
|
||||
|
||||
@ -96,13 +101,15 @@ public:
|
||||
|
||||
static int NumAlive() { return fNumAlive; }
|
||||
|
||||
void setUnrefWhenDestroyed(TestResource* resource) {
|
||||
SkRefCnt_SafeAssign(fToDelete, resource);
|
||||
void setDeleteWhenDestroyed(GrResourceCache* cache, TestResource* resource) {
|
||||
fCache = cache;
|
||||
fToDelete = resource;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t onGpuMemorySize() const SK_OVERRIDE { return fSize; }
|
||||
|
||||
GrResourceCache* fCache;
|
||||
TestResource* fToDelete;
|
||||
size_t fSize;
|
||||
static int fNumAlive;
|
||||
@ -111,61 +118,6 @@ private:
|
||||
};
|
||||
int TestResource::fNumAlive = 0;
|
||||
|
||||
static void test_no_key(skiatest::Reporter* reporter) {
|
||||
SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
|
||||
REPORTER_ASSERT(reporter, SkToBool(context));
|
||||
if (NULL == context) {
|
||||
return;
|
||||
}
|
||||
context->setResourceCacheLimits(10, 30000);
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
|
||||
// Create a bunch of resources with no keys
|
||||
TestResource* a = new TestResource(context->getGpu());
|
||||
TestResource* b = new TestResource(context->getGpu());
|
||||
TestResource* c = new TestResource(context->getGpu());
|
||||
TestResource* d = new TestResource(context->getGpu());
|
||||
a->setSize(11);
|
||||
b->setSize(12);
|
||||
c->setSize(13);
|
||||
d->setSize(14);
|
||||
|
||||
REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, 4 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
|
||||
d->gpuMemorySize() == cache2->getResourceBytes());
|
||||
|
||||
// Should be safe to purge without deleting the resources since we still have refs.
|
||||
cache2->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
|
||||
|
||||
// Since the resources have neither content nor scratch keys, delete immediately upon unref.
|
||||
|
||||
a->unref();
|
||||
REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, 3 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() ==
|
||||
cache2->getResourceBytes());
|
||||
|
||||
c->unref();
|
||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
|
||||
cache2->getResourceBytes());
|
||||
|
||||
d->unref();
|
||||
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache2->getResourceBytes());
|
||||
|
||||
b->unref();
|
||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
|
||||
}
|
||||
|
||||
static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
|
||||
SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
|
||||
REPORTER_ASSERT(reporter, SkToBool(context));
|
||||
@ -173,9 +125,10 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
|
||||
return;
|
||||
}
|
||||
context->setResourceCacheLimits(5, 30000);
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
SkDEBUGCODE(GrResourceCache2* cache2 = context->getResourceCache2();)
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
GrCacheID::Key keyData;
|
||||
memset(&keyData, 0, sizeof(keyData));
|
||||
@ -189,16 +142,30 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
|
||||
a->setSize(11);
|
||||
b->setSize(12);
|
||||
// Scratch resources are registered with GrResourceCache2 just by existing. There are 2.
|
||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
|
||||
|
||||
REPORTER_ASSERT(reporter, cache->addResource(scratchKey, a));
|
||||
|
||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
|
||||
|
||||
// Can't add the same resource twice.
|
||||
REPORTER_ASSERT(reporter, !cache->addResource(scratchKey, a));
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getCachedResourceBytes());
|
||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
|
||||
|
||||
// Add a second with the same key.
|
||||
REPORTER_ASSERT(reporter, cache->addResource(scratchKey, b));
|
||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
|
||||
cache->getCachedResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
|
||||
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
|
||||
cache2->getResourceBytes());
|
||||
|
||||
// Our refs mean that the resources are non purgable.
|
||||
cache2->purgeAllUnlocked();
|
||||
cache->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
||||
|
||||
// Unref but don't purge
|
||||
a->unref();
|
||||
@ -207,9 +174,9 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
|
||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
|
||||
|
||||
// Purge again. This time resources should be purgable.
|
||||
cache2->purgeAllUnlocked();
|
||||
cache->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceCount());
|
||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));)
|
||||
}
|
||||
|
||||
@ -220,9 +187,9 @@ static void test_duplicate_content_key(skiatest::Reporter* reporter) {
|
||||
return;
|
||||
}
|
||||
context->setResourceCacheLimits(5, 30000);
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
GrCacheID::Domain domain = GrCacheID::GenerateDomain();
|
||||
GrCacheID::Key keyData;
|
||||
@ -230,42 +197,30 @@ static void test_duplicate_content_key(skiatest::Reporter* reporter) {
|
||||
GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
|
||||
GrResourceKey key(GrCacheID(domain, keyData), t, 0);
|
||||
|
||||
|
||||
// Create two resources that we will attempt to register with the same content key.
|
||||
TestResource* a = new TestResource(context->getGpu());
|
||||
TestResource* b = new TestResource(context->getGpu());
|
||||
a->setSize(11);
|
||||
b->setSize(12);
|
||||
|
||||
// Can't set the same content key on two resources.
|
||||
REPORTER_ASSERT(reporter, a->cacheAccess().setContentKey(key));
|
||||
REPORTER_ASSERT(reporter, !b->cacheAccess().setContentKey(key));
|
||||
|
||||
// Still have two resources because b is still reffed.
|
||||
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
|
||||
cache2->getResourceBytes());
|
||||
REPORTER_ASSERT(reporter, cache->addResource(key, a));
|
||||
// Can't add the same or another resource with the same key.
|
||||
REPORTER_ASSERT(reporter, !cache->addResource(key, a));
|
||||
REPORTER_ASSERT(reporter, !cache->addResource(key, b));
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getCachedResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||
|
||||
b->unref();
|
||||
// Now b should be gone.
|
||||
REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache2->getResourceBytes());
|
||||
cache->purgeAllUnlocked();
|
||||
a->setSize(10);
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
|
||||
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
||||
|
||||
cache2->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache2->getResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
||||
|
||||
// Drop the ref on a but it isn't immediately purged as it still has a valid scratch key.
|
||||
a->unref();
|
||||
REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache2->getResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
||||
|
||||
cache2->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
|
||||
cache->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceCount());
|
||||
REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||
}
|
||||
|
||||
@ -290,17 +245,18 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
|
||||
GrResourceKey key3(GrCacheID(domain, keyData), t, 0);
|
||||
|
||||
context->setResourceCacheLimits(5, 30000);
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
// Add three resources to the cache.
|
||||
TestResource* a = new TestResource(context->getGpu());
|
||||
TestResource* b = new TestResource(context->getGpu());
|
||||
TestResource* c = new TestResource(context->getGpu());
|
||||
a->cacheAccess().setContentKey(key1);
|
||||
b->cacheAccess().setContentKey(key2);
|
||||
c->cacheAccess().setContentKey(key3);
|
||||
cache->addResource(key1, a);
|
||||
cache->addResource(key2, b);
|
||||
cache->addResource(key3, c);
|
||||
a->unref();
|
||||
b->unref();
|
||||
c->unref();
|
||||
@ -315,8 +271,8 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
|
||||
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg1);
|
||||
const GrResourceInvalidatedMessage msg2 = { key2 };
|
||||
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg2);
|
||||
cache->purgeAsNeeded();
|
||||
#if 0 // Disabled until reimplemented in GrResourceCache2.
|
||||
cache2->purgeAsNeeded();
|
||||
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
|
||||
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key2));
|
||||
@ -326,19 +282,14 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
|
||||
// Invalidate the third.
|
||||
const GrResourceInvalidatedMessage msg3 = { key3 };
|
||||
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg3);
|
||||
cache->purgeAsNeeded();
|
||||
#if 0 // Disabled until reimplemented in GrResourceCache2.
|
||||
cache2->purgeAsNeeded();
|
||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key3));
|
||||
#endif
|
||||
|
||||
cache2->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||
REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
|
||||
}
|
||||
|
||||
static void test_cache_chained_purge(skiatest::Reporter* reporter) {
|
||||
static void test_cache_delete_on_destruction(skiatest::Reporter* reporter) {
|
||||
SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
|
||||
REPORTER_ASSERT(reporter, SkToBool(context));
|
||||
if (NULL == context) {
|
||||
@ -358,34 +309,44 @@ static void test_cache_chained_purge(skiatest::Reporter* reporter) {
|
||||
|
||||
{
|
||||
context->setResourceCacheLimits(3, 30000);
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
TestResource* a = new TestResource(context->getGpu());
|
||||
TestResource* b = new TestResource(context->getGpu());
|
||||
a->cacheAccess().setContentKey(key1);
|
||||
b->cacheAccess().setContentKey(key2);
|
||||
cache->addResource(key1, a);
|
||||
cache->addResource(key2, b);
|
||||
|
||||
// Make a cycle
|
||||
a->setUnrefWhenDestroyed(b);
|
||||
b->setUnrefWhenDestroyed(a);
|
||||
|
||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||
a->setDeleteWhenDestroyed(cache, b);
|
||||
b->setDeleteWhenDestroyed(cache, a);
|
||||
|
||||
a->unref();
|
||||
b->unref();
|
||||
|
||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||
|
||||
cache2->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||
cache->purgeAllUnlocked();
|
||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||
}
|
||||
{
|
||||
context->setResourceCacheLimits(3, 30000);
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
// Break the cycle
|
||||
a->setUnrefWhenDestroyed(NULL);
|
||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||
TestResource* a = new TestResource(context->getGpu());
|
||||
TestResource* b = new TestResource(context->getGpu());
|
||||
cache->addResource(key1, a);
|
||||
cache->addResource(key2, b);
|
||||
|
||||
cache2->purgeAllUnlocked();
|
||||
a->setDeleteWhenDestroyed(cache, b);
|
||||
b->setDeleteWhenDestroyed(cache, a);
|
||||
|
||||
a->unref();
|
||||
b->unref();
|
||||
|
||||
cache->deleteResource(a->cacheAccess().getCacheEntry());
|
||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||
}
|
||||
}
|
||||
@ -413,20 +374,23 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
|
||||
// Test changing resources sizes (both increase & decrease).
|
||||
{
|
||||
context->setResourceCacheLimits(3, 30000);
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
TestResource* a = new TestResource(context->getGpu());
|
||||
a->cacheAccess().setContentKey(key1);
|
||||
a->setSize(100); // Test didChangeGpuMemorySize() when not in the cache.
|
||||
cache->addResource(key1, a);
|
||||
a->unref();
|
||||
|
||||
TestResource* b = new TestResource(context->getGpu());
|
||||
b->cacheAccess().setContentKey(key2);
|
||||
b->setSize(100);
|
||||
cache->addResource(key2, b);
|
||||
b->unref();
|
||||
|
||||
REPORTER_ASSERT(reporter, 200 == cache2->getResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 200 == cache->getCachedResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
||||
{
|
||||
SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
|
||||
find2->setSize(200);
|
||||
@ -434,29 +398,30 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
|
||||
find1->setSize(50);
|
||||
}
|
||||
|
||||
REPORTER_ASSERT(reporter, 250 == cache2->getResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 250 == cache->getCachedResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
||||
}
|
||||
|
||||
// Test increasing a resources size beyond the cache budget.
|
||||
{
|
||||
context->setResourceCacheLimits(2, 300);
|
||||
GrResourceCache* cache = context->getResourceCache();
|
||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||
cache2->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||
cache->purgeAllUnlocked();
|
||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
||||
|
||||
TestResource* a = new TestResource(context->getGpu());
|
||||
a->setSize(100);
|
||||
a->cacheAccess().setContentKey(key1);
|
||||
cache->addResource(key1, a);
|
||||
a->unref();
|
||||
|
||||
TestResource* b = new TestResource(context->getGpu());
|
||||
b->setSize(100);
|
||||
b->cacheAccess().setContentKey(key2);
|
||||
cache->addResource(key2, b);
|
||||
b->unref();
|
||||
|
||||
REPORTER_ASSERT(reporter, 200 == cache2->getResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 200 == cache->getCachedResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
||||
|
||||
{
|
||||
SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
|
||||
@ -464,8 +429,8 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
|
||||
}
|
||||
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
|
||||
|
||||
REPORTER_ASSERT(reporter, 201 == cache2->getResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
|
||||
REPORTER_ASSERT(reporter, 201 == cache->getCachedResourceBytes());
|
||||
REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,11 +456,10 @@ DEF_GPUTEST(ResourceCache, reporter, factory) {
|
||||
}
|
||||
|
||||
// The below tests create their own mock contexts.
|
||||
test_no_key(reporter);
|
||||
test_duplicate_content_key(reporter);
|
||||
test_duplicate_scratch_key(reporter);
|
||||
test_purge_invalidated(reporter);
|
||||
test_cache_chained_purge(reporter);
|
||||
test_cache_delete_on_destruction(reporter);
|
||||
test_resource_size_changed(reporter);
|
||||
}
|
||||
|
||||
|
@ -321,6 +321,33 @@ static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
static void TestSurfaceInCache(skiatest::Reporter* reporter,
|
||||
SurfaceType surfaceType,
|
||||
GrContext* context) {
|
||||
context->freeGpuResources();
|
||||
int resourceCount;
|
||||
|
||||
context->getResourceCacheUsage(&resourceCount, NULL);
|
||||
REPORTER_ASSERT(reporter, 0 == resourceCount);
|
||||
SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
|
||||
// Note: the stencil buffer is always cached, so kGpu_SurfaceType uses
|
||||
// one cached resource, and kGpuScratch_SurfaceType uses two.
|
||||
int expectedCachedResources = surfaceType == kGpuScratch_SurfaceType ? 2 : 1;
|
||||
context->getResourceCacheUsage(&resourceCount, NULL);
|
||||
REPORTER_ASSERT(reporter, expectedCachedResources == resourceCount);
|
||||
|
||||
// Verify that all the cached resources are locked in cache.
|
||||
context->freeGpuResources();
|
||||
context->getResourceCacheUsage(&resourceCount, NULL);
|
||||
REPORTER_ASSERT(reporter, expectedCachedResources == resourceCount);
|
||||
|
||||
// Verify that all the cached resources are unlocked upon surface release
|
||||
surface.reset(0);
|
||||
context->freeGpuResources();
|
||||
context->getResourceCacheUsage(&resourceCount, NULL);
|
||||
REPORTER_ASSERT(reporter, 0 == resourceCount);
|
||||
}
|
||||
|
||||
static void Test_crbug263329(skiatest::Reporter* reporter,
|
||||
SurfaceType surfaceType,
|
||||
GrContext* context) {
|
||||
@ -426,6 +453,8 @@ DEF_GPUTEST(Surface, reporter, factory) {
|
||||
}
|
||||
GrContext* context = factory->get(glCtxType);
|
||||
if (context) {
|
||||
TestSurfaceInCache(reporter, kGpu_SurfaceType, context);
|
||||
TestSurfaceInCache(reporter, kGpuScratch_SurfaceType, context);
|
||||
Test_crbug263329(reporter, kGpu_SurfaceType, context);
|
||||
Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
|
||||
TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
|
||||
|
Loading…
Reference in New Issue
Block a user