Replace GrResourceCache with GrResourceCache2.
BUG=skia:2889 Committed: https://skia.googlesource.com/skia/+/66a450f21a3da174b7eed89a1d5fc8591e8b6ee6 Review URL: https://codereview.chromium.org/716143004
This commit is contained in:
parent
5ae776504f
commit
407aa584d1
@ -13,7 +13,6 @@
|
|||||||
#include "GrGpuResource.h"
|
#include "GrGpuResource.h"
|
||||||
#include "GrContext.h"
|
#include "GrContext.h"
|
||||||
#include "GrGpu.h"
|
#include "GrGpu.h"
|
||||||
#include "GrResourceCache.h"
|
|
||||||
#include "GrResourceCache2.h"
|
#include "GrResourceCache2.h"
|
||||||
#include "GrStencilBuffer.h"
|
#include "GrStencilBuffer.h"
|
||||||
#include "GrTexture.h"
|
#include "GrTexture.h"
|
||||||
@ -89,22 +88,20 @@ static void get_stencil(int i, int* w, int* h, int* s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void get_texture_desc(int i, GrSurfaceDesc* desc) {
|
static void get_texture_desc(int i, GrSurfaceDesc* desc) {
|
||||||
desc->fFlags = kRenderTarget_GrSurfaceFlag |
|
desc->fFlags = kRenderTarget_GrSurfaceFlag | kNoStencil_GrSurfaceFlag;
|
||||||
kNoStencil_GrSurfaceFlag;
|
|
||||||
desc->fWidth = i % 1024;
|
desc->fWidth = i % 1024;
|
||||||
desc->fHeight = i * 2 % 1024;
|
desc->fHeight = i * 2 % 1024;
|
||||||
desc->fConfig = static_cast<GrPixelConfig>(i % (kLast_GrPixelConfig + 1));
|
desc->fConfig = static_cast<GrPixelConfig>(i % (kLast_GrPixelConfig + 1));
|
||||||
desc->fSampleCnt = i % 1 == 0 ? 0 : 4;
|
desc->fSampleCnt = ((i % 2) == 0) ? 0 : 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void populate_cache(GrResourceCache* cache, GrGpu* gpu, int resourceCount) {
|
static void populate_cache(GrGpu* gpu, int resourceCount) {
|
||||||
for (int i = 0; i < resourceCount; ++i) {
|
for (int i = 0; i < resourceCount; ++i) {
|
||||||
int w, h, s;
|
int w, h, s;
|
||||||
get_stencil(i, &w, &h, &s);
|
get_stencil(i, &w, &h, &s);
|
||||||
GrResourceKey key = GrStencilBuffer::ComputeKey(w, h, s);
|
GrResourceKey key = GrStencilBuffer::ComputeKey(w, h, s);
|
||||||
GrGpuResource* resource = SkNEW_ARGS(StencilResource, (gpu, i));
|
GrGpuResource* resource = SkNEW_ARGS(StencilResource, (gpu, i));
|
||||||
cache->purgeAsNeeded(1, resource->gpuMemorySize());
|
resource->cacheAccess().setContentKey(key);
|
||||||
cache->addResource(key, resource);
|
|
||||||
resource->unref();
|
resource->unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,8 +110,7 @@ static void populate_cache(GrResourceCache* cache, GrGpu* gpu, int resourceCount
|
|||||||
get_texture_desc(i, &desc);
|
get_texture_desc(i, &desc);
|
||||||
GrResourceKey key = TextureResource::ComputeKey(desc);
|
GrResourceKey key = TextureResource::ComputeKey(desc);
|
||||||
GrGpuResource* resource = SkNEW_ARGS(TextureResource, (gpu, i));
|
GrGpuResource* resource = SkNEW_ARGS(TextureResource, (gpu, i));
|
||||||
cache->purgeAsNeeded(1, resource->gpuMemorySize());
|
resource->cacheAccess().setContentKey(key);
|
||||||
cache->addResource(key, resource);
|
|
||||||
resource->unref();
|
resource->unref();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,25 +194,24 @@ protected:
|
|||||||
// Set the cache budget to be very large so no purging occurs.
|
// Set the cache budget to be very large so no purging occurs.
|
||||||
context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30);
|
context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30);
|
||||||
|
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
|
||||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||||
|
|
||||||
// Make sure the cache is empty.
|
// Make sure the cache is empty.
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
|
|
||||||
GrGpu* gpu = context->getGpu();
|
GrGpu* gpu = context->getGpu();
|
||||||
|
|
||||||
for (int i = 0; i < loops; ++i) {
|
for (int i = 0; i < loops; ++i) {
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
|
|
||||||
populate_cache(cache, gpu, RESOURCE_COUNT);
|
populate_cache(gpu, RESOURCE_COUNT);
|
||||||
|
|
||||||
// Check that cache works.
|
// Check that cache works.
|
||||||
for (int k = 0; k < RESOURCE_COUNT; k += 33) {
|
for (int k = 0; k < RESOURCE_COUNT; k += 33) {
|
||||||
check_cache_contents_or_die(cache2, k);
|
check_cache_contents_or_die(cache2, k);
|
||||||
}
|
}
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,16 +242,15 @@ protected:
|
|||||||
// Set the cache budget to be very large so no purging occurs.
|
// Set the cache budget to be very large so no purging occurs.
|
||||||
context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30);
|
context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30);
|
||||||
|
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
|
||||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||||
|
|
||||||
// Make sure the cache is empty.
|
// Make sure the cache is empty.
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
|
|
||||||
GrGpu* gpu = context->getGpu();
|
GrGpu* gpu = context->getGpu();
|
||||||
|
|
||||||
populate_cache(cache, gpu, RESOURCE_COUNT);
|
populate_cache(gpu, RESOURCE_COUNT);
|
||||||
|
|
||||||
for (int i = 0; i < loops; ++i) {
|
for (int i = 0; i < loops; ++i) {
|
||||||
for (int k = 0; k < RESOURCE_COUNT; ++k) {
|
for (int k = 0; k < RESOURCE_COUNT; ++k) {
|
||||||
|
10
gyp/gpu.gyp
10
gyp/gpu.gyp
@ -63,16 +63,6 @@
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
[ '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': {
|
'direct_dependent_settings': {
|
||||||
'conditions': [
|
'conditions': [
|
||||||
|
@ -136,8 +136,6 @@
|
|||||||
'<(skia_src_path)/gpu/GrRenderTarget.cpp',
|
'<(skia_src_path)/gpu/GrRenderTarget.cpp',
|
||||||
'<(skia_src_path)/gpu/GrReducedClip.cpp',
|
'<(skia_src_path)/gpu/GrReducedClip.cpp',
|
||||||
'<(skia_src_path)/gpu/GrReducedClip.h',
|
'<(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.cpp',
|
||||||
'<(skia_src_path)/gpu/GrResourceCache2.h',
|
'<(skia_src_path)/gpu/GrResourceCache2.h',
|
||||||
'<(skia_src_path)/gpu/GrStencil.cpp',
|
'<(skia_src_path)/gpu/GrStencil.cpp',
|
||||||
|
@ -212,24 +212,6 @@ typedef unsigned __int64 uint64_t;
|
|||||||
#define GR_GEOM_BUFFER_MAP_THRESHOLD (1 << 15)
|
#define GR_GEOM_BUFFER_MAP_THRESHOLD (1 << 15)
|
||||||
#endif
|
#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
|
* GR_STROKE_PATH_RENDERING controls whether or not the GrStrokePathRenderer can be selected
|
||||||
* as a path renderer. GrStrokePathRenderer is currently an experimental path renderer.
|
* as a path renderer. GrStrokePathRenderer is currently an experimental path renderer.
|
||||||
|
@ -33,7 +33,6 @@ class GrOvalRenderer;
|
|||||||
class GrPath;
|
class GrPath;
|
||||||
class GrPathRenderer;
|
class GrPathRenderer;
|
||||||
class GrResourceEntry;
|
class GrResourceEntry;
|
||||||
class GrResourceCache;
|
|
||||||
class GrResourceCache2;
|
class GrResourceCache2;
|
||||||
class GrStencilBuffer;
|
class GrStencilBuffer;
|
||||||
class GrTestTarget;
|
class GrTestTarget;
|
||||||
@ -883,7 +882,6 @@ public:
|
|||||||
GrDrawTarget* getTextTarget();
|
GrDrawTarget* getTextTarget();
|
||||||
const GrIndexBuffer* getQuadIndexBuffer() const;
|
const GrIndexBuffer* getQuadIndexBuffer() const;
|
||||||
GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; }
|
GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; }
|
||||||
GrResourceCache* getResourceCache() { return fResourceCache; }
|
|
||||||
GrResourceCache2* getResourceCache2() { return fResourceCache2; }
|
GrResourceCache2* getResourceCache2() { return fResourceCache2; }
|
||||||
|
|
||||||
// Called by tests that draw directly to the context via GrDrawTarget
|
// Called by tests that draw directly to the context via GrDrawTarget
|
||||||
@ -948,7 +946,6 @@ private:
|
|||||||
const GrClipData* fClip; // TODO: make this ref counted
|
const GrClipData* fClip; // TODO: make this ref counted
|
||||||
GrDrawState* fDrawState;
|
GrDrawState* fDrawState;
|
||||||
|
|
||||||
GrResourceCache* fResourceCache;
|
|
||||||
GrResourceCache2* fResourceCache2;
|
GrResourceCache2* fResourceCache2;
|
||||||
GrFontCache* fFontCache;
|
GrFontCache* fFontCache;
|
||||||
SkAutoTDelete<GrLayerCache> fLayerCache;
|
SkAutoTDelete<GrLayerCache> fLayerCache;
|
||||||
@ -962,7 +959,6 @@ private:
|
|||||||
|
|
||||||
// Set by OverbudgetCB() to request that GrContext flush before exiting a draw.
|
// Set by OverbudgetCB() to request that GrContext flush before exiting a draw.
|
||||||
bool fFlushToReduceCacheSize;
|
bool fFlushToReduceCacheSize;
|
||||||
|
|
||||||
GrAARectRenderer* fAARectRenderer;
|
GrAARectRenderer* fAARectRenderer;
|
||||||
GrOvalRenderer* fOvalRenderer;
|
GrOvalRenderer* fOvalRenderer;
|
||||||
|
|
||||||
@ -1003,8 +999,6 @@ private:
|
|||||||
size_t rowBytes,
|
size_t rowBytes,
|
||||||
bool filter);
|
bool filter);
|
||||||
|
|
||||||
GrTexture* createNewScratchTexture(const GrSurfaceDesc& desc);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These functions create premul <-> unpremul effects if it is possible to generate a pair
|
* 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
|
* of effects that make a readToUPM->writeToPM->readToUPM cycle invariant. Otherwise, they
|
||||||
@ -1015,9 +1009,9 @@ private:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This callback allows the resource cache to callback into the GrContext
|
* This callback allows the resource cache to callback into the GrContext
|
||||||
* when the cache is still overbudget after a purge.
|
* when the cache is still over budget after a purge.
|
||||||
*/
|
*/
|
||||||
static bool OverbudgetCB(void* data);
|
static void OverBudgetCB(void* data);
|
||||||
|
|
||||||
typedef SkRefCnt INHERITED;
|
typedef SkRefCnt INHERITED;
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
class GrContext;
|
class GrContext;
|
||||||
class GrGpu;
|
class GrGpu;
|
||||||
class GrResourceCache2;
|
class GrResourceCache2;
|
||||||
class GrResourceCacheEntry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
|
* Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
|
||||||
@ -126,7 +125,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for objects that can be kept in the GrResourceCache.
|
* Base class for objects that can be kept in the GrResourceCache2.
|
||||||
*/
|
*/
|
||||||
class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
|
class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
|
||||||
public:
|
public:
|
||||||
@ -257,7 +256,6 @@ private:
|
|||||||
|
|
||||||
uint32_t fFlags;
|
uint32_t fFlags;
|
||||||
|
|
||||||
GrResourceCacheEntry* fCacheEntry; // NULL if not in cache
|
|
||||||
mutable size_t fGpuMemorySize;
|
mutable size_t fGpuMemorySize;
|
||||||
const uint32_t fUniqueID;
|
const uint32_t fUniqueID;
|
||||||
|
|
||||||
|
@ -19,16 +19,4 @@
|
|||||||
*/
|
*/
|
||||||
//#define GR_GEOM_BUFFER_MAP_THRESHOLD (1<<15)
|
//#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
|
#endif
|
||||||
|
@ -68,6 +68,11 @@ 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*);
|
bool GrIsBitmapInCache(const GrContext*, const SkBitmap&, const GrTextureParams*);
|
||||||
|
|
||||||
GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams*);
|
GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams*);
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "GrRect.h"
|
#include "GrRect.h"
|
||||||
|
|
||||||
#include "SkChecksum.h"
|
#include "SkChecksum.h"
|
||||||
|
#include "SkTDynamicHash.h"
|
||||||
|
|
||||||
class GrContext;
|
class GrContext;
|
||||||
class GrPlot;
|
class GrPlot;
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include "GrOvalRenderer.h"
|
#include "GrOvalRenderer.h"
|
||||||
#include "GrPathRenderer.h"
|
#include "GrPathRenderer.h"
|
||||||
#include "GrPathUtils.h"
|
#include "GrPathUtils.h"
|
||||||
#include "GrResourceCache.h"
|
|
||||||
#include "GrResourceCache2.h"
|
#include "GrResourceCache2.h"
|
||||||
#include "GrSoftwarePathRenderer.h"
|
#include "GrSoftwarePathRenderer.h"
|
||||||
#include "GrStencilBuffer.h"
|
#include "GrStencilBuffer.h"
|
||||||
@ -52,9 +51,6 @@
|
|||||||
#define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
|
#define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
|
||||||
#endif
|
#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 size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
|
||||||
static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
|
static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
|
||||||
|
|
||||||
@ -103,7 +99,6 @@ GrContext::GrContext(const Options& opts) : fOptions(opts) {
|
|||||||
fClip = NULL;
|
fClip = NULL;
|
||||||
fPathRendererChain = NULL;
|
fPathRendererChain = NULL;
|
||||||
fSoftwarePathRenderer = NULL;
|
fSoftwarePathRenderer = NULL;
|
||||||
fResourceCache = NULL;
|
|
||||||
fResourceCache2 = NULL;
|
fResourceCache2 = NULL;
|
||||||
fFontCache = NULL;
|
fFontCache = NULL;
|
||||||
fDrawBuffer = NULL;
|
fDrawBuffer = NULL;
|
||||||
@ -130,11 +125,8 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
|
|||||||
void GrContext::initCommon() {
|
void GrContext::initCommon() {
|
||||||
fDrawState = SkNEW(GrDrawState);
|
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 = SkNEW(GrResourceCache2);
|
||||||
|
fResourceCache2->setOverBudgetCallback(OverBudgetCB, this);
|
||||||
|
|
||||||
fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
|
fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
|
||||||
|
|
||||||
@ -160,9 +152,6 @@ GrContext::~GrContext() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkDELETE(fResourceCache2);
|
SkDELETE(fResourceCache2);
|
||||||
fResourceCache2 = NULL;
|
|
||||||
SkDELETE(fResourceCache);
|
|
||||||
fResourceCache = NULL;
|
|
||||||
SkDELETE(fFontCache);
|
SkDELETE(fFontCache);
|
||||||
SkDELETE(fDrawBuffer);
|
SkDELETE(fDrawBuffer);
|
||||||
SkDELETE(fDrawBufferVBAllocPool);
|
SkDELETE(fDrawBufferVBAllocPool);
|
||||||
@ -201,8 +190,6 @@ void GrContext::abandonContext() {
|
|||||||
fAARectRenderer->reset();
|
fAARectRenderer->reset();
|
||||||
fOvalRenderer->reset();
|
fOvalRenderer->reset();
|
||||||
|
|
||||||
fResourceCache->purgeAllUnlocked();
|
|
||||||
|
|
||||||
fFontCache->freeAll();
|
fFontCache->freeAll();
|
||||||
fLayerCache->freeAll();
|
fLayerCache->freeAll();
|
||||||
}
|
}
|
||||||
@ -221,7 +208,6 @@ void GrContext::freeGpuResources() {
|
|||||||
fAARectRenderer->reset();
|
fAARectRenderer->reset();
|
||||||
fOvalRenderer->reset();
|
fOvalRenderer->reset();
|
||||||
|
|
||||||
fResourceCache->purgeAllUnlocked();
|
|
||||||
fFontCache->freeAll();
|
fFontCache->freeAll();
|
||||||
fLayerCache->freeAll();
|
fLayerCache->freeAll();
|
||||||
// a path renderer may be holding onto resources
|
// a path renderer may be holding onto resources
|
||||||
@ -230,12 +216,12 @@ void GrContext::freeGpuResources() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
|
void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
|
||||||
if (resourceCount) {
|
if (resourceCount) {
|
||||||
*resourceCount = fResourceCache->getCachedResourceCount();
|
*resourceCount = fResourceCache2->getResourceCount();
|
||||||
}
|
}
|
||||||
if (resourceBytes) {
|
if (resourceBytes) {
|
||||||
*resourceBytes = fResourceCache->getCachedResourceBytes();
|
*resourceBytes = fResourceCache2->getResourceBytes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
|
GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
|
||||||
@ -273,12 +259,13 @@ bool GrContext::isTextureInCache(const GrSurfaceDesc& desc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
|
void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
|
||||||
|
// TODO: Make GrStencilBuffers use the scratch mechanism rather than content keys.
|
||||||
ASSERT_OWNED_RESOURCE(sb);
|
ASSERT_OWNED_RESOURCE(sb);
|
||||||
|
|
||||||
GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(),
|
GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(),
|
||||||
sb->height(),
|
sb->height(),
|
||||||
sb->numSamples());
|
sb->numSamples());
|
||||||
fResourceCache->addResource(resourceKey, sb);
|
SkAssertResult(sb->cacheAccess().setContentKey(resourceKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
GrStencilBuffer* GrContext::findAndRefStencilBuffer(int width, int height, int sampleCnt) {
|
GrStencilBuffer* GrContext::findAndRefStencilBuffer(int width, int height, int sampleCnt) {
|
||||||
@ -420,25 +407,19 @@ GrTexture* GrContext::createTexture(const GrTextureParams* params,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (texture) {
|
if (texture) {
|
||||||
fResourceCache->addResource(resourceKey, texture);
|
if (texture->cacheAccess().setContentKey(resourceKey)) {
|
||||||
|
if (cacheKey) {
|
||||||
if (cacheKey) {
|
*cacheKey = resourceKey;
|
||||||
*cacheKey = resourceKey;
|
}
|
||||||
|
} else {
|
||||||
|
texture->unref();
|
||||||
|
texture = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture;
|
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,
|
GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexMatch match,
|
||||||
bool calledDuringFlush) {
|
bool calledDuringFlush) {
|
||||||
// kNoStencil has no meaning if kRT isn't set.
|
// kNoStencil has no meaning if kRT isn't set.
|
||||||
@ -473,7 +454,6 @@ GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexM
|
|||||||
}
|
}
|
||||||
GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key, scratchFlags);
|
GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key, scratchFlags);
|
||||||
if (resource) {
|
if (resource) {
|
||||||
fResourceCache->makeResourceMRU(resource);
|
|
||||||
return static_cast<GrSurface*>(resource)->asTexture();
|
return static_cast<GrSurface*>(resource)->asTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,21 +476,19 @@ GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& inDesc, ScratchTexM
|
|||||||
desc.writable()->fFlags = origFlags;
|
desc.writable()->fFlags = origFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrTexture* texture = this->createNewScratchTexture(*desc);
|
GrTexture* texture = fGpu->createTexture(*desc, NULL, 0);
|
||||||
SkASSERT(NULL == texture ||
|
SkASSERT(NULL == texture ||
|
||||||
texture->cacheAccess().getScratchKey() == GrTexturePriv::ComputeScratchKey(*desc));
|
texture->cacheAccess().getScratchKey() == GrTexturePriv::ComputeScratchKey(*desc));
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrContext::OverbudgetCB(void* data) {
|
void GrContext::OverBudgetCB(void* data) {
|
||||||
SkASSERT(data);
|
SkASSERT(data);
|
||||||
|
|
||||||
GrContext* context = reinterpret_cast<GrContext*>(data);
|
GrContext* context = reinterpret_cast<GrContext*>(data);
|
||||||
|
|
||||||
// Flush the InOrderDrawBuffer to possibly free up some textures
|
// Flush the InOrderDrawBuffer to possibly free up some textures
|
||||||
context->fFlushToReduceCacheSize = true;
|
context->fFlushToReduceCacheSize = true;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -522,11 +500,16 @@ GrTexture* GrContext::createUncachedTexture(const GrSurfaceDesc& descIn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
|
void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
|
||||||
fResourceCache->getLimits(maxTextures, maxTextureBytes);
|
if (maxTextures) {
|
||||||
|
*maxTextures = fResourceCache2->getMaxResourceCount();
|
||||||
|
}
|
||||||
|
if (maxTextureBytes) {
|
||||||
|
*maxTextureBytes = fResourceCache2->getMaxResourceBytes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
|
void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
|
||||||
fResourceCache->setLimits(maxTextures, maxTextureBytes);
|
fResourceCache2->setLimits(maxTextures, maxTextureBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GrContext::getMaxTextureSize() const {
|
int GrContext::getMaxTextureSize() const {
|
||||||
@ -1242,7 +1225,6 @@ void GrContext::flush(int flagsBitfield) {
|
|||||||
} else {
|
} else {
|
||||||
fDrawBuffer->flush();
|
fDrawBuffer->flush();
|
||||||
}
|
}
|
||||||
fResourceCache->purgeAsNeeded();
|
|
||||||
fFlushToReduceCacheSize = false;
|
fFlushToReduceCacheSize = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1746,15 +1728,11 @@ const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResource* resource) {
|
void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResource* resource) {
|
||||||
fResourceCache->addResource(resourceKey, resource);
|
resource->cacheAccess().setContentKey(resourceKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resourceKey) {
|
GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resourceKey) {
|
||||||
GrGpuResource* resource = fResourceCache2->findAndRefContentResource(resourceKey);
|
return fResourceCache2->findAndRefContentResource(resourceKey);
|
||||||
if (resource) {
|
|
||||||
fResourceCache->makeResourceMRU(resource);
|
|
||||||
}
|
|
||||||
return resource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
||||||
@ -1774,7 +1752,7 @@ void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#if GR_CACHE_STATS
|
#if GR_CACHE_STATS
|
||||||
void GrContext::printCacheStats() const {
|
void GrContext::printCacheStats() const {
|
||||||
fResourceCache->printStats();
|
fResourceCache2->printStats();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -18,16 +18,8 @@ static inline GrResourceCache2* get_resource_cache2(GrGpu* gpu) {
|
|||||||
return gpu->getContext()->getResourceCache2();
|
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)
|
GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
|
||||||
: fGpu(gpu)
|
: fGpu(gpu)
|
||||||
, fCacheEntry(NULL)
|
|
||||||
, fGpuMemorySize(kInvalidGpuMemorySize)
|
, fGpuMemorySize(kInvalidGpuMemorySize)
|
||||||
, fUniqueID(CreateUniqueID())
|
, fUniqueID(CreateUniqueID())
|
||||||
, fScratchKey(GrResourceKey::NullScratchKey())
|
, fScratchKey(GrResourceKey::NullScratchKey())
|
||||||
@ -40,7 +32,7 @@ GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrGpuResource::registerWithCache() {
|
void GrGpuResource::registerWithCache() {
|
||||||
get_resource_cache2(fGpu)->insertResource(this);
|
get_resource_cache2(fGpu)->resourceAccess().insertResource(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrGpuResource::~GrGpuResource() {
|
GrGpuResource::~GrGpuResource() {
|
||||||
@ -51,16 +43,18 @@ GrGpuResource::~GrGpuResource() {
|
|||||||
void GrGpuResource::release() {
|
void GrGpuResource::release() {
|
||||||
if (fGpu) {
|
if (fGpu) {
|
||||||
this->onRelease();
|
this->onRelease();
|
||||||
get_resource_cache2(fGpu)->removeResource(this);
|
get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
|
||||||
fGpu = NULL;
|
fGpu = NULL;
|
||||||
|
fGpuMemorySize = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrGpuResource::abandon() {
|
void GrGpuResource::abandon() {
|
||||||
if (fGpu) {
|
if (fGpu) {
|
||||||
this->onAbandon();
|
this->onAbandon();
|
||||||
get_resource_cache2(fGpu)->removeResource(this);
|
get_resource_cache2(fGpu)->resourceAccess().removeResource(this);
|
||||||
fGpu = NULL;
|
fGpu = NULL;
|
||||||
|
fGpuMemorySize = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +74,17 @@ GrContext* GrGpuResource::getContext() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GrGpuResource::didChangeGpuMemorySize() const {
|
||||||
|
if (this->wasDestroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t oldSize = fGpuMemorySize;
|
||||||
|
SkASSERT(kInvalidGpuMemorySize != oldSize);
|
||||||
|
fGpuMemorySize = kInvalidGpuMemorySize;
|
||||||
|
get_resource_cache2(fGpu)->resourceAccess().didChangeGpuMemorySize(this, oldSize);
|
||||||
|
}
|
||||||
|
|
||||||
bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
|
bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
|
||||||
// Currently this can only be called once and can't be called when the resource is scratch.
|
// Currently this can only be called once and can't be called when the resource is scratch.
|
||||||
SkASSERT(!contentKey.isScratch());
|
SkASSERT(!contentKey.isScratch());
|
||||||
@ -92,7 +97,7 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
|
|||||||
fContentKey = contentKey;
|
fContentKey = contentKey;
|
||||||
fContentKeySet = true;
|
fContentKeySet = true;
|
||||||
|
|
||||||
if (!get_resource_cache2(fGpu)->didSetContentKey(this)) {
|
if (!get_resource_cache2(fGpu)->resourceAccess().didSetContentKey(this)) {
|
||||||
fContentKeySet = false;
|
fContentKeySet = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -100,8 +105,8 @@ bool GrGpuResource::setContentKey(const GrResourceKey& contentKey) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrGpuResource::notifyIsPurgable() const {
|
void GrGpuResource::notifyIsPurgable() const {
|
||||||
if (fCacheEntry && !this->wasDestroyed()) {
|
if (!this->wasDestroyed()) {
|
||||||
get_resource_cache(fGpu)->notifyPurgable(this);
|
get_resource_cache2(fGpu)->resourceAccess().notifyPurgable(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,25 +28,6 @@ public:
|
|||||||
return fResource->setContentKey(contentKey);
|
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
|
* Is the resource currently cached as scratch? This means it has a valid scratch key and does
|
||||||
* not have a content key.
|
* not have a content key.
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#define GrPath_DEFINED
|
#define GrPath_DEFINED
|
||||||
|
|
||||||
#include "GrGpuResource.h"
|
#include "GrGpuResource.h"
|
||||||
#include "GrResourceCache.h"
|
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
#include "SkRect.h"
|
#include "SkRect.h"
|
||||||
#include "SkStrokeRec.h"
|
#include "SkStrokeRec.h"
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#define GrPathRange_DEFINED
|
#define GrPathRange_DEFINED
|
||||||
|
|
||||||
#include "GrGpuResource.h"
|
#include "GrGpuResource.h"
|
||||||
#include "GrResourceCache.h"
|
|
||||||
#include "SkRefCnt.h"
|
#include "SkRefCnt.h"
|
||||||
#include "SkStrokeRec.h"
|
#include "SkStrokeRec.h"
|
||||||
#include "SkTArray.h"
|
#include "SkTArray.h"
|
||||||
|
@ -1,393 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "GrResourceCache.h"
|
|
||||||
#include "GrGpuResource.h"
|
|
||||||
#include "GrGpuResourceCacheAccess.h"
|
|
||||||
#include "GrTexturePriv.h"
|
|
||||||
|
|
||||||
DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void GrGpuResource::didChangeGpuMemorySize() const {
|
|
||||||
fGpuMemorySize = kInvalidGpuMemorySize;
|
|
||||||
if (this->cacheAccess().isInCache()) {
|
|
||||||
fCacheEntry->didChangeResourceSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() {
|
|
||||||
static int32_t gNextType = 0;
|
|
||||||
|
|
||||||
int32_t type = sk_atomic_inc(&gNextType);
|
|
||||||
if (type >= (1 << 8 * sizeof(ResourceType))) {
|
|
||||||
SkFAIL("Too many Resource Types");
|
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<ResourceType>(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, GrGpuResource* resource)
|
|
||||||
: fResourceCache(resourceCache),
|
|
||||||
fResource(resource),
|
|
||||||
fCachedSize(resource->gpuMemorySize()) {
|
|
||||||
// we assume ownership of the resource, and will unref it when we die
|
|
||||||
SkASSERT(resource);
|
|
||||||
resource->ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
GrResourceCacheEntry::~GrResourceCacheEntry() {
|
|
||||||
// We're relying on having the cache entry to remove this from GrResourceCache2's content hash.
|
|
||||||
// fResource->setCacheEntry(NULL);
|
|
||||||
fResource->unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SK_DEBUG
|
|
||||||
void GrResourceCacheEntry::validate() const {
|
|
||||||
SkASSERT(fResourceCache);
|
|
||||||
SkASSERT(fResource);
|
|
||||||
SkASSERT(fResource->cacheAccess().getCacheEntry() == this);
|
|
||||||
SkASSERT(fResource->gpuMemorySize() == fCachedSize);
|
|
||||||
fResource->validate();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void GrResourceCacheEntry::didChangeResourceSize() {
|
|
||||||
size_t oldSize = fCachedSize;
|
|
||||||
fCachedSize = fResource->gpuMemorySize();
|
|
||||||
if (fCachedSize > oldSize) {
|
|
||||||
fResourceCache->didIncreaseResourceSize(this, fCachedSize - oldSize);
|
|
||||||
} else if (fCachedSize < oldSize) {
|
|
||||||
fResourceCache->didDecreaseResourceSize(this, oldSize - fCachedSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
GrResourceCache::GrResourceCache(const GrDrawTargetCaps* caps, int maxCount, size_t maxBytes)
|
|
||||||
: fMaxCount(maxCount)
|
|
||||||
, fMaxBytes(maxBytes)
|
|
||||||
, fCaps(SkRef(caps)) {
|
|
||||||
#if GR_CACHE_STATS
|
|
||||||
fHighWaterEntryCount = 0;
|
|
||||||
fHighWaterEntryBytes = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fEntryCount = 0;
|
|
||||||
fEntryBytes = 0;
|
|
||||||
|
|
||||||
fPurging = false;
|
|
||||||
|
|
||||||
fOverbudgetCB = NULL;
|
|
||||||
fOverbudgetData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GrResourceCache::~GrResourceCache() {
|
|
||||||
GrAutoResourceCacheValidate atcv(this);
|
|
||||||
|
|
||||||
EntryList::Iter iter;
|
|
||||||
|
|
||||||
// Unlike the removeAll, here we really remove everything, including locked resources.
|
|
||||||
while (GrResourceCacheEntry* entry = fList.head()) {
|
|
||||||
GrAutoResourceCacheValidate atcv(this);
|
|
||||||
|
|
||||||
// remove from our llist
|
|
||||||
this->internalDetach(entry);
|
|
||||||
|
|
||||||
delete entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
|
|
||||||
if (maxResources) {
|
|
||||||
*maxResources = fMaxCount;
|
|
||||||
}
|
|
||||||
if (maxResourceBytes) {
|
|
||||||
*maxResourceBytes = fMaxBytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
|
|
||||||
bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
|
|
||||||
|
|
||||||
fMaxCount = maxResources;
|
|
||||||
fMaxBytes = maxResourceBytes;
|
|
||||||
|
|
||||||
if (smaller) {
|
|
||||||
this->purgeAsNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::internalDetach(GrResourceCacheEntry* entry) {
|
|
||||||
fList.remove(entry);
|
|
||||||
fEntryCount -= 1;
|
|
||||||
fEntryBytes -= entry->fCachedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::attachToHead(GrResourceCacheEntry* entry) {
|
|
||||||
fList.addToHead(entry);
|
|
||||||
|
|
||||||
fEntryCount += 1;
|
|
||||||
fEntryBytes += entry->fCachedSize;
|
|
||||||
|
|
||||||
#if GR_CACHE_STATS
|
|
||||||
if (fHighWaterEntryCount < fEntryCount) {
|
|
||||||
fHighWaterEntryCount = fEntryCount;
|
|
||||||
}
|
|
||||||
if (fHighWaterEntryBytes < fEntryBytes) {
|
|
||||||
fHighWaterEntryBytes = fEntryBytes;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void GrResourceCache::makeResourceMRU(GrGpuResource* resource) {
|
|
||||||
GrResourceCacheEntry* entry = resource->cacheAccess().getCacheEntry();
|
|
||||||
if (entry) {
|
|
||||||
this->internalDetach(entry);
|
|
||||||
this->attachToHead(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::notifyPurgable(const GrGpuResource* resource) {
|
|
||||||
// Remove scratch textures from the cache the moment they become purgeable if
|
|
||||||
// scratch texture reuse is turned off.
|
|
||||||
SkASSERT(resource->cacheAccess().getCacheEntry());
|
|
||||||
if (resource->cacheAccess().isScratch()) {
|
|
||||||
const GrResourceKey& key = resource->cacheAccess().getScratchKey();
|
|
||||||
if (key.getResourceType() == GrTexturePriv::ResourceType() &&
|
|
||||||
!fCaps->reuseScratchTextures() &&
|
|
||||||
!(static_cast<const GrSurface*>(resource)->desc().fFlags & kRenderTarget_GrSurfaceFlag)) {
|
|
||||||
this->deleteResource(resource->cacheAccess().getCacheEntry());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GrResourceCache::addResource(const GrResourceKey& key, GrGpuResource* resource) {
|
|
||||||
if (NULL != resource->cacheAccess().getCacheEntry()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key.isScratch()) {
|
|
||||||
SkASSERT(resource->cacheAccess().isScratch());
|
|
||||||
SkASSERT(key == resource->cacheAccess().getScratchKey());
|
|
||||||
} else {
|
|
||||||
if (!resource->cacheAccess().setContentKey(key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we don't expect to create new resources during a purge. In theory
|
|
||||||
// this could cause purgeAsNeeded() into an infinite loop (e.g.
|
|
||||||
// each resource destroyed creates and locks 2 resources and
|
|
||||||
// unlocks 1 thereby causing a new purge).
|
|
||||||
SkASSERT(!fPurging);
|
|
||||||
GrAutoResourceCacheValidate atcv(this);
|
|
||||||
|
|
||||||
GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, resource));
|
|
||||||
resource->cacheAccess().setCacheEntry(entry);
|
|
||||||
|
|
||||||
this->attachToHead(entry);
|
|
||||||
this->purgeAsNeeded();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountInc) {
|
|
||||||
fEntryBytes += amountInc;
|
|
||||||
this->purgeAsNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountDec) {
|
|
||||||
fEntryBytes -= amountDec;
|
|
||||||
#ifdef SK_DEBUG
|
|
||||||
this->validate();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroying a resource may potentially trigger the unlock of additional
|
|
||||||
* resources which in turn will trigger a nested purge. We block the nested
|
|
||||||
* purge using the fPurging variable. However, the initial purge will keep
|
|
||||||
* looping until either all resources in the cache are unlocked or we've met
|
|
||||||
* the budget. There is an assertion in createAndLock to check against a
|
|
||||||
* resource's destructor inserting new resources into the cache. If these
|
|
||||||
* new resources were unlocked before purgeAsNeeded completed it could
|
|
||||||
* potentially make purgeAsNeeded loop infinitely.
|
|
||||||
*
|
|
||||||
* extraCount and extraBytes are added to the current resource totals to account
|
|
||||||
* for incoming resources (e.g., GrContext is about to add 10MB split between
|
|
||||||
* 10 textures).
|
|
||||||
*/
|
|
||||||
void GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) {
|
|
||||||
if (fPurging) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fPurging = true;
|
|
||||||
|
|
||||||
this->internalPurge(extraCount, extraBytes);
|
|
||||||
if (((fEntryCount+extraCount) > fMaxCount ||
|
|
||||||
(fEntryBytes+extraBytes) > fMaxBytes) &&
|
|
||||||
fOverbudgetCB) {
|
|
||||||
// Despite the purge we're still over budget. See if Ganesh can
|
|
||||||
// release some resources and purge again.
|
|
||||||
if ((*fOverbudgetCB)(fOverbudgetData)) {
|
|
||||||
this->internalPurge(extraCount, extraBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fPurging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::purgeInvalidated() {
|
|
||||||
// TODO: Implement this in GrResourceCache2.
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::deleteResource(GrResourceCacheEntry* entry) {
|
|
||||||
SkASSERT(entry->fResource->isPurgable());
|
|
||||||
// remove from our llist
|
|
||||||
this->internalDetach(entry);
|
|
||||||
delete entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::internalPurge(int extraCount, size_t extraBytes) {
|
|
||||||
SkASSERT(fPurging);
|
|
||||||
|
|
||||||
bool withinBudget = false;
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
// The purging process is repeated several times since one pass
|
|
||||||
// may free up other resources
|
|
||||||
do {
|
|
||||||
EntryList::Iter iter;
|
|
||||||
|
|
||||||
changed = false;
|
|
||||||
|
|
||||||
// Note: the following code relies on the fact that the
|
|
||||||
// doubly linked list doesn't invalidate its data/pointers
|
|
||||||
// outside of the specific area where a deletion occurs (e.g.,
|
|
||||||
// in internalDetach)
|
|
||||||
GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart);
|
|
||||||
|
|
||||||
while (entry) {
|
|
||||||
GrAutoResourceCacheValidate atcv(this);
|
|
||||||
|
|
||||||
if ((fEntryCount+extraCount) <= fMaxCount &&
|
|
||||||
(fEntryBytes+extraBytes) <= fMaxBytes) {
|
|
||||||
withinBudget = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
GrResourceCacheEntry* prev = iter.prev();
|
|
||||||
if (entry->fResource->isPurgable()) {
|
|
||||||
changed = true;
|
|
||||||
this->deleteResource(entry);
|
|
||||||
}
|
|
||||||
entry = prev;
|
|
||||||
}
|
|
||||||
} while (!withinBudget && changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::purgeAllUnlocked() {
|
|
||||||
GrAutoResourceCacheValidate atcv(this);
|
|
||||||
|
|
||||||
// we can have one GrCacheable holding a lock on another
|
|
||||||
// so we don't want to just do a simple loop kicking each
|
|
||||||
// entry out. Instead change the budget and purge.
|
|
||||||
|
|
||||||
size_t savedMaxBytes = fMaxBytes;
|
|
||||||
int savedMaxCount = fMaxCount;
|
|
||||||
fMaxBytes = (size_t) -1;
|
|
||||||
fMaxCount = 0;
|
|
||||||
this->purgeAsNeeded();
|
|
||||||
|
|
||||||
fMaxBytes = savedMaxBytes;
|
|
||||||
fMaxCount = savedMaxCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifdef SK_DEBUG
|
|
||||||
size_t GrResourceCache::countBytes(const EntryList& list) {
|
|
||||||
size_t bytes = 0;
|
|
||||||
|
|
||||||
EntryList::Iter iter;
|
|
||||||
|
|
||||||
const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(list),
|
|
||||||
EntryList::Iter::kTail_IterStart);
|
|
||||||
|
|
||||||
for ( ; entry; entry = iter.prev()) {
|
|
||||||
bytes += entry->resource()->gpuMemorySize();
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool both_zero_or_nonzero(int count, size_t bytes) {
|
|
||||||
return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrResourceCache::validate() const {
|
|
||||||
fList.validate();
|
|
||||||
SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes));
|
|
||||||
|
|
||||||
EntryList::Iter iter;
|
|
||||||
|
|
||||||
// check that the shareable entries are okay
|
|
||||||
const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fList),
|
|
||||||
EntryList::Iter::kHead_IterStart);
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
for ( ; entry; entry = iter.next()) {
|
|
||||||
entry->validate();
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
SkASSERT(count == fEntryCount);
|
|
||||||
|
|
||||||
size_t bytes = this->countBytes(fList);
|
|
||||||
SkASSERT(bytes == fEntryBytes);
|
|
||||||
SkASSERT(fList.countEntries() == fEntryCount);
|
|
||||||
}
|
|
||||||
#endif // SK_DEBUG
|
|
||||||
|
|
||||||
#if GR_CACHE_STATS
|
|
||||||
|
|
||||||
void GrResourceCache::printStats() {
|
|
||||||
int locked = 0;
|
|
||||||
int scratch = 0;
|
|
||||||
|
|
||||||
EntryList::Iter iter;
|
|
||||||
|
|
||||||
GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart);
|
|
||||||
|
|
||||||
for ( ; entry; entry = iter.prev()) {
|
|
||||||
if (!entry->fResource->isPurgable()) {
|
|
||||||
++locked;
|
|
||||||
}
|
|
||||||
if (entry->fResource->cacheAccess().isScratch()) {
|
|
||||||
++scratch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float countUtilization = (100.f * fEntryCount) / fMaxCount;
|
|
||||||
float byteUtilization = (100.f * fEntryBytes) / fMaxBytes;
|
|
||||||
|
|
||||||
SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes);
|
|
||||||
SkDebugf("\t\tEntry Count: current %d (%d locked, %d scratch %.2g%% full), high %d\n",
|
|
||||||
fEntryCount, locked, scratch, countUtilization, fHighWaterEntryCount);
|
|
||||||
SkDebugf("\t\tEntry Bytes: current %d (%.2g%% full) high %d\n",
|
|
||||||
fEntryBytes, byteUtilization, fHighWaterEntryBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
@ -1,251 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GrResourceCache_DEFINED
|
|
||||||
#define GrResourceCache_DEFINED
|
|
||||||
|
|
||||||
#include "GrDrawTargetCaps.h"
|
|
||||||
#include "GrResourceKey.h"
|
|
||||||
#include "SkTMultiMap.h"
|
|
||||||
#include "SkMessageBus.h"
|
|
||||||
#include "SkTInternalLList.h"
|
|
||||||
|
|
||||||
class GrGpuResource;
|
|
||||||
class GrResourceCache;
|
|
||||||
class GrResourceCacheEntry;
|
|
||||||
|
|
||||||
|
|
||||||
// The cache listens for these messages to purge junk resources proactively.
|
|
||||||
struct GrResourceInvalidatedMessage {
|
|
||||||
GrResourceKey key;
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class GrResourceCacheEntry {
|
|
||||||
public:
|
|
||||||
GrGpuResource* resource() const { return fResource; }
|
|
||||||
|
|
||||||
static uint32_t Hash(const GrGpuResource* resource) {
|
|
||||||
return static_cast<uint32_t>(reinterpret_cast<intptr_t>(resource));
|
|
||||||
}
|
|
||||||
#ifdef SK_DEBUG
|
|
||||||
void validate() const;
|
|
||||||
#else
|
|
||||||
void validate() const {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the cached size for this entry and inform the resource cache that
|
|
||||||
* it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize,
|
|
||||||
* not directly from here.
|
|
||||||
*/
|
|
||||||
void didChangeResourceSize();
|
|
||||||
|
|
||||||
private:
|
|
||||||
GrResourceCacheEntry(GrResourceCache*, GrGpuResource*);
|
|
||||||
~GrResourceCacheEntry();
|
|
||||||
|
|
||||||
GrResourceCache* fResourceCache;
|
|
||||||
GrGpuResource* fResource;
|
|
||||||
size_t fCachedSize;
|
|
||||||
|
|
||||||
// Linked list for the LRU ordering.
|
|
||||||
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
|
|
||||||
|
|
||||||
friend class GrResourceCache;
|
|
||||||
friend class GrContext;
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache of GrGpuResource objects.
|
|
||||||
*
|
|
||||||
* These have a corresponding GrResourceKey, built from 128bits identifying the
|
|
||||||
* resource. Multiple resources can map to same GrResourceKey.
|
|
||||||
*
|
|
||||||
* The cache stores the entries in a double-linked list, which is its LRU.
|
|
||||||
* When an entry is "locked" (i.e. given to the caller), it is moved to the
|
|
||||||
* head of the list. If/when we must purge some of the entries, we walk the
|
|
||||||
* list backwards from the tail, since those are the least recently used.
|
|
||||||
*
|
|
||||||
* For fast searches, we maintain a hash map based on the GrResourceKey.
|
|
||||||
*
|
|
||||||
* It is a goal to make the GrResourceCache the central repository and bookkeeper
|
|
||||||
* of all resources. It should replace the linked list of GrGpuResources that
|
|
||||||
* GrGpu uses to call abandon/release.
|
|
||||||
*/
|
|
||||||
class GrResourceCache {
|
|
||||||
public:
|
|
||||||
GrResourceCache(const GrDrawTargetCaps*, int maxCount, size_t maxBytes);
|
|
||||||
~GrResourceCache();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current resource cache limits.
|
|
||||||
*
|
|
||||||
* @param maxResource If non-null, returns maximum number of resources
|
|
||||||
* that can be held in the cache.
|
|
||||||
* @param maxBytes If non-null, returns maximum number of bytes of
|
|
||||||
* gpu memory that can be held in the cache.
|
|
||||||
*/
|
|
||||||
void getLimits(int* maxResources, size_t* maxBytes) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the resource cache limits. If the current cache exceeds either
|
|
||||||
* of these, it will be purged (LRU) to keep the cache within these limits.
|
|
||||||
*
|
|
||||||
* @param maxResources The maximum number of resources that can be held in
|
|
||||||
* the cache.
|
|
||||||
* @param maxBytes The maximum number of bytes of resource memory that
|
|
||||||
* can be held in the cache.
|
|
||||||
*/
|
|
||||||
void setLimits(int maxResources, size_t maxResourceBytes);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The callback function used by the cache when it is still over budget
|
|
||||||
* after a purge. The passed in 'data' is the same 'data' handed to
|
|
||||||
* setOverbudgetCallback. The callback returns true if some resources
|
|
||||||
* have been freed.
|
|
||||||
*/
|
|
||||||
typedef bool (*PFOverbudgetCB)(void* data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the callback the cache should use when it is still over budget
|
|
||||||
* after a purge. The 'data' provided here will be passed back to the
|
|
||||||
* callback. Note that the cache will attempt to purge any resources newly
|
|
||||||
* freed by the callback.
|
|
||||||
*/
|
|
||||||
void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
|
|
||||||
fOverbudgetCB = overbudgetCB;
|
|
||||||
fOverbudgetData = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of bytes consumed by cached resources.
|
|
||||||
*/
|
|
||||||
size_t getCachedResourceBytes() const { return fEntryBytes; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of cached resources.
|
|
||||||
*/
|
|
||||||
int getCachedResourceCount() const { return fEntryCount; }
|
|
||||||
|
|
||||||
void makeResourceMRU(GrGpuResource*);
|
|
||||||
|
|
||||||
/** Called by GrGpuResources when they detects that they are newly purgable. */
|
|
||||||
void notifyPurgable(const GrGpuResource*);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the new resource to the cache (by creating a new cache entry based
|
|
||||||
* on the provided key and resource).
|
|
||||||
*
|
|
||||||
* Ownership of the resource is transferred to the resource cache,
|
|
||||||
* which will unref() it when it is purged or deleted.
|
|
||||||
*
|
|
||||||
* This can fail if the key is already taken, or the resource is already in
|
|
||||||
* the cache.
|
|
||||||
*/
|
|
||||||
bool addResource(const GrResourceKey& key, GrGpuResource* resource);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the cache that the size of a resource has changed.
|
|
||||||
*/
|
|
||||||
void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
|
|
||||||
void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a resource from the cache and delete it!
|
|
||||||
*/
|
|
||||||
void deleteResource(GrResourceCacheEntry* entry);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes every resource in the cache that isn't locked.
|
|
||||||
*/
|
|
||||||
void purgeAllUnlocked();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow cache to purge unused resources to obey resource limitations
|
|
||||||
* Note: this entry point will be hidden (again) once totally ref-driven
|
|
||||||
* cache maintenance is implemented. Note that the overbudget callback
|
|
||||||
* will be called if the initial purge doesn't get the cache under
|
|
||||||
* its budget.
|
|
||||||
*
|
|
||||||
* extraCount and extraBytes are added to the current resource allocation
|
|
||||||
* to make sure enough room is available for future additions (e.g,
|
|
||||||
* 10MB across 10 textures is about to be added).
|
|
||||||
*/
|
|
||||||
void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
|
|
||||||
|
|
||||||
#ifdef SK_DEBUG
|
|
||||||
void validate() const;
|
|
||||||
#else
|
|
||||||
void validate() const {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if GR_CACHE_STATS
|
|
||||||
void printStats();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
void internalDetach(GrResourceCacheEntry*);
|
|
||||||
void attachToHead(GrResourceCacheEntry*);
|
|
||||||
void purgeInvalidated();
|
|
||||||
void internalPurge(int extraCount, size_t extraBytes);
|
|
||||||
#ifdef SK_DEBUG
|
|
||||||
static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// We're an internal doubly linked list
|
|
||||||
typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
|
|
||||||
EntryList fList;
|
|
||||||
|
|
||||||
// our budget, used in purgeAsNeeded()
|
|
||||||
int fMaxCount;
|
|
||||||
size_t fMaxBytes;
|
|
||||||
|
|
||||||
// our current stats, related to our budget
|
|
||||||
#if GR_CACHE_STATS
|
|
||||||
int fHighWaterEntryCount;
|
|
||||||
size_t fHighWaterEntryBytes;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int fEntryCount;
|
|
||||||
size_t fEntryBytes;
|
|
||||||
|
|
||||||
// prevents recursive purging
|
|
||||||
bool fPurging;
|
|
||||||
|
|
||||||
PFOverbudgetCB fOverbudgetCB;
|
|
||||||
void* fOverbudgetData;
|
|
||||||
|
|
||||||
SkAutoTUnref<const GrDrawTargetCaps> fCaps;
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifdef SK_DEBUG
|
|
||||||
class GrAutoResourceCacheValidate {
|
|
||||||
public:
|
|
||||||
GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
|
|
||||||
cache->validate();
|
|
||||||
}
|
|
||||||
~GrAutoResourceCacheValidate() {
|
|
||||||
fCache->validate();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
GrResourceCache* fCache;
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
class GrAutoResourceCacheValidate {
|
|
||||||
public:
|
|
||||||
GrAutoResourceCacheValidate(GrResourceCache*) {}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -10,6 +10,13 @@
|
|||||||
#include "GrResourceCache2.h"
|
#include "GrResourceCache2.h"
|
||||||
#include "GrGpuResource.h"
|
#include "GrGpuResource.h"
|
||||||
|
|
||||||
|
#include "SkGr.h"
|
||||||
|
#include "SkMessageBus.h"
|
||||||
|
|
||||||
|
DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
GrResourceKey& GrResourceKey::NullScratchKey() {
|
GrResourceKey& GrResourceKey::NullScratchKey() {
|
||||||
static const GrCacheID::Key kBogusKey = { { {0} } };
|
static const GrCacheID::Key kBogusKey = { { {0} } };
|
||||||
static GrCacheID kBogusID(ScratchDomain(), kBogusKey);
|
static GrCacheID kBogusID(ScratchDomain(), kBogusKey);
|
||||||
@ -27,26 +34,85 @@ GrCacheID::Domain GrResourceKey::ScratchDomain() {
|
|||||||
return gDomain;
|
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() {
|
GrResourceCache2::~GrResourceCache2() {
|
||||||
this->releaseAll();
|
this->releaseAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GrResourceCache2::setLimits(int count, size_t bytes) {
|
||||||
|
fMaxCount = count;
|
||||||
|
fMaxBytes = bytes;
|
||||||
|
this->purgeAsNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
void GrResourceCache2::insertResource(GrGpuResource* resource) {
|
void GrResourceCache2::insertResource(GrGpuResource* resource) {
|
||||||
|
AutoValidate av(this);
|
||||||
|
|
||||||
SkASSERT(resource);
|
SkASSERT(resource);
|
||||||
SkASSERT(!resource->wasDestroyed());
|
SkASSERT(!resource->wasDestroyed());
|
||||||
SkASSERT(!this->isInCache(resource));
|
SkASSERT(!this->isInCache(resource));
|
||||||
|
SkASSERT(!fPurging);
|
||||||
fResources.addToHead(resource);
|
fResources.addToHead(resource);
|
||||||
|
resource->ref();
|
||||||
|
|
||||||
++fCount;
|
++fCount;
|
||||||
|
SkDEBUGCODE(fHighWaterCount = SkTMax(fCount, fHighWaterCount));
|
||||||
|
fBytes += resource->gpuMemorySize();
|
||||||
|
SkDEBUGCODE(fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes));
|
||||||
if (!resource->cacheAccess().getScratchKey().isNullScratch()) {
|
if (!resource->cacheAccess().getScratchKey().isNullScratch()) {
|
||||||
// TODO(bsalomon): Make this assertion possible.
|
// TODO(bsalomon): Make this assertion possible.
|
||||||
// SkASSERT(!resource->isWrapped());
|
// SkASSERT(!resource->isWrapped());
|
||||||
fScratchMap.insert(resource->cacheAccess().getScratchKey(), resource);
|
fScratchMap.insert(resource->cacheAccess().getScratchKey(), resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->purgeAsNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrResourceCache2::removeResource(GrGpuResource* resource) {
|
void GrResourceCache2::removeResource(GrGpuResource* resource) {
|
||||||
|
AutoValidate av(this);
|
||||||
|
|
||||||
|
--fCount;
|
||||||
|
fBytes -= resource->gpuMemorySize();
|
||||||
SkASSERT(this->isInCache(resource));
|
SkASSERT(this->isInCache(resource));
|
||||||
fResources.remove(resource);
|
fResources.remove(resource);
|
||||||
if (!resource->cacheAccess().getScratchKey().isNullScratch()) {
|
if (!resource->cacheAccess().getScratchKey().isNullScratch()) {
|
||||||
@ -55,13 +121,16 @@ void GrResourceCache2::removeResource(GrGpuResource* resource) {
|
|||||||
if (const GrResourceKey* contentKey = resource->cacheAccess().getContentKey()) {
|
if (const GrResourceKey* contentKey = resource->cacheAccess().getContentKey()) {
|
||||||
fContentHash.remove(*contentKey);
|
fContentHash.remove(*contentKey);
|
||||||
}
|
}
|
||||||
--fCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrResourceCache2::abandonAll() {
|
void GrResourceCache2::abandonAll() {
|
||||||
|
AutoValidate av(this);
|
||||||
|
|
||||||
|
SkASSERT(!fPurging);
|
||||||
while (GrGpuResource* head = fResources.head()) {
|
while (GrGpuResource* head = fResources.head()) {
|
||||||
SkASSERT(!head->wasDestroyed());
|
SkASSERT(!head->wasDestroyed());
|
||||||
head->abandon();
|
head->abandon();
|
||||||
|
head->unref();
|
||||||
// abandon should have already removed this from the list.
|
// abandon should have already removed this from the list.
|
||||||
SkASSERT(head != fResources.head());
|
SkASSERT(head != fResources.head());
|
||||||
}
|
}
|
||||||
@ -71,9 +140,13 @@ void GrResourceCache2::abandonAll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrResourceCache2::releaseAll() {
|
void GrResourceCache2::releaseAll() {
|
||||||
|
AutoValidate av(this);
|
||||||
|
|
||||||
|
SkASSERT(!fPurging);
|
||||||
while (GrGpuResource* head = fResources.head()) {
|
while (GrGpuResource* head = fResources.head()) {
|
||||||
SkASSERT(!head->wasDestroyed());
|
SkASSERT(!head->wasDestroyed());
|
||||||
head->release();
|
head->release();
|
||||||
|
head->unref();
|
||||||
// release should have already removed this from the list.
|
// release should have already removed this from the list.
|
||||||
SkASSERT(head != fResources.head());
|
SkASSERT(head != fResources.head());
|
||||||
}
|
}
|
||||||
@ -99,11 +172,16 @@ private:
|
|||||||
|
|
||||||
GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey& scratchKey,
|
GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey& scratchKey,
|
||||||
uint32_t flags) {
|
uint32_t flags) {
|
||||||
|
AutoValidate av(this);
|
||||||
|
|
||||||
|
SkASSERT(!fPurging);
|
||||||
SkASSERT(scratchKey.isScratch());
|
SkASSERT(scratchKey.isScratch());
|
||||||
|
|
||||||
|
GrGpuResource* resource;
|
||||||
if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
|
if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
|
||||||
GrGpuResource* resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
|
resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
|
||||||
if (resource) {
|
if (resource) {
|
||||||
|
this->makeResourceMRU(resource);
|
||||||
return SkRef(resource);
|
return SkRef(resource);
|
||||||
} else if (flags & kRequireNoPendingIO_ScratchFlag) {
|
} else if (flags & kRequireNoPendingIO_ScratchFlag) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -111,11 +189,18 @@ GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey&
|
|||||||
// TODO: fail here when kPrefer is specified, we didn't find a resource without pending io,
|
// 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.
|
// but there is still space in our budget for the resource.
|
||||||
}
|
}
|
||||||
return SkSafeRef(fScratchMap.find(scratchKey, AvailableForScratchUse(false)));
|
resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
|
||||||
|
if (resource) {
|
||||||
|
resource->ref();
|
||||||
|
this->makeResourceMRU(resource);
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) {
|
bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) {
|
||||||
|
SkASSERT(!fPurging);
|
||||||
SkASSERT(resource);
|
SkASSERT(resource);
|
||||||
|
SkASSERT(this->isInCache(resource));
|
||||||
SkASSERT(resource->cacheAccess().getContentKey());
|
SkASSERT(resource->cacheAccess().getContentKey());
|
||||||
SkASSERT(!resource->cacheAccess().getContentKey()->isScratch());
|
SkASSERT(!resource->cacheAccess().getContentKey()->isScratch());
|
||||||
|
|
||||||
@ -125,5 +210,214 @@ bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fContentHash.add(resource);
|
fContentHash.add(resource);
|
||||||
|
this->validate();
|
||||||
return true;
|
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,27 +17,65 @@
|
|||||||
#include "SkTMultiMap.h"
|
#include "SkTMultiMap.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Eventual replacement for GrResourceCache. Currently it simply holds a list
|
* Manages the lifetime of all GrGpuResource instances.
|
||||||
* of all GrGpuResource objects for a GrContext. It is used to invalidate all
|
*
|
||||||
* the resources when necessary.
|
* Resources may have optionally have two types of keys:
|
||||||
|
* 1) A scratch key. This is for resources whose allocations are cached but not their contents.
|
||||||
|
* Multiple resources can share the same scratch key. This is so a caller can have two
|
||||||
|
* resource instances with the same properties (e.g. multipass rendering that ping pongs
|
||||||
|
* between two temporary surfaces. The scratch key is set at resource creation time and
|
||||||
|
* should never change. Resources need not have a scratch key.
|
||||||
|
* 2) A content key. This key represents the contents of the resource rather than just its
|
||||||
|
* allocation properties. They may not collide. The content key can be set after resource
|
||||||
|
* creation. Currently it may only be set once and cannot be cleared. This restriction will
|
||||||
|
* be removed.
|
||||||
|
* If a resource has neither key type then it will be deleted as soon as the last reference to it
|
||||||
|
* is dropped. If a key has both keys the content key takes precedence.
|
||||||
*/
|
*/
|
||||||
class GrResourceCache2 {
|
class GrResourceCache2 {
|
||||||
public:
|
public:
|
||||||
GrResourceCache2() : fCount(0) {};
|
GrResourceCache2();
|
||||||
~GrResourceCache2();
|
~GrResourceCache2();
|
||||||
|
|
||||||
void insertResource(GrGpuResource*);
|
/** Used to access functionality needed by GrGpuResource for lifetime management. */
|
||||||
|
class ResourceAccess;
|
||||||
|
ResourceAccess resourceAccess();
|
||||||
|
|
||||||
void removeResource(GrGpuResource*);
|
/**
|
||||||
|
* Sets the cache limits in terms of number of resources and max gpu memory byte size.
|
||||||
|
*/
|
||||||
|
void setLimits(int count, size_t bytes);
|
||||||
|
|
||||||
// This currently returns a bool and fails when an existing resource has a key that collides
|
/**
|
||||||
// with the new content key. In the future it will null out the content key for the existing
|
* Returns the number of cached resources.
|
||||||
// resource. The failure is a temporary measure taken because duties are split between two
|
*/
|
||||||
// cache objects currently.
|
int getResourceCount() const { return fCount; }
|
||||||
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();
|
void abandonAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the backend API resources owned by all GrGpuResource objects and removes them from
|
||||||
|
* the cache.
|
||||||
|
*/
|
||||||
void releaseAll();
|
void releaseAll();
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -46,6 +84,10 @@ public:
|
|||||||
/** Will not return any resources that match but have pending IO. */
|
/** Will not return any resources that match but have pending IO. */
|
||||||
kRequireNoPendingIO_ScratchFlag = 0x2,
|
kRequireNoPendingIO_ScratchFlag = 0x2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a resource that matches a scratch key.
|
||||||
|
*/
|
||||||
GrGpuResource* findAndRefScratchResource(const GrResourceKey& scratchKey, uint32_t flags = 0);
|
GrGpuResource* findAndRefScratchResource(const GrResourceKey& scratchKey, uint32_t flags = 0);
|
||||||
|
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
@ -56,21 +98,80 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a resource that matches a content key.
|
||||||
|
*/
|
||||||
GrGpuResource* findAndRefContentResource(const GrResourceKey& contentKey) {
|
GrGpuResource* findAndRefContentResource(const GrResourceKey& contentKey) {
|
||||||
SkASSERT(!contentKey.isScratch());
|
SkASSERT(!contentKey.isScratch());
|
||||||
return SkSafeRef(fContentHash.find(contentKey));
|
GrGpuResource* resource = fContentHash.find(contentKey);
|
||||||
|
if (resource) {
|
||||||
|
resource->ref();
|
||||||
|
this->makeResourceMRU(resource);
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query whether a content key exists in the cache.
|
||||||
|
*/
|
||||||
bool hasContentKey(const GrResourceKey& contentKey) const {
|
bool hasContentKey(const GrResourceKey& contentKey) const {
|
||||||
SkASSERT(!contentKey.isScratch());
|
SkASSERT(!contentKey.isScratch());
|
||||||
return SkToBool(fContentHash.find(contentKey));
|
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:
|
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
|
#ifdef SK_DEBUG
|
||||||
bool isInCache(const GrGpuResource* r) const { return fResources.isInList(r); }
|
bool isInCache(const GrGpuResource* r) const { return fResources.isInList(r); }
|
||||||
|
void validate() const;
|
||||||
|
#else
|
||||||
|
void validate() const {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class AutoValidate;
|
||||||
|
|
||||||
class AvailableForScratchUse;
|
class AvailableForScratchUse;
|
||||||
|
|
||||||
struct ScratchMapTraits {
|
struct ScratchMapTraits {
|
||||||
@ -91,12 +192,86 @@ private:
|
|||||||
};
|
};
|
||||||
typedef SkTDynamicHash<GrGpuResource, GrResourceKey, ContentHashTraits> ContentHash;
|
typedef SkTDynamicHash<GrGpuResource, GrResourceKey, ContentHashTraits> ContentHash;
|
||||||
|
|
||||||
int fCount;
|
typedef SkTInternalLList<GrGpuResource> ResourceList;
|
||||||
SkTInternalLList<GrGpuResource> fResources;
|
|
||||||
|
ResourceList fResources;
|
||||||
// This map holds all resources that can be used as scratch resources.
|
// This map holds all resources that can be used as scratch resources.
|
||||||
ScratchMap fScratchMap;
|
ScratchMap fScratchMap;
|
||||||
// This holds all resources that have content keys.
|
// This holds all resources that have content keys.
|
||||||
ContentHash fContentHash;
|
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
|
#endif
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
#include "GrResourceCache2.h"
|
#include "GrResourceCache2.h"
|
||||||
|
|
||||||
void GrStencilBuffer::transferToCache() {
|
void GrStencilBuffer::transferToCache() {
|
||||||
SkASSERT(!this->cacheAccess().isInCache());
|
|
||||||
|
|
||||||
this->getGpu()->getContext()->addStencilBuffer(this);
|
this->getGpu()->getContext()->addStencilBuffer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include "GrTest.h"
|
#include "GrTest.h"
|
||||||
|
|
||||||
#include "GrInOrderDrawBuffer.h"
|
#include "GrInOrderDrawBuffer.h"
|
||||||
#include "GrResourceCache.h"
|
#include "GrResourceCache2.h"
|
||||||
|
|
||||||
void GrTestTarget::init(GrContext* ctx, GrDrawTarget* target) {
|
void GrTestTarget::init(GrContext* ctx, GrDrawTarget* target) {
|
||||||
SkASSERT(!fContext);
|
SkASSERT(!fContext);
|
||||||
@ -38,7 +38,7 @@ void GrContext::setMaxTextureSizeOverride(int maxTextureSizeOverride) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GrContext::purgeAllUnlockedResources() {
|
void GrContext::purgeAllUnlockedResources() {
|
||||||
fResourceCache->purgeAllUnlocked();
|
fResourceCache2->purgeAllUnlocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "GrContext.h"
|
#include "GrContext.h"
|
||||||
#include "GrDrawTargetCaps.h"
|
#include "GrDrawTargetCaps.h"
|
||||||
#include "GrGpu.h"
|
#include "GrGpu.h"
|
||||||
#include "GrResourceCache.h"
|
|
||||||
#include "GrTexture.h"
|
#include "GrTexture.h"
|
||||||
#include "GrTexturePriv.h"
|
#include "GrTexturePriv.h"
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include "SkMessageBus.h"
|
#include "SkMessageBus.h"
|
||||||
#include "SkPixelRef.h"
|
#include "SkPixelRef.h"
|
||||||
#include "SkTextureCompressor.h"
|
#include "SkTextureCompressor.h"
|
||||||
#include "GrResourceCache.h"
|
|
||||||
#include "GrGpu.h"
|
#include "GrGpu.h"
|
||||||
#include "effects/GrDitherEffect.h"
|
#include "effects/GrDitherEffect.h"
|
||||||
#include "GrDrawTargetCaps.h"
|
#include "GrDrawTargetCaps.h"
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
#include "GrContext.h"
|
#include "GrContext.h"
|
||||||
#include "GrContextFactory.h"
|
#include "GrContextFactory.h"
|
||||||
#include "GrGpu.h"
|
#include "GrGpu.h"
|
||||||
#include "GrResourceCache.h"
|
|
||||||
#include "GrResourceCache2.h"
|
#include "GrResourceCache2.h"
|
||||||
#include "SkCanvas.h"
|
#include "SkCanvas.h"
|
||||||
|
#include "SkGr.h"
|
||||||
|
#include "SkMessageBus.h"
|
||||||
#include "SkSurface.h"
|
#include "SkSurface.h"
|
||||||
#include "Test.h"
|
#include "Test.h"
|
||||||
|
|
||||||
@ -67,7 +68,6 @@ public:
|
|||||||
SK_DECLARE_INST_COUNT(TestResource);
|
SK_DECLARE_INST_COUNT(TestResource);
|
||||||
TestResource(GrGpu* gpu)
|
TestResource(GrGpu* gpu)
|
||||||
: INHERITED(gpu, false)
|
: INHERITED(gpu, false)
|
||||||
, fCache(NULL)
|
|
||||||
, fToDelete(NULL)
|
, fToDelete(NULL)
|
||||||
, fSize(kDefaultSize) {
|
, fSize(kDefaultSize) {
|
||||||
++fNumAlive;
|
++fNumAlive;
|
||||||
@ -76,7 +76,6 @@ public:
|
|||||||
|
|
||||||
TestResource(GrGpu* gpu, const GrResourceKey& scratchKey)
|
TestResource(GrGpu* gpu, const GrResourceKey& scratchKey)
|
||||||
: INHERITED(gpu, false)
|
: INHERITED(gpu, false)
|
||||||
, fCache(NULL)
|
|
||||||
, fToDelete(NULL)
|
, fToDelete(NULL)
|
||||||
, fSize(kDefaultSize) {
|
, fSize(kDefaultSize) {
|
||||||
this->setScratchKey(scratchKey);
|
this->setScratchKey(scratchKey);
|
||||||
@ -86,11 +85,7 @@ public:
|
|||||||
|
|
||||||
~TestResource() {
|
~TestResource() {
|
||||||
--fNumAlive;
|
--fNumAlive;
|
||||||
if (fToDelete) {
|
SkSafeUnref(fToDelete);
|
||||||
// Breaks our little 2-element cycle below.
|
|
||||||
fToDelete->setDeleteWhenDestroyed(NULL, NULL);
|
|
||||||
fCache->deleteResource(fToDelete->cacheAccess().getCacheEntry());
|
|
||||||
}
|
|
||||||
this->release();
|
this->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,15 +96,13 @@ public:
|
|||||||
|
|
||||||
static int NumAlive() { return fNumAlive; }
|
static int NumAlive() { return fNumAlive; }
|
||||||
|
|
||||||
void setDeleteWhenDestroyed(GrResourceCache* cache, TestResource* resource) {
|
void setUnrefWhenDestroyed(TestResource* resource) {
|
||||||
fCache = cache;
|
SkRefCnt_SafeAssign(fToDelete, resource);
|
||||||
fToDelete = resource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t onGpuMemorySize() const SK_OVERRIDE { return fSize; }
|
size_t onGpuMemorySize() const SK_OVERRIDE { return fSize; }
|
||||||
|
|
||||||
GrResourceCache* fCache;
|
|
||||||
TestResource* fToDelete;
|
TestResource* fToDelete;
|
||||||
size_t fSize;
|
size_t fSize;
|
||||||
static int fNumAlive;
|
static int fNumAlive;
|
||||||
@ -118,6 +111,61 @@ private:
|
|||||||
};
|
};
|
||||||
int TestResource::fNumAlive = 0;
|
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) {
|
static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
|
||||||
SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
|
SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
|
||||||
REPORTER_ASSERT(reporter, SkToBool(context));
|
REPORTER_ASSERT(reporter, SkToBool(context));
|
||||||
@ -125,10 +173,9 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context->setResourceCacheLimits(5, 30000);
|
context->setResourceCacheLimits(5, 30000);
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||||
SkDEBUGCODE(GrResourceCache2* cache2 = context->getResourceCache2();)
|
cache2->purgeAllUnlocked();
|
||||||
cache->purgeAllUnlocked();
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
|
||||||
|
|
||||||
GrCacheID::Key keyData;
|
GrCacheID::Key keyData;
|
||||||
memset(&keyData, 0, sizeof(keyData));
|
memset(&keyData, 0, sizeof(keyData));
|
||||||
@ -142,30 +189,16 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
|
|||||||
a->setSize(11);
|
a->setSize(11);
|
||||||
b->setSize(12);
|
b->setSize(12);
|
||||||
// Scratch resources are registered with GrResourceCache2 just by existing. There are 2.
|
// 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());
|
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
|
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.
|
// Our refs mean that the resources are non purgable.
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||||
|
|
||||||
// Unref but don't purge
|
// Unref but don't purge
|
||||||
a->unref();
|
a->unref();
|
||||||
@ -174,9 +207,9 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
|
|||||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
|
SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));)
|
||||||
|
|
||||||
// Purge again. This time resources should be purgable.
|
// Purge again. This time resources should be purgable.
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||||
REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceCount());
|
REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
|
||||||
SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));)
|
SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,9 +220,9 @@ static void test_duplicate_content_key(skiatest::Reporter* reporter) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context->setResourceCacheLimits(5, 30000);
|
context->setResourceCacheLimits(5, 30000);
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
|
|
||||||
GrCacheID::Domain domain = GrCacheID::GenerateDomain();
|
GrCacheID::Domain domain = GrCacheID::GenerateDomain();
|
||||||
GrCacheID::Key keyData;
|
GrCacheID::Key keyData;
|
||||||
@ -197,30 +230,42 @@ static void test_duplicate_content_key(skiatest::Reporter* reporter) {
|
|||||||
GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
|
GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
|
||||||
GrResourceKey key(GrCacheID(domain, keyData), t, 0);
|
GrResourceKey key(GrCacheID(domain, keyData), t, 0);
|
||||||
|
|
||||||
|
|
||||||
// Create two resources that we will attempt to register with the same content key.
|
// Create two resources that we will attempt to register with the same content key.
|
||||||
TestResource* a = new TestResource(context->getGpu());
|
TestResource* a = new TestResource(context->getGpu());
|
||||||
TestResource* b = new TestResource(context->getGpu());
|
TestResource* b = new TestResource(context->getGpu());
|
||||||
a->setSize(11);
|
a->setSize(11);
|
||||||
b->setSize(12);
|
b->setSize(12);
|
||||||
REPORTER_ASSERT(reporter, cache->addResource(key, a));
|
|
||||||
// Can't add the same or another resource with the same key.
|
// Can't set the same content key on two resources.
|
||||||
REPORTER_ASSERT(reporter, !cache->addResource(key, a));
|
REPORTER_ASSERT(reporter, a->cacheAccess().setContentKey(key));
|
||||||
REPORTER_ASSERT(reporter, !cache->addResource(key, b));
|
REPORTER_ASSERT(reporter, !b->cacheAccess().setContentKey(key));
|
||||||
REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
|
|
||||||
REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getCachedResourceBytes());
|
// 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, 2 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||||
|
|
||||||
b->unref();
|
b->unref();
|
||||||
cache->purgeAllUnlocked();
|
// Now b should be gone.
|
||||||
a->setSize(10);
|
REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
|
||||||
REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
|
REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache2->getResourceBytes());
|
||||||
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
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();
|
a->unref();
|
||||||
cache->purgeAllUnlocked();
|
REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
|
||||||
REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceCount());
|
REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache2->getResourceBytes());
|
||||||
REPORTER_ASSERT(reporter, 0 == cache->getCachedResourceBytes());
|
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
||||||
|
|
||||||
|
cache2->purgeAllUnlocked();
|
||||||
|
REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount());
|
||||||
|
REPORTER_ASSERT(reporter, 0 == cache2->getResourceBytes());
|
||||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,18 +290,17 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
|
|||||||
GrResourceKey key3(GrCacheID(domain, keyData), t, 0);
|
GrResourceKey key3(GrCacheID(domain, keyData), t, 0);
|
||||||
|
|
||||||
context->setResourceCacheLimits(5, 30000);
|
context->setResourceCacheLimits(5, 30000);
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
|
||||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
|
|
||||||
// Add three resources to the cache.
|
// Add three resources to the cache.
|
||||||
TestResource* a = new TestResource(context->getGpu());
|
TestResource* a = new TestResource(context->getGpu());
|
||||||
TestResource* b = new TestResource(context->getGpu());
|
TestResource* b = new TestResource(context->getGpu());
|
||||||
TestResource* c = new TestResource(context->getGpu());
|
TestResource* c = new TestResource(context->getGpu());
|
||||||
cache->addResource(key1, a);
|
a->cacheAccess().setContentKey(key1);
|
||||||
cache->addResource(key2, b);
|
b->cacheAccess().setContentKey(key2);
|
||||||
cache->addResource(key3, c);
|
c->cacheAccess().setContentKey(key3);
|
||||||
a->unref();
|
a->unref();
|
||||||
b->unref();
|
b->unref();
|
||||||
c->unref();
|
c->unref();
|
||||||
@ -271,8 +315,8 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
|
|||||||
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg1);
|
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg1);
|
||||||
const GrResourceInvalidatedMessage msg2 = { key2 };
|
const GrResourceInvalidatedMessage msg2 = { key2 };
|
||||||
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg2);
|
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg2);
|
||||||
cache->purgeAsNeeded();
|
|
||||||
#if 0 // Disabled until reimplemented in GrResourceCache2.
|
#if 0 // Disabled until reimplemented in GrResourceCache2.
|
||||||
|
cache2->purgeAsNeeded();
|
||||||
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
|
||||||
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
|
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
|
||||||
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key2));
|
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key2));
|
||||||
@ -282,14 +326,19 @@ static void test_purge_invalidated(skiatest::Reporter* reporter) {
|
|||||||
// Invalidate the third.
|
// Invalidate the third.
|
||||||
const GrResourceInvalidatedMessage msg3 = { key3 };
|
const GrResourceInvalidatedMessage msg3 = { key3 };
|
||||||
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg3);
|
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg3);
|
||||||
cache->purgeAsNeeded();
|
|
||||||
#if 0 // Disabled until reimplemented in GrResourceCache2.
|
#if 0 // Disabled until reimplemented in GrResourceCache2.
|
||||||
|
cache2->purgeAsNeeded();
|
||||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||||
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key3));
|
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key3));
|
||||||
#endif
|
#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_delete_on_destruction(skiatest::Reporter* reporter) {
|
static void test_cache_chained_purge(skiatest::Reporter* reporter) {
|
||||||
SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
|
SkAutoTUnref<GrContext> context(GrContext::CreateMockContext());
|
||||||
REPORTER_ASSERT(reporter, SkToBool(context));
|
REPORTER_ASSERT(reporter, SkToBool(context));
|
||||||
if (NULL == context) {
|
if (NULL == context) {
|
||||||
@ -309,44 +358,34 @@ static void test_cache_delete_on_destruction(skiatest::Reporter* reporter) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
context->setResourceCacheLimits(3, 30000);
|
context->setResourceCacheLimits(3, 30000);
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
|
|
||||||
TestResource* a = new TestResource(context->getGpu());
|
TestResource* a = new TestResource(context->getGpu());
|
||||||
TestResource* b = new TestResource(context->getGpu());
|
TestResource* b = new TestResource(context->getGpu());
|
||||||
cache->addResource(key1, a);
|
a->cacheAccess().setContentKey(key1);
|
||||||
cache->addResource(key2, b);
|
b->cacheAccess().setContentKey(key2);
|
||||||
|
|
||||||
a->setDeleteWhenDestroyed(cache, b);
|
// Make a cycle
|
||||||
b->setDeleteWhenDestroyed(cache, a);
|
a->setUnrefWhenDestroyed(b);
|
||||||
|
b->setUnrefWhenDestroyed(a);
|
||||||
|
|
||||||
|
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||||
|
|
||||||
a->unref();
|
a->unref();
|
||||||
b->unref();
|
b->unref();
|
||||||
|
|
||||||
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||||
|
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||||
}
|
|
||||||
{
|
|
||||||
context->setResourceCacheLimits(3, 30000);
|
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
|
||||||
cache->purgeAllUnlocked();
|
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
|
||||||
|
|
||||||
TestResource* a = new TestResource(context->getGpu());
|
// Break the cycle
|
||||||
TestResource* b = new TestResource(context->getGpu());
|
a->setUnrefWhenDestroyed(NULL);
|
||||||
cache->addResource(key1, a);
|
REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
|
||||||
cache->addResource(key2, b);
|
|
||||||
|
|
||||||
a->setDeleteWhenDestroyed(cache, b);
|
cache2->purgeAllUnlocked();
|
||||||
b->setDeleteWhenDestroyed(cache, a);
|
|
||||||
|
|
||||||
a->unref();
|
|
||||||
b->unref();
|
|
||||||
|
|
||||||
cache->deleteResource(a->cacheAccess().getCacheEntry());
|
|
||||||
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,23 +413,20 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
|
|||||||
// Test changing resources sizes (both increase & decrease).
|
// Test changing resources sizes (both increase & decrease).
|
||||||
{
|
{
|
||||||
context->setResourceCacheLimits(3, 30000);
|
context->setResourceCacheLimits(3, 30000);
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
|
||||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
|
|
||||||
TestResource* a = new TestResource(context->getGpu());
|
TestResource* a = new TestResource(context->getGpu());
|
||||||
a->setSize(100); // Test didChangeGpuMemorySize() when not in the cache.
|
a->cacheAccess().setContentKey(key1);
|
||||||
cache->addResource(key1, a);
|
|
||||||
a->unref();
|
a->unref();
|
||||||
|
|
||||||
TestResource* b = new TestResource(context->getGpu());
|
TestResource* b = new TestResource(context->getGpu());
|
||||||
b->setSize(100);
|
b->cacheAccess().setContentKey(key2);
|
||||||
cache->addResource(key2, b);
|
|
||||||
b->unref();
|
b->unref();
|
||||||
|
|
||||||
REPORTER_ASSERT(reporter, 200 == cache->getCachedResourceBytes());
|
REPORTER_ASSERT(reporter, 200 == cache2->getResourceBytes());
|
||||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||||
{
|
{
|
||||||
SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
|
SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
|
||||||
find2->setSize(200);
|
find2->setSize(200);
|
||||||
@ -398,30 +434,29 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
|
|||||||
find1->setSize(50);
|
find1->setSize(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
REPORTER_ASSERT(reporter, 250 == cache->getCachedResourceBytes());
|
REPORTER_ASSERT(reporter, 250 == cache2->getResourceBytes());
|
||||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test increasing a resources size beyond the cache budget.
|
// Test increasing a resources size beyond the cache budget.
|
||||||
{
|
{
|
||||||
context->setResourceCacheLimits(2, 300);
|
context->setResourceCacheLimits(2, 300);
|
||||||
GrResourceCache* cache = context->getResourceCache();
|
|
||||||
GrResourceCache2* cache2 = context->getResourceCache2();
|
GrResourceCache2* cache2 = context->getResourceCache2();
|
||||||
cache->purgeAllUnlocked();
|
cache2->purgeAllUnlocked();
|
||||||
SkASSERT(0 == cache->getCachedResourceCount() && 0 == cache->getCachedResourceBytes());
|
SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes());
|
||||||
|
|
||||||
TestResource* a = new TestResource(context->getGpu());
|
TestResource* a = new TestResource(context->getGpu());
|
||||||
a->setSize(100);
|
a->setSize(100);
|
||||||
cache->addResource(key1, a);
|
a->cacheAccess().setContentKey(key1);
|
||||||
a->unref();
|
a->unref();
|
||||||
|
|
||||||
TestResource* b = new TestResource(context->getGpu());
|
TestResource* b = new TestResource(context->getGpu());
|
||||||
b->setSize(100);
|
b->setSize(100);
|
||||||
cache->addResource(key2, b);
|
b->cacheAccess().setContentKey(key2);
|
||||||
b->unref();
|
b->unref();
|
||||||
|
|
||||||
REPORTER_ASSERT(reporter, 200 == cache->getCachedResourceBytes());
|
REPORTER_ASSERT(reporter, 200 == cache2->getResourceBytes());
|
||||||
REPORTER_ASSERT(reporter, 2 == cache->getCachedResourceCount());
|
REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount());
|
||||||
|
|
||||||
{
|
{
|
||||||
SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
|
SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(cache2->findAndRefContentResource(key2)));
|
||||||
@ -429,8 +464,8 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) {
|
|||||||
}
|
}
|
||||||
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
|
REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1));
|
||||||
|
|
||||||
REPORTER_ASSERT(reporter, 201 == cache->getCachedResourceBytes());
|
REPORTER_ASSERT(reporter, 201 == cache2->getResourceBytes());
|
||||||
REPORTER_ASSERT(reporter, 1 == cache->getCachedResourceCount());
|
REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,10 +491,11 @@ DEF_GPUTEST(ResourceCache, reporter, factory) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The below tests create their own mock contexts.
|
// The below tests create their own mock contexts.
|
||||||
|
test_no_key(reporter);
|
||||||
test_duplicate_content_key(reporter);
|
test_duplicate_content_key(reporter);
|
||||||
test_duplicate_scratch_key(reporter);
|
test_duplicate_scratch_key(reporter);
|
||||||
test_purge_invalidated(reporter);
|
test_purge_invalidated(reporter);
|
||||||
test_cache_delete_on_destruction(reporter);
|
test_cache_chained_purge(reporter);
|
||||||
test_resource_size_changed(reporter);
|
test_resource_size_changed(reporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,33 +321,6 @@ static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if SK_SUPPORT_GPU
|
#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,
|
static void Test_crbug263329(skiatest::Reporter* reporter,
|
||||||
SurfaceType surfaceType,
|
SurfaceType surfaceType,
|
||||||
GrContext* context) {
|
GrContext* context) {
|
||||||
@ -453,8 +426,6 @@ DEF_GPUTEST(Surface, reporter, factory) {
|
|||||||
}
|
}
|
||||||
GrContext* context = factory->get(glCtxType);
|
GrContext* context = factory->get(glCtxType);
|
||||||
if (context) {
|
if (context) {
|
||||||
TestSurfaceInCache(reporter, kGpu_SurfaceType, context);
|
|
||||||
TestSurfaceInCache(reporter, kGpuScratch_SurfaceType, context);
|
|
||||||
Test_crbug263329(reporter, kGpu_SurfaceType, context);
|
Test_crbug263329(reporter, kGpu_SurfaceType, context);
|
||||||
Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
|
Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
|
||||||
TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
|
TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
|
||||||
|
Loading…
Reference in New Issue
Block a user