1 /*
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
8 #include "src/core/SkRemoteGlyphCache.h"
9
10 #include <bitset>
11 #include <iterator>
12 #include <memory>
13 #include <new>
14 #include <string>
15 #include <tuple>
16
17 #include "include/private/SkChecksum.h"
18 #include "src/core/SkDevice.h"
19 #include "src/core/SkDraw.h"
20 #include "src/core/SkEnumerate.h"
21 #include "src/core/SkGlyphRun.h"
22 #include "src/core/SkScalerCache.h"
23 #include "src/core/SkSpan.h"
24 #include "src/core/SkStrikeCache.h"
25 #include "src/core/SkTLazy.h"
26 #include "src/core/SkTraceEvent.h"
27 #include "src/core/SkTypeface_remote.h"
28 #include "src/core/SkZip.h"
29
30 #if SK_SUPPORT_GPU
31 #include "src/gpu/GrDrawOpAtlas.h"
32 #include "src/gpu/text/GrTextContext.h"
33 #endif
34
auto_descriptor_from_desc(const SkDescriptor * source_desc,SkFontID font_id,SkAutoDescriptor * ad)35 static SkDescriptor* auto_descriptor_from_desc(const SkDescriptor* source_desc,
36 SkFontID font_id,
37 SkAutoDescriptor* ad) {
38 ad->reset(source_desc->getLength());
39 auto* desc = ad->getDesc();
40
41 // Rec.
42 {
43 uint32_t size;
44 auto ptr = source_desc->findEntry(kRec_SkDescriptorTag, &size);
45 SkScalerContextRec rec;
46 std::memcpy((void*)&rec, ptr, size);
47 rec.fFontID = font_id;
48 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
49 }
50
51 // Effects.
52 {
53 uint32_t size;
54 auto ptr = source_desc->findEntry(kEffects_SkDescriptorTag, &size);
55 if (ptr) { desc->addEntry(kEffects_SkDescriptorTag, size, ptr); }
56 }
57
58 desc->computeChecksum();
59 return desc;
60 }
61
create_descriptor(const SkPaint & paint,const SkFont & font,const SkMatrix & m,const SkSurfaceProps & props,SkScalerContextFlags flags,SkAutoDescriptor * ad,SkScalerContextEffects * effects)62 static const SkDescriptor* create_descriptor(
63 const SkPaint& paint, const SkFont& font, const SkMatrix& m,
64 const SkSurfaceProps& props, SkScalerContextFlags flags,
65 SkAutoDescriptor* ad, SkScalerContextEffects* effects) {
66 SkScalerContextRec rec;
67 SkScalerContext::MakeRecAndEffects(font, paint, props, flags, m, &rec, effects);
68 return SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, *effects, ad);
69 }
70
71 // -- Serializer -----------------------------------------------------------------------------------
pad(size_t size,size_t alignment)72 size_t pad(size_t size, size_t alignment) { return (size + (alignment - 1)) & ~(alignment - 1); }
73
74 // Alignment between x86 and x64 differs for some types, in particular
75 // int64_t and doubles have 4 and 8-byte alignment, respectively.
76 // Be consistent even when writing and reading across different architectures.
77 template<typename T>
serialization_alignment()78 size_t serialization_alignment() {
79 return sizeof(T) == 8 ? 8 : alignof(T);
80 }
81
82 class Serializer {
83 public:
Serializer(std::vector<uint8_t> * buffer)84 explicit Serializer(std::vector<uint8_t>* buffer) : fBuffer{buffer} {}
85
86 template <typename T, typename... Args>
87 T* emplace(Args&&... args) {
88 auto result = allocate(sizeof(T), serialization_alignment<T>());
89 return new (result) T{std::forward<Args>(args)...};
90 }
91
92 template <typename T>
write(const T & data)93 void write(const T& data) {
94 T* result = (T*)allocate(sizeof(T), serialization_alignment<T>());
95 memcpy(result, &data, sizeof(T));
96 }
97
98 template <typename T>
allocate()99 T* allocate() {
100 T* result = (T*)allocate(sizeof(T), serialization_alignment<T>());
101 return result;
102 }
103
writeDescriptor(const SkDescriptor & desc)104 void writeDescriptor(const SkDescriptor& desc) {
105 write(desc.getLength());
106 auto result = allocate(desc.getLength(), alignof(SkDescriptor));
107 memcpy(result, &desc, desc.getLength());
108 }
109
allocate(size_t size,size_t alignment)110 void* allocate(size_t size, size_t alignment) {
111 size_t aligned = pad(fBuffer->size(), alignment);
112 fBuffer->resize(aligned + size);
113 return &(*fBuffer)[aligned];
114 }
115
116 private:
117 std::vector<uint8_t>* fBuffer;
118 };
119
120 // -- Deserializer -------------------------------------------------------------------------------
121 // Note that the Deserializer is reading untrusted data, we need to guard against invalid data.
122 class Deserializer {
123 public:
Deserializer(const volatile char * memory,size_t memorySize)124 Deserializer(const volatile char* memory, size_t memorySize)
125 : fMemory(memory), fMemorySize(memorySize) {}
126
127 template <typename T>
read(T * val)128 bool read(T* val) {
129 auto* result = this->ensureAtLeast(sizeof(T), serialization_alignment<T>());
130 if (!result) return false;
131
132 memcpy(val, const_cast<const char*>(result), sizeof(T));
133 return true;
134 }
135
readDescriptor(SkAutoDescriptor * ad)136 bool readDescriptor(SkAutoDescriptor* ad) {
137 uint32_t descLength = 0u;
138 if (!read<uint32_t>(&descLength)) return false;
139 if (descLength < sizeof(SkDescriptor)) return false;
140 if (descLength != SkAlign4(descLength)) return false;
141
142 auto* result = this->ensureAtLeast(descLength, alignof(SkDescriptor));
143 if (!result) return false;
144
145 ad->reset(descLength);
146 memcpy(ad->getDesc(), const_cast<const char*>(result), descLength);
147
148 if (ad->getDesc()->getLength() > descLength) return false;
149 return ad->getDesc()->isValid();
150 }
151
read(size_t size,size_t alignment)152 const volatile void* read(size_t size, size_t alignment) {
153 return this->ensureAtLeast(size, alignment);
154 }
155
bytesRead() const156 size_t bytesRead() const { return fBytesRead; }
157
158 private:
ensureAtLeast(size_t size,size_t alignment)159 const volatile char* ensureAtLeast(size_t size, size_t alignment) {
160 size_t padded = pad(fBytesRead, alignment);
161
162 // Not enough data.
163 if (padded > fMemorySize) return nullptr;
164 if (size > fMemorySize - padded) return nullptr;
165
166 auto* result = fMemory + padded;
167 fBytesRead = padded + size;
168 return result;
169 }
170
171 // Note that we read each piece of memory only once to guard against TOCTOU violations.
172 const volatile char* fMemory;
173 size_t fMemorySize;
174 size_t fBytesRead = 0u;
175 };
176
SkFuzzDeserializeSkDescriptor(sk_sp<SkData> bytes,SkAutoDescriptor * ad)177 bool SkFuzzDeserializeSkDescriptor(sk_sp<SkData> bytes, SkAutoDescriptor* ad) {
178 auto d = Deserializer(reinterpret_cast<const volatile char*>(bytes->data()), bytes->size());
179 return d.readDescriptor(ad);
180 }
181
182 // Paths use a SkWriter32 which requires 4 byte alignment.
183 static const size_t kPathAlignment = 4u;
184
185 // -- StrikeSpec -----------------------------------------------------------------------------------
186 struct StrikeSpec {
187 StrikeSpec() = default;
StrikeSpecStrikeSpec188 StrikeSpec(SkFontID typefaceID_, SkDiscardableHandleId discardableHandleId_)
189 : typefaceID{typefaceID_}, discardableHandleId(discardableHandleId_) {}
190 SkFontID typefaceID = 0u;
191 SkDiscardableHandleId discardableHandleId = 0u;
192 /* desc */
193 /* n X (glyphs ids) */
194 };
195
196 // Represent a set of x sub-pixel-position glyphs with a glyph id < kMaxGlyphID and
197 // y sub-pxiel-position must be 0. Most sub-pixel-positioned glyphs have been x-axis aligned
198 // forcing the y sub-pixel position to be zero. We can organize the SkPackedGlyphID to check that
199 // the glyph id and the y position == 0 with a single compare in the following way:
200 // <y-sub-pixel-position>:2 | <glyphid:16> | <x-sub-pixel-position>:2
201 // This organization allows a single check of a packed-id to be:
202 // packed-id < kMaxGlyphID * possible-x-sub-pixel-positions
203 // where possible-x-sub-pixel-positions == 4.
204 class LowerRangeBitVector {
205 public:
test(SkPackedGlyphID packedID) const206 bool test(SkPackedGlyphID packedID) const {
207 uint32_t bit = packedID.value();
208 return bit < kMaxIndex && fBits.test(bit);
209 }
setIfLower(SkPackedGlyphID packedID)210 void setIfLower(SkPackedGlyphID packedID) {
211 uint32_t bit = packedID.value();
212 if (bit < kMaxIndex) {
213 fBits.set(bit);
214 }
215 }
216
217 private:
218 using GID = SkPackedGlyphID;
219 static_assert(GID::kSubPixelX < GID::kGlyphID && GID::kGlyphID < GID::kSubPixelY,
220 "SkPackedGlyphID must be organized: sub-y | glyph id | sub-x");
221 static constexpr int kMaxGlyphID = 128;
222 static constexpr int kMaxIndex = kMaxGlyphID * (1u << GID::kSubPixelPosLen);
223 std::bitset<kMaxIndex> fBits;
224 };
225
226 // -- RemoteStrike ----------------------------------------------------------------------------
227 class SkStrikeServer::RemoteStrike final : public SkStrikeForGPU {
228 public:
229 // N.B. RemoteStrike is not valid until ensureScalerContext is called.
230 RemoteStrike(const SkDescriptor& descriptor,
231 std::unique_ptr<SkScalerContext> context,
232 SkDiscardableHandleId discardableHandleId);
233 ~RemoteStrike() override;
234
235 void writePendingGlyphs(Serializer* serializer);
discardableHandleId() const236 SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
237
getDescriptor() const238 const SkDescriptor& getDescriptor() const override {
239 return *fDescriptor.getDesc();
240 }
241
242 void setTypefaceAndEffects(const SkTypeface* typeface, SkScalerContextEffects effects);
243
roundingSpec() const244 const SkGlyphPositionRoundingSpec& roundingSpec() const override {
245 return fRoundingSpec;
246 }
247
248 void prepareForMaskDrawing(
249 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
250
251 void prepareForSDFTDrawing(
252 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
253
254 void prepareForPathDrawing(
255 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
256
onAboutToExitScope()257 void onAboutToExitScope() override {}
258
hasPendingGlyphs() const259 bool hasPendingGlyphs() const {
260 return !fMasksToSend.empty() || !fPathsToSend.empty();
261 }
262
263 void resetScalerContext();
264
265 private:
266 template <typename Rejector>
267 void commonMaskLoop(
268 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects, Rejector&& reject);
269
270 // Keep track of if the glyph draw has been totally satisfied. It could be that this
271 // strike can not draw the glyph, and it must be rejected to be handled by fallback.
272 // For example, if a glyph has canDrawAsMask sent, then that data is on the GPU, and this
273 // strike totally satisfies this result. If canDrawAsMask is false, then this glyph must be
274 // rejected, and handled by a later stage using a latter strike.
275 struct MaskSummary {
276 static_assert(SkPackedGlyphID::kMaskAll < (1u << 30), "SkPackedGlyphID is too big.");
277 uint32_t packedID:30;
278 uint32_t canDrawAsMask:1;
279 uint32_t canDrawAsSDFT:1;
280 };
281
282 struct MaskSummaryTraits {
GetKeySkStrikeServer::RemoteStrike::MaskSummaryTraits283 static SkPackedGlyphID GetKey(MaskSummary summary) {
284 return SkPackedGlyphID{summary.packedID};
285 }
286
HashSkStrikeServer::RemoteStrike::MaskSummaryTraits287 static uint32_t Hash(SkPackedGlyphID packedID) {
288 return packedID.hash();
289 }
290 };
291
292 // Same thing as MaskSummary, but for paths.
293 struct PathSummary {
294 constexpr static uint16_t kIsPath = 0;
295 SkGlyphID glyphID;
296 // If drawing glyphID can be done with a path, this is 0, otherwise it is the max
297 // dimension of the glyph.
298 uint16_t maxDimensionOrPath;
299 };
300
301 struct PathSummaryTraits {
GetKeySkStrikeServer::RemoteStrike::PathSummaryTraits302 static SkGlyphID GetKey(PathSummary summary) {
303 return summary.glyphID;
304 }
305
HashSkStrikeServer::RemoteStrike::PathSummaryTraits306 static uint32_t Hash(SkGlyphID packedID) {
307 return SkChecksum::CheapMix(packedID);
308 }
309 };
310
311 void writeGlyphPath(const SkGlyph& glyph, Serializer* serializer) const;
312 void ensureScalerContext();
313
314 const int fNumberOfGlyphs;
315 const SkAutoDescriptor fDescriptor;
316 const SkDiscardableHandleId fDiscardableHandleId;
317
318 const SkGlyphPositionRoundingSpec fRoundingSpec;
319
320 // The context built using fDescriptor
321 std::unique_ptr<SkScalerContext> fContext;
322
323 // These fields are set every time getOrCreateCache. This allows the code to maintain the
324 // fContext as lazy as possible.
325 const SkTypeface* fTypeface{nullptr};
326 SkScalerContextEffects fEffects;
327
328 // Have the metrics been sent for this strike. Only send them once.
329 bool fHaveSentFontMetrics{false};
330
331 LowerRangeBitVector fSentLowGlyphIDs;
332
333 // The masks and paths that currently reside in the GPU process.
334 SkTHashTable<MaskSummary, SkPackedGlyphID, MaskSummaryTraits> fSentGlyphs;
335 SkTHashTable<PathSummary, SkGlyphID, PathSummaryTraits> fSentPaths;
336
337 // The Masks, SDFT Mask, and Paths that need to be sent to the GPU task for the processed
338 // TextBlobs. Cleared after diffs are serialized.
339 std::vector<SkGlyph> fMasksToSend;
340 std::vector<SkGlyph> fPathsToSend;
341
342 // Alloc for storing bits and pieces of paths, Cleared after diffs are serialized.
343 SkArenaAlloc fPathAlloc{256};
344 };
345
RemoteStrike(const SkDescriptor & descriptor,std::unique_ptr<SkScalerContext> context,uint32_t discardableHandleId)346 SkStrikeServer::RemoteStrike::RemoteStrike(
347 const SkDescriptor& descriptor,
348 std::unique_ptr<SkScalerContext> context,
349 uint32_t discardableHandleId)
350 : fNumberOfGlyphs(context->getGlyphCount())
351 , fDescriptor{descriptor}
352 , fDiscardableHandleId(discardableHandleId)
353 , fRoundingSpec{context->isSubpixel(), context->computeAxisAlignmentForHText()}
354 // N.B. context must come last because it is used above.
355 , fContext{std::move(context)}
356 , fSentLowGlyphIDs{} {
357 SkASSERT(fDescriptor.getDesc() != nullptr);
358 SkASSERT(fContext != nullptr);
359 }
360
361 SkStrikeServer::RemoteStrike::~RemoteStrike() = default;
362
operator ()(const SkDescriptor * key) const363 size_t SkStrikeServer::MapOps::operator()(const SkDescriptor* key) const {
364 return key->getChecksum();
365 }
366
operator ()(const SkDescriptor * lhs,const SkDescriptor * rhs) const367 bool SkStrikeServer::MapOps::operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const {
368 return *lhs == *rhs;
369 }
370
371 // -- TrackLayerDevice -----------------------------------------------------------------------------
372 class SkTextBlobCacheDiffCanvas::TrackLayerDevice final : public SkNoPixelsDevice {
373 public:
TrackLayerDevice(const SkIRect & bounds,const SkSurfaceProps & props,SkStrikeServer * server,sk_sp<SkColorSpace> colorSpace,bool DFTSupport)374 TrackLayerDevice(
375 const SkIRect& bounds, const SkSurfaceProps& props, SkStrikeServer* server,
376 sk_sp<SkColorSpace> colorSpace, bool DFTSupport)
377 : SkNoPixelsDevice(bounds, props, std::move(colorSpace))
378 , fStrikeServer(server)
379 , fDFTSupport(DFTSupport)
380 , fPainter{props, kUnknown_SkColorType, imageInfo().colorSpace(), fStrikeServer} {
381 SkASSERT(fStrikeServer != nullptr);
382 }
383
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)384 SkBaseDevice* onCreateDevice(const CreateInfo& cinfo, const SkPaint*) override {
385 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
386 return new TrackLayerDevice(this->getGlobalBounds(), surfaceProps, fStrikeServer,
387 cinfo.fInfo.refColorSpace(), fDFTSupport);
388 }
389
strikeServer()390 SkStrikeServer* strikeServer() { return fStrikeServer; }
391
392 protected:
drawGlyphRunList(const SkGlyphRunList & glyphRunList)393 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override {
394 #if SK_SUPPORT_GPU
395 GrTextContext::Options options;
396 GrTextContext::SanitizeOptions(&options);
397
398 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
399 if (SkTextBlobTrace::Capture* capture = fStrikeServer->fCapture.get()) {
400 capture->capture(glyphRunList);
401 }
402 #endif // SK_CAPTURE_DRAW_TEXT_BLOB
403
404 fPainter.processGlyphRunList(glyphRunList,
405 this->localToDevice(),
406 this->surfaceProps(),
407 fDFTSupport,
408 options,
409 nullptr);
410 #endif // SK_SUPPORT_GPU
411 }
412
413 private:
414 SkStrikeServer* const fStrikeServer;
415 const bool fDFTSupport{false};
416 SkGlyphRunListPainter fPainter;
417 };
418
419 // -- SkTextBlobCacheDiffCanvas -------------------------------------------------------------------
SkTextBlobCacheDiffCanvas(int width,int height,const SkSurfaceProps & props,SkStrikeServer * strikeServer,bool DFTSupport)420 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
421 const SkSurfaceProps& props,
422 SkStrikeServer* strikeServer,
423 bool DFTSupport)
424 : SkTextBlobCacheDiffCanvas{width, height, props, strikeServer, nullptr, DFTSupport} { }
425
SkTextBlobCacheDiffCanvas(int width,int height,const SkSurfaceProps & props,SkStrikeServer * strikeServer,sk_sp<SkColorSpace> colorSpace,bool DFTSupport)426 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
427 const SkSurfaceProps& props,
428 SkStrikeServer* strikeServer,
429 sk_sp<SkColorSpace> colorSpace,
430 bool DFTSupport)
431 : SkNoDrawCanvas{sk_make_sp<TrackLayerDevice>(SkIRect::MakeWH(width, height),
432 props,
433 strikeServer,
434 std::move(colorSpace),
435 DFTSupport)} {
436 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
437 if (!strikeServer->fCapture) {
438 strikeServer->fCapture.reset(new SkTextBlobTrace::Capture);
439 }
440 #endif // SK_CAPTURE_DRAW_TEXT_BLOB
441 }
442
~SkTextBlobCacheDiffCanvas()443 SkTextBlobCacheDiffCanvas::~SkTextBlobCacheDiffCanvas() {
444 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
445 SkTextBlobTrace::Capture* capture =
446 ((TrackLayerDevice*)this->getTopDevice())->strikeServer()->fCapture.get();
447 if (capture) {
448 capture->dump();
449 }
450 #endif // SK_CAPTURE_DRAW_TEXT_BLOB
451 }
452
getSaveLayerStrategy(const SaveLayerRec & rec)453 SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy(
454 const SaveLayerRec& rec) {
455 return kFullLayer_SaveLayerStrategy;
456 }
457
onDoSaveBehind(const SkRect *)458 bool SkTextBlobCacheDiffCanvas::onDoSaveBehind(const SkRect*) {
459 return false;
460 }
461
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)462 void SkTextBlobCacheDiffCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
463 const SkPaint& paint) {
464 SkCanvas::onDrawTextBlob(blob, x, y, paint);
465 }
466
467 // -- WireTypeface ---------------------------------------------------------------------------------
468 struct WireTypeface {
469 WireTypeface() = default;
WireTypefaceWireTypeface470 WireTypeface(SkFontID typeface_id, int glyph_count, SkFontStyle style, bool is_fixed)
471 : typefaceID(typeface_id), glyphCount(glyph_count), style(style), isFixed(is_fixed) {}
472
473 SkFontID typefaceID{0};
474 int glyphCount{0};
475 SkFontStyle style;
476 bool isFixed{false};
477 };
478
479 // SkStrikeServer ----------------------------------------------------------------------------------
SkStrikeServer(DiscardableHandleManager * discardableHandleManager)480 SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager)
481 : fDiscardableHandleManager(discardableHandleManager) {
482 SkASSERT(fDiscardableHandleManager);
483 }
484
~SkStrikeServer()485 SkStrikeServer::~SkStrikeServer() {
486 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
487 if (fCapture) {
488 fCapture->dump();
489 }
490 #endif // SK_CAPTURE_DRAW_TEXT_BLOB
491 }
492
serializeTypeface(SkTypeface * tf)493 sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) {
494 auto* data = fSerializedTypefaces.find(SkTypeface::UniqueID(tf));
495 if (data) {
496 return *data;
497 }
498
499 WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(),
500 tf->isFixedPitch());
501 data = fSerializedTypefaces.set(SkTypeface::UniqueID(tf),
502 SkData::MakeWithCopy(&wire, sizeof(wire)));
503 return *data;
504 }
505
writeStrikeData(std::vector<uint8_t> * memory)506 void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
507 size_t strikesToSend = 0;
508 fRemoteStrikesToSend.foreach ([&](RemoteStrike* strike) {
509 if (strike->hasPendingGlyphs()) {
510 strikesToSend++;
511 } else {
512 strike->resetScalerContext();
513 }
514 });
515
516 if (strikesToSend == 0 && fTypefacesToSend.empty()) {
517 fRemoteStrikesToSend.reset();
518 return;
519 }
520
521 Serializer serializer(memory);
522 serializer.emplace<uint64_t>(fTypefacesToSend.size());
523 for (const auto& tf : fTypefacesToSend) {
524 serializer.write<WireTypeface>(tf);
525 }
526 fTypefacesToSend.clear();
527
528 serializer.emplace<uint64_t>(SkTo<uint64_t>(strikesToSend));
529 fRemoteStrikesToSend.foreach (
530 #ifdef SK_DEBUG
531 [&](RemoteStrike* strike) {
532 if (strike->hasPendingGlyphs()) {
533 strike->writePendingGlyphs(&serializer);
534 strike->resetScalerContext();
535 }
536 auto it = fDescToRemoteStrike.find(&strike->getDescriptor());
537 SkASSERT(it != fDescToRemoteStrike.end());
538 SkASSERT(it->second.get() == strike);
539 }
540
541 #else
542 [&serializer](RemoteStrike* strike) {
543 if (strike->hasPendingGlyphs()) {
544 strike->writePendingGlyphs(&serializer);
545 strike->resetScalerContext();
546 }
547 }
548 #endif
549 );
550 fRemoteStrikesToSend.reset();
551 }
552
getOrCreateCache(const SkPaint & paint,const SkFont & font,const SkSurfaceProps & props,const SkMatrix & matrix,SkScalerContextFlags flags,SkScalerContextEffects * effects)553 SkStrikeServer::RemoteStrike* SkStrikeServer::getOrCreateCache(
554 const SkPaint& paint,
555 const SkFont& font,
556 const SkSurfaceProps& props,
557 const SkMatrix& matrix,
558 SkScalerContextFlags flags,
559 SkScalerContextEffects* effects) {
560 SkAutoDescriptor descStorage;
561 auto desc = create_descriptor(paint, font, matrix, props, flags, &descStorage, effects);
562
563 return this->getOrCreateCache(*desc, *font.getTypefaceOrDefault(), *effects);
564 }
565
findOrCreateScopedStrike(const SkDescriptor & desc,const SkScalerContextEffects & effects,const SkTypeface & typeface)566 SkScopedStrikeForGPU SkStrikeServer::findOrCreateScopedStrike(const SkDescriptor& desc,
567 const SkScalerContextEffects& effects,
568 const SkTypeface& typeface) {
569 return SkScopedStrikeForGPU{this->getOrCreateCache(desc, typeface, effects)};
570 }
571
AddGlyphForTesting(RemoteStrike * strike,SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects)572 void SkStrikeServer::AddGlyphForTesting(
573 RemoteStrike* strike, SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
574 strike->prepareForMaskDrawing(drawables, rejects);
575 rejects->flipRejectsToSource();
576 SkASSERT(rejects->source().empty());
577 }
578
checkForDeletedEntries()579 void SkStrikeServer::checkForDeletedEntries() {
580 auto it = fDescToRemoteStrike.begin();
581 while (fDescToRemoteStrike.size() > fMaxEntriesInDescriptorMap &&
582 it != fDescToRemoteStrike.end()) {
583 RemoteStrike* strike = it->second.get();
584 if (fDiscardableHandleManager->isHandleDeleted(strike->discardableHandleId())) {
585 // If we are removing the strike, we better not be trying to send it at the same time.
586 SkASSERT(!fRemoteStrikesToSend.contains(strike));
587 it = fDescToRemoteStrike.erase(it);
588 } else {
589 ++it;
590 }
591 }
592 }
593
getOrCreateCache(const SkDescriptor & desc,const SkTypeface & typeface,SkScalerContextEffects effects)594 SkStrikeServer::RemoteStrike* SkStrikeServer::getOrCreateCache(
595 const SkDescriptor& desc, const SkTypeface& typeface, SkScalerContextEffects effects) {
596
597 // In cases where tracing is turned off, make sure not to get an unused function warning.
598 // Lambdaize the function.
599 TRACE_EVENT1("skia", "RecForDesc", "rec",
600 TRACE_STR_COPY(
601 [&desc](){
602 auto ptr = desc.findEntry(kRec_SkDescriptorTag, nullptr);
603 SkScalerContextRec rec;
604 std::memcpy((void*)&rec, ptr, sizeof(rec));
605 return rec.dump();
606 }().c_str()
607 )
608 );
609
610 auto it = fDescToRemoteStrike.find(&desc);
611 if (it != fDescToRemoteStrike.end()) {
612 // We have processed the RemoteStrike before. Reuse it.
613 RemoteStrike* strike = it->second.get();
614 strike->setTypefaceAndEffects(&typeface, effects);
615 if (fRemoteStrikesToSend.contains(strike)) {
616 // Already tracking
617 return strike;
618 }
619
620 // Strike is in unknown state on GPU. Start tracking strike on GPU by locking it.
621 bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId());
622 if (locked) {
623 fRemoteStrikesToSend.add(strike);
624 return strike;
625 }
626
627 fDescToRemoteStrike.erase(it);
628 }
629
630 // Create a new RemoteStrike. Start by processing the typeface.
631 const SkFontID typefaceId = typeface.uniqueID();
632 if (!fCachedTypefaces.contains(typefaceId)) {
633 fCachedTypefaces.add(typefaceId);
634 fTypefacesToSend.emplace_back(typefaceId, typeface.countGlyphs(),
635 typeface.fontStyle(),
636 typeface.isFixedPitch());
637 }
638
639 auto context = typeface.createScalerContext(effects, &desc);
640 auto newHandle = fDiscardableHandleManager->createHandle(); // Locked on creation
641 auto remoteStrike = std::make_unique<RemoteStrike>(desc, std::move(context), newHandle);
642 remoteStrike->setTypefaceAndEffects(&typeface, effects);
643 auto remoteStrikePtr = remoteStrike.get();
644 fRemoteStrikesToSend.add(remoteStrikePtr);
645 auto d = &remoteStrike->getDescriptor();
646 fDescToRemoteStrike[d] = std::move(remoteStrike);
647
648 checkForDeletedEntries();
649
650 // Be sure we can build glyphs with this RemoteStrike.
651 remoteStrikePtr->setTypefaceAndEffects(&typeface, effects);
652 return remoteStrikePtr;
653 }
654
655 // No need to write fForceBW because it is a flag private to SkScalerContext_DW, which will never
656 // be called on the GPU side.
writeGlyph(const SkGlyph & glyph,Serializer * serializer)657 static void writeGlyph(const SkGlyph& glyph, Serializer* serializer) {
658 serializer->write<SkPackedGlyphID>(glyph.getPackedID());
659 serializer->write<float>(glyph.advanceX());
660 serializer->write<float>(glyph.advanceY());
661 serializer->write<uint16_t>(glyph.width());
662 serializer->write<uint16_t>(glyph.height());
663 serializer->write<int16_t>(glyph.top());
664 serializer->write<int16_t>(glyph.left());
665 serializer->write<uint8_t>(glyph.maskFormat());
666 }
667
writePendingGlyphs(Serializer * serializer)668 void SkStrikeServer::RemoteStrike::writePendingGlyphs(Serializer* serializer) {
669 SkASSERT(this->hasPendingGlyphs());
670
671 // Write the desc.
672 serializer->emplace<StrikeSpec>(fContext->getTypeface()->uniqueID(), fDiscardableHandleId);
673 serializer->writeDescriptor(*fDescriptor.getDesc());
674
675 serializer->emplace<bool>(fHaveSentFontMetrics);
676 if (!fHaveSentFontMetrics) {
677 // Write FontMetrics if not sent before.
678 SkFontMetrics fontMetrics;
679 fContext->getFontMetrics(&fontMetrics);
680 serializer->write<SkFontMetrics>(fontMetrics);
681 fHaveSentFontMetrics = true;
682 }
683
684 // Write mask glyphs
685 serializer->emplace<uint64_t>(fMasksToSend.size());
686 for (SkGlyph& glyph : fMasksToSend) {
687 SkASSERT(SkMask::IsValidFormat(glyph.fMaskFormat));
688
689 writeGlyph(glyph, serializer);
690 auto imageSize = glyph.imageSize();
691 if (imageSize > 0 && FitsInAtlas(glyph)) {
692 glyph.fImage = serializer->allocate(imageSize, glyph.formatAlignment());
693 fContext->getImage(glyph);
694 }
695 }
696 fMasksToSend.clear();
697
698 // Write glyphs paths.
699 serializer->emplace<uint64_t>(fPathsToSend.size());
700 for (SkGlyph& glyph : fPathsToSend) {
701 SkASSERT(SkMask::IsValidFormat(glyph.fMaskFormat));
702
703 writeGlyph(glyph, serializer);
704 writeGlyphPath(glyph, serializer);
705 }
706 fPathsToSend.clear();
707 fPathAlloc.reset();
708 }
709
ensureScalerContext()710 void SkStrikeServer::RemoteStrike::ensureScalerContext() {
711 if (fContext == nullptr) {
712 fContext = fTypeface->createScalerContext(fEffects, fDescriptor.getDesc());
713 }
714 }
715
resetScalerContext()716 void SkStrikeServer::RemoteStrike::resetScalerContext() {
717 fContext.reset();
718 fTypeface = nullptr;
719 }
720
setTypefaceAndEffects(const SkTypeface * typeface,SkScalerContextEffects effects)721 void SkStrikeServer::RemoteStrike::setTypefaceAndEffects(
722 const SkTypeface* typeface, SkScalerContextEffects effects) {
723 fTypeface = typeface;
724 fEffects = effects;
725 }
726
writeGlyphPath(const SkGlyph & glyph,Serializer * serializer) const727 void SkStrikeServer::RemoteStrike::writeGlyphPath(
728 const SkGlyph& glyph, Serializer* serializer) const {
729 if (glyph.isColor() || glyph.isEmpty()) {
730 serializer->write<uint64_t>(0u);
731 return;
732 }
733
734 const SkPath* path = glyph.path();
735
736 if (path == nullptr) {
737 serializer->write<uint64_t>(0u);
738 return;
739 }
740
741 size_t pathSize = path->writeToMemory(nullptr);
742 serializer->write<uint64_t>(pathSize);
743 path->writeToMemory(serializer->allocate(pathSize, kPathAlignment));
744 }
745
746 template <typename Rejector>
commonMaskLoop(SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects,Rejector && reject)747 void SkStrikeServer::RemoteStrike::commonMaskLoop(
748 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects, Rejector&& reject) {
749 drawables->forEachGlyphID(
750 [&](size_t i, SkPackedGlyphID packedID, SkPoint position) {
751 MaskSummary* summary = fSentGlyphs.find(packedID);
752 if (summary == nullptr) {
753 // Put the new SkGlyph in the glyphs to send.
754 fMasksToSend.emplace_back(packedID);
755 SkGlyph* glyph = &fMasksToSend.back();
756
757 // Build the glyph
758 this->ensureScalerContext();
759 fContext->getMetrics(glyph);
760 MaskSummary newSummary =
761 {packedID.value(), CanDrawAsMask(*glyph), CanDrawAsSDFT(*glyph)};
762 summary = fSentGlyphs.set(newSummary);
763 }
764
765 // Reject things that are too big.
766 if (reject(*summary)) {
767 rejects->reject(i);
768 }
769 });
770 }
771
prepareForMaskDrawing(SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects)772 void SkStrikeServer::RemoteStrike::prepareForMaskDrawing(
773 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
774 for (auto t : SkMakeEnumerate(drawables->input())) {
775 size_t i; SkPackedGlyphID packedID;
776 std::forward_as_tuple(i, std::tie(packedID, std::ignore)) = t;
777
778 if (fSentLowGlyphIDs.test(packedID)) {
779 #ifdef SK_DEBUG
780 MaskSummary* summary = fSentGlyphs.find(packedID);
781 SkASSERT(summary != nullptr);
782 SkASSERT(summary->canDrawAsMask && summary->canDrawAsSDFT);
783 #endif
784 continue;
785 }
786
787 MaskSummary* summary = fSentGlyphs.find(packedID);
788 if (summary == nullptr) {
789 // Put the new SkGlyph in the glyphs to send.
790 fMasksToSend.emplace_back(packedID);
791 SkGlyph* glyph = &fMasksToSend.back();
792
793 // Build the glyph
794 this->ensureScalerContext();
795 fContext->getMetrics(glyph);
796
797 MaskSummary newSummary =
798 {packedID.value(), CanDrawAsMask(*glyph), CanDrawAsSDFT(*glyph)};
799
800 summary = fSentGlyphs.set(newSummary);
801
802 if (summary->canDrawAsMask && summary->canDrawAsSDFT) {
803 fSentLowGlyphIDs.setIfLower(packedID);
804 }
805 }
806
807 // Reject things that are too big.
808 if (!summary->canDrawAsMask) {
809 rejects->reject(i);
810 }
811 }
812 }
813
prepareForSDFTDrawing(SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects)814 void SkStrikeServer::RemoteStrike::prepareForSDFTDrawing(
815 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
816 this->commonMaskLoop(drawables, rejects,
817 [](MaskSummary summary){return !summary.canDrawAsSDFT;});
818 }
819
prepareForPathDrawing(SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects)820 void SkStrikeServer::RemoteStrike::prepareForPathDrawing(
821 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
822 drawables->forEachGlyphID(
823 [&](size_t i, SkPackedGlyphID packedID, SkPoint position) {
824 SkGlyphID glyphID = packedID.glyphID();
825 PathSummary* summary = fSentPaths.find(glyphID);
826 if (summary == nullptr) {
827 // Put the new SkGlyph in the glyphs to send.
828 fPathsToSend.emplace_back(SkPackedGlyphID{glyphID});
829 SkGlyph* glyph = &fPathsToSend.back();
830
831 // Build the glyph
832 this->ensureScalerContext();
833 fContext->getMetrics(glyph);
834
835 uint16_t maxDimensionOrPath = glyph->maxDimension();
836 // Only try to get the path if the glyphs is not color.
837 if (!glyph->isColor() && !glyph->isEmpty()) {
838 glyph->setPath(&fPathAlloc, fContext.get());
839 if (glyph->path() != nullptr) {
840 maxDimensionOrPath = PathSummary::kIsPath;
841 }
842 }
843
844 PathSummary newSummary = {glyph->getGlyphID(), maxDimensionOrPath};
845 summary = fSentPaths.set(newSummary);
846 }
847
848 if (summary->maxDimensionOrPath != PathSummary::kIsPath) {
849 rejects->reject(i, (int)summary->maxDimensionOrPath);
850 }
851 });
852 }
853
854 // SkStrikeClient ----------------------------------------------------------------------------------
855 class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner {
856 public:
DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,sk_sp<DiscardableHandleManager> manager)857 DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
858 sk_sp<DiscardableHandleManager> manager)
859 : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
860
861 ~DiscardableStrikePinner() override = default;
canDelete()862 bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
863
864 private:
865 const SkDiscardableHandleId fDiscardableHandleId;
866 sk_sp<DiscardableHandleManager> fManager;
867 };
868
SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,bool isLogging,SkStrikeCache * strikeCache)869 SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,
870 bool isLogging,
871 SkStrikeCache* strikeCache)
872 : fDiscardableHandleManager(std::move(discardableManager))
873 , fStrikeCache{strikeCache ? strikeCache : SkStrikeCache::GlobalStrikeCache()}
874 , fIsLogging{isLogging} {}
875
876 SkStrikeClient::~SkStrikeClient() = default;
877
878 #define READ_FAILURE \
879 { \
880 SkDebugf("Bad font data serialization line: %d", __LINE__); \
881 DiscardableHandleManager::ReadFailureData data = { \
882 memorySize, deserializer.bytesRead(), typefaceSize, \
883 strikeCount, glyphImagesCount, glyphPathsCount}; \
884 fDiscardableHandleManager->notifyReadFailure(data); \
885 return false; \
886 }
887
888 // No need to read fForceBW because it is a flag private to SkScalerContext_DW, which will never
889 // be called on the GPU side.
ReadGlyph(SkTLazy<SkGlyph> & glyph,Deserializer * deserializer)890 bool SkStrikeClient::ReadGlyph(SkTLazy<SkGlyph>& glyph, Deserializer* deserializer) {
891 SkPackedGlyphID glyphID;
892 if (!deserializer->read<SkPackedGlyphID>(&glyphID)) return false;
893 glyph.init(glyphID);
894 if (!deserializer->read<float>(&glyph->fAdvanceX)) return false;
895 if (!deserializer->read<float>(&glyph->fAdvanceY)) return false;
896 if (!deserializer->read<uint16_t>(&glyph->fWidth)) return false;
897 if (!deserializer->read<uint16_t>(&glyph->fHeight)) return false;
898 if (!deserializer->read<int16_t>(&glyph->fTop)) return false;
899 if (!deserializer->read<int16_t>(&glyph->fLeft)) return false;
900 if (!deserializer->read<uint8_t>(&glyph->fMaskFormat)) return false;
901 if (!SkMask::IsValidFormat(glyph->fMaskFormat)) return false;
902
903 return true;
904 }
905
readStrikeData(const volatile void * memory,size_t memorySize)906 bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) {
907 SkASSERT(memorySize != 0u);
908 Deserializer deserializer(static_cast<const volatile char*>(memory), memorySize);
909
910 uint64_t typefaceSize = 0;
911 uint64_t strikeCount = 0;
912 uint64_t glyphImagesCount = 0;
913 uint64_t glyphPathsCount = 0;
914
915 if (!deserializer.read<uint64_t>(&typefaceSize)) READ_FAILURE
916 for (size_t i = 0; i < typefaceSize; ++i) {
917 WireTypeface wire;
918 if (!deserializer.read<WireTypeface>(&wire)) READ_FAILURE
919
920 // TODO(khushalsagar): The typeface no longer needs a reference to the
921 // SkStrikeClient, since all needed glyphs must have been pushed before
922 // raster.
923 addTypeface(wire);
924 }
925
926 if (!deserializer.read<uint64_t>(&strikeCount)) READ_FAILURE
927
928 for (size_t i = 0; i < strikeCount; ++i) {
929 StrikeSpec spec;
930 if (!deserializer.read<StrikeSpec>(&spec)) READ_FAILURE
931
932 SkAutoDescriptor sourceAd;
933 if (!deserializer.readDescriptor(&sourceAd)) READ_FAILURE
934
935 bool fontMetricsInitialized;
936 if (!deserializer.read(&fontMetricsInitialized)) READ_FAILURE
937
938 SkFontMetrics fontMetrics{};
939 if (!fontMetricsInitialized) {
940 if (!deserializer.read<SkFontMetrics>(&fontMetrics)) READ_FAILURE
941 }
942
943 // Get the local typeface from remote fontID.
944 auto* tfPtr = fRemoteFontIdToTypeface.find(spec.typefaceID);
945 // Received strikes for a typeface which doesn't exist.
946 if (!tfPtr) READ_FAILURE
947 auto* tf = tfPtr->get();
948
949 // Replace the ContextRec in the desc from the server to create the client
950 // side descriptor.
951 // TODO: Can we do this in-place and re-compute checksum? Instead of a complete copy.
952 SkAutoDescriptor ad;
953 auto* client_desc = auto_descriptor_from_desc(sourceAd.getDesc(), tf->uniqueID(), &ad);
954
955 auto strike = fStrikeCache->findStrike(*client_desc);
956 // Metrics are only sent the first time. If the metrics are not initialized, there must
957 // be an existing strike.
958 if (fontMetricsInitialized && strike == nullptr) READ_FAILURE
959 if (strike == nullptr) {
960 // Note that we don't need to deserialize the effects since we won't be generating any
961 // glyphs here anyway, and the desc is still correct since it includes the serialized
962 // effects.
963 SkScalerContextEffects effects;
964 auto scaler = tf->createScalerContext(effects, client_desc);
965 strike = fStrikeCache->createStrike(
966 *client_desc, std::move(scaler), &fontMetrics,
967 std::make_unique<DiscardableStrikePinner>(
968 spec.discardableHandleId, fDiscardableHandleManager));
969 }
970
971 if (!deserializer.read<uint64_t>(&glyphImagesCount)) READ_FAILURE
972 for (size_t j = 0; j < glyphImagesCount; j++) {
973 SkTLazy<SkGlyph> glyph;
974 if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE
975
976 if (!glyph->isEmpty() && SkStrikeForGPU::FitsInAtlas(*glyph)) {
977 const volatile void* image =
978 deserializer.read(glyph->imageSize(), glyph->formatAlignment());
979 if (!image) READ_FAILURE
980 glyph->fImage = (void*)image;
981 }
982
983 strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph);
984 }
985
986 if (!deserializer.read<uint64_t>(&glyphPathsCount)) READ_FAILURE
987 for (size_t j = 0; j < glyphPathsCount; j++) {
988 SkTLazy<SkGlyph> glyph;
989 if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE
990
991 SkGlyph* allocatedGlyph = strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph);
992
993 SkPath* pathPtr = nullptr;
994 SkPath path;
995 uint64_t pathSize = 0u;
996 if (!deserializer.read<uint64_t>(&pathSize)) READ_FAILURE
997
998 if (pathSize > 0) {
999 auto* pathData = deserializer.read(pathSize, kPathAlignment);
1000 if (!pathData) READ_FAILURE
1001 if (!path.readFromMemory(const_cast<const void*>(pathData), pathSize)) READ_FAILURE
1002 pathPtr = &path;
1003 }
1004
1005 strike->mergePath(allocatedGlyph, pathPtr);
1006 }
1007 }
1008
1009 return true;
1010 }
1011
deserializeTypeface(const void * buf,size_t len)1012 sk_sp<SkTypeface> SkStrikeClient::deserializeTypeface(const void* buf, size_t len) {
1013 WireTypeface wire;
1014 if (len != sizeof(wire)) return nullptr;
1015 memcpy(&wire, buf, sizeof(wire));
1016 return this->addTypeface(wire);
1017 }
1018
addTypeface(const WireTypeface & wire)1019 sk_sp<SkTypeface> SkStrikeClient::addTypeface(const WireTypeface& wire) {
1020 auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID);
1021 if (typeface) return *typeface;
1022
1023 auto newTypeface = sk_make_sp<SkTypefaceProxy>(
1024 wire.typefaceID, wire.glyphCount, wire.style, wire.isFixed,
1025 fDiscardableHandleManager, fIsLogging);
1026 fRemoteFontIdToTypeface.set(wire.typefaceID, newTypeface);
1027 return std::move(newTypeface);
1028 }
1029