diff options
author | Mike Klein <mtklein@google.com> | 2018-05-02 13:54:11 +0000 |
---|---|---|
committer | Mike Klein <mtklein@google.com> | 2018-05-02 13:55:08 +0000 |
commit | 8a232023e192b30a2148b0c07116e43f800d3233 (patch) | |
tree | 17a3a809cbb7e0d50efc9c758c350c1957c77e73 | |
parent | c76e26a6bb8af9ac9b0c7226851b2ded12d18687 (diff) |
Revert "fonts: Set up remote glyph caching to push fonts."
This reverts commit 101d56359a5a5dc3b8a2a4149ac171e25eb0bec0.
Reason for revert: 5 of 5
Original change's description:
> fonts: Set up remote glyph caching to push fonts.
>
> Currently the SkStrikeClient is designed to pull fonts from the server
> on demand, and to pre-fetch a batched request by analyzing the ops using
> a SkTextBlobCacheDiffCanvas. This change modifies the design to support
> a push based model, where the server pushes fonts required by the client
> and sets up the requisite SkGlyphCaches on the client prior to
> rasterizing the ops.
>
> This model still relies on the SkTextBlobCacheDiffCanvas for analyzing
> the glyphs required for rasterizing an op. The glyph caches required for
> raster are locked and missing glyphs to be sent to the client are tracked
> by the SkStrikeServer. The embedder can serialize this font data at any
> point, but must ensure that this data is deserialized by the
> SkStrikeClient at the remote end, before rasterizing any ops analyzed
> prior to serialization. Any refs on the caches are released once the
> font data is serialized by the server.
>
> The locking of glyph caches relies on the embedder providing discardable
> handles. These handles can be created on the server and serialized to be
> sent to the client, and map to an instance of SkGlyphCache. This allows
> the server to control the lifetime of the caches on the client.
>
> Bug: skia:7515
> Change-Id: Id39f346b47b60899778404bbd0429ee811d0e53b
> Reviewed-on: https://skia-review.googlesource.com/120283
> Commit-Queue: Khusal Sagar <khushalsagar@chromium.org>
> Reviewed-by: Herb Derby <herb@google.com>
TBR=mtklein@google.com,herb@google.com,khushalsagar@chromium.org
Change-Id: If72caf968ddcbf70b8b9d71782a2339a118ed202
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:7515
Reviewed-on: https://skia-review.googlesource.com/125264
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
-rw-r--r-- | gn/tests.gni | 1 | ||||
-rw-r--r-- | src/core/SkRemoteGlyphCache.cpp | 797 | ||||
-rw-r--r-- | src/core/SkRemoteGlyphCache.h | 288 | ||||
-rw-r--r-- | src/core/SkScalerContext.h | 4 | ||||
-rw-r--r-- | src/core/SkStrikeCache.h | 19 | ||||
-rw-r--r-- | src/core/SkTypeface_remote.cpp | 17 | ||||
-rw-r--r-- | src/core/SkTypeface_remote.h | 27 | ||||
-rw-r--r-- | tests/SkRemoteGlyphCacheTest.cpp | 220 | ||||
-rw-r--r-- | tools/remote_demo.cpp | 130 |
9 files changed, 642 insertions, 861 deletions
diff --git a/gn/tests.gni b/gn/tests.gni index ebf83bbd63..d18758c05e 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -226,7 +226,6 @@ tests_sources = [ "$_tests/SkNxTest.cpp", "$_tests/SkPEGTest.cpp", "$_tests/SkRasterPipelineTest.cpp", - "$_tests/SkRemoteGlyphCacheTest.cpp", "$_tests/SkResourceCacheTest.cpp", "$_tests/SkSharedMutexTest.cpp", "$_tests/SkSLErrorTest.cpp", diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp index e45421aa05..ed484dd6fd 100644 --- a/src/core/SkRemoteGlyphCache.cpp +++ b/src/core/SkRemoteGlyphCache.cpp @@ -9,51 +9,13 @@ #include <iterator> #include <memory> -#include <string> #include <tuple> #include "SkDevice.h" #include "SkFindAndPlaceGlyph.h" #include "SkStrikeCache.h" -#include "SkTextBlobRunIterator.h" -#include "SkTraceEvent.h" #include "SkTypeface_remote.h" -static SkDescriptor* auto_descriptor_from_desc(const SkDescriptor* source_desc, - SkFontID font_id, - SkAutoDescriptor* ad) { - ad->reset(source_desc->getLength()); - auto* desc = ad->getDesc(); - desc->init(); - - // Rec. - { - uint32_t size; - auto ptr = source_desc->findEntry(kRec_SkDescriptorTag, &size); - SkScalerContextRec rec; - std::memcpy(&rec, ptr, size); - rec.fFontID = font_id; - desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - } - - // Path effect. - { - uint32_t size; - auto ptr = source_desc->findEntry(kPathEffect_SkDescriptorTag, &size); - if (ptr) desc->addEntry(kPathEffect_SkDescriptorTag, size, ptr); - } - - // Mask filter. - { - uint32_t size; - auto ptr = source_desc->findEntry(kMaskFilter_SkDescriptorTag, &size); - if (ptr) desc->addEntry(kMaskFilter_SkDescriptorTag, size, ptr); - } - - desc->computeChecksum(); - return desc; -} - template <typename T> class ArraySlice final : public std::tuple<const T*, size_t> { public: @@ -64,6 +26,7 @@ public: const T* begin() { return this->data(); } + const T* end() { return &this->data()[this->size()]; } @@ -83,32 +46,28 @@ private: // -- Serializer ---------------------------------------------------------------------------------- -size_t pad(size_t size, size_t alignment) { return (size + (alignment - 1)) & ~(alignment - 1); } +static size_t pad(size_t size, size_t alignment) { + return (size + (alignment - 1)) & ~(alignment - 1); +} +// N.B. pointers are only valid until the next call. class Serializer { public: Serializer(std::vector<uint8_t>* buffer) : fBuffer{buffer} { } - template <typename T, typename... Args> - T* emplace(Args&&... args) { - auto result = allocate(sizeof(T), alignof(T)); - return new (result) T{std::forward<Args>(args)...}; - } - template <typename T> - void write(const T& data) { - T* result = (T*)allocate(sizeof(T), alignof(T)); - memcpy(result, &data, sizeof(T)); + T* push_back(const T& data) { + auto result = allocate(sizeof(T), alignof(T)); + return new (result) T(data); } - template <typename T> - T* allocate() { - T* result = (T*)allocate(sizeof(T), alignof(T)); - return result; + template <typename T, typename... Args> + T* emplace_back(Args&& ... args) { + auto result = allocate(sizeof(T), alignof(T)); + return new (result) T{std::forward<Args>(args)...}; } void writeDescriptor(const SkDescriptor& desc) { - write(desc.getLength()); auto result = allocate(desc.getLength(), alignof(SkDescriptor)); memcpy(result, &desc, desc.getLength()); } @@ -130,69 +89,86 @@ private: }; // -- Deserializer ------------------------------------------------------------------------------- -// Note that the Deserializer is reading untrusted data, we need to guard against invalid data. + class Deserializer { public: - Deserializer(const volatile char* memory, size_t memorySize) - : fMemory(memory), fMemorySize(memorySize) {} + Deserializer(const SkData& buffer) : fBuffer{buffer} { } template <typename T> - bool read(T* val) { - auto* result = this->ensureAtLeast(sizeof(T), alignof(T)); - if (!result) return false; - - memcpy(val, const_cast<const char*>(result), sizeof(T)); - return true; - } - - bool readDescriptor(SkAutoDescriptor* ad) { - uint32_t desc_length = 0u; - if (!read<uint32_t>(&desc_length)) return false; - - auto* result = this->ensureAtLeast(desc_length, alignof(SkDescriptor)); - if (!result) return false; - - ad->reset(desc_length); - memcpy(ad->getDesc(), const_cast<const char*>(result), desc_length); - return true; + T* read() { + size_t padded = pad(fCursor, alignof(T)); + fCursor = padded + sizeof(T); + auto data = (uint8_t*)fBuffer.data(); + return (T*)&data[padded]; + } + + SkDescriptor* readDescriptor() { + size_t padded = pad(fCursor, alignof(SkDescriptor)); + auto data = (uint8_t*)fBuffer.data(); + SkDescriptor* result = (SkDescriptor*)&data[padded]; + fCursor = padded + result->getLength(); + return result; } template <typename T> ArraySlice<T> readArray(int count) { + size_t padded = pad(fCursor, alignof(T)); size_t size = count * sizeof(T); - const T* base = (const T*)this->ensureAtLeast(size, alignof(T)); - if (!base) return ArraySlice<T>(); - + auto data = (uint8_t*)fBuffer.data(); + const T* base = (const T*)&data[padded]; ArraySlice<T> result = ArraySlice<T>{base, (uint32_t)count}; + fCursor = padded + size; return result; } + size_t size() {return fCursor;} + private: - const volatile char* ensureAtLeast(size_t size, size_t alignment) { - size_t padded = pad(fBytesRead, alignment); + const SkData& fBuffer; + size_t fCursor{0}; +}; - // Not enough data - if (padded + size > fMemorySize) return nullptr; - auto* result = fMemory + padded; - fBytesRead = padded + size; - return result; - } +// -- SkStrikeCacheDifferenceSpec ------------------------------------------------------------------ - // Note that we read each piece of memory only once to guard against TOCTOU violations. - const volatile char* fMemory; - size_t fMemorySize; - size_t fBytesRead = 0u; -}; +SkStrikeDifferences::SkStrikeDifferences( + SkFontID typefaceID, std::unique_ptr<SkDescriptor> desc) + : fTypefaceID{typefaceID} + , fDesc{std::move(desc)} { } -size_t SkDescriptorMapOperators::operator()(const SkDescriptor* key) const { - return key->getChecksum(); +void SkStrikeDifferences::add(uint16_t glyphID, SkIPoint pos) { + SkPackedGlyphID packedGlyphID{glyphID, pos.x(), pos.y()}; + fGlyphIDs->add(packedGlyphID); +} + +SkStrikeDifferences& SkStrikeCacheDifferenceSpec::findStrikeDifferences( + const SkDescriptor& desc, SkFontID typefaceID) +{ + auto mapIter = fDescriptorToDifferencesMap.find(&desc); + if (mapIter == fDescriptorToDifferencesMap.end()) { + auto newDesc = desc.copy(); + auto newDescPtr = newDesc.get(); + SkStrikeDifferences strikeDiffs{typefaceID, std::move(newDesc)}; + + mapIter = fDescriptorToDifferencesMap.emplace_hint( + mapIter, newDescPtr, std::move(strikeDiffs)); } - bool SkDescriptorMapOperators::operator()(const SkDescriptor* lhs, - const SkDescriptor* rhs) const { - return *lhs == *rhs; + return mapIter->second; +} + +template <typename PerStrike, typename PerGlyph> +void SkStrikeCacheDifferenceSpec::iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const { + for (auto& i : fDescriptorToDifferencesMap) { + auto strikeDiff = &i.second; + perStrike(strikeDiff->fTypefaceID, + *strikeDiff->fDesc, + strikeDiff->fGlyphIDs->count()); + strikeDiff->fGlyphIDs->foreach([&](SkPackedGlyphID id) { + perGlyph(id); + }); } +} // -- TrackLayerDevice ----------------------------------------------------------------------------- class TrackLayerDevice : public SkNoPixelsDevice { @@ -206,18 +182,17 @@ public: }; // -- SkTextBlobCacheDiffCanvas ------------------------------------------------------------------- -SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height, - const SkMatrix& deviceMatrix, - const SkSurfaceProps& props, - SkStrikeServer* strikeSever) +SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas( + int width, int height, + const SkMatrix& deviceMatrix, + const SkSurfaceProps& props, + SkScalerContextFlags flags, + SkStrikeCacheDifferenceSpec* strikeDiffs) : SkNoDrawCanvas{new TrackLayerDevice{SkIRect::MakeWH(width, height), props}} , fDeviceMatrix{deviceMatrix} , fSurfaceProps{props} - , fStrikeServer{strikeSever} { - SkASSERT(fStrikeServer); -} - -SkTextBlobCacheDiffCanvas::~SkTextBlobCacheDiffCanvas() = default; + , fScalerContextFlags{flags} + , fStrikeCacheDiff{strikeDiffs} { } SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy( const SaveLayerRec&rec) @@ -260,10 +235,6 @@ void SkTextBlobCacheDiffCanvas::processLooper( } } -#define FAIL_AND_RETURN \ - SkDEBUGFAIL("Failed to process glyph run"); \ - return; - void SkTextBlobCacheDiffCanvas::processGlyphRun( const SkPoint& position, const SkTextBlobRunIterator& it, @@ -271,24 +242,20 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun( { if (runPaint.getTextEncoding() != SkPaint::TextEncoding::kGlyphID_TextEncoding) { - TRACE_EVENT0("skia", "kGlyphID_TextEncoding"); - FAIL_AND_RETURN + return; } // All other alignment modes need the glyph advances. Use the slow drawing mode. if (runPaint.getTextAlign() != SkPaint::kLeft_Align) { - TRACE_EVENT0("skia", "kLeft_Align"); - FAIL_AND_RETURN + return; } using PosFn = SkPoint(*)(int index, const SkScalar* pos); PosFn posFn; switch (it.positioning()) { - case SkTextBlob::kDefault_Positioning: { + case SkTextBlob::kDefault_Positioning: // Default positioning needs advances. Can't do that. - TRACE_EVENT0("skia", "kDefault_Positioning"); - FAIL_AND_RETURN - } + return; case SkTextBlob::kHorizontal_Positioning: posFn = [](int index, const SkScalar* pos) { @@ -311,8 +278,7 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun( SkMatrix blobMatrix{fDeviceMatrix}; blobMatrix.preConcat(this->getTotalMatrix()); if (blobMatrix.hasPerspective()) { - TRACE_EVENT0("skia", "hasPerspective"); - FAIL_AND_RETURN + return; } blobMatrix.preTranslate(position.x(), position.y()); @@ -349,21 +315,19 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun( SK_ABORT("Bad matrix."); } + SkAutoDescriptor ad; SkScalerContextRec rec; SkScalerContextEffects effects; - // TODO(crbug.com/831354): The typeface proxy on the client does not replicate the - // filtering done by the typeface on the server. SkScalerContext::MakeRecAndEffects(runPaint, &fSurfaceProps, &runMatrix, - SkScalerContextFlags::kFakeGammaAndBoostContrast, &rec, - &effects); + fScalerContextFlags, &rec, &effects); + + auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad); - TRACE_EVENT1("skia", "RecForDesc", "rec", TRACE_STR_COPY(rec.dump().c_str())); - auto desc = SkScalerContext::DescriptorGivenRecAndEffects(rec, effects); - auto* glyphCacheState = static_cast<SkStrikeServer*>(fStrikeServer) - ->getOrCreateCache(runPaint.getTypeface(), std::move(desc)); - SkASSERT(glyphCacheState); + auto typefaceID = SkTypefaceProxy::DownCast(runPaint.getTypeface())->remoteTypefaceID(); + auto& diffs = fStrikeCacheDiff->findStrikeDifferences(*desc, typefaceID); + auto cache = SkStrikeCache::FindStrikeExclusive(*desc); bool isSubpixel = SkToBool(rec.fFlags & SkScalerContext::kSubpixelPositioning_Flag); SkAxisAlignment axisAlignment = SkAxisAlignment::kNone_SkAxisAlignment; if (it.positioning() == SkTextBlob::kHorizontal_Positioning) { @@ -378,323 +342,392 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun( subPixelPos = SkFindAndPlaceGlyph::SubpixelAlignment(axisAlignment, glyphPos); } - glyphCacheState->addGlyph(runPaint.getTypeface(), - effects, - SkPackedGlyphID(glyphs[index], subPixelPos.x(), subPixelPos.y())); + if (cache && + cache->isGlyphCached(glyphs[index], subPixelPos.x(), subPixelPos.y())) { + continue; + } + + diffs.add(glyphs[index], subPixelPos); } } +// Op code semantics: +// * FontMetrics - (SkFontID, SkDescriptor) -> SkPaint::FontMetrics +// * GlyphPath - (SkFontID, SkDescriptor, SkPackedGlyphID) -> SkPath +// * GlyphMetricsAndImage - (SkFontID, SkDescriptor, SkPackedGlyphID) -> (SkGlyph, <image bits>) +// * PrepopulateCache - StrikeCacheDifferenceSpec -> StrikeCacheDifferenceData + +enum class OpCode : int32_t { + kFontMetrics = 0, + kGlyphPath = 1, + kGlyphMetricsAndImage = 2, + kPrepopulateCache = 3, +}; + +struct StrikeDiffHeader { + StrikeDiffHeader() {} + StrikeDiffHeader(int strikeCount_) : strikeCount{strikeCount_} {} + int strikeCount; +}; + struct StrikeSpec { - StrikeSpec() {} - StrikeSpec(SkFontID typefaceID_, size_t glyphCount_, SkDiscardableHandleId discardableHandleId_) + StrikeSpec(SkFontID typefaceID_, uint32_t descLength_, int glyphCount_) : typefaceID{typefaceID_} - , glyphCount{glyphCount_} - , discardableHandleId(discardableHandleId_) {} - SkFontID typefaceID = 0u; - size_t glyphCount = 0u; - SkDiscardableHandleId discardableHandleId = 0u; + , descLength{descLength_} + , glyphCount{glyphCount_} { } + SkFontID typefaceID; + uint32_t descLength; + int glyphCount; /* desc */ /* n X (glyphs ids) */ }; struct WireTypeface { - WireTypeface() = default; - WireTypeface(SkFontID typeface_id, int glyph_count, SkFontStyle style, bool is_fixed) - : typefaceID(typeface_id), glyphCount(glyph_count), style(style), isFixed(is_fixed) {} - - // std::thread::id thread_id; // TODO:need to figure a good solution SkFontID typefaceID; int glyphCount; SkFontStyle style; bool isFixed; }; -// SkStrikeServer ----------------------------------------- - -SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager) - : fDiscardableHandleManager(discardableHandleManager) { - SkASSERT(fDiscardableHandleManager); -} - -SkStrikeServer::~SkStrikeServer() = default; +class Op { +public: + Op(OpCode opCode, SkFontID typefaceId, const SkScalerContextRec& rec) + : opCode{opCode} + , typefaceId{typefaceId} + , descriptor{rec} { } + const OpCode opCode; + const SkFontID typefaceId; + const SkScalerContextRecDescriptor descriptor; + union { + // kGlyphPath and kGlyphMetricsAndImage + SkPackedGlyphID glyphID; + // kPrepopulateCache + StrikeDiffHeader strikeSpecHeader; + }; +}; -sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) { - WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(), - tf->isFixedPitch()); - return SkData::MakeWithCopy(&wire, sizeof(wire)); +size_t SkStrikeCacheDifferenceSpec::sizeBytes() const { + size_t sum = sizeof(Op) + sizeof(StrikeDiffHeader); + for (auto& pair : fDescriptorToDifferencesMap) { + const auto& strike = pair.second; + sum += sizeof(StrikeSpec) + + strike.fDesc->getLength() + + strike.fGlyphIDs->count() * sizeof(SkPackedGlyphID); + } + return sum; } -void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) { - if (fLockedDescs.empty() && fTypefacesToSend.empty()) return; +static void write_strikes_spec(const SkStrikeCacheDifferenceSpec &spec, + Serializer* serializer) { + serializer->emplace_back<Op>(OpCode::kPrepopulateCache, SkFontID{0}, SkScalerContextRec{}); - Serializer serializer(memory); - serializer.emplace<size_t>(fTypefacesToSend.size()); - for (const auto& tf : fTypefacesToSend) serializer.write<WireTypeface>(tf); - fTypefacesToSend.clear(); + serializer->emplace_back<StrikeDiffHeader>(spec.strikeCount()); - serializer.emplace<size_t>(fLockedDescs.size()); - for (const auto* desc : fLockedDescs) { - auto it = fRemoteGlyphStateMap.find(desc); - SkASSERT(it != fRemoteGlyphStateMap.end()); + auto perStrike = [serializer](SkFontID typefaceID, const SkDescriptor& desc, int glyphCount) { + serializer->emplace_back<StrikeSpec>(typefaceID, desc.getLength(), glyphCount); + serializer->writeDescriptor(desc); + }; - // TODO: This is unnecessary, write only the descs which has any glyphs - // to send. It was getting awkward to write the size after writing the - // descs because the vector reallocs. - serializer.emplace<bool>(it->second->has_pending_glyphs()); - if (!it->second->has_pending_glyphs()) continue; + auto perGlyph = [serializer](SkPackedGlyphID glyphID) { + serializer->push_back<SkPackedGlyphID>(glyphID); + }; - it->second->writePendingGlyphs(&serializer); - } - fLockedDescs.clear(); + spec.iterateDifferences(perStrike, perGlyph); } -SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache( - SkTypeface* tf, std::unique_ptr<SkDescriptor> desc) { - SkASSERT(desc); - - // Already locked. - if (fLockedDescs.find(desc.get()) != fLockedDescs.end()) { - auto it = fRemoteGlyphStateMap.find(desc.get()); - SkASSERT(it != fRemoteGlyphStateMap.end()); - return it->second.get(); - } - - // Try to lock. - auto it = fRemoteGlyphStateMap.find(desc.get()); - if (it != fRemoteGlyphStateMap.end()) { - bool locked = fDiscardableHandleManager->lockHandle(it->second->discardable_handle_id()); - if (locked) { - fLockedDescs.insert(it->first); - return it->second.get(); +static void read_strikes_spec_write_strikes_data( + Deserializer* deserializer, Serializer* serializer, SkStrikeServer* server) +{ + // Don't start because the op started this deserialization. + auto header = deserializer->read<StrikeDiffHeader>(); + serializer->push_back<StrikeDiffHeader>(*header); + for (int i = 0; i < header->strikeCount; i++) { + auto spec = deserializer->read<StrikeSpec>(); + auto desc = deserializer->readDescriptor(); + serializer->push_back<StrikeSpec>(*spec); + serializer->writeDescriptor(*desc); + SkScalerContextRecDescriptor recDesc{*desc}; + auto scaler = server->generateScalerContext(recDesc, spec->typefaceID); + SkPaint::FontMetrics fontMetrics; + scaler->getFontMetrics(&fontMetrics); + serializer->push_back<SkPaint::FontMetrics>(fontMetrics); + auto glyphIDs = deserializer->readArray<SkPackedGlyphID>(spec->glyphCount); + for (auto glyphID : glyphIDs) { + auto glyph = serializer->emplace_back<SkGlyph>(); + glyph->initWithGlyphID(glyphID); + scaler->getMetrics(glyph); + auto imageSize = glyph->computeImageSize(); + glyph->fPathData = nullptr; + glyph->fImage = nullptr; + + if (imageSize > 0) { + // Since the allocateArray can move glyph, make one that stays in one place. + SkGlyph stationaryGlyph = *glyph; + stationaryGlyph.fImage = serializer->allocateArray<uint8_t>(imageSize); + scaler->getImage(stationaryGlyph); + } } - - // If the lock failed, the entry was deleted on the client. Remove our - // tracking. - fRemoteGlyphStateMap.erase(it); } - - const SkFontID typeface_id = tf->uniqueID(); - if (!fCachedTypefaces.contains(typeface_id)) { - fCachedTypefaces.add(typeface_id); - fTypefacesToSend.emplace_back(typeface_id, tf->countGlyphs(), tf->fontStyle(), - tf->isFixedPitch()); - } - - auto* desc_ptr = desc.get(); - auto new_handle = fDiscardableHandleManager->createHandle(); - auto cache_state = skstd::make_unique<SkGlyphCacheState>(std::move(desc), new_handle); - auto* cache_state_ptr = cache_state.get(); - - fLockedDescs.insert(desc_ptr); - fRemoteGlyphStateMap[desc_ptr] = std::move(cache_state); - return cache_state_ptr; -} - -SkStrikeServer::SkGlyphCacheState::SkGlyphCacheState(std::unique_ptr<SkDescriptor> desc, - uint32_t discardable_handle_id) - : fDesc(std::move(desc)), fDiscardableHandleId(discardable_handle_id) { - SkASSERT(fDesc); -} - -SkStrikeServer::SkGlyphCacheState::~SkGlyphCacheState() = default; - -void SkStrikeServer::SkGlyphCacheState::addGlyph(SkTypeface* typeface, - const SkScalerContextEffects& effects, - SkPackedGlyphID glyph) { - // Already cached. - if (fCachedGlyphs.contains(glyph)) return; - - // Serialize and cache. Also create the scalar context to use when serializing - // this glyph. - fCachedGlyphs.add(glyph); - fPendingGlyphs.push_back(glyph); - if (!fContext) fContext = typeface->createScalerContext(effects, fDesc.get(), false); } -void SkStrikeServer::SkGlyphCacheState::writePendingGlyphs(Serializer* serializer) { - // Write the desc. - serializer->emplace<StrikeSpec>(fContext->getTypeface()->uniqueID(), fPendingGlyphs.size(), - fDiscardableHandleId); - serializer->writeDescriptor(*fDesc.get()); - - // Write FontMetrics. - SkPaint::FontMetrics fontMetrics; - fContext->getFontMetrics(&fontMetrics); - serializer->write<SkPaint::FontMetrics>(fontMetrics); - - // Write Glyphs. - for (const auto& glyphID : fPendingGlyphs) { - auto glyph = serializer->emplace<SkGlyph>(); - glyph->initWithGlyphID(glyphID); - fContext->getMetrics(glyph); - auto imageSize = glyph->computeImageSize(); - glyph->fPathData = nullptr; - glyph->fImage = nullptr; - - if (imageSize > 0) { - // Since the allocateArray can move glyph, make one that stays in one place. - SkGlyph stationaryGlyph = *glyph; - stationaryGlyph.fImage = serializer->allocateArray<uint8_t>(imageSize); - fContext->getImage(stationaryGlyph); +static void update_caches_from_strikes_data(SkStrikeClient *client, + Deserializer *deserializer) { + auto header = deserializer->read<StrikeDiffHeader>(); + for (int i = 0; i < header->strikeCount; i++) { + auto spec = deserializer->read<StrikeSpec>(); + auto desc = deserializer->readDescriptor(); + auto fontMetrics = deserializer->read<SkPaint::FontMetrics>(); + auto tf = client->lookupTypeface(spec->typefaceID); + + // TODO: implement effects handling. + SkScalerContextEffects effects; + auto strike = SkStrikeCache::FindStrikeExclusive(*desc); + if (strike == nullptr) { + auto scaler = SkStrikeCache::CreateScalerContext(*desc, effects, *tf); + strike = SkStrikeCache::CreateStrikeExclusive(*desc, std::move(scaler), fontMetrics); + } + for (int j = 0; j < spec->glyphCount; j++) { + auto glyph = deserializer->read<SkGlyph>(); + ArraySlice<uint8_t> image; + auto imageSize = glyph->computeImageSize(); + if (imageSize != 0) { + image = deserializer->readArray<uint8_t>(imageSize); + } + SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph->getPackedID()); + *allocatedGlyph = *glyph; + allocatedGlyph->allocImage(strike->getAlloc()); + memcpy(allocatedGlyph->fImage, image.data(), image.size()); } } - - // Note that we reset the context after serializing pending glyphs since we - // don't want to extend the lifetime of the typeface. - fPendingGlyphs.clear(); - fContext.reset(); } -// SkStrikeClient ----------------------------------------- +// -- SkStrikeServer ------------------------------------------------------------------------------- +SkStrikeServer::SkStrikeServer() { } -class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner { -public: - DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId, - sk_sp<DiscardableHandleManager> manager) - : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {} +SkStrikeServer::~SkStrikeServer() { + printf("Strike server - ops: %d\n", fOpCount); +} - ~DiscardableStrikePinner() override = default; - bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); } +void SkStrikeServer::serve(const SkData& inBuffer, std::vector<uint8_t>* outBuffer) { -private: - const SkDiscardableHandleId fDiscardableHandleId; - sk_sp<DiscardableHandleManager> fManager; -}; + fOpCount += 1; -SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager) - : fDiscardableHandleManager(std::move(discardableManager)) {} + Serializer serializer{outBuffer}; + Deserializer deserializer{inBuffer}; + Op* op = deserializer.read<Op>(); -SkStrikeClient::~SkStrikeClient() = default; + switch (op->opCode) { + case OpCode::kFontMetrics : { + auto scaler = this->generateScalerContext(op->descriptor, op->typefaceId); + SkPaint::FontMetrics metrics; + scaler->getFontMetrics(&metrics); + serializer.push_back<SkPaint::FontMetrics>(metrics); + break; + } + case OpCode::kGlyphPath : { + auto sc = this->generateScalerContext(op->descriptor, op->typefaceId); + // TODO: check for buffer overflow. + SkPath path; + if (sc->getPath(op->glyphID, &path)) { + size_t pathSize = path.writeToMemory(nullptr); + serializer.push_back<size_t>(pathSize); + auto pathData = serializer.allocateArray<uint8_t>(pathSize); + path.writeToMemory(pathData); + } + break; + } + case OpCode::kGlyphMetricsAndImage : { + auto scaler = this->generateScalerContext(op->descriptor, op->typefaceId); + + auto glyph = serializer.emplace_back<SkGlyph>(); + // TODO: check for buffer overflow. + glyph->initWithGlyphID(op->glyphID); + scaler->getMetrics(glyph); + auto imageSize = glyph->computeImageSize(); + glyph->fPathData = nullptr; + glyph->fImage = nullptr; + if (imageSize > 0) { + // Since the allocateArray can move glyph, make one that stays in one place. + SkGlyph stationaryGlyph = *glyph; + stationaryGlyph.fImage = serializer.allocateArray<uint8_t>(imageSize); + scaler->getImage(stationaryGlyph); + } + break; + } + case OpCode::kPrepopulateCache : { + read_strikes_spec_write_strikes_data( + &deserializer, &serializer, this); + break; + } -#define READ_FAILURE \ - { \ - SkDEBUGFAIL("Bad serialization"); \ - return false; \ + default: + SK_ABORT("Bad op"); } +} -bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) { - SkASSERT(memorySize != 0u); - Deserializer deserializer(static_cast<const volatile char*>(memory), memorySize); - - size_t typefaceSize = 0u; - if (!deserializer.read<size_t>(&typefaceSize)) READ_FAILURE +void SkStrikeServer::prepareSerializeProcs(SkSerialProcs* procs) { + auto encode = [](SkTypeface* tf, void* ctx) { + return reinterpret_cast<SkStrikeServer*>(ctx)->encodeTypeface(tf); + }; + procs->fTypefaceProc = encode; + procs->fTypefaceCtx = this; +} - for (size_t i = 0; i < typefaceSize; ++i) { - WireTypeface wire; - if (!deserializer.read<WireTypeface>(&wire)) READ_FAILURE +SkScalerContext* SkStrikeServer::generateScalerContext( + const SkScalerContextRecDescriptor& desc, SkFontID typefaceId) +{ - // TODO(khushalsagar): The typeface no longer needs a reference to the - // SkStrikeClient, since all needed glyphs must have been pushed before - // raster. - addTypeface(wire); + auto scaler = fScalerContextMap.find(desc); + if (scaler == nullptr) { + auto typefaceIter = fTypefaceMap.find(typefaceId); + if (typefaceIter == nullptr) { + // TODO: handle this with some future fallback strategy. + SK_ABORT("unknown type face"); + // Should never happen + return nullptr; + } + auto tf = typefaceIter->get(); + // TODO: make effects really work. + SkScalerContextEffects effects; + auto mapSc = tf->createScalerContext(effects, &desc.desc(), false); + scaler = fScalerContextMap.set(desc, std::move(mapSc)); } + return scaler->get(); +} - size_t strikeCount = 0u; - if (!deserializer.read<size_t>(&strikeCount)) READ_FAILURE - - for (size_t i = 0; i < strikeCount; ++i) { - bool has_glyphs = false; - if (!deserializer.read<bool>(&has_glyphs)) READ_FAILURE - - if (!has_glyphs) continue; - - StrikeSpec spec; - if (!deserializer.read<StrikeSpec>(&spec)) READ_FAILURE - - SkAutoDescriptor sourceAd; - if (!deserializer.readDescriptor(&sourceAd)) READ_FAILURE - - SkPaint::FontMetrics fontMetrics; - if (!deserializer.read<SkPaint::FontMetrics>(&fontMetrics)) READ_FAILURE - - // Get the local typeface from remote fontID. - auto* tf = fRemoteFontIdToTypeface.find(spec.typefaceID)->get(); - // Received strikes for a typeface which doesn't exist. - if (!tf) READ_FAILURE +sk_sp<SkData> SkStrikeServer::encodeTypeface(SkTypeface* tf) { + WireTypeface wire = { + SkTypeface::UniqueID(tf), + tf->countGlyphs(), + tf->fontStyle(), + tf->isFixedPitch() + }; + auto typeFace = fTypefaceMap.find(SkTypeface::UniqueID(tf)); + if (typeFace == nullptr) { + fTypefaceMap.set(SkTypeface::UniqueID(tf), sk_ref_sp(tf)); + } + // Can this be done with no copy? + return SkData::MakeWithCopy(&wire, sizeof(wire)); +} - // Replace the ContextRec in the desc from the server to create the client - // side descriptor. - // TODO: Can we do this in-place and re-compute checksum? Instead of a complete copy. - SkAutoDescriptor ad; - auto* client_desc = auto_descriptor_from_desc(sourceAd.getDesc(), tf->uniqueID(), &ad); +// -- SkStrikeClient ------------------------------------------------------------------------------- +SkStrikeClient::SkStrikeClient(SkStrikeCacheClientRPC clientRPC) + : fClientRPC{clientRPC} { } - auto strike = SkStrikeCache::FindStrikeExclusive(*client_desc); - if (strike == nullptr) { - // Note that we don't need to deserialize the effects since we won't be generating any - // glyphs here anyway, and the desc is still correct since it includes the serialized - // effects. - SkScalerContextEffects effects; - auto scaler = SkStrikeCache::CreateScalerContext(*client_desc, effects, *tf); - strike = SkStrikeCache::CreateStrikeExclusive( - *client_desc, std::move(scaler), &fontMetrics, - skstd::make_unique<DiscardableStrikePinner>(spec.discardableHandleId, - fDiscardableHandleManager)); - } +void SkStrikeClient::generateFontMetrics( + const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkPaint::FontMetrics* metrics) +{ + fBuffer.clear(); - for (size_t j = 0; j < spec.glyphCount; j++) { - SkGlyph glyph; - if (!deserializer.read<SkGlyph>(&glyph)) READ_FAILURE + Serializer serializer{&fBuffer}; + serializer.emplace_back<Op>(OpCode::kFontMetrics, typefaceProxy.remoteTypefaceID(), rec); - ArraySlice<uint8_t> image; - auto imageSize = glyph.computeImageSize(); - if (imageSize != 0) { - image = deserializer.readArray<uint8_t>(imageSize); - if (!image.data()) READ_FAILURE - } + auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size()); + auto inbuffer = fClientRPC(*outBuffer); + Deserializer deserializer(*inbuffer); + *metrics = *deserializer.read<SkPaint::FontMetrics>(); +} - SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph.getPackedID()); - *allocatedGlyph = glyph; - allocatedGlyph->allocImage(strike->getAlloc()); - memcpy(allocatedGlyph->fImage, image.data(), image.size()); - } +void SkStrikeClient::generateMetricsAndImage( + const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkArenaAlloc* alloc, + SkGlyph* glyph) +{ + fBuffer.clear(); + Serializer serializer(&fBuffer); + Op *op = serializer.emplace_back<Op>( + OpCode::kGlyphMetricsAndImage, typefaceProxy.remoteTypefaceID(), rec); + op->glyphID = glyph->getPackedID(); + + auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size()); + auto inbuffer = fClientRPC(*outBuffer); + Deserializer deserializer(*inbuffer); + *glyph = *deserializer.read<SkGlyph>(); + auto imageSize = glyph->computeImageSize(); + glyph->fPathData = nullptr; + glyph->fImage = nullptr; + if (imageSize > 0) { + auto image = deserializer.readArray<uint8_t>(imageSize); + SkASSERT(imageSize == image.size()); + glyph->allocImage(alloc); + memcpy(glyph->fImage, image.data(), imageSize); } +} +bool SkStrikeClient::generatePath( + const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkGlyphID glyphID, + SkPath* path) +{ + fBuffer.clear(); + + Serializer serializer{&fBuffer}; + Op *op = serializer.emplace_back<Op>( + OpCode::kGlyphPath, typefaceProxy.remoteTypefaceID(), rec); + op->glyphID = glyphID; + + auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size()); + auto inbuffer = fClientRPC(*outBuffer); + Deserializer deserializer(*inbuffer); + size_t pathSize = *deserializer.read<size_t>(); + if (pathSize == 0) { + return false; + } + auto rawPath = deserializer.readArray<uint8_t>(pathSize); + path->readFromMemory(rawPath.data(), rawPath.size()); return true; } -sk_sp<SkTypeface> SkStrikeClient::deserializeTypeface(const void* buf, size_t len) { - WireTypeface wire; - if (len != sizeof(wire)) return nullptr; +void SkStrikeClient::primeStrikeCache(const SkStrikeCacheDifferenceSpec& strikeDifferences) { + fBuffer.clear(); + fBuffer.reserve(strikeDifferences.sizeBytes()); - memcpy(&wire, buf, sizeof(wire)); - return addTypeface(wire); + Serializer serializer{&fBuffer}; + write_strikes_spec(strikeDifferences, &serializer); + + auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size()); + auto inbuffer = fClientRPC(*outBuffer); + Deserializer deserializer(*inbuffer); + update_caches_from_strikes_data(this, &deserializer); } -sk_sp<SkTypeface> SkStrikeClient::addTypeface(const WireTypeface& wire) { - auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID); - if (typeface) return *typeface; +void SkStrikeClient::prepareDeserializeProcs(SkDeserialProcs* procs) { + auto decode = [](const void* buf, size_t len, void* ctx) { + return reinterpret_cast<SkStrikeClient*>(ctx)->decodeTypeface(buf, len); + }; + procs->fTypefaceProc = decode; + procs->fTypefaceCtx = this; - auto newTypeface = sk_make_sp<SkTypefaceProxy>(wire.typefaceID, wire.glyphCount, wire.style, - wire.isFixed, this); - fRemoteFontIdToTypeface.set(wire.typefaceID, newTypeface); - return newTypeface; } -void SkStrikeClient::generateFontMetrics(const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkPaint::FontMetrics* metrics) { - TRACE_EVENT1("skia", "generateFontMetrics", "rec", TRACE_STR_COPY(rec.dump().c_str())); - SkDebugf("generateFontMetrics: %s\n", rec.dump().c_str()); - SkStrikeCache::Dump(); - SkDEBUGFAIL("GlyphCacheMiss"); +SkTypeface* SkStrikeClient::lookupTypeface(SkFontID id) { + auto typeface = fMapIdToTypeface.find(id); + SkASSERT(typeface != nullptr); + return typeface->get(); } -void SkStrikeClient::generateMetricsAndImage(const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkArenaAlloc* alloc, - SkGlyph* glyph) { - TRACE_EVENT1("skia", "generateMetricsAndImage", "rec", TRACE_STR_COPY(rec.dump().c_str())); - SkDebugf("generateMetricsAndImage: %s\n", rec.dump().c_str()); - SkStrikeCache::Dump(); - SkDEBUGFAIL("GlyphCacheMiss"); -} +sk_sp<SkTypeface> SkStrikeClient::decodeTypeface(const void* buf, size_t len) { + WireTypeface wire; + if (len < sizeof(wire)) { + SK_ABORT("Incomplete transfer"); + return nullptr; + } + memcpy(&wire, buf, sizeof(wire)); -void SkStrikeClient::generatePath(const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkGlyphID glyphID, - SkPath* path) { - TRACE_EVENT1("skia", "generateMetricsAndImage", "rec", TRACE_STR_COPY(rec.dump().c_str())); - SkDebugf("generatePath: %s\n", rec.dump().c_str()); - SkStrikeCache::Dump(); - SkDEBUGFAIL("GlyphCacheMiss"); + auto typeFace = fMapIdToTypeface.find(wire.typefaceID); + if (typeFace == nullptr) { + auto newTypeface = sk_make_sp<SkTypefaceProxy>( + wire.typefaceID, + wire.glyphCount, + wire.style, + wire.isFixed, + this); + + typeFace = fMapIdToTypeface.set(wire.typefaceID, newTypeface); + } + return *typeFace; } diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h index b210f1c6d7..ff905862fa 100644 --- a/src/core/SkRemoteGlyphCache.h +++ b/src/core/SkRemoteGlyphCache.h @@ -5,196 +5,192 @@ * found in the LICENSE file. */ -#ifndef SkRemoteGlyphCachePriv_DEFINED -#define SkRemoteGlyphCachePriv_DEFINED +#ifndef SkRemoteGlyphCache_DEFINED +#define SkRemoteGlyphCache_DEFINED #include <memory> #include <tuple> #include <unordered_map> -#include <unordered_set> #include <vector> -#include "../private/SkTHash.h" #include "SkData.h" +#include "SkDescriptor.h" #include "SkDrawLooper.h" +#include "SkGlyphCache.h" #include "SkMakeUnique.h" #include "SkNoDrawCanvas.h" #include "SkRefCnt.h" -#include "SkRemoteGlyphCache.h" #include "SkSerialProcs.h" +#include "SkStrikeCache.h" +#include "SkTextBlobRunIterator.h" +#include "SkTHash.h" #include "SkTypeface.h" +#include "SkTypeface_remote.h" -class Serializer; -class SkDescriptor; -class SkGlyphCache; -struct SkPackedGlyphID; -class SkScalerContextRecDescriptor; -class SkTextBlobRunIterator; -class SkTypefaceProxy; -struct WireTypeface; +// The client uses a SkStrikeCacheClientRPC to send and receive data. +using SkStrikeCacheClientRPC = std::function<sk_sp<SkData>(const SkData&)>; -class SkStrikeServer; +class SkScalerContextRecDescriptor { +public: + SkScalerContextRecDescriptor() {} + explicit SkScalerContextRecDescriptor(const SkScalerContextRec& rec) { + auto desc = reinterpret_cast<SkDescriptor*>(&fDescriptor); + desc->init(); + desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + desc->computeChecksum(); + SkASSERT(sizeof(fDescriptor) == desc->getLength()); + } + + explicit SkScalerContextRecDescriptor(const SkDescriptor& desc) + : SkScalerContextRecDescriptor(ExtractRec(desc)) { } + + SkScalerContextRecDescriptor& operator=(const SkScalerContextRecDescriptor& rhs) { + std::memcpy(&fDescriptor, &rhs.fDescriptor, rhs.desc().getLength()); + return *this; + } + + const SkDescriptor& desc() const { + return *reinterpret_cast<const SkDescriptor*>(&fDescriptor); + } + + struct Hash { + uint32_t operator()(SkScalerContextRecDescriptor const& s) const { + return s.desc().getChecksum(); + } + }; + + friend bool operator==(const SkScalerContextRecDescriptor& lhs, + const SkScalerContextRecDescriptor& rhs ) { + return lhs.desc() == rhs.desc(); + } -struct SkDescriptorMapOperators { - size_t operator()(const SkDescriptor* key) const; - bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const; +private: + static SkScalerContextRec ExtractRec(const SkDescriptor& desc) { + uint32_t size; + auto recPtr = desc.findEntry(kRec_SkDescriptorTag, &size); + + SkScalerContextRec result; + std::memcpy(&result, recPtr, size); + return result; + } + // The system only passes descriptors without effects. That is why it uses a fixed size + // descriptor. storageFor is needed because some of the constructors below are private. + template <typename T> + using storageFor = typename std::aligned_storage<sizeof(T), alignof(T)>::type; + struct { + storageFor<SkDescriptor> dummy1; + storageFor<SkDescriptor::Entry> dummy2; + storageFor<SkScalerContextRec> dummy3; + } fDescriptor; }; -template <typename T> -using SkDescriptorMap = std::unordered_map<const SkDescriptor*, T, SkDescriptorMapOperators, - SkDescriptorMapOperators>; +class SkStrikeDifferences { +public: + SkStrikeDifferences(SkFontID typefaceID, std::unique_ptr<SkDescriptor> desc); + void add(uint16_t glyphID, SkIPoint pos); + SkFontID fTypefaceID; + std::unique_ptr<SkDescriptor> fDesc; + std::unique_ptr<SkTHashSet<SkPackedGlyphID>> fGlyphIDs = + skstd::make_unique<SkTHashSet<SkPackedGlyphID>>(); +}; -using SkDescriptorSet = - std::unordered_set<const SkDescriptor*, SkDescriptorMapOperators, SkDescriptorMapOperators>; +class SkStrikeCacheDifferenceSpec { +public: + SkStrikeDifferences& findStrikeDifferences(const SkDescriptor& desc, SkFontID typefaceID); + int strikeCount() const { return fDescriptorToDifferencesMap.size(); } + size_t sizeBytes() const; + template <typename PerStrike, typename PerGlyph> + void iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const; -// A SkTextBlobCacheDiffCanvas is used to populate the SkStrikeServer with ops -// which will be serialized and renderered using the SkStrikeClient. -class SK_API SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas { +private: + SkDescriptorMap<SkStrikeDifferences> fDescriptorToDifferencesMap{16}; +}; + +class SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas { public: - SkTextBlobCacheDiffCanvas(int width, int height, const SkMatrix& deviceMatrix, - const SkSurfaceProps& props, SkStrikeServer* strikeserver); - ~SkTextBlobCacheDiffCanvas() override; + SkTextBlobCacheDiffCanvas(int width, int height, + const SkMatrix& deviceMatrix, + const SkSurfaceProps& props, + SkScalerContextFlags flags, + SkStrikeCacheDifferenceSpec* strikeDiffs); protected: - SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; - void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, - const SkPaint& paint) override; + void onDrawTextBlob( + const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) override; private: - void processLooper(const SkPoint& position, - const SkTextBlobRunIterator& it, - const SkPaint& origPaint, - SkDrawLooper* looper); - void processGlyphRun(const SkPoint& position, - const SkTextBlobRunIterator& it, - const SkPaint& runPaint); + void processLooper( + const SkPoint& position, + const SkTextBlobRunIterator& it, + const SkPaint& origPaint, + SkDrawLooper* looper); + + void processGlyphRun( + const SkPoint& position, + const SkTextBlobRunIterator& it, + const SkPaint& runPaint); const SkMatrix fDeviceMatrix; const SkSurfaceProps fSurfaceProps; - SkStrikeServer* const fStrikeServer; -}; + const SkScalerContextFlags fScalerContextFlags; -using SkDiscardableHandleId = uint32_t; + SkStrikeCacheDifferenceSpec* const fStrikeCacheDiff; +}; -// This class is not thread-safe. -class SK_API SkStrikeServer { +class SkStrikeServer { public: - // An interface used by the server to create handles for pinning SkGlyphCache - // entries on the remote client. - class SK_API DiscardableHandleManager { - public: - virtual ~DiscardableHandleManager() {} - - // Creates a new *locked* handle and returns a unique ID that can be used to identify - // it on the remote client. - virtual SkDiscardableHandleId createHandle() = 0; - - // Returns true if the handle could be successfully locked. The server can - // assume it will remain locked until the next set of serialized entries is - // pulled from the SkStrikeServer. - // If returns false, the cache entry mapped to the handle has been deleted - // on the client. Any subsequent attempts to lock the same handle are not - // allowed. - virtual bool lockHandle(SkDiscardableHandleId) = 0; - - // TODO(khushalsagar): Add an API which checks whether a handle is still - // valid without locking, so we can avoid tracking stale handles once they - // have been purged on the remote side. - }; - - SkStrikeServer(DiscardableHandleManager* discardableHandleManager); + SkStrikeServer(); ~SkStrikeServer(); - // Serializes the typeface to be remoted using this server. - sk_sp<SkData> serializeTypeface(SkTypeface*); - - // Serializes the strike data captured using a SkTextBlobCacheDiffCanvas. Any - // handles locked using the DiscardableHandleManager will be assumed to be - // unlocked after this call. - void writeStrikeData(std::vector<uint8_t>* memory); - - // Methods used internally in skia ------------------------------------------ - class SkGlyphCacheState { - public: - SkGlyphCacheState(std::unique_ptr<SkDescriptor> desc, - SkDiscardableHandleId discardableHandleId); - ~SkGlyphCacheState(); - - void addGlyph(SkTypeface*, const SkScalerContextEffects&, SkPackedGlyphID); - void writePendingGlyphs(Serializer* serializer); - bool has_pending_glyphs() const { return !fPendingGlyphs.empty(); } - SkDiscardableHandleId discardable_handle_id() const { return fDiscardableHandleId; } - - private: - // The set of glyphs cached on the remote client. - SkTHashSet<SkPackedGlyphID> fCachedGlyphs; - - // The set of glyphs which has not yet been serialized and sent to the - // remote client. - std::vector<SkPackedGlyphID> fPendingGlyphs; - - std::unique_ptr<SkDescriptor> fDesc; - const SkDiscardableHandleId fDiscardableHandleId = -1; - std::unique_ptr<SkScalerContext> fContext; - }; - SkGlyphCacheState* getOrCreateCache(SkTypeface*, std::unique_ptr<SkDescriptor>); + // embedding clients call these methods + void serve(const SkData&, std::vector<uint8_t>*); + + void prepareSerializeProcs(SkSerialProcs* procs); + + // mostly called internally by Skia + SkScalerContext* generateScalerContext( + const SkScalerContextRecDescriptor& desc, SkFontID typefaceId); private: - SkDescriptorMap<std::unique_ptr<SkGlyphCacheState>> fRemoteGlyphStateMap; - DiscardableHandleManager* const fDiscardableHandleManager; - SkTHashSet<SkFontID> fCachedTypefaces; + using DescriptorToContextMap = SkTHashMap<SkScalerContextRecDescriptor, + std::unique_ptr<SkScalerContext>, + SkScalerContextRecDescriptor::Hash>; + + sk_sp<SkData> encodeTypeface(SkTypeface* tf); - // State cached until the next serialization. - SkDescriptorSet fLockedDescs; - std::vector<WireTypeface> fTypefacesToSend; + int fOpCount = 0; + SkTHashMap<SkFontID, sk_sp<SkTypeface>> fTypefaceMap; + DescriptorToContextMap fScalerContextMap; }; -class SK_API SkStrikeClient { +class SkStrikeClient { public: - // An interface to delete handles that may be pinned by the remote server. - class DiscardableHandleManager : public SkRefCnt { - public: - virtual ~DiscardableHandleManager() {} - - // Returns true if the handle was unlocked and can be safely deleted. Once - // successful, subsequent attempts to delete the same handle are invalid. - virtual bool deleteHandle(SkDiscardableHandleId) = 0; - }; + SkStrikeClient(SkStrikeCacheClientRPC); - SkStrikeClient(sk_sp<DiscardableHandleManager>); - ~SkStrikeClient(); - - // Deserializes the typeface previously serialized using the SkStrikeServer. Returns null if the - // data is invalid. - sk_sp<SkTypeface> deserializeTypeface(const void* data, size_t length); - - // Deserializes the strike data from a SkStrikeServer. All messages generated - // from a server when serializing the ops must be deserialized before the op - // is rasterized. - // Returns false if the data is invalid. - bool readStrikeData(const volatile void* memory, size_t memorySize); - - // TODO: Remove these since we don't support pulling this data on-demand. - void generateFontMetrics(const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkPaint::FontMetrics* metrics); - void generateMetricsAndImage(const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkArenaAlloc* alloc, - SkGlyph* glyph); - void generatePath(const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkGlyphID glyphID, - SkPath* path); + // embedding clients call these methods + void primeStrikeCache(const SkStrikeCacheDifferenceSpec&); + void prepareDeserializeProcs(SkDeserialProcs* procs); + + // mostly called internally by Skia + void generateFontMetrics( + const SkTypefaceProxy&, const SkScalerContextRec&, SkPaint::FontMetrics*); + void generateMetricsAndImage( + const SkTypefaceProxy&, const SkScalerContextRec&, SkArenaAlloc*, SkGlyph*); + bool generatePath( + const SkTypefaceProxy&, const SkScalerContextRec&, SkGlyphID glyph, SkPath* path); + SkTypeface* lookupTypeface(SkFontID id); private: - class DiscardableStrikePinner; + sk_sp<SkTypeface> decodeTypeface(const void* buf, size_t len); + + // TODO: Figure out how to manage the entries for the following maps. + SkTHashMap<SkFontID, sk_sp<SkTypefaceProxy>> fMapIdToTypeface; - sk_sp<SkTypeface> addTypeface(const WireTypeface& wire); + SkStrikeCacheClientRPC fClientRPC; - SkTHashMap<SkFontID, sk_sp<SkTypeface>> fRemoteFontIdToTypeface; - sk_sp<DiscardableHandleManager> fDiscardableHandleManager; + std::vector<uint8_t> fBuffer; }; -#endif // SkRemoteGlyphCachePriv_DEFINED +#endif // SkRemoteGlyphCache_DEFINED diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h index 675e9a0524..84abdcc1a4 100644 --- a/src/core/SkScalerContext.h +++ b/src/core/SkScalerContext.h @@ -135,8 +135,8 @@ public: fPost2x2[0][1], fPost2x2[1][0], fPost2x2[1][1]); msg.appendf(" frame %g miter %g format %d join %d cap %d flags %#hx\n", fFrameWidth, fMiterLimit, fMaskFormat, fStrokeJoin, fStrokeCap, fFlags); - msg.appendf(" lum bits %x, device gamma %d, paint gamma %d contrast %d\n", fLumBits, - fDeviceGamma, fPaintGamma, fContrast); + msg.appendf(" lum bits %x, device gamma %d, paint gamma %d contrast %d\n", + fLumBits, fDeviceGamma, fPaintGamma, fContrast); return msg; } diff --git a/src/core/SkStrikeCache.h b/src/core/SkStrikeCache.h index df048e33be..3e199da1e9 100644 --- a/src/core/SkStrikeCache.h +++ b/src/core/SkStrikeCache.h @@ -9,7 +9,6 @@ #define SkStrikeCache_DEFINED #include <unordered_map> -#include <unordered_set> #include "SkDescriptor.h" #include "SkSpinlock.h" @@ -32,6 +31,24 @@ class SkTraceMemoryDump; /////////////////////////////////////////////////////////////////////////////// +struct SkDescriptorMapOperators { + size_t operator()(const SkDescriptor* key) const { + return key->getChecksum(); + } + + bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const { + return *lhs == *rhs; + } +}; + +template <typename T> +using SkDescriptorMap = + std::unordered_map< + const SkDescriptor*, + T, + SkDescriptorMapOperators, + SkDescriptorMapOperators>; + class SkStrikePinner { public: virtual ~SkStrikePinner() = default; diff --git a/src/core/SkTypeface_remote.cpp b/src/core/SkTypeface_remote.cpp index 3b58af9366..bc0d04bc2a 100644 --- a/src/core/SkTypeface_remote.cpp +++ b/src/core/SkTypeface_remote.cpp @@ -6,15 +6,17 @@ */ #include "SkTypeface_remote.h" -#include "SkRemoteGlyphCache.h" #include "SkPaint.h" +#include "SkRemoteGlyphCache.h" -SkScalerContextProxy::SkScalerContextProxy(sk_sp<SkTypeface> tf, - const SkScalerContextEffects& effects, - const SkDescriptor* desc, - SkStrikeClient* rsc) - : SkScalerContext{std::move(tf), effects, desc}, fClient{rsc} {} +SkScalerContextProxy::SkScalerContextProxy( + sk_sp<SkTypeface> tf, + const SkScalerContextEffects& effects, + const SkDescriptor* desc, + SkStrikeClient* rsc) + : SkScalerContext{std::move(tf), effects, desc} + , fClient{rsc} {} unsigned SkScalerContextProxy::generateGlyphCount() { SK_ABORT("Should never be called."); @@ -38,8 +40,7 @@ void SkScalerContextProxy::generateImage(const SkGlyph& glyph) { } bool SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) { - fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path); - return true; + return fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path); } void SkScalerContextProxy::generateFontMetrics(SkPaint::FontMetrics* metrics) { diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h index 691b124049..85a8fc5617 100644 --- a/src/core/SkTypeface_remote.h +++ b/src/core/SkTypeface_remote.h @@ -21,10 +21,11 @@ class SkTypefaceProxy; class SkScalerContextProxy : public SkScalerContext { public: - SkScalerContextProxy(sk_sp<SkTypeface> tf, - const SkScalerContextEffects& effects, - const SkDescriptor* desc, - SkStrikeClient* rsc); + SkScalerContextProxy( + sk_sp<SkTypeface> tf, + const SkScalerContextEffects& effects, + const SkDescriptor* desc, + SkStrikeClient* rsc); protected: unsigned generateGlyphCount() override; @@ -51,12 +52,16 @@ private: class SkTypefaceProxy : public SkTypeface { public: - SkTypefaceProxy(SkFontID fontId, - int glyphCount, - const SkFontStyle& style, - bool isFixed, - SkStrikeClient* rsc) - : INHERITED{style, false}, fFontId{fontId}, fGlyphCount{glyphCount}, fRsc{rsc} {} + SkTypefaceProxy( + SkFontID fontId, + int glyphCount, + const SkFontStyle& style, + bool isFixed, + SkStrikeClient* rsc) + : INHERITED{style, false} + , fFontId{fontId} + , fGlyphCount{glyphCount} + , fRsc{rsc} { } SkFontID remoteTypefaceID() const {return fFontId;} int glyphCount() const {return fGlyphCount;} static SkTypefaceProxy* DownCast(SkTypeface* typeface) { @@ -133,8 +138,6 @@ protected: private: const SkFontID fFontId; const int fGlyphCount; - - // TODO: Does this need a ref to the strike client? If yes, make it a weak ref. SkStrikeClient* const fRsc; typedef SkTypeface INHERITED; diff --git a/tests/SkRemoteGlyphCacheTest.cpp b/tests/SkRemoteGlyphCacheTest.cpp deleted file mode 100644 index 7369acec15..0000000000 --- a/tests/SkRemoteGlyphCacheTest.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkGraphics.h" -#include "SkMutex.h" -#include "SkRemoteGlyphCache.h" -#include "SkStrikeCache.h" -#include "SkSurface.h" -#include "SkTextBlob.h" -#include "SkTypeface_remote.h" -#include "Test.h" - -class DiscardableManager : public SkStrikeServer::DiscardableHandleManager, - public SkStrikeClient::DiscardableHandleManager { -public: - DiscardableManager() = default; - ~DiscardableManager() override = default; - - // Server implementation. - SkDiscardableHandleId createHandle() override { - // Handles starts as locked. - fLockedHandles.add(++fNextHandleId); - return fNextHandleId; - } - bool lockHandle(SkDiscardableHandleId id) override { - if (id <= fLastDeletedHandleId) return false; - fLockedHandles.add(id); - return true; - } - - // Client implementation. - bool deleteHandle(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; } - - void unlockAll() { fLockedHandles.reset(); } - void unlockAndDeleteAll() { - unlockAll(); - fLastDeletedHandleId = fNextHandleId; - } - const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; } - SkDiscardableHandleId handleCount() { return fNextHandleId; } - -private: - SkDiscardableHandleId fNextHandleId = 0u; - SkDiscardableHandleId fLastDeletedHandleId = 0u; - SkTHashSet<SkDiscardableHandleId> fLockedHandles; -}; - -sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) { - SkPaint font; - font.setTypeface(tf); - font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - font.setTextAlign(SkPaint::kLeft_Align); - font.setStyle(SkPaint::kFill_Style); - font.setHinting(SkPaint::kNormal_Hinting); - font.setTextSize(1u); - - SkTextBlobBuilder builder; - SkRect bounds = SkRect::MakeWH(10, 10); - const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds); - for (int i = 0; i < glyphCount; i++) runBuffer.glyphs[i] = static_cast<SkGlyphID>(i); - return builder.make(); -} - -SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height) { - auto surface = SkSurface::MakeRasterN32Premul(width, height); - SkPaint paint; - surface->getCanvas()->drawTextBlob(blob.get(), 0u, 0u, paint); - SkBitmap bitmap; - bitmap.allocN32Pixels(width, height); - surface->readPixels(bitmap, 0, 0); - return bitmap; -} - -DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) { - sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>(); - SkStrikeServer server(discardableManager.get()); - SkStrikeClient client(discardableManager); - - auto server_tf = SkTypeface::MakeDefault(); - auto tf_data = server.serializeTypeface(server_tf.get()); - - auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size()); - REPORTER_ASSERT(reporter, client_tf); - REPORTER_ASSERT(reporter, SkTypefaceProxy::DownCast(client_tf.get())->remoteTypefaceID() == - server_tf->uniqueID()); -} - -#if 0 -TODO(khushalsagar): Re-enable once crbug.com/831354 is fixed. -DEF_TEST(SkRemoteGlyphCache_StrikeSerialization, reporter) { - sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>(); - SkStrikeServer server(discardableManager.get()); - SkStrikeClient client(discardableManager); - - // Server. - auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle()); - auto serverTfData = server.serializeTypeface(serverTf.get()); - - int glyphCount = 10; - auto serverBlob = buildTextBlob(serverTf, glyphCount); - const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); - SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server); - SkPaint paint; - cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint); - - std::vector<uint8_t> serverStrikeData; - server.writeStrikeData(&serverStrikeData); - - // Client. - auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()); - REPORTER_ASSERT(reporter, - client.readStrikeData(serverStrikeData.data(), serverStrikeData.size())); - auto clientBlob = buildTextBlob(clientTf, glyphCount); - - SkBitmap expected = RasterBlob(serverBlob, 10, 10); - SkBitmap actual = RasterBlob(clientBlob, 10, 10); - for (int i = 0; i < expected.width(); ++i) { - for (int j = 0; j < expected.height(); ++j) { - REPORTER_ASSERT(reporter, expected.getColor(i, j) == actual.getColor(i, j)); - } - } -} -#endif - -DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) { - sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>(); - SkStrikeServer server(discardableManager.get()); - SkStrikeClient client(discardableManager); - - auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle()); - server.serializeTypeface(serverTf.get()); - int glyphCount = 10; - auto serverBlob = buildTextBlob(serverTf, glyphCount); - - const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); - SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server); - SkPaint paint; - cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint); - - // The strike from the blob should be locked after it has been drawn on the canvas. - REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u); - REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u); - - // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle - // again. - std::vector<uint8_t> fontData; - server.writeStrikeData(&fontData); - discardableManager->unlockAll(); - REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u); - - cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint); - REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u); - REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u); -} - -DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) { - sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>(); - SkStrikeServer server(discardableManager.get()); - SkStrikeClient client(discardableManager); - - auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle()); - server.serializeTypeface(serverTf.get()); - int glyphCount = 10; - auto serverBlob = buildTextBlob(serverTf, glyphCount); - - const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); - SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server); - SkPaint paint; - cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint); - REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u); - - // Write the strike data and delete all the handles. Re-analyzing the blob should create new - // handles. - std::vector<uint8_t> fontData; - server.writeStrikeData(&fontData); - discardableManager->unlockAndDeleteAll(); - cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint); - printf("HandleCount: %d\n ", discardableManager->handleCount()); - REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u); -} - -DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) { - sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>(); - SkStrikeServer server(discardableManager.get()); - SkStrikeClient client(discardableManager); - - // Server. - auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle()); - auto serverTfData = server.serializeTypeface(serverTf.get()); - - int glyphCount = 10; - auto serverBlob = buildTextBlob(serverTf, glyphCount); - - const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); - SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server); - SkPaint paint; - cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint); - - std::vector<uint8_t> serverStrikeData; - server.writeStrikeData(&serverStrikeData); - - // Client. - REPORTER_ASSERT(reporter, - client.readStrikeData(serverStrikeData.data(), serverStrikeData.size())); - auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get(); - - // The cache remains alive until it is pinned in the discardable manager. - SkGraphics::PurgeFontCache(); - REPORTER_ASSERT(reporter, !clientTf->unique()); - - // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the - // clientTf. - discardableManager->unlockAndDeleteAll(); - SkGraphics::PurgeFontCache(); - REPORTER_ASSERT(reporter, clientTf->unique()); -} diff --git a/tools/remote_demo.cpp b/tools/remote_demo.cpp index 105a9b3ea7..8fc96cadb8 100644 --- a/tools/remote_demo.cpp +++ b/tools/remote_demo.cpp @@ -16,9 +16,8 @@ #include <thread> #include <unistd.h> -#include "SkGraphics.h" #include "SkRemoteGlyphCache.h" -#include "SkScalerContext.h" +#include "SkGraphics.h" #include "SkSurface.h" static std::string gSkpName; @@ -26,46 +25,6 @@ static bool gUseGpu = true; static bool gPurgeFontCaches = true; static bool gUseProcess = true; -class ServerDiscardableManager : public SkStrikeServer::DiscardableHandleManager { -public: - ServerDiscardableManager() = default; - ~ServerDiscardableManager() override = default; - - SkDiscardableHandleId createHandle() override { return ++nextHandleId; } - bool lockHandle(SkDiscardableHandleId handleId) override { - return handleId > lastPurgedHandleId; - } - void purgeAll() { lastPurgedHandleId = nextHandleId; } - -private: - SkDiscardableHandleId nextHandleId = 0u; - SkDiscardableHandleId lastPurgedHandleId = 0u; -}; - -class ClientDiscardableManager : public SkStrikeClient::DiscardableHandleManager { -public: - class ScopedPurgeCache { - public: - ScopedPurgeCache(ClientDiscardableManager* manager) : fManager(manager) { - if (fManager) fManager->allowPurging = true; - } - ~ScopedPurgeCache() { - if (fManager) fManager->allowPurging = false; - } - - private: - ClientDiscardableManager* fManager; - }; - - ClientDiscardableManager() = default; - ~ClientDiscardableManager() override = default; - - bool deleteHandle(SkDiscardableHandleId) override { return allowPurging; } - -private: - bool allowPurging = false; -}; - static bool write_SkData(int fd, const SkData& data) { size_t size = data.size(); ssize_t bytesWritten = ::write(fd, &size, sizeof(size)); @@ -84,6 +43,7 @@ static bool write_SkData(int fd, const SkData& data) { } static sk_sp<SkData> read_SkData(int fd) { + size_t size; ssize_t readSize = ::read(fd, &size, sizeof(size)); if (readSize <= 0) { @@ -132,56 +92,44 @@ private: std::chrono::duration<double> fElapsedSeconds{0.0}; }; -static bool push_font_data(const SkPicture& pic, SkStrikeServer* strikeServer, int writeFd) { +static void build_prime_cache_spec(const SkIRect &bounds, + const SkSurfaceProps &props, + const SkPicture &pic, + SkStrikeCacheDifferenceSpec *strikeDifference) { SkMatrix deviceMatrix = SkMatrix::I(); - const SkIRect bounds = pic.cullRect().round(); - const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); - SkTextBlobCacheDiffCanvas filter(bounds.width(), bounds.height(), deviceMatrix, props, - strikeServer); - pic.playback(&filter); - std::vector<uint8_t> fontData; - strikeServer->writeStrikeData(&fontData); - auto data = SkData::MakeWithoutCopy(fontData.data(), fontData.size()); - return write_SkData(writeFd, *data); + SkTextBlobCacheDiffCanvas filter( + bounds.width(), bounds.height(), deviceMatrix, props, + SkScalerContextFlags::kFakeGammaAndBoostContrast, + strikeDifference); + + pic.playback(&filter); } -static void final_draw(std::string outFilename, SkData* picData, SkStrikeClient* client, - ClientDiscardableManager* discardableManager, int readFd, int writeFd) { - SkDeserialProcs procs; - auto decode = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> { - return reinterpret_cast<SkStrikeClient*>(ctx)->deserializeTypeface(data, length); - }; - procs.fTypefaceProc = decode; - procs.fTypefaceCtx = client; +static void final_draw(std::string outFilename, + SkDeserialProcs* procs, + SkData* picData, + SkStrikeClient* client) { - auto pic = SkPicture::MakeFromData(picData, &procs); + auto pic = SkPicture::MakeFromData(picData, procs); auto cullRect = pic->cullRect(); auto r = cullRect.round(); auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height()); auto c = s->getCanvas(); - auto picUnderTest = SkPicture::MakeFromData(picData, &procs); + auto picUnderTest = SkPicture::MakeFromData(picData, procs); Timer drawTime; - auto randomData = SkData::MakeUninitialized(1u); for (int i = 0; i < 100; i++) { if (gPurgeFontCaches) { - ClientDiscardableManager::ScopedPurgeCache purge(discardableManager); SkGraphics::PurgeFontCache(); - SkASSERT(SkGraphics::GetFontCacheUsed() == 0u); } - drawTime.start(); if (client != nullptr) { - // Kick the renderer to send us the fonts. - write_SkData(writeFd, *randomData); - auto fontData = read_SkData(readFd); - if (fontData && !fontData->isEmpty()) { - if (!client->readStrikeData(fontData->data(), fontData->size())) - SK_ABORT("Bad serialization"); - } + SkStrikeCacheDifferenceSpec strikeDifference; + build_prime_cache_spec(r, s->props(), *picUnderTest, &strikeDifference); + client->primeStrikeCache(strikeDifference); } c->drawPicture(picUnderTest); drawTime.stop(); @@ -202,16 +150,22 @@ static void final_draw(std::string outFilename, SkData* picData, SkStrikeClient* static void gpu(int readFd, int writeFd) { if (gUseGpu) { + auto clientRPC = [readFd, writeFd](const SkData& inBuffer) { + write_SkData(writeFd, inBuffer); + return read_SkData(readFd); + }; + auto picData = read_SkData(readFd); if (picData == nullptr) { return; } - sk_sp<ClientDiscardableManager> discardableManager = sk_make_sp<ClientDiscardableManager>(); - SkStrikeClient strikeClient(discardableManager); + SkStrikeClient client{clientRPC}; - final_draw("test.png", picData.get(), &strikeClient, discardableManager.get(), readFd, - writeFd); + SkDeserialProcs procs; + client.prepareDeserializeProcs(&procs); + + final_draw("test.png", &procs, picData.get(), &client); } ::close(writeFd); @@ -223,8 +177,7 @@ static void gpu(int readFd, int writeFd) { static int renderer( const std::string& skpName, int readFd, int writeFd) { - ServerDiscardableManager discardableManager; - SkStrikeServer server(&discardableManager); + SkStrikeServer server{}; auto closeAll = [readFd, writeFd]() { ::close(writeFd); ::close(readFd); @@ -233,16 +186,11 @@ static int renderer( auto skpData = SkData::MakeFromFileName(skpName.c_str()); std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl; + SkSerialProcs procs; sk_sp<SkData> stream; if (gUseGpu) { auto pic = SkPicture::MakeFromData(skpData.get()); - SkSerialProcs procs; - auto encode = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> { - return reinterpret_cast<SkStrikeServer*>(ctx)->serializeTypeface(tf); - }; - procs.fTypefaceProc = encode; - procs.fTypefaceCtx = &server; - + server.prepareSerializeProcs(&procs); stream = pic->serialize(&procs); if (!write_SkData(writeFd, *stream)) { @@ -250,18 +198,22 @@ static int renderer( return 1; } + std::vector<uint8_t> tmpBuffer; while (true) { auto inBuffer = read_SkData(readFd); if (inBuffer == nullptr) { closeAll(); return 0; } - if (gPurgeFontCaches) discardableManager.purgeAll(); - push_font_data(*pic.get(), &server, writeFd); + + tmpBuffer.clear(); + server.serve(*inBuffer, &tmpBuffer); + auto outBuffer = SkData::MakeWithoutCopy(tmpBuffer.data(), tmpBuffer.size()); + write_SkData(writeFd, *outBuffer); } } else { stream = skpData; - final_draw("test-correct.png", stream.get(), nullptr, nullptr, -1, -1); + final_draw("test-correct.png", nullptr, stream.get(), nullptr); closeAll(); return 0; } |