diff options
-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 | ||||
-rw-r--r-- | tools/remote_demo.cpp | 978 |
5 files changed, 1067 insertions, 976 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; }; diff --git a/tools/remote_demo.cpp b/tools/remote_demo.cpp index 7cedaea00b..0649ec9cbd 100644 --- a/tools/remote_demo.cpp +++ b/tools/remote_demo.cpp @@ -5,817 +5,76 @@ * found in the LICENSE file. */ -#include "SkCanvas.h" -#include "SkGlyph.h" -#include "SkPathEffect.h" -#include "SkMaskFilter.h" -#include "SkData.h" -#include "SkDescriptor.h" -#include "SkGraphics.h" -#include "SkNoDrawCanvas.h" -#include "SkPictureRecorder.h" -#include "SkSerialProcs.h" -#include "SkSurface.h" -#include "SkTypeface.h" -#include "SkWriteBuffer.h" -#include "SkTextBlobRunIterator.h" -#include "SkGlyphCache.h" -#include "SkDrawFilter.h" -#include "SkDevice.h" - -#include <type_traits> #include <chrono> -#include <ctype.h> #include <err.h> -#include <memory> -#include <stdio.h> -#include <thread> -#include <tuple> #include <iostream> -#include <unordered_map> -#include <iomanip> - +#include <memory> +#include <string> #include <sys/types.h> #include <sys/uio.h> #include <sys/wait.h> +#include <thread> #include <unistd.h> -#include <sys/mman.h> -#include <SkFindAndPlaceGlyph.h> -#include <SkDrawLooper.h> -#include "SkTypeface_remote.h" -#include "SkRemoteGlyphCache.h" -#include "SkMakeUnique.h" -static const size_t kPageSize = 4096; +#include "SkRemoteGlyphCache.h" +#include "SkGraphics.h" +#include "SkSurface.h" +static std::string gSkpName; static bool gUseGpu = true; static bool gPurgeFontCaches = true; static bool gUseProcess = true; -static int gFontMetrics; -static int gMetricsImage; -static int gPath; - -enum direction : int {kRead = 0, kWrite = 1}; - -#define INSTRUMENT 0 - -template <typename T> -class SkArraySlice : public std::tuple<const T*, size_t> { -public: - // Additional constructors as needed. - SkArraySlice(const T* data, size_t size) : std::tuple<const T*, size_t>{data, size} { } - SkArraySlice() : SkArraySlice<T>(nullptr, 0) { } - friend const T* begin(const SkArraySlice<T>& slice) { - return slice.data(); - } - - friend const T* end(const SkArraySlice<T>& slice) { - return &slice.data()[slice.size()]; - } - const T* data() const { - return std::get<0>(*this); - } - - size_t size() const { - return std::get<1>(*this); - } -}; - -// TODO: handle alignment -// TODO: handle overflow -class Transport { +class ReadWriteTransport : public SkTransport { public: - enum IOResult : bool {kFail = false, kSuccess = true}; - - Transport(Transport&& t) - : fReadFd{t.fReadFd} - , fWriteFd{t.fWriteFd} - , fBuffer{std::move(t.fBuffer)} - , fCloser{t.fCloser} { } - - Transport(const Transport& t) - : fReadFd{t.fReadFd} - , fWriteFd{t.fWriteFd} - , fBuffer{new uint8_t[kBufferSize]} - , fCloser{t.fCloser} { } - - Transport(int readFd, int writeFd) - : fReadFd{readFd} - , fWriteFd{writeFd} - , fCloser{std::make_shared<Closer>(readFd, writeFd)} { } - - static Transport DoubleBuffer(const Transport& transport) { - return Transport{transport}; - } - - struct Closer { - Closer(int readFd, int writeFd) : fReadFd{readFd}, fWriteFd{writeFd} { } - ~Closer() { - close(fWriteFd); - close(fReadFd); - } - int fReadFd, - fWriteFd; - }; - - void startRead() { - fCursor = 0; - fEnd = 0; - } - - template <typename T> - T* startRead() { - this->startRead(); - 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> - SkArraySlice<T> readArray(int count) { - size_t size = count * sizeof(T); - const T* base = (const T*)this->ensureAtLeast(size); - SkArraySlice<T> result = SkArraySlice<T>{base, (uint32_t)count}; - fCursor += size; - return result; - } - - size_t endRead() {return size();} - - sk_sp<SkData> readEntireData() { - size_t* size = this->startRead<size_t>(); - if (size == nullptr) { - return nullptr; - } - const uint8_t* data = this->readArray<uint8_t>(*size).data(); - if (size == nullptr || data == nullptr) { - this->endRead(); - return sk_sp<SkData>(nullptr); - } - auto result = SkData::MakeWithCopy(data, *size); - this->endRead(); - return result; - } - - 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); - } - - 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; - } - - IOResult endWrite() { - ssize_t written; - if((written = ::write(fWriteFd, fBuffer.get(), fCursor)) < 0) { + ReadWriteTransport(int readFd, int writeFd) : fReadFd{readFd}, fWriteFd{writeFd} {} + ~ReadWriteTransport() override { + close(fWriteFd); + close(fReadFd); + } + IOResult write(const void* buffer, size_t size) override { + ssize_t writeSize = ::write(fWriteFd, buffer, size); + if (writeSize < 0) { + err(1,"Failed write %zu", size); return kFail; } return kSuccess; } - IOResult writeEntireData(const SkData& data) { - size_t size = data.size(); - iovec vec[2]; - vec[0].iov_base = &size; - vec[0].iov_len = sizeof(size); - vec[1].iov_base = (void *)data.data(); - vec[1].iov_len = size; - - if(::writev(fWriteFd, vec, 2) < 0) { - return kFail; + std::tuple<size_t, IOResult> read(void* buffer, size_t size) override { + ssize_t readSize = ::read(fReadFd, buffer, size); + if (readSize < 0) { + err(1,"Failed read %zu", size); + return {size, kFail}; } - return kSuccess; + return {readSize, kSuccess}; } - size_t size() {return fCursor;} - private: - void* ensureAtLeast(size_t size) { - if (size > fEnd - fCursor) { - if (readAtLeast(size) == kFail) { - return nullptr; - } - } - return &fBuffer[fCursor]; - } - - IOResult readAtLeast(size_t size) { - size_t readSoFar = 0; - size_t bufferLeft = kBufferSize - fCursor; - size_t needed = size - (fEnd - fCursor); - while (readSoFar < needed) { - ssize_t readSize; - if ((readSize = ::read(fReadFd, &fBuffer[fEnd+readSoFar], bufferLeft - readSoFar)) <= 0) { - if (readSize != 0) { - err(1,"Failed read %zu", size); - } - return kFail; - } - readSoFar += readSize; - } - fEnd += readSoFar; - return kSuccess; - } - - static constexpr size_t kBufferSize = kPageSize * 2000; const int fReadFd, fWriteFd; - - std::unique_ptr<uint8_t[]> fBuffer{new uint8_t[kBufferSize]}; - std::shared_ptr<Closer> fCloser; - - size_t fCursor{0}; - size_t fEnd{0}; -}; - -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; - }; - }; }; +static void prime_cache_spec(const SkIRect& bounds, + const SkSurfaceProps& props, + const SkPicture& pic, + SkStrikeCacheDifferenceSpec* strikeDifference) { + SkMatrix deviceMatrix = SkMatrix::I(); -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); - } -}; - - -class TextBlobFilterCanvas : public SkNoDrawCanvas { -public: - 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 Header { - Header(int strikeCount_) : strikeCount{strikeCount_} {} - const int strikeCount; - }; - - TextBlobFilterCanvas(int width, int height, - const SkMatrix& deviceMatrix, - const SkSurfaceProps& props, - SkScalerContextFlags flags) - : SkNoDrawCanvas{new TrackLayerDevice{SkIRect::MakeWH(width, height), props}} - , fDeviceMatrix{deviceMatrix} - , fSurfaceProps{props} - , fScalerContextFlags{flags} { } - - void writeSpecToTransport(Transport* transport) { - transport->emplace<Header>((int)fDescMap.size()); - for (auto& i : fDescMap) { - auto accum = &i.second; - transport->emplace<StrikeSpec>( - accum->typefaceID, accum->desc->getLength(), accum->glyphIDs->count()); - transport->writeDescriptor(*accum->desc); - accum->glyphIDs->foreach([&](SkPackedGlyphID id) { - transport->write<SkPackedGlyphID>(id); - }); - } - } - - static void WriteDataToTransport( - Transport* in, Transport* 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); - } - - template <typename PerHeader, typename PerStrike, typename PerGlyph> - static void ReadSpecFromTransport(Transport* transport, - PerHeader perHeader, - PerStrike perStrike, - PerGlyph perGlyph) { - auto header = transport->read<TextBlobFilterCanvas::Header>(); - perHeader(header); - for (int i = 0; i < header->strikeCount; i++) { - auto strike = transport->read<TextBlobFilterCanvas::StrikeSpec>(); - auto desc = transport->readDescriptor(); - //desc->assertChecksum(); - perStrike(strike, desc); - auto glyphIDs = transport->readArray<SkPackedGlyphID>(strike->glyphCount); - for (auto glyphID : glyphIDs) { - perGlyph(glyphID); - } - } - } - - template <typename PerStrike, typename PerGlyph, typename FinishStrike> - void readDataFromTransport( - Transport* transport, PerStrike perStrike, PerGlyph perGlyph, FinishStrike finishStrike) { - auto header = transport->read<Header>(); - for (int i = 0; i < header->strikeCount; i++) { - auto strike = transport->read<StrikeSpec>(); - auto desc = transport->readDescriptor(); - auto fontMetrics = transport->read<SkPaint::FontMetrics>(); - perStrike(strike, desc, fontMetrics); - for (int j = 0; j < strike->glyphCount; j++) { - auto glyph = transport->read<SkGlyph>(); - SkArraySlice<uint8_t> image = SkArraySlice<uint8_t>{}; - auto imageSize = glyph->computeImageSize(); - if (imageSize != 0) { - image = transport->readArray<uint8_t>(imageSize); - } - perGlyph(glyph, image); - } - finishStrike(); - } - } - - -protected: - SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override { - return kFullLayer_SaveLayerStrategy; - } - - void onDrawTextBlob( - const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) override - { - 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, this); - } else { - this->processGlyphRun(position, it, runPaint); - } - } - } - - void onDrawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override { - SK_ABORT("DrawText"); - } - void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override { - SK_ABORT("DrawPosText"); - } - void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override { - SK_ABORT("DrawPosTextH"); - } - -private: - using PosFn = SkPoint(*)(int index, const SkScalar* pos); - using MapFn = SkPoint(*)(const SkMatrix& m, SkPoint pt); - - struct CacheAccum { - SkFontID typefaceID; - SkDescriptor* desc; - //std::vector<SkPackedGlyphID> glyphIDs; - std::unique_ptr<SkTHashSet<SkPackedGlyphID>> glyphIDs; - }; - - void processLooper( - const SkPoint& position, - const SkTextBlobRunIterator& it, - const SkPaint& origPaint, - SkDrawLooper* looper, - SkCanvas* canvas) - { - SkSTArenaAlloc<48> alloc; - auto context = looper->makeContext(canvas, &alloc); - SkPaint runPaint = origPaint; - while (context->next(this, &runPaint)) { - canvas->save(); - this->processGlyphRun(position, it, runPaint); - canvas->restore(); - runPaint = origPaint; - } - } - - void 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; - } - - 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()); - - 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); - - SkAxisAlignment axisAlignment = SkAxisAlignment::kNone_SkAxisAlignment; - if (it.positioning() == SkTextBlob::kHorizontal_Positioning) { - axisAlignment = rec.computeAxisAlignmentForHText(); - } - - auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad); - - auto mapIter = fDescMap.find(desc); - if (mapIter == fDescMap.end()) { - auto newDesc = desc->copy(); - auto newDescPtr = newDesc.get(); - fUniqueDescriptors.emplace_back(std::move(newDesc)); - CacheAccum newAccum; - newAccum.desc = newDescPtr; - - newAccum.typefaceID = - SkTypefaceProxy::DownCast(runPaint.getTypeface())->fontID(); - - newAccum.glyphIDs = skstd::make_unique<SkTHashSet<SkPackedGlyphID>>(); - mapIter = fDescMap.emplace_hint(mapIter, newDescPtr, std::move(newAccum)); - } - - auto accum = &mapIter->second; - - auto cache = SkGlyphCache::FindStrikeExclusive(*desc); - bool isSubpixel = SkToBool(rec.fFlags & SkScalerContext::kSubpixelPositioning_Flag); - - 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; - } - - SkPackedGlyphID glyphID{glyphs[index], subPixelPos.x(), subPixelPos.y()}; - accum->glyphIDs->add(glyphID); - } - } - - const SkMatrix fDeviceMatrix; - const SkSurfaceProps fSurfaceProps; - const SkScalerContextFlags fScalerContextFlags; - - 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<SkDescriptor*, CacheAccum, DescHash, DescEq>; - DescMap fDescMap{16, DescHash(), DescEq()}; - std::vector<std::unique_ptr<SkDescriptor>> fUniqueDescriptors; - - std::vector<SkPackedGlyphID> fTempGlyphs; - std::vector<SkPackedGlyphID> runGlyphs; -}; - - -class RemoteScalerContextFIFO : public SkRemoteScalerContext { -public: - explicit RemoteScalerContextFIFO(Transport* transport) - : fTransport{transport} { } - void generateFontMetrics(const SkTypefaceProxy& tf, - const SkScalerContextRec& rec, - SkPaint::FontMetrics* metrics) override { - gFontMetrics += 1; - - //SK_ABORT("generateFontMetrics should not be called."); - // Send generateFontMetrics - Op* op = this->startOpWrite(OpCode::kFontMetrics, tf, rec); - fTransport->endWrite(); - -#if INSTRUMENT - SkScalerContextRecDescriptor rd{rec}; - std::cout << " metrics font op rec tf: " << rec.fFontID - << " tf id: " << tf.fontID() - << " rec: " << rd.desc().getChecksum() - << rec.dump().c_str() << std::endl; -#endif - // Receive generateFontMetrics - op = fTransport->startRead<Op>(); - *metrics = op->fontMetrics; - fTransport->endRead(); - } - - void generateMetricsAndImage(const SkTypefaceProxy& tf, - const SkScalerContextRec& rec, - SkArenaAlloc* alloc, - SkGlyph* glyph) override { - gMetricsImage += 1; - //SK_ABORT("generateMetricsAndImage should not be called."); - // Send generateMetricsAndImage - SkScalerContextRecDescriptor rd{rec}; - -#if INSTRUMENT - std::cout << " metrics image op rec tf: " << rec.fFontID - << " tf id: " << tf.fontID() - << " rec: " << rd.desc().getChecksum() - << " glyphid: " << glyph->getPackedID().getPackedID() << "\n" - << rec.dump().c_str() << std::endl; -#endif - Op* op = this->startOpWrite(OpCode::kGlyphMetricsAndImage, tf, rec); - op->glyph = *glyph; - fTransport->endWrite(); - - // Receive generateMetricsAndImage - op = fTransport->startRead<Op>(); - *glyph = op->glyph; - auto imageSize = op->glyph.computeImageSize(); - glyph->fPathData = nullptr; - if (imageSize > 0) { - auto image = fTransport->readArray<uint8_t>(imageSize); - SkASSERT(imageSize == image.size()); - glyph->allocImage(alloc); - memcpy(glyph->fImage, image.data(), imageSize); - } else { - glyph->fImage = nullptr; - } - fTransport->endRead(); - } - - void generatePath(const SkTypefaceProxy& tf, - const SkScalerContextRec& rec, - SkGlyphID glyph, SkPath* path) override { - gPath += 1; - // Send generatePath - SkScalerContextRecDescriptor rd{rec}; - - std::cout << " path op rec tf: " << rec.fFontID - << " tf id: " << tf.fontID() - << " rec: " << rd.desc().getChecksum() - << " glyphid: " << glyph << std::endl; - Op* op = this->startOpWrite(OpCode::kGlyphPath, tf, rec); - op->glyphId = glyph; - fTransport->endWrite(); - - op = fTransport->startRead<Op>(); - auto rawPath = fTransport->readArray<uint8_t>(op->pathSize); - path->readFromMemory(rawPath.data(), rawPath.size()); - fTransport->endRead(); - } - -private: - Op* startOpWrite(OpCode opCode, const SkTypefaceProxy& tf, - const SkScalerContextRec& rec) { - return fTransport->startEmplace<Op>(opCode, tf.fontID(), rec); - } - - Transport* const fTransport; -}; - -static void prepopulate_cache( - Transport* transport, - SkRemoteGlyphCacheGPU* cache, - sk_sp<SkPicture> pic, - TextBlobFilterCanvas* filter) { - - pic->playback(filter); - - transport->startEmplace<Op>(OpCode::kPrepopulateCache, SkFontID{0}, - SkScalerContextRec{}); - filter->writeSpecToTransport(transport); - transport->endWrite(); - - SkExclusiveStrikePtr strike; - - auto perStrike = [&strike, cache](TextBlobFilterCanvas::StrikeSpec* spec, - SkDescriptor* desc, - SkPaint::FontMetrics* fontMetrics) { - auto tf = cache->lookupTypeface(spec->typefaceID); - // TODO: implement effects handling. - SkScalerContextEffects effects; - if ((strike = SkGlyphCache::FindStrikeExclusive(*desc)) == nullptr) { - auto scaler = SkGlyphCache::CreateScalerContext(*desc, effects, *tf); - strike = SkGlyphCache::CreateStrikeExclusive(*desc, std::move(scaler), fontMetrics); - } -#if INSTRUMENT - std::cout << std::hex << "prepop cache " << (intptr_t)cache - << " desc: " << desc->getChecksum() - << " typeface id: " << tf->uniqueID() - << " glyph count: " << spec->glyphCount << std::endl; - auto rec = (SkScalerContextRec*)desc->findEntry(kRec_SkDescriptorTag, nullptr); - SkDebugf("%s\n", rec->dump().c_str()); -#endif - - }; - - auto perGlyph = [&strike](SkGlyph* glyph, SkArraySlice<uint8_t> image) { - SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph->getPackedID()); - *allocatedGlyph = *glyph; - allocatedGlyph->allocImage(strike->getAlloc()); - memcpy(allocatedGlyph->fImage, image.data(), image.size()); - }; - - auto finishStrike = [&strike]() { - strike.reset(nullptr); - }; - - // needed for font metrics mistake. - Transport in = Transport::DoubleBuffer(*transport); -#if INSTRUMENT - SkDebugf("========= Sending prep cache ========\n"); -#endif + SkTextBlobCacheDiffCanvas filter( + bounds.width(), bounds.height(), deviceMatrix, props, + SkScalerContextFlags::kFakeGammaAndBoostContrast, + strikeDifference); - in.startRead(); - filter->readDataFromTransport(&in, perStrike, perGlyph, finishStrike); - in.endRead(); + pic.playback(&filter); } -std::string gSkpName; static void final_draw(std::string outFilename, - Transport* transport, + SkTransport* transport, SkDeserialProcs* procs, SkData* picData, - SkRemoteGlyphCacheGPU* cache) { + SkStrikeClient* client) { auto pic = SkPicture::MakeFromData(picData, procs); @@ -827,34 +86,43 @@ static void final_draw(std::string outFilename, auto picUnderTest = SkPicture::MakeFromData(picData, procs); SkMatrix deviceMatrix = SkMatrix::I(); - // kFakeGammaAndBoostContrast - TextBlobFilterCanvas filter( + + SkStrikeCacheDifferenceSpec strikeDifference; + SkTextBlobCacheDiffCanvas filter( r.width(), r.height(), deviceMatrix, s->props(), - SkScalerContextFlags::kFakeGammaAndBoostContrast); + SkScalerContextFlags::kFakeGammaAndBoostContrast, + &strikeDifference); - if (cache != nullptr) { + if (client != nullptr) { for (int i = 0; i < 0; i++) { auto start = std::chrono::high_resolution_clock::now(); - prepopulate_cache(transport, cache, picUnderTest, &filter); + + + SkStrikeCacheDifferenceSpec strikeDifference; + + prime_cache_spec(r, s->props(), *picUnderTest, &strikeDifference); + + client->primeStrikeCache(strikeDifference); auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration<double> elapsed_seconds = end - start; (void)elapsed_seconds; if (i == 0) { - std::cout << "filter time: " << elapsed_seconds.count() * 1e6 - << "us size: " << transport->size() << std::endl; + std::cout << "filter time: " << elapsed_seconds.count() * 1e6 << std::endl; } } } std::chrono::duration<double> total_seconds{0.0}; - for (int i = 0; i < 100; i++) { // 20 + for (int i = 0; i < 1; i++) { // 20 if (gPurgeFontCaches) { SkGraphics::PurgeFontCache(); } auto start = std::chrono::high_resolution_clock::now(); - if (cache != nullptr) { - prepopulate_cache(transport, cache, picUnderTest, &filter); + if (client != nullptr) { + SkStrikeCacheDifferenceSpec strikeDifference; + prime_cache_spec(r, s->props(), *picUnderTest, &strikeDifference); + client->primeStrikeCache(strikeDifference); } c->drawPicture(picUnderTest); auto end = std::chrono::high_resolution_clock::now(); @@ -867,9 +135,6 @@ static void final_draw(std::string outFilename, << " purgeCache: " << gPurgeFontCaches << std::endl; fprintf(stderr, "%s use GPU %s elapsed time %8.6f s\n", gSkpName.c_str(), gUseGpu ? "true" : "false", total_seconds.count()); - /*std::cerr << gSkpName << " use GPU " << std::boolalpha << gUseGpu << " elapsed time: " - << std::fixed << std::setw( 6 ) << std::setprecision( 1 ) - << total_seconds.count() << " s\n";*/ auto i = s->makeImageSnapshot(); auto data = i->encodeToData(); @@ -879,139 +144,53 @@ static void final_draw(std::string outFilename, static void gpu(int readFd, int writeFd) { - Transport transport{readFd, writeFd}; + ReadWriteTransport rwTransport{readFd, writeFd}; - auto picData = transport.readEntireData(); + auto picData = rwTransport.readSkData(); if (picData == nullptr) { return; } - SkRemoteGlyphCacheGPU rc{ - skstd::make_unique<RemoteScalerContextFIFO>(&transport) - }; + SkStrikeClient client{&rwTransport}; + SkDeserialProcs procs; - rc.prepareDeserializeProcs(&procs); + client.prepareDeserializeProcs(&procs); - final_draw("test.png", &transport, &procs, picData.get(), &rc); + final_draw("test.png", &rwTransport, &procs, picData.get(), &client); - if (gFontMetrics + gMetricsImage + gPath > 0) { - fprintf(stderr, "exceptions - fm: %d mi: %d p: %d\n", gFontMetrics, gMetricsImage, gPath); - } + printf("GPU is exiting\n"); } static int renderer( const std::string& skpName, int readFd, int writeFd) { - Transport transport{readFd, writeFd}; + ReadWriteTransport rwTransport{readFd, writeFd}; + SkStrikeServer server{&rwTransport}; auto skpData = SkData::MakeFromFileName(skpName.c_str()); std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl; - SkRemoteGlyphCacheRenderer rc; SkSerialProcs procs; sk_sp<SkData> stream; if (gUseGpu) { auto pic = SkPicture::MakeFromData(skpData.get()); - rc.prepareSerializeProcs(&procs); + server.prepareSerializeProcs(&procs); stream = pic->serialize(&procs); - } else { - stream = skpData; - } - - std::cout << "stream is " << stream->size() << " bytes long" << std::endl; - - if (!gUseGpu) { - final_draw("test-direct.png", &transport, nullptr, stream.get(), nullptr); - return 0; - } - - if (transport.writeEntireData(*stream) == Transport::kFail) { - return 1; - } - - std::cout << "Waiting for scaler context ops." << std::endl; - - while (true) { - - // Share the buffer between read and write. - Op* op = transport.startRead<Op>(); - if (op == nullptr) { std::cout << "Exit op loop" << std::endl; break;} - - switch (op->opCode) { - case OpCode::kFontMetrics : { - auto sc = rc.generateScalerContext(op->descriptor, op->typefaceId); - sc->getFontMetrics(&op->fontMetrics); - transport.endWrite(); - break; - } - case OpCode::kGlyphPath : { - auto sc = rc.generateScalerContext(op->descriptor, op->typefaceId); - // TODO: check for buffer overflow. - SkPath path; - sc->getPath(op->glyphId, &path); - size_t pathSize = path.writeToMemory(nullptr); - auto pathData = transport.allocateArray<uint8_t>(pathSize); - op->pathSize = path.writeToMemory(pathData); - transport.endWrite(); - break; - } - case OpCode::kGlyphMetricsAndImage : { - auto sc = rc.generateScalerContext(op->descriptor, op->typefaceId); - - // TODO: check for buffer overflow. - auto glyphId = op->glyph.getPackedID(); - op->glyph.initWithGlyphID(glyphId); - sc->getMetrics(&op->glyph); - auto imageSize = op->glyph.computeImageSize(); - op->glyph.fPathData = nullptr; - - if (imageSize > 0) { - op->glyph.fImage = transport.allocateArray<uint8_t>(imageSize); - sk_bzero(op->glyph.fImage, imageSize); - sc->getImage(op->glyph); - } else { - op->glyph.fImage = nullptr; - } - transport.endWrite(); - break; - } - case OpCode::kPrepopulateCache : { - Transport& in = transport; - Transport out = Transport::DoubleBuffer(transport); + if (rwTransport.writeSkData(*stream) == SkTransport::kFail) { + return 1; + } - out.startWrite(); - TextBlobFilterCanvas::WriteDataToTransport(&in ,&out, &rc); - out.endWrite(); - in.endRead(); + std::cout << "Waiting for scaler context ops." << std::endl; - //std::cout << "read prepopulate spec size: " << in.size() << std::endl; - //std::cout << "write prepopulate data size: " << out.size() << std::endl; - break; - } - default: - SK_ABORT("Bad op"); - } + return server.serve(); + } else { + stream = skpData; + final_draw("test-correct.png", &rwTransport, nullptr, stream.get(), nullptr); + return 0; } - - std::cout << "Returning from render" << std::endl; - - return 0; } -static void start_gpu(int render_to_gpu[2], int gpu_to_render[2]) { - std::cout << "gpu - Starting GPU" << std::endl; - close(gpu_to_render[kRead]); - close(render_to_gpu[kWrite]); - gpu(render_to_gpu[kRead], gpu_to_render[kWrite]); -} - -static void start_render(std::string& skpName, int render_to_gpu[2], int gpu_to_render[2]) { - std::cout << "renderer - Starting Renderer" << std::endl; - close(render_to_gpu[kRead]); - close(gpu_to_render[kWrite]); - renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]); -} int main(int argc, char** argv) { std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"skps/desk_nytimes.skp"}; @@ -1020,6 +199,9 @@ int main(int argc, char** argv) { gSkpName = skpName; + enum direction : int {kRead = 0, kWrite = 1}; + + int render_to_gpu[2], gpu_to_render[2]; @@ -1048,9 +230,13 @@ int main(int argc, char** argv) { SkGraphics::Init(); if (child == 0) { - start_gpu(render_to_gpu, gpu_to_render); + close(gpu_to_render[kRead]); + close(render_to_gpu[kWrite]); + gpu(render_to_gpu[kRead], gpu_to_render[kWrite]); } else { - start_render(skpName, render_to_gpu, gpu_to_render); + close(render_to_gpu[kRead]); + close(gpu_to_render[kWrite]); + renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]); waitpid(child, nullptr, 0); } } else { |