From 97be88f58a82b8e6ad7ef60a072cd8407d6423ce Mon Sep 17 00:00:00 2001 From: Herb Derby Date: Wed, 21 Mar 2018 16:23:49 -0400 Subject: Move cache difference code into remote cache files BUG=skia:7515 Change-Id: I59e75d460b4ed4d0a737c833520b2335808a4ce4 Reviewed-on: https://skia-review.googlesource.com/115706 Reviewed-by: Herb Derby Commit-Queue: Herb Derby --- tools/remote_demo.cpp | 978 +++++--------------------------------------------- 1 file changed, 82 insertions(+), 896 deletions(-) (limited to 'tools/remote_demo.cpp') 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 #include -#include #include -#include -#include -#include -#include #include -#include -#include - +#include +#include #include #include #include +#include #include -#include -#include -#include -#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 -class SkArraySlice : public std::tuple { -public: - // Additional constructors as needed. - SkArraySlice(const T* data, size_t size) : std::tuple{data, size} { } - SkArraySlice() : SkArraySlice(nullptr, 0) { } - friend const T* begin(const SkArraySlice& slice) { - return slice.data(); - } - - friend const T* end(const SkArraySlice& 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(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 - T* startRead() { - this->startRead(); - return this->read(); - } - - template - 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 - SkArraySlice readArray(int count) { - size_t size = count * sizeof(T); - const T* base = (const T*)this->ensureAtLeast(size); - SkArraySlice result = SkArraySlice{base, (uint32_t)count}; - fCursor += size; - return result; - } - - size_t endRead() {return size();} - - sk_sp readEntireData() { - size_t* size = this->startRead(); - if (size == nullptr) { - return nullptr; - } - const uint8_t* data = this->readArray(*size).data(); - if (size == nullptr || data == nullptr) { - this->endRead(); - return sk_sp(nullptr); - } - auto result = SkData::MakeWithCopy(data, *size); - this->endRead(); - return result; - } - - void startWrite() { - fCursor = 0; - } - - template - void startWrite(const T& data) { - this->startWrite(); - this->write(data); - } - - template - T* startEmplace(Args&&... args) { - this->startWrite(); - return this->emplace(std::forward(args)...); - } - - template - T* emplace(Args&&... args) { - T* result = new (&fBuffer[fCursor]) T{std::forward(args)...}; - fCursor += sizeof(T); - return result; - } - - template - 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 - 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 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 fBuffer{new uint8_t[kBufferSize]}; - std::shared_ptr 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
((int)fDescMap.size()); - for (auto& i : fDescMap) { - auto accum = &i.second; - transport->emplace( - accum->typefaceID, accum->desc->getLength(), accum->glyphIDs->count()); - transport->writeDescriptor(*accum->desc); - accum->glyphIDs->foreach([&](SkPackedGlyphID id) { - transport->write(id); - }); - } - } - - static void WriteDataToTransport( - Transport* in, Transport* out, SkRemoteGlyphCacheRenderer* rc) { - auto perHeader = [out](Header* header) { - out->write
(*header); - }; - - struct { - SkScalerContext* scaler{nullptr}; - } strikeData; - - auto perStrike = [out, &strikeData, rc](StrikeSpec* spec, SkDescriptor* desc) { - out->write(*spec); - out->writeDescriptor(*desc); - SkScalerContextRecDescriptor recDesc{*desc}; - strikeData.scaler = rc->generateScalerContext(recDesc, spec->typefaceID); - SkPaint::FontMetrics fontMetrics; - strikeData.scaler->getFontMetrics(&fontMetrics); - out->write(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(glyph); - - if (imageSize > 0) { - glyph.fImage = out->allocateArray(imageSize); - strikeData.scaler->getImage(glyph); - } - }; - - ReadSpecFromTransport(in, perHeader, perStrike, perGlyph); - } - - template - static void ReadSpecFromTransport(Transport* transport, - PerHeader perHeader, - PerStrike perStrike, - PerGlyph perGlyph) { - auto header = transport->read(); - perHeader(header); - for (int i = 0; i < header->strikeCount; i++) { - auto strike = transport->read(); - auto desc = transport->readDescriptor(); - //desc->assertChecksum(); - perStrike(strike, desc); - auto glyphIDs = transport->readArray(strike->glyphCount); - for (auto glyphID : glyphIDs) { - perGlyph(glyphID); - } - } - } - - template - void readDataFromTransport( - Transport* transport, PerStrike perStrike, PerGlyph perGlyph, FinishStrike finishStrike) { - auto header = transport->read
(); - for (int i = 0; i < header->strikeCount; i++) { - auto strike = transport->read(); - auto desc = transport->readDescriptor(); - auto fontMetrics = transport->read(); - perStrike(strike, desc, fontMetrics); - for (int j = 0; j < strike->glyphCount; j++) { - auto glyph = transport->read(); - SkArraySlice image = SkArraySlice{}; - auto imageSize = glyph->computeImageSize(); - if (imageSize != 0) { - image = transport->readArray(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 glyphIDs; - std::unique_ptr> 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>(); - 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; - DescMap fDescMap{16, DescHash(), DescEq()}; - std::vector> fUniqueDescriptors; - - std::vector fTempGlyphs; - std::vector 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(); - *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(); - *glyph = op->glyph; - auto imageSize = op->glyph.computeImageSize(); - glyph->fPathData = nullptr; - if (imageSize > 0) { - auto image = fTransport->readArray(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(); - auto rawPath = fTransport->readArray(op->pathSize); - path->readFromMemory(rawPath.data(), rawPath.size()); - fTransport->endRead(); - } - -private: - Op* startOpWrite(OpCode opCode, const SkTypefaceProxy& tf, - const SkScalerContextRec& rec) { - return fTransport->startEmplace(opCode, tf.fontID(), rec); - } - - Transport* const fTransport; -}; - -static void prepopulate_cache( - Transport* transport, - SkRemoteGlyphCacheGPU* cache, - sk_sp pic, - TextBlobFilterCanvas* filter) { - - pic->playback(filter); - - transport->startEmplace(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 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 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 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(&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 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(); - 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(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(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 { -- cgit v1.2.3