/* * 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 GrTextureDesc& 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, GrTextureDesc* desc) { desc->fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc->fWidth = i % 1024; desc->fHeight = i * 2 % 1024; desc->fConfig = static_cast(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) { GrTextureDesc 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. { GrTextureDesc 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(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(item)->fID != k) { SkFAIL("cache add does not work as expected"); return; } } // Benchmark also find calls that always fail. { GrTextureDesc 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