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 "GrCacheable.h"
13#include "GrContext.h"
14#include "GrResourceCache.h"
15#include "GrStencilBuffer.h"
16#include "GrTexture.h"
17#include "SkCanvas.h"
18
19enum {
20    CACHE_SIZE_COUNT = 2048,
21    CACHE_SIZE_BYTES = 2 * 1024 * 1024,
22};
23
24class StencilResource : public GrCacheable {
25public:
26    SK_DECLARE_INST_COUNT(StencilResource);
27    StencilResource(int id)
28        : fID(id) {
29    }
30
31    virtual size_t gpuMemorySize() const SK_OVERRIDE {
32        return 100 + ((fID % 1 == 0) ? -5 : 6);
33    }
34
35    virtual bool isValidOnGpu() const SK_OVERRIDE {
36        return true;
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
45private:
46    typedef GrCacheable INHERITED;
47};
48
49class TextureResource : public GrCacheable {
50public:
51    SK_DECLARE_INST_COUNT(TextureResource);
52    TextureResource(int id)
53        : fID(id) {
54    }
55
56    virtual size_t gpuMemorySize() const SK_OVERRIDE {
57        return 100 + ((fID % 1 == 0) ? -40 : 33);
58    }
59
60    virtual bool isValidOnGpu() const SK_OVERRIDE {
61        return true;
62    }
63
64    static GrResourceKey ComputeKey(const GrTextureDesc& desc) {
65        return GrTextureImpl::ComputeScratchKey(desc);
66    }
67
68    int fID;
69
70private:
71    typedef GrCacheable INHERITED;
72};
73
74static 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
80static 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
89static 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        GrCacheable* resource = SkNEW_ARGS(StencilResource, (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        GrCacheable* resource = SkNEW_ARGS(TextureResource, (i));
105        cache->purgeAsNeeded(1, resource->gpuMemorySize());
106        cache->addResource(key, resource);
107        resource->unref();
108    }
109}
110
111static 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        GrCacheable* 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        GrCacheable* 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        GrCacheable* item = cache->find(key);
149        if (NULL != 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        GrCacheable* item = cache->find(key);
160        if (NULL != item) {
161            SkFAIL("cache add does not work as expected");
162            return;
163        }
164    }
165}
166
167class GrResourceCacheBenchAdd : public Benchmark {
168    enum {
169        RESOURCE_COUNT = CACHE_SIZE_COUNT / 2,
170        DUPLICATE_COUNT = CACHE_SIZE_COUNT / 4,
171    };
172
173public:
174    virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
175        return backend == kGPU_Backend;
176    }
177
178protected:
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
199private:
200    typedef Benchmark INHERITED;
201};
202
203class GrResourceCacheBenchFind : public Benchmark {
204    enum {
205        RESOURCE_COUNT = (CACHE_SIZE_COUNT / 2) - 100,
206        DUPLICATE_COUNT = 100
207    };
208
209public:
210    virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
211        return backend == kGPU_Backend;
212    }
213
214protected:
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
232private:
233    typedef Benchmark INHERITED;
234};
235
236DEF_BENCH( return new GrResourceCacheBenchAdd(); )
237DEF_BENCH( return new GrResourceCacheBenchFind(); )
238
239#endif
240