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