1 2 /* 3 * Copyright 2013 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #if SK_SUPPORT_GPU 10 11 #include "Benchmark.h" 12 #include "GrGpuResource.h" 13 #include "GrContext.h" 14 #include "GrResourceCache.h" 15 #include "GrStencilBuffer.h" 16 #include "GrTexture.h" 17 #include "SkCanvas.h" 18 19 enum { 20 CACHE_SIZE_COUNT = 2048, 21 CACHE_SIZE_BYTES = 2 * 1024 * 1024, 22 }; 23 24 class StencilResource : public GrGpuResource { 25 public: 26 SK_DECLARE_INST_COUNT(StencilResource); 27 StencilResource(GrGpu* gpu, int id) 28 : INHERITED(gpu, false) 29 , fID(id) { 30 this->registerWithCache(); 31 } 32 33 virtual ~StencilResource() { this->release(); } 34 35 virtual size_t gpuMemorySize() const SK_OVERRIDE { 36 return 100 + ((fID % 1 == 0) ? -5 : 6); 37 } 38 39 static GrResourceKey ComputeKey(int width, int height, int sampleCnt) { 40 return GrStencilBuffer::ComputeKey(width, height, sampleCnt); 41 } 42 43 int fID; 44 45 private: 46 typedef GrGpuResource INHERITED; 47 }; 48 49 class TextureResource : public GrGpuResource { 50 public: 51 SK_DECLARE_INST_COUNT(TextureResource); 52 TextureResource(GrGpu* gpu, int id) 53 : INHERITED(gpu, false) 54 , fID(id) { 55 this->registerWithCache(); 56 } 57 58 virtual ~TextureResource() { this->release(); } 59 60 virtual size_t gpuMemorySize() const SK_OVERRIDE { 61 return 100 + ((fID % 1 == 0) ? -40 : 33); 62 } 63 64 static GrResourceKey ComputeKey(const GrTextureDesc& desc) { 65 return GrTextureImpl::ComputeScratchKey(desc); 66 } 67 68 int fID; 69 70 private: 71 typedef GrGpuResource INHERITED; 72 }; 73 74 static void get_stencil(int i, int* w, int* h, int* s) { 75 *w = i % 1024; 76 *h = i * 2 % 1024; 77 *s = i % 1 == 0 ? 0 : 4; 78 } 79 80 static void get_texture_desc(int i, GrTextureDesc* desc) { 81 desc->fFlags = kRenderTarget_GrTextureFlagBit | 82 kNoStencil_GrTextureFlagBit; 83 desc->fWidth = i % 1024; 84 desc->fHeight = i * 2 % 1024; 85 desc->fConfig = static_cast<GrPixelConfig>(i % (kLast_GrPixelConfig + 1)); 86 desc->fSampleCnt = i % 1 == 0 ? 0 : 4; 87 } 88 89 static void populate_cache(GrResourceCache* cache, GrGpu* gpu, int resourceCount) { 90 for (int i = 0; i < resourceCount; ++i) { 91 int w, h, s; 92 get_stencil(i, &w, &h, &s); 93 GrResourceKey key = GrStencilBuffer::ComputeKey(w, h, s); 94 GrGpuResource* resource = SkNEW_ARGS(StencilResource, (gpu, i)); 95 cache->purgeAsNeeded(1, resource->gpuMemorySize()); 96 cache->addResource(key, resource); 97 resource->unref(); 98 } 99 100 for (int i = 0; i < resourceCount; ++i) { 101 GrTextureDesc desc; 102 get_texture_desc(i, &desc); 103 GrResourceKey key = TextureResource::ComputeKey(desc); 104 GrGpuResource* resource = SkNEW_ARGS(TextureResource, (gpu, i)); 105 cache->purgeAsNeeded(1, resource->gpuMemorySize()); 106 cache->addResource(key, resource); 107 resource->unref(); 108 } 109 } 110 111 static void check_cache_contents_or_die(GrResourceCache* cache, int k) { 112 // Benchmark find calls that succeed. 113 { 114 GrTextureDesc desc; 115 get_texture_desc(k, &desc); 116 GrResourceKey key = TextureResource::ComputeKey(desc); 117 GrGpuResource* item = cache->find(key); 118 if (NULL == item) { 119 SkFAIL("cache add does not work as expected"); 120 return; 121 } 122 if (static_cast<TextureResource*>(item)->fID != k) { 123 SkFAIL("cache add does not work as expected"); 124 return; 125 } 126 } 127 { 128 int w, h, s; 129 get_stencil(k, &w, &h, &s); 130 GrResourceKey key = StencilResource::ComputeKey(w, h, s); 131 GrGpuResource* item = cache->find(key); 132 if (NULL == item) { 133 SkFAIL("cache add does not work as expected"); 134 return; 135 } 136 if (static_cast<TextureResource*>(item)->fID != k) { 137 SkFAIL("cache add does not work as expected"); 138 return; 139 } 140 } 141 142 // Benchmark also find calls that always fail. 143 { 144 GrTextureDesc desc; 145 get_texture_desc(k, &desc); 146 desc.fHeight |= 1; 147 GrResourceKey key = TextureResource::ComputeKey(desc); 148 GrGpuResource* item = cache->find(key); 149 if (item) { 150 SkFAIL("cache add does not work as expected"); 151 return; 152 } 153 } 154 { 155 int w, h, s; 156 get_stencil(k, &w, &h, &s); 157 h |= 1; 158 GrResourceKey key = StencilResource::ComputeKey(w, h, s); 159 GrGpuResource* item = cache->find(key); 160 if (item) { 161 SkFAIL("cache add does not work as expected"); 162 return; 163 } 164 } 165 } 166 167 class GrResourceCacheBenchAdd : public Benchmark { 168 enum { 169 RESOURCE_COUNT = CACHE_SIZE_COUNT / 2, 170 DUPLICATE_COUNT = CACHE_SIZE_COUNT / 4, 171 }; 172 173 public: 174 virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { 175 return backend == kGPU_Backend; 176 } 177 178 protected: 179 virtual const char* onGetName() SK_OVERRIDE { 180 return "grresourcecache_add"; 181 } 182 183 virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { 184 GrGpu* gpu = canvas->getGrContext()->getGpu(); 185 186 for (int i = 0; i < loops; ++i) { 187 GrResourceCache cache(CACHE_SIZE_COUNT, CACHE_SIZE_BYTES); 188 populate_cache(&cache, gpu, DUPLICATE_COUNT); 189 populate_cache(&cache, gpu, RESOURCE_COUNT); 190 191 // Check that cache works. 192 for (int k = 0; k < RESOURCE_COUNT; k += 33) { 193 check_cache_contents_or_die(&cache, k); 194 } 195 cache.purgeAllUnlocked(); 196 } 197 } 198 199 private: 200 typedef Benchmark INHERITED; 201 }; 202 203 class GrResourceCacheBenchFind : public Benchmark { 204 enum { 205 RESOURCE_COUNT = (CACHE_SIZE_COUNT / 2) - 100, 206 DUPLICATE_COUNT = 100 207 }; 208 209 public: 210 virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { 211 return backend == kGPU_Backend; 212 } 213 214 protected: 215 virtual const char* onGetName() SK_OVERRIDE { 216 return "grresourcecache_find"; 217 } 218 219 virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { 220 GrGpu* gpu = canvas->getGrContext()->getGpu(); 221 GrResourceCache cache(CACHE_SIZE_COUNT, CACHE_SIZE_BYTES); 222 populate_cache(&cache, gpu, DUPLICATE_COUNT); 223 populate_cache(&cache, gpu, RESOURCE_COUNT); 224 225 for (int i = 0; i < loops; ++i) { 226 for (int k = 0; k < RESOURCE_COUNT; ++k) { 227 check_cache_contents_or_die(&cache, k); 228 } 229 } 230 } 231 232 private: 233 typedef Benchmark INHERITED; 234 }; 235 236 DEF_BENCH( return new GrResourceCacheBenchAdd(); ) 237 DEF_BENCH( return new GrResourceCacheBenchFind(); ) 238 239 #endif 240