blob: c173328a8900f9f4c33c6ff658610eb8bcc2fb45 [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 Reedac9f0c92020-12-23 10:11:33 -05008#include "include/core/SkBitmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/core/SkGraphics.h"
10#include "include/core/SkSurface.h"
11#include "include/core/SkTextBlob.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040012#include "include/gpu/GrDirectContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/private/SkMutex.h"
14#include "src/core/SkDraw.h"
15#include "src/core/SkRemoteGlyphCache.h"
Herb Derby81e84a62020-02-14 11:47:35 -050016#include "src/core/SkScalerCache.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/core/SkStrikeCache.h"
Herb Derbyd249e8c2019-06-03 11:36:01 -040018#include "src/core/SkStrikeSpec.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/core/SkSurfacePriv.h"
20#include "src/core/SkTypeface_remote.h"
Adlai Hollera0693042020-10-14 11:23:11 -040021#include "src/gpu/GrDirectContextPriv.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040022#include "src/gpu/GrRecordingContextPriv.h"
23#include "src/gpu/text/GrSDFTOptions.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "tests/Test.h"
25#include "tools/Resources.h"
26#include "tools/ToolUtils.h"
27#include "tools/fonts/TestEmptyTypeface.h"
Khushal38a08432018-05-02 10:29:37 -070028
29class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
30 public SkStrikeClient::DiscardableHandleManager {
31public:
Khushald4160832018-05-23 18:16:00 -070032 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070033 ~DiscardableManager() override = default;
34
35 // Server implementation.
36 SkDiscardableHandleId createHandle() override {
Herb Derby9b869552019-05-10 12:16:17 -040037 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070038
Khushal38a08432018-05-02 10:29:37 -070039 // Handles starts as locked.
40 fLockedHandles.add(++fNextHandleId);
41 return fNextHandleId;
42 }
43 bool lockHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040044 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070045
Khushal38a08432018-05-02 10:29:37 -070046 if (id <= fLastDeletedHandleId) return false;
47 fLockedHandles.add(id);
48 return true;
49 }
50
51 // Client implementation.
Khushal3de67bd2019-03-15 14:43:15 -070052 bool deleteHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040053 SkAutoMutexExclusive l(fMutex);
Khushal38a08432018-05-02 10:29:37 -070054
Khushal3de67bd2019-03-15 14:43:15 -070055 return id <= fLastDeletedHandleId;
56 }
57
58 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
Herb Derby9b869552019-05-10 12:16:17 -040059 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070060
61 fCacheMissCount[type]++;
62 }
63 bool isHandleDeleted(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040064 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070065
66 return id <= fLastDeletedHandleId;
67 }
68
69 void unlockAll() {
Herb Derby9b869552019-05-10 12:16:17 -040070 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070071
72 fLockedHandles.reset();
73 }
Khushal38a08432018-05-02 10:29:37 -070074 void unlockAndDeleteAll() {
Herb Derby9b869552019-05-10 12:16:17 -040075 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070076
77 fLockedHandles.reset();
Khushal38a08432018-05-02 10:29:37 -070078 fLastDeletedHandleId = fNextHandleId;
79 }
Khushal3de67bd2019-03-15 14:43:15 -070080 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
Herb Derby9b869552019-05-10 12:16:17 -040081 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070082
83 return fLockedHandles;
84 }
85 SkDiscardableHandleId handleCount() {
Herb Derby9b869552019-05-10 12:16:17 -040086 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070087
88 return fNextHandleId;
89 }
90 int cacheMissCount(uint32_t type) {
Herb Derby9b869552019-05-10 12:16:17 -040091 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070092
93 return fCacheMissCount[type];
94 }
Khushalfa8ff092018-06-06 17:46:38 -070095 bool hasCacheMiss() const {
Herb Derby9b869552019-05-10 12:16:17 -040096 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070097
Khushalfa8ff092018-06-06 17:46:38 -070098 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
Hal Canarye107faa2019-10-23 12:52:33 -040099 if (fCacheMissCount[i] > 0) { return true; }
Khushalfa8ff092018-06-06 17:46:38 -0700100 }
101 return false;
102 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400103 void resetCacheMissCounts() {
104 SkAutoMutexExclusive l(fMutex);
105 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
106 }
Khushal38a08432018-05-02 10:29:37 -0700107
108private:
Khushal3de67bd2019-03-15 14:43:15 -0700109 // The tests below run in parallel on multiple threads and use the same
110 // process global SkStrikeCache. So the implementation needs to be
111 // thread-safe.
112 mutable SkMutex fMutex;
113
Khushal38a08432018-05-02 10:29:37 -0700114 SkDiscardableHandleId fNextHandleId = 0u;
115 SkDiscardableHandleId fLastDeletedHandleId = 0u;
116 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -0700117 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -0700118};
119
120sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -0500121 SkFont font;
Khushal38a08432018-05-02 10:29:37 -0700122 font.setTypeface(tf);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400123 font.setHinting(SkFontHinting::kNormal);
Mike Reed2ed78202018-11-21 15:10:08 -0500124 font.setSize(1u);
125 font.setEdging(SkFont::Edging::kAntiAlias);
126 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -0700127
128 SkTextBlobBuilder builder;
129 SkRect bounds = SkRect::MakeWH(10, 10);
130 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
131 SkASSERT(runBuffer.utf8text == nullptr);
132 SkASSERT(runBuffer.clusters == nullptr);
133
134 for (int i = 0; i < glyphCount; i++) {
135 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
136 runBuffer.pos[i] = SkIntToScalar(i);
137 }
138 return builder.make();
139}
140
Chris Daltonf9a90a22018-08-28 14:17:55 -0600141static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
142 skiatest::Reporter* reporter, int tolerance = 0) {
143 SkASSERT(expected.width() == actual.width());
144 SkASSERT(expected.height() == actual.height());
145 for (int i = 0; i < expected.width(); ++i) {
146 for (int j = 0; j < expected.height(); ++j) {
147 SkColor expectedColor = expected.getColor(i, j);
148 SkColor actualColor = actual.getColor(i, j);
149 if (0 == tolerance) {
150 REPORTER_ASSERT(reporter, expectedColor == actualColor);
151 } else {
152 for (int k = 0; k < 4; ++k) {
153 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
154 int actualChannel = (actualColor >> (k*8)) & 0xff;
155 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
156 }
157 }
158 }
Khushal51371a42018-05-17 10:41:40 -0700159 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600160}
Khushal51371a42018-05-17 10:41:40 -0700161
Robert Phillipse94b4e12020-07-23 13:54:35 -0400162sk_sp<SkSurface> MakeSurface(int width, int height, GrRecordingContext* rContext) {
Herb Derbyc3415002018-11-08 16:40:26 -0500163 const SkImageInfo info =
164 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
Robert Phillipse94b4e12020-07-23 13:54:35 -0400165 return SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info);
Herb Derbyc3415002018-11-08 16:40:26 -0500166}
167
John Stilesec9b4aa2020-08-07 13:05:14 -0400168SkSurfaceProps FindSurfaceProps(GrRecordingContext* rContext) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400169 auto surface = MakeSurface(1, 1, rContext);
Herb Derbyc3415002018-11-08 16:40:26 -0500170 return surface->props();
171}
172
Ravi Mistrycd21d672018-05-29 21:45:46 +0000173SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Robert Phillipse94b4e12020-07-23 13:54:35 -0400174 GrRecordingContext* rContext, const SkMatrix* matrix = nullptr,
Herb Derby1a9971e2018-07-19 13:41:15 -0400175 SkScalar x = 0) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400176 auto surface = MakeSurface(width, height, rContext);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000177 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400178 surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
Khushal38a08432018-05-02 10:29:37 -0700179 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000180 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700181 surface->readPixels(bitmap, 0, 0);
182 return bitmap;
183}
184
185DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
186 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
187 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400188 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700189
190 auto server_tf = SkTypeface::MakeDefault();
191 auto tf_data = server.serializeTypeface(server_tf.get());
192
193 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
194 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700195 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700196 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700197
198 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
199 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700200}
201
Khushal3e7548c2018-05-23 15:45:01 -0700202DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400203 auto dContext = ctxInfo.directContext();
Khushal38a08432018-05-02 10:29:37 -0700204 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
205 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400206 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700207 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700208
209 // Server.
210 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
211 auto serverTfData = server.serializeTypeface(serverTf.get());
212
213 int glyphCount = 10;
214 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillipse94b4e12020-07-23 13:54:35 -0400215 auto props = FindSurfaceProps(dContext);
Mike Reedf922c782019-02-19 15:46:38 -0500216 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
Robert Phillipse94b4e12020-07-23 13:54:35 -0400217 dContext->supportsDistanceFieldText());
Khushal38a08432018-05-02 10:29:37 -0700218 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
219
220 std::vector<uint8_t> serverStrikeData;
221 server.writeStrikeData(&serverStrikeData);
222
223 // Client.
224 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
225 REPORTER_ASSERT(reporter,
226 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
227 auto clientBlob = buildTextBlob(clientTf, glyphCount);
228
Robert Phillipse94b4e12020-07-23 13:54:35 -0400229 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, dContext);
230 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, dContext);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600231 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700232 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700233
234 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
235 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700236}
237
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400238DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
239 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
240 SkStrikeServer server(discardableManager.get());
241 SkStrikeClient client(discardableManager, false);
242
243 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500244 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400245 auto serverTfData = server.serializeTypeface(serverTf.get());
246 REPORTER_ASSERT(reporter, serverTf->unique());
247
248 {
249 const SkPaint paint;
250 int glyphCount = 10;
251 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ben Wagnerae4bb982020-09-24 14:49:00 -0400252 const SkSurfaceProps props;
herb7022b772019-08-15 22:45:43 -0400253 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400254 10, 10, props, &server, ctxInfo.directContext()->supportsDistanceFieldText());
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400255 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
256 REPORTER_ASSERT(reporter, !serverTf->unique());
257
258 std::vector<uint8_t> serverStrikeData;
259 server.writeStrikeData(&serverStrikeData);
260 }
261 REPORTER_ASSERT(reporter, serverTf->unique());
262
263 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
264 discardableManager->unlockAndDeleteAll();
265}
266
Khushal38a08432018-05-02 10:29:37 -0700267DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
268 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
269 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400270 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700271
272 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
273 server.serializeTypeface(serverTf.get());
274 int glyphCount = 10;
275 auto serverBlob = buildTextBlob(serverTf, glyphCount);
276
Ben Wagnerae4bb982020-09-24 14:49:00 -0400277 const SkSurfaceProps props;
Mike Reedf922c782019-02-19 15:46:38 -0500278 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700279 SkPaint paint;
280 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
281
282 // The strike from the blob should be locked after it has been drawn on the canvas.
283 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
284 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
285
286 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
287 // again.
288 std::vector<uint8_t> fontData;
289 server.writeStrikeData(&fontData);
290 discardableManager->unlockAll();
291 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
292
293 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
294 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
295 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700296
297 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
298 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700299}
300
301DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
302 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
303 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400304 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700305
306 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
307 server.serializeTypeface(serverTf.get());
308 int glyphCount = 10;
309 auto serverBlob = buildTextBlob(serverTf, glyphCount);
310
Ben Wagnerae4bb982020-09-24 14:49:00 -0400311 const SkSurfaceProps props;
Mike Reedf922c782019-02-19 15:46:38 -0500312 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700313 SkPaint paint;
314 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
315 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
316
317 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
318 // handles.
319 std::vector<uint8_t> fontData;
320 server.writeStrikeData(&fontData);
Khushal498a9b22019-09-04 16:19:22 -0700321
322 // Another analysis pass, to ensure that deleting handles after a complete cache hit still
323 // works. This is a regression test for crbug.com/999682.
324 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
325 server.writeStrikeData(&fontData);
326 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
327
Khushal38a08432018-05-02 10:29:37 -0700328 discardableManager->unlockAndDeleteAll();
329 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700330 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700331
332 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
333 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700334}
335
336DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
337 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
338 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400339 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700340
341 // Server.
342 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
343 auto serverTfData = server.serializeTypeface(serverTf.get());
344
345 int glyphCount = 10;
346 auto serverBlob = buildTextBlob(serverTf, glyphCount);
347
Ben Wagnerae4bb982020-09-24 14:49:00 -0400348 const SkSurfaceProps props;
Mike Reedf922c782019-02-19 15:46:38 -0500349 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700350 SkPaint paint;
351 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
352
353 std::vector<uint8_t> serverStrikeData;
354 server.writeStrikeData(&serverStrikeData);
355
356 // Client.
357 REPORTER_ASSERT(reporter,
358 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
359 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
360
361 // The cache remains alive until it is pinned in the discardable manager.
362 SkGraphics::PurgeFontCache();
363 REPORTER_ASSERT(reporter, !clientTf->unique());
364
365 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
366 // clientTf.
367 discardableManager->unlockAndDeleteAll();
368 SkGraphics::PurgeFontCache();
369 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700370
371 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
372 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700373}
Khushalb2e71272018-05-15 12:59:48 -0700374
375DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
376 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
377 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400378 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700379
380 // Server.
381 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
382 auto serverTfData = server.serializeTypeface(serverTf.get());
383
384 int glyphCount = 10;
385 auto serverBlob = buildTextBlob(serverTf, glyphCount);
386
Ben Wagnerae4bb982020-09-24 14:49:00 -0400387 const SkSurfaceProps props;
Mike Reedf922c782019-02-19 15:46:38 -0500388 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalb2e71272018-05-15 12:59:48 -0700389 SkPaint paint;
390 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
391
392 std::vector<uint8_t> serverStrikeData;
393 server.writeStrikeData(&serverStrikeData);
394
395 // Client.
396 REPORTER_ASSERT(reporter,
397 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Khushal3e7548c2018-05-23 15:45:01 -0700398
399 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
400 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700401}
Khushal51371a42018-05-17 10:41:40 -0700402
Khushalcf33b1b2018-08-29 16:16:25 -0700403DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
404 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
405 SkStrikeServer server(discardableManager.get());
406 server.setMaxEntriesInDescriptorMapForTesting(1u);
407 SkStrikeClient client(discardableManager, false);
408
409 {
410 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
411 int glyphCount = 10;
412 auto serverBlob = buildTextBlob(serverTf, glyphCount);
413
Ben Wagnerae4bb982020-09-24 14:49:00 -0400414 const SkSurfaceProps props;
Mike Reedf922c782019-02-19 15:46:38 -0500415 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700416 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400417 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
Khushalcf33b1b2018-08-29 16:16:25 -0700418 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400419 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700420 }
421
422 // Serialize to release the lock from the strike server and delete all current
423 // handles.
424 std::vector<uint8_t> fontData;
425 server.writeStrikeData(&fontData);
426 discardableManager->unlockAndDeleteAll();
427
428 // Use a different typeface. Creating a new strike should evict the previous
429 // one.
430 {
431 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
432 int glyphCount = 10;
433 auto serverBlob = buildTextBlob(serverTf, glyphCount);
434
Ben Wagnerae4bb982020-09-24 14:49:00 -0400435 const SkSurfaceProps props;
Mike Reedf922c782019-02-19 15:46:38 -0500436 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700437 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400438 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700439 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400440 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700441 }
442
443 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
444 discardableManager->unlockAndDeleteAll();
445}
446
Khushal3e7548c2018-05-23 15:45:01 -0700447DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400448 auto direct = ctxInfo.directContext();
Khushal51371a42018-05-17 10:41:40 -0700449 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
450 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400451 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700452 SkPaint paint;
453 paint.setStyle(SkPaint::kStroke_Style);
454 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400455 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400456 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700457
458 // Server.
459 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
460 auto serverTfData = server.serializeTypeface(serverTf.get());
461
462 int glyphCount = 10;
463 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillips6d344c32020-07-06 10:56:46 -0400464 auto props = FindSurfaceProps(direct);
herb7022b772019-08-15 22:45:43 -0400465 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400466 10, 10, props, &server, direct->supportsDistanceFieldText());
Khushal51371a42018-05-17 10:41:40 -0700467 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
468
469 std::vector<uint8_t> serverStrikeData;
470 server.writeStrikeData(&serverStrikeData);
471
472 // Client.
473 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
474 REPORTER_ASSERT(reporter,
475 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
476 auto clientBlob = buildTextBlob(clientTf, glyphCount);
477
Robert Phillips6d344c32020-07-06 10:56:46 -0400478 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct);
479 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600480 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700481 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700482
483 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
484 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700485}
Khushal3e7548c2018-05-23 15:45:01 -0700486
Herb Derby8e318fd2018-08-29 11:04:18 -0400487sk_sp<SkTextBlob> make_blob_causing_fallback(
488 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500489 SkFont font;
490 font.setSubpixel(true);
491 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400492 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500493 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400494
Herb Derbyd249e8c2019-06-03 11:36:01 -0400495 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400496 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400497
498 char s[] = "Skia";
499 int runSize = strlen(s);
500
501 SkTextBlobBuilder builder;
502 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500503 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400504 SkASSERT(runBuffer.utf8text == nullptr);
505 SkASSERT(runBuffer.clusters == nullptr);
506
Mike Reed64670cb2019-04-16 11:37:38 -0700507 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
508 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400509
510 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500511 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400512
Herb Derby5fd955e2019-01-16 11:23:29 -0500513 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400514
515 for (int i = 0; i < runSize; i++) {
516 runBuffer.pos[i] = i * 10;
517 }
518
519 return builder.make();
520}
521
522DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
523 reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400524 auto direct = ctxInfo.directContext();
Herb Derby8e318fd2018-08-29 11:04:18 -0400525 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
526 SkStrikeServer server(discardableManager.get());
527 SkStrikeClient client(discardableManager, false);
528
529 SkPaint paint;
530
531 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
532 // TODO: when the cq bots can handle this font remove the check.
533 if (serverTf == nullptr) {
534 return;
535 }
536 auto serverTfData = server.serializeTypeface(serverTf.get());
537
538 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
539
Robert Phillips6d344c32020-07-06 10:56:46 -0400540 auto props = FindSurfaceProps(direct);
herb7022b772019-08-15 22:45:43 -0400541 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400542 10, 10, props, &server, direct->supportsDistanceFieldText());
Herb Derby8e318fd2018-08-29 11:04:18 -0400543 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
544
545 std::vector<uint8_t> serverStrikeData;
546 server.writeStrikeData(&serverStrikeData);
547
548 // Client.
549 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
550 REPORTER_ASSERT(reporter,
551 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
552
553 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
554
Robert Phillips6d344c32020-07-06 10:56:46 -0400555 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct);
556 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct);
Herb Derby8e318fd2018-08-29 11:04:18 -0400557 compare_blobs(expected, actual, reporter);
558 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby8e318fd2018-08-29 11:04:18 -0400559
560 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
561 discardableManager->unlockAndDeleteAll();
562}
563
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400564#if 0
565// TODO: turn this one when I figure out how to deal with the pixel variance from linear
566// interpolation from GPU to GPU.
567DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
568 reporter, ctxInfo) {
569 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
570 SkStrikeServer server(discardableManager.get());
571 SkStrikeClient client(discardableManager, false);
572
573 SkPaint paint;
574
575 auto serverTf = ToolUtils::planet_typeface();
576 // TODO: when the cq bots can handle this font remove the check.
577 if (serverTf == nullptr) {
578 return;
579 }
580 auto serverTfData = server.serializeTypeface(serverTf.get());
581
582 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
583 SkFont font;
584 font.setSubpixel(true);
585 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400586 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400587 font.setTypeface(typeface);
588
589 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
590
591 // Mercury to Uranus.
592 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
593
594 SkTextBlobBuilder builder;
595 SkRect bounds = SkRect::MakeIWH(100, 100);
596 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
597 SkASSERT(runBuffer.utf8text == nullptr);
598 SkASSERT(runBuffer.clusters == nullptr);
599
600 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
601
602 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
603 runBuffer.pos[i] = i * 100;
604 }
605
606 return builder.make();
607 };
608
609 auto serverBlob = makeBlob(serverTf);
610
611 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400612 SkTextBlobCacheDiffCanvas cache_diff_canvas(
613 800, 800, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400614 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
615
616 std::vector<uint8_t> serverStrikeData;
617 server.writeStrikeData(&serverStrikeData);
618
619 // Client.
620 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
621 REPORTER_ASSERT(reporter,
622 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
623
624 auto clientBlob = makeBlob(clientTf);
625
626 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
627 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
628
629 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
630 // interpolation.
631 compare_blobs(expected, actual, reporter, 36);
632 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400633
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) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400640 auto direct = ctxInfo.directContext();
Herb Derby1a9971e2018-07-19 13:41:15 -0400641 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
642 SkStrikeServer server(discardableManager.get());
643 SkStrikeClient client(discardableManager, false);
644 SkPaint paint;
645 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400646
647 // Server.
648 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
649 auto serverTfData = server.serializeTypeface(serverTf.get());
650
651 int glyphCount = 10;
652 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillips6d344c32020-07-06 10:56:46 -0400653 auto props = FindSurfaceProps(direct);
herb7022b772019-08-15 22:45:43 -0400654 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400655 10, 10, props, &server, direct->supportsDistanceFieldText());
Herb Derby1a9971e2018-07-19 13:41:15 -0400656 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
657
658 std::vector<uint8_t> serverStrikeData;
659 server.writeStrikeData(&serverStrikeData);
660
661 // Client.
662 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
663 REPORTER_ASSERT(reporter,
664 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
665 auto clientBlob = buildTextBlob(clientTf, glyphCount);
666
Robert Phillips6d344c32020-07-06 10:56:46 -0400667 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct, nullptr, 0.5);
668 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct, nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600669 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400670 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby1a9971e2018-07-19 13:41:15 -0400671
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) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400677 auto direct = ctxInfo.directContext();
Khushal3e7548c2018-05-23 15:45:01 -0700678 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
679 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400680 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700681 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500682 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700683
Jim Van Verthce3cf802019-10-10 11:06:20 -0400684 // A scale transform forces fallback to dft.
Mike Reed1f607332020-05-21 12:11:27 -0400685 SkMatrix matrix = SkMatrix::Scale(16, 16);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000686 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Robert Phillips6d344c32020-07-06 10:56:46 -0400687 GrSDFTOptions options = direct->priv().asRecordingContext()->priv().SDFTOptions();
Herb Derby45fe2e82020-06-12 14:30:05 -0400688 REPORTER_ASSERT(reporter,
689 options.canDrawAsDistanceFields(paint, font, matrix, surfaceProps, true));
Khushal3e7548c2018-05-23 15:45:01 -0700690
691 // Server.
692 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
693 auto serverTfData = server.serializeTypeface(serverTf.get());
694
695 int glyphCount = 10;
696 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ben Wagnerae4bb982020-09-24 14:49:00 -0400697 const SkSurfaceProps props;
herb7022b772019-08-15 22:45:43 -0400698 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400699 10, 10, props, &server, direct->supportsDistanceFieldText());
Khushal3e7548c2018-05-23 15:45:01 -0700700 cache_diff_canvas.concat(matrix);
701 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
702
703 std::vector<uint8_t> serverStrikeData;
704 server.writeStrikeData(&serverStrikeData);
705
706 // Client.
707 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
708 REPORTER_ASSERT(reporter,
709 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
710 auto clientBlob = buildTextBlob(clientTf, glyphCount);
711
Robert Phillips6d344c32020-07-06 10:56:46 -0400712 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct, &matrix);
713 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct, &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600714 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700715 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700716
717 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
718 discardableManager->unlockAndDeleteAll();
719}
Khushald4160832018-05-23 18:16:00 -0700720
721DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
722 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
723 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400724 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700725
726 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
727 auto tfData = server.serializeTypeface(serverTf.get());
728 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
729 REPORTER_ASSERT(reporter, clientTf);
730 int glyphCount = 10;
731 auto clientBlob = buildTextBlob(clientTf, glyphCount);
732
733 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000734 SkPaint paint;
735 SkMatrix matrix = SkMatrix::I();
Robert Phillips6d344c32020-07-06 10:56:46 -0400736 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.directContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700737 REPORTER_ASSERT(reporter,
738 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
739 REPORTER_ASSERT(reporter,
740 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
741
742 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
743 // miss.
744 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
745 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
746
747 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
748 discardableManager->unlockAndDeleteAll();
749}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400750
Herb Derbye384a1e2019-05-21 11:27:40 -0400751sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
752 sk_sp<SkTypeface> clientTf = nullptr) {
753 SkFont font;
754 font.setTypeface(serverTf);
755 font.setSize(textSize);
756
757 const char* text = ToolUtils::emoji_sample_text();
758 SkFont serverFont = font;
759 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
760 if (clientTf == nullptr) return blob;
761
762 SkSerialProcs s_procs;
763 s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
764 return SkData::MakeUninitialized(1u);
765 };
766 auto serialized = blob->serialize(s_procs);
767
768 SkDeserialProcs d_procs;
769 d_procs.fTypefaceCtx = &clientTf;
770 d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
771 return *(static_cast<sk_sp<SkTypeface>*>(ctx));
772 };
773 return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
774}
775
776DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400777 auto direct = ctxInfo.directContext();
Herb Derbye384a1e2019-05-21 11:27:40 -0400778 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
779 SkStrikeServer server(discardableManager.get());
780 SkStrikeClient client(discardableManager, false);
781
782 auto serverTf = ToolUtils::emoji_typeface();
783 auto serverTfData = server.serializeTypeface(serverTf.get());
784 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
785
Mike Reed69aaee02019-05-30 11:40:51 +0000786 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400787 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
Robert Phillips6d344c32020-07-06 10:56:46 -0400788 auto props = FindSurfaceProps(direct);
herb7022b772019-08-15 22:45:43 -0400789 SkTextBlobCacheDiffCanvas cache_diff_canvas(
Robert Phillips6d344c32020-07-06 10:56:46 -0400790 500, 500, props, &server, direct->supportsDistanceFieldText());
Herb Derbye384a1e2019-05-21 11:27:40 -0400791 SkPaint paint;
Mike Reed69aaee02019-05-30 11:40:51 +0000792 cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400793
794 std::vector<uint8_t> serverStrikeData;
795 server.writeStrikeData(&serverStrikeData);
Herb Derbyf5e9b422019-10-22 16:06:22 -0400796 if (!serverStrikeData.empty()) {
797 REPORTER_ASSERT(reporter,
798 client.readStrikeData(serverStrikeData.data(),
799 serverStrikeData.size()));
800 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400801 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
802 REPORTER_ASSERT(reporter, clientBlob);
803
Robert Phillips6d344c32020-07-06 10:56:46 -0400804 RasterBlob(clientBlob, 500, 500, paint, direct);
Herb Derbye384a1e2019-05-21 11:27:40 -0400805 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbye384a1e2019-05-21 11:27:40 -0400806 discardableManager->resetCacheMissCounts();
807 }
808
809 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
810 discardableManager->unlockAndDeleteAll();
811}
812