blob: 0df019327786655d5a9bff4dd8a6f7e9e1b9cd36 [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"
Robert Phillipscc44feb2021-07-06 12:21:37 -040021#include "src/gpu/GrCaps.h"
Adlai Hollera0693042020-10-14 11:23:11 -040022#include "src/gpu/GrDirectContextPriv.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040023#include "src/gpu/GrRecordingContextPriv.h"
Herb Derbybf2dd2a2021-03-04 10:13:22 -050024#include "src/gpu/text/GrSDFTControl.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "tests/Test.h"
26#include "tools/Resources.h"
27#include "tools/ToolUtils.h"
28#include "tools/fonts/TestEmptyTypeface.h"
Khushal38a08432018-05-02 10:29:37 -070029
30class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
31 public SkStrikeClient::DiscardableHandleManager {
32public:
Khushald4160832018-05-23 18:16:00 -070033 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070034 ~DiscardableManager() override = default;
35
36 // Server implementation.
37 SkDiscardableHandleId createHandle() override {
Herb Derby9b869552019-05-10 12:16:17 -040038 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070039
Khushal38a08432018-05-02 10:29:37 -070040 // Handles starts as locked.
41 fLockedHandles.add(++fNextHandleId);
42 return fNextHandleId;
43 }
44 bool lockHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040045 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070046
Khushal38a08432018-05-02 10:29:37 -070047 if (id <= fLastDeletedHandleId) return false;
48 fLockedHandles.add(id);
49 return true;
50 }
51
52 // Client implementation.
Khushal3de67bd2019-03-15 14:43:15 -070053 bool deleteHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040054 SkAutoMutexExclusive l(fMutex);
Khushal38a08432018-05-02 10:29:37 -070055
Khushal3de67bd2019-03-15 14:43:15 -070056 return id <= fLastDeletedHandleId;
57 }
58
Herb Derbye5ed50b2021-02-03 14:29:54 -050059 void notifyCacheMiss(SkStrikeClient::CacheMissType type, int fontSize) override {
Herb Derby9b869552019-05-10 12:16:17 -040060 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070061
62 fCacheMissCount[type]++;
63 }
64 bool isHandleDeleted(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040065 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070066
67 return id <= fLastDeletedHandleId;
68 }
69
70 void unlockAll() {
Herb Derby9b869552019-05-10 12:16:17 -040071 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070072
73 fLockedHandles.reset();
74 }
Khushal38a08432018-05-02 10:29:37 -070075 void unlockAndDeleteAll() {
Herb Derby9b869552019-05-10 12:16:17 -040076 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070077
78 fLockedHandles.reset();
Khushal38a08432018-05-02 10:29:37 -070079 fLastDeletedHandleId = fNextHandleId;
80 }
Khushal3de67bd2019-03-15 14:43:15 -070081 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
Herb Derby9b869552019-05-10 12:16:17 -040082 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070083
84 return fLockedHandles;
85 }
86 SkDiscardableHandleId handleCount() {
Herb Derby9b869552019-05-10 12:16:17 -040087 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070088
89 return fNextHandleId;
90 }
91 int cacheMissCount(uint32_t type) {
Herb Derby9b869552019-05-10 12:16:17 -040092 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070093
94 return fCacheMissCount[type];
95 }
Khushalfa8ff092018-06-06 17:46:38 -070096 bool hasCacheMiss() const {
Herb Derby9b869552019-05-10 12:16:17 -040097 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070098
Khushalfa8ff092018-06-06 17:46:38 -070099 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
Hal Canarye107faa2019-10-23 12:52:33 -0400100 if (fCacheMissCount[i] > 0) { return true; }
Khushalfa8ff092018-06-06 17:46:38 -0700101 }
102 return false;
103 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400104 void resetCacheMissCounts() {
105 SkAutoMutexExclusive l(fMutex);
106 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
107 }
Khushal38a08432018-05-02 10:29:37 -0700108
109private:
Khushal3de67bd2019-03-15 14:43:15 -0700110 // The tests below run in parallel on multiple threads and use the same
111 // process global SkStrikeCache. So the implementation needs to be
112 // thread-safe.
113 mutable SkMutex fMutex;
114
Khushal38a08432018-05-02 10:29:37 -0700115 SkDiscardableHandleId fNextHandleId = 0u;
116 SkDiscardableHandleId fLastDeletedHandleId = 0u;
117 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -0700118 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -0700119};
120
121sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -0500122 SkFont font;
Khushal38a08432018-05-02 10:29:37 -0700123 font.setTypeface(tf);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400124 font.setHinting(SkFontHinting::kNormal);
Mike Reed2ed78202018-11-21 15:10:08 -0500125 font.setSize(1u);
126 font.setEdging(SkFont::Edging::kAntiAlias);
127 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -0700128
129 SkTextBlobBuilder builder;
130 SkRect bounds = SkRect::MakeWH(10, 10);
131 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
132 SkASSERT(runBuffer.utf8text == nullptr);
133 SkASSERT(runBuffer.clusters == nullptr);
134
135 for (int i = 0; i < glyphCount; i++) {
136 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
137 runBuffer.pos[i] = SkIntToScalar(i);
138 }
139 return builder.make();
140}
141
Chris Daltonf9a90a22018-08-28 14:17:55 -0600142static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
143 skiatest::Reporter* reporter, int tolerance = 0) {
144 SkASSERT(expected.width() == actual.width());
145 SkASSERT(expected.height() == actual.height());
146 for (int i = 0; i < expected.width(); ++i) {
147 for (int j = 0; j < expected.height(); ++j) {
148 SkColor expectedColor = expected.getColor(i, j);
149 SkColor actualColor = actual.getColor(i, j);
150 if (0 == tolerance) {
151 REPORTER_ASSERT(reporter, expectedColor == actualColor);
152 } else {
153 for (int k = 0; k < 4; ++k) {
154 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
155 int actualChannel = (actualColor >> (k*8)) & 0xff;
156 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
157 }
158 }
159 }
Khushal51371a42018-05-17 10:41:40 -0700160 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600161}
Khushal51371a42018-05-17 10:41:40 -0700162
Robert Phillipse94b4e12020-07-23 13:54:35 -0400163sk_sp<SkSurface> MakeSurface(int width, int height, GrRecordingContext* rContext) {
Herb Derbyc3415002018-11-08 16:40:26 -0500164 const SkImageInfo info =
165 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
Robert Phillipse94b4e12020-07-23 13:54:35 -0400166 return SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info);
Herb Derbyc3415002018-11-08 16:40:26 -0500167}
168
John Stilesec9b4aa2020-08-07 13:05:14 -0400169SkSurfaceProps FindSurfaceProps(GrRecordingContext* rContext) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400170 auto surface = MakeSurface(1, 1, rContext);
Herb Derbyc3415002018-11-08 16:40:26 -0500171 return surface->props();
172}
173
Ravi Mistrycd21d672018-05-29 21:45:46 +0000174SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Robert Phillipse94b4e12020-07-23 13:54:35 -0400175 GrRecordingContext* rContext, const SkMatrix* matrix = nullptr,
Herb Derby1a9971e2018-07-19 13:41:15 -0400176 SkScalar x = 0) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400177 auto surface = MakeSurface(width, height, rContext);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000178 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400179 surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
Khushal38a08432018-05-02 10:29:37 -0700180 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000181 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700182 surface->readPixels(bitmap, 0, 0);
183 return bitmap;
184}
185
186DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
187 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
188 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400189 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700190
191 auto server_tf = SkTypeface::MakeDefault();
192 auto tf_data = server.serializeTypeface(server_tf.get());
193
194 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
195 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700196 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700197 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700198
199 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
200 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700201}
202
Khushal3e7548c2018-05-23 15:45:01 -0700203DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Robert Phillipse94b4e12020-07-23 13:54:35 -0400204 auto dContext = ctxInfo.directContext();
Khushal38a08432018-05-02 10:29:37 -0700205 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
206 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400207 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700208 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700209
210 // Server.
211 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
212 auto serverTfData = server.serializeTypeface(serverTf.get());
213
214 int glyphCount = 10;
215 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillipse94b4e12020-07-23 13:54:35 -0400216 auto props = FindSurfaceProps(dContext);
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400217 std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
218 10, 10, props, nullptr, dContext->supportsDistanceFieldText());
219 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700220
221 std::vector<uint8_t> serverStrikeData;
222 server.writeStrikeData(&serverStrikeData);
223
224 // Client.
225 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
226 REPORTER_ASSERT(reporter,
227 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
228 auto clientBlob = buildTextBlob(clientTf, glyphCount);
229
Robert Phillipse94b4e12020-07-23 13:54:35 -0400230 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, dContext);
231 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, dContext);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600232 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700233 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700234
235 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
236 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700237}
238
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400239DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
240 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
241 SkStrikeServer server(discardableManager.get());
242 SkStrikeClient client(discardableManager, false);
243
244 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500245 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400246 auto serverTfData = server.serializeTypeface(serverTf.get());
247 REPORTER_ASSERT(reporter, serverTf->unique());
248
249 {
250 const SkPaint paint;
251 int glyphCount = 10;
252 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ben Wagnerae4bb982020-09-24 14:49:00 -0400253 const SkSurfaceProps props;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400254 std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
255 10, 10, props, nullptr, ctxInfo.directContext()->supportsDistanceFieldText());
256 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400257 REPORTER_ASSERT(reporter, !serverTf->unique());
258
259 std::vector<uint8_t> serverStrikeData;
260 server.writeStrikeData(&serverStrikeData);
261 }
262 REPORTER_ASSERT(reporter, serverTf->unique());
263
264 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
265 discardableManager->unlockAndDeleteAll();
266}
267
Khushal38a08432018-05-02 10:29:37 -0700268DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
269 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
270 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400271 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700272
273 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
274 server.serializeTypeface(serverTf.get());
275 int glyphCount = 10;
276 auto serverBlob = buildTextBlob(serverTf, glyphCount);
277
Ben Wagnerae4bb982020-09-24 14:49:00 -0400278 const SkSurfaceProps props;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400279 std::unique_ptr<SkCanvas> cache_diff_canvas =
280 server.makeAnalysisCanvas(10, 10, props, nullptr, true);
Khushal38a08432018-05-02 10:29:37 -0700281 SkPaint paint;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400282 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700283
284 // The strike from the blob should be locked after it has been drawn on the canvas.
285 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
286 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
287
288 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
289 // again.
290 std::vector<uint8_t> fontData;
291 server.writeStrikeData(&fontData);
292 discardableManager->unlockAll();
293 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
294
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400295 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700296 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
297 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700298
299 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
300 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700301}
302
303DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
304 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
305 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400306 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700307
308 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
309 server.serializeTypeface(serverTf.get());
310 int glyphCount = 10;
311 auto serverBlob = buildTextBlob(serverTf, glyphCount);
312
Ben Wagnerae4bb982020-09-24 14:49:00 -0400313 const SkSurfaceProps props;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400314 std::unique_ptr<SkCanvas> cache_diff_canvas =
315 server.makeAnalysisCanvas(10, 10, props, nullptr, true);
Khushal38a08432018-05-02 10:29:37 -0700316 SkPaint paint;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400317 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700318 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
319
320 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
321 // handles.
322 std::vector<uint8_t> fontData;
323 server.writeStrikeData(&fontData);
Khushal498a9b22019-09-04 16:19:22 -0700324
325 // Another analysis pass, to ensure that deleting handles after a complete cache hit still
326 // works. This is a regression test for crbug.com/999682.
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400327 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal498a9b22019-09-04 16:19:22 -0700328 server.writeStrikeData(&fontData);
329 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
330
Khushal38a08432018-05-02 10:29:37 -0700331 discardableManager->unlockAndDeleteAll();
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400332 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700333 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700334
335 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
336 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700337}
338
339DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
340 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
341 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400342 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700343
344 // Server.
345 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
346 auto serverTfData = server.serializeTypeface(serverTf.get());
347
348 int glyphCount = 10;
349 auto serverBlob = buildTextBlob(serverTf, glyphCount);
350
Ben Wagnerae4bb982020-09-24 14:49:00 -0400351 const SkSurfaceProps props;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400352 std::unique_ptr<SkCanvas> cache_diff_canvas =
353 server.makeAnalysisCanvas(10, 10, props, nullptr, true);
Khushal38a08432018-05-02 10:29:37 -0700354 SkPaint paint;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400355 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700356
357 std::vector<uint8_t> serverStrikeData;
358 server.writeStrikeData(&serverStrikeData);
359
360 // Client.
361 REPORTER_ASSERT(reporter,
362 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
363 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
364
365 // The cache remains alive until it is pinned in the discardable manager.
366 SkGraphics::PurgeFontCache();
367 REPORTER_ASSERT(reporter, !clientTf->unique());
368
369 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
370 // clientTf.
371 discardableManager->unlockAndDeleteAll();
372 SkGraphics::PurgeFontCache();
373 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700374
375 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
376 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700377}
Khushalb2e71272018-05-15 12:59:48 -0700378
379DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
380 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
381 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400382 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700383
384 // Server.
385 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
386 auto serverTfData = server.serializeTypeface(serverTf.get());
387
388 int glyphCount = 10;
389 auto serverBlob = buildTextBlob(serverTf, glyphCount);
390
Ben Wagnerae4bb982020-09-24 14:49:00 -0400391 const SkSurfaceProps props;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400392 std::unique_ptr<SkCanvas> cache_diff_canvas =
393 server.makeAnalysisCanvas(10, 10, props, nullptr, true);
Khushalb2e71272018-05-15 12:59:48 -0700394 SkPaint paint;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400395 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushalb2e71272018-05-15 12:59:48 -0700396
397 std::vector<uint8_t> serverStrikeData;
398 server.writeStrikeData(&serverStrikeData);
399
400 // Client.
401 REPORTER_ASSERT(reporter,
402 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Khushal3e7548c2018-05-23 15:45:01 -0700403
404 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
405 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700406}
Khushal51371a42018-05-17 10:41:40 -0700407
Khushalcf33b1b2018-08-29 16:16:25 -0700408DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
409 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
410 SkStrikeServer server(discardableManager.get());
411 server.setMaxEntriesInDescriptorMapForTesting(1u);
412 SkStrikeClient client(discardableManager, false);
413
414 {
415 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
416 int glyphCount = 10;
417 auto serverBlob = buildTextBlob(serverTf, glyphCount);
418
Ben Wagnerae4bb982020-09-24 14:49:00 -0400419 const SkSurfaceProps props;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400420 std::unique_ptr<SkCanvas> cache_diff_canvas =
421 server.makeAnalysisCanvas(10, 10, props, nullptr, true);
Khushalcf33b1b2018-08-29 16:16:25 -0700422 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400423 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400424 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400425 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700426 }
427
428 // Serialize to release the lock from the strike server and delete all current
429 // handles.
430 std::vector<uint8_t> fontData;
431 server.writeStrikeData(&fontData);
432 discardableManager->unlockAndDeleteAll();
433
434 // Use a different typeface. Creating a new strike should evict the previous
435 // one.
436 {
437 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
438 int glyphCount = 10;
439 auto serverBlob = buildTextBlob(serverTf, glyphCount);
440
Ben Wagnerae4bb982020-09-24 14:49:00 -0400441 const SkSurfaceProps props;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400442 std::unique_ptr<SkCanvas> cache_diff_canvas =
443 server.makeAnalysisCanvas(10, 10, props, nullptr, true);
Khushalcf33b1b2018-08-29 16:16:25 -0700444 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400445 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400446 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400447 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700448 }
449
450 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
451 discardableManager->unlockAndDeleteAll();
452}
453
Khushal3e7548c2018-05-23 15:45:01 -0700454DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400455 auto direct = ctxInfo.directContext();
Khushal51371a42018-05-17 10:41:40 -0700456 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
457 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400458 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700459 SkPaint paint;
460 paint.setStyle(SkPaint::kStroke_Style);
461 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400462 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400463 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700464
465 // Server.
466 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
467 auto serverTfData = server.serializeTypeface(serverTf.get());
468
469 int glyphCount = 10;
470 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillips6d344c32020-07-06 10:56:46 -0400471 auto props = FindSurfaceProps(direct);
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400472 std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
473 10, 10, props, nullptr, direct->supportsDistanceFieldText());
474 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal51371a42018-05-17 10:41:40 -0700475
476 std::vector<uint8_t> serverStrikeData;
477 server.writeStrikeData(&serverStrikeData);
478
479 // Client.
480 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
481 REPORTER_ASSERT(reporter,
482 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
483 auto clientBlob = buildTextBlob(clientTf, glyphCount);
484
Robert Phillips6d344c32020-07-06 10:56:46 -0400485 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct);
486 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600487 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700488 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700489
490 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
491 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700492}
Khushal3e7548c2018-05-23 15:45:01 -0700493
Herb Derby8e318fd2018-08-29 11:04:18 -0400494sk_sp<SkTextBlob> make_blob_causing_fallback(
495 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500496 SkFont font;
497 font.setSubpixel(true);
498 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400499 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500500 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400501
Herb Derbyd249e8c2019-06-03 11:36:01 -0400502 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400503 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400504
505 char s[] = "Skia";
506 int runSize = strlen(s);
507
508 SkTextBlobBuilder builder;
509 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500510 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400511 SkASSERT(runBuffer.utf8text == nullptr);
512 SkASSERT(runBuffer.clusters == nullptr);
513
Mike Reed64670cb2019-04-16 11:37:38 -0700514 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
515 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400516
517 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500518 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400519
Herb Derby5fd955e2019-01-16 11:23:29 -0500520 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400521
522 for (int i = 0; i < runSize; i++) {
523 runBuffer.pos[i] = i * 10;
524 }
525
526 return builder.make();
527}
528
529DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
530 reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400531 auto direct = ctxInfo.directContext();
Herb Derby8e318fd2018-08-29 11:04:18 -0400532 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
533 SkStrikeServer server(discardableManager.get());
534 SkStrikeClient client(discardableManager, false);
535
536 SkPaint paint;
537
538 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
539 // TODO: when the cq bots can handle this font remove the check.
540 if (serverTf == nullptr) {
541 return;
542 }
543 auto serverTfData = server.serializeTypeface(serverTf.get());
544
545 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
546
Robert Phillips6d344c32020-07-06 10:56:46 -0400547 auto props = FindSurfaceProps(direct);
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400548 std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
549 10, 10, props, nullptr, direct->supportsDistanceFieldText());
550 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derby8e318fd2018-08-29 11:04:18 -0400551
552 std::vector<uint8_t> serverStrikeData;
553 server.writeStrikeData(&serverStrikeData);
554
555 // Client.
556 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
557 REPORTER_ASSERT(reporter,
558 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
559
560 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
561
Robert Phillips6d344c32020-07-06 10:56:46 -0400562 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct);
563 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct);
Herb Derby8e318fd2018-08-29 11:04:18 -0400564 compare_blobs(expected, actual, reporter);
565 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby8e318fd2018-08-29 11:04:18 -0400566
567 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
568 discardableManager->unlockAndDeleteAll();
569}
570
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400571#if 0
572// TODO: turn this one when I figure out how to deal with the pixel variance from linear
573// interpolation from GPU to GPU.
574DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
575 reporter, ctxInfo) {
576 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
577 SkStrikeServer server(discardableManager.get());
578 SkStrikeClient client(discardableManager, false);
579
580 SkPaint paint;
581
582 auto serverTf = ToolUtils::planet_typeface();
583 // TODO: when the cq bots can handle this font remove the check.
584 if (serverTf == nullptr) {
585 return;
586 }
587 auto serverTfData = server.serializeTypeface(serverTf.get());
588
589 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
590 SkFont font;
591 font.setSubpixel(true);
592 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400593 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400594 font.setTypeface(typeface);
595
596 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
597
598 // Mercury to Uranus.
599 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
600
601 SkTextBlobBuilder builder;
602 SkRect bounds = SkRect::MakeIWH(100, 100);
603 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
604 SkASSERT(runBuffer.utf8text == nullptr);
605 SkASSERT(runBuffer.clusters == nullptr);
606
607 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
608
609 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
610 runBuffer.pos[i] = i * 100;
611 }
612
613 return builder.make();
614 };
615
616 auto serverBlob = makeBlob(serverTf);
617
618 auto props = FindSurfaceProps(ctxInfo.grContext());
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400619 std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
620 10, 10, props, nullptr, ctxInfo.directContext()->supportsDistanceFieldText());
621 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 400, paint);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400622
623 std::vector<uint8_t> serverStrikeData;
624 server.writeStrikeData(&serverStrikeData);
625
626 // Client.
627 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
628 REPORTER_ASSERT(reporter,
629 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
630
631 auto clientBlob = makeBlob(clientTf);
632
633 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
634 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
635
636 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
637 // interpolation.
638 compare_blobs(expected, actual, reporter, 36);
639 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400640
641 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
642 discardableManager->unlockAndDeleteAll();
643}
644#endif
645
Herb Derby1a9971e2018-07-19 13:41:15 -0400646DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400647 auto direct = ctxInfo.directContext();
Herb Derby1a9971e2018-07-19 13:41:15 -0400648 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
649 SkStrikeServer server(discardableManager.get());
650 SkStrikeClient client(discardableManager, false);
651 SkPaint paint;
652 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400653
654 // Server.
655 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
656 auto serverTfData = server.serializeTypeface(serverTf.get());
657
658 int glyphCount = 10;
659 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Robert Phillips6d344c32020-07-06 10:56:46 -0400660 auto props = FindSurfaceProps(direct);
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400661 std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
662 10, 10, props, nullptr, direct->supportsDistanceFieldText());
663 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0.5, 0, paint);
Herb Derby1a9971e2018-07-19 13:41:15 -0400664
665 std::vector<uint8_t> serverStrikeData;
666 server.writeStrikeData(&serverStrikeData);
667
668 // Client.
669 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
670 REPORTER_ASSERT(reporter,
671 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
672 auto clientBlob = buildTextBlob(clientTf, glyphCount);
673
Robert Phillips6d344c32020-07-06 10:56:46 -0400674 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct, nullptr, 0.5);
675 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct, nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600676 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400677 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby1a9971e2018-07-19 13:41:15 -0400678
679 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
680 discardableManager->unlockAndDeleteAll();
681}
682
Khushal3e7548c2018-05-23 15:45:01 -0700683DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400684 auto direct = ctxInfo.directContext();
Chris Dalton89d460f2021-06-08 10:46:36 -0600685 if (!direct->priv().caps()->shaderCaps()->supportsDistanceFieldText()) {
686 return;
687 }
Khushal3e7548c2018-05-23 15:45:01 -0700688 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
689 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400690 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700691 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500692 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700693
Jim Van Verthce3cf802019-10-10 11:06:20 -0400694 // A scale transform forces fallback to dft.
Mike Reed1f607332020-05-21 12:11:27 -0400695 SkMatrix matrix = SkMatrix::Scale(16, 16);
Herb Derbybf2dd2a2021-03-04 10:13:22 -0500696 GrSDFTControl control = direct->priv().asRecordingContext()->priv().getSDFTControl(true);
697 REPORTER_ASSERT(reporter, control.drawingType(font, paint, matrix) == GrSDFTControl::kSDFT);
Khushal3e7548c2018-05-23 15:45:01 -0700698
699 // Server.
700 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
701 auto serverTfData = server.serializeTypeface(serverTf.get());
702
703 int glyphCount = 10;
704 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ben Wagnerae4bb982020-09-24 14:49:00 -0400705 const SkSurfaceProps props;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400706 std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
707 10, 10, props, nullptr, direct->supportsDistanceFieldText());
708 cache_diff_canvas->concat(matrix);
709 cache_diff_canvas->drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal3e7548c2018-05-23 15:45:01 -0700710
711 std::vector<uint8_t> serverStrikeData;
712 server.writeStrikeData(&serverStrikeData);
713
714 // Client.
715 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
716 REPORTER_ASSERT(reporter,
717 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
718 auto clientBlob = buildTextBlob(clientTf, glyphCount);
719
Robert Phillips6d344c32020-07-06 10:56:46 -0400720 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, direct, &matrix);
721 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, direct, &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600722 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700723 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700724
725 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
726 discardableManager->unlockAndDeleteAll();
727}
Khushald4160832018-05-23 18:16:00 -0700728
729DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
730 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
731 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400732 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700733
734 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
735 auto tfData = server.serializeTypeface(serverTf.get());
736 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
737 REPORTER_ASSERT(reporter, clientTf);
738 int glyphCount = 10;
739 auto clientBlob = buildTextBlob(clientTf, glyphCount);
740
741 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000742 SkPaint paint;
743 SkMatrix matrix = SkMatrix::I();
Robert Phillips6d344c32020-07-06 10:56:46 -0400744 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.directContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700745 REPORTER_ASSERT(reporter,
746 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
747 REPORTER_ASSERT(reporter,
748 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
749
750 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
751 // miss.
752 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
753 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
754
755 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
756 discardableManager->unlockAndDeleteAll();
757}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400758
Herb Derbye384a1e2019-05-21 11:27:40 -0400759sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
760 sk_sp<SkTypeface> clientTf = nullptr) {
761 SkFont font;
762 font.setTypeface(serverTf);
763 font.setSize(textSize);
764
765 const char* text = ToolUtils::emoji_sample_text();
766 SkFont serverFont = font;
767 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
768 if (clientTf == nullptr) return blob;
769
770 SkSerialProcs s_procs;
771 s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
772 return SkData::MakeUninitialized(1u);
773 };
774 auto serialized = blob->serialize(s_procs);
775
776 SkDeserialProcs d_procs;
777 d_procs.fTypefaceCtx = &clientTf;
778 d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
779 return *(static_cast<sk_sp<SkTypeface>*>(ctx));
780 };
781 return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
782}
783
784DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400785 auto direct = ctxInfo.directContext();
Herb Derbye384a1e2019-05-21 11:27:40 -0400786 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
787 SkStrikeServer server(discardableManager.get());
788 SkStrikeClient client(discardableManager, false);
789
790 auto serverTf = ToolUtils::emoji_typeface();
791 auto serverTfData = server.serializeTypeface(serverTf.get());
792 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
793
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400794 auto props = FindSurfaceProps(direct);
795 std::unique_ptr<SkCanvas> cache_diff_canvas = server.makeAnalysisCanvas(
796 500, 500, props, nullptr, direct->supportsDistanceFieldText());
Mike Reed69aaee02019-05-30 11:40:51 +0000797 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400798 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400799
Herb Derbye384a1e2019-05-21 11:27:40 -0400800 SkPaint paint;
Michael Ludwig97f85bb2021-05-06 08:59:26 -0400801 cache_diff_canvas->drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400802
803 std::vector<uint8_t> serverStrikeData;
804 server.writeStrikeData(&serverStrikeData);
Herb Derbyf5e9b422019-10-22 16:06:22 -0400805 if (!serverStrikeData.empty()) {
806 REPORTER_ASSERT(reporter,
807 client.readStrikeData(serverStrikeData.data(),
808 serverStrikeData.size()));
809 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400810 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
811 REPORTER_ASSERT(reporter, clientBlob);
812
Robert Phillips6d344c32020-07-06 10:56:46 -0400813 RasterBlob(clientBlob, 500, 500, paint, direct);
Herb Derbye384a1e2019-05-21 11:27:40 -0400814 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbye384a1e2019-05-21 11:27:40 -0400815 discardableManager->resetCacheMissCounts();
816 }
817
818 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
819 discardableManager->unlockAndDeleteAll();
820}