blob: ccb549388776fde555bcbfc611adbbecfd2b2c8c [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkGraphics.h"
9#include "include/core/SkSurface.h"
10#include "include/core/SkTextBlob.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040011#include "include/gpu/GrDirectContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/private/SkMutex.h"
13#include "src/core/SkDraw.h"
14#include "src/core/SkRemoteGlyphCache.h"
Herb Derby81e84a62020-02-14 11:47:35 -050015#include "src/core/SkScalerCache.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/core/SkStrikeCache.h"
Herb Derbyd249e8c2019-06-03 11:36:01 -040017#include "src/core/SkStrikeSpec.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/core/SkSurfacePriv.h"
19#include "src/core/SkTypeface_remote.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040020#include "src/gpu/GrContextPriv.h"
21#include "src/gpu/GrRecordingContextPriv.h"
22#include "src/gpu/text/GrSDFTOptions.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "tests/Test.h"
24#include "tools/Resources.h"
25#include "tools/ToolUtils.h"
26#include "tools/fonts/TestEmptyTypeface.h"
Khushal38a08432018-05-02 10:29:37 -070027
28class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
29 public SkStrikeClient::DiscardableHandleManager {
30public:
Khushald4160832018-05-23 18:16:00 -070031 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070032 ~DiscardableManager() override = default;
33
34 // Server implementation.
35 SkDiscardableHandleId createHandle() override {
Herb Derby9b869552019-05-10 12:16:17 -040036 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070037
Khushal38a08432018-05-02 10:29:37 -070038 // Handles starts as locked.
39 fLockedHandles.add(++fNextHandleId);
40 return fNextHandleId;
41 }
42 bool lockHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040043 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070044
Khushal38a08432018-05-02 10:29:37 -070045 if (id <= fLastDeletedHandleId) return false;
46 fLockedHandles.add(id);
47 return true;
48 }
49
50 // Client implementation.
Khushal3de67bd2019-03-15 14:43:15 -070051 bool deleteHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040052 SkAutoMutexExclusive l(fMutex);
Khushal38a08432018-05-02 10:29:37 -070053
Khushal3de67bd2019-03-15 14:43:15 -070054 return id <= fLastDeletedHandleId;
55 }
56
57 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
Herb Derby9b869552019-05-10 12:16:17 -040058 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070059
60 fCacheMissCount[type]++;
61 }
62 bool isHandleDeleted(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040063 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070064
65 return id <= fLastDeletedHandleId;
66 }
67
68 void unlockAll() {
Herb Derby9b869552019-05-10 12:16:17 -040069 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070070
71 fLockedHandles.reset();
72 }
Khushal38a08432018-05-02 10:29:37 -070073 void unlockAndDeleteAll() {
Herb Derby9b869552019-05-10 12:16:17 -040074 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070075
76 fLockedHandles.reset();
Khushal38a08432018-05-02 10:29:37 -070077 fLastDeletedHandleId = fNextHandleId;
78 }
Khushal3de67bd2019-03-15 14:43:15 -070079 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
Herb Derby9b869552019-05-10 12:16:17 -040080 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070081
82 return fLockedHandles;
83 }
84 SkDiscardableHandleId handleCount() {
Herb Derby9b869552019-05-10 12:16:17 -040085 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070086
87 return fNextHandleId;
88 }
89 int cacheMissCount(uint32_t type) {
Herb Derby9b869552019-05-10 12:16:17 -040090 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070091
92 return fCacheMissCount[type];
93 }
Khushalfa8ff092018-06-06 17:46:38 -070094 bool hasCacheMiss() const {
Herb Derby9b869552019-05-10 12:16:17 -040095 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070096
Khushalfa8ff092018-06-06 17:46:38 -070097 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
Hal Canarye107faa2019-10-23 12:52:33 -040098 if (fCacheMissCount[i] > 0) { return true; }
Khushalfa8ff092018-06-06 17:46:38 -070099 }
100 return false;
101 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400102 void resetCacheMissCounts() {
103 SkAutoMutexExclusive l(fMutex);
104 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
105 }
Khushal38a08432018-05-02 10:29:37 -0700106
107private:
Khushal3de67bd2019-03-15 14:43:15 -0700108 // The tests below run in parallel on multiple threads and use the same
109 // process global SkStrikeCache. So the implementation needs to be
110 // thread-safe.
111 mutable SkMutex fMutex;
112
Khushal38a08432018-05-02 10:29:37 -0700113 SkDiscardableHandleId fNextHandleId = 0u;
114 SkDiscardableHandleId fLastDeletedHandleId = 0u;
115 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -0700116 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -0700117};
118
119sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -0500120 SkFont font;
Khushal38a08432018-05-02 10:29:37 -0700121 font.setTypeface(tf);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400122 font.setHinting(SkFontHinting::kNormal);
Mike Reed2ed78202018-11-21 15:10:08 -0500123 font.setSize(1u);
124 font.setEdging(SkFont::Edging::kAntiAlias);
125 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -0700126
127 SkTextBlobBuilder builder;
128 SkRect bounds = SkRect::MakeWH(10, 10);
129 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
130 SkASSERT(runBuffer.utf8text == nullptr);
131 SkASSERT(runBuffer.clusters == nullptr);
132
133 for (int i = 0; i < glyphCount; i++) {
134 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
135 runBuffer.pos[i] = SkIntToScalar(i);
136 }
137 return builder.make();
138}
139
Chris Daltonf9a90a22018-08-28 14:17:55 -0600140static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
141 skiatest::Reporter* reporter, int tolerance = 0) {
142 SkASSERT(expected.width() == actual.width());
143 SkASSERT(expected.height() == actual.height());
144 for (int i = 0; i < expected.width(); ++i) {
145 for (int j = 0; j < expected.height(); ++j) {
146 SkColor expectedColor = expected.getColor(i, j);
147 SkColor actualColor = actual.getColor(i, j);
148 if (0 == tolerance) {
149 REPORTER_ASSERT(reporter, expectedColor == actualColor);
150 } else {
151 for (int k = 0; k < 4; ++k) {
152 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
153 int actualChannel = (actualColor >> (k*8)) & 0xff;
154 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
155 }
156 }
157 }
Khushal51371a42018-05-17 10:41:40 -0700158 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600159}
Khushal51371a42018-05-17 10:41:40 -0700160
Robert Phillipse94b4e12020-07-23 13:54:35 -0400161sk_sp<SkSurface> MakeSurface(int width, int height, GrRecordingContext* rContext) {
Herb Derbyc3415002018-11-08 16:40:26 -0500162 const SkImageInfo info =
163 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
Robert Phillipse94b4e12020-07-23 13:54:35 -0400164 return SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info);
Herb Derbyc3415002018-11-08 16:40:26 -0500165}
166
John Stilesec9b4aa2020-08-07 13:05:14 -0400167SkSurfaceProps FindSurfaceProps(GrRecordingContext* rContext) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400168 auto surface = MakeSurface(1, 1, rContext);
Herb Derbyc3415002018-11-08 16:40:26 -0500169 return surface->props();
170}
171
Ravi Mistrycd21d672018-05-29 21:45:46 +0000172SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Robert Phillipse94b4e12020-07-23 13:54:35 -0400173 GrRecordingContext* rContext, const SkMatrix* matrix = nullptr,
Herb Derby1a9971e2018-07-19 13:41:15 -0400174 SkScalar x = 0) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400175 auto surface = MakeSurface(width, height, rContext);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000176 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400177 surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
Khushal38a08432018-05-02 10:29:37 -0700178 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000179 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700180 surface->readPixels(bitmap, 0, 0);
181 return bitmap;
182}
183
184DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
185 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
186 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400187 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700188
189 auto server_tf = SkTypeface::MakeDefault();
190 auto tf_data = server.serializeTypeface(server_tf.get());
191
192 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
193 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700194 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700195 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700196
197 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
198 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700199}
200
Khushal3e7548c2018-05-23 15:45:01 -0700201DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400202 auto dContext = ctxInfo.directContext();
Khushal38a08432018-05-02 10:29:37 -0700203 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
204 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400205 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700206 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700207
208 // Server.
209 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
210 auto serverTfData = server.serializeTypeface(serverTf.get());
211
212 int glyphCount = 10;
213 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillipse94b4e12020-07-23 13:54:35 -0400214 auto props = FindSurfaceProps(dContext);
Mike Reedf922c782019-02-19 15:46:38 -0500215 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
Robert Phillipse94b4e12020-07-23 13:54:35 -0400216 dContext->supportsDistanceFieldText());
Hal Canarye107faa2019-10-23 12:52:33 -0400217 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
218 {
219 SkDynamicMemoryWStream wStream;
220 server.fCapture.reset(new SkTextBlobTrace::Capture);
221 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
222 server.fCapture->dump(&wStream);
223 std::unique_ptr<SkStreamAsset> stream = wStream.detachAsStream();
224 std::vector<SkTextBlobTrace::Record> trace = SkTextBlobTrace::CreateBlobTrace(stream.get());
225 REPORTER_ASSERT(reporter, trace.size() == 1);
226 }
227 #else
Khushal38a08432018-05-02 10:29:37 -0700228 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Hal Canarye107faa2019-10-23 12:52:33 -0400229 #endif
Khushal38a08432018-05-02 10:29:37 -0700230
231 std::vector<uint8_t> serverStrikeData;
232 server.writeStrikeData(&serverStrikeData);
233
234 // Client.
235 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
236 REPORTER_ASSERT(reporter,
237 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
238 auto clientBlob = buildTextBlob(clientTf, glyphCount);
239
Robert Phillipse94b4e12020-07-23 13:54:35 -0400240 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, dContext);
241 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, dContext);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600242 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700243 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700244
245 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
246 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700247}
248
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400249DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
250 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
251 SkStrikeServer server(discardableManager.get());
252 SkStrikeClient client(discardableManager, false);
253
254 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500255 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400256 auto serverTfData = server.serializeTypeface(serverTf.get());
257 REPORTER_ASSERT(reporter, serverTf->unique());
258
259 {
260 const SkPaint paint;
261 int glyphCount = 10;
262 auto serverBlob = buildTextBlob(serverTf, glyphCount);
263 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400264 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400265 10, 10, props, &server, ctxInfo.directContext()->supportsDistanceFieldText());
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400266 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
267 REPORTER_ASSERT(reporter, !serverTf->unique());
268
269 std::vector<uint8_t> serverStrikeData;
270 server.writeStrikeData(&serverStrikeData);
271 }
272 REPORTER_ASSERT(reporter, serverTf->unique());
273
274 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
275 discardableManager->unlockAndDeleteAll();
276}
277
Khushal38a08432018-05-02 10:29:37 -0700278DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
279 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
280 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400281 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700282
283 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
284 server.serializeTypeface(serverTf.get());
285 int glyphCount = 10;
286 auto serverBlob = buildTextBlob(serverTf, glyphCount);
287
288 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500289 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700290 SkPaint paint;
291 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
292
293 // The strike from the blob should be locked after it has been drawn on the canvas.
294 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
295 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
296
297 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
298 // again.
299 std::vector<uint8_t> fontData;
300 server.writeStrikeData(&fontData);
301 discardableManager->unlockAll();
302 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
303
304 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
305 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
306 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700307
308 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
309 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700310}
311
312DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
313 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
314 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400315 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700316
317 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
318 server.serializeTypeface(serverTf.get());
319 int glyphCount = 10;
320 auto serverBlob = buildTextBlob(serverTf, glyphCount);
321
322 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500323 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700324 SkPaint paint;
325 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
326 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
327
328 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
329 // handles.
330 std::vector<uint8_t> fontData;
331 server.writeStrikeData(&fontData);
Khushal498a9b22019-09-04 16:19:22 -0700332
333 // Another analysis pass, to ensure that deleting handles after a complete cache hit still
334 // works. This is a regression test for crbug.com/999682.
335 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
336 server.writeStrikeData(&fontData);
337 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
338
Khushal38a08432018-05-02 10:29:37 -0700339 discardableManager->unlockAndDeleteAll();
340 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700341 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700342
343 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
344 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700345}
346
347DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
348 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
349 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400350 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700351
352 // Server.
353 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
354 auto serverTfData = server.serializeTypeface(serverTf.get());
355
356 int glyphCount = 10;
357 auto serverBlob = buildTextBlob(serverTf, glyphCount);
358
359 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500360 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700361 SkPaint paint;
362 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
363
364 std::vector<uint8_t> serverStrikeData;
365 server.writeStrikeData(&serverStrikeData);
366
367 // Client.
368 REPORTER_ASSERT(reporter,
369 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
370 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
371
372 // The cache remains alive until it is pinned in the discardable manager.
373 SkGraphics::PurgeFontCache();
374 REPORTER_ASSERT(reporter, !clientTf->unique());
375
376 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
377 // clientTf.
378 discardableManager->unlockAndDeleteAll();
379 SkGraphics::PurgeFontCache();
380 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700381
382 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
383 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700384}
Khushalb2e71272018-05-15 12:59:48 -0700385
386DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
387 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
388 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400389 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700390
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(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500399 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalb2e71272018-05-15 12:59:48 -0700400 SkPaint paint;
401 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
402
403 std::vector<uint8_t> serverStrikeData;
404 server.writeStrikeData(&serverStrikeData);
405
406 // Client.
407 REPORTER_ASSERT(reporter,
408 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Khushal3e7548c2018-05-23 15:45:01 -0700409
410 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
411 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700412}
Khushal51371a42018-05-17 10:41:40 -0700413
Khushalcf33b1b2018-08-29 16:16:25 -0700414DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
415 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
416 SkStrikeServer server(discardableManager.get());
417 server.setMaxEntriesInDescriptorMapForTesting(1u);
418 SkStrikeClient client(discardableManager, false);
419
420 {
421 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
422 int glyphCount = 10;
423 auto serverBlob = buildTextBlob(serverTf, glyphCount);
424
425 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500426 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700427 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400428 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
Khushalcf33b1b2018-08-29 16:16:25 -0700429 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400430 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700431 }
432
433 // Serialize to release the lock from the strike server and delete all current
434 // handles.
435 std::vector<uint8_t> fontData;
436 server.writeStrikeData(&fontData);
437 discardableManager->unlockAndDeleteAll();
438
439 // Use a different typeface. Creating a new strike should evict the previous
440 // one.
441 {
442 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
443 int glyphCount = 10;
444 auto serverBlob = buildTextBlob(serverTf, glyphCount);
445
446 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500447 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700448 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400449 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700450 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400451 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700452 }
453
454 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
455 discardableManager->unlockAndDeleteAll();
456}
457
Khushal3e7548c2018-05-23 15:45:01 -0700458DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400459 auto direct = ctxInfo.directContext();
Khushal51371a42018-05-17 10:41:40 -0700460 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
461 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400462 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700463 SkPaint paint;
464 paint.setStyle(SkPaint::kStroke_Style);
465 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400466 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400467 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700468
469 // Server.
470 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
471 auto serverTfData = server.serializeTypeface(serverTf.get());
472
473 int glyphCount = 10;
474 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillips6d344c32020-07-06 10:56:46 -0400475 auto props = FindSurfaceProps(direct);
herb7022b772019-08-15 22:45:43 -0400476 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400477 10, 10, props, &server, direct->supportsDistanceFieldText());
Khushal51371a42018-05-17 10:41:40 -0700478 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
479
480 std::vector<uint8_t> serverStrikeData;
481 server.writeStrikeData(&serverStrikeData);
482
483 // Client.
484 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
485 REPORTER_ASSERT(reporter,
486 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
487 auto clientBlob = buildTextBlob(clientTf, glyphCount);
488
Robert Phillips6d344c32020-07-06 10:56:46 -0400489 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct);
490 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600491 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700492 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700493
494 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
495 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700496}
Khushal3e7548c2018-05-23 15:45:01 -0700497
Herb Derby8e318fd2018-08-29 11:04:18 -0400498sk_sp<SkTextBlob> make_blob_causing_fallback(
499 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500500 SkFont font;
501 font.setSubpixel(true);
502 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400503 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500504 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400505
Herb Derbyd249e8c2019-06-03 11:36:01 -0400506 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400507 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400508
509 char s[] = "Skia";
510 int runSize = strlen(s);
511
512 SkTextBlobBuilder builder;
513 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500514 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400515 SkASSERT(runBuffer.utf8text == nullptr);
516 SkASSERT(runBuffer.clusters == nullptr);
517
Mike Reed64670cb2019-04-16 11:37:38 -0700518 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
519 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400520
521 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500522 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400523
Herb Derby5fd955e2019-01-16 11:23:29 -0500524 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400525
526 for (int i = 0; i < runSize; i++) {
527 runBuffer.pos[i] = i * 10;
528 }
529
530 return builder.make();
531}
532
533DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
534 reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400535 auto direct = ctxInfo.directContext();
Herb Derby8e318fd2018-08-29 11:04:18 -0400536 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
537 SkStrikeServer server(discardableManager.get());
538 SkStrikeClient client(discardableManager, false);
539
540 SkPaint paint;
541
542 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
543 // TODO: when the cq bots can handle this font remove the check.
544 if (serverTf == nullptr) {
545 return;
546 }
547 auto serverTfData = server.serializeTypeface(serverTf.get());
548
549 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
550
Robert Phillips6d344c32020-07-06 10:56:46 -0400551 auto props = FindSurfaceProps(direct);
herb7022b772019-08-15 22:45:43 -0400552 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400553 10, 10, props, &server, direct->supportsDistanceFieldText());
Herb Derby8e318fd2018-08-29 11:04:18 -0400554 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
555
556 std::vector<uint8_t> serverStrikeData;
557 server.writeStrikeData(&serverStrikeData);
558
559 // Client.
560 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
561 REPORTER_ASSERT(reporter,
562 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
563
564 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
565
Robert Phillips6d344c32020-07-06 10:56:46 -0400566 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct);
567 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct);
Herb Derby8e318fd2018-08-29 11:04:18 -0400568 compare_blobs(expected, actual, reporter);
569 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby8e318fd2018-08-29 11:04:18 -0400570
571 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
572 discardableManager->unlockAndDeleteAll();
573}
574
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400575#if 0
576// TODO: turn this one when I figure out how to deal with the pixel variance from linear
577// interpolation from GPU to GPU.
578DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
579 reporter, ctxInfo) {
580 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
581 SkStrikeServer server(discardableManager.get());
582 SkStrikeClient client(discardableManager, false);
583
584 SkPaint paint;
585
586 auto serverTf = ToolUtils::planet_typeface();
587 // TODO: when the cq bots can handle this font remove the check.
588 if (serverTf == nullptr) {
589 return;
590 }
591 auto serverTfData = server.serializeTypeface(serverTf.get());
592
593 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
594 SkFont font;
595 font.setSubpixel(true);
596 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400597 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400598 font.setTypeface(typeface);
599
600 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
601
602 // Mercury to Uranus.
603 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
604
605 SkTextBlobBuilder builder;
606 SkRect bounds = SkRect::MakeIWH(100, 100);
607 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
608 SkASSERT(runBuffer.utf8text == nullptr);
609 SkASSERT(runBuffer.clusters == nullptr);
610
611 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
612
613 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
614 runBuffer.pos[i] = i * 100;
615 }
616
617 return builder.make();
618 };
619
620 auto serverBlob = makeBlob(serverTf);
621
622 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400623 SkTextBlobCacheDiffCanvas cache_diff_canvas(
624 800, 800, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400625 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
626
627 std::vector<uint8_t> serverStrikeData;
628 server.writeStrikeData(&serverStrikeData);
629
630 // Client.
631 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
632 REPORTER_ASSERT(reporter,
633 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
634
635 auto clientBlob = makeBlob(clientTf);
636
637 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
638 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
639
640 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
641 // interpolation.
642 compare_blobs(expected, actual, reporter, 36);
643 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400644
645 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
646 discardableManager->unlockAndDeleteAll();
647}
648#endif
649
Herb Derby1a9971e2018-07-19 13:41:15 -0400650DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400651 auto direct = ctxInfo.directContext();
Herb Derby1a9971e2018-07-19 13:41:15 -0400652 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
653 SkStrikeServer server(discardableManager.get());
654 SkStrikeClient client(discardableManager, false);
655 SkPaint paint;
656 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400657
658 // Server.
659 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
660 auto serverTfData = server.serializeTypeface(serverTf.get());
661
662 int glyphCount = 10;
663 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillips6d344c32020-07-06 10:56:46 -0400664 auto props = FindSurfaceProps(direct);
herb7022b772019-08-15 22:45:43 -0400665 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400666 10, 10, props, &server, direct->supportsDistanceFieldText());
Herb Derby1a9971e2018-07-19 13:41:15 -0400667 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
668
669 std::vector<uint8_t> serverStrikeData;
670 server.writeStrikeData(&serverStrikeData);
671
672 // Client.
673 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
674 REPORTER_ASSERT(reporter,
675 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
676 auto clientBlob = buildTextBlob(clientTf, glyphCount);
677
Robert Phillips6d344c32020-07-06 10:56:46 -0400678 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct, nullptr, 0.5);
679 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct, nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600680 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400681 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby1a9971e2018-07-19 13:41:15 -0400682
683 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
684 discardableManager->unlockAndDeleteAll();
685}
686
Khushal3e7548c2018-05-23 15:45:01 -0700687DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400688 auto direct = ctxInfo.directContext();
Khushal3e7548c2018-05-23 15:45:01 -0700689 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
690 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400691 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700692 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500693 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700694
Jim Van Verthce3cf802019-10-10 11:06:20 -0400695 // A scale transform forces fallback to dft.
Mike Reed1f607332020-05-21 12:11:27 -0400696 SkMatrix matrix = SkMatrix::Scale(16, 16);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000697 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Robert Phillips6d344c32020-07-06 10:56:46 -0400698 GrSDFTOptions options = direct->priv().asRecordingContext()->priv().SDFTOptions();
Herb Derby45fe2e82020-06-12 14:30:05 -0400699 REPORTER_ASSERT(reporter,
700 options.canDrawAsDistanceFields(paint, font, matrix, surfaceProps, true));
Khushal3e7548c2018-05-23 15:45:01 -0700701
702 // Server.
703 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
704 auto serverTfData = server.serializeTypeface(serverTf.get());
705
706 int glyphCount = 10;
707 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000708 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400709 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400710 10, 10, props, &server, direct->supportsDistanceFieldText());
Khushal3e7548c2018-05-23 15:45:01 -0700711 cache_diff_canvas.concat(matrix);
712 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
713
714 std::vector<uint8_t> serverStrikeData;
715 server.writeStrikeData(&serverStrikeData);
716
717 // Client.
718 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
719 REPORTER_ASSERT(reporter,
720 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
721 auto clientBlob = buildTextBlob(clientTf, glyphCount);
722
Robert Phillips6d344c32020-07-06 10:56:46 -0400723 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct, &matrix);
724 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct, &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600725 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700726 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700727
728 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
729 discardableManager->unlockAndDeleteAll();
730}
Khushald4160832018-05-23 18:16:00 -0700731
732DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
733 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
734 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400735 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700736
737 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
738 auto tfData = server.serializeTypeface(serverTf.get());
739 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
740 REPORTER_ASSERT(reporter, clientTf);
741 int glyphCount = 10;
742 auto clientBlob = buildTextBlob(clientTf, glyphCount);
743
744 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000745 SkPaint paint;
746 SkMatrix matrix = SkMatrix::I();
Robert Phillips6d344c32020-07-06 10:56:46 -0400747 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.directContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700748 REPORTER_ASSERT(reporter,
749 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
750 REPORTER_ASSERT(reporter,
751 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
752
753 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
754 // miss.
755 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
756 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
757
758 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
759 discardableManager->unlockAndDeleteAll();
760}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400761
Herb Derbye384a1e2019-05-21 11:27:40 -0400762sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
763 sk_sp<SkTypeface> clientTf = nullptr) {
764 SkFont font;
765 font.setTypeface(serverTf);
766 font.setSize(textSize);
767
768 const char* text = ToolUtils::emoji_sample_text();
769 SkFont serverFont = font;
770 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
771 if (clientTf == nullptr) return blob;
772
773 SkSerialProcs s_procs;
774 s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
775 return SkData::MakeUninitialized(1u);
776 };
777 auto serialized = blob->serialize(s_procs);
778
779 SkDeserialProcs d_procs;
780 d_procs.fTypefaceCtx = &clientTf;
781 d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
782 return *(static_cast<sk_sp<SkTypeface>*>(ctx));
783 };
784 return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
785}
786
787DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400788 auto direct = ctxInfo.directContext();
Herb Derbye384a1e2019-05-21 11:27:40 -0400789 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
790 SkStrikeServer server(discardableManager.get());
791 SkStrikeClient client(discardableManager, false);
792
793 auto serverTf = ToolUtils::emoji_typeface();
794 auto serverTfData = server.serializeTypeface(serverTf.get());
795 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
796
Mike Reed69aaee02019-05-30 11:40:51 +0000797 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400798 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
Robert Phillips6d344c32020-07-06 10:56:46 -0400799 auto props = FindSurfaceProps(direct);
herb7022b772019-08-15 22:45:43 -0400800 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400801 500, 500, props, &server, direct->supportsDistanceFieldText());
Herb Derbye384a1e2019-05-21 11:27:40 -0400802 SkPaint paint;
Mike Reed69aaee02019-05-30 11:40:51 +0000803 cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400804
805 std::vector<uint8_t> serverStrikeData;
806 server.writeStrikeData(&serverStrikeData);
Herb Derbyf5e9b422019-10-22 16:06:22 -0400807 if (!serverStrikeData.empty()) {
808 REPORTER_ASSERT(reporter,
809 client.readStrikeData(serverStrikeData.data(),
810 serverStrikeData.size()));
811 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400812 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
813 REPORTER_ASSERT(reporter, clientBlob);
814
Robert Phillips6d344c32020-07-06 10:56:46 -0400815 RasterBlob(clientBlob, 500, 500, paint, direct);
Herb Derbye384a1e2019-05-21 11:27:40 -0400816 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbye384a1e2019-05-21 11:27:40 -0400817 discardableManager->resetCacheMissCounts();
818 }
819
820 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
821 discardableManager->unlockAndDeleteAll();
822}
823