• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #include "include/core/SkBitmap.h"
9 #include "include/core/SkGraphics.h"
10 #include "include/core/SkSurface.h"
11 #include "include/core/SkTextBlob.h"
12 #include "include/gpu/GrDirectContext.h"
13 #include "include/private/SkMutex.h"
14 #include "src/core/SkDraw.h"
15 #include "src/core/SkRemoteGlyphCache.h"
16 #include "src/core/SkScalerCache.h"
17 #include "src/core/SkStrikeCache.h"
18 #include "src/core/SkStrikeSpec.h"
19 #include "src/core/SkSurfacePriv.h"
20 #include "src/core/SkTypeface_remote.h"
21 #include "src/gpu/GrCaps.h"
22 #include "src/gpu/GrDirectContextPriv.h"
23 #include "src/gpu/GrRecordingContextPriv.h"
24 #include "src/gpu/text/GrSDFTControl.h"
25 #include "tests/Test.h"
26 #include "tools/Resources.h"
27 #include "tools/ToolUtils.h"
28 #include "tools/fonts/TestEmptyTypeface.h"
29 
30 class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
31                            public SkStrikeClient::DiscardableHandleManager {
32 public:
DiscardableManager()33     DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
34     ~DiscardableManager() override = default;
35 
36     // Server implementation.
createHandle()37     SkDiscardableHandleId createHandle() override {
38         SkAutoMutexExclusive l(fMutex);
39 
40         // Handles starts as locked.
41         fLockedHandles.add(++fNextHandleId);
42         return fNextHandleId;
43     }
lockHandle(SkDiscardableHandleId id)44     bool lockHandle(SkDiscardableHandleId id) override {
45         SkAutoMutexExclusive l(fMutex);
46 
47         if (id <= fLastDeletedHandleId) return false;
48         fLockedHandles.add(id);
49         return true;
50     }
51 
52     // Client implementation.
deleteHandle(SkDiscardableHandleId id)53     bool deleteHandle(SkDiscardableHandleId id) override {
54         SkAutoMutexExclusive l(fMutex);
55 
56         return id <= fLastDeletedHandleId;
57     }
58 
notifyCacheMiss(SkStrikeClient::CacheMissType type,int fontSize)59     void notifyCacheMiss(SkStrikeClient::CacheMissType type, int fontSize) override {
60         SkAutoMutexExclusive l(fMutex);
61 
62         fCacheMissCount[type]++;
63     }
isHandleDeleted(SkDiscardableHandleId id)64     bool isHandleDeleted(SkDiscardableHandleId id) override {
65         SkAutoMutexExclusive l(fMutex);
66 
67         return id <= fLastDeletedHandleId;
68     }
69 
unlockAll()70     void unlockAll() {
71         SkAutoMutexExclusive l(fMutex);
72 
73         fLockedHandles.reset();
74     }
unlockAndDeleteAll()75     void unlockAndDeleteAll() {
76         SkAutoMutexExclusive l(fMutex);
77 
78         fLockedHandles.reset();
79         fLastDeletedHandleId = fNextHandleId;
80     }
lockedHandles() const81     const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
82         SkAutoMutexExclusive l(fMutex);
83 
84         return fLockedHandles;
85     }
handleCount()86     SkDiscardableHandleId handleCount() {
87         SkAutoMutexExclusive l(fMutex);
88 
89         return fNextHandleId;
90     }
cacheMissCount(uint32_t type)91     int cacheMissCount(uint32_t type) {
92         SkAutoMutexExclusive l(fMutex);
93 
94         return fCacheMissCount[type];
95     }
hasCacheMiss() const96     bool hasCacheMiss() const {
97         SkAutoMutexExclusive l(fMutex);
98 
99         for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
100             if (fCacheMissCount[i] > 0) { return true; }
101         }
102         return false;
103     }
resetCacheMissCounts()104     void resetCacheMissCounts() {
105         SkAutoMutexExclusive l(fMutex);
106         sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
107     }
108 
109 private:
110     // The tests below run in parallel on multiple threads and use the same
111     // process global SkStrikeCache. So the implementation needs to be
112     // thread-safe.
113     mutable SkMutex fMutex;
114 
115     SkDiscardableHandleId fNextHandleId = 0u;
116     SkDiscardableHandleId fLastDeletedHandleId = 0u;
117     SkTHashSet<SkDiscardableHandleId> fLockedHandles;
118     int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
119 };
120 
buildTextBlob(sk_sp<SkTypeface> tf,int glyphCount)121 sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
122     SkFont font;
123     font.setTypeface(tf);
124     font.setHinting(SkFontHinting::kNormal);
125     font.setSize(1u);
126     font.setEdging(SkFont::Edging::kAntiAlias);
127     font.setSubpixel(true);
128 
129     SkTextBlobBuilder builder;
130     SkRect bounds = SkRect::MakeWH(10, 10);
131     const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
132     SkASSERT(runBuffer.utf8text == nullptr);
133     SkASSERT(runBuffer.clusters == nullptr);
134 
135     for (int i = 0; i < glyphCount; i++) {
136         runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
137         runBuffer.pos[i] = SkIntToScalar(i);
138     }
139     return builder.make();
140 }
141 
compare_blobs(const SkBitmap & expected,const SkBitmap & actual,skiatest::Reporter * reporter,int tolerance=0)142 static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
143                           skiatest::Reporter* reporter, int tolerance = 0) {
144     SkASSERT(expected.width() == actual.width());
145     SkASSERT(expected.height() == actual.height());
146     for (int i = 0; i < expected.width(); ++i) {
147         for (int j = 0; j < expected.height(); ++j) {
148             SkColor expectedColor = expected.getColor(i, j);
149             SkColor actualColor = actual.getColor(i, j);
150             if (0 == tolerance) {
151                 REPORTER_ASSERT(reporter, expectedColor == actualColor);
152             } else {
153                 for (int k = 0; k < 4; ++k) {
154                     int expectedChannel = (expectedColor >> (k*8)) & 0xff;
155                     int actualChannel = (actualColor >> (k*8)) & 0xff;
156                     REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
157                 }
158             }
159         }
160     }
161 }
162 
MakeSurface(int width,int height,GrRecordingContext * rContext)163 sk_sp<SkSurface> MakeSurface(int width, int height, GrRecordingContext* rContext) {
164     const SkImageInfo info =
165             SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
166     return SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info);
167 }
168 
FindSurfaceProps(GrRecordingContext * rContext)169 SkSurfaceProps FindSurfaceProps(GrRecordingContext* rContext) {
170     auto surface = MakeSurface(1, 1, rContext);
171     return surface->props();
172 }
173 
RasterBlob(sk_sp<SkTextBlob> blob,int width,int height,const SkPaint & paint,GrRecordingContext * rContext,const SkMatrix * matrix=nullptr,SkScalar x=0)174 SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
175                     GrRecordingContext* rContext, const SkMatrix* matrix = nullptr,
176                     SkScalar x = 0) {
177     auto surface = MakeSurface(width, height, rContext);
178     if (matrix) surface->getCanvas()->concat(*matrix);
179     surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
180     SkBitmap bitmap;
181     bitmap.allocN32Pixels(width, height);
182     surface->readPixels(bitmap, 0, 0);
183     return bitmap;
184 }
185 
DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization,reporter)186 DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
187     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
188     SkStrikeServer server(discardableManager.get());
189     SkStrikeClient client(discardableManager, false);
190 
191     auto server_tf = SkTypeface::MakeDefault();
192     auto tf_data = server.serializeTypeface(server_tf.get());
193 
194     auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
195     REPORTER_ASSERT(reporter, client_tf);
196     REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
197                                       server_tf->uniqueID());
198 
199     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
200     discardableManager->unlockAndDeleteAll();
201 }
202 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization,reporter,ctxInfo)203 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
204     auto dContext = ctxInfo.directContext();
205     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
206     SkStrikeServer server(discardableManager.get());
207     SkStrikeClient client(discardableManager, false);
208     const SkPaint paint;
209 
210     // Server.
211     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
212     auto serverTfData = server.serializeTypeface(serverTf.get());
213 
214     int glyphCount = 10;
215     auto serverBlob = buildTextBlob(serverTf, glyphCount);
216     auto props = FindSurfaceProps(dContext);
217     std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
218             10, 10, props, nullptr, dContext->supportsDistanceFieldText());
219     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
220 
221     std::vector<uint8_t> serverStrikeData;
222     server.writeStrikeData(&serverStrikeData);
223 
224     // Client.
225     auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
226     REPORTER_ASSERT(reporter,
227                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
228     auto clientBlob = buildTextBlob(clientTf, glyphCount);
229 
230     SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, dContext);
231     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, dContext);
232     compare_blobs(expected, actual, reporter);
233     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
234 
235     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
236     discardableManager->unlockAndDeleteAll();
237 }
238 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace,reporter,ctxInfo)239 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
240     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
241     SkStrikeServer server(discardableManager.get());
242     SkStrikeClient client(discardableManager, false);
243 
244     // Server.
245     auto serverTf     = TestEmptyTypeface::Make();
246     auto serverTfData = server.serializeTypeface(serverTf.get());
247     REPORTER_ASSERT(reporter, serverTf->unique());
248 
249     {
250         const SkPaint paint;
251         int glyphCount = 10;
252         auto serverBlob = buildTextBlob(serverTf, glyphCount);
253         const SkSurfaceProps props;
254         std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
255             10, 10, props, nullptr, ctxInfo.directContext()->supportsDistanceFieldText());
256         cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
257         REPORTER_ASSERT(reporter, !serverTf->unique());
258 
259         std::vector<uint8_t> serverStrikeData;
260         server.writeStrikeData(&serverStrikeData);
261     }
262     REPORTER_ASSERT(reporter, serverTf->unique());
263 
264     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
265     discardableManager->unlockAndDeleteAll();
266 }
267 
268 #ifdef SKIA_COMPILE_DM_ALL
DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer,reporter)269 DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
270     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
271     SkStrikeServer server(discardableManager.get());
272     SkStrikeClient client(discardableManager, false);
273 
274     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
275     server.serializeTypeface(serverTf.get());
276     int glyphCount = 10;
277     auto serverBlob = buildTextBlob(serverTf, glyphCount);
278 
279     const SkSurfaceProps props;
280     std::unique_ptr<SkCanvas> cache_diff_canvas =
281             server.makeAnalysisCanvas(10, 10, props, nullptr, true);
282     SkPaint paint;
283     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
284 
285     // The strike from the blob should be locked after it has been drawn on the canvas.
286     REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
287     REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
288 
289     // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
290     // again.
291     std::vector<uint8_t> fontData;
292     server.writeStrikeData(&fontData);
293     discardableManager->unlockAll();
294     REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
295 
296     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
297     REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
298     REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
299 
300     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
301     discardableManager->unlockAndDeleteAll();
302 }
303 #endif
304 
305 #ifdef SKIA_COMPILE_DM_ALL
DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer,reporter)306 DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
307     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
308     SkStrikeServer server(discardableManager.get());
309     SkStrikeClient client(discardableManager, false);
310 
311     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
312     server.serializeTypeface(serverTf.get());
313     int glyphCount = 10;
314     auto serverBlob = buildTextBlob(serverTf, glyphCount);
315 
316     const SkSurfaceProps props;
317     std::unique_ptr<SkCanvas> cache_diff_canvas =
318             server.makeAnalysisCanvas(10, 10, props, nullptr, true);
319     SkPaint paint;
320     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
321     REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
322 
323     // Write the strike data and delete all the handles. Re-analyzing the blob should create new
324     // handles.
325     std::vector<uint8_t> fontData;
326     server.writeStrikeData(&fontData);
327 
328     // Another analysis pass, to ensure that deleting handles after a complete cache hit still
329     // works. This is a regression test for crbug.com/999682.
330     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
331     server.writeStrikeData(&fontData);
332     REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
333 
334     discardableManager->unlockAndDeleteAll();
335     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
336     REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
337 
338     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
339     discardableManager->unlockAndDeleteAll();
340 }
341 #endif
342 
343 #ifdef SKIA_COMPILE_DM_ALL
DEF_TEST(SkRemoteGlyphCache_StrikePinningClient,reporter)344 DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
345     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
346     SkStrikeServer server(discardableManager.get());
347     SkStrikeClient client(discardableManager, false);
348 
349     // Server.
350     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
351     auto serverTfData = server.serializeTypeface(serverTf.get());
352 
353     int glyphCount = 10;
354     auto serverBlob = buildTextBlob(serverTf, glyphCount);
355 
356     const SkSurfaceProps props;
357     std::unique_ptr<SkCanvas> cache_diff_canvas =
358             server.makeAnalysisCanvas(10, 10, props, nullptr, true);
359     SkPaint paint;
360     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
361 
362     std::vector<uint8_t> serverStrikeData;
363     server.writeStrikeData(&serverStrikeData);
364 
365     // Client.
366     REPORTER_ASSERT(reporter,
367                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
368     auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
369 
370     // The cache remains alive until it is pinned in the discardable manager.
371     SkGraphics::PurgeFontCache();
372     REPORTER_ASSERT(reporter, !clientTf->unique());
373 
374     // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
375     // clientTf.
376     discardableManager->unlockAndDeleteAll();
377     SkGraphics::PurgeFontCache();
378     REPORTER_ASSERT(reporter, clientTf->unique());
379 
380     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
381     discardableManager->unlockAndDeleteAll();
382 }
383 #endif
384 
385 #ifdef SKIA_COMPILE_DM_ALL
DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting,reporter)386 DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
387     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
388     SkStrikeServer server(discardableManager.get());
389     SkStrikeClient client(discardableManager, false);
390 
391     // Server.
392     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
393     auto serverTfData = server.serializeTypeface(serverTf.get());
394 
395     int glyphCount = 10;
396     auto serverBlob = buildTextBlob(serverTf, glyphCount);
397 
398     const SkSurfaceProps props;
399     std::unique_ptr<SkCanvas> cache_diff_canvas =
400             server.makeAnalysisCanvas(10, 10, props, nullptr, true);
401     SkPaint paint;
402     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
403 
404     std::vector<uint8_t> serverStrikeData;
405     server.writeStrikeData(&serverStrikeData);
406 
407     // Client.
408     REPORTER_ASSERT(reporter,
409                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
410 
411     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
412     discardableManager->unlockAndDeleteAll();
413 }
414 #endif
415 
DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries,reporter)416 DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
417     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
418     SkStrikeServer server(discardableManager.get());
419     server.setMaxEntriesInDescriptorMapForTesting(1u);
420     SkStrikeClient client(discardableManager, false);
421 
422     {
423         auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
424         int glyphCount = 10;
425         auto serverBlob = buildTextBlob(serverTf, glyphCount);
426 
427         const SkSurfaceProps props;
428         std::unique_ptr<SkCanvas> cache_diff_canvas =
429             server.makeAnalysisCanvas(10, 10, props, nullptr, true);
430         SkPaint paint;
431         REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
432         cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
433         REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
434     }
435 
436     // Serialize to release the lock from the strike server and delete all current
437     // handles.
438     std::vector<uint8_t> fontData;
439     server.writeStrikeData(&fontData);
440     discardableManager->unlockAndDeleteAll();
441 
442     // Use a different typeface. Creating a new strike should evict the previous
443     // one.
444     {
445         auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
446         int glyphCount = 10;
447         auto serverBlob = buildTextBlob(serverTf, glyphCount);
448 
449         const SkSurfaceProps props;
450         std::unique_ptr<SkCanvas> cache_diff_canvas =
451             server.makeAnalysisCanvas(10, 10, props, nullptr, true);
452         SkPaint paint;
453         REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
454         cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
455         REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
456     }
457 
458     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
459     discardableManager->unlockAndDeleteAll();
460 }
461 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath,reporter,ctxInfo)462 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
463     auto direct = ctxInfo.directContext();
464     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
465     SkStrikeServer server(discardableManager.get());
466     SkStrikeClient client(discardableManager, false);
467     SkPaint paint;
468     paint.setStyle(SkPaint::kStroke_Style);
469     paint.setStrokeWidth(0);
470     REPORTER_ASSERT(reporter,
471             SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
472 
473     // Server.
474     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
475     auto serverTfData = server.serializeTypeface(serverTf.get());
476 
477     int glyphCount = 10;
478     auto serverBlob = buildTextBlob(serverTf, glyphCount);
479     auto props = FindSurfaceProps(direct);
480     std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
481             10, 10, props, nullptr, direct->supportsDistanceFieldText());
482     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
483 
484     std::vector<uint8_t> serverStrikeData;
485     server.writeStrikeData(&serverStrikeData);
486 
487     // Client.
488     auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
489     REPORTER_ASSERT(reporter,
490                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
491     auto clientBlob = buildTextBlob(clientTf, glyphCount);
492 
493     SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct);
494     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct);
495     compare_blobs(expected, actual, reporter, 1);
496     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
497 
498     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
499     discardableManager->unlockAndDeleteAll();
500 }
501 
make_blob_causing_fallback(sk_sp<SkTypeface> targetTf,const SkTypeface * glyphTf,skiatest::Reporter * reporter)502 sk_sp<SkTextBlob> make_blob_causing_fallback(
503         sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
504     SkFont font;
505     font.setSubpixel(true);
506     font.setSize(96);
507     font.setHinting(SkFontHinting::kNormal);
508     font.setTypeface(targetTf);
509 
510     REPORTER_ASSERT(reporter,
511             !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
512 
513     char s[] = "Skia";
514     int runSize = strlen(s);
515 
516     SkTextBlobBuilder builder;
517     SkRect bounds = SkRect::MakeIWH(100, 100);
518     const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
519     SkASSERT(runBuffer.utf8text == nullptr);
520     SkASSERT(runBuffer.clusters == nullptr);
521 
522     SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
523                                             runBuffer.glyphs, runSize);
524 
525     SkRect glyphBounds;
526     font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
527 
528     REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
529 
530     for (int i = 0; i < runSize; i++) {
531         runBuffer.pos[i] = i * 10;
532     }
533 
534     return builder.make();
535 }
536 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,reporter,ctxInfo)537 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
538         reporter, ctxInfo) {
539     auto direct = ctxInfo.directContext();
540     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
541     SkStrikeServer server(discardableManager.get());
542     SkStrikeClient client(discardableManager, false);
543 
544     SkPaint paint;
545 
546     auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
547     // TODO: when the cq bots can handle this font remove the check.
548     if (serverTf == nullptr) {
549         return;
550     }
551     auto serverTfData = server.serializeTypeface(serverTf.get());
552 
553     auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
554 
555     auto props = FindSurfaceProps(direct);
556     std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
557             10, 10, props, nullptr, direct->supportsDistanceFieldText());
558     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
559 
560     std::vector<uint8_t> serverStrikeData;
561     server.writeStrikeData(&serverStrikeData);
562 
563     // Client.
564     auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
565     REPORTER_ASSERT(reporter,
566                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
567 
568     auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
569 
570     SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct);
571     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct);
572     compare_blobs(expected, actual, reporter);
573     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
574 
575     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
576     discardableManager->unlockAndDeleteAll();
577 }
578 
579 #if 0
580 // TODO: turn this one when I figure out how to deal with the pixel variance from linear
581 //  interpolation from GPU to GPU.
582 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
583                                    reporter, ctxInfo) {
584     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
585     SkStrikeServer server(discardableManager.get());
586     SkStrikeClient client(discardableManager, false);
587 
588     SkPaint paint;
589 
590     auto serverTf = ToolUtils::planet_typeface();
591     // TODO: when the cq bots can handle this font remove the check.
592     if (serverTf == nullptr) {
593         return;
594     }
595     auto serverTfData = server.serializeTypeface(serverTf.get());
596 
597     auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
598         SkFont font;
599         font.setSubpixel(true);
600         font.setSize(96);
601         font.setHinting(SkFontHinting::kNormal);
602         font.setTypeface(typeface);
603 
604         REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
605 
606         // Mercury to Uranus.
607         SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
608 
609         SkTextBlobBuilder builder;
610         SkRect bounds = SkRect::MakeIWH(100, 100);
611         const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
612         SkASSERT(runBuffer.utf8text == nullptr);
613         SkASSERT(runBuffer.clusters == nullptr);
614 
615         std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
616 
617         for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
618             runBuffer.pos[i] = i * 100;
619         }
620 
621         return builder.make();
622     };
623 
624     auto serverBlob = makeBlob(serverTf);
625 
626     auto props = FindSurfaceProps(ctxInfo.grContext());
627     std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
628             10, 10, props, nullptr, ctxInfo.directContext()->supportsDistanceFieldText());
629     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 400, paint);
630 
631     std::vector<uint8_t> serverStrikeData;
632     server.writeStrikeData(&serverStrikeData);
633 
634     // Client.
635     auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
636     REPORTER_ASSERT(reporter,
637                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
638 
639     auto clientBlob = makeBlob(clientTf);
640 
641     SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
642     SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
643 
644     // Pixel variance can be high because of the atlas placement, and large scaling in the linear
645     // interpolation.
646     compare_blobs(expected, actual, reporter, 36);
647     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
648 
649     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
650     discardableManager->unlockAndDeleteAll();
651 }
652 #endif
653 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY,reporter,ctxInfo)654 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
655     auto direct = ctxInfo.directContext();
656     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
657     SkStrikeServer server(discardableManager.get());
658     SkStrikeClient client(discardableManager, false);
659     SkPaint paint;
660     paint.setAntiAlias(true);
661 
662     // Server.
663     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
664     auto serverTfData = server.serializeTypeface(serverTf.get());
665 
666     int glyphCount = 10;
667     auto serverBlob = buildTextBlob(serverTf, glyphCount);
668     auto props = FindSurfaceProps(direct);
669     std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
670             10, 10, props, nullptr, direct->supportsDistanceFieldText());
671     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0.5, 0, paint);
672 
673     std::vector<uint8_t> serverStrikeData;
674     server.writeStrikeData(&serverStrikeData);
675 
676     // Client.
677     auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
678     REPORTER_ASSERT(reporter,
679                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
680     auto clientBlob = buildTextBlob(clientTf, glyphCount);
681 
682     SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct, nullptr, 0.5);
683     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct, nullptr, 0.5);
684     compare_blobs(expected, actual, reporter);
685     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
686 
687     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
688     discardableManager->unlockAndDeleteAll();
689 }
690 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT,reporter,ctxInfo)691 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
692     auto direct = ctxInfo.directContext();
693     if (!direct->priv().caps()->shaderCaps()->supportsDistanceFieldText()) {
694         return;
695     }
696     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
697     SkStrikeServer server(discardableManager.get());
698     SkStrikeClient client(discardableManager, false);
699     SkPaint paint;
700     SkFont font;
701 
702     // A scale transform forces fallback to dft.
703     SkMatrix matrix = SkMatrix::Scale(16, 16);
704     GrSDFTControl control = direct->priv().asRecordingContext()->priv().getSDFTControl(true);
705     REPORTER_ASSERT(reporter, control.drawingType(font, paint, matrix) == GrSDFTControl::kSDFT);
706 
707     // Server.
708     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
709     auto serverTfData = server.serializeTypeface(serverTf.get());
710 
711     int glyphCount = 10;
712     auto serverBlob = buildTextBlob(serverTf, glyphCount);
713     const SkSurfaceProps props;
714     std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
715             10, 10, props, nullptr, direct->supportsDistanceFieldText());
716     cache_diff_canvas->concat(matrix);
717     cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
718 
719     std::vector<uint8_t> serverStrikeData;
720     server.writeStrikeData(&serverStrikeData);
721 
722     // Client.
723     auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
724     REPORTER_ASSERT(reporter,
725                     client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
726     auto clientBlob = buildTextBlob(clientTf, glyphCount);
727 
728     SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct, &matrix);
729     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct, &matrix);
730     compare_blobs(expected, actual, reporter);
731     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
732 
733     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
734     discardableManager->unlockAndDeleteAll();
735 }
736 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting,reporter,ctxInfo)737 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
738     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
739     SkStrikeServer server(discardableManager.get());
740     SkStrikeClient client(discardableManager, false);
741 
742     auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
743     auto tfData = server.serializeTypeface(serverTf.get());
744     auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
745     REPORTER_ASSERT(reporter, clientTf);
746     int glyphCount = 10;
747     auto clientBlob = buildTextBlob(clientTf, glyphCount);
748 
749     // Raster the client-side blob without the glyph data, we should get cache miss notifications.
750     SkPaint paint;
751     SkMatrix matrix = SkMatrix::I();
752     RasterBlob(clientBlob, 10, 10, paint, ctxInfo.directContext(), &matrix);
753     REPORTER_ASSERT(reporter,
754                     discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
755     REPORTER_ASSERT(reporter,
756                     discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
757 
758     // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
759     // miss.
760     REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
761     REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
762 
763     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
764     discardableManager->unlockAndDeleteAll();
765 }
766 
MakeEmojiBlob(sk_sp<SkTypeface> serverTf,SkScalar textSize,sk_sp<SkTypeface> clientTf=nullptr)767 sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
768                                 sk_sp<SkTypeface> clientTf = nullptr) {
769     SkFont font;
770     font.setTypeface(serverTf);
771     font.setSize(textSize);
772 
773     const char* text = ToolUtils::emoji_sample_text();
774     SkFont serverFont = font;
775     auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
776     if (clientTf == nullptr) return blob;
777 
778     SkSerialProcs s_procs;
779     s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
780         return SkData::MakeUninitialized(1u);
781     };
782     auto serialized = blob->serialize(s_procs);
783 
784     SkDeserialProcs d_procs;
785     d_procs.fTypefaceCtx = &clientTf;
786     d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
787         return *(static_cast<sk_sp<SkTypeface>*>(ctx));
788     };
789     return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
790 }
791 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths,reporter,ctxInfo)792 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
793     auto direct = ctxInfo.directContext();
794     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
795     SkStrikeServer server(discardableManager.get());
796     SkStrikeClient client(discardableManager, false);
797 
798     auto serverTf = ToolUtils::emoji_typeface();
799     auto serverTfData = server.serializeTypeface(serverTf.get());
800     auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
801 
802     auto props = FindSurfaceProps(direct);
803     std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
804             500, 500, props, nullptr, direct->supportsDistanceFieldText());
805     for (SkScalar textSize : { 70, 180, 270, 340}) {
806         auto serverBlob = MakeEmojiBlob(serverTf, textSize);
807 
808         SkPaint paint;
809         cache_diff_canvas->drawTextBlob(serverBlob.get(), 100, 100, paint);
810 
811         std::vector<uint8_t> serverStrikeData;
812         server.writeStrikeData(&serverStrikeData);
813         if (!serverStrikeData.empty()) {
814             REPORTER_ASSERT(reporter,
815                             client.readStrikeData(serverStrikeData.data(),
816                                                   serverStrikeData.size()));
817         }
818         auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
819         REPORTER_ASSERT(reporter, clientBlob);
820 
821         RasterBlob(clientBlob, 500, 500, paint, direct);
822         REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
823         discardableManager->resetCacheMissCounts();
824     }
825 
826     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
827     discardableManager->unlockAndDeleteAll();
828 }
829