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 | |
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 | |
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 ----------------------------------------------------------------------------------- |
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> |
78 | size_t serialization_alignment() { |
79 | return sizeof(T) == 8 ? 8 : alignof(T); |
80 | } |
81 | |
82 | class Serializer { |
83 | public: |
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> |
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> |
99 | T* allocate() { |
100 | T* result = (T*)allocate(sizeof(T), serialization_alignment<T>()); |
101 | return result; |
102 | } |
103 | |
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 | |
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: |
124 | Deserializer(const volatile char* memory, size_t memorySize) |
125 | : fMemory(memory), fMemorySize(memorySize) {} |
126 | |
127 | template <typename T> |
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 | |
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 | |
152 | const volatile void* read(size_t size, size_t alignment) { |
153 | return this->ensureAtLeast(size, alignment); |
154 | } |
155 | |
156 | size_t bytesRead() const { return fBytesRead; } |
157 | |
158 | private: |
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 | |
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; |
188 | 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: |
206 | bool test(SkPackedGlyphID packedID) const { |
207 | uint32_t bit = packedID.value(); |
208 | return bit < kMaxIndex && fBits.test(bit); |
209 | } |
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); |
236 | SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; } |
237 | |
238 | const SkDescriptor& getDescriptor() const override { |
239 | return *fDescriptor.getDesc(); |
240 | } |
241 | |
242 | void setTypefaceAndEffects(const SkTypeface* typeface, SkScalerContextEffects effects); |
243 | |
244 | 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 | |
257 | void onAboutToExitScope() override {} |
258 | |
259 | 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 { |
283 | static SkPackedGlyphID GetKey(MaskSummary summary) { |
284 | return SkPackedGlyphID{summary.packedID}; |
285 | } |
286 | |
287 | 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 { |
302 | static SkGlyphID GetKey(PathSummary summary) { |
303 | return summary.glyphID; |
304 | } |
305 | |
306 | 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 | |
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 | |
363 | size_t SkStrikeServer::MapOps::operator()(const SkDescriptor* key) const { |
364 | return key->getChecksum(); |
365 | } |
366 | |
367 | 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: |
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 | |
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 | |
390 | SkStrikeServer* strikeServer() { return fStrikeServer; } |
391 | |
392 | protected: |
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 ------------------------------------------------------------------- |
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 | |
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 | |
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 | |
453 | SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy( |
454 | const SaveLayerRec& rec) { |
455 | return kFullLayer_SaveLayerStrategy; |
456 | } |
457 | |
458 | bool SkTextBlobCacheDiffCanvas::onDoSaveBehind(const SkRect*) { |
459 | return false; |
460 | } |
461 | |
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; |
470 | 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 ---------------------------------------------------------------------------------- |
480 | SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager) |
481 | : fDiscardableHandleManager(discardableHandleManager) { |
482 | SkASSERT(fDiscardableHandleManager); |
483 | } |
484 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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. |
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 | |
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 | |
710 | void SkStrikeServer::RemoteStrike::ensureScalerContext() { |
711 | if (fContext == nullptr) { |
712 | fContext = fTypeface->createScalerContext(fEffects, fDescriptor.getDesc()); |
713 | } |
714 | } |
715 | |
716 | void SkStrikeServer::RemoteStrike::resetScalerContext() { |
717 | fContext.reset(); |
718 | fTypeface = nullptr; |
719 | } |
720 | |
721 | void SkStrikeServer::RemoteStrike::setTypefaceAndEffects( |
722 | const SkTypeface* typeface, SkScalerContextEffects effects) { |
723 | fTypeface = typeface; |
724 | fEffects = effects; |
725 | } |
726 | |
727 | 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> |
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 | |
772 | void SkStrikeServer::RemoteStrike::prepareForMaskDrawing( |
773 | SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) { |
774 | for (auto [i, variant, _] : SkMakeEnumerate(drawables->input())) { |
775 | SkPackedGlyphID packedID = variant.packedID(); |
776 | if (fSentLowGlyphIDs.test(packedID)) { |
777 | SkASSERT(fSentGlyphs.find(packedID) != nullptr); |
778 | continue; |
779 | } |
780 | |
781 | MaskSummary* summary = fSentGlyphs.find(packedID); |
782 | if (summary == nullptr) { |
783 | // Put the new SkGlyph in the glyphs to send. |
784 | fMasksToSend.emplace_back(packedID); |
785 | SkGlyph* glyph = &fMasksToSend.back(); |
786 | |
787 | // Build the glyph |
788 | this->ensureScalerContext(); |
789 | fContext->getMetrics(glyph); |
790 | |
791 | fSentLowGlyphIDs.setIfLower(packedID); |
792 | |
793 | MaskSummary newSummary = |
794 | {packedID.value(), CanDrawAsMask(*glyph), CanDrawAsSDFT(*glyph)}; |
795 | summary = fSentGlyphs.set(newSummary); |
796 | } |
797 | |
798 | // Reject things that are too big. |
799 | if (!summary->canDrawAsMask) { |
800 | rejects->reject(i); |
801 | } |
802 | } |
803 | } |
804 | |
805 | void SkStrikeServer::RemoteStrike::prepareForSDFTDrawing( |
806 | SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) { |
807 | this->commonMaskLoop(drawables, rejects, |
808 | [](MaskSummary summary){return !summary.canDrawAsSDFT;}); |
809 | } |
810 | |
811 | void SkStrikeServer::RemoteStrike::prepareForPathDrawing( |
812 | SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) { |
813 | drawables->forEachGlyphID( |
814 | [&](size_t i, SkPackedGlyphID packedID, SkPoint position) { |
815 | SkGlyphID glyphID = packedID.glyphID(); |
816 | PathSummary* summary = fSentPaths.find(glyphID); |
817 | if (summary == nullptr) { |
818 | // Put the new SkGlyph in the glyphs to send. |
819 | fPathsToSend.emplace_back(SkPackedGlyphID{glyphID}); |
820 | SkGlyph* glyph = &fPathsToSend.back(); |
821 | |
822 | // Build the glyph |
823 | this->ensureScalerContext(); |
824 | fContext->getMetrics(glyph); |
825 | |
826 | uint16_t maxDimensionOrPath = glyph->maxDimension(); |
827 | // Only try to get the path if the glyphs is not color. |
828 | if (!glyph->isColor() && !glyph->isEmpty()) { |
829 | glyph->setPath(&fPathAlloc, fContext.get()); |
830 | if (glyph->path() != nullptr) { |
831 | maxDimensionOrPath = PathSummary::kIsPath; |
832 | } |
833 | } |
834 | |
835 | PathSummary newSummary = {glyph->getGlyphID(), maxDimensionOrPath}; |
836 | summary = fSentPaths.set(newSummary); |
837 | } |
838 | |
839 | if (summary->maxDimensionOrPath != PathSummary::kIsPath) { |
840 | rejects->reject(i, (int)summary->maxDimensionOrPath); |
841 | } |
842 | }); |
843 | } |
844 | |
845 | // SkStrikeClient ---------------------------------------------------------------------------------- |
846 | class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner { |
847 | public: |
848 | DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId, |
849 | sk_sp<DiscardableHandleManager> manager) |
850 | : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {} |
851 | |
852 | ~DiscardableStrikePinner() override = default; |
853 | bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); } |
854 | |
855 | private: |
856 | const SkDiscardableHandleId fDiscardableHandleId; |
857 | sk_sp<DiscardableHandleManager> fManager; |
858 | }; |
859 | |
860 | SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager, |
861 | bool isLogging, |
862 | SkStrikeCache* strikeCache) |
863 | : fDiscardableHandleManager(std::move(discardableManager)) |
864 | , fStrikeCache{strikeCache ? strikeCache : SkStrikeCache::GlobalStrikeCache()} |
865 | , fIsLogging{isLogging} {} |
866 | |
867 | SkStrikeClient::~SkStrikeClient() = default; |
868 | |
869 | #define READ_FAILURE \ |
870 | { \ |
871 | SkDebugf("Bad font data serialization line: %d", __LINE__); \ |
872 | DiscardableHandleManager::ReadFailureData data = { \ |
873 | memorySize, deserializer.bytesRead(), typefaceSize, \ |
874 | strikeCount, glyphImagesCount, glyphPathsCount}; \ |
875 | fDiscardableHandleManager->notifyReadFailure(data); \ |
876 | return false; \ |
877 | } |
878 | |
879 | // No need to read fForceBW because it is a flag private to SkScalerContext_DW, which will never |
880 | // be called on the GPU side. |
881 | bool SkStrikeClient::ReadGlyph(SkTLazy<SkGlyph>& glyph, Deserializer* deserializer) { |
882 | SkPackedGlyphID glyphID; |
883 | if (!deserializer->read<SkPackedGlyphID>(&glyphID)) return false; |
884 | glyph.init(glyphID); |
885 | if (!deserializer->read<float>(&glyph->fAdvanceX)) return false; |
886 | if (!deserializer->read<float>(&glyph->fAdvanceY)) return false; |
887 | if (!deserializer->read<uint16_t>(&glyph->fWidth)) return false; |
888 | if (!deserializer->read<uint16_t>(&glyph->fHeight)) return false; |
889 | if (!deserializer->read<int16_t>(&glyph->fTop)) return false; |
890 | if (!deserializer->read<int16_t>(&glyph->fLeft)) return false; |
891 | if (!deserializer->read<uint8_t>(&glyph->fMaskFormat)) return false; |
892 | if (!SkMask::IsValidFormat(glyph->fMaskFormat)) return false; |
893 | |
894 | return true; |
895 | } |
896 | |
897 | bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) { |
898 | SkASSERT(memorySize != 0u); |
899 | Deserializer deserializer(static_cast<const volatile char*>(memory), memorySize); |
900 | |
901 | uint64_t typefaceSize = 0; |
902 | uint64_t strikeCount = 0; |
903 | uint64_t glyphImagesCount = 0; |
904 | uint64_t glyphPathsCount = 0; |
905 | |
906 | if (!deserializer.read<uint64_t>(&typefaceSize)) READ_FAILURE |
907 | for (size_t i = 0; i < typefaceSize; ++i) { |
908 | WireTypeface wire; |
909 | if (!deserializer.read<WireTypeface>(&wire)) READ_FAILURE |
910 | |
911 | // TODO(khushalsagar): The typeface no longer needs a reference to the |
912 | // SkStrikeClient, since all needed glyphs must have been pushed before |
913 | // raster. |
914 | addTypeface(wire); |
915 | } |
916 | |
917 | if (!deserializer.read<uint64_t>(&strikeCount)) READ_FAILURE |
918 | |
919 | for (size_t i = 0; i < strikeCount; ++i) { |
920 | StrikeSpec spec; |
921 | if (!deserializer.read<StrikeSpec>(&spec)) READ_FAILURE |
922 | |
923 | SkAutoDescriptor sourceAd; |
924 | if (!deserializer.readDescriptor(&sourceAd)) READ_FAILURE |
925 | |
926 | bool fontMetricsInitialized; |
927 | if (!deserializer.read(&fontMetricsInitialized)) READ_FAILURE |
928 | |
929 | SkFontMetrics fontMetrics{}; |
930 | if (!fontMetricsInitialized) { |
931 | if (!deserializer.read<SkFontMetrics>(&fontMetrics)) READ_FAILURE |
932 | } |
933 | |
934 | // Get the local typeface from remote fontID. |
935 | auto* tfPtr = fRemoteFontIdToTypeface.find(spec.typefaceID); |
936 | // Received strikes for a typeface which doesn't exist. |
937 | if (!tfPtr) READ_FAILURE |
938 | auto* tf = tfPtr->get(); |
939 | |
940 | // Replace the ContextRec in the desc from the server to create the client |
941 | // side descriptor. |
942 | // TODO: Can we do this in-place and re-compute checksum? Instead of a complete copy. |
943 | SkAutoDescriptor ad; |
944 | auto* client_desc = auto_descriptor_from_desc(sourceAd.getDesc(), tf->uniqueID(), &ad); |
945 | |
946 | auto strike = fStrikeCache->findStrike(*client_desc); |
947 | // Metrics are only sent the first time. If the metrics are not initialized, there must |
948 | // be an existing strike. |
949 | if (fontMetricsInitialized && strike == nullptr) READ_FAILURE |
950 | if (strike == nullptr) { |
951 | // Note that we don't need to deserialize the effects since we won't be generating any |
952 | // glyphs here anyway, and the desc is still correct since it includes the serialized |
953 | // effects. |
954 | SkScalerContextEffects effects; |
955 | auto scaler = tf->createScalerContext(effects, client_desc); |
956 | strike = fStrikeCache->createStrike( |
957 | *client_desc, std::move(scaler), &fontMetrics, |
958 | std::make_unique<DiscardableStrikePinner>( |
959 | spec.discardableHandleId, fDiscardableHandleManager)); |
960 | } |
961 | |
962 | if (!deserializer.read<uint64_t>(&glyphImagesCount)) READ_FAILURE |
963 | for (size_t j = 0; j < glyphImagesCount; j++) { |
964 | SkTLazy<SkGlyph> glyph; |
965 | if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE |
966 | |
967 | if (!glyph->isEmpty() && SkStrikeForGPU::FitsInAtlas(*glyph)) { |
968 | const volatile void* image = |
969 | deserializer.read(glyph->imageSize(), glyph->formatAlignment()); |
970 | if (!image) READ_FAILURE |
971 | glyph->fImage = (void*)image; |
972 | } |
973 | |
974 | strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph); |
975 | } |
976 | |
977 | if (!deserializer.read<uint64_t>(&glyphPathsCount)) READ_FAILURE |
978 | for (size_t j = 0; j < glyphPathsCount; j++) { |
979 | SkTLazy<SkGlyph> glyph; |
980 | if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE |
981 | |
982 | SkGlyph* allocatedGlyph = strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph); |
983 | |
984 | SkPath* pathPtr = nullptr; |
985 | SkPath path; |
986 | uint64_t pathSize = 0u; |
987 | if (!deserializer.read<uint64_t>(&pathSize)) READ_FAILURE |
988 | |
989 | if (pathSize > 0) { |
990 | auto* pathData = deserializer.read(pathSize, kPathAlignment); |
991 | if (!pathData) READ_FAILURE |
992 | if (!path.readFromMemory(const_cast<const void*>(pathData), pathSize)) READ_FAILURE |
993 | pathPtr = &path; |
994 | } |
995 | |
996 | strike->mergePath(allocatedGlyph, pathPtr); |
997 | } |
998 | } |
999 | |
1000 | return true; |
1001 | } |
1002 | |
1003 | sk_sp<SkTypeface> SkStrikeClient::deserializeTypeface(const void* buf, size_t len) { |
1004 | WireTypeface wire; |
1005 | if (len != sizeof(wire)) return nullptr; |
1006 | memcpy(&wire, buf, sizeof(wire)); |
1007 | return this->addTypeface(wire); |
1008 | } |
1009 | |
1010 | sk_sp<SkTypeface> SkStrikeClient::addTypeface(const WireTypeface& wire) { |
1011 | auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID); |
1012 | if (typeface) return *typeface; |
1013 | |
1014 | auto newTypeface = sk_make_sp<SkTypefaceProxy>( |
1015 | wire.typefaceID, wire.glyphCount, wire.style, wire.isFixed, |
1016 | fDiscardableHandleManager, fIsLogging); |
1017 | fRemoteFontIdToTypeface.set(wire.typefaceID, newTypeface); |
1018 | return std::move(newTypeface); |
1019 | } |
1020 | |