blob: 30d4cd410c1b9ebcf0eb5cccbd5a2d8502dc65af [file] [log] [blame]
/*
* 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 "Benchmark.h"
#include "GrGpuResource.h"
#include "GrContext.h"
#include "GrGpu.h"
#include "GrResourceCache.h"
#include "GrStencilBuffer.h"
#include "GrTexture.h"
#include "GrTexturePriv.h"
#include "SkCanvas.h"
enum {
CACHE_SIZE_COUNT = 2048,
CACHE_SIZE_BYTES = 2 * 1024 * 1024,
};
class StencilResource : public GrGpuResource {
public:
SK_DECLARE_INST_COUNT(StencilResource);
StencilResource(GrGpu* gpu, int id)
: INHERITED(gpu, false)
, fID(id) {
this->registerWithCache();
}
virtual ~StencilResource() { this->release(); }
virtual size_t gpuMemorySize() const SK_OVERRIDE {
return 100 + ((fID % 1 == 0) ? -5 : 6);
}
static GrResourceKey ComputeKey(int width, int height, int sampleCnt) {
return GrStencilBuffer::ComputeKey(width, height, sampleCnt);
}
int fID;
private:
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();
}
virtual ~TextureResource() { this->release(); }
virtual size_t gpuMemorySize() const SK_OVERRIDE {
return 100 + ((fID % 1 == 0) ? -40 : 33);
}
static GrResourceKey ComputeKey(const GrSurfaceDesc& desc) {
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;
static int gType = GrResourceKey::GenerateResourceType();
static int gDomain = GrCacheID::GenerateDomain();
return GrResourceKey(GrCacheID(gDomain, key), gType, 0);
}
int fID;
private:
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<GrPixelConfig>(i % (kLast_GrPixelConfig + 1));
desc->fSampleCnt = i % 1 == 0 ? 0 : 4;
}
static void populate_cache(GrResourceCache* cache, GrGpu* gpu, int resourceCount) {
for (int i = 0; i < resourceCount; ++i) {
int w, h, s;
get_stencil(i, &w, &h, &s);
GrResourceKey key = GrStencilBuffer::ComputeKey(w, h, s);
GrGpuResource* resource = SkNEW_ARGS(StencilResource, (gpu, i));
cache->purgeAsNeeded(1, resource->gpuMemorySize());
cache->addResource(key, resource);
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));
cache->purgeAsNeeded(1, resource->gpuMemorySize());
cache->addResource(key, resource);
resource->unref();
}
}
static void check_cache_contents_or_die(GrResourceCache* cache, int k) {
// Benchmark find calls that succeed.
{
GrSurfaceDesc desc;
get_texture_desc(k, &desc);
GrResourceKey key = TextureResource::ComputeKey(desc);
GrGpuResource* item = cache->find(key);
if (NULL == item) {
SkFAIL("cache add does not work as expected");
return;
}
if (static_cast<TextureResource*>(item)->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);
GrGpuResource* item = cache->find(key);
if (NULL == item) {
SkFAIL("cache add does not work as expected");
return;
}
if (static_cast<TextureResource*>(item)->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);
GrGpuResource* item = cache->find(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);
GrGpuResource* item = cache->find(key);
if (item) {
SkFAIL("cache add does not work as expected");
return;
}
}
}
class GrResourceCacheBenchAdd : public Benchmark {
enum {
RESOURCE_COUNT = CACHE_SIZE_COUNT / 2,
DUPLICATE_COUNT = CACHE_SIZE_COUNT / 4,
};
public:
virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
return backend == kGPU_Backend;
}
protected:
virtual const char* onGetName() SK_OVERRIDE {
return "grresourcecache_add";
}
virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
GrGpu* gpu = canvas->getGrContext()->getGpu();
for (int i = 0; i < loops; ++i) {
GrResourceCache cache(gpu->caps(), CACHE_SIZE_COUNT, CACHE_SIZE_BYTES);
populate_cache(&cache, gpu, DUPLICATE_COUNT);
populate_cache(&cache, gpu, RESOURCE_COUNT);
// Check that cache works.
for (int k = 0; k < RESOURCE_COUNT; k += 33) {
check_cache_contents_or_die(&cache, k);
}
cache.purgeAllUnlocked();
}
}
private:
typedef Benchmark INHERITED;
};
class GrResourceCacheBenchFind : public Benchmark {
enum {
RESOURCE_COUNT = (CACHE_SIZE_COUNT / 2) - 100,
DUPLICATE_COUNT = 100
};
public:
virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
return backend == kGPU_Backend;
}
protected:
virtual const char* onGetName() SK_OVERRIDE {
return "grresourcecache_find";
}
virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
GrGpu* gpu = canvas->getGrContext()->getGpu();
GrResourceCache cache(gpu->caps(), CACHE_SIZE_COUNT, CACHE_SIZE_BYTES);
populate_cache(&cache, gpu, DUPLICATE_COUNT);
populate_cache(&cache, gpu, RESOURCE_COUNT);
for (int i = 0; i < loops; ++i) {
for (int k = 0; k < RESOURCE_COUNT; ++k) {
check_cache_contents_or_die(&cache, k);
}
}
}
private:
typedef Benchmark INHERITED;
};
DEF_BENCH( return new GrResourceCacheBenchAdd(); )
DEF_BENCH( return new GrResourceCacheBenchFind(); )
#endif