| /* | |
| * 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 "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) { | |
| return GrTexturePriv::ComputeScratchKey(desc); | |
| } | |
| 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<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) { | |
| 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<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. | |
| { | |
| 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(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(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 |