diff --git a/bench/GrResourceCacheBench.cpp b/bench/GrResourceCacheBench.cpp index e1ec90d511..e30dd3052f 100644 --- a/bench/GrResourceCacheBench.cpp +++ b/bench/GrResourceCacheBench.cpp @@ -14,181 +14,63 @@ #include "GrContext.h" #include "GrGpu.h" #include "GrResourceCache2.h" -#include "GrStencilBuffer.h" -#include "GrTexture.h" -#include "GrTexturePriv.h" #include "SkCanvas.h" enum { - CACHE_SIZE_COUNT = 2048, - CACHE_SIZE_BYTES = 2 * 1024 * 1024, + CACHE_SIZE_COUNT = 4096, }; -class StencilResource : public GrGpuResource { +class BenchResource : public GrGpuResource { public: - SK_DECLARE_INST_COUNT(StencilResource); - StencilResource(GrGpu* gpu, int id) - : INHERITED(gpu, false) - , fID(id) { + SK_DECLARE_INST_COUNT(BenchResource); + BenchResource (GrGpu* gpu) + : INHERITED(gpu, false) { this->registerWithCache(); } - static GrResourceKey ComputeKey(int width, int height, int sampleCnt) { - return GrStencilBuffer::ComputeKey(width, height, sampleCnt); - } - - int fID; - -private: - virtual size_t onGpuMemorySize() const SK_OVERRIDE { - return 100 + ((fID % 1 == 0) ? -5 : 6); - } - - typedef GrGpuResource INHERITED; -}; - -class TextureResource : public GrGpuResource { -public: - SK_DECLARE_INST_COUNT(TextureResource); - TextureResource(GrGpu* gpu, int id) - : INHERITED(gpu, false) - , fID(id) { - this->registerWithCache(); - } - - static GrResourceKey ComputeKey(const GrSurfaceDesc& desc) { + static GrResourceKey ComputeKey(int i) { GrCacheID::Key key; memset(&key, 0, sizeof(key)); - key.fData32[0] = (desc.fWidth) | (desc.fHeight << 16); - key.fData32[1] = desc.fConfig | desc.fSampleCnt << 16; - key.fData32[2] = desc.fFlags; + key.fData32[0] = i; static int gType = GrResourceKey::GenerateResourceType(); static int gDomain = GrCacheID::GenerateDomain(); return GrResourceKey(GrCacheID(gDomain, key), gType, 0); } - int fID; private: - virtual size_t onGpuMemorySize() const SK_OVERRIDE { - return 100 + ((fID % 1 == 0) ? -40 : 33); - } + size_t onGpuMemorySize() const SK_OVERRIDE { return 100; } typedef GrGpuResource INHERITED; }; -static void get_stencil(int i, int* w, int* h, int* s) { - *w = i % 1024; - *h = i * 2 % 1024; - *s = i % 1 == 0 ? 0 : 4; -} - -static void get_texture_desc(int i, GrSurfaceDesc* desc) { - desc->fFlags = kRenderTarget_GrSurfaceFlag | kNoStencil_GrSurfaceFlag; - desc->fWidth = i % 1024; - desc->fHeight = i * 2 % 1024; - desc->fConfig = static_cast(i % (kLast_GrPixelConfig + 1)); - desc->fSampleCnt = ((i % 2) == 0) ? 0 : 4; -} - static void populate_cache(GrGpu* gpu, int resourceCount) { for (int i = 0; i < resourceCount; ++i) { - int w, h, s; - get_stencil(i, &w, &h, &s); - GrResourceKey key = GrStencilBuffer::ComputeKey(w, h, s); - GrGpuResource* resource = SkNEW_ARGS(StencilResource, (gpu, i)); + GrResourceKey key = BenchResource::ComputeKey(i); + GrGpuResource* resource = SkNEW_ARGS(BenchResource, (gpu)); resource->cacheAccess().setContentKey(key); resource->unref(); } - - for (int i = 0; i < resourceCount; ++i) { - GrSurfaceDesc desc; - get_texture_desc(i, &desc); - GrResourceKey key = TextureResource::ComputeKey(desc); - GrGpuResource* resource = SkNEW_ARGS(TextureResource, (gpu, i)); - resource->cacheAccess().setContentKey(key); - resource->unref(); - } -} - -static void check_cache_contents_or_die(GrResourceCache2* cache, int k) { - // Benchmark find calls that succeed. - { - GrSurfaceDesc desc; - get_texture_desc(k, &desc); - GrResourceKey key = TextureResource::ComputeKey(desc); - SkAutoTUnref item(cache->findAndRefContentResource(key)); - if (!item) { - SkFAIL("cache add does not work as expected"); - return; - } - if (static_cast(item.get())->fID != k) { - SkFAIL("cache add does not work as expected"); - return; - } - } - { - int w, h, s; - get_stencil(k, &w, &h, &s); - GrResourceKey key = StencilResource::ComputeKey(w, h, s); - SkAutoTUnref item(cache->findAndRefContentResource(key)); - if (!item) { - SkFAIL("cache add does not work as expected"); - return; - } - if (static_cast(item.get())->fID != k) { - SkFAIL("cache add does not work as expected"); - return; - } - } - - // Benchmark also find calls that always fail. - { - GrSurfaceDesc desc; - get_texture_desc(k, &desc); - desc.fHeight |= 1; - GrResourceKey key = TextureResource::ComputeKey(desc); - SkAutoTUnref item(cache->findAndRefContentResource(key)); - if (item) { - SkFAIL("cache add does not work as expected"); - return; - } - } - { - int w, h, s; - get_stencil(k, &w, &h, &s); - h |= 1; - GrResourceKey key = StencilResource::ComputeKey(w, h, s); - SkAutoTUnref item(cache->findAndRefContentResource(key)); - if (item) { - SkFAIL("cache add does not work as expected"); - return; - } - } } class GrResourceCacheBenchAdd : public Benchmark { - enum { - RESOURCE_COUNT = CACHE_SIZE_COUNT / 2, - }; - public: - virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + bool isSuitableFor(Backend backend) SK_OVERRIDE { return backend == kNonRendering_Backend; } protected: - virtual const char* onGetName() SK_OVERRIDE { + const char* onGetName() SK_OVERRIDE { return "grresourcecache_add"; } - virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { SkAutoTUnref context(GrContext::CreateMockContext()); if (NULL == context) { return; } // Set the cache budget to be very large so no purging occurs. - context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30); + context->setResourceCacheLimits(CACHE_SIZE_COUNT, 1 << 30); GrResourceCache2* cache2 = context->getResourceCache2(); @@ -199,15 +81,8 @@ protected: GrGpu* gpu = context->getGpu(); for (int i = 0; i < loops; ++i) { - SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes()); - - populate_cache(gpu, RESOURCE_COUNT); - - // Check that cache works. - for (int k = 0; k < RESOURCE_COUNT; k += 33) { - check_cache_contents_or_die(cache2, k); - } - cache2->purgeAllUnlocked(); + populate_cache(gpu, CACHE_SIZE_COUNT); + SkASSERT(CACHE_SIZE_COUNT == cache2->getResourceCount()); } } @@ -216,46 +91,52 @@ private: }; class GrResourceCacheBenchFind : public Benchmark { - enum { - RESOURCE_COUNT = CACHE_SIZE_COUNT / 2, - }; - public: - virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { + bool isSuitableFor(Backend backend) SK_OVERRIDE { return backend == kNonRendering_Backend; } protected: - virtual const char* onGetName() SK_OVERRIDE { + const char* onGetName() SK_OVERRIDE { return "grresourcecache_find"; } - virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { - SkAutoTUnref context(GrContext::CreateMockContext()); - if (NULL == context) { + void onPreDraw() SK_OVERRIDE { + fContext.reset(GrContext::CreateMockContext()); + if (!fContext) { return; } // Set the cache budget to be very large so no purging occurs. - context->setResourceCacheLimits(2 * RESOURCE_COUNT, 1 << 30); + fContext->setResourceCacheLimits(CACHE_SIZE_COUNT, 1 << 30); - GrResourceCache2* cache2 = context->getResourceCache2(); + GrResourceCache2* cache2 = fContext->getResourceCache2(); // Make sure the cache is empty. cache2->purgeAllUnlocked(); SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes()); - GrGpu* gpu = context->getGpu(); + GrGpu* gpu = fContext->getGpu(); - populate_cache(gpu, RESOURCE_COUNT); + populate_cache(gpu, CACHE_SIZE_COUNT); + } + void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + if (!fContext) { + return; + } + GrResourceCache2* cache2 = fContext->getResourceCache2(); + SkASSERT(CACHE_SIZE_COUNT == cache2->getResourceCount()); for (int i = 0; i < loops; ++i) { - for (int k = 0; k < RESOURCE_COUNT; ++k) { - check_cache_contents_or_die(cache2, k); + for (int k = 0; k < CACHE_SIZE_COUNT; ++k) { + GrResourceKey key = BenchResource::ComputeKey(k); + SkAutoTUnref resource(cache2->findAndRefContentResource(key)); + SkASSERT(resource); } } } private: + SkAutoTUnref fContext; typedef Benchmark INHERITED; }; diff --git a/expectations/gm/Test-Android-GalaxyS4-SGX544-Arm7-Debug/expected-results.json b/expectations/gm/Test-Android-GalaxyS4-SGX544-Arm7-Debug/expected-results.json index 79c32f0ac8..5b7b400306 100644 --- a/expectations/gm/Test-Android-GalaxyS4-SGX544-Arm7-Debug/expected-results.json +++ b/expectations/gm/Test-Android-GalaxyS4-SGX544-Arm7-Debug/expected-results.json @@ -3857,7 +3857,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 4938590834664658305 + 18165407505633347407 ] ], "reviewed-by-human": true @@ -5852,7 +5852,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 17492314805851855065 + 14771652249910100761 ] ], "reviewed-by-human": true @@ -5970,7 +5970,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 571194008531839949 + 5148862615526465916 ] ], "ignore-failure": false, diff --git a/expectations/gm/Test-Android-GalaxyS4-SGX544-Arm7-Release/expected-results.json b/expectations/gm/Test-Android-GalaxyS4-SGX544-Arm7-Release/expected-results.json index 8ab1e2f777..5072d20803 100644 --- a/expectations/gm/Test-Android-GalaxyS4-SGX544-Arm7-Release/expected-results.json +++ b/expectations/gm/Test-Android-GalaxyS4-SGX544-Arm7-Release/expected-results.json @@ -3857,7 +3857,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 4938590834664658305 + 18165407505633347407 ] ], "reviewed-by-human": true @@ -5844,7 +5844,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 167979044054175148 + 3695575234877280011 ] ], "reviewed-by-human": true @@ -5962,7 +5962,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 9298514044054867967 + 5148862615526465916 ] ], "ignore-failure": false, diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86-Debug/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86-Debug/expected-results.json index 030afb41e6..2d955b41fc 100644 --- a/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86-Debug/expected-results.json +++ b/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86-Debug/expected-results.json @@ -7059,7 +7059,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 10566742216990551435 + 11009857797348161863 ] ], "reviewed-by-human": true diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86-Release/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86-Release/expected-results.json index c7d8ba1545..03a5e8fe2c 100644 --- a/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86-Release/expected-results.json +++ b/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86-Release/expected-results.json @@ -7061,7 +7061,7 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 10566742216990551435 + 11009857797348161863 ] ], "reviewed-by-human": true diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86_64-Debug/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86_64-Debug/expected-results.json index 75e57f344f..b364463578 100644 --- a/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86_64-Debug/expected-results.json +++ b/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86_64-Debug/expected-results.json @@ -7131,13 +7131,10 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 10566742216990551435 + 11009857797348161863 ] ], - "bugs": [ - 2325 - ], - "reviewed-by-human": false + "reviewed-by-human": true }, "dashing2_pdf-poppler.png": { "allowed-digests": [ diff --git a/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86_64-Release/expected-results.json b/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86_64-Release/expected-results.json index 44e94cd374..517640fae7 100644 --- a/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86_64-Release/expected-results.json +++ b/expectations/gm/Test-Ubuntu12-ShuttleA-GTX660-x86_64-Release/expected-results.json @@ -7131,13 +7131,10 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 10566742216990551435 + 11009857797348161863 ] ], - "bugs": [ - 2325 - ], - "reviewed-by-human": false + "reviewed-by-human": true }, "dashing2_pdf-poppler.png": { "allowed-digests": [ diff --git a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json index a28354c42d..521399e0ac 100644 --- a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json +++ b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86-Release/expected-results.json @@ -7116,10 +7116,10 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 10566742216990551435 + 11009857797348161863 ] ], - "reviewed-by-human": false + "reviewed-by-human": true }, "dashing2_pdf-poppler.png": { "allowed-digests": [ @@ -11911,10 +11911,10 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 17326560431224736462 + 12821620961617303185 ] ], - "reviewed-by-human": false + "reviewed-by-human": true }, "glyph_pos_n_b_nvprmsaa4.png": { "allowed-digests": [ diff --git a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86_64-Debug/expected-results.json b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86_64-Debug/expected-results.json index 6deffd9898..0dc0fbffdc 100644 --- a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86_64-Debug/expected-results.json +++ b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86_64-Debug/expected-results.json @@ -7116,10 +7116,10 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 10566742216990551435 + 11009857797348161863 ] ], - "reviewed-by-human": false + "reviewed-by-human": true }, "dashing2_pdf-poppler.png": { "allowed-digests": [ @@ -11911,10 +11911,10 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 17326560431224736462 + 12821620961617303185 ] ], - "reviewed-by-human": false + "reviewed-by-human": true }, "glyph_pos_n_b_nvprmsaa4.png": { "allowed-digests": [ diff --git a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86_64-Release/expected-results.json b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86_64-Release/expected-results.json index 53cc5e0908..502191a913 100644 --- a/expectations/gm/Test-Win8-ShuttleA-GTX660-x86_64-Release/expected-results.json +++ b/expectations/gm/Test-Win8-ShuttleA-GTX660-x86_64-Release/expected-results.json @@ -7116,10 +7116,10 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 10566742216990551435 + 11009857797348161863 ] ], - "reviewed-by-human": false + "reviewed-by-human": true }, "dashing2_pdf-poppler.png": { "allowed-digests": [ @@ -11911,10 +11911,10 @@ "allowed-digests": [ [ "bitmap-64bitMD5", - 17326560431224736462 + 12821620961617303185 ] ], - "reviewed-by-human": false + "reviewed-by-human": true }, "glyph_pos_n_b_nvprmsaa4.png": { "allowed-digests": [ diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index b83df45743..c6dd2d7563 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -34,7 +34,6 @@ class GrPath; class GrPathRenderer; class GrResourceEntry; class GrResourceCache2; -class GrStencilBuffer; class GrTestTarget; class GrTextContext; class GrTextureParams; @@ -890,13 +889,6 @@ public: void addGpuTraceMarker(const GrGpuTraceMarker* marker); void removeGpuTraceMarker(const GrGpuTraceMarker* marker); - /** - * Stencil buffers add themselves to the cache using addStencilBuffer. findStencilBuffer is - * called to check the cache for a SB that matches an RT's criteria. - */ - void addStencilBuffer(GrStencilBuffer* sb); - GrStencilBuffer* findAndRefStencilBuffer(int width, int height, int sampleCnt); - GrPathRenderer* getPathRenderer( const GrDrawTarget* target, const GrDrawState*, diff --git a/include/gpu/GrGpuResource.h b/include/gpu/GrGpuResource.h index 806a45aa11..659b767616 100644 --- a/include/gpu/GrGpuResource.h +++ b/include/gpu/GrGpuResource.h @@ -223,6 +223,7 @@ private: bool setContentKey(const GrResourceKey& contentKey); void setBudgeted(bool countsAgainstBudget); void notifyIsPurgable() const; + void removeScratchKey(); #ifdef SK_DEBUG friend class GrGpu; // for assert in GrGpu to access getGpu diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 657e57da33..607d3c3cc7 100755 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -24,7 +24,6 @@ #include "GrPathUtils.h" #include "GrResourceCache2.h" #include "GrSoftwarePathRenderer.h" -#include "GrStencilBuffer.h" #include "GrStencilAndCoverTextContext.h" #include "GrStrokeInfo.h" #include "GrSurfacePriv.h" @@ -252,22 +251,6 @@ bool GrContext::isTextureInCache(const GrSurfaceDesc& desc, return fResourceCache2->hasContentKey(resourceKey); } -void GrContext::addStencilBuffer(GrStencilBuffer* sb) { - // TODO: Make GrStencilBuffers use the scratch mechanism rather than content keys. - ASSERT_OWNED_RESOURCE(sb); - - GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(), - sb->height(), - sb->numSamples()); - SkAssertResult(sb->cacheAccess().setContentKey(resourceKey)); -} - -GrStencilBuffer* GrContext::findAndRefStencilBuffer(int width, int height, int sampleCnt) { - GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width, height, sampleCnt); - GrGpuResource* resource = this->findAndRefCachedResource(resourceKey); - return static_cast(resource); -} - static void stretch_image(void* dst, int dstW, int dstH, diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index 2bda594b9a..6b742c4cc3 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -13,14 +13,12 @@ #include "GrContext.h" #include "GrDrawTargetCaps.h" #include "GrIndexBuffer.h" +#include "GrResourceCache2.h" #include "GrStencilBuffer.h" #include "GrVertexBuffer.h" //////////////////////////////////////////////////////////////////////////////// -#define DEBUG_INVAL_BUFFER 0xdeadcafe -#define DEBUG_INVAL_START_IDX -1 - GrGpu::GrGpu(GrContext* context) : fResetTimestamp(kExpiredTimestamp+1) , fResetBits(kAll_GrBackendState) @@ -78,8 +76,9 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& desc, bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) { SkASSERT(NULL == rt->getStencilBuffer()); - SkAutoTUnref sb( - this->getContext()->findAndRefStencilBuffer(rt->width(), rt->height(), rt->numSamples())); + GrResourceKey sbKey = GrStencilBuffer::ComputeKey(rt->width(), rt->height(), rt->numSamples()); + SkAutoTUnref sb(static_cast( + this->getContext()->getResourceCache2()->findAndRefScratchResource(sbKey))); if (sb) { rt->setStencilBuffer(sb); bool attached = this->attachStencilBufferToRenderTarget(sb, rt); diff --git a/src/gpu/GrGpuResource.cpp b/src/gpu/GrGpuResource.cpp index 8dbbd83ef5..cc24335184 100644 --- a/src/gpu/GrGpuResource.cpp +++ b/src/gpu/GrGpuResource.cpp @@ -128,6 +128,13 @@ void GrGpuResource::setScratchKey(const GrResourceKey& scratchKey) { fScratchKey = scratchKey; } +void GrGpuResource::removeScratchKey() { + if (!this->wasDestroyed() && !fScratchKey.isNullScratch()) { + get_resource_cache2(fGpu)->resourceAccess().willRemoveScratchKey(this); + fScratchKey = GrResourceKey::NullScratchKey(); + } +} + uint32_t GrGpuResource::CreateUniqueID() { static int32_t gUniqueID = SK_InvalidUniqueID; uint32_t id; diff --git a/src/gpu/GrGpuResourceCacheAccess.h b/src/gpu/GrGpuResourceCacheAccess.h index c55bb07774..e220e5f263 100644 --- a/src/gpu/GrGpuResourceCacheAccess.h +++ b/src/gpu/GrGpuResourceCacheAccess.h @@ -49,6 +49,12 @@ public: */ const GrResourceKey& getScratchKey() const { return fResource->fScratchKey; } + /** + * If the resource has a scratch key, the key will be removed. Since scratch keys are installed + * at resource creation time, this means the resource will never again be used as scratch. + */ + void removeScratchKey() const { fResource->removeScratchKey(); } + /** * If the resource is currently cached by a content key, the key is returned, otherwise NULL. */ diff --git a/src/gpu/GrResourceCache2.cpp b/src/gpu/GrResourceCache2.cpp index d30397337f..39181554d2 100644 --- a/src/gpu/GrResourceCache2.cpp +++ b/src/gpu/GrResourceCache2.cpp @@ -218,6 +218,11 @@ GrGpuResource* GrResourceCache2::findAndRefScratchResource(const GrResourceKey& return resource; } +void GrResourceCache2::willRemoveScratchKey(const GrGpuResource* resource) { + SkASSERT(resource->cacheAccess().isScratch()); + fScratchMap.remove(resource->cacheAccess().getScratchKey(), resource); +} + bool GrResourceCache2::didSetContentKey(GrGpuResource* resource) { SkASSERT(!fPurging); SkASSERT(resource); diff --git a/src/gpu/GrResourceCache2.h b/src/gpu/GrResourceCache2.h index 9331e9dfd3..3c5eea5a3f 100644 --- a/src/gpu/GrResourceCache2.h +++ b/src/gpu/GrResourceCache2.h @@ -161,6 +161,7 @@ private: void notifyPurgable(GrGpuResource*); void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize); bool didSetContentKey(GrGpuResource*); + void willRemoveScratchKey(const GrGpuResource*); void didChangeBudgetStatus(GrGpuResource*); void makeResourceMRU(GrGpuResource*); /// @} @@ -277,6 +278,12 @@ private: */ bool didSetContentKey(GrGpuResource* resource) { return fCache->didSetContentKey(resource); } + /** + * Called by GrGpuResources when the remove their scratch key. + */ + void willRemoveScratchKey(const GrGpuResource* resource) { + fCache->willRemoveScratchKey(resource); + } /** * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa. diff --git a/src/gpu/GrStencilBuffer.cpp b/src/gpu/GrStencilBuffer.cpp index 16b0150a4d..5aa56e0717 100644 --- a/src/gpu/GrStencilBuffer.cpp +++ b/src/gpu/GrStencilBuffer.cpp @@ -12,14 +12,10 @@ #include "GrGpu.h" #include "GrResourceCache2.h" -void GrStencilBuffer::transferToCache() { - this->getGpu()->getContext()->addStencilBuffer(this); -} - namespace { // we should never have more than one stencil buffer with same combo of (width,height,samplecount) void gen_cache_id(int width, int height, int sampleCnt, GrCacheID* cacheID) { - static const GrCacheID::Domain gStencilBufferDomain = GrCacheID::GenerateDomain(); + static const GrCacheID::Domain gStencilBufferDomain = GrResourceKey::ScratchDomain(); GrCacheID::Key key; uint32_t* keyData = key.fData32; keyData[0] = width; diff --git a/src/gpu/GrStencilBuffer.h b/src/gpu/GrStencilBuffer.h index 86fef50225..187556bd4c 100644 --- a/src/gpu/GrStencilBuffer.h +++ b/src/gpu/GrStencilBuffer.h @@ -47,9 +47,6 @@ public: !fLastClipStackRect.contains(clipSpaceRect); } - // Places the sb in the cache. The cache takes a ref of the stencil buffer. - void transferToCache(); - static GrResourceKey ComputeKey(int width, int height, int sampleCnt); protected: @@ -60,6 +57,7 @@ protected: , fBits(bits) , fSampleCnt(sampleCnt) , fLastClipStackGenID(SkClipStack::kInvalidGenID) { + this->setScratchKey(ComputeKey(width, height, sampleCnt)); fLastClipStackRect.setEmpty(); } diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index 9e1f754a82..bb40839f48 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -9,6 +9,7 @@ #include "GrGpuGL.h" #include "GrGLStencilBuffer.h" #include "GrGLTextureRenderTarget.h" +#include "GrGpuResourceCacheAccess.h" #include "GrOptDrawState.h" #include "GrSurfacePriv.h" #include "GrTemplates.h" @@ -1121,8 +1122,7 @@ void inline get_stencil_rb_sizes(const GrGLInterface* gl, } } -bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt, - int width, int height) { +bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt, int width, int height) { // All internally created RTs are also textures. We don't create // SBs for a client's standalone RT (that is a RT that isn't also a texture). @@ -1171,15 +1171,16 @@ bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt, SkAutoTUnref sb(SkNEW_ARGS(GrGLStencilBuffer, (this, kIsWrapped, sbID, width, height, samples, format))); - // If we fail we have to create a new render buffer ID since we gave this one to the - // GrGLStencilBuffer object. - sbID = 0; if (this->attachStencilBufferToRenderTarget(sb, rt)) { fLastSuccessfulStencilFmtIdx = sIdx; - sb->transferToCache(); rt->setStencilBuffer(sb); return true; } + // Remove the scratch key from this resource so we don't grab it from the cache ever + // again. + sb->cacheAccess().removeScratchKey(); + // Set this to 0 since we handed the valid ID off to the failed stencil buffer resource. + sbID = 0; } } GL_CALL(DeleteRenderbuffers(1, &sbID)); diff --git a/tests/ResourceCacheTest.cpp b/tests/ResourceCacheTest.cpp index 930bd1217c..f925b07754 100644 --- a/tests/ResourceCacheTest.cpp +++ b/tests/ResourceCacheTest.cpp @@ -313,6 +313,68 @@ static void test_duplicate_scratch_key(skiatest::Reporter* reporter) { SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));) } +static void test_remove_scratch_key(skiatest::Reporter* reporter) { + SkAutoTUnref context(GrContext::CreateMockContext()); + REPORTER_ASSERT(reporter, SkToBool(context)); + if (NULL == context) { + return; + } + context->setResourceCacheLimits(5, 30000); + GrResourceCache2* cache2 = context->getResourceCache2(); + cache2->purgeAllUnlocked(); + SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes()); + + GrCacheID::Key keyData; + memset(&keyData, 0, sizeof(keyData)); + GrCacheID::Domain domain = GrResourceKey::ScratchDomain(); + GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType(); + GrResourceKey scratchKey(GrCacheID(domain, keyData), t, 0); + + // Create two resources that have the same scratch key. + TestResource* a = new TestResource(context->getGpu(), scratchKey); + TestResource* b = new TestResource(context->getGpu(), scratchKey); + a->unref(); + b->unref(); + + // Scratch resources are registered with GrResourceCache2 just by existing. There are 2. + REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); + SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache2->countScratchEntriesForKey(scratchKey));) + REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount()); + + // Find the first resource and remove its scratch key + GrGpuResource* find; + find = cache2->findAndRefScratchResource(scratchKey); + find->cacheAccess().removeScratchKey(); + // It's still alive, but not cached by scratch key anymore + REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); + SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache2->countScratchEntriesForKey(scratchKey));) + REPORTER_ASSERT(reporter, 2 == cache2->getResourceCount()); + + // The cache should immediately delete it when it's unrefed since it isn't accessible. + find->unref(); + REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); + SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache2->countScratchEntriesForKey(scratchKey));) + REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount()); + + // Repeat for the second resource. + find = cache2->findAndRefScratchResource(scratchKey); + find->cacheAccess().removeScratchKey(); + REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); + SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));) + REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount()); + + // Should be able to call this multiple times with no problem. + find->cacheAccess().removeScratchKey(); + REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); + SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));) + REPORTER_ASSERT(reporter, 1 == cache2->getResourceCount()); + + find->unref(); + REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); + SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache2->countScratchEntriesForKey(scratchKey));) + REPORTER_ASSERT(reporter, 0 == cache2->getResourceCount()); +} + static void test_duplicate_content_key(skiatest::Reporter* reporter) { SkAutoTUnref context(GrContext::CreateMockContext()); REPORTER_ASSERT(reporter, SkToBool(context)); @@ -569,6 +631,76 @@ static void test_resource_size_changed(skiatest::Reporter* reporter) { } } +static void test_large_resource_count(skiatest::Reporter* reporter) { + SkAutoTUnref context(GrContext::CreateMockContext()); + REPORTER_ASSERT(reporter, SkToBool(context)); + if (NULL == context) { + return; + } + + static const int kResourceCnt = 2000; + // Set the cache size to double the resource count because we're going to create 2x that number + // resources, using two different key domains. Add a little slop to the bytes because we resize + // down to 1 byte after creating the resource. + context->setResourceCacheLimits(2 * kResourceCnt, 2 * kResourceCnt + 1000); + GrResourceCache2* cache2 = context->getResourceCache2(); + cache2->purgeAllUnlocked(); + SkASSERT(0 == cache2->getResourceCount() && 0 == cache2->getResourceBytes()); + + GrCacheID::Domain domain0 = GrCacheID::GenerateDomain(); + GrCacheID::Domain domain1 = GrCacheID::GenerateDomain(); + GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType(); + + GrCacheID::Key keyData; + memset(&keyData, 0, sizeof(keyData)); + + for (int i = 0; i < kResourceCnt; ++i) { + TestResource* resource; + keyData.fData32[0] = i; + + GrResourceKey key0(GrCacheID(domain0, keyData), t, 0); + resource = SkNEW_ARGS(TestResource, (context->getGpu())); + resource->cacheAccess().setContentKey(key0); + resource->setSize(1); + resource->unref(); + + GrResourceKey key1(GrCacheID(domain1, keyData), t, 0); + resource = SkNEW_ARGS(TestResource, (context->getGpu())); + resource->cacheAccess().setContentKey(key1); + resource->setSize(1); + resource->unref(); + } + + REPORTER_ASSERT(reporter, TestResource::NumAlive() == 2 * kResourceCnt); + REPORTER_ASSERT(reporter, cache2->getBudgetedResourceBytes() == 2 * kResourceCnt); + REPORTER_ASSERT(reporter, cache2->getBudgetedResourceCount() == 2 * kResourceCnt); + REPORTER_ASSERT(reporter, cache2->getResourceBytes() == 2 * kResourceCnt); + REPORTER_ASSERT(reporter, cache2->getResourceCount() == 2 * kResourceCnt); + for (int i = 0; i < kResourceCnt; ++i) { + keyData.fData32[0] = i; + GrResourceKey key0(GrCacheID(domain0, keyData), t, 0); + REPORTER_ASSERT(reporter, cache2->hasContentKey(key0)); + GrResourceKey key1(GrCacheID(domain0, keyData), t, 0); + REPORTER_ASSERT(reporter, cache2->hasContentKey(key1)); + } + + cache2->purgeAllUnlocked(); + REPORTER_ASSERT(reporter, TestResource::NumAlive() == 0); + REPORTER_ASSERT(reporter, cache2->getBudgetedResourceBytes() == 0); + REPORTER_ASSERT(reporter, cache2->getBudgetedResourceCount() == 0); + REPORTER_ASSERT(reporter, cache2->getResourceBytes() == 0); + REPORTER_ASSERT(reporter, cache2->getResourceCount() == 0); + + for (int i = 0; i < kResourceCnt; ++i) { + keyData.fData32[0] = i; + GrResourceKey key0(GrCacheID(domain0, keyData), t, 0); + REPORTER_ASSERT(reporter, !cache2->hasContentKey(key0)); + GrResourceKey key1(GrCacheID(domain0, keyData), t, 0); + REPORTER_ASSERT(reporter, !cache2->hasContentKey(key1)); + } +} + + //////////////////////////////////////////////////////////////////////////////// DEF_GPUTEST(ResourceCache, reporter, factory) { for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) { @@ -595,9 +727,11 @@ DEF_GPUTEST(ResourceCache, reporter, factory) { test_budgeting(reporter); test_duplicate_content_key(reporter); test_duplicate_scratch_key(reporter); + test_remove_scratch_key(reporter); test_purge_invalidated(reporter); test_cache_chained_purge(reporter); test_resource_size_changed(reporter); + test_large_resource_count(reporter); } #endif