blob: c05bda5d4732fea73c5fe4cca078c025fcb29810 [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);
Herb Derby1a9971e2018-07-19 13:41:15 -040072 font.setAntiAlias(true);
73 font.setSubpixelText(true);
Khushal38a08432018-05-02 10:29:37 -070074
75 SkTextBlobBuilder builder;
76 SkRect bounds = SkRect::MakeWH(10, 10);
77 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
78 SkASSERT(runBuffer.utf8text == nullptr);
79 SkASSERT(runBuffer.clusters == nullptr);
80
81 for (int i = 0; i < glyphCount; i++) {
82 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
83 runBuffer.pos[i] = SkIntToScalar(i);
84 }
85 return builder.make();
86}
87
Khushal51371a42018-05-17 10:41:40 -070088#define COMPARE_BLOBS(expected, actual, reporter) \
89 for (int i = 0; i < expected.width(); ++i) { \
90 for (int j = 0; j < expected.height(); ++j) { \
91 REPORTER_ASSERT(reporter, expected.getColor(i, j) == actual.getColor(i, j)); \
92 } \
93 }
94
Khushal3e7548c2018-05-23 15:45:01 -070095SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
96 SkTextBlobCacheDiffCanvas::Settings settings;
97 settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
Khushalfa8ff092018-06-06 17:46:38 -070098 settings.fMaxTextureSize = context->maxTextureSize();
99 settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
Khushal3e7548c2018-05-23 15:45:01 -0700100 return settings;
101}
102
Ravi Mistrycd21d672018-05-29 21:45:46 +0000103SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400104 GrContext* context, const SkMatrix* matrix = nullptr,
105 SkScalar x = 0) {
Ravi Mistrycd21d672018-05-29 21:45:46 +0000106 const SkImageInfo info =
107 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
Khushal3e7548c2018-05-23 15:45:01 -0700108 auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000109 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derby1a9971e2018-07-19 13:41:15 -0400110 surface->getCanvas()->drawTextBlob(blob.get(), x, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700111 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000112 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700113 surface->readPixels(bitmap, 0, 0);
114 return bitmap;
115}
116
117DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
118 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
119 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400120 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700121
122 auto server_tf = SkTypeface::MakeDefault();
123 auto tf_data = server.serializeTypeface(server_tf.get());
124
125 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
126 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700127 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700128 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700129
130 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
131 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700132}
133
Khushal3e7548c2018-05-23 15:45:01 -0700134DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700135 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
136 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400137 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700138 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700139
140 // Server.
141 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
142 auto serverTfData = server.serializeTypeface(serverTf.get());
143
144 int glyphCount = 10;
145 auto serverBlob = buildTextBlob(serverTf, glyphCount);
146 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Khushal3e7548c2018-05-23 15:45:01 -0700147 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
148 MakeSettings(ctxInfo.grContext()));
Khushal38a08432018-05-02 10:29:37 -0700149 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
150
151 std::vector<uint8_t> serverStrikeData;
152 server.writeStrikeData(&serverStrikeData);
153
154 // Client.
155 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
156 REPORTER_ASSERT(reporter,
157 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
158 auto clientBlob = buildTextBlob(clientTf, glyphCount);
159
Ravi Mistrycd21d672018-05-29 21:45:46 +0000160 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
161 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Khushal51371a42018-05-17 10:41:40 -0700162 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700163 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700164
165 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
166 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700167}
168
169DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
170 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
171 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400172 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700173
174 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
175 server.serializeTypeface(serverTf.get());
176 int glyphCount = 10;
177 auto serverBlob = buildTextBlob(serverTf, glyphCount);
178
179 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
180 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
181 SkPaint paint;
182 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
183
184 // The strike from the blob should be locked after it has been drawn on the canvas.
185 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
186 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
187
188 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
189 // again.
190 std::vector<uint8_t> fontData;
191 server.writeStrikeData(&fontData);
192 discardableManager->unlockAll();
193 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
194
195 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
196 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
197 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700198
199 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
200 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700201}
202
203DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
204 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
205 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400206 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700207
208 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
209 server.serializeTypeface(serverTf.get());
210 int glyphCount = 10;
211 auto serverBlob = buildTextBlob(serverTf, glyphCount);
212
213 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
214 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
215 SkPaint paint;
216 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
217 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
218
219 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
220 // handles.
221 std::vector<uint8_t> fontData;
222 server.writeStrikeData(&fontData);
223 discardableManager->unlockAndDeleteAll();
224 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700225 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700226
227 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
228 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700229}
230
231DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
232 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
233 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400234 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700235
236 // Server.
237 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
238 auto serverTfData = server.serializeTypeface(serverTf.get());
239
240 int glyphCount = 10;
241 auto serverBlob = buildTextBlob(serverTf, glyphCount);
242
243 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
244 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
245 SkPaint paint;
246 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
247
248 std::vector<uint8_t> serverStrikeData;
249 server.writeStrikeData(&serverStrikeData);
250
251 // Client.
252 REPORTER_ASSERT(reporter,
253 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
254 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
255
256 // The cache remains alive until it is pinned in the discardable manager.
257 SkGraphics::PurgeFontCache();
258 REPORTER_ASSERT(reporter, !clientTf->unique());
259
260 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
261 // clientTf.
262 discardableManager->unlockAndDeleteAll();
263 SkGraphics::PurgeFontCache();
264 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700265
266 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
267 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700268}
Khushalb2e71272018-05-15 12:59:48 -0700269
270DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
271 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
272 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400273 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700274
275 // Server.
276 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
277 auto serverTfData = server.serializeTypeface(serverTf.get());
278
279 int glyphCount = 10;
280 auto serverBlob = buildTextBlob(serverTf, glyphCount);
281
282 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
283 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
284 SkPaint paint;
285 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
286
287 std::vector<uint8_t> serverStrikeData;
288 server.writeStrikeData(&serverStrikeData);
289
290 // Client.
291 REPORTER_ASSERT(reporter,
292 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Herb Derbyc113e9e2018-06-21 14:06:30 -0400293 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700294
295 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
296 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700297}
Khushal51371a42018-05-17 10:41:40 -0700298
Khushal3e7548c2018-05-23 15:45:01 -0700299DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700300 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
301 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400302 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700303 SkPaint paint;
304 paint.setStyle(SkPaint::kStroke_Style);
305 paint.setStrokeWidth(0);
306 REPORTER_ASSERT(reporter, SkDraw::ShouldDrawTextAsPaths(paint, SkMatrix::I()));
307
308 // Server.
309 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
310 auto serverTfData = server.serializeTypeface(serverTf.get());
311
312 int glyphCount = 10;
313 auto serverBlob = buildTextBlob(serverTf, glyphCount);
314 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Khushal3e7548c2018-05-23 15:45:01 -0700315 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
316 MakeSettings(ctxInfo.grContext()));
Khushal51371a42018-05-17 10:41:40 -0700317 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
318
319 std::vector<uint8_t> serverStrikeData;
320 server.writeStrikeData(&serverStrikeData);
321
322 // Client.
323 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
324 REPORTER_ASSERT(reporter,
325 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
326 auto clientBlob = buildTextBlob(clientTf, glyphCount);
327
Ravi Mistrycd21d672018-05-29 21:45:46 +0000328 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
329 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Khushal51371a42018-05-17 10:41:40 -0700330 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700331 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400332 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700333
334 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
335 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700336}
Khushal3e7548c2018-05-23 15:45:01 -0700337
Herb Derby1a9971e2018-07-19 13:41:15 -0400338DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
339 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
340 SkStrikeServer server(discardableManager.get());
341 SkStrikeClient client(discardableManager, false);
342 SkPaint paint;
343 paint.setAntiAlias(true);
344 paint.setSubpixelText(true);
345 paint.setLCDRenderText(true);
346
347 // Server.
348 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
349 auto serverTfData = server.serializeTypeface(serverTf.get());
350
351 int glyphCount = 10;
352 auto serverBlob = buildTextBlob(serverTf, glyphCount);
353 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
354 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
355 MakeSettings(ctxInfo.grContext()));
356 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
357
358 std::vector<uint8_t> serverStrikeData;
359 server.writeStrikeData(&serverStrikeData);
360
361 // Client.
362 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
363 REPORTER_ASSERT(reporter,
364 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
365 auto clientBlob = buildTextBlob(clientTf, glyphCount);
366
367 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
368 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
369 COMPARE_BLOBS(expected, actual, reporter);
370 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
371 SkStrikeCache::ValidateGlyphCacheDataSize();
372
373 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
374 discardableManager->unlockAndDeleteAll();
375}
376
Khushal3e7548c2018-05-23 15:45:01 -0700377DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
378 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
379 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400380 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700381 SkPaint paint;
382
383 // A perspective transform forces fallback to dft.
384 SkMatrix matrix = SkMatrix::I();
385 matrix[SkMatrix::kMPersp0] = 0.5f;
386 REPORTER_ASSERT(reporter, matrix.hasPerspective());
Ravi Mistrycd21d672018-05-29 21:45:46 +0000387 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400388 GrTextContext::Options options;
389 GrTextContext::SanitizeOptions(&options);
390 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Khushal3e7548c2018-05-23 15:45:01 -0700391 paint, matrix, surfaceProps, true, options));
392
393 // Server.
394 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
395 auto serverTfData = server.serializeTypeface(serverTf.get());
396
397 int glyphCount = 10;
398 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000399 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
400 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
Khushal3e7548c2018-05-23 15:45:01 -0700401 MakeSettings(ctxInfo.grContext()));
402 cache_diff_canvas.concat(matrix);
403 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
404
405 std::vector<uint8_t> serverStrikeData;
406 server.writeStrikeData(&serverStrikeData);
407
408 // Client.
409 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
410 REPORTER_ASSERT(reporter,
411 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
412 auto clientBlob = buildTextBlob(clientTf, glyphCount);
413
Ravi Mistrycd21d672018-05-29 21:45:46 +0000414 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
415 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushal3e7548c2018-05-23 15:45:01 -0700416 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700417 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400418 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700419
420 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
421 discardableManager->unlockAndDeleteAll();
422}
Khushald4160832018-05-23 18:16:00 -0700423
424DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
425 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
426 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400427 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700428
429 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
430 auto tfData = server.serializeTypeface(serverTf.get());
431 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
432 REPORTER_ASSERT(reporter, clientTf);
433 int glyphCount = 10;
434 auto clientBlob = buildTextBlob(clientTf, glyphCount);
435
436 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000437 SkPaint paint;
438 SkMatrix matrix = SkMatrix::I();
439 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700440 REPORTER_ASSERT(reporter,
441 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
442 REPORTER_ASSERT(reporter,
443 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
444
445 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
446 // miss.
447 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
448 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
449
450 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
451 discardableManager->unlockAndDeleteAll();
452}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400453
454DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
Khushal8523b6b2018-06-12 11:26:17 -0700455 // Build proxy typeface on the client for initializing the cache.
456 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
457 SkStrikeServer server(discardableManager.get());
458 SkStrikeClient client(discardableManager, false);
459
460 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
461 auto tfData = server.serializeTypeface(serverTf.get());
462 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
463 REPORTER_ASSERT(reporter, clientTf);
464
Herb Derby65b7bfc2018-06-05 13:32:12 -0400465 SkPaint paint;
466 paint.setAntiAlias(true);
Khushal8523b6b2018-06-12 11:26:17 -0700467 paint.setTypeface(clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400468 paint.setColor(SK_ColorRED);
469
470 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400471 const uint8_t glyphImage[] = {0xFF, 0xFF};
472
Herb Derby5c0c7982018-06-21 15:15:50 -0400473 SkStrikeCache strikeCache;
474
Herb Derby65b7bfc2018-06-05 13:32:12 -0400475 // Build a fallback cache.
476 {
477 SkAutoDescriptor ad;
478 SkScalerContextRec rec;
479 SkScalerContextEffects effects;
480 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
481 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
482 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
483
Herb Derby5c0c7982018-06-21 15:15:50 -0400484 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400485 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
486 glyph->fMaskFormat = SkMask::kA8_Format;
487 glyph->fHeight = 1;
488 glyph->fWidth = 2;
489 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
490 glyph->fImage = (void *)glyphImage;
491 }
492
493 // Make sure we can find the fall back cache.
494 {
495 SkAutoDescriptor ad;
496 SkScalerContextRec rec;
497 SkScalerContextEffects effects;
498 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
499 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
500 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400501 auto testCache = strikeCache.findStrikeExclusive(*desc);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400502 REPORTER_ASSERT(reporter, !(testCache == nullptr));
503 }
504
Khushal8523b6b2018-06-12 11:26:17 -0700505 // Create the target cache.
506 SkExclusiveStrikePtr testCache;
507 SkAutoDescriptor ad;
508 SkScalerContextRec rec;
509 SkScalerContextEffects effects;
510 SkScalerContextFlags flags = SkScalerContextFlags::kNone;
511 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
512 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400513 testCache = strikeCache.findStrikeExclusive(*desc);
Khushal8523b6b2018-06-12 11:26:17 -0700514 REPORTER_ASSERT(reporter, testCache == nullptr);
Herb Derby5c0c7982018-06-21 15:15:50 -0400515 testCache = strikeCache.createStrikeExclusive(*desc,
Khushal8523b6b2018-06-12 11:26:17 -0700516 clientTf->createScalerContext(effects, desc));
Herb Derby5c0c7982018-06-21 15:15:50 -0400517 auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
518 scalerProxy->initCache(testCache.get(), &strikeCache);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400519
Khushal8523b6b2018-06-12 11:26:17 -0700520 // Look for the lost glyph.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400521 {
Khushal8523b6b2018-06-12 11:26:17 -0700522 const auto& lostGlyph = testCache->getGlyphIDMetrics(
523 lostGlyphID.code(), lostGlyphID.getSubXFixed(), lostGlyphID.getSubYFixed());
524 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400525
Herb Derby65b7bfc2018-06-05 13:32:12 -0400526 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
527 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
528 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700529 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400530 }
531
Khushal8523b6b2018-06-12 11:26:17 -0700532 // Look for the lost glyph with a different sub-pix position.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400533 {
Khushal8523b6b2018-06-12 11:26:17 -0700534 const auto& lostGlyph =
535 testCache->getGlyphIDMetrics(lostGlyphID.code(), SK_FixedQuarter, SK_FixedQuarter);
536 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400537
Herb Derby65b7bfc2018-06-05 13:32:12 -0400538 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
539 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
540 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700541 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400542 }
543
Khushal8523b6b2018-06-12 11:26:17 -0700544 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
545 if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
546 i == SkStrikeClient::CacheMissType::kFontMetrics) {
547 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
548 } else {
549 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
550 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400551 }
Herb Derby5c0c7982018-06-21 15:15:50 -0400552 strikeCache.validateGlyphCacheDataSize();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400553
Khushal8523b6b2018-06-12 11:26:17 -0700554 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
555 discardableManager->unlockAndDeleteAll();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400556}
Khushal4010c792018-06-13 09:44:23 -0700557
558DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
559 // Build proxy typeface on the client for initializing the cache.
560 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
561 SkStrikeServer server(discardableManager.get());
562 SkStrikeClient client(discardableManager, false);
563
564 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
565 auto tfData = server.serializeTypeface(serverTf.get());
566 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
567 REPORTER_ASSERT(reporter, clientTf);
568
569 SkPaint paint;
570 paint.setAntiAlias(true);
571 paint.setColor(SK_ColorRED);
572
573 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
574 const uint8_t glyphImage[] = {0xFF, 0xFF};
575 uint32_t realMask;
576 uint32_t fakeMask;
577
Herb Derby5c0c7982018-06-21 15:15:50 -0400578 SkStrikeCache strikeCache;
579
Khushal4010c792018-06-13 09:44:23 -0700580 {
581 SkAutoDescriptor ad;
582 SkScalerContextRec rec;
583 SkScalerContextEffects effects;
584 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
585 paint.setTypeface(serverTf);
586 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
587 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
588
589 auto context = serverTf->createScalerContext(effects, desc, false);
590 SkGlyph glyph;
591 glyph.initWithGlyphID(lostGlyphID);
592 context->getMetrics(&glyph);
593 realMask = glyph.fMaskFormat;
594 REPORTER_ASSERT(reporter, realMask != MASK_FORMAT_UNKNOWN);
595 }
596
597 // Build a fallback cache.
598 {
599 SkAutoDescriptor ad;
600 SkScalerContextRec rec;
601 SkScalerContextEffects effects;
602 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
603 paint.setTypeface(clientTf);
604 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
605 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
606
Herb Derby5c0c7982018-06-21 15:15:50 -0400607 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Khushal4010c792018-06-13 09:44:23 -0700608 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
609 fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
610 glyph->fMaskFormat = fakeMask;
611 glyph->fHeight = 1;
612 glyph->fWidth = 2;
613 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
614 }
615
616 // Send over the real glyph and make sure the client cache stays intact.
617 {
618 SkAutoDescriptor ad;
Khushal4010c792018-06-13 09:44:23 -0700619 SkScalerContextEffects effects;
620 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
621 paint.setTypeface(serverTf);
Khushal1c94a8f2018-07-23 13:40:37 -0700622 auto* cacheState = server.getOrCreateCache(paint, nullptr, nullptr, flags, &effects);
Khushal4010c792018-06-13 09:44:23 -0700623 cacheState->addGlyph(serverTf.get(), effects, lostGlyphID, false);
624
625 std::vector<uint8_t> serverStrikeData;
626 server.writeStrikeData(&serverStrikeData);
627 REPORTER_ASSERT(reporter,
Herb Derby5c0c7982018-06-21 15:15:50 -0400628 client.readStrikeData(
629 serverStrikeData.data(),
630 serverStrikeData.size()));
Khushal4010c792018-06-13 09:44:23 -0700631 }
632
633 {
634 SkAutoDescriptor ad;
635 SkScalerContextRec rec;
636 SkScalerContextEffects effects;
637 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
638 paint.setTypeface(clientTf);
639 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
640 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
641
Herb Derby5c0c7982018-06-21 15:15:50 -0400642 auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
Khushal4010c792018-06-13 09:44:23 -0700643 REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
644 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
645 REPORTER_ASSERT(reporter, glyph->fMaskFormat == fakeMask);
646
647 // Try overriding the image, it should stay the same.
648 REPORTER_ASSERT(reporter,
649 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
650 const uint8_t newGlyphImage[] = {0, 0};
651 fallbackCache->initializeImage(newGlyphImage, glyph->computeImageSize(), glyph);
652 REPORTER_ASSERT(reporter,
653 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
654 }
655
Herb Derby5c0c7982018-06-21 15:15:50 -0400656 strikeCache.validateGlyphCacheDataSize();
Khushal4010c792018-06-13 09:44:23 -0700657
658 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
659 discardableManager->unlockAndDeleteAll();
660}