diff options
author | Herb Derby <herb@google.com> | 2018-03-21 16:23:49 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-26 21:28:04 +0000 |
commit | 97be88f58a82b8e6ad7ef60a072cd8407d6423ce (patch) | |
tree | 89d5c94f0afef2662c870b57af7c9cf12491ac53 /src | |
parent | f9e12df94f7f4eacb1072415909b9c92be293130 (diff) |
Move cache difference code into remote cache files
BUG=skia:7515
Change-Id: I59e75d460b4ed4d0a737c833520b2335808a4ce4
Reviewed-on: https://skia-review.googlesource.com/115706
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Herb Derby <herb@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkRemoteGlyphCache.cpp | 856 | ||||
-rw-r--r-- | src/core/SkRemoteGlyphCache.h | 128 | ||||
-rw-r--r-- | src/core/SkTypeface_remote.cpp | 31 | ||||
-rw-r--r-- | src/core/SkTypeface_remote.h | 50 |
4 files changed, 985 insertions, 80 deletions
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp index 4aa25128cf..dfad89a7c2 100644 --- a/src/core/SkRemoteGlyphCache.cpp +++ b/src/core/SkRemoteGlyphCache.cpp @@ -7,14 +7,228 @@ #include "SkRemoteGlyphCache.h" -struct WireTypeface { - // std::thread::id thread_id; // TODO:need to figure a good solution - SkFontID typefaceID; - int glyphCount; - SkFontStyle style; - bool isFixed; +#include <iterator> +#include <memory> +#include <tuple> + +#include "SkDevice.h" +#include "SkFindAndPlaceGlyph.h" +#include "SkTypeface_remote.h" + +static const size_t kPageSize = 4096; + +template <typename T> +class ArraySlice final : public std::tuple<const T*, size_t> { +public: + // Additional constructors as needed. + ArraySlice(const T* data, size_t size) : fData{data}, fSize{size} { } + ArraySlice() : ArraySlice<T>(nullptr, 0) { } + + const T* begin() { + return this->data(); + } + + const T* end() { + return &this->data()[this->size()]; + } + + const T* data() const { + return fData; + } + + size_t size() const { + return fSize; + } + +private: + const T* fData; + size_t fSize; +}; + +// -- SkTransport ---------------------------------------------------------------------------------- + +SkTransport::IOResult SkTransport::writeSkData(const SkData& data) { + size_t size = data.size(); + + if (this->write(&size, sizeof(size)) == kFail) { + return kFail; + } + + if (this->write(data.data(), size) == kFail) { + return kFail; + } + + return kSuccess; +} +sk_sp<SkData> SkTransport::readSkData() { + size_t size; + if(std::get<1>(this->read(&size, sizeof(size))) == kFail) { + return nullptr; + } + + auto data = std::unique_ptr<uint8_t[]>{new uint8_t[size]}; + size_t totalRead = 0; + while (totalRead < size) { + size_t sizeRead; + IOResult result; + std::tie(sizeRead, result) = this->read(&data[totalRead], size - totalRead); + if (result == kFail || sizeRead == 0) { + return nullptr; + } + totalRead += sizeRead; + } + + return SkData::MakeWithCopy(data.get(), size); +} + +// -- Serializer ---------------------------------------------------------------------------------- + +class Serializer { +public: + void startWrite() { + fCursor = 0; + } + + template <typename T> + void startWrite(const T& data) { + this->startWrite(); + this->write<T>(data); + } + + template <typename T, typename... Args> + T* startEmplace(Args&&... args) { + this->startWrite(); + return this->emplace<T>(std::forward<Args>(args)...); + } + + template <typename T, typename... Args> + T* emplace(Args&&... args) { + T* result = new (&fBuffer[fCursor]) T{std::forward<Args>(args)...}; + fCursor += sizeof(T); + return result; + } + + template <typename T> + void write(const T& data) { + // TODO: guard against bad T. + memcpy(&fBuffer[fCursor], &data, sizeof(data)); + fCursor += sizeof(data); + } + + template <typename T> + T* allocate() { + // TODO: guard against bad T. + T* result = (T*)&fBuffer[fCursor]; + fCursor += sizeof(T); + return result; + } + + void writeDescriptor(const SkDescriptor& desc) { + memcpy(&fBuffer[fCursor], &desc, desc.getLength()); + fCursor += desc.getLength(); + } + + template <typename T> + T* allocateArray(int count) { + T* result = (T*)&fBuffer[fCursor]; + fCursor += count * sizeof(T); + return result; + } + + SkTransport::IOResult endWrite(SkTransport* transport) { + return transport->write(fBuffer.get(), fCursor); + } + +private: + static constexpr size_t kBufferSize = kPageSize * 2000; + std::unique_ptr<uint8_t[]> fBuffer{new uint8_t[kBufferSize]}; + size_t fCursor{0}; + //size_t fEnd{0}; }; +// -- Deserializer ------------------------------------------------------------------------------- + +class Deserializer { +public: + void startRead(SkTransport* transport) { + fCursor = 0; + fEnd = 0; + fTransport = transport; + } + + template <typename T> + T* startRead(SkTransport* transport) { + this->startRead(transport); + return this->read<T>(); + } + + template <typename T> + T* read() { + T* result = (T*)this->ensureAtLeast(sizeof(T)); + fCursor += sizeof(T); + return result; + } + + SkDescriptor* readDescriptor() { + SkDescriptor* result = (SkDescriptor*)this->ensureAtLeast(sizeof(SkDescriptor)); + size_t size = result->getLength(); + this->ensureAtLeast(size); + fCursor += size; + return result; + } + + template <typename T> + ArraySlice<T> readArray(int count) { + size_t size = count * sizeof(T); + const T* base = (const T*)this->ensureAtLeast(size); + ArraySlice<T> result = ArraySlice<T>{base, (uint32_t)count}; + fCursor += size; + return result; + } + + size_t endRead() { + fTransport = nullptr; + return size(); + } + + size_t size() {return fCursor;} + +private: + void* ensureAtLeast(size_t size) { + if (size > fEnd - fCursor) { + if (readAtLeast(size) == SkTransport::kFail) { + return nullptr; + } + } + return &fBuffer[fCursor]; + } + + SkTransport::IOResult readAtLeast(size_t size) { + size_t readSoFar = 0; + size_t bufferLeft = kBufferSize - fCursor; + size_t needed = size - (fEnd - fCursor); + while (readSoFar < needed) { + SkTransport::IOResult result; + size_t readSize; + std::tie(readSize, result) = + fTransport->read(&fBuffer[fEnd+readSoFar], bufferLeft - readSoFar); + if (result == SkTransport::kFail || readSize == 0) {return SkTransport::kFail;} + readSoFar += readSize; + } + fEnd += readSoFar; + return SkTransport::kSuccess; + } + + SkTransport* fTransport; + + static constexpr size_t kBufferSize = kPageSize * 2000; + std::unique_ptr<uint8_t[]> fBuffer{new uint8_t[kBufferSize]}; + size_t fCursor{0}; + size_t fEnd{0}; +}; + +// -- SkRemoteGlyphCacheRenderer ----------------------------------------------------------------- + void SkRemoteGlyphCacheRenderer::prepareSerializeProcs(SkSerialProcs* procs) { auto encode = [](SkTypeface* tf, void* ctx) { return reinterpret_cast<SkRemoteGlyphCacheRenderer*>(ctx)->encodeTypeface(tf); @@ -45,12 +259,289 @@ SkScalerContext* SkRemoteGlyphCacheRenderer::generateScalerContext( return scaler->get(); } +// -- TrackLayerDevice ----------------------------------------------------------------------------- +class TrackLayerDevice : public SkNoPixelsDevice { +public: + TrackLayerDevice(const SkIRect& bounds, const SkSurfaceProps& props) + : SkNoPixelsDevice(bounds, props) { } + SkBaseDevice* onCreateDevice(const CreateInfo& cinfo, const SkPaint*) override { + const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry); + return new TrackLayerDevice(this->getGlobalBounds(), surfaceProps); + } +}; + +// -- SkStrikeCacheDifferenceSpec ------------------------------------------------------------------ + +SkStrikeCacheDifferenceSpec::StrikeDifferences::StrikeDifferences( + SkFontID typefaceID, std::unique_ptr<SkDescriptor> desc) + : fTypefaceID{typefaceID} + , fDesc{std::move(desc)} { } + +void SkStrikeCacheDifferenceSpec::StrikeDifferences::operator()(uint16_t glyphID, SkIPoint pos) { + SkPackedGlyphID packedGlyphID{glyphID, pos.x(), pos.y()}; + fGlyphIDs->add(packedGlyphID); +} + + +SkStrikeCacheDifferenceSpec::StrikeDifferences& +SkStrikeCacheDifferenceSpec::findStrikeDifferences(const SkDescriptor& desc, + SkFontID typefaceID) { + auto mapIter = fDescMap.find(&desc); + if (mapIter == fDescMap.end()) { + auto newDesc = desc.copy(); + auto newDescPtr = newDesc.get(); + StrikeDifferences strikeDiffs{typefaceID, std::move(newDesc)}; + + mapIter = fDescMap.emplace_hint(mapIter, newDescPtr, std::move(strikeDiffs)); + } + + return mapIter->second; +} + +template <typename PerStrike, typename PerGlyph> +void SkStrikeCacheDifferenceSpec::iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const { + for (auto& i : fDescMap) { + auto strikeDiff = &i.second; + perStrike(strikeDiff->fTypefaceID, + *strikeDiff->fDesc, + strikeDiff->fGlyphIDs->count()); + strikeDiff->fGlyphIDs->foreach([&](SkPackedGlyphID id) { + perGlyph(id); + }); + } +} + +// -- SkTextBlobCacheDiffCanvas ------------------------------------------------------------------- +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} + , fScalerContextFlags{flags} + , fStrikeCacheDiff{strikeDiffs} { } + +SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy( + const SaveLayerRec&rec) +{ + return kFullLayer_SaveLayerStrategy; +} + +void SkTextBlobCacheDiffCanvas::onDrawTextBlob( + const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { + SkPoint position{x, y}; + + SkPaint runPaint{paint}; + SkTextBlobRunIterator it(blob); + for (;!it.done(); it.next()) { + // applyFontToPaint() always overwrites the exact same attributes, + // so it is safe to not re-seed the paint for this reason. + it.applyFontToPaint(&runPaint); + runPaint.setFlags(this->getTopDevice()->filterTextFlags(runPaint)); + if (auto looper = runPaint.getLooper()) { + this->processLooper(position, it, runPaint, looper); + } else { + this->processGlyphRun(position, it, runPaint); + } + } +} + +void SkTextBlobCacheDiffCanvas::processLooper( + const SkPoint& position, + const SkTextBlobRunIterator& it, + const SkPaint& origPaint, + SkDrawLooper* looper) +{ + SkSTArenaAlloc<48> alloc; + auto context = looper->makeContext(this, &alloc); + SkPaint runPaint = origPaint; + while (context->next(this, &runPaint)) { + this->save(); + this->processGlyphRun(position, it, runPaint); + this->restore(); + runPaint = origPaint; + } +} + +void SkTextBlobCacheDiffCanvas::processGlyphRun( + const SkPoint& position, + const SkTextBlobRunIterator& it, + const SkPaint& runPaint) +{ + + if (runPaint.getTextEncoding() != SkPaint::TextEncoding::kGlyphID_TextEncoding) { + return; + } + + // All other alignment modes need the glyph advances. Use the slow drawing mode. + if (runPaint.getTextAlign() != SkPaint::kLeft_Align) { + return; + } + + using PosFn = SkPoint(*)(int index, const SkScalar* pos); + PosFn posFn; + switch (it.positioning()) { + case SkTextBlob::kDefault_Positioning: + // Default positioning needs advances. Can't do that. + return; + + case SkTextBlob::kHorizontal_Positioning: + posFn = [](int index, const SkScalar* pos) { + return SkPoint{pos[index], 0}; + }; + + break; + + case SkTextBlob::kFull_Positioning: + posFn = [](int index, const SkScalar* pos) { + return SkPoint{pos[2 * index], pos[2 * index + 1]}; + }; + break; + + default: + posFn = nullptr; + SK_ABORT("unhandled positioning mode"); + } + + SkMatrix blobMatrix{fDeviceMatrix}; + blobMatrix.preConcat(this->getTotalMatrix()); + if (blobMatrix.hasPerspective()) { + return; + } + blobMatrix.preTranslate(position.x(), position.y()); + + SkMatrix runMatrix{blobMatrix}; + runMatrix.preTranslate(it.offset().x(), it.offset().y()); + + using MapFn = SkPoint(*)(const SkMatrix& m, SkPoint pt); + MapFn mapFn; + switch ((int)runMatrix.getType()) { + case SkMatrix::kIdentity_Mask: + case SkMatrix::kTranslate_Mask: + mapFn = [](const SkMatrix& m, SkPoint pt) { + pt.offset(m.getTranslateX(), m.getTranslateY()); + return pt; + }; + break; + case SkMatrix::kScale_Mask: + case SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask: + mapFn = [](const SkMatrix& m, SkPoint pt) { + return SkPoint{pt.x() * m.getScaleX() + m.getTranslateX(), + pt.y() * m.getScaleY() + m.getTranslateY()}; + }; + break; + case SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask: + case SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask: + mapFn = [](const SkMatrix& m, SkPoint pt) { + return SkPoint{ + pt.x() * m.getScaleX() + pt.y() * m.getSkewX() + m.getTranslateX(), + pt.x() * m.getSkewY() + pt.y() * m.getScaleY() + m.getTranslateY()}; + }; + break; + default: + mapFn = nullptr; + SK_ABORT("Bad matrix."); + } + + SkAutoDescriptor ad; + SkScalerContextRec rec; + SkScalerContextEffects effects; + + SkScalerContext::MakeRecAndEffects(runPaint, &fSurfaceProps, &runMatrix, + fScalerContextFlags, &rec, &effects); + + auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad); + + auto typefaceID = SkTypefaceProxy::DownCast(runPaint.getTypeface())->remoteTypefaceID(); + auto& addGlyph = fStrikeCacheDiff->findStrikeDifferences(*desc, typefaceID); + + auto cache = SkGlyphCache::FindStrikeExclusive(*desc); + bool isSubpixel = SkToBool(rec.fFlags & SkScalerContext::kSubpixelPositioning_Flag); + SkAxisAlignment axisAlignment = SkAxisAlignment::kNone_SkAxisAlignment; + if (it.positioning() == SkTextBlob::kHorizontal_Positioning) { + axisAlignment = rec.computeAxisAlignmentForHText(); + } + auto pos = it.pos(); + const uint16_t* glyphs = it.glyphs(); + for (uint32_t index = 0; index < it.glyphCount(); index++) { + SkIPoint subPixelPos{0, 0}; + if (runPaint.isAntiAlias() && isSubpixel) { + SkPoint glyphPos = mapFn(runMatrix, posFn(index, pos)); + subPixelPos = SkFindAndPlaceGlyph::SubpixelAlignment(axisAlignment, glyphPos); + } + + if (cache && + cache->isGlyphCached(glyphs[index], subPixelPos.x(), subPixelPos.y())) { + continue; + } + + addGlyph(glyphs[index], subPixelPos); + } +} + + +enum class OpCode : int32_t { + kFontMetrics = 0, + kGlyphPath = 1, + kGlyphMetricsAndImage = 2, + kPrepopulateCache = 3, +}; + +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 { + // op 0 + SkPaint::FontMetrics fontMetrics; + // op 1, 2, and 4 + SkGlyph glyph; + // op 3 + struct { + SkGlyphID glyphId; + size_t pathSize; + }; + }; +}; + +struct Header { + Header(int strikeCount_) : strikeCount{strikeCount_} {} + const int strikeCount; +}; +struct StrikeSpec { + StrikeSpec(SkFontID typefaceID_, uint32_t descLength_, int glyphCount_) + : typefaceID{typefaceID_} + , descLength{descLength_} + , glyphCount{glyphCount_} { } + SkFontID typefaceID; + uint32_t descLength; + int glyphCount; + /* desc */ + /* n X (glyphs ids) */ +}; + +struct WireTypeface { + // std::thread::id thread_id; // TODO:need to figure a good solution + SkFontID typefaceID; + int glyphCount; + SkFontStyle style; + bool isFixed; +}; + sk_sp<SkData> SkRemoteGlyphCacheRenderer::encodeTypeface(SkTypeface* tf) { WireTypeface wire = { - SkTypeface::UniqueID(tf), - tf->countGlyphs(), - tf->fontStyle(), - tf->isFixedPitch() + SkTypeface::UniqueID(tf), + tf->countGlyphs(), + tf->fontStyle(), + tf->isFixedPitch() }; auto typeFace = fTypefaceMap.find(SkTypeface::UniqueID(tf)); if (typeFace == nullptr) { @@ -59,26 +550,342 @@ sk_sp<SkData> SkRemoteGlyphCacheRenderer::encodeTypeface(SkTypeface* tf) { // Can this be done with no copy? return SkData::MakeWithCopy(&wire, sizeof(wire)); } +static void write_strikes_spec(const SkStrikeCacheDifferenceSpec &spec, + Serializer* serializer, + SkTransport* transport) { + serializer->startEmplace<Op>(OpCode::kPrepopulateCache, SkFontID{0}, SkScalerContextRec{}); + + serializer->emplace<Header>(spec.size()); + + auto perStrike = [serializer](SkFontID typefaceID, const SkDescriptor& desc, int glyphCount) { + serializer->emplace<StrikeSpec>(typefaceID, desc.getLength(), glyphCount); + serializer->writeDescriptor(desc); + }; + + auto perGlyph = [serializer](SkPackedGlyphID glyphID) { + serializer->write<SkPackedGlyphID>(glyphID); + }; + + spec.iterateDifferences(perStrike, perGlyph); + + serializer->endWrite(transport); +} + +#if 0 +template <typename PerHeader, typename PerStrike, typename PerGlyph> + static void ReadSpecFromTransport(AllInOneTransport* transport, + PerHeader perHeader, + PerStrike perStrike, + PerGlyph perGlyph) { + auto header = transport->read<SkTextBlobCacheDiffCanvas::Header>(); + perHeader(header); + for (int i = 0; i < header->strikeCount; i++) { + auto strike = transport->read<SkTextBlobCacheDiffCanvas::StrikeSpec>(); + auto desc = transport->readDescriptor(); + //desc->assertChecksum(); + perStrike(strike, desc); + auto glyphIDs = transport->readArray<SkPackedGlyphID>(strike->glyphCount); + for (auto glyphID : glyphIDs) { + perGlyph(glyphID); + } + } + } + + static void WriteDataToTransport( + AllInOneTransport* in, AllInOneTransport* out, SkRemoteGlyphCacheRenderer* rc) { + auto perHeader = [out](Header* header) { + out->write<Header>(*header); + }; + + struct { + SkScalerContext* scaler{nullptr}; + } strikeData; + + auto perStrike = [out, &strikeData, rc](StrikeSpec* spec, SkDescriptor* desc) { + out->write<StrikeSpec>(*spec); + out->writeDescriptor(*desc); + SkScalerContextRecDescriptor recDesc{*desc}; + strikeData.scaler = rc->generateScalerContext(recDesc, spec->typefaceID); + SkPaint::FontMetrics fontMetrics; + strikeData.scaler->getFontMetrics(&fontMetrics); + out->write<SkPaint::FontMetrics>(fontMetrics); + }; + + auto perGlyph = [out, &strikeData](SkPackedGlyphID glyphID) { + SkGlyph glyph; + glyph.initWithGlyphID(glyphID); + strikeData.scaler->getMetrics(&glyph); + auto imageSize = glyph.computeImageSize(); + glyph.fImage = nullptr; + glyph.fPathData = nullptr; + out->write<SkGlyph>(glyph); + + if (imageSize > 0) { + glyph.fImage = out->allocateArray<uint8_t>(imageSize); + strikeData.scaler->getImage(glyph); + } + }; + + ReadSpecFromTransport(in, perHeader, perStrike, perGlyph); + } +#endif + +static void read_strikes_spec_write_strikes_data( + Deserializer* deserializer, Serializer* serializer, SkTransport* transport, + SkRemoteGlyphCacheRenderer* rc) +{ + // Don't start because the op started this deserialization. + auto header = deserializer->read<Header>(); + serializer->startWrite<Header>(*header); + for (int i = 0; i < header->strikeCount; i++) { + auto spec = deserializer->read<StrikeSpec>(); + auto desc = deserializer->readDescriptor(); + serializer->write<StrikeSpec>(*spec); + serializer->writeDescriptor(*desc); + SkScalerContextRecDescriptor recDesc{*desc}; + auto scaler = rc->generateScalerContext(recDesc, spec->typefaceID); + SkPaint::FontMetrics fontMetrics; + scaler->getFontMetrics(&fontMetrics); + serializer->write<SkPaint::FontMetrics>(fontMetrics); + auto glyphIDs = deserializer->readArray<SkPackedGlyphID>(spec->glyphCount); + for (auto glyphID : glyphIDs) { + auto glyph = serializer->allocate<SkGlyph>(); + glyph->initWithGlyphID(glyphID); + scaler->getMetrics(glyph); + auto imageSize = glyph->computeImageSize(); + glyph->fPathData = nullptr; + glyph->fImage = nullptr; + + if (imageSize > 0) { + glyph->fImage = serializer->allocateArray<uint8_t>(imageSize); + scaler->getImage(*glyph); + } + } + } + deserializer->endRead(); + serializer->endWrite(transport); +} + +static void update_caches_from_strikes_data(SkStrikeClient *client, + Deserializer *deserializer, + SkTransport *transport) { + deserializer->startRead(transport); + auto header = deserializer->read<Header>(); + 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 = SkGlyphCache::FindStrikeExclusive(*desc); + if (strike == nullptr) { + auto scaler = SkGlyphCache::CreateScalerContext(*desc, effects, *tf); + strike = SkGlyphCache::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()); + } + } + deserializer->endRead(); +} + + +// -- SkStrikeServer ------------------------------------------------------------------------------- +SkStrikeServer::SkStrikeServer(SkTransport* transport) + : fTransport{transport} { } -SkRemoteGlyphCacheGPU::SkRemoteGlyphCacheGPU( - std::unique_ptr<SkRemoteScalerContext> remoteScalerContext) - : fRemoteScalerContext{std::move(remoteScalerContext)} { } +int SkStrikeServer::serve() { + + auto serializer = skstd::make_unique<Serializer>(); + auto deserializer = skstd::make_unique<Deserializer>();; + + while (true) { + printf("Server is waiting for an op\n"); + Op* op = deserializer->startRead<Op>(fTransport); + if (op == nullptr) { break; } + + switch (op->opCode) { + case OpCode::kFontMetrics : { + auto sc = fRendererCache.generateScalerContext(op->descriptor, op->typefaceId); + SkPaint::FontMetrics metrics; + sc->getFontMetrics(&metrics); + serializer->startWrite<SkPaint::FontMetrics>(metrics); + serializer->endWrite(fTransport); + break; + } + case OpCode::kGlyphPath : { + auto sc = fRendererCache.generateScalerContext(op->descriptor, op->typefaceId); + // TODO: check for buffer overflow. + SkPath path; + sc->getPath(op->glyphId, &path); + size_t pathSize = path.writeToMemory(nullptr); + serializer->startWrite<size_t>(pathSize); + auto pathData = serializer->allocateArray<uint8_t>(pathSize); + path.writeToMemory(pathData); + serializer->endWrite(fTransport); + break; + } + case OpCode::kGlyphMetricsAndImage : { + auto sc = fRendererCache.generateScalerContext(op->descriptor, op->typefaceId); + + serializer->startWrite(); + auto glyph = serializer->allocate<SkGlyph>(); + // TODO: check for buffer overflow. + glyph->initWithGlyphID(op->glyph.getPackedID()); + sc->getMetrics(glyph); + auto imageSize = glyph->computeImageSize(); + glyph->fPathData = nullptr; + glyph->fImage = nullptr; + + if (imageSize > 0) { + glyph->fImage = serializer->allocateArray<uint8_t>(imageSize); + sc->getImage(*glyph); + } + + serializer->endWrite(fTransport); + break; + } + case OpCode::kPrepopulateCache : { + read_strikes_spec_write_strikes_data( + deserializer.get(), serializer.get(), fTransport, &fRendererCache); + break; + } + + default: + SK_ABORT("Bad op"); + } + } + return 0; +} + +// -- SkStrikeClient ------------------------------------------------------------------------------- + +static Op* start_op_write( + OpCode opCode, const SkTypefaceProxy& tf, const SkScalerContextRec& rec, Serializer* serializer) +{ + return serializer->startEmplace<Op>(opCode, tf.remoteTypefaceID(), rec); +} -void SkRemoteGlyphCacheGPU::prepareDeserializeProcs(SkDeserialProcs* procs) { +SkStrikeClient::SkStrikeClient(SkTransport* transport) : fTransport{transport} { } + +void SkStrikeClient::generateFontMetrics( + const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkPaint::FontMetrics* metrics) { + // Send generateFontMetrics + { + Serializer serializer; + serializer.startEmplace<Op>(OpCode::kFontMetrics, typefaceProxy.remoteTypefaceID(), rec); + start_op_write(OpCode::kFontMetrics, typefaceProxy, rec, &serializer); + serializer.endWrite(fTransport); + } + + // Receive generateFontMetrics + { + Deserializer deserializer; + deserializer.startRead(fTransport); + *metrics = *deserializer.read<SkPaint::FontMetrics>(); + deserializer.endRead(); + } +} + +void SkStrikeClient::generateMetricsAndImage( + const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkArenaAlloc* alloc, + SkGlyph* glyph) { + SkScalerContextRecDescriptor rd{rec}; + + { + Serializer serializer; + Op *op = serializer.startEmplace<Op>( + OpCode::kGlyphMetricsAndImage, typefaceProxy.remoteTypefaceID(), rec); + op->glyph = *glyph; + serializer.endWrite(fTransport); + } + + // Receive generateMetricsAndImage + { + Deserializer deserializer; + *glyph = *deserializer.startRead<SkGlyph>(fTransport); + 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); + } else { + glyph->fImage = nullptr; + } + deserializer.endRead(); + } + +} +void SkStrikeClient::generatePath( + const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkGlyphID glyphID, + SkPath* path) { + // Send generatePath + SkScalerContextRecDescriptor rd{rec}; + + { + Serializer serializer; + Op *op = serializer.startEmplace<Op>( + OpCode::kGlyphPath, typefaceProxy.remoteTypefaceID(), rec); + op->glyphId = glyphID; + serializer.endWrite(fTransport); + } + + { + Deserializer deserializer; + size_t pathSize = *deserializer.startRead<size_t>(fTransport); + auto rawPath = deserializer.readArray<uint8_t>(pathSize); + path->readFromMemory(rawPath.data(), rawPath.size()); + deserializer.endRead(); + } +} + +void SkStrikeClient::primeStrikeCache(const SkStrikeCacheDifferenceSpec& strikeDifferences) { + { + auto serializer = skstd::make_unique<Serializer>(); + write_strikes_spec(strikeDifferences, serializer.get(), fTransport); + } + { + auto deserializer = skstd::make_unique<Deserializer>();; + update_caches_from_strikes_data(this, deserializer.get(), fTransport); + } +} + +void SkStrikeClient::prepareDeserializeProcs(SkDeserialProcs* procs) { auto decode = [](const void* buf, size_t len, void* ctx) { - return reinterpret_cast<SkRemoteGlyphCacheGPU*>(ctx)->decodeTypeface(buf, len); + return reinterpret_cast<SkStrikeClient*>(ctx)->decodeTypeface(buf, len); }; procs->fTypefaceProc = decode; procs->fTypefaceCtx = this; + } -SkTypeface* SkRemoteGlyphCacheGPU::lookupTypeface(SkFontID id) { +SkTypeface* SkStrikeClient::lookupTypeface(SkFontID id) { auto typeface = fMapIdToTypeface.find(id); SkASSERT(typeface != nullptr); return typeface->get(); } -sk_sp<SkTypeface> SkRemoteGlyphCacheGPU::decodeTypeface(const void* buf, size_t len) { +sk_sp<SkTypeface> SkStrikeClient::decodeTypeface(const void* buf, size_t len) { WireTypeface wire; if (len < sizeof(wire)) { SK_ABORT("Incomplete transfer"); @@ -88,17 +895,14 @@ sk_sp<SkTypeface> SkRemoteGlyphCacheGPU::decodeTypeface(const void* buf, size_t auto typeFace = fMapIdToTypeface.find(wire.typefaceID); if (typeFace == nullptr) { - auto newTypeface = sk_make_sp<SkTypefaceProxy>( - wire.typefaceID, - wire.glyphCount, - wire.style, - wire.isFixed, - fRemoteScalerContext.get()); + wire.typefaceID, + wire.glyphCount, + wire.style, + wire.isFixed, + this); typeFace = fMapIdToTypeface.set(wire.typefaceID, newTypeface); } return *typeFace; -} - - +}
\ No newline at end of file diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h index e9afacefd7..021431e656 100644 --- a/src/core/SkRemoteGlyphCache.h +++ b/src/core/SkRemoteGlyphCache.h @@ -9,14 +9,33 @@ #define SkRemoteGlyphCache_DEFINED #include <memory> +#include <tuple> +#include <unordered_map> #include <vector> + #include "SkData.h" #include "SkDescriptor.h" +#include "SkDrawLooper.h" +#include "SkGlyphCache.h" +#include "SkMakeUnique.h" +#include "SkNoDrawCanvas.h" #include "SkSerialProcs.h" +#include "SkTextBlobRunIterator.h" #include "SkTHash.h" #include "SkTypeface.h" #include "SkTypeface_remote.h" +class SkTransport { +public: + enum IOResult : bool {kFail = false, kSuccess = true}; + + virtual ~SkTransport() {} + virtual IOResult write(const void*, size_t) = 0; + virtual std::tuple<size_t, IOResult> read(void*, size_t) = 0; + IOResult writeSkData(const SkData&); + sk_sp<SkData> readSkData(); +}; + class SkScalerContextRecDescriptor { public: SkScalerContextRecDescriptor() {} @@ -29,7 +48,7 @@ public: } explicit SkScalerContextRecDescriptor(const SkDescriptor& desc) - : SkScalerContextRecDescriptor(ExtractRec(desc)) { } + : SkScalerContextRecDescriptor(ExtractRec(desc)) { } SkScalerContextRecDescriptor& operator=(const SkScalerContextRecDescriptor& rhs) { std::memcpy(&fDescriptor, &rhs.fDescriptor, rhs.desc().getLength()); @@ -76,7 +95,7 @@ public: void prepareSerializeProcs(SkSerialProcs* procs); SkScalerContext* generateScalerContext( - const SkScalerContextRecDescriptor& desc, SkFontID typefaceId); + const SkScalerContextRecDescriptor& desc, SkFontID typefaceId); private: sk_sp<SkData> encodeTypeface(SkTypeface* tf); @@ -84,25 +103,120 @@ private: SkTHashMap<SkFontID, sk_sp<SkTypeface>> fTypefaceMap; using DescriptorToContextMap = SkTHashMap<SkScalerContextRecDescriptor, - std::unique_ptr<SkScalerContext>, - SkScalerContextRecDescriptor::Hash>; + std::unique_ptr<SkScalerContext>, + SkScalerContextRecDescriptor::Hash>; DescriptorToContextMap fScalerContextMap; }; -class SkRemoteGlyphCacheGPU { +class SkStrikeCacheDifferenceSpec { + class StrikeDifferences; + +public: + StrikeDifferences& findStrikeDifferences(const SkDescriptor& desc, SkFontID typefaceID); + int size() const { return fDescMap.size(); } + template <typename PerStrike, typename PerGlyph> + void iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const; + +private: + class StrikeDifferences { + public: + StrikeDifferences(SkFontID typefaceID, std::unique_ptr<SkDescriptor> desc); + void operator()(uint16_t glyphID, SkIPoint pos); + SkFontID fTypefaceID; + std::unique_ptr<SkDescriptor> fDesc; + std::unique_ptr<SkTHashSet<SkPackedGlyphID>> fGlyphIDs = + skstd::make_unique<SkTHashSet<SkPackedGlyphID>>(); + }; + + struct DescHash { + size_t operator()(const SkDescriptor* key) const { + return key->getChecksum(); + } + }; + + struct DescEq { + bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const { + return lhs->getChecksum() == rhs->getChecksum(); + } + }; + + using DescMap = std::unordered_map<const SkDescriptor*, StrikeDifferences, DescHash, DescEq>; + DescMap fDescMap{16, DescHash(), DescEq()}; +}; + + +class SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas { +public: + SkTextBlobCacheDiffCanvas(int width, int height, + const SkMatrix& deviceMatrix, + const SkSurfaceProps& props, + SkScalerContextFlags flags, + SkStrikeCacheDifferenceSpec* strikeDiffs); + +protected: + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) 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); + + const SkMatrix fDeviceMatrix; + const SkSurfaceProps fSurfaceProps; + const SkScalerContextFlags fScalerContextFlags; + + SkStrikeCacheDifferenceSpec* const fStrikeCacheDiff; +}; + + +class SkStrikeServer { public: - explicit SkRemoteGlyphCacheGPU(std::unique_ptr<SkRemoteScalerContext> remoteScalerContext); + SkStrikeServer(SkTransport* transport); + + int serve(); + void prepareSerializeProcs(SkSerialProcs* procs) { + fRendererCache.prepareSerializeProcs(procs); + } + +private: + SkTransport* const fTransport; + SkRemoteGlyphCacheRenderer fRendererCache; +}; + +class SkStrikeClient { +public: + SkStrikeClient(SkTransport*); + void generateFontMetrics( + const SkTypefaceProxy&, const SkScalerContextRec&, SkPaint::FontMetrics*); + void generateMetricsAndImage( + const SkTypefaceProxy&, const SkScalerContextRec&, SkArenaAlloc*, SkGlyph*); + void generatePath( + const SkTypefaceProxy&, const SkScalerContextRec&, SkGlyphID glyph, SkPath* path); + + void primeStrikeCache(const SkStrikeCacheDifferenceSpec&); void prepareDeserializeProcs(SkDeserialProcs* procs); + SkTypeface* lookupTypeface(SkFontID id); private: sk_sp<SkTypeface> decodeTypeface(const void* buf, size_t len); - std::unique_ptr<SkRemoteScalerContext> fRemoteScalerContext; // TODO: Figure out how to manage the entries for the following maps. SkTHashMap<SkFontID, sk_sp<SkTypefaceProxy>> fMapIdToTypeface; + + SkTransport* const fTransport; }; #endif // SkRemoteGlyphCache_DEFINED diff --git a/src/core/SkTypeface_remote.cpp b/src/core/SkTypeface_remote.cpp index 504d2413ec..6fc6aa46d7 100644 --- a/src/core/SkTypeface_remote.cpp +++ b/src/core/SkTypeface_remote.cpp @@ -5,33 +5,46 @@ * found in the LICENSE file. */ -#include "SkPaint.h" - -#include "SkSemaphore.h" #include "SkTypeface_remote.h" -#include <iostream> + +#include "SkPaint.h" +#include "SkRemoteGlyphCache.h" SkScalerContextProxy::SkScalerContextProxy( sk_sp<SkTypeface> tf, const SkScalerContextEffects& effects, const SkDescriptor* desc, - SkRemoteScalerContext* rsc) + SkStrikeClient* rsc) : SkScalerContext{std::move(tf), effects, desc} - , fRemote{rsc} {} + , fClient{rsc} {} + +unsigned SkScalerContextProxy::generateGlyphCount() { + SK_ABORT("Should never be called."); + return 0; +} + +uint16_t SkScalerContextProxy::generateCharToGlyph(SkUnichar) { + SK_ABORT("Should never be called."); + return 0; +} + +void SkScalerContextProxy::generateAdvance(SkGlyph* glyph) { + this->generateMetrics(glyph); +} void SkScalerContextProxy::generateMetrics(SkGlyph* glyph) { - fRemote->generateMetricsAndImage(*this->typefaceProxy(), this->getRec(), &fAlloc, glyph); + fClient->generateMetricsAndImage(*this->typefaceProxy(), this->getRec(), &fAlloc, glyph); } void SkScalerContextProxy::generateImage(const SkGlyph& glyph) { } void SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) { - fRemote->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path); + fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path); } void SkScalerContextProxy::generateFontMetrics(SkPaint::FontMetrics* metrics) { - fRemote->generateFontMetrics(*this->typefaceProxy(), this->getRec(), metrics); + fClient->generateFontMetrics(*this->typefaceProxy(), this->getRec(), metrics); } SkTypefaceProxy* SkScalerContextProxy::typefaceProxy() { diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h index af90367d26..485982aa2d 100644 --- a/src/core/SkTypeface_remote.h +++ b/src/core/SkTypeface_remote.h @@ -16,44 +16,21 @@ #include "SkScalerContext.h" #include "SkTypeface.h" -#include <thread> - +class SkStrikeClient; class SkTypefaceProxy; -class SkRemoteScalerContext { -public: - virtual ~SkRemoteScalerContext() {} - // TODO: do metrics need effects? - virtual void generateFontMetrics( - const SkTypefaceProxy& tf, - const SkScalerContextRec& rec, - SkPaint::FontMetrics*) = 0; - virtual void generateMetricsAndImage( - const SkTypefaceProxy& tf, - const SkScalerContextRec& rec, - SkArenaAlloc* alloc, - SkGlyph* glyph) = 0; - virtual void generatePath( - const SkTypefaceProxy& tf, - const SkScalerContextRec& rec, - SkGlyphID glyph, SkPath* path) = 0; -}; - class SkScalerContextProxy : public SkScalerContext { public: SkScalerContextProxy( sk_sp<SkTypeface> tf, const SkScalerContextEffects& effects, const SkDescriptor* desc, - SkRemoteScalerContext* rsc); + SkStrikeClient* rsc); protected: - unsigned generateGlyphCount(void) override { SK_ABORT("Should never be called."); return 0;} - uint16_t generateCharToGlyph(SkUnichar uni) override { - SK_ABORT("Should never be called."); - return 0; - } - void generateAdvance(SkGlyph* glyph) override { this->generateMetrics(glyph); } + unsigned generateGlyphCount() override; + uint16_t generateCharToGlyph(SkUnichar) override; + void generateAdvance(SkGlyph* glyph) override; void generateMetrics(SkGlyph* glyph) override; void generateImage(const SkGlyph& glyph) override; void generatePath(SkGlyphID glyphID, SkPath* path) override; @@ -68,8 +45,8 @@ private: SkTypefaceProxy* typefaceProxy(); - SkArenaAlloc fAlloc{kMinAllocAmount}; - SkRemoteScalerContext* const fRemote; + SkArenaAlloc fAlloc{kMinAllocAmount}; + SkStrikeClient* const fClient; typedef SkScalerContext INHERITED; }; @@ -80,12 +57,12 @@ public: int glyphCount, const SkFontStyle& style, bool isFixed, - SkRemoteScalerContext* rsc) + SkStrikeClient* rsc) : INHERITED{style, false} , fFontId{fontId} , fGlyphCount{glyphCount} , fRsc{rsc} { } - SkFontID fontID() const {return fFontId;} + SkFontID remoteTypefaceID() const {return fFontId;} int glyphCount() const {return fGlyphCount;} static SkTypefaceProxy* DownCast(SkTypeface* typeface) { // TODO: how to check the safety of the down cast? @@ -124,8 +101,6 @@ protected: } SkScalerContext* onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const override { - //std::cout << fFontId << fThreadId; - return new SkScalerContextProxy(sk_ref_sp(const_cast<SkTypefaceProxy*>(this)), effects, desc, fRsc); @@ -161,10 +136,9 @@ protected: } private: - const SkFontID fFontId; - const int fGlyphCount; - // const std::thread::id fThreadId; // TODO: figure out a good solutions for this. - SkRemoteScalerContext* const fRsc; + const SkFontID fFontId; + const int fGlyphCount; + SkStrikeClient* const fRsc; typedef SkTypeface INHERITED; }; |