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