skia2/tests/ResourceCacheTest.cpp
commit-bot@chromium.org bd58febffb Speed up GrResourceCache add and lookup by using TDynamicHash
Speed up GrResourceCache add and lookup by using TDynamicHash instead
of GrTHashTable. GrTHashTable spends most of its time memmoving the
array elements while sorting after an add. Lookup is not particularly
fast either.

R=mtklein@google.com, bsalomon@google.com, reed@google.com

Author: kkinnunen@nvidia.com

Review URL: https://codereview.chromium.org/91453002

git-svn-id: http://skia.googlecode.com/svn/trunk@13122 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-01-17 17:56:21 +00:00

208 lines
6.5 KiB
C++

/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
#include "GrResourceCache.h"
#include "SkGpuDevice.h"
#include "Test.h"
static const int gWidth = 640;
static const int gHeight = 480;
////////////////////////////////////////////////////////////////////////////////
static void test_cache(skiatest::Reporter* reporter,
GrContext* context,
SkCanvas* canvas) {
const SkIRect size = SkIRect::MakeWH(gWidth, gHeight);
SkBitmap src;
src.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
src.allocPixels();
src.eraseColor(SK_ColorBLACK);
size_t srcSize = src.getSize();
size_t initialCacheSize = context->getGpuTextureCacheBytes();
int oldMaxNum;
size_t oldMaxBytes;
context->getTextureCacheLimits(&oldMaxNum, &oldMaxBytes);
// Set the cache limits so we can fit 10 "src" images and the
// max number of textures doesn't matter
size_t maxCacheSize = initialCacheSize + 10*srcSize;
context->setTextureCacheLimits(1000, maxCacheSize);
SkBitmap readback;
readback.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
readback.allocPixels();
for (int i = 0; i < 100; ++i) {
canvas->drawBitmap(src, 0, 0);
canvas->readPixels(size, &readback);
// "modify" the src texture
src.notifyPixelsChanged();
size_t curCacheSize = context->getGpuTextureCacheBytes();
// we should never go over the size limit
REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize);
}
context->setTextureCacheLimits(oldMaxNum, oldMaxBytes);
}
class TestResource : public GrResource {
public:
SK_DECLARE_INST_COUNT(TestResource);
explicit TestResource(GrGpu* gpu)
: INHERITED(gpu, false)
, fCache(NULL)
, fToDelete(NULL) {
++fAlive;
}
~TestResource() {
--fAlive;
if (NULL != fToDelete) {
// Breaks our little 2-element cycle below.
fToDelete->setDeleteWhenDestroyed(NULL, NULL);
fCache->deleteResource(fToDelete->getCacheEntry());
}
this->release();
}
size_t sizeInBytes() const SK_OVERRIDE { return 100; }
static int alive() { return fAlive; }
void setDeleteWhenDestroyed(GrResourceCache* cache, TestResource* resource) {
fCache = cache;
fToDelete = resource;
}
private:
GrResourceCache* fCache;
TestResource* fToDelete;
static int fAlive;
typedef GrResource INHERITED;
};
int TestResource::fAlive = 0;
static void test_purge_invalidated(skiatest::Reporter* reporter, GrContext* context) {
GrCacheID::Domain domain = GrCacheID::GenerateDomain();
GrCacheID::Key keyData;
keyData.fData64[0] = 5;
keyData.fData64[1] = 18;
GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
GrResourceKey key(GrCacheID(domain, keyData), t, 0);
GrResourceCache cache(5, 30000);
// Add two resources with the same key that delete each other from the cache when destroyed.
TestResource* a = new TestResource(context->getGpu());
TestResource* b = new TestResource(context->getGpu());
cache.addResource(key, a);
cache.addResource(key, b);
// Circle back.
a->setDeleteWhenDestroyed(&cache, b);
b->setDeleteWhenDestroyed(&cache, a);
a->unref();
b->unref();
// Add a third independent resource also with the same key.
GrResource* r = new TestResource(context->getGpu());
cache.addResource(key, r);
r->unref();
// Invalidate all three, all three should be purged and destroyed.
REPORTER_ASSERT(reporter, 3 == TestResource::alive());
const GrResourceInvalidatedMessage msg = { key };
SkMessageBus<GrResourceInvalidatedMessage>::Post(msg);
cache.purgeAsNeeded();
REPORTER_ASSERT(reporter, 0 == TestResource::alive());
}
static void test_cache_delete_on_destruction(skiatest::Reporter* reporter,
GrContext* context) {
GrCacheID::Domain domain = GrCacheID::GenerateDomain();
GrCacheID::Key keyData;
keyData.fData64[0] = 5;
keyData.fData64[1] = 0;
GrResourceKey::ResourceType t = GrResourceKey::GenerateResourceType();
GrResourceKey key(GrCacheID(domain, keyData), t, 0);
{
{
GrResourceCache cache(3, 30000);
TestResource* a = new TestResource(context->getGpu());
TestResource* b = new TestResource(context->getGpu());
cache.addResource(key, a);
cache.addResource(key, b);
a->setDeleteWhenDestroyed(&cache, b);
b->setDeleteWhenDestroyed(&cache, a);
a->unref();
b->unref();
REPORTER_ASSERT(reporter, 2 == TestResource::alive());
}
REPORTER_ASSERT(reporter, 0 == TestResource::alive());
}
{
GrResourceCache cache(3, 30000);
TestResource* a = new TestResource(context->getGpu());
TestResource* b = new TestResource(context->getGpu());
cache.addResource(key, a);
cache.addResource(key, b);
a->setDeleteWhenDestroyed(&cache, b);
b->setDeleteWhenDestroyed(&cache, a);
a->unref();
b->unref();
cache.deleteResource(a->getCacheEntry());
REPORTER_ASSERT(reporter, 0 == TestResource::alive());
}
}
////////////////////////////////////////////////////////////////////////////////
DEF_GPUTEST(ResourceCache, reporter, factory) {
for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type);
if (!GrContextFactory::IsRenderingGLContext(glType)) {
continue;
}
GrContext* context = factory->get(glType);
if (NULL == context) {
continue;
}
GrTextureDesc desc;
desc.fConfig = kSkia8888_GrPixelConfig;
desc.fFlags = kRenderTarget_GrTextureFlagBit;
desc.fWidth = gWidth;
desc.fHeight = gHeight;
SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0));
SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice, (context, texture.get())));
SkCanvas canvas(device.get());
test_cache(reporter, context, &canvas);
test_purge_invalidated(reporter, context);
test_cache_delete_on_destruction(reporter, context);
}
}
#endif