blob: 8bdfb7af698256fe20b2a54a7e5be11ee76c374c [file] [log] [blame]
Khushal38a08432018-05-02 10:29:37 -07001/*
2 * Copyright 2018 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
Khushal51371a42018-05-17 10:41:40 -07008#include "SkDraw.h"
Khushal38a08432018-05-02 10:29:37 -07009#include "SkGraphics.h"
10#include "SkMutex.h"
11#include "SkRemoteGlyphCache.h"
12#include "SkStrikeCache.h"
13#include "SkSurface.h"
14#include "SkTextBlob.h"
15#include "SkTypeface_remote.h"
16#include "Test.h"
17
Herb Derby26cbe512018-05-24 14:39:01 -040018#include "text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070019
Khushal38a08432018-05-02 10:29:37 -070020class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
21 public SkStrikeClient::DiscardableHandleManager {
22public:
Khushald4160832018-05-23 18:16:00 -070023 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070024 ~DiscardableManager() override = default;
25
26 // Server implementation.
27 SkDiscardableHandleId createHandle() override {
28 // Handles starts as locked.
29 fLockedHandles.add(++fNextHandleId);
30 return fNextHandleId;
31 }
32 bool lockHandle(SkDiscardableHandleId id) override {
33 if (id <= fLastDeletedHandleId) return false;
34 fLockedHandles.add(id);
35 return true;
36 }
37
38 // Client implementation.
39 bool deleteHandle(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
Khushalfa8ff092018-06-06 17:46:38 -070040 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override { fCacheMissCount[type]++; }
Khushal38a08432018-05-02 10:29:37 -070041
42 void unlockAll() { fLockedHandles.reset(); }
43 void unlockAndDeleteAll() {
44 unlockAll();
45 fLastDeletedHandleId = fNextHandleId;
46 }
47 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; }
48 SkDiscardableHandleId handleCount() { return fNextHandleId; }
Khushal8523b6b2018-06-12 11:26:17 -070049 int cacheMissCount(uint32_t type) { return fCacheMissCount[type]; }
Khushalfa8ff092018-06-06 17:46:38 -070050 bool hasCacheMiss() const {
51 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
52 if (fCacheMissCount[i] > 0) return true;
53 }
54 return false;
55 }
Khushal38a08432018-05-02 10:29:37 -070056
57private:
58 SkDiscardableHandleId fNextHandleId = 0u;
59 SkDiscardableHandleId fLastDeletedHandleId = 0u;
60 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -070061 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -070062};
63
64sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
65 SkPaint font;
66 font.setTypeface(tf);
67 font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
68 font.setTextAlign(SkPaint::kLeft_Align);
69 font.setStyle(SkPaint::kFill_Style);
70 font.setHinting(SkPaint::kNormal_Hinting);
71 font.setTextSize(1u);
72
73 SkTextBlobBuilder builder;
74 SkRect bounds = SkRect::MakeWH(10, 10);
75 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
76 SkASSERT(runBuffer.utf8text == nullptr);
77 SkASSERT(runBuffer.clusters == nullptr);
78
79 for (int i = 0; i < glyphCount; i++) {
80 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
81 runBuffer.pos[i] = SkIntToScalar(i);
82 }
83 return builder.make();
84}
85
Khushal51371a42018-05-17 10:41:40 -070086#define COMPARE_BLOBS(expected, actual, reporter) \
87 for (int i = 0; i < expected.width(); ++i) { \
88 for (int j = 0; j < expected.height(); ++j) { \
89 REPORTER_ASSERT(reporter, expected.getColor(i, j) == actual.getColor(i, j)); \
90 } \
91 }
92
Khushal3e7548c2018-05-23 15:45:01 -070093SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
94 SkTextBlobCacheDiffCanvas::Settings settings;
95 settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
Khushalfa8ff092018-06-06 17:46:38 -070096 settings.fMaxTextureSize = context->maxTextureSize();
97 settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
Khushal3e7548c2018-05-23 15:45:01 -070098 return settings;
99}
100
Ravi Mistrycd21d672018-05-29 21:45:46 +0000101SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
102 GrContext* context, const SkMatrix* matrix = nullptr) {
103 const SkImageInfo info =
104 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
Khushal3e7548c2018-05-23 15:45:01 -0700105 auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000106 if (matrix) surface->getCanvas()->concat(*matrix);
107 surface->getCanvas()->drawTextBlob(blob.get(), 0u, 0u, paint);
Khushal38a08432018-05-02 10:29:37 -0700108 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000109 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700110 surface->readPixels(bitmap, 0, 0);
111 return bitmap;
112}
113
114DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
115 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
116 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400117 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700118
119 auto server_tf = SkTypeface::MakeDefault();
120 auto tf_data = server.serializeTypeface(server_tf.get());
121
122 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
123 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700124 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700125 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700126
127 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
128 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700129}
130
Khushal3e7548c2018-05-23 15:45:01 -0700131DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700132 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
133 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400134 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700135 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700136
137 // Server.
138 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
139 auto serverTfData = server.serializeTypeface(serverTf.get());
140
141 int glyphCount = 10;
142 auto serverBlob = buildTextBlob(serverTf, glyphCount);
143 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Khushal3e7548c2018-05-23 15:45:01 -0700144 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
145 MakeSettings(ctxInfo.grContext()));
Khushal38a08432018-05-02 10:29:37 -0700146 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
147
148 std::vector<uint8_t> serverStrikeData;
149 server.writeStrikeData(&serverStrikeData);
150
151 // Client.
152 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
153 REPORTER_ASSERT(reporter,
154 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
155 auto clientBlob = buildTextBlob(clientTf, glyphCount);
156
Ravi Mistrycd21d672018-05-29 21:45:46 +0000157 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
158 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Khushal51371a42018-05-17 10:41:40 -0700159 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700160 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700161
162 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
163 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700164}
165
166DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
167 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
168 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400169 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700170
171 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
172 server.serializeTypeface(serverTf.get());
173 int glyphCount = 10;
174 auto serverBlob = buildTextBlob(serverTf, glyphCount);
175
176 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
177 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
178 SkPaint paint;
179 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
180
181 // The strike from the blob should be locked after it has been drawn on the canvas.
182 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
183 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
184
185 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
186 // again.
187 std::vector<uint8_t> fontData;
188 server.writeStrikeData(&fontData);
189 discardableManager->unlockAll();
190 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
191
192 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
193 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
194 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700195
196 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
197 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700198}
199
200DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
201 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
202 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400203 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700204
205 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
206 server.serializeTypeface(serverTf.get());
207 int glyphCount = 10;
208 auto serverBlob = buildTextBlob(serverTf, glyphCount);
209
210 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
211 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
212 SkPaint paint;
213 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
214 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
215
216 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
217 // handles.
218 std::vector<uint8_t> fontData;
219 server.writeStrikeData(&fontData);
220 discardableManager->unlockAndDeleteAll();
221 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700222 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700223
224 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
225 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700226}
227
228DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
229 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
230 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400231 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700232
233 // Server.
234 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
235 auto serverTfData = server.serializeTypeface(serverTf.get());
236
237 int glyphCount = 10;
238 auto serverBlob = buildTextBlob(serverTf, glyphCount);
239
240 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
241 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
242 SkPaint paint;
243 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
244
245 std::vector<uint8_t> serverStrikeData;
246 server.writeStrikeData(&serverStrikeData);
247
248 // Client.
249 REPORTER_ASSERT(reporter,
250 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
251 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
252
253 // The cache remains alive until it is pinned in the discardable manager.
254 SkGraphics::PurgeFontCache();
255 REPORTER_ASSERT(reporter, !clientTf->unique());
256
257 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
258 // clientTf.
259 discardableManager->unlockAndDeleteAll();
260 SkGraphics::PurgeFontCache();
261 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700262
263 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
264 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700265}
Khushalb2e71272018-05-15 12:59:48 -0700266
267DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
268 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
269 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400270 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700271
272 // Server.
273 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
274 auto serverTfData = server.serializeTypeface(serverTf.get());
275
276 int glyphCount = 10;
277 auto serverBlob = buildTextBlob(serverTf, glyphCount);
278
279 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
280 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
281 SkPaint paint;
282 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
283
284 std::vector<uint8_t> serverStrikeData;
285 server.writeStrikeData(&serverStrikeData);
286
287 // Client.
288 REPORTER_ASSERT(reporter,
289 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
290 SkStrikeCache::Validate();
Khushal3e7548c2018-05-23 15:45:01 -0700291
292 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
293 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700294}
Khushal51371a42018-05-17 10:41:40 -0700295
Khushal3e7548c2018-05-23 15:45:01 -0700296DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700297 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
298 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400299 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700300 SkPaint paint;
301 paint.setStyle(SkPaint::kStroke_Style);
302 paint.setStrokeWidth(0);
303 REPORTER_ASSERT(reporter, SkDraw::ShouldDrawTextAsPaths(paint, SkMatrix::I()));
304
305 // Server.
306 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
307 auto serverTfData = server.serializeTypeface(serverTf.get());
308
309 int glyphCount = 10;
310 auto serverBlob = buildTextBlob(serverTf, glyphCount);
311 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Khushal3e7548c2018-05-23 15:45:01 -0700312 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
313 MakeSettings(ctxInfo.grContext()));
Khushal51371a42018-05-17 10:41:40 -0700314 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
315
316 std::vector<uint8_t> serverStrikeData;
317 server.writeStrikeData(&serverStrikeData);
318
319 // Client.
320 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
321 REPORTER_ASSERT(reporter,
322 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
323 auto clientBlob = buildTextBlob(clientTf, glyphCount);
324
Ravi Mistrycd21d672018-05-29 21:45:46 +0000325 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
326 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Khushal51371a42018-05-17 10:41:40 -0700327 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700328 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal51371a42018-05-17 10:41:40 -0700329 SkStrikeCache::Validate();
Khushal3e7548c2018-05-23 15:45:01 -0700330
331 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
332 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700333}
Khushal3e7548c2018-05-23 15:45:01 -0700334
Khushal3e7548c2018-05-23 15:45:01 -0700335DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
336 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
337 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400338 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700339 SkPaint paint;
340
341 // A perspective transform forces fallback to dft.
342 SkMatrix matrix = SkMatrix::I();
343 matrix[SkMatrix::kMPersp0] = 0.5f;
344 REPORTER_ASSERT(reporter, matrix.hasPerspective());
Ravi Mistrycd21d672018-05-29 21:45:46 +0000345 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400346 GrTextContext::Options options;
347 GrTextContext::SanitizeOptions(&options);
348 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Khushal3e7548c2018-05-23 15:45:01 -0700349 paint, matrix, surfaceProps, true, options));
350
351 // Server.
352 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
353 auto serverTfData = server.serializeTypeface(serverTf.get());
354
355 int glyphCount = 10;
356 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000357 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
358 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
Khushal3e7548c2018-05-23 15:45:01 -0700359 MakeSettings(ctxInfo.grContext()));
360 cache_diff_canvas.concat(matrix);
361 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
362
363 std::vector<uint8_t> serverStrikeData;
364 server.writeStrikeData(&serverStrikeData);
365
366 // Client.
367 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
368 REPORTER_ASSERT(reporter,
369 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
370 auto clientBlob = buildTextBlob(clientTf, glyphCount);
371
Ravi Mistrycd21d672018-05-29 21:45:46 +0000372 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
373 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushal3e7548c2018-05-23 15:45:01 -0700374 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700375 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700376 SkStrikeCache::Validate();
377
378 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
379 discardableManager->unlockAndDeleteAll();
380}
Khushald4160832018-05-23 18:16:00 -0700381
382DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
383 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
384 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400385 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700386
387 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
388 auto tfData = server.serializeTypeface(serverTf.get());
389 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
390 REPORTER_ASSERT(reporter, clientTf);
391 int glyphCount = 10;
392 auto clientBlob = buildTextBlob(clientTf, glyphCount);
393
394 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000395 SkPaint paint;
396 SkMatrix matrix = SkMatrix::I();
397 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700398 REPORTER_ASSERT(reporter,
399 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
400 REPORTER_ASSERT(reporter,
401 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
402
403 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
404 // miss.
405 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
406 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
407
408 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
409 discardableManager->unlockAndDeleteAll();
410}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400411
412DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
Khushal8523b6b2018-06-12 11:26:17 -0700413 // Build proxy typeface on the client for initializing the cache.
414 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
415 SkStrikeServer server(discardableManager.get());
416 SkStrikeClient client(discardableManager, false);
417
418 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
419 auto tfData = server.serializeTypeface(serverTf.get());
420 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
421 REPORTER_ASSERT(reporter, clientTf);
422
Herb Derby65b7bfc2018-06-05 13:32:12 -0400423 SkPaint paint;
424 paint.setAntiAlias(true);
Khushal8523b6b2018-06-12 11:26:17 -0700425 paint.setTypeface(clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400426 paint.setColor(SK_ColorRED);
427
428 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400429 const uint8_t glyphImage[] = {0xFF, 0xFF};
430
431 // Build a fallback cache.
432 {
433 SkAutoDescriptor ad;
434 SkScalerContextRec rec;
435 SkScalerContextEffects effects;
436 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
437 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
438 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
439
Khushal8523b6b2018-06-12 11:26:17 -0700440 auto fallbackCache = SkStrikeCache::FindOrCreateStrikeExclusive(*desc, effects, *clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400441 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
442 glyph->fMaskFormat = SkMask::kA8_Format;
443 glyph->fHeight = 1;
444 glyph->fWidth = 2;
445 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
446 glyph->fImage = (void *)glyphImage;
447 }
448
449 // Make sure we can find the fall back cache.
450 {
451 SkAutoDescriptor ad;
452 SkScalerContextRec rec;
453 SkScalerContextEffects effects;
454 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
455 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
456 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
457 auto testCache = SkStrikeCache::FindStrikeExclusive(*desc);
458 REPORTER_ASSERT(reporter, !(testCache == nullptr));
459 }
460
Khushal8523b6b2018-06-12 11:26:17 -0700461 // Create the target cache.
462 SkExclusiveStrikePtr testCache;
463 SkAutoDescriptor ad;
464 SkScalerContextRec rec;
465 SkScalerContextEffects effects;
466 SkScalerContextFlags flags = SkScalerContextFlags::kNone;
467 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
468 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
469 testCache = SkStrikeCache::FindStrikeExclusive(*desc);
470 REPORTER_ASSERT(reporter, testCache == nullptr);
471 testCache = SkStrikeCache::CreateStrikeExclusive(*desc,
472 clientTf->createScalerContext(effects, desc));
473 static_cast<SkScalerContextProxy*>(testCache->getScalerContext())->initCache(testCache.get());
Herb Derby65b7bfc2018-06-05 13:32:12 -0400474
Khushal8523b6b2018-06-12 11:26:17 -0700475 // Look for the lost glyph.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400476 {
Khushal8523b6b2018-06-12 11:26:17 -0700477 const auto& lostGlyph = testCache->getGlyphIDMetrics(
478 lostGlyphID.code(), lostGlyphID.getSubXFixed(), lostGlyphID.getSubYFixed());
479 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400480
Herb Derby65b7bfc2018-06-05 13:32:12 -0400481 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
482 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
483 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700484 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400485 }
486
Khushal8523b6b2018-06-12 11:26:17 -0700487 // Look for the lost glyph with a different sub-pix position.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400488 {
Khushal8523b6b2018-06-12 11:26:17 -0700489 const auto& lostGlyph =
490 testCache->getGlyphIDMetrics(lostGlyphID.code(), SK_FixedQuarter, SK_FixedQuarter);
491 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400492
Herb Derby65b7bfc2018-06-05 13:32:12 -0400493 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
494 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
495 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700496 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400497 }
498
Khushal8523b6b2018-06-12 11:26:17 -0700499 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
500 if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
501 i == SkStrikeClient::CacheMissType::kFontMetrics) {
502 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
503 } else {
504 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
505 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400506 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400507 SkStrikeCache::Validate();
508
Khushal8523b6b2018-06-12 11:26:17 -0700509 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
510 discardableManager->unlockAndDeleteAll();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400511}
Khushal4010c792018-06-13 09:44:23 -0700512
513DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
514 // Build proxy typeface on the client for initializing the cache.
515 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
516 SkStrikeServer server(discardableManager.get());
517 SkStrikeClient client(discardableManager, false);
518
519 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
520 auto tfData = server.serializeTypeface(serverTf.get());
521 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
522 REPORTER_ASSERT(reporter, clientTf);
523
524 SkPaint paint;
525 paint.setAntiAlias(true);
526 paint.setColor(SK_ColorRED);
527
528 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
529 const uint8_t glyphImage[] = {0xFF, 0xFF};
530 uint32_t realMask;
531 uint32_t fakeMask;
532
533 {
534 SkAutoDescriptor ad;
535 SkScalerContextRec rec;
536 SkScalerContextEffects effects;
537 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
538 paint.setTypeface(serverTf);
539 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
540 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
541
542 auto context = serverTf->createScalerContext(effects, desc, false);
543 SkGlyph glyph;
544 glyph.initWithGlyphID(lostGlyphID);
545 context->getMetrics(&glyph);
546 realMask = glyph.fMaskFormat;
547 REPORTER_ASSERT(reporter, realMask != MASK_FORMAT_UNKNOWN);
548 }
549
550 // Build a fallback cache.
551 {
552 SkAutoDescriptor ad;
553 SkScalerContextRec rec;
554 SkScalerContextEffects effects;
555 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
556 paint.setTypeface(clientTf);
557 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
558 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
559
560 auto fallbackCache = SkStrikeCache::FindOrCreateStrikeExclusive(*desc, effects, *clientTf);
561 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
562 fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
563 glyph->fMaskFormat = fakeMask;
564 glyph->fHeight = 1;
565 glyph->fWidth = 2;
566 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
567 }
568
569 // Send over the real glyph and make sure the client cache stays intact.
570 {
571 SkAutoDescriptor ad;
572 SkScalerContextRec rec;
573 SkScalerContextEffects effects;
574 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
575 paint.setTypeface(serverTf);
576 auto* cacheState = server.getOrCreateCache(paint, nullptr, nullptr, flags, &rec, &effects);
577 cacheState->addGlyph(serverTf.get(), effects, lostGlyphID, false);
578
579 std::vector<uint8_t> serverStrikeData;
580 server.writeStrikeData(&serverStrikeData);
581 REPORTER_ASSERT(reporter,
582 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
583 }
584
585 {
586 SkAutoDescriptor ad;
587 SkScalerContextRec rec;
588 SkScalerContextEffects effects;
589 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
590 paint.setTypeface(clientTf);
591 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
592 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
593
594 auto fallbackCache = SkStrikeCache::FindStrikeExclusive(*desc);
595 REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
596 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
597 REPORTER_ASSERT(reporter, glyph->fMaskFormat == fakeMask);
598
599 // Try overriding the image, it should stay the same.
600 REPORTER_ASSERT(reporter,
601 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
602 const uint8_t newGlyphImage[] = {0, 0};
603 fallbackCache->initializeImage(newGlyphImage, glyph->computeImageSize(), glyph);
604 REPORTER_ASSERT(reporter,
605 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
606 }
607
608 SkStrikeCache::Validate();
609
610 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
611 discardableManager->unlockAndDeleteAll();
612}