blob: 3e69c907072b8c7238c96ff506151fcbb571ad2e [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"
14#include "src/core/SkRemoteGlyphCacheImpl.h"
15#include "src/core/SkStrike.h"
16#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"
20#include "tests/Test.h"
21#include "tools/Resources.h"
22#include "tools/ToolUtils.h"
23#include "tools/fonts/TestEmptyTypeface.h"
Khushal38a08432018-05-02 10:29:37 -070024
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070026
Khushal38a08432018-05-02 10:29:37 -070027class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
28 public SkStrikeClient::DiscardableHandleManager {
29public:
Khushald4160832018-05-23 18:16:00 -070030 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070031 ~DiscardableManager() override = default;
32
33 // Server implementation.
34 SkDiscardableHandleId createHandle() override {
Herb Derby9b869552019-05-10 12:16:17 -040035 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070036
Khushal38a08432018-05-02 10:29:37 -070037 // Handles starts as locked.
38 fLockedHandles.add(++fNextHandleId);
39 return fNextHandleId;
40 }
41 bool lockHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040042 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070043
Khushal38a08432018-05-02 10:29:37 -070044 if (id <= fLastDeletedHandleId) return false;
45 fLockedHandles.add(id);
46 return true;
47 }
48
49 // Client implementation.
Khushal3de67bd2019-03-15 14:43:15 -070050 bool deleteHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040051 SkAutoMutexExclusive l(fMutex);
Khushal38a08432018-05-02 10:29:37 -070052
Khushal3de67bd2019-03-15 14:43:15 -070053 return id <= fLastDeletedHandleId;
54 }
55
56 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
Herb Derby9b869552019-05-10 12:16:17 -040057 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070058
59 fCacheMissCount[type]++;
60 }
61 bool isHandleDeleted(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040062 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070063
64 return id <= fLastDeletedHandleId;
65 }
66
67 void unlockAll() {
Herb Derby9b869552019-05-10 12:16:17 -040068 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070069
70 fLockedHandles.reset();
71 }
Khushal38a08432018-05-02 10:29:37 -070072 void unlockAndDeleteAll() {
Herb Derby9b869552019-05-10 12:16:17 -040073 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070074
75 fLockedHandles.reset();
Khushal38a08432018-05-02 10:29:37 -070076 fLastDeletedHandleId = fNextHandleId;
77 }
Khushal3de67bd2019-03-15 14:43:15 -070078 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
Herb Derby9b869552019-05-10 12:16:17 -040079 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070080
81 return fLockedHandles;
82 }
83 SkDiscardableHandleId handleCount() {
Herb Derby9b869552019-05-10 12:16:17 -040084 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070085
86 return fNextHandleId;
87 }
88 int cacheMissCount(uint32_t type) {
Herb Derby9b869552019-05-10 12:16:17 -040089 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070090
91 return fCacheMissCount[type];
92 }
Khushalfa8ff092018-06-06 17:46:38 -070093 bool hasCacheMiss() const {
Herb Derby9b869552019-05-10 12:16:17 -040094 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070095
Khushalfa8ff092018-06-06 17:46:38 -070096 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
97 if (fCacheMissCount[i] > 0) return true;
98 }
99 return false;
100 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400101 void resetCacheMissCounts() {
102 SkAutoMutexExclusive l(fMutex);
103 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
104 }
Khushal38a08432018-05-02 10:29:37 -0700105
106private:
Khushal3de67bd2019-03-15 14:43:15 -0700107 // The tests below run in parallel on multiple threads and use the same
108 // process global SkStrikeCache. So the implementation needs to be
109 // thread-safe.
110 mutable SkMutex fMutex;
111
Khushal38a08432018-05-02 10:29:37 -0700112 SkDiscardableHandleId fNextHandleId = 0u;
113 SkDiscardableHandleId fLastDeletedHandleId = 0u;
114 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -0700115 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -0700116};
117
118sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -0500119 SkFont font;
Khushal38a08432018-05-02 10:29:37 -0700120 font.setTypeface(tf);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400121 font.setHinting(SkFontHinting::kNormal);
Mike Reed2ed78202018-11-21 15:10:08 -0500122 font.setSize(1u);
123 font.setEdging(SkFont::Edging::kAntiAlias);
124 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -0700125
126 SkTextBlobBuilder builder;
127 SkRect bounds = SkRect::MakeWH(10, 10);
128 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
129 SkASSERT(runBuffer.utf8text == nullptr);
130 SkASSERT(runBuffer.clusters == nullptr);
131
132 for (int i = 0; i < glyphCount; i++) {
133 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
134 runBuffer.pos[i] = SkIntToScalar(i);
135 }
136 return builder.make();
137}
138
Chris Daltonf9a90a22018-08-28 14:17:55 -0600139static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
140 skiatest::Reporter* reporter, int tolerance = 0) {
141 SkASSERT(expected.width() == actual.width());
142 SkASSERT(expected.height() == actual.height());
143 for (int i = 0; i < expected.width(); ++i) {
144 for (int j = 0; j < expected.height(); ++j) {
145 SkColor expectedColor = expected.getColor(i, j);
146 SkColor actualColor = actual.getColor(i, j);
147 if (0 == tolerance) {
148 REPORTER_ASSERT(reporter, expectedColor == actualColor);
149 } else {
150 for (int k = 0; k < 4; ++k) {
151 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
152 int actualChannel = (actualColor >> (k*8)) & 0xff;
153 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
154 }
155 }
156 }
Khushal51371a42018-05-17 10:41:40 -0700157 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600158}
Khushal51371a42018-05-17 10:41:40 -0700159
Khushal3e7548c2018-05-23 15:45:01 -0700160SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
161 SkTextBlobCacheDiffCanvas::Settings settings;
162 settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
Khushalfa8ff092018-06-06 17:46:38 -0700163 settings.fMaxTextureSize = context->maxTextureSize();
164 settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
Khushal3e7548c2018-05-23 15:45:01 -0700165 return settings;
166}
167
Herb Derbyc3415002018-11-08 16:40:26 -0500168sk_sp<SkSurface> MakeSurface(int width, int height, GrContext* context) {
169 const SkImageInfo info =
170 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
171 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
172}
173
174const SkSurfaceProps FindSurfaceProps(GrContext* context) {
175 auto surface = MakeSurface(1, 1, context);
176 return surface->props();
177}
178
Ravi Mistrycd21d672018-05-29 21:45:46 +0000179SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400180 GrContext* context, const SkMatrix* matrix = nullptr,
181 SkScalar x = 0) {
Herb Derbyc3415002018-11-08 16:40:26 -0500182 auto surface = MakeSurface(width, height, context);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000183 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400184 surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
Khushal38a08432018-05-02 10:29:37 -0700185 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000186 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700187 surface->readPixels(bitmap, 0, 0);
188 return bitmap;
189}
190
191DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
192 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
193 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400194 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700195
196 auto server_tf = SkTypeface::MakeDefault();
197 auto tf_data = server.serializeTypeface(server_tf.get());
198
199 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
200 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700201 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700202 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700203
204 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
205 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700206}
207
Khushal3e7548c2018-05-23 15:45:01 -0700208DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700209 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
210 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400211 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700212 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700213
214 // Server.
215 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
216 auto serverTfData = server.serializeTypeface(serverTf.get());
217
218 int glyphCount = 10;
219 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500220 auto props = FindSurfaceProps(ctxInfo.grContext());
Mike Reedf922c782019-02-19 15:46:38 -0500221 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
Khushal3e7548c2018-05-23 15:45:01 -0700222 MakeSettings(ctxInfo.grContext()));
Khushal38a08432018-05-02 10:29:37 -0700223 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
224
225 std::vector<uint8_t> serverStrikeData;
226 server.writeStrikeData(&serverStrikeData);
227
228 // Client.
229 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
230 REPORTER_ASSERT(reporter,
231 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
232 auto clientBlob = buildTextBlob(clientTf, glyphCount);
233
Ravi Mistrycd21d672018-05-29 21:45:46 +0000234 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
235 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600236 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700237 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700238
239 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
240 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700241}
242
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400243DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
244 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
245 SkStrikeServer server(discardableManager.get());
246 SkStrikeClient client(discardableManager, false);
247
248 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500249 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400250 auto serverTfData = server.serializeTypeface(serverTf.get());
251 REPORTER_ASSERT(reporter, serverTf->unique());
252
253 {
254 const SkPaint paint;
255 int glyphCount = 10;
256 auto serverBlob = buildTextBlob(serverTf, glyphCount);
257 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500258 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400259 MakeSettings(ctxInfo.grContext()));
260 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
261 REPORTER_ASSERT(reporter, !serverTf->unique());
262
263 std::vector<uint8_t> serverStrikeData;
264 server.writeStrikeData(&serverStrikeData);
265 }
266 REPORTER_ASSERT(reporter, serverTf->unique());
267
268 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
269 discardableManager->unlockAndDeleteAll();
270}
271
Khushal38a08432018-05-02 10:29:37 -0700272DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
273 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
274 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400275 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700276
277 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
278 server.serializeTypeface(serverTf.get());
279 int glyphCount = 10;
280 auto serverBlob = buildTextBlob(serverTf, glyphCount);
281
282 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500283 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700284 SkPaint paint;
285 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
286
287 // The strike from the blob should be locked after it has been drawn on the canvas.
288 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
289 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
290
291 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
292 // again.
293 std::vector<uint8_t> fontData;
294 server.writeStrikeData(&fontData);
295 discardableManager->unlockAll();
296 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
297
298 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
299 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
300 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700301
302 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
303 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700304}
305
306DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
307 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
308 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400309 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700310
311 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
312 server.serializeTypeface(serverTf.get());
313 int glyphCount = 10;
314 auto serverBlob = buildTextBlob(serverTf, glyphCount);
315
316 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500317 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700318 SkPaint paint;
319 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
320 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
321
322 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
323 // handles.
324 std::vector<uint8_t> fontData;
325 server.writeStrikeData(&fontData);
326 discardableManager->unlockAndDeleteAll();
327 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700328 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700329
330 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
331 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700332}
333
334DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
335 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
336 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400337 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700338
339 // Server.
340 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
341 auto serverTfData = server.serializeTypeface(serverTf.get());
342
343 int glyphCount = 10;
344 auto serverBlob = buildTextBlob(serverTf, glyphCount);
345
346 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500347 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700348 SkPaint paint;
349 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
350
351 std::vector<uint8_t> serverStrikeData;
352 server.writeStrikeData(&serverStrikeData);
353
354 // Client.
355 REPORTER_ASSERT(reporter,
356 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
357 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
358
359 // The cache remains alive until it is pinned in the discardable manager.
360 SkGraphics::PurgeFontCache();
361 REPORTER_ASSERT(reporter, !clientTf->unique());
362
363 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
364 // clientTf.
365 discardableManager->unlockAndDeleteAll();
366 SkGraphics::PurgeFontCache();
367 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700368
369 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
370 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700371}
Khushalb2e71272018-05-15 12:59:48 -0700372
373DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
374 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
375 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400376 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700377
378 // Server.
379 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
380 auto serverTfData = server.serializeTypeface(serverTf.get());
381
382 int glyphCount = 10;
383 auto serverBlob = buildTextBlob(serverTf, glyphCount);
384
385 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500386 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalb2e71272018-05-15 12:59:48 -0700387 SkPaint paint;
388 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
389
390 std::vector<uint8_t> serverStrikeData;
391 server.writeStrikeData(&serverStrikeData);
392
393 // Client.
394 REPORTER_ASSERT(reporter,
395 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Herb Derbyc113e9e2018-06-21 14:06:30 -0400396 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700397
398 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
399 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700400}
Khushal51371a42018-05-17 10:41:40 -0700401
Khushalcf33b1b2018-08-29 16:16:25 -0700402DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
403 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
404 SkStrikeServer server(discardableManager.get());
405 server.setMaxEntriesInDescriptorMapForTesting(1u);
406 SkStrikeClient client(discardableManager, false);
407
408 {
409 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
410 int glyphCount = 10;
411 auto serverBlob = buildTextBlob(serverTf, glyphCount);
412
413 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500414 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700415 SkPaint paint;
416 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 0u);
417 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
418 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
419 }
420
421 // Serialize to release the lock from the strike server and delete all current
422 // handles.
423 std::vector<uint8_t> fontData;
424 server.writeStrikeData(&fontData);
425 discardableManager->unlockAndDeleteAll();
426
427 // Use a different typeface. Creating a new strike should evict the previous
428 // one.
429 {
430 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
431 int glyphCount = 10;
432 auto serverBlob = buildTextBlob(serverTf, glyphCount);
433
434 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500435 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700436 SkPaint paint;
437 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
438 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
439 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
440 }
441
442 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
443 discardableManager->unlockAndDeleteAll();
444}
445
Khushal3e7548c2018-05-23 15:45:01 -0700446DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700447 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
448 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400449 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700450 SkPaint paint;
451 paint.setStyle(SkPaint::kStroke_Style);
452 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400453 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400454 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700455
456 // Server.
457 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
458 auto serverTfData = server.serializeTypeface(serverTf.get());
459
460 int glyphCount = 10;
461 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500462 auto props = FindSurfaceProps(ctxInfo.grContext());
Mike Reedf922c782019-02-19 15:46:38 -0500463 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
Khushal3e7548c2018-05-23 15:45:01 -0700464 MakeSettings(ctxInfo.grContext()));
Khushal51371a42018-05-17 10:41:40 -0700465 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
466
467 std::vector<uint8_t> serverStrikeData;
468 server.writeStrikeData(&serverStrikeData);
469
470 // Client.
471 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
472 REPORTER_ASSERT(reporter,
473 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
474 auto clientBlob = buildTextBlob(clientTf, glyphCount);
475
Ravi Mistrycd21d672018-05-29 21:45:46 +0000476 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
477 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600478 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700479 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400480 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700481
482 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
483 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700484}
Khushal3e7548c2018-05-23 15:45:01 -0700485
Herb Derby8e318fd2018-08-29 11:04:18 -0400486sk_sp<SkTextBlob> make_blob_causing_fallback(
487 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500488 SkFont font;
489 font.setSubpixel(true);
490 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400491 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500492 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400493
Herb Derbyd249e8c2019-06-03 11:36:01 -0400494 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400495 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400496
497 char s[] = "Skia";
498 int runSize = strlen(s);
499
500 SkTextBlobBuilder builder;
501 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500502 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400503 SkASSERT(runBuffer.utf8text == nullptr);
504 SkASSERT(runBuffer.clusters == nullptr);
505
Mike Reed64670cb2019-04-16 11:37:38 -0700506 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
507 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400508
509 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500510 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400511
Herb Derby5fd955e2019-01-16 11:23:29 -0500512 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400513
514 for (int i = 0; i < runSize; i++) {
515 runBuffer.pos[i] = i * 10;
516 }
517
518 return builder.make();
519}
520
521DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
522 reporter, ctxInfo) {
523 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
524 SkStrikeServer server(discardableManager.get());
525 SkStrikeClient client(discardableManager, false);
526
527 SkPaint paint;
528
529 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
530 // TODO: when the cq bots can handle this font remove the check.
531 if (serverTf == nullptr) {
532 return;
533 }
534 auto serverTfData = server.serializeTypeface(serverTf.get());
535
536 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
537
Herb Derbyc3415002018-11-08 16:40:26 -0500538 auto props = FindSurfaceProps(ctxInfo.grContext());
Mike Reedf922c782019-02-19 15:46:38 -0500539 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
Herb Derby8e318fd2018-08-29 11:04:18 -0400540 MakeSettings(ctxInfo.grContext()));
541 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
542
543 std::vector<uint8_t> serverStrikeData;
544 server.writeStrikeData(&serverStrikeData);
545
546 // Client.
547 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
548 REPORTER_ASSERT(reporter,
549 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
550
551 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
552
553 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
554 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
555 compare_blobs(expected, actual, reporter);
556 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
557 SkStrikeCache::ValidateGlyphCacheDataSize();
558
559 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
560 discardableManager->unlockAndDeleteAll();
561}
562
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400563#if 0
564// TODO: turn this one when I figure out how to deal with the pixel variance from linear
565// interpolation from GPU to GPU.
566DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
567 reporter, ctxInfo) {
568 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
569 SkStrikeServer server(discardableManager.get());
570 SkStrikeClient client(discardableManager, false);
571
572 SkPaint paint;
573
574 auto serverTf = ToolUtils::planet_typeface();
575 // TODO: when the cq bots can handle this font remove the check.
576 if (serverTf == nullptr) {
577 return;
578 }
579 auto serverTfData = server.serializeTypeface(serverTf.get());
580
581 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
582 SkFont font;
583 font.setSubpixel(true);
584 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400585 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400586 font.setTypeface(typeface);
587
588 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
589
590 // Mercury to Uranus.
591 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
592
593 SkTextBlobBuilder builder;
594 SkRect bounds = SkRect::MakeIWH(100, 100);
595 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
596 SkASSERT(runBuffer.utf8text == nullptr);
597 SkASSERT(runBuffer.clusters == nullptr);
598
599 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
600
601 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
602 runBuffer.pos[i] = i * 100;
603 }
604
605 return builder.make();
606 };
607
608 auto serverBlob = makeBlob(serverTf);
609
610 auto props = FindSurfaceProps(ctxInfo.grContext());
611 SkTextBlobCacheDiffCanvas cache_diff_canvas(800, 800, props, &server,
612 MakeSettings(ctxInfo.grContext()));
613 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
614
615 std::vector<uint8_t> serverStrikeData;
616 server.writeStrikeData(&serverStrikeData);
617
618 // Client.
619 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
620 REPORTER_ASSERT(reporter,
621 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
622
623 auto clientBlob = makeBlob(clientTf);
624
625 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
626 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
627
628 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
629 // interpolation.
630 compare_blobs(expected, actual, reporter, 36);
631 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
632 SkStrikeCache::ValidateGlyphCacheDataSize();
633
634 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
635 discardableManager->unlockAndDeleteAll();
636}
637#endif
638
Herb Derby1a9971e2018-07-19 13:41:15 -0400639DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
640 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
641 SkStrikeServer server(discardableManager.get());
642 SkStrikeClient client(discardableManager, false);
643 SkPaint paint;
644 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400645
646 // Server.
647 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
648 auto serverTfData = server.serializeTypeface(serverTf.get());
649
650 int glyphCount = 10;
651 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500652 auto props = FindSurfaceProps(ctxInfo.grContext());
Mike Reedf922c782019-02-19 15:46:38 -0500653 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
Herb Derby1a9971e2018-07-19 13:41:15 -0400654 MakeSettings(ctxInfo.grContext()));
655 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
656
657 std::vector<uint8_t> serverStrikeData;
658 server.writeStrikeData(&serverStrikeData);
659
660 // Client.
661 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
662 REPORTER_ASSERT(reporter,
663 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
664 auto clientBlob = buildTextBlob(clientTf, glyphCount);
665
666 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
667 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600668 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400669 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
670 SkStrikeCache::ValidateGlyphCacheDataSize();
671
672 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
673 discardableManager->unlockAndDeleteAll();
674}
675
Khushal3e7548c2018-05-23 15:45:01 -0700676DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
677 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
678 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400679 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700680 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500681 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700682
683 // A perspective transform forces fallback to dft.
684 SkMatrix matrix = SkMatrix::I();
685 matrix[SkMatrix::kMPersp0] = 0.5f;
686 REPORTER_ASSERT(reporter, matrix.hasPerspective());
Ravi Mistrycd21d672018-05-29 21:45:46 +0000687 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400688 GrTextContext::Options options;
689 GrTextContext::SanitizeOptions(&options);
690 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Mike Reedf2b074e2018-12-03 16:52:59 -0500691 paint, font, matrix, surfaceProps, true, options));
Khushal3e7548c2018-05-23 15:45:01 -0700692
693 // Server.
694 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
695 auto serverTfData = server.serializeTypeface(serverTf.get());
696
697 int glyphCount = 10;
698 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000699 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500700 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
Khushal3e7548c2018-05-23 15:45:01 -0700701 MakeSettings(ctxInfo.grContext()));
702 cache_diff_canvas.concat(matrix);
703 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
704
705 std::vector<uint8_t> serverStrikeData;
706 server.writeStrikeData(&serverStrikeData);
707
708 // Client.
709 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
710 REPORTER_ASSERT(reporter,
711 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
712 auto clientBlob = buildTextBlob(clientTf, glyphCount);
713
Ravi Mistrycd21d672018-05-29 21:45:46 +0000714 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
715 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600716 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700717 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400718 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700719
720 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
721 discardableManager->unlockAndDeleteAll();
722}
Khushald4160832018-05-23 18:16:00 -0700723
724DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
725 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
726 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400727 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700728
729 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
730 auto tfData = server.serializeTypeface(serverTf.get());
731 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
732 REPORTER_ASSERT(reporter, clientTf);
733 int glyphCount = 10;
734 auto clientBlob = buildTextBlob(clientTf, glyphCount);
735
736 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000737 SkPaint paint;
738 SkMatrix matrix = SkMatrix::I();
739 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700740 REPORTER_ASSERT(reporter,
741 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
742 REPORTER_ASSERT(reporter,
743 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
744
745 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
746 // miss.
747 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
748 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
749
750 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
751 discardableManager->unlockAndDeleteAll();
752}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400753
Herb Derbye384a1e2019-05-21 11:27:40 -0400754sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
755 sk_sp<SkTypeface> clientTf = nullptr) {
756 SkFont font;
757 font.setTypeface(serverTf);
758 font.setSize(textSize);
759
760 const char* text = ToolUtils::emoji_sample_text();
761 SkFont serverFont = font;
762 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
763 if (clientTf == nullptr) return blob;
764
765 SkSerialProcs s_procs;
766 s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
767 return SkData::MakeUninitialized(1u);
768 };
769 auto serialized = blob->serialize(s_procs);
770
771 SkDeserialProcs d_procs;
772 d_procs.fTypefaceCtx = &clientTf;
773 d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
774 return *(static_cast<sk_sp<SkTypeface>*>(ctx));
775 };
776 return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
777}
778
779DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
780 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
781 SkStrikeServer server(discardableManager.get());
782 SkStrikeClient client(discardableManager, false);
783
784 auto serverTf = ToolUtils::emoji_typeface();
785 auto serverTfData = server.serializeTypeface(serverTf.get());
786 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
787
Mike Reed69aaee02019-05-30 11:40:51 +0000788 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400789 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
790 auto props = FindSurfaceProps(ctxInfo.grContext());
791 SkTextBlobCacheDiffCanvas cache_diff_canvas(500, 500, props, &server,
792 MakeSettings(ctxInfo.grContext()));
793 SkPaint paint;
Mike Reed69aaee02019-05-30 11:40:51 +0000794 cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400795
796 std::vector<uint8_t> serverStrikeData;
797 server.writeStrikeData(&serverStrikeData);
798
799 REPORTER_ASSERT(reporter,
800 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
801 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
802 REPORTER_ASSERT(reporter, clientBlob);
803
Mike Reed69aaee02019-05-30 11:40:51 +0000804 RasterBlob(clientBlob, 500, 500, paint, ctxInfo.grContext());
Herb Derbye384a1e2019-05-21 11:27:40 -0400805 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
806 SkStrikeCache::ValidateGlyphCacheDataSize();
807 discardableManager->resetCacheMissCounts();
808 }
809
810 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
811 discardableManager->unlockAndDeleteAll();
812}
813
Herb Derby65b7bfc2018-06-05 13:32:12 -0400814DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
Khushal8523b6b2018-06-12 11:26:17 -0700815 // Build proxy typeface on the client for initializing the cache.
816 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
817 SkStrikeServer server(discardableManager.get());
818 SkStrikeClient client(discardableManager, false);
819
820 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
821 auto tfData = server.serializeTypeface(serverTf.get());
822 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
823 REPORTER_ASSERT(reporter, clientTf);
824
Mike Reed4529cb52018-11-06 08:03:42 -0500825 SkFont font;
826 font.setTypeface(clientTf);
Herb Derby511dcfc2019-06-24 12:58:41 -0400827 font.setSubpixel(true);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400828 SkPaint paint;
829 paint.setAntiAlias(true);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400830 paint.setColor(SK_ColorRED);
831
832 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400833 const uint8_t glyphImage[] = {0xFF, 0xFF};
834
Herb Derby5c0c7982018-06-21 15:15:50 -0400835 SkStrikeCache strikeCache;
836
Herb Derby65b7bfc2018-06-05 13:32:12 -0400837 // Build a fallback cache.
838 {
839 SkAutoDescriptor ad;
840 SkScalerContextRec rec;
841 SkScalerContextEffects effects;
842 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbyc3415002018-11-08 16:40:26 -0500843 SkScalerContext::MakeRecAndEffects(
844 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500845 SkMatrix::I(), &rec, &effects);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400846 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
847
Herb Derby5c0c7982018-06-21 15:15:50 -0400848 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Herb Derby37216882019-06-13 17:24:24 -0400849 SkGlyphPrototype proto = {lostGlyphID, 0.f, 0.f, 2, 1, 0, 0, SkMask::kA8_Format, false};
Herb Derby511dcfc2019-06-24 12:58:41 -0400850 fallbackCache->glyphFromPrototype(proto, (void*)glyphImage);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400851 }
852
853 // Make sure we can find the fall back cache.
854 {
855 SkAutoDescriptor ad;
856 SkScalerContextRec rec;
857 SkScalerContextEffects effects;
858 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbyc3415002018-11-08 16:40:26 -0500859 SkScalerContext::MakeRecAndEffects(
860 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500861 SkMatrix::I(), &rec, &effects);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400862 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400863 auto testCache = strikeCache.findStrikeExclusive(*desc);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400864 REPORTER_ASSERT(reporter, !(testCache == nullptr));
865 }
866
Khushal8523b6b2018-06-12 11:26:17 -0700867 // Create the target cache.
868 SkExclusiveStrikePtr testCache;
869 SkAutoDescriptor ad;
870 SkScalerContextRec rec;
871 SkScalerContextEffects effects;
872 SkScalerContextFlags flags = SkScalerContextFlags::kNone;
Herb Derbyc3415002018-11-08 16:40:26 -0500873 SkScalerContext::MakeRecAndEffects(
874 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500875 SkMatrix::I(), &rec, &effects);
Khushal8523b6b2018-06-12 11:26:17 -0700876 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400877 testCache = strikeCache.findStrikeExclusive(*desc);
Khushal8523b6b2018-06-12 11:26:17 -0700878 REPORTER_ASSERT(reporter, testCache == nullptr);
Herb Derby5c0c7982018-06-21 15:15:50 -0400879 testCache = strikeCache.createStrikeExclusive(*desc,
Khushal8523b6b2018-06-12 11:26:17 -0700880 clientTf->createScalerContext(effects, desc));
Herb Derby5c0c7982018-06-21 15:15:50 -0400881 auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
882 scalerProxy->initCache(testCache.get(), &strikeCache);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400883
Khushal8523b6b2018-06-12 11:26:17 -0700884 // Look for the lost glyph.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400885 {
Herb Derby511dcfc2019-06-24 12:58:41 -0400886 SkPoint pt{SkFixedToScalar(lostGlyphID.getSubXFixed()),
887 SkFixedToScalar(lostGlyphID.getSubYFixed())};
888 SkGlyph* lostGlyph = testCache->glyph(lostGlyphID.code(), pt);
Herb Derbya4eecd82019-06-25 15:05:30 -0400889 testCache->prepareImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400890
Herb Derby511dcfc2019-06-24 12:58:41 -0400891 REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
892 REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
893 REPORTER_ASSERT(reporter, lostGlyph->maskFormat() == SkMask::kA8_Format);
894 REPORTER_ASSERT(reporter, memcmp(lostGlyph->image(), glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400895 }
896
Khushal8523b6b2018-06-12 11:26:17 -0700897 // Look for the lost glyph with a different sub-pix position.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400898 {
Herb Derby511dcfc2019-06-24 12:58:41 -0400899 SkPoint pt{SkFixedToScalar(SK_FixedQuarter),
900 SkFixedToScalar(SK_FixedQuarter)};
901 SkGlyph* lostGlyph = testCache->glyph(lostGlyphID.code(), pt);
Herb Derbya4eecd82019-06-25 15:05:30 -0400902 testCache->prepareImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400903
Herb Derby511dcfc2019-06-24 12:58:41 -0400904 REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
905 REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
906 REPORTER_ASSERT(reporter, lostGlyph->maskFormat() == SkMask::kA8_Format);
907 REPORTER_ASSERT(reporter, memcmp(lostGlyph->image(), glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400908 }
909
Khushal8523b6b2018-06-12 11:26:17 -0700910 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
911 if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
912 i == SkStrikeClient::CacheMissType::kFontMetrics) {
913 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
914 } else {
915 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
916 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400917 }
Herb Derby5c0c7982018-06-21 15:15:50 -0400918 strikeCache.validateGlyphCacheDataSize();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400919
Khushal8523b6b2018-06-12 11:26:17 -0700920 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
921 discardableManager->unlockAndDeleteAll();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400922}
Khushal4010c792018-06-13 09:44:23 -0700923
924DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
925 // Build proxy typeface on the client for initializing the cache.
926 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
927 SkStrikeServer server(discardableManager.get());
928 SkStrikeClient client(discardableManager, false);
929
930 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
931 auto tfData = server.serializeTypeface(serverTf.get());
932 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
933 REPORTER_ASSERT(reporter, clientTf);
934
Mike Reed4529cb52018-11-06 08:03:42 -0500935 SkFont font;
Herb Derbye7f662b2018-12-17 12:12:56 -0500936 font.setEdging(SkFont::Edging::kAntiAlias);
Khushal4010c792018-06-13 09:44:23 -0700937 SkPaint paint;
Khushal4010c792018-06-13 09:44:23 -0700938 paint.setColor(SK_ColorRED);
939
940 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
941 const uint8_t glyphImage[] = {0xFF, 0xFF};
Herb Derby37216882019-06-13 17:24:24 -0400942 SkMask::Format realMask;
943 SkMask::Format fakeMask;
Khushal4010c792018-06-13 09:44:23 -0700944
Herb Derby5c0c7982018-06-21 15:15:50 -0400945 SkStrikeCache strikeCache;
946
Khushal4010c792018-06-13 09:44:23 -0700947 {
948 SkAutoDescriptor ad;
949 SkScalerContextRec rec;
950 SkScalerContextEffects effects;
951 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500952 font.setTypeface(serverTf);
Herb Derbyc3415002018-11-08 16:40:26 -0500953 SkScalerContext::MakeRecAndEffects(
954 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500955 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -0700956 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
957
958 auto context = serverTf->createScalerContext(effects, desc, false);
Herb Derbyf6fca262019-01-09 15:13:54 -0500959 SkGlyph glyph{lostGlyphID};
Khushal4010c792018-06-13 09:44:23 -0700960 context->getMetrics(&glyph);
Herb Derby37216882019-06-13 17:24:24 -0400961 realMask = glyph.maskFormat();
Khushal4010c792018-06-13 09:44:23 -0700962 }
963
964 // Build a fallback cache.
965 {
966 SkAutoDescriptor ad;
967 SkScalerContextRec rec;
968 SkScalerContextEffects effects;
969 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500970 font.setTypeface(clientTf);
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
Herb Derby5c0c7982018-06-21 15:15:50 -0400976 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Khushal4010c792018-06-13 09:44:23 -0700977 fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
Herb Derby37216882019-06-13 17:24:24 -0400978 SkGlyphPrototype proto = {lostGlyphID, 0.f, 0.f, 2, 1, 0, 0, fakeMask, false};
Herb Derby511dcfc2019-06-24 12:58:41 -0400979 fallbackCache->glyphFromPrototype(proto, (void *)glyphImage);
Khushal4010c792018-06-13 09:44:23 -0700980 }
981
982 // Send over the real glyph and make sure the client cache stays intact.
983 {
984 SkAutoDescriptor ad;
Khushal4010c792018-06-13 09:44:23 -0700985 SkScalerContextEffects effects;
986 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500987 font.setTypeface(serverTf);
Herb Derbyc03716d2018-09-17 11:39:51 -0400988 auto* cacheState = server.getOrCreateCache(
Herb Derbye7f662b2018-12-17 12:12:56 -0500989 paint, font, SkSurfacePropsCopyOrDefault(nullptr),
Herb Derbyc03716d2018-09-17 11:39:51 -0400990 SkMatrix::I(), flags, &effects);
Herb Derbyb2c72162018-08-23 16:16:31 -0400991 cacheState->addGlyph(lostGlyphID, false);
Khushal4010c792018-06-13 09:44:23 -0700992
993 std::vector<uint8_t> serverStrikeData;
994 server.writeStrikeData(&serverStrikeData);
995 REPORTER_ASSERT(reporter,
Herb Derby5c0c7982018-06-21 15:15:50 -0400996 client.readStrikeData(
997 serverStrikeData.data(),
998 serverStrikeData.size()));
Khushal4010c792018-06-13 09:44:23 -0700999 }
1000
1001 {
1002 SkAutoDescriptor ad;
1003 SkScalerContextRec rec;
1004 SkScalerContextEffects effects;
1005 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -05001006 font.setTypeface(clientTf);
Herb Derbyc3415002018-11-08 16:40:26 -05001007 SkScalerContext::MakeRecAndEffects(
1008 font, paint, SkSurfaceProps(0, kUnknown_SkPixelGeometry), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -05001009 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -07001010 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
1011
Herb Derby5c0c7982018-06-21 15:15:50 -04001012 auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
Khushal4010c792018-06-13 09:44:23 -07001013 REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
Herb Derby511dcfc2019-06-24 12:58:41 -04001014 auto glyph = fallbackCache->glyphOrNull(lostGlyphID);
1015 REPORTER_ASSERT(reporter, glyph && glyph->maskFormat() == fakeMask);
1016 if (glyph) {
1017 REPORTER_ASSERT(reporter,
1018 memcmp(glyph->image(), glyphImage, glyph->imageSize()) == 0);
1019 }
Khushal4010c792018-06-13 09:44:23 -07001020 }
1021
Herb Derby5c0c7982018-06-21 15:15:50 -04001022 strikeCache.validateGlyphCacheDataSize();
Khushal4010c792018-06-13 09:44:23 -07001023
1024 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
1025 discardableManager->unlockAndDeleteAll();
1026}