1b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon/*
2b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * Copyright 2016 Google Inc.
3b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon *
4b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * Use of this source code is governed by a BSD-style license that can be
5b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * found in the LICENSE file.
6b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon */
7b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
8b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon#include "Benchmark.h"
9b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon#include "sk_tool_utils.h"
10b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon#include "SkCanvas.h"
11b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon#include "SkImage.h"
12b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon#include "SkSurface.h"
13b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
149f1f6e2c28066c7d7ff26727ce7d7504c7d032bdbrianosman#if SK_SUPPORT_GPU
159f1f6e2c28066c7d7ff26727ce7d7504c7d032bdbrianosman
169f1f6e2c28066c7d7ff26727ce7d7504c7d032bdbrianosman#include "GrContext.h"
179f1f6e2c28066c7d7ff26727ce7d7504c7d032bdbrianosman
18b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon/** These benchmarks were designed to measure changes to GrResourceCache's replacement policy */
19b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
20b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon//////////////////////////////////////////////////////////////////////////////
21b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
22b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon// The width/height of the images to draw. The small size underestimates the value of a good
23b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon// replacement strategy since the texture uploads are quite small. However, the effects are still
24b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon// significant and this lets the benchmarks complete a lot faster, especially on mobile.
25b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonstatic constexpr int kS = 25;
26b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
27b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonstatic void make_images(sk_sp<SkImage> imgs[], int cnt) {
28b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    for (int i = 0; i < cnt; ++i) {
29b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        SkBitmap bmp = sk_tool_utils::create_checkerboard_bitmap(kS, kS, SK_ColorBLACK,
30b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                                                                 SK_ColorCYAN, 10);
31b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        imgs[i] = SkImage::MakeFromBitmap(bmp);
32b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
33b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon}
34b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
35b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonstatic void draw_image(SkCanvas* canvas, SkImage* img) {
36b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    // Make the paint transparent to avoid any issues of deferred tiler blending
37b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    // optmizations
38b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    SkPaint paint;
39b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    paint.setAlpha(0x10);
40b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    canvas->drawImage(img, 0, 0, &paint);
41b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon}
42b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
43b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonvoid set_cache_budget(SkCanvas* canvas, int approxImagesInBudget) {
44b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    // This is inexact but we attempt to figure out a baseline number of resources GrContext needs
45b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    // to render an SkImage and add one additional resource for each image we'd like to fit.
46b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    GrContext* context =  canvas->getGrContext();
47b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    SkASSERT(context);
48b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    context->flush();
49b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    context->purgeAllUnlockedResources();
50b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    sk_sp<SkImage> image;
51b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    make_images(&image, 1);
52b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    draw_image(canvas, image.get());
53b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    context->flush();
54b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    int baselineCount;
55b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    context->getResourceCacheUsage(&baselineCount, nullptr);
56b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    baselineCount -= 1; // for the image's textures.
57b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    context->setResourceCacheLimits(baselineCount + approxImagesInBudget, 1 << 30);
58b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    context->purgeAllUnlockedResources();
59b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon}
60b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
61b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon//////////////////////////////////////////////////////////////////////////////
62b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
63b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon/**
64b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * Tests repeatedly drawing the same set of images in each frame. Different instances of the bench
65b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * run with different cache sizes and either repeat the image order each frame or use a random
66b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * order. Every variation of this bench draws the same image set, only the budget and order of
67b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * images differs. Since the total fill is the same they can be cross-compared.
68b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon */
69b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonclass ImageCacheBudgetBench : public Benchmark {
70b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonpublic:
71b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    /** budgetSize is the number of images that can fit in the cache. 100 images will be drawn. */
72b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    ImageCacheBudgetBench(int budgetSize, bool shuffle)
73b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            : fBudgetSize(budgetSize)
74b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            , fShuffle(shuffle)
75b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            , fIndices(nullptr) {
76b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        float imagesOverBudget = float(kImagesToDraw) / budgetSize;
77b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        // Make the benchmark name contain the percentage of the budget that is used in each
78b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        // simulated frame.
79b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        fName.printf("image_cache_budget_%.0f%s", imagesOverBudget * 100,
80b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                     (shuffle ? "_shuffle" : ""));
81b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
82b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
83b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
84b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
85b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonprotected:
86b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    const char* onGetName() override {
87b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        return fName.c_str();
88b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
89b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
90b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    void onPerCanvasPreDraw(SkCanvas* canvas) override {
91b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        GrContext* context = canvas->getGrContext();
92b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        SkASSERT(context);
93b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        context->getResourceCacheLimits(&fOldCount, &fOldBytes);
94b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        set_cache_budget(canvas, fBudgetSize);
95b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        make_images(fImages, kImagesToDraw);
96b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        if (fShuffle) {
97b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            SkRandom random;
98b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            fIndices.reset(new int[kSimulatedFrames * kImagesToDraw]);
99b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            for (int frame = 0; frame < kSimulatedFrames; ++frame) {
100b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                int* base = fIndices.get() + frame * kImagesToDraw;
101b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                for (int i = 0; i < kImagesToDraw; ++i) {
102b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    base[i] = i;
103b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                }
104b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                for (int i = 0; i < kImagesToDraw - 1; ++i) {
105b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    int other = random.nextULessThan(kImagesToDraw - i) + i;
106b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    SkTSwap(base[i], base[other]);
107b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                }
108b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            }
109b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        }
110b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
111b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
112b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    void onPerCanvasPostDraw(SkCanvas* canvas) override {
113b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        GrContext* context =  canvas->getGrContext();
114b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        SkASSERT(context);
115b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        context->setResourceCacheLimits(fOldCount, fOldBytes);
116b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        for (int i = 0; i < kImagesToDraw; ++i) {
117b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            fImages[i].reset();
118b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        }
119b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        fIndices.reset(nullptr);
120b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
121b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
122b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    void onDraw(int loops, SkCanvas* canvas) override {
123b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        for (int i = 0; i < loops; ++i) {
124b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            for (int frame = 0; frame < kSimulatedFrames; ++frame) {
125b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                for (int j = 0; j < kImagesToDraw; ++j) {
126b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    int idx;
127b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    if (fShuffle) {
128b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                        idx = fIndices[frame * kImagesToDraw + j];
129b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    } else {
130b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                        idx = j;
131b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    }
132b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    draw_image(canvas, fImages[idx].get());
133b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                }
134b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                // Simulate a frame boundary by flushing. This should notify GrResourceCache.
135b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                canvas->flush();
136b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon           }
137b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        }
138b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
139b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
140b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonprivate:
141b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    static constexpr int kImagesToDraw = 100;
142b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    static constexpr int kSimulatedFrames = 5;
143b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
144b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    int                         fBudgetSize;
145b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    bool                        fShuffle;
146b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    SkString                    fName;
147b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    sk_sp<SkImage>              fImages[kImagesToDraw];
1487ecc59610de72043e9b7ebaf1ef45c43425e54fcBen Wagner    std::unique_ptr<int[]>      fIndices;
149b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    size_t                      fOldBytes;
150b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    int                         fOldCount;
151b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
152b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    typedef Benchmark INHERITED;
153b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon};
154b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
155b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetBench(105, false); )
156b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
157b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetBench(90, false); )
158b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
159b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetBench(80, false); )
160b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
161b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetBench(50, false); )
162b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
163b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetBench(105, true); )
164b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
165b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetBench(90, true); )
166b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
167b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetBench(80, true); )
168b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
169b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetBench(50, true); )
170b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
171b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon//////////////////////////////////////////////////////////////////////////////
172b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
173b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon/**
174b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * Similar to above but changes between being over and under budget by varying the number of images
175b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon * rendered. This is not directly comparable to the non-dynamic benchmarks.
176b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon */
177b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonclass ImageCacheBudgetDynamicBench : public Benchmark {
178b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonpublic:
179b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    enum class Mode {
180b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        // Increase from min to max images drawn gradually over simulated frames and then back.
181b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        kPingPong,
182b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        // Alternate between under and over budget every other simulated frame.
183b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        kFlipFlop
184b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    };
185b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
186b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    ImageCacheBudgetDynamicBench(Mode mode) : fMode(mode) {}
187b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
188b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
189b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
190b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonprotected:
191b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    const char* onGetName() override {
192b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        switch (fMode) {
193b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            case Mode::kPingPong:
194b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                return "image_cache_budget_dynamic_ping_pong";
195b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            case Mode::kFlipFlop:
196b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                return "image_cache_budget_dynamic_flip_flop";
197b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        }
198b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        return "";
199b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
200b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
201b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    void onPerCanvasPreDraw(SkCanvas* canvas) override {
202b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        GrContext* context =  canvas->getGrContext();
203b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        SkASSERT(context);
204b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        context->getResourceCacheLimits(&fOldCount, &fOldBytes);
205b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        make_images(fImages, kMaxImagesToDraw);
206b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        set_cache_budget(canvas, kImagesInBudget);
207b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
208b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
209b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    void onPerCanvasPostDraw(SkCanvas* canvas) override {
210b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        GrContext* context =  canvas->getGrContext();
211b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        SkASSERT(context);
212b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        context->setResourceCacheLimits(fOldCount, fOldBytes);
213b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        for (int i = 0; i < kMaxImagesToDraw; ++i) {
214b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            fImages[i].reset();
215b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        }
216b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
217b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
218b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    void onDraw(int loops, SkCanvas* canvas) override {
219b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        int delta = 0;
220b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        switch (fMode) {
221b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            case Mode::kPingPong:
222b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                delta = 1;
223b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                break;
224b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            case Mode::kFlipFlop:
225b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                delta = kMaxImagesToDraw - kMinImagesToDraw;
226b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                break;
227b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        }
228b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        for (int i = 0; i < loops; ++i) {
229b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            int imgsToDraw = kMinImagesToDraw;
230b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            for (int frame = 0; frame < kSimulatedFrames; ++frame) {
231b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                for (int j = 0; j < imgsToDraw; ++j) {
232b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    draw_image(canvas, fImages[j].get());
233b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                }
234b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                imgsToDraw += delta;
235b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                if (imgsToDraw > kMaxImagesToDraw || imgsToDraw < kMinImagesToDraw) {
236b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    delta = -delta;
237b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                    imgsToDraw += 2 * delta;
238b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                }
239b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                // Simulate a frame boundary by flushing. This should notify GrResourceCache.
240b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon                canvas->flush();
241b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon            }
242b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon        }
243b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    }
244b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
245b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonprivate:
246b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    static constexpr int kImagesInBudget  = 25;
247b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    static constexpr int kMinImagesToDraw = 15;
248b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    static constexpr int kMaxImagesToDraw = 35;
249b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    static constexpr int kSimulatedFrames = 80;
250b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
251b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    Mode                        fMode;
252b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    sk_sp<SkImage>              fImages[kMaxImagesToDraw];
253b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    size_t                      fOldBytes;
254b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    int                         fOldCount;
255b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
256b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon    typedef Benchmark INHERITED;
257b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon};
258b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomon
259b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetDynamicBench(ImageCacheBudgetDynamicBench::Mode::kPingPong); )
260b3cb2142725f9d0cd88a7200770536bc21f73b14bsalomonDEF_BENCH( return new ImageCacheBudgetDynamicBench(ImageCacheBudgetDynamicBench::Mode::kFlipFlop); )
2619f1f6e2c28066c7d7ff26727ce7d7504c7d032bdbrianosman
2629f1f6e2c28066c7d7ff26727ce7d7504c7d032bdbrianosman#endif
263