blob: 60ef272d9889036eb572069e6881dafb34793b31 [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"
Herb Derbyd2fec232018-08-23 18:44:45 -040012#include "SkRemoteGlyphCacheImpl.h"
Khushal38a08432018-05-02 10:29:37 -070013#include "SkStrikeCache.h"
14#include "SkSurface.h"
15#include "SkTextBlob.h"
16#include "SkTypeface_remote.h"
17#include "Test.h"
18
Herb Derby26cbe512018-05-24 14:39:01 -040019#include "text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070020
Khushal38a08432018-05-02 10:29:37 -070021class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
22 public SkStrikeClient::DiscardableHandleManager {
23public:
Khushald4160832018-05-23 18:16:00 -070024 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070025 ~DiscardableManager() override = default;
26
27 // Server implementation.
28 SkDiscardableHandleId createHandle() override {
29 // Handles starts as locked.
30 fLockedHandles.add(++fNextHandleId);
31 return fNextHandleId;
32 }
33 bool lockHandle(SkDiscardableHandleId id) override {
34 if (id <= fLastDeletedHandleId) return false;
35 fLockedHandles.add(id);
36 return true;
37 }
38
39 // Client implementation.
40 bool deleteHandle(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
Khushalfa8ff092018-06-06 17:46:38 -070041 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override { fCacheMissCount[type]++; }
Khushal38a08432018-05-02 10:29:37 -070042
43 void unlockAll() { fLockedHandles.reset(); }
44 void unlockAndDeleteAll() {
45 unlockAll();
46 fLastDeletedHandleId = fNextHandleId;
47 }
48 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; }
49 SkDiscardableHandleId handleCount() { return fNextHandleId; }
Khushal8523b6b2018-06-12 11:26:17 -070050 int cacheMissCount(uint32_t type) { return fCacheMissCount[type]; }
Khushalfa8ff092018-06-06 17:46:38 -070051 bool hasCacheMiss() const {
52 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
53 if (fCacheMissCount[i] > 0) return true;
54 }
55 return false;
56 }
Khushal38a08432018-05-02 10:29:37 -070057
58private:
59 SkDiscardableHandleId fNextHandleId = 0u;
60 SkDiscardableHandleId fLastDeletedHandleId = 0u;
61 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -070062 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -070063};
64
65sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
66 SkPaint font;
67 font.setTypeface(tf);
68 font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
69 font.setTextAlign(SkPaint::kLeft_Align);
70 font.setStyle(SkPaint::kFill_Style);
71 font.setHinting(SkPaint::kNormal_Hinting);
72 font.setTextSize(1u);
Herb Derby1a9971e2018-07-19 13:41:15 -040073 font.setAntiAlias(true);
74 font.setSubpixelText(true);
Khushal38a08432018-05-02 10:29:37 -070075
76 SkTextBlobBuilder builder;
77 SkRect bounds = SkRect::MakeWH(10, 10);
78 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
79 SkASSERT(runBuffer.utf8text == nullptr);
80 SkASSERT(runBuffer.clusters == nullptr);
81
82 for (int i = 0; i < glyphCount; i++) {
83 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
84 runBuffer.pos[i] = SkIntToScalar(i);
85 }
86 return builder.make();
87}
88
Khushal51371a42018-05-17 10:41:40 -070089#define COMPARE_BLOBS(expected, actual, reporter) \
90 for (int i = 0; i < expected.width(); ++i) { \
91 for (int j = 0; j < expected.height(); ++j) { \
92 REPORTER_ASSERT(reporter, expected.getColor(i, j) == actual.getColor(i, j)); \
93 } \
94 }
95
Khushal3e7548c2018-05-23 15:45:01 -070096SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
97 SkTextBlobCacheDiffCanvas::Settings settings;
98 settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
Khushalfa8ff092018-06-06 17:46:38 -070099 settings.fMaxTextureSize = context->maxTextureSize();
100 settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
Khushal3e7548c2018-05-23 15:45:01 -0700101 return settings;
102}
103
Ravi Mistrycd21d672018-05-29 21:45:46 +0000104SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400105 GrContext* context, const SkMatrix* matrix = nullptr,
106 SkScalar x = 0) {
Ravi Mistrycd21d672018-05-29 21:45:46 +0000107 const SkImageInfo info =
108 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
Khushal3e7548c2018-05-23 15:45:01 -0700109 auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000110 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derby1a9971e2018-07-19 13:41:15 -0400111 surface->getCanvas()->drawTextBlob(blob.get(), x, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700112 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000113 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700114 surface->readPixels(bitmap, 0, 0);
115 return bitmap;
116}
117
118DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
119 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
120 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400121 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700122
123 auto server_tf = SkTypeface::MakeDefault();
124 auto tf_data = server.serializeTypeface(server_tf.get());
125
126 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
127 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700128 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700129 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700130
131 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
132 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700133}
134
Khushal3e7548c2018-05-23 15:45:01 -0700135DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700136 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
137 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400138 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700139 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700140
141 // Server.
142 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
143 auto serverTfData = server.serializeTypeface(serverTf.get());
144
145 int glyphCount = 10;
146 auto serverBlob = buildTextBlob(serverTf, glyphCount);
147 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Khushal3e7548c2018-05-23 15:45:01 -0700148 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
149 MakeSettings(ctxInfo.grContext()));
Khushal38a08432018-05-02 10:29:37 -0700150 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
151
152 std::vector<uint8_t> serverStrikeData;
153 server.writeStrikeData(&serverStrikeData);
154
155 // Client.
156 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
157 REPORTER_ASSERT(reporter,
158 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
159 auto clientBlob = buildTextBlob(clientTf, glyphCount);
160
Ravi Mistrycd21d672018-05-29 21:45:46 +0000161 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
162 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Khushal51371a42018-05-17 10:41:40 -0700163 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700164 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700165
166 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
167 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700168}
169
170DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
171 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
172 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400173 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700174
175 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
176 server.serializeTypeface(serverTf.get());
177 int glyphCount = 10;
178 auto serverBlob = buildTextBlob(serverTf, glyphCount);
179
180 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
181 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
182 SkPaint paint;
183 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
184
185 // The strike from the blob should be locked after it has been drawn on the canvas.
186 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
187 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
188
189 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
190 // again.
191 std::vector<uint8_t> fontData;
192 server.writeStrikeData(&fontData);
193 discardableManager->unlockAll();
194 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
195
196 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
197 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
198 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700199
200 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
201 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700202}
203
204DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
205 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
206 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400207 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700208
209 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
210 server.serializeTypeface(serverTf.get());
211 int glyphCount = 10;
212 auto serverBlob = buildTextBlob(serverTf, glyphCount);
213
214 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
215 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
216 SkPaint paint;
217 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
218 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
219
220 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
221 // handles.
222 std::vector<uint8_t> fontData;
223 server.writeStrikeData(&fontData);
224 discardableManager->unlockAndDeleteAll();
225 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700226 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700227
228 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
229 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700230}
231
232DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
233 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
234 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400235 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700236
237 // Server.
238 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
239 auto serverTfData = server.serializeTypeface(serverTf.get());
240
241 int glyphCount = 10;
242 auto serverBlob = buildTextBlob(serverTf, glyphCount);
243
244 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
245 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
246 SkPaint paint;
247 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
248
249 std::vector<uint8_t> serverStrikeData;
250 server.writeStrikeData(&serverStrikeData);
251
252 // Client.
253 REPORTER_ASSERT(reporter,
254 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
255 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
256
257 // The cache remains alive until it is pinned in the discardable manager.
258 SkGraphics::PurgeFontCache();
259 REPORTER_ASSERT(reporter, !clientTf->unique());
260
261 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
262 // clientTf.
263 discardableManager->unlockAndDeleteAll();
264 SkGraphics::PurgeFontCache();
265 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700266
267 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
268 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700269}
Khushalb2e71272018-05-15 12:59:48 -0700270
271DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
272 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
273 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400274 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700275
276 // Server.
277 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
278 auto serverTfData = server.serializeTypeface(serverTf.get());
279
280 int glyphCount = 10;
281 auto serverBlob = buildTextBlob(serverTf, glyphCount);
282
283 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
284 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
285 SkPaint paint;
286 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
287
288 std::vector<uint8_t> serverStrikeData;
289 server.writeStrikeData(&serverStrikeData);
290
291 // Client.
292 REPORTER_ASSERT(reporter,
293 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Herb Derbyc113e9e2018-06-21 14:06:30 -0400294 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700295
296 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
297 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700298}
Khushal51371a42018-05-17 10:41:40 -0700299
Khushal3e7548c2018-05-23 15:45:01 -0700300DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700301 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
302 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400303 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700304 SkPaint paint;
305 paint.setStyle(SkPaint::kStroke_Style);
306 paint.setStrokeWidth(0);
307 REPORTER_ASSERT(reporter, SkDraw::ShouldDrawTextAsPaths(paint, SkMatrix::I()));
308
309 // Server.
310 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
311 auto serverTfData = server.serializeTypeface(serverTf.get());
312
313 int glyphCount = 10;
314 auto serverBlob = buildTextBlob(serverTf, glyphCount);
315 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Khushal3e7548c2018-05-23 15:45:01 -0700316 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
317 MakeSettings(ctxInfo.grContext()));
Khushal51371a42018-05-17 10:41:40 -0700318 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
319
320 std::vector<uint8_t> serverStrikeData;
321 server.writeStrikeData(&serverStrikeData);
322
323 // Client.
324 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
325 REPORTER_ASSERT(reporter,
326 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
327 auto clientBlob = buildTextBlob(clientTf, glyphCount);
328
Ravi Mistrycd21d672018-05-29 21:45:46 +0000329 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
330 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Khushal51371a42018-05-17 10:41:40 -0700331 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700332 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400333 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700334
335 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
336 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700337}
Khushal3e7548c2018-05-23 15:45:01 -0700338
Herb Derby1a9971e2018-07-19 13:41:15 -0400339DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
340 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
341 SkStrikeServer server(discardableManager.get());
342 SkStrikeClient client(discardableManager, false);
343 SkPaint paint;
344 paint.setAntiAlias(true);
345 paint.setSubpixelText(true);
346 paint.setLCDRenderText(true);
347
348 // Server.
349 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
350 auto serverTfData = server.serializeTypeface(serverTf.get());
351
352 int glyphCount = 10;
353 auto serverBlob = buildTextBlob(serverTf, glyphCount);
354 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
355 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
356 MakeSettings(ctxInfo.grContext()));
357 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
358
359 std::vector<uint8_t> serverStrikeData;
360 server.writeStrikeData(&serverStrikeData);
361
362 // Client.
363 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
364 REPORTER_ASSERT(reporter,
365 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
366 auto clientBlob = buildTextBlob(clientTf, glyphCount);
367
368 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
369 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
370 COMPARE_BLOBS(expected, actual, reporter);
371 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
372 SkStrikeCache::ValidateGlyphCacheDataSize();
373
374 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
375 discardableManager->unlockAndDeleteAll();
376}
377
Khushal3e7548c2018-05-23 15:45:01 -0700378DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
379 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
380 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400381 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700382 SkPaint paint;
383
384 // A perspective transform forces fallback to dft.
385 SkMatrix matrix = SkMatrix::I();
386 matrix[SkMatrix::kMPersp0] = 0.5f;
387 REPORTER_ASSERT(reporter, matrix.hasPerspective());
Ravi Mistrycd21d672018-05-29 21:45:46 +0000388 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400389 GrTextContext::Options options;
390 GrTextContext::SanitizeOptions(&options);
391 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Khushal3e7548c2018-05-23 15:45:01 -0700392 paint, matrix, surfaceProps, true, options));
393
394 // Server.
395 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
396 auto serverTfData = server.serializeTypeface(serverTf.get());
397
398 int glyphCount = 10;
399 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000400 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
401 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
Khushal3e7548c2018-05-23 15:45:01 -0700402 MakeSettings(ctxInfo.grContext()));
403 cache_diff_canvas.concat(matrix);
404 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
405
406 std::vector<uint8_t> serverStrikeData;
407 server.writeStrikeData(&serverStrikeData);
408
409 // Client.
410 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
411 REPORTER_ASSERT(reporter,
412 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
413 auto clientBlob = buildTextBlob(clientTf, glyphCount);
414
Ravi Mistrycd21d672018-05-29 21:45:46 +0000415 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
416 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushal3e7548c2018-05-23 15:45:01 -0700417 COMPARE_BLOBS(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700418 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400419 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700420
421 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
422 discardableManager->unlockAndDeleteAll();
423}
Khushald4160832018-05-23 18:16:00 -0700424
425DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
426 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
427 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400428 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700429
430 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
431 auto tfData = server.serializeTypeface(serverTf.get());
432 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
433 REPORTER_ASSERT(reporter, clientTf);
434 int glyphCount = 10;
435 auto clientBlob = buildTextBlob(clientTf, glyphCount);
436
437 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000438 SkPaint paint;
439 SkMatrix matrix = SkMatrix::I();
440 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700441 REPORTER_ASSERT(reporter,
442 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
443 REPORTER_ASSERT(reporter,
444 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
445
446 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
447 // miss.
448 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
449 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
450
451 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
452 discardableManager->unlockAndDeleteAll();
453}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400454
455DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
Khushal8523b6b2018-06-12 11:26:17 -0700456 // Build proxy typeface on the client for initializing the cache.
457 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
458 SkStrikeServer server(discardableManager.get());
459 SkStrikeClient client(discardableManager, false);
460
461 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
462 auto tfData = server.serializeTypeface(serverTf.get());
463 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
464 REPORTER_ASSERT(reporter, clientTf);
465
Herb Derby65b7bfc2018-06-05 13:32:12 -0400466 SkPaint paint;
467 paint.setAntiAlias(true);
Khushal8523b6b2018-06-12 11:26:17 -0700468 paint.setTypeface(clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400469 paint.setColor(SK_ColorRED);
470
471 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400472 const uint8_t glyphImage[] = {0xFF, 0xFF};
473
Herb Derby5c0c7982018-06-21 15:15:50 -0400474 SkStrikeCache strikeCache;
475
Herb Derby65b7bfc2018-06-05 13:32:12 -0400476 // Build a fallback cache.
477 {
478 SkAutoDescriptor ad;
479 SkScalerContextRec rec;
480 SkScalerContextEffects effects;
481 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
482 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
483 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
484
Herb Derby5c0c7982018-06-21 15:15:50 -0400485 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400486 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
487 glyph->fMaskFormat = SkMask::kA8_Format;
488 glyph->fHeight = 1;
489 glyph->fWidth = 2;
490 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
491 glyph->fImage = (void *)glyphImage;
492 }
493
494 // Make sure we can find the fall back cache.
495 {
496 SkAutoDescriptor ad;
497 SkScalerContextRec rec;
498 SkScalerContextEffects effects;
499 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
500 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
501 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400502 auto testCache = strikeCache.findStrikeExclusive(*desc);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400503 REPORTER_ASSERT(reporter, !(testCache == nullptr));
504 }
505
Khushal8523b6b2018-06-12 11:26:17 -0700506 // Create the target cache.
507 SkExclusiveStrikePtr testCache;
508 SkAutoDescriptor ad;
509 SkScalerContextRec rec;
510 SkScalerContextEffects effects;
511 SkScalerContextFlags flags = SkScalerContextFlags::kNone;
512 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
513 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400514 testCache = strikeCache.findStrikeExclusive(*desc);
Khushal8523b6b2018-06-12 11:26:17 -0700515 REPORTER_ASSERT(reporter, testCache == nullptr);
Herb Derby5c0c7982018-06-21 15:15:50 -0400516 testCache = strikeCache.createStrikeExclusive(*desc,
Khushal8523b6b2018-06-12 11:26:17 -0700517 clientTf->createScalerContext(effects, desc));
Herb Derby5c0c7982018-06-21 15:15:50 -0400518 auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
519 scalerProxy->initCache(testCache.get(), &strikeCache);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400520
Khushal8523b6b2018-06-12 11:26:17 -0700521 // Look for the lost glyph.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400522 {
Khushal8523b6b2018-06-12 11:26:17 -0700523 const auto& lostGlyph = testCache->getGlyphIDMetrics(
524 lostGlyphID.code(), lostGlyphID.getSubXFixed(), lostGlyphID.getSubYFixed());
525 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400526
Herb Derby65b7bfc2018-06-05 13:32:12 -0400527 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
528 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
529 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700530 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400531 }
532
Khushal8523b6b2018-06-12 11:26:17 -0700533 // Look for the lost glyph with a different sub-pix position.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400534 {
Khushal8523b6b2018-06-12 11:26:17 -0700535 const auto& lostGlyph =
536 testCache->getGlyphIDMetrics(lostGlyphID.code(), SK_FixedQuarter, SK_FixedQuarter);
537 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400538
Herb Derby65b7bfc2018-06-05 13:32:12 -0400539 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
540 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
541 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700542 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400543 }
544
Khushal8523b6b2018-06-12 11:26:17 -0700545 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
546 if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
547 i == SkStrikeClient::CacheMissType::kFontMetrics) {
548 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
549 } else {
550 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
551 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400552 }
Herb Derby5c0c7982018-06-21 15:15:50 -0400553 strikeCache.validateGlyphCacheDataSize();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400554
Khushal8523b6b2018-06-12 11:26:17 -0700555 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
556 discardableManager->unlockAndDeleteAll();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400557}
Khushal4010c792018-06-13 09:44:23 -0700558
559DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
560 // Build proxy typeface on the client for initializing the cache.
561 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
562 SkStrikeServer server(discardableManager.get());
563 SkStrikeClient client(discardableManager, false);
564
565 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
566 auto tfData = server.serializeTypeface(serverTf.get());
567 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
568 REPORTER_ASSERT(reporter, clientTf);
569
570 SkPaint paint;
571 paint.setAntiAlias(true);
572 paint.setColor(SK_ColorRED);
573
574 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
575 const uint8_t glyphImage[] = {0xFF, 0xFF};
576 uint32_t realMask;
577 uint32_t fakeMask;
578
Herb Derby5c0c7982018-06-21 15:15:50 -0400579 SkStrikeCache strikeCache;
580
Khushal4010c792018-06-13 09:44:23 -0700581 {
582 SkAutoDescriptor ad;
583 SkScalerContextRec rec;
584 SkScalerContextEffects effects;
585 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
586 paint.setTypeface(serverTf);
587 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
588 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
589
590 auto context = serverTf->createScalerContext(effects, desc, false);
591 SkGlyph glyph;
592 glyph.initWithGlyphID(lostGlyphID);
593 context->getMetrics(&glyph);
594 realMask = glyph.fMaskFormat;
595 REPORTER_ASSERT(reporter, realMask != MASK_FORMAT_UNKNOWN);
596 }
597
598 // Build a fallback cache.
599 {
600 SkAutoDescriptor ad;
601 SkScalerContextRec rec;
602 SkScalerContextEffects effects;
603 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
604 paint.setTypeface(clientTf);
605 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
606 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
607
Herb Derby5c0c7982018-06-21 15:15:50 -0400608 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Khushal4010c792018-06-13 09:44:23 -0700609 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
610 fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
611 glyph->fMaskFormat = fakeMask;
612 glyph->fHeight = 1;
613 glyph->fWidth = 2;
614 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
615 }
616
617 // Send over the real glyph and make sure the client cache stays intact.
618 {
619 SkAutoDescriptor ad;
Khushal4010c792018-06-13 09:44:23 -0700620 SkScalerContextEffects effects;
621 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
622 paint.setTypeface(serverTf);
Khushal1c94a8f2018-07-23 13:40:37 -0700623 auto* cacheState = server.getOrCreateCache(paint, nullptr, nullptr, flags, &effects);
Herb Derbyb2c72162018-08-23 16:16:31 -0400624 cacheState->addGlyph(lostGlyphID, false);
Khushal4010c792018-06-13 09:44:23 -0700625
626 std::vector<uint8_t> serverStrikeData;
627 server.writeStrikeData(&serverStrikeData);
628 REPORTER_ASSERT(reporter,
Herb Derby5c0c7982018-06-21 15:15:50 -0400629 client.readStrikeData(
630 serverStrikeData.data(),
631 serverStrikeData.size()));
Khushal4010c792018-06-13 09:44:23 -0700632 }
633
634 {
635 SkAutoDescriptor ad;
636 SkScalerContextRec rec;
637 SkScalerContextEffects effects;
638 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
639 paint.setTypeface(clientTf);
640 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
641 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
642
Herb Derby5c0c7982018-06-21 15:15:50 -0400643 auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
Khushal4010c792018-06-13 09:44:23 -0700644 REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
645 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
646 REPORTER_ASSERT(reporter, glyph->fMaskFormat == fakeMask);
647
648 // Try overriding the image, it should stay the same.
649 REPORTER_ASSERT(reporter,
650 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
651 const uint8_t newGlyphImage[] = {0, 0};
652 fallbackCache->initializeImage(newGlyphImage, glyph->computeImageSize(), glyph);
653 REPORTER_ASSERT(reporter,
654 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
655 }
656
Herb Derby5c0c7982018-06-21 15:15:50 -0400657 strikeCache.validateGlyphCacheDataSize();
Khushal4010c792018-06-13 09:44:23 -0700658
659 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
660 discardableManager->unlockAndDeleteAll();
661}