blob: dded96ef6fe44ff778d052d487191d01d43c74fa [file] [log] [blame]
herb1052f512015-09-18 12:09:43 -07001/*
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
Herb Derby81e84a62020-02-14 11:47:35 -05008#include "src/core/SkScalerCache.h"
herb1052f512015-09-18 12:09:43 -07009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "bench/Benchmark.h"
11#include "include/core/SkCanvas.h"
12#include "include/core/SkGraphics.h"
13#include "include/core/SkTypeface.h"
Hal Canarye107faa2019-10-23 12:52:33 -040014#include "src/core/SkRemoteGlyphCache.h"
Herb Derbybaf64782019-04-17 18:01:04 -040015#include "src/core/SkStrikeSpec.h"
Herb Derby0b0fb4d2020-09-29 10:58:21 -040016#include "src/core/SkTLazy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/core/SkTaskGroup.h"
Hal Canarye107faa2019-10-23 12:52:33 -040018#include "src/core/SkTextBlobTrace.h"
19#include "tools/Resources.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "tools/ToolUtils.h"
herb1052f512015-09-18 12:09:43 -070021
Mike Reed32c60662018-11-28 10:28:07 -050022static void do_font_stuff(SkFont* font) {
23 SkPaint defaultPaint;
herb1052f512015-09-18 12:09:43 -070024 for (SkScalar i = 8; i < 64; i++) {
Mike Reed32c60662018-11-28 10:28:07 -050025 font->setSize(i);
Herb Derby36a54c12019-06-06 10:50:56 -040026 auto strikeSpec = SkStrikeSpec::MakeMask(
Mike Reed32c60662018-11-28 10:28:07 -050027 *font, defaultPaint, SkSurfaceProps(0, kUnknown_SkPixelGeometry),
Herb Derbyc3415002018-11-08 16:40:26 -050028 SkScalerContextFlags::kNone, SkMatrix::I());
Herb Derby55a85fc2019-07-03 14:46:05 -040029 SkPackedGlyphID glyphs['z'];
herb1052f512015-09-18 12:09:43 -070030 for (int c = ' '; c < 'z'; c++) {
Herb Derby55a85fc2019-07-03 14:46:05 -040031 glyphs[c] = SkPackedGlyphID{font->unicharToGlyph(c)};
herb1052f512015-09-18 12:09:43 -070032 }
Herb Derby55a85fc2019-07-03 14:46:05 -040033 constexpr size_t glyphCount = 'z' - ' ';
34 SkSpan<const SkPackedGlyphID> glyphIDs{&glyphs[SkTo<int>(' ')], glyphCount};
35 SkBulkGlyphMetricsAndImages images{strikeSpec};
herb1052f512015-09-18 12:09:43 -070036 for (int lookups = 0; lookups < 10; lookups++) {
Herb Derby55a85fc2019-07-03 14:46:05 -040037 (void)images.glyphs(glyphIDs);
herb1052f512015-09-18 12:09:43 -070038 }
herb1052f512015-09-18 12:09:43 -070039 }
40}
41
42class SkGlyphCacheBasic : public Benchmark {
43public:
44 explicit SkGlyphCacheBasic(size_t cacheSize) : fCacheSize(cacheSize) { }
45
46protected:
47 const char* onGetName() override {
48 fName.printf("SkGlyphCacheBasic%dK", (int)(fCacheSize >> 10));
49 return fName.c_str();
50 }
51
52 bool isSuitableFor(Backend backend) override {
53 return backend == kNonRendering_Backend;
54 }
55
mtkleina1ebeb22015-10-01 09:43:39 -070056 void onDraw(int loops, SkCanvas*) override {
herb1052f512015-09-18 12:09:43 -070057 size_t oldCacheLimitSize = SkGraphics::GetFontCacheLimit();
58 SkGraphics::SetFontCacheLimit(fCacheSize);
Mike Reed32c60662018-11-28 10:28:07 -050059 SkFont font;
60 font.setEdging(SkFont::Edging::kAntiAlias);
61 font.setSubpixel(true);
Mike Kleinea3f0142019-03-20 11:12:10 -050062 font.setTypeface(ToolUtils::create_portable_typeface("serif", SkFontStyle::Italic()));
herb1052f512015-09-18 12:09:43 -070063
64 for (int work = 0; work < loops; work++) {
Mike Reed32c60662018-11-28 10:28:07 -050065 do_font_stuff(&font);
herb1052f512015-09-18 12:09:43 -070066 }
67 SkGraphics::SetFontCacheLimit(oldCacheLimitSize);
68 }
69
70private:
John Stiles7571f9e2020-09-02 22:42:33 -040071 using INHERITED = Benchmark;
herb1052f512015-09-18 12:09:43 -070072 const size_t fCacheSize;
73 SkString fName;
74};
75
76class SkGlyphCacheStressTest : public Benchmark {
77public:
78 explicit SkGlyphCacheStressTest(int cacheSize) : fCacheSize(cacheSize) { }
79
80protected:
81 const char* onGetName() override {
82 fName.printf("SkGlyphCacheStressTest%dK", (int)(fCacheSize >> 10));
83 return fName.c_str();
84 }
85
86 bool isSuitableFor(Backend backend) override {
87 return backend == kNonRendering_Backend;
88 }
89
mtkleina1ebeb22015-10-01 09:43:39 -070090 void onDraw(int loops, SkCanvas*) override {
herb1052f512015-09-18 12:09:43 -070091 size_t oldCacheLimitSize = SkGraphics::GetFontCacheLimit();
92 SkGraphics::SetFontCacheLimit(fCacheSize);
Mike Kleinea3f0142019-03-20 11:12:10 -050093 sk_sp<SkTypeface> typefaces[] = {
94 ToolUtils::create_portable_typeface("serif", SkFontStyle::Italic()),
95 ToolUtils::create_portable_typeface("sans-serif", SkFontStyle::Italic())};
herb1052f512015-09-18 12:09:43 -070096
97 for (int work = 0; work < loops; work++) {
mtklein279c7862016-01-04 19:13:19 -080098 SkTaskGroup().batch(16, [&](int threadIndex) {
Mike Reed32c60662018-11-28 10:28:07 -050099 SkFont font;
100 font.setEdging(SkFont::Edging::kAntiAlias);
101 font.setSubpixel(true);
102 font.setTypeface(typefaces[threadIndex % 2]);
103 do_font_stuff(&font);
herb1052f512015-09-18 12:09:43 -0700104 });
105 }
106 SkGraphics::SetFontCacheLimit(oldCacheLimitSize);
herb1052f512015-09-18 12:09:43 -0700107 }
108
109private:
John Stiles7571f9e2020-09-02 22:42:33 -0400110 using INHERITED = Benchmark;
herb1052f512015-09-18 12:09:43 -0700111 const size_t fCacheSize;
112 SkString fName;
113};
114
115DEF_BENCH( return new SkGlyphCacheBasic(256 * 1024); )
116DEF_BENCH( return new SkGlyphCacheBasic(32 * 1024 * 1024); )
117DEF_BENCH( return new SkGlyphCacheStressTest(256 * 1024); )
118DEF_BENCH( return new SkGlyphCacheStressTest(32 * 1024 * 1024); )
Hal Canarye107faa2019-10-23 12:52:33 -0400119
120namespace {
121class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
122 public SkStrikeClient::DiscardableHandleManager {
123public:
124 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
125 ~DiscardableManager() override = default;
126
127 // Server implementation.
128 SkDiscardableHandleId createHandle() override {
129 SkAutoMutexExclusive l(fMutex);
130
131 // Handles starts as locked.
132 fLockedHandles.add(++fNextHandleId);
133 return fNextHandleId;
134 }
135 bool lockHandle(SkDiscardableHandleId id) override {
136 SkAutoMutexExclusive l(fMutex);
137
138 if (id <= fLastDeletedHandleId) return false;
139 fLockedHandles.add(id);
140 return true;
141 }
142
143 // Client implementation.
144 bool deleteHandle(SkDiscardableHandleId id) override {
145 SkAutoMutexExclusive l(fMutex);
146
147 return id <= fLastDeletedHandleId;
148 }
149
150 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
151 SkAutoMutexExclusive l(fMutex);
152
153 fCacheMissCount[type]++;
154 }
155 bool isHandleDeleted(SkDiscardableHandleId id) override {
156 SkAutoMutexExclusive l(fMutex);
157
158 return id <= fLastDeletedHandleId;
159 }
160
161 void unlockAll() {
162 SkAutoMutexExclusive l(fMutex);
163
164 fLockedHandles.reset();
165 }
166 void unlockAndDeleteAll() {
167 SkAutoMutexExclusive l(fMutex);
168
169 fLockedHandles.reset();
170 fLastDeletedHandleId = fNextHandleId;
171 }
172 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
173 SkAutoMutexExclusive l(fMutex);
174
175 return fLockedHandles;
176 }
177 SkDiscardableHandleId handleCount() {
178 SkAutoMutexExclusive l(fMutex);
179
180 return fNextHandleId;
181 }
182 int cacheMissCount(uint32_t type) {
183 SkAutoMutexExclusive l(fMutex);
184
185 return fCacheMissCount[type];
186 }
187 bool hasCacheMiss() const {
188 SkAutoMutexExclusive l(fMutex);
189
190 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
191 if (fCacheMissCount[i] > 0) return true;
192 }
193 return false;
194 }
195 void resetCacheMissCounts() {
196 SkAutoMutexExclusive l(fMutex);
197 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
198 }
199
200private:
201 // The tests below run in parallel on multiple threads and use the same
202 // process global SkStrikeCache. So the implementation needs to be
203 // thread-safe.
204 mutable SkMutex fMutex;
205
206 SkDiscardableHandleId fNextHandleId = 0u;
207 SkDiscardableHandleId fLastDeletedHandleId = 0u;
208 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
209 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
210};
211
Hal Canary5dfefa22019-10-24 13:52:17 -0400212class DiffCanvasBench : public Benchmark {
213 SkString fBenchName;
214 std::function<std::unique_ptr<SkStreamAsset>()> fDataProvider;
Hal Canarye107faa2019-10-23 12:52:33 -0400215 std::vector<SkTextBlobTrace::Record> fTrace;
216 sk_sp<DiscardableManager> fDiscardableManager;
217 SkTLazy<SkStrikeServer> fServer;
218
219 const char* onGetName() override { return fBenchName.c_str(); }
220
221 bool isSuitableFor(Backend b) override { return b == kNonRendering_Backend; }
222
Ben Wagnerae4bb982020-09-24 14:49:00 -0400223 void onDraw(int loops, SkCanvas* modelCanvas) override {
224 SkSurfaceProps props;
225 if (modelCanvas) { modelCanvas->getProps(&props); }
Hal Canarye107faa2019-10-23 12:52:33 -0400226 SkTextBlobCacheDiffCanvas canvas{1024, 1024, props, fServer.get()};
227 loops *= 100;
228 while (loops --> 0) {
229 for (const auto& record : fTrace) {
230 canvas.drawTextBlob(
231 record.blob.get(), record.offset.x(), record.offset.y(),record.paint);
232 }
233 }
234 }
235
236 void onDelayedSetup() override {
Hal Canary5dfefa22019-10-24 13:52:17 -0400237 auto stream = fDataProvider();
Hal Canarye107faa2019-10-23 12:52:33 -0400238 fDiscardableManager = sk_make_sp<DiscardableManager>();
239 fServer.init(fDiscardableManager.get());
240 fTrace = SkTextBlobTrace::CreateBlobTrace(stream.get());
241 }
242
243public:
Hal Canary5dfefa22019-10-24 13:52:17 -0400244 DiffCanvasBench(SkString n, std::function<std::unique_ptr<SkStreamAsset>()> f)
245 : fBenchName(std::move(n)), fDataProvider(std::move(f)) {}
Hal Canarye107faa2019-10-23 12:52:33 -0400246};
247} // namespace
248
Hal Canary5dfefa22019-10-24 13:52:17 -0400249Benchmark* CreateDiffCanvasBench(
250 SkString name, std::function<std::unique_ptr<SkStreamAsset>()> dataSrc) {
251 return new DiffCanvasBench(std::move(name), std::move(dataSrc));
252}
253
254DEF_BENCH( return CreateDiffCanvasBench(
255 SkString("SkDiffBench-lorem_ipsum"),
256 [](){ return GetResourceAsStream("diff_canvas_traces/lorem_ipsum.trace"); }));