1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/core/SkScalerCache.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "bench/Benchmark.h"
11cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
12cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h"
13cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h"
14cb93a386Sopenharmony_ci#include "src/core/SkRemoteGlyphCache.h"
15cb93a386Sopenharmony_ci#include "src/core/SkStrikeSpec.h"
16cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h"
17cb93a386Sopenharmony_ci#include "src/core/SkTaskGroup.h"
18cb93a386Sopenharmony_ci#include "src/core/SkTextBlobTrace.h"
19cb93a386Sopenharmony_ci#include "tools/Resources.h"
20cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_cistatic void do_font_stuff(SkFont* font) {
23cb93a386Sopenharmony_ci    SkPaint defaultPaint;
24cb93a386Sopenharmony_ci    for (SkScalar i = 8; i < 64; i++) {
25cb93a386Sopenharmony_ci        font->setSize(i);
26cb93a386Sopenharmony_ci        auto strikeSpec = SkStrikeSpec::MakeMask(
27cb93a386Sopenharmony_ci                *font,  defaultPaint, SkSurfaceProps(0, kUnknown_SkPixelGeometry),
28cb93a386Sopenharmony_ci                SkScalerContextFlags::kNone, SkMatrix::I());
29cb93a386Sopenharmony_ci        SkPackedGlyphID glyphs['z'];
30cb93a386Sopenharmony_ci        for (int c = ' '; c < 'z'; c++) {
31cb93a386Sopenharmony_ci            glyphs[c] = SkPackedGlyphID{font->unicharToGlyph(c)};
32cb93a386Sopenharmony_ci        }
33cb93a386Sopenharmony_ci        constexpr size_t glyphCount = 'z' - ' ';
34cb93a386Sopenharmony_ci        SkSpan<const SkPackedGlyphID> glyphIDs{&glyphs[SkTo<int>(' ')], glyphCount};
35cb93a386Sopenharmony_ci        SkBulkGlyphMetricsAndImages images{strikeSpec};
36cb93a386Sopenharmony_ci        for (int lookups = 0; lookups < 10; lookups++) {
37cb93a386Sopenharmony_ci            (void)images.glyphs(glyphIDs);
38cb93a386Sopenharmony_ci        }
39cb93a386Sopenharmony_ci    }
40cb93a386Sopenharmony_ci}
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ciclass SkGlyphCacheBasic : public Benchmark {
43cb93a386Sopenharmony_cipublic:
44cb93a386Sopenharmony_ci    explicit SkGlyphCacheBasic(size_t cacheSize) : fCacheSize(cacheSize) { }
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ciprotected:
47cb93a386Sopenharmony_ci    const char* onGetName() override {
48cb93a386Sopenharmony_ci        fName.printf("SkGlyphCacheBasic%dK", (int)(fCacheSize >> 10));
49cb93a386Sopenharmony_ci        return fName.c_str();
50cb93a386Sopenharmony_ci    }
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
53cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
54cb93a386Sopenharmony_ci    }
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
57cb93a386Sopenharmony_ci        size_t oldCacheLimitSize = SkGraphics::GetFontCacheLimit();
58cb93a386Sopenharmony_ci        SkGraphics::SetFontCacheLimit(fCacheSize);
59cb93a386Sopenharmony_ci        SkFont font;
60cb93a386Sopenharmony_ci        font.setEdging(SkFont::Edging::kAntiAlias);
61cb93a386Sopenharmony_ci        font.setSubpixel(true);
62cb93a386Sopenharmony_ci        font.setTypeface(ToolUtils::create_portable_typeface("serif", SkFontStyle::Italic()));
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci        for (int work = 0; work < loops; work++) {
65cb93a386Sopenharmony_ci            do_font_stuff(&font);
66cb93a386Sopenharmony_ci        }
67cb93a386Sopenharmony_ci        SkGraphics::SetFontCacheLimit(oldCacheLimitSize);
68cb93a386Sopenharmony_ci    }
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ciprivate:
71cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
72cb93a386Sopenharmony_ci    const size_t fCacheSize;
73cb93a386Sopenharmony_ci    SkString fName;
74cb93a386Sopenharmony_ci};
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ciclass SkGlyphCacheStressTest : public Benchmark {
77cb93a386Sopenharmony_cipublic:
78cb93a386Sopenharmony_ci    explicit SkGlyphCacheStressTest(int cacheSize) : fCacheSize(cacheSize) { }
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ciprotected:
81cb93a386Sopenharmony_ci    const char* onGetName() override {
82cb93a386Sopenharmony_ci        fName.printf("SkGlyphCacheStressTest%dK", (int)(fCacheSize >> 10));
83cb93a386Sopenharmony_ci        return fName.c_str();
84cb93a386Sopenharmony_ci    }
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
87cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
88cb93a386Sopenharmony_ci    }
89cb93a386Sopenharmony_ci
90cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) override {
91cb93a386Sopenharmony_ci        size_t oldCacheLimitSize = SkGraphics::GetFontCacheLimit();
92cb93a386Sopenharmony_ci        SkGraphics::SetFontCacheLimit(fCacheSize);
93cb93a386Sopenharmony_ci        sk_sp<SkTypeface> typefaces[] = {
94cb93a386Sopenharmony_ci                ToolUtils::create_portable_typeface("serif", SkFontStyle::Italic()),
95cb93a386Sopenharmony_ci                ToolUtils::create_portable_typeface("sans-serif", SkFontStyle::Italic())};
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci        for (int work = 0; work < loops; work++) {
98cb93a386Sopenharmony_ci            SkTaskGroup().batch(16, [&](int threadIndex) {
99cb93a386Sopenharmony_ci                SkFont font;
100cb93a386Sopenharmony_ci                font.setEdging(SkFont::Edging::kAntiAlias);
101cb93a386Sopenharmony_ci                font.setSubpixel(true);
102cb93a386Sopenharmony_ci                font.setTypeface(typefaces[threadIndex % 2]);
103cb93a386Sopenharmony_ci                do_font_stuff(&font);
104cb93a386Sopenharmony_ci            });
105cb93a386Sopenharmony_ci        }
106cb93a386Sopenharmony_ci        SkGraphics::SetFontCacheLimit(oldCacheLimitSize);
107cb93a386Sopenharmony_ci    }
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ciprivate:
110cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
111cb93a386Sopenharmony_ci    const size_t fCacheSize;
112cb93a386Sopenharmony_ci    SkString fName;
113cb93a386Sopenharmony_ci};
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ciDEF_BENCH( return new SkGlyphCacheBasic(256 * 1024); )
116cb93a386Sopenharmony_ciDEF_BENCH( return new SkGlyphCacheBasic(32 * 1024 * 1024); )
117cb93a386Sopenharmony_ciDEF_BENCH( return new SkGlyphCacheStressTest(256 * 1024); )
118cb93a386Sopenharmony_ciDEF_BENCH( return new SkGlyphCacheStressTest(32 * 1024 * 1024); )
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_cinamespace {
121cb93a386Sopenharmony_ciclass DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
122cb93a386Sopenharmony_ci                           public SkStrikeClient::DiscardableHandleManager {
123cb93a386Sopenharmony_cipublic:
124cb93a386Sopenharmony_ci    DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
125cb93a386Sopenharmony_ci    ~DiscardableManager() override = default;
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci    // Server implementation.
128cb93a386Sopenharmony_ci    SkDiscardableHandleId createHandle() override {
129cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci        // Handles starts as locked.
132cb93a386Sopenharmony_ci        fLockedHandles.add(++fNextHandleId);
133cb93a386Sopenharmony_ci        return fNextHandleId;
134cb93a386Sopenharmony_ci    }
135cb93a386Sopenharmony_ci    bool lockHandle(SkDiscardableHandleId id) override {
136cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci        if (id <= fLastDeletedHandleId) return false;
139cb93a386Sopenharmony_ci        fLockedHandles.add(id);
140cb93a386Sopenharmony_ci        return true;
141cb93a386Sopenharmony_ci    }
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci    // Client implementation.
144cb93a386Sopenharmony_ci    bool deleteHandle(SkDiscardableHandleId id) override {
145cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci        return id <= fLastDeletedHandleId;
148cb93a386Sopenharmony_ci    }
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci    void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
151cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci        fCacheMissCount[type]++;
154cb93a386Sopenharmony_ci    }
155cb93a386Sopenharmony_ci    bool isHandleDeleted(SkDiscardableHandleId id) override {
156cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci        return id <= fLastDeletedHandleId;
159cb93a386Sopenharmony_ci    }
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_ci    void unlockAll() {
162cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci        fLockedHandles.reset();
165cb93a386Sopenharmony_ci    }
166cb93a386Sopenharmony_ci    void unlockAndDeleteAll() {
167cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci        fLockedHandles.reset();
170cb93a386Sopenharmony_ci        fLastDeletedHandleId = fNextHandleId;
171cb93a386Sopenharmony_ci    }
172cb93a386Sopenharmony_ci    const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
173cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ci        return fLockedHandles;
176cb93a386Sopenharmony_ci    }
177cb93a386Sopenharmony_ci    SkDiscardableHandleId handleCount() {
178cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci        return fNextHandleId;
181cb93a386Sopenharmony_ci    }
182cb93a386Sopenharmony_ci    int cacheMissCount(uint32_t type) {
183cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci        return fCacheMissCount[type];
186cb93a386Sopenharmony_ci    }
187cb93a386Sopenharmony_ci    bool hasCacheMiss() const {
188cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci        for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
191cb93a386Sopenharmony_ci            if (fCacheMissCount[i] > 0) return true;
192cb93a386Sopenharmony_ci        }
193cb93a386Sopenharmony_ci        return false;
194cb93a386Sopenharmony_ci    }
195cb93a386Sopenharmony_ci    void resetCacheMissCounts() {
196cb93a386Sopenharmony_ci        SkAutoMutexExclusive l(fMutex);
197cb93a386Sopenharmony_ci        sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
198cb93a386Sopenharmony_ci    }
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ciprivate:
201cb93a386Sopenharmony_ci    // The tests below run in parallel on multiple threads and use the same
202cb93a386Sopenharmony_ci    // process global SkStrikeCache. So the implementation needs to be
203cb93a386Sopenharmony_ci    // thread-safe.
204cb93a386Sopenharmony_ci    mutable SkMutex fMutex;
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_ci    SkDiscardableHandleId fNextHandleId = 0u;
207cb93a386Sopenharmony_ci    SkDiscardableHandleId fLastDeletedHandleId = 0u;
208cb93a386Sopenharmony_ci    SkTHashSet<SkDiscardableHandleId> fLockedHandles;
209cb93a386Sopenharmony_ci    int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
210cb93a386Sopenharmony_ci};
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ciclass DiffCanvasBench : public Benchmark {
213cb93a386Sopenharmony_ci    SkString fBenchName;
214cb93a386Sopenharmony_ci    std::function<std::unique_ptr<SkStreamAsset>()> fDataProvider;
215cb93a386Sopenharmony_ci    std::vector<SkTextBlobTrace::Record> fTrace;
216cb93a386Sopenharmony_ci    sk_sp<DiscardableManager> fDiscardableManager;
217cb93a386Sopenharmony_ci    SkTLazy<SkStrikeServer> fServer;
218cb93a386Sopenharmony_ci
219cb93a386Sopenharmony_ci    const char* onGetName() override { return fBenchName.c_str(); }
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_ci    bool isSuitableFor(Backend b) override { return b == kNonRendering_Backend; }
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas* modelCanvas) override {
224cb93a386Sopenharmony_ci        SkSurfaceProps props;
225cb93a386Sopenharmony_ci        if (modelCanvas) { modelCanvas->getProps(&props); }
226cb93a386Sopenharmony_ci        std::unique_ptr<SkCanvas> canvas = fServer->makeAnalysisCanvas(1024, 1024, props,
227cb93a386Sopenharmony_ci                                                                       nullptr, true);
228cb93a386Sopenharmony_ci        loops *= 100;
229cb93a386Sopenharmony_ci        while (loops --> 0) {
230cb93a386Sopenharmony_ci            for (const auto& record : fTrace) {
231cb93a386Sopenharmony_ci                canvas->drawTextBlob(
232cb93a386Sopenharmony_ci                        record.blob.get(), record.offset.x(), record.offset.y(),record.paint);
233cb93a386Sopenharmony_ci            }
234cb93a386Sopenharmony_ci        }
235cb93a386Sopenharmony_ci    }
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci    void onDelayedSetup() override {
238cb93a386Sopenharmony_ci        auto stream = fDataProvider();
239cb93a386Sopenharmony_ci        fDiscardableManager = sk_make_sp<DiscardableManager>();
240cb93a386Sopenharmony_ci        fServer.init(fDiscardableManager.get());
241cb93a386Sopenharmony_ci        fTrace = SkTextBlobTrace::CreateBlobTrace(stream.get());
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_cipublic:
245cb93a386Sopenharmony_ci    DiffCanvasBench(SkString n, std::function<std::unique_ptr<SkStreamAsset>()> f)
246cb93a386Sopenharmony_ci        : fBenchName(std::move(n)), fDataProvider(std::move(f)) {}
247cb93a386Sopenharmony_ci};
248cb93a386Sopenharmony_ci}  // namespace
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_ciBenchmark* CreateDiffCanvasBench(
251cb93a386Sopenharmony_ci        SkString name, std::function<std::unique_ptr<SkStreamAsset>()> dataSrc) {
252cb93a386Sopenharmony_ci    return new DiffCanvasBench(std::move(name), std::move(dataSrc));
253cb93a386Sopenharmony_ci}
254cb93a386Sopenharmony_ci
255cb93a386Sopenharmony_ciDEF_BENCH( return CreateDiffCanvasBench(
256cb93a386Sopenharmony_ci        SkString("SkDiffBench-lorem_ipsum"),
257cb93a386Sopenharmony_ci        [](){ return GetResourceAsStream("diff_canvas_traces/lorem_ipsum.trace"); }));
258