blob: fd327e8624180601759203c6f7262090a6cac35d [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"
11#include "include/private/SkMutex.h"
12#include "src/core/SkDraw.h"
13#include "src/core/SkRemoteGlyphCache.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/core/SkStrike.h"
15#include "src/core/SkStrikeCache.h"
Herb Derbyd249e8c2019-06-03 11:36:01 -040016#include "src/core/SkStrikeSpec.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/core/SkSurfacePriv.h"
18#include "src/core/SkTypeface_remote.h"
19#include "tests/Test.h"
20#include "tools/Resources.h"
21#include "tools/ToolUtils.h"
22#include "tools/fonts/TestEmptyTypeface.h"
Khushal38a08432018-05-02 10:29:37 -070023
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070025
Khushal38a08432018-05-02 10:29:37 -070026class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
27 public SkStrikeClient::DiscardableHandleManager {
28public:
Khushald4160832018-05-23 18:16:00 -070029 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070030 ~DiscardableManager() override = default;
31
32 // Server implementation.
33 SkDiscardableHandleId createHandle() override {
Herb Derby9b869552019-05-10 12:16:17 -040034 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070035
Khushal38a08432018-05-02 10:29:37 -070036 // Handles starts as locked.
37 fLockedHandles.add(++fNextHandleId);
38 return fNextHandleId;
39 }
40 bool lockHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040041 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070042
Khushal38a08432018-05-02 10:29:37 -070043 if (id <= fLastDeletedHandleId) return false;
44 fLockedHandles.add(id);
45 return true;
46 }
47
48 // Client implementation.
Khushal3de67bd2019-03-15 14:43:15 -070049 bool deleteHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040050 SkAutoMutexExclusive l(fMutex);
Khushal38a08432018-05-02 10:29:37 -070051
Khushal3de67bd2019-03-15 14:43:15 -070052 return id <= fLastDeletedHandleId;
53 }
54
55 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
Herb Derby9b869552019-05-10 12:16:17 -040056 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070057
58 fCacheMissCount[type]++;
59 }
60 bool isHandleDeleted(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040061 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070062
63 return id <= fLastDeletedHandleId;
64 }
65
66 void unlockAll() {
Herb Derby9b869552019-05-10 12:16:17 -040067 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070068
69 fLockedHandles.reset();
70 }
Khushal38a08432018-05-02 10:29:37 -070071 void unlockAndDeleteAll() {
Herb Derby9b869552019-05-10 12:16:17 -040072 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070073
74 fLockedHandles.reset();
Khushal38a08432018-05-02 10:29:37 -070075 fLastDeletedHandleId = fNextHandleId;
76 }
Khushal3de67bd2019-03-15 14:43:15 -070077 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
Herb Derby9b869552019-05-10 12:16:17 -040078 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070079
80 return fLockedHandles;
81 }
82 SkDiscardableHandleId handleCount() {
Herb Derby9b869552019-05-10 12:16:17 -040083 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070084
85 return fNextHandleId;
86 }
87 int cacheMissCount(uint32_t type) {
Herb Derby9b869552019-05-10 12:16:17 -040088 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070089
90 return fCacheMissCount[type];
91 }
Khushalfa8ff092018-06-06 17:46:38 -070092 bool hasCacheMiss() const {
Herb Derby9b869552019-05-10 12:16:17 -040093 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070094
Khushalfa8ff092018-06-06 17:46:38 -070095 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
Hal Canarye107faa2019-10-23 12:52:33 -040096 if (fCacheMissCount[i] > 0) { return true; }
Khushalfa8ff092018-06-06 17:46:38 -070097 }
98 return false;
99 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400100 void resetCacheMissCounts() {
101 SkAutoMutexExclusive l(fMutex);
102 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
103 }
Khushal38a08432018-05-02 10:29:37 -0700104
105private:
Khushal3de67bd2019-03-15 14:43:15 -0700106 // The tests below run in parallel on multiple threads and use the same
107 // process global SkStrikeCache. So the implementation needs to be
108 // thread-safe.
109 mutable SkMutex fMutex;
110
Khushal38a08432018-05-02 10:29:37 -0700111 SkDiscardableHandleId fNextHandleId = 0u;
112 SkDiscardableHandleId fLastDeletedHandleId = 0u;
113 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -0700114 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -0700115};
116
117sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -0500118 SkFont font;
Khushal38a08432018-05-02 10:29:37 -0700119 font.setTypeface(tf);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400120 font.setHinting(SkFontHinting::kNormal);
Mike Reed2ed78202018-11-21 15:10:08 -0500121 font.setSize(1u);
122 font.setEdging(SkFont::Edging::kAntiAlias);
123 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -0700124
125 SkTextBlobBuilder builder;
126 SkRect bounds = SkRect::MakeWH(10, 10);
127 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
128 SkASSERT(runBuffer.utf8text == nullptr);
129 SkASSERT(runBuffer.clusters == nullptr);
130
131 for (int i = 0; i < glyphCount; i++) {
132 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
133 runBuffer.pos[i] = SkIntToScalar(i);
134 }
135 return builder.make();
136}
137
Chris Daltonf9a90a22018-08-28 14:17:55 -0600138static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
139 skiatest::Reporter* reporter, int tolerance = 0) {
140 SkASSERT(expected.width() == actual.width());
141 SkASSERT(expected.height() == actual.height());
142 for (int i = 0; i < expected.width(); ++i) {
143 for (int j = 0; j < expected.height(); ++j) {
144 SkColor expectedColor = expected.getColor(i, j);
145 SkColor actualColor = actual.getColor(i, j);
146 if (0 == tolerance) {
147 REPORTER_ASSERT(reporter, expectedColor == actualColor);
148 } else {
149 for (int k = 0; k < 4; ++k) {
150 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
151 int actualChannel = (actualColor >> (k*8)) & 0xff;
152 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
153 }
154 }
155 }
Khushal51371a42018-05-17 10:41:40 -0700156 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600157}
Khushal51371a42018-05-17 10:41:40 -0700158
Herb Derbyc3415002018-11-08 16:40:26 -0500159sk_sp<SkSurface> MakeSurface(int width, int height, GrContext* context) {
160 const SkImageInfo info =
161 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
162 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
163}
164
165const SkSurfaceProps FindSurfaceProps(GrContext* context) {
166 auto surface = MakeSurface(1, 1, context);
167 return surface->props();
168}
169
Ravi Mistrycd21d672018-05-29 21:45:46 +0000170SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400171 GrContext* context, const SkMatrix* matrix = nullptr,
172 SkScalar x = 0) {
Herb Derbyc3415002018-11-08 16:40:26 -0500173 auto surface = MakeSurface(width, height, context);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000174 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400175 surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
Khushal38a08432018-05-02 10:29:37 -0700176 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000177 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700178 surface->readPixels(bitmap, 0, 0);
179 return bitmap;
180}
181
182DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
183 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
184 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400185 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700186
187 auto server_tf = SkTypeface::MakeDefault();
188 auto tf_data = server.serializeTypeface(server_tf.get());
189
190 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
191 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700192 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700193 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700194
195 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
196 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700197}
198
Khushal3e7548c2018-05-23 15:45:01 -0700199DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700200 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
201 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400202 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700203 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700204
205 // Server.
206 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
207 auto serverTfData = server.serializeTypeface(serverTf.get());
208
209 int glyphCount = 10;
210 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500211 auto props = FindSurfaceProps(ctxInfo.grContext());
Mike Reedf922c782019-02-19 15:46:38 -0500212 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
herb7022b772019-08-15 22:45:43 -0400213 ctxInfo.grContext()->supportsDistanceFieldText());
Hal Canarye107faa2019-10-23 12:52:33 -0400214 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
215 {
216 SkDynamicMemoryWStream wStream;
217 server.fCapture.reset(new SkTextBlobTrace::Capture);
218 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
219 server.fCapture->dump(&wStream);
220 std::unique_ptr<SkStreamAsset> stream = wStream.detachAsStream();
221 std::vector<SkTextBlobTrace::Record> trace = SkTextBlobTrace::CreateBlobTrace(stream.get());
222 REPORTER_ASSERT(reporter, trace.size() == 1);
223 }
224 #else
Khushal38a08432018-05-02 10:29:37 -0700225 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Hal Canarye107faa2019-10-23 12:52:33 -0400226 #endif
Khushal38a08432018-05-02 10:29:37 -0700227
228 std::vector<uint8_t> serverStrikeData;
229 server.writeStrikeData(&serverStrikeData);
230
231 // Client.
232 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
233 REPORTER_ASSERT(reporter,
234 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
235 auto clientBlob = buildTextBlob(clientTf, glyphCount);
236
Ravi Mistrycd21d672018-05-29 21:45:46 +0000237 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
238 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600239 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700240 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700241
242 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
243 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700244}
245
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400246DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
247 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
248 SkStrikeServer server(discardableManager.get());
249 SkStrikeClient client(discardableManager, false);
250
251 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500252 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400253 auto serverTfData = server.serializeTypeface(serverTf.get());
254 REPORTER_ASSERT(reporter, serverTf->unique());
255
256 {
257 const SkPaint paint;
258 int glyphCount = 10;
259 auto serverBlob = buildTextBlob(serverTf, glyphCount);
260 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400261 SkTextBlobCacheDiffCanvas cache_diff_canvas(
262 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400263 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
264 REPORTER_ASSERT(reporter, !serverTf->unique());
265
266 std::vector<uint8_t> serverStrikeData;
267 server.writeStrikeData(&serverStrikeData);
268 }
269 REPORTER_ASSERT(reporter, serverTf->unique());
270
271 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
272 discardableManager->unlockAndDeleteAll();
273}
274
Khushal38a08432018-05-02 10:29:37 -0700275DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
276 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
277 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400278 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700279
280 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
281 server.serializeTypeface(serverTf.get());
282 int glyphCount = 10;
283 auto serverBlob = buildTextBlob(serverTf, glyphCount);
284
285 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500286 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700287 SkPaint paint;
288 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
289
290 // The strike from the blob should be locked after it has been drawn on the canvas.
291 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
292 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
293
294 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
295 // again.
296 std::vector<uint8_t> fontData;
297 server.writeStrikeData(&fontData);
298 discardableManager->unlockAll();
299 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
300
301 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
302 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
303 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700304
305 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
306 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700307}
308
309DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
310 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
311 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400312 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700313
314 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
315 server.serializeTypeface(serverTf.get());
316 int glyphCount = 10;
317 auto serverBlob = buildTextBlob(serverTf, glyphCount);
318
319 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500320 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700321 SkPaint paint;
322 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
323 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
324
325 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
326 // handles.
327 std::vector<uint8_t> fontData;
328 server.writeStrikeData(&fontData);
Khushal498a9b22019-09-04 16:19:22 -0700329
330 // Another analysis pass, to ensure that deleting handles after a complete cache hit still
331 // works. This is a regression test for crbug.com/999682.
332 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
333 server.writeStrikeData(&fontData);
334 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
335
Khushal38a08432018-05-02 10:29:37 -0700336 discardableManager->unlockAndDeleteAll();
337 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700338 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700339
340 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
341 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700342}
343
344DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
345 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
346 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400347 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700348
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(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500357 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700358 SkPaint paint;
359 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
360
361 std::vector<uint8_t> serverStrikeData;
362 server.writeStrikeData(&serverStrikeData);
363
364 // Client.
365 REPORTER_ASSERT(reporter,
366 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
367 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
368
369 // The cache remains alive until it is pinned in the discardable manager.
370 SkGraphics::PurgeFontCache();
371 REPORTER_ASSERT(reporter, !clientTf->unique());
372
373 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
374 // clientTf.
375 discardableManager->unlockAndDeleteAll();
376 SkGraphics::PurgeFontCache();
377 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700378
379 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
380 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700381}
Khushalb2e71272018-05-15 12:59:48 -0700382
383DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
384 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
385 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400386 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700387
388 // Server.
389 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
390 auto serverTfData = server.serializeTypeface(serverTf.get());
391
392 int glyphCount = 10;
393 auto serverBlob = buildTextBlob(serverTf, glyphCount);
394
395 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500396 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalb2e71272018-05-15 12:59:48 -0700397 SkPaint paint;
398 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
399
400 std::vector<uint8_t> serverStrikeData;
401 server.writeStrikeData(&serverStrikeData);
402
403 // Client.
404 REPORTER_ASSERT(reporter,
405 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Herb Derbyc113e9e2018-06-21 14:06:30 -0400406 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700407
408 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
409 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700410}
Khushal51371a42018-05-17 10:41:40 -0700411
Khushalcf33b1b2018-08-29 16:16:25 -0700412DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
413 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
414 SkStrikeServer server(discardableManager.get());
415 server.setMaxEntriesInDescriptorMapForTesting(1u);
416 SkStrikeClient client(discardableManager, false);
417
418 {
419 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
420 int glyphCount = 10;
421 auto serverBlob = buildTextBlob(serverTf, glyphCount);
422
423 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500424 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700425 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400426 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
Khushalcf33b1b2018-08-29 16:16:25 -0700427 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400428 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700429 }
430
431 // Serialize to release the lock from the strike server and delete all current
432 // handles.
433 std::vector<uint8_t> fontData;
434 server.writeStrikeData(&fontData);
435 discardableManager->unlockAndDeleteAll();
436
437 // Use a different typeface. Creating a new strike should evict the previous
438 // one.
439 {
440 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
441 int glyphCount = 10;
442 auto serverBlob = buildTextBlob(serverTf, glyphCount);
443
444 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500445 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700446 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400447 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700448 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400449 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700450 }
451
452 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
453 discardableManager->unlockAndDeleteAll();
454}
455
Khushal3e7548c2018-05-23 15:45:01 -0700456DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700457 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
458 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400459 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700460 SkPaint paint;
461 paint.setStyle(SkPaint::kStroke_Style);
462 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400463 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400464 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700465
466 // Server.
467 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
468 auto serverTfData = server.serializeTypeface(serverTf.get());
469
470 int glyphCount = 10;
471 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500472 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400473 SkTextBlobCacheDiffCanvas cache_diff_canvas(
474 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal51371a42018-05-17 10:41:40 -0700475 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
476
477 std::vector<uint8_t> serverStrikeData;
478 server.writeStrikeData(&serverStrikeData);
479
480 // Client.
481 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
482 REPORTER_ASSERT(reporter,
483 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
484 auto clientBlob = buildTextBlob(clientTf, glyphCount);
485
Ravi Mistrycd21d672018-05-29 21:45:46 +0000486 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
487 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600488 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700489 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400490 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700491
492 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
493 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700494}
Khushal3e7548c2018-05-23 15:45:01 -0700495
Herb Derby8e318fd2018-08-29 11:04:18 -0400496sk_sp<SkTextBlob> make_blob_causing_fallback(
497 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500498 SkFont font;
499 font.setSubpixel(true);
500 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400501 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500502 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400503
Herb Derbyd249e8c2019-06-03 11:36:01 -0400504 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400505 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400506
507 char s[] = "Skia";
508 int runSize = strlen(s);
509
510 SkTextBlobBuilder builder;
511 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500512 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400513 SkASSERT(runBuffer.utf8text == nullptr);
514 SkASSERT(runBuffer.clusters == nullptr);
515
Mike Reed64670cb2019-04-16 11:37:38 -0700516 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
517 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400518
519 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500520 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400521
Herb Derby5fd955e2019-01-16 11:23:29 -0500522 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400523
524 for (int i = 0; i < runSize; i++) {
525 runBuffer.pos[i] = i * 10;
526 }
527
528 return builder.make();
529}
530
531DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
532 reporter, ctxInfo) {
533 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
534 SkStrikeServer server(discardableManager.get());
535 SkStrikeClient client(discardableManager, false);
536
537 SkPaint paint;
538
539 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
540 // TODO: when the cq bots can handle this font remove the check.
541 if (serverTf == nullptr) {
542 return;
543 }
544 auto serverTfData = server.serializeTypeface(serverTf.get());
545
546 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
547
Herb Derbyc3415002018-11-08 16:40:26 -0500548 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400549 SkTextBlobCacheDiffCanvas cache_diff_canvas(
550 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby8e318fd2018-08-29 11:04:18 -0400551 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
552
553 std::vector<uint8_t> serverStrikeData;
554 server.writeStrikeData(&serverStrikeData);
555
556 // Client.
557 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
558 REPORTER_ASSERT(reporter,
559 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
560
561 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
562
563 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
564 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
565 compare_blobs(expected, actual, reporter);
566 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
567 SkStrikeCache::ValidateGlyphCacheDataSize();
568
569 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
570 discardableManager->unlockAndDeleteAll();
571}
572
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400573#if 0
574// TODO: turn this one when I figure out how to deal with the pixel variance from linear
575// interpolation from GPU to GPU.
576DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
577 reporter, ctxInfo) {
578 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
579 SkStrikeServer server(discardableManager.get());
580 SkStrikeClient client(discardableManager, false);
581
582 SkPaint paint;
583
584 auto serverTf = ToolUtils::planet_typeface();
585 // TODO: when the cq bots can handle this font remove the check.
586 if (serverTf == nullptr) {
587 return;
588 }
589 auto serverTfData = server.serializeTypeface(serverTf.get());
590
591 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
592 SkFont font;
593 font.setSubpixel(true);
594 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400595 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400596 font.setTypeface(typeface);
597
598 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
599
600 // Mercury to Uranus.
601 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
602
603 SkTextBlobBuilder builder;
604 SkRect bounds = SkRect::MakeIWH(100, 100);
605 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
606 SkASSERT(runBuffer.utf8text == nullptr);
607 SkASSERT(runBuffer.clusters == nullptr);
608
609 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
610
611 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
612 runBuffer.pos[i] = i * 100;
613 }
614
615 return builder.make();
616 };
617
618 auto serverBlob = makeBlob(serverTf);
619
620 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400621 SkTextBlobCacheDiffCanvas cache_diff_canvas(
622 800, 800, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400623 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
624
625 std::vector<uint8_t> serverStrikeData;
626 server.writeStrikeData(&serverStrikeData);
627
628 // Client.
629 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
630 REPORTER_ASSERT(reporter,
631 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
632
633 auto clientBlob = makeBlob(clientTf);
634
635 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
636 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
637
638 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
639 // interpolation.
640 compare_blobs(expected, actual, reporter, 36);
641 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
642 SkStrikeCache::ValidateGlyphCacheDataSize();
643
644 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
645 discardableManager->unlockAndDeleteAll();
646}
647#endif
648
Herb Derby1a9971e2018-07-19 13:41:15 -0400649DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
650 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
651 SkStrikeServer server(discardableManager.get());
652 SkStrikeClient client(discardableManager, false);
653 SkPaint paint;
654 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400655
656 // Server.
657 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
658 auto serverTfData = server.serializeTypeface(serverTf.get());
659
660 int glyphCount = 10;
661 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500662 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400663 SkTextBlobCacheDiffCanvas cache_diff_canvas(
664 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby1a9971e2018-07-19 13:41:15 -0400665 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
666
667 std::vector<uint8_t> serverStrikeData;
668 server.writeStrikeData(&serverStrikeData);
669
670 // Client.
671 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
672 REPORTER_ASSERT(reporter,
673 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
674 auto clientBlob = buildTextBlob(clientTf, glyphCount);
675
676 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
677 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600678 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400679 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
680 SkStrikeCache::ValidateGlyphCacheDataSize();
681
682 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
683 discardableManager->unlockAndDeleteAll();
684}
685
Khushal3e7548c2018-05-23 15:45:01 -0700686DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
687 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
688 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400689 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700690 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500691 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700692
Jim Van Verthce3cf802019-10-10 11:06:20 -0400693 // A scale transform forces fallback to dft.
694 SkMatrix matrix = SkMatrix::MakeScale(16);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000695 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400696 GrTextContext::Options options;
697 GrTextContext::SanitizeOptions(&options);
698 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Mike Reedf2b074e2018-12-03 16:52:59 -0500699 paint, font, matrix, surfaceProps, true, options));
Khushal3e7548c2018-05-23 15:45:01 -0700700
701 // Server.
702 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
703 auto serverTfData = server.serializeTypeface(serverTf.get());
704
705 int glyphCount = 10;
706 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000707 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400708 SkTextBlobCacheDiffCanvas cache_diff_canvas(
709 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal3e7548c2018-05-23 15:45:01 -0700710 cache_diff_canvas.concat(matrix);
711 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
712
713 std::vector<uint8_t> serverStrikeData;
714 server.writeStrikeData(&serverStrikeData);
715
716 // Client.
717 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
718 REPORTER_ASSERT(reporter,
719 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
720 auto clientBlob = buildTextBlob(clientTf, glyphCount);
721
Ravi Mistrycd21d672018-05-29 21:45:46 +0000722 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
723 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600724 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700725 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400726 SkStrikeCache::ValidateGlyphCacheDataSize();
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();
747 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &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) {
788 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
789 SkStrikeServer server(discardableManager.get());
790 SkStrikeClient client(discardableManager, false);
791
792 auto serverTf = ToolUtils::emoji_typeface();
793 auto serverTfData = server.serializeTypeface(serverTf.get());
794 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
795
Mike Reed69aaee02019-05-30 11:40:51 +0000796 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400797 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
798 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400799 SkTextBlobCacheDiffCanvas cache_diff_canvas(
800 500, 500, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbye384a1e2019-05-21 11:27:40 -0400801 SkPaint paint;
Mike Reed69aaee02019-05-30 11:40:51 +0000802 cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400803
804 std::vector<uint8_t> serverStrikeData;
805 server.writeStrikeData(&serverStrikeData);
Herb Derbyf5e9b422019-10-22 16:06:22 -0400806 if (!serverStrikeData.empty()) {
807 REPORTER_ASSERT(reporter,
808 client.readStrikeData(serverStrikeData.data(),
809 serverStrikeData.size()));
810 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400811 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
812 REPORTER_ASSERT(reporter, clientBlob);
813
Mike Reed69aaee02019-05-30 11:40:51 +0000814 RasterBlob(clientBlob, 500, 500, paint, ctxInfo.grContext());
Herb Derbye384a1e2019-05-21 11:27:40 -0400815 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
816 SkStrikeCache::ValidateGlyphCacheDataSize();
817 discardableManager->resetCacheMissCounts();
818 }
819
820 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
821 discardableManager->unlockAndDeleteAll();
822}
823
Herb Derby65b7bfc2018-06-05 13:32:12 -0400824DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
Khushal8523b6b2018-06-12 11:26:17 -0700825 // Build proxy typeface on the client for initializing the cache.
826 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
827 SkStrikeServer server(discardableManager.get());
828 SkStrikeClient client(discardableManager, false);
829
830 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
831 auto tfData = server.serializeTypeface(serverTf.get());
832 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
833 REPORTER_ASSERT(reporter, clientTf);
834
Mike Reed4529cb52018-11-06 08:03:42 -0500835 SkFont font;
836 font.setTypeface(clientTf);
Herb Derby511dcfc2019-06-24 12:58:41 -0400837 font.setSubpixel(true);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400838 SkPaint paint;
839 paint.setAntiAlias(true);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400840 paint.setColor(SK_ColorRED);
841
842 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400843 const uint8_t glyphImage[] = {0xFF, 0xFF};
844
Herb Derby5c0c7982018-06-21 15:15:50 -0400845 SkStrikeCache strikeCache;
846
Herb Derby65b7bfc2018-06-05 13:32:12 -0400847 // Build a fallback cache.
848 {
849 SkAutoDescriptor ad;
850 SkScalerContextRec rec;
851 SkScalerContextEffects effects;
852 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbyc3415002018-11-08 16:40:26 -0500853 SkScalerContext::MakeRecAndEffects(
854 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500855 SkMatrix::I(), &rec, &effects);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400856 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
857
Herb Derby5c0c7982018-06-21 15:15:50 -0400858 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Herb Derby37216882019-06-13 17:24:24 -0400859 SkGlyphPrototype proto = {lostGlyphID, 0.f, 0.f, 2, 1, 0, 0, SkMask::kA8_Format, false};
Herb Derby511dcfc2019-06-24 12:58:41 -0400860 fallbackCache->glyphFromPrototype(proto, (void*)glyphImage);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400861 }
862
863 // Make sure we can find the fall back cache.
864 {
865 SkAutoDescriptor ad;
866 SkScalerContextRec rec;
867 SkScalerContextEffects effects;
868 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbyc3415002018-11-08 16:40:26 -0500869 SkScalerContext::MakeRecAndEffects(
870 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500871 SkMatrix::I(), &rec, &effects);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400872 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400873 auto testCache = strikeCache.findStrikeExclusive(*desc);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400874 REPORTER_ASSERT(reporter, !(testCache == nullptr));
875 }
876
Khushal8523b6b2018-06-12 11:26:17 -0700877 // Create the target cache.
878 SkExclusiveStrikePtr testCache;
879 SkAutoDescriptor ad;
880 SkScalerContextRec rec;
881 SkScalerContextEffects effects;
882 SkScalerContextFlags flags = SkScalerContextFlags::kNone;
Herb Derbyc3415002018-11-08 16:40:26 -0500883 SkScalerContext::MakeRecAndEffects(
884 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500885 SkMatrix::I(), &rec, &effects);
Khushal8523b6b2018-06-12 11:26:17 -0700886 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400887 testCache = strikeCache.findStrikeExclusive(*desc);
Khushal8523b6b2018-06-12 11:26:17 -0700888 REPORTER_ASSERT(reporter, testCache == nullptr);
Herb Derby5c0c7982018-06-21 15:15:50 -0400889 testCache = strikeCache.createStrikeExclusive(*desc,
Khushal8523b6b2018-06-12 11:26:17 -0700890 clientTf->createScalerContext(effects, desc));
Herb Derby5c0c7982018-06-21 15:15:50 -0400891 auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
892 scalerProxy->initCache(testCache.get(), &strikeCache);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400893
Herb Derbycb443a52019-11-11 18:01:36 -0500894 auto rounding = testCache->roundingSpec();
895 SkBulkGlyphMetricsAndImages metricsAndImages{std::move(testCache)};
896
Khushal8523b6b2018-06-12 11:26:17 -0700897 // Look for the lost glyph.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400898 {
Herb Derby511dcfc2019-06-24 12:58:41 -0400899 SkPoint pt{SkFixedToScalar(lostGlyphID.getSubXFixed()),
900 SkFixedToScalar(lostGlyphID.getSubYFixed())};
herb252cdb72019-11-07 12:20:10 -0500901 SkPackedGlyphID packedID{
Herb Derbycb443a52019-11-11 18:01:36 -0500902 lostGlyphID.glyphID(), pt, rounding.ignorePositionFieldMask};
903
904 const SkGlyph* lostGlyph = metricsAndImages.glyph(packedID);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400905
Herb Derby511dcfc2019-06-24 12:58:41 -0400906 REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
907 REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
908 REPORTER_ASSERT(reporter, lostGlyph->maskFormat() == SkMask::kA8_Format);
909 REPORTER_ASSERT(reporter, memcmp(lostGlyph->image(), glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400910 }
911
Khushal8523b6b2018-06-12 11:26:17 -0700912 // Look for the lost glyph with a different sub-pix position.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400913 {
Herb Derby511dcfc2019-06-24 12:58:41 -0400914 SkPoint pt{SkFixedToScalar(SK_FixedQuarter),
915 SkFixedToScalar(SK_FixedQuarter)};
herb252cdb72019-11-07 12:20:10 -0500916 SkPackedGlyphID packedID{
Herb Derbycb443a52019-11-11 18:01:36 -0500917 lostGlyphID.glyphID(), pt, rounding.ignorePositionFieldMask};
918 const SkGlyph* lostGlyph = metricsAndImages.glyph(packedID);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400919
Herb Derby511dcfc2019-06-24 12:58:41 -0400920 REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
921 REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
922 REPORTER_ASSERT(reporter, lostGlyph->maskFormat() == SkMask::kA8_Format);
923 REPORTER_ASSERT(reporter, memcmp(lostGlyph->image(), glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400924 }
925
Khushal8523b6b2018-06-12 11:26:17 -0700926 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
927 if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
928 i == SkStrikeClient::CacheMissType::kFontMetrics) {
929 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
930 } else {
931 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
932 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400933 }
Herb Derby5c0c7982018-06-21 15:15:50 -0400934 strikeCache.validateGlyphCacheDataSize();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400935
Khushal8523b6b2018-06-12 11:26:17 -0700936 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
937 discardableManager->unlockAndDeleteAll();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400938}
Khushal4010c792018-06-13 09:44:23 -0700939
940DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
941 // Build proxy typeface on the client for initializing the cache.
942 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
943 SkStrikeServer server(discardableManager.get());
944 SkStrikeClient client(discardableManager, false);
945
946 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
947 auto tfData = server.serializeTypeface(serverTf.get());
948 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
949 REPORTER_ASSERT(reporter, clientTf);
950
Mike Reed4529cb52018-11-06 08:03:42 -0500951 SkFont font;
Herb Derbye7f662b2018-12-17 12:12:56 -0500952 font.setEdging(SkFont::Edging::kAntiAlias);
Khushal4010c792018-06-13 09:44:23 -0700953 SkPaint paint;
Khushal4010c792018-06-13 09:44:23 -0700954 paint.setColor(SK_ColorRED);
955
Herb Derbyf5e9b422019-10-22 16:06:22 -0400956 SkPoint glyphPos = {0.5f, 0.5f};
957 SkIPoint glyphIPos = {SkScalarToFixed(glyphPos.x()), SkScalarToFixed(glyphPos.y())};
958 auto lostGlyphID = SkPackedGlyphID(1, glyphIPos.x(), glyphIPos.y());
Khushal4010c792018-06-13 09:44:23 -0700959 const uint8_t glyphImage[] = {0xFF, 0xFF};
Herb Derby37216882019-06-13 17:24:24 -0400960 SkMask::Format realMask;
961 SkMask::Format fakeMask;
Khushal4010c792018-06-13 09:44:23 -0700962
Herb Derby5c0c7982018-06-21 15:15:50 -0400963 SkStrikeCache strikeCache;
964
Khushal4010c792018-06-13 09:44:23 -0700965 {
966 SkAutoDescriptor ad;
967 SkScalerContextRec rec;
968 SkScalerContextEffects effects;
969 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500970 font.setTypeface(serverTf);
Herb Derbyc3415002018-11-08 16:40:26 -0500971 SkScalerContext::MakeRecAndEffects(
972 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500973 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -0700974 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
975
976 auto context = serverTf->createScalerContext(effects, desc, false);
Herb Derbyf6fca262019-01-09 15:13:54 -0500977 SkGlyph glyph{lostGlyphID};
Khushal4010c792018-06-13 09:44:23 -0700978 context->getMetrics(&glyph);
Herb Derby37216882019-06-13 17:24:24 -0400979 realMask = glyph.maskFormat();
Khushal4010c792018-06-13 09:44:23 -0700980 }
981
982 // Build a fallback cache.
983 {
984 SkAutoDescriptor ad;
985 SkScalerContextRec rec;
986 SkScalerContextEffects effects;
987 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500988 font.setTypeface(clientTf);
Herb Derbyc3415002018-11-08 16:40:26 -0500989 SkScalerContext::MakeRecAndEffects(
990 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500991 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -0700992 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
993
Herb Derby5c0c7982018-06-21 15:15:50 -0400994 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Khushal4010c792018-06-13 09:44:23 -0700995 fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
Herb Derby37216882019-06-13 17:24:24 -0400996 SkGlyphPrototype proto = {lostGlyphID, 0.f, 0.f, 2, 1, 0, 0, fakeMask, false};
Herb Derby511dcfc2019-06-24 12:58:41 -0400997 fallbackCache->glyphFromPrototype(proto, (void *)glyphImage);
Khushal4010c792018-06-13 09:44:23 -0700998 }
999
1000 // Send over the real glyph and make sure the client cache stays intact.
1001 {
1002 SkAutoDescriptor ad;
Khushal4010c792018-06-13 09:44:23 -07001003 SkScalerContextEffects effects;
1004 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -05001005 font.setTypeface(serverTf);
Herb Derbyc03716d2018-09-17 11:39:51 -04001006 auto* cacheState = server.getOrCreateCache(
Herb Derbye7f662b2018-12-17 12:12:56 -05001007 paint, font, SkSurfacePropsCopyOrDefault(nullptr),
Herb Derbyc03716d2018-09-17 11:39:51 -04001008 SkMatrix::I(), flags, &effects);
Herb Derbyf5e9b422019-10-22 16:06:22 -04001009 SkGlyphID glyphID = lostGlyphID.glyphID();
1010 SkZip<const SkGlyphID, const SkPoint> source{1, &glyphID, &glyphPos};
1011 SkSourceGlyphBuffer rejects;
1012 SkDrawableGlyphBuffer drawables;
1013 drawables.ensureSize(source.size());
1014 rejects.setSource(source);
1015 drawables.startSource(rejects.source(), {0, 0});
1016 SkStrikeServer::AddGlyphForTesting(cacheState, &drawables, &rejects);
Khushal4010c792018-06-13 09:44:23 -07001017 std::vector<uint8_t> serverStrikeData;
1018 server.writeStrikeData(&serverStrikeData);
Herb Derbyf5e9b422019-10-22 16:06:22 -04001019 REPORTER_ASSERT(reporter, !serverStrikeData.empty());
Khushal4010c792018-06-13 09:44:23 -07001020 REPORTER_ASSERT(reporter,
Herb Derby5c0c7982018-06-21 15:15:50 -04001021 client.readStrikeData(
1022 serverStrikeData.data(),
1023 serverStrikeData.size()));
Khushal4010c792018-06-13 09:44:23 -07001024 }
1025
1026 {
1027 SkAutoDescriptor ad;
1028 SkScalerContextRec rec;
1029 SkScalerContextEffects effects;
1030 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -05001031 font.setTypeface(clientTf);
Herb Derbyc3415002018-11-08 16:40:26 -05001032 SkScalerContext::MakeRecAndEffects(
1033 font, paint, SkSurfaceProps(0, kUnknown_SkPixelGeometry), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -05001034 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -07001035 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
1036
Herb Derby5c0c7982018-06-21 15:15:50 -04001037 auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
Khushal4010c792018-06-13 09:44:23 -07001038 REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
Herb Derby511dcfc2019-06-24 12:58:41 -04001039 auto glyph = fallbackCache->glyphOrNull(lostGlyphID);
1040 REPORTER_ASSERT(reporter, glyph && glyph->maskFormat() == fakeMask);
1041 if (glyph) {
1042 REPORTER_ASSERT(reporter,
1043 memcmp(glyph->image(), glyphImage, glyph->imageSize()) == 0);
1044 }
Khushal4010c792018-06-13 09:44:23 -07001045 }
1046
Herb Derby5c0c7982018-06-21 15:15:50 -04001047 strikeCache.validateGlyphCacheDataSize();
Khushal4010c792018-06-13 09:44:23 -07001048
1049 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
1050 discardableManager->unlockAndDeleteAll();
1051}