aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core/SkRemoteGlyphCache.cpp856
-rw-r--r--src/core/SkRemoteGlyphCache.h128
-rw-r--r--src/core/SkTypeface_remote.cpp31
-rw-r--r--src/core/SkTypeface_remote.h50
-rw-r--r--tools/remote_demo.cpp978
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 {