diff options
-rw-r--r-- | gn/core.gni | 2 | ||||
-rw-r--r-- | src/core/SkRemoteGlyphCache.cpp | 92 | ||||
-rw-r--r-- | src/core/SkRemoteGlyphCache.h | 99 | ||||
-rw-r--r-- | src/core/SkTypeface_remote.h | 4 | ||||
-rw-r--r-- | tools/remote_demo.cpp | 163 |
5 files changed, 214 insertions, 146 deletions
diff --git a/gn/core.gni b/gn/core.gni index d94bda4c4c..6cc8d14dff 100644 --- a/gn/core.gni +++ b/gn/core.gni @@ -255,6 +255,8 @@ skia_core_sources = [ "$_src/core/SkRegion.cpp", "$_src/core/SkRegionPriv.h", "$_src/core/SkRegion_path.cpp", + "$_src/core/SkRemoteGlyphCache.h", + "$_src/core/SkRemoteGlyphCache.cpp", "$_src/core/SkResourceCache.cpp", "$_src/core/SkRRect.cpp", "$_src/core/SkRTree.h", diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp new file mode 100644 index 0000000000..a2044ff13b --- /dev/null +++ b/src/core/SkRemoteGlyphCache.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkRemoteGlyphCache.h" + +struct WireTypeface { + // std::thread::id thread_id; // TODO:need to figure a good solution + SkFontID typeface_id; + SkFontStyle style; + bool is_fixed; +}; + +void SkRemoteGlyphCacheRenderer::prepareSerializeProcs(SkSerialProcs* procs) { + auto encode = [](SkTypeface* tf, void* ctx) { + return reinterpret_cast<SkRemoteGlyphCacheRenderer*>(ctx)->encodeTypeface(tf); + }; + procs->fTypefaceProc = encode; + procs->fTypefaceCtx = this; +} + +SkScalerContext* SkRemoteGlyphCacheRenderer::generateScalerContext( + const SkScalerContextRecDescriptor& desc, SkFontID typefaceId) +{ + auto scaler = fScalerContextMap.find(desc); + if (scaler == nullptr) { + auto typefaceIter = fTypefaceMap.find(typefaceId); + if (typefaceIter == nullptr) { + // TODO: handle this with some future fallback strategy. + SK_ABORT("unknown type face"); + // Should never happen + return nullptr; + } + auto tf = typefaceIter->get(); + SkScalerContextEffects effects; + auto mapSc = tf->createScalerContext(effects, &desc.desc(), false); + scaler = fScalerContextMap.set(desc, std::move(mapSc)); + } + return scaler->get(); +} + +sk_sp<SkData> SkRemoteGlyphCacheRenderer::encodeTypeface(SkTypeface* tf) { + WireTypeface wire = { + SkTypeface::UniqueID(tf), + tf->fontStyle(), + tf->isFixedPitch() + }; + auto typeFace = fTypefaceMap.find(SkTypeface::UniqueID(tf)); + if (typeFace == nullptr) { + fTypefaceMap.set(SkTypeface::UniqueID(tf), sk_ref_sp(tf)); + } + // Can this be done with no copy? + return SkData::MakeWithCopy(&wire, sizeof(wire)); +} + +SkRemoteGlyphCacheGPU::SkRemoteGlyphCacheGPU( + std::unique_ptr<SkRemoteScalerContext> remoteScalerContext) + : fRemoteScalerContext{std::move(remoteScalerContext)} { } + +void SkRemoteGlyphCacheGPU::prepareDeserializeProcs(SkDeserialProcs* procs) { + auto decode = [](const void* buf, size_t len, void* ctx) { + return reinterpret_cast<SkRemoteGlyphCacheGPU*>(ctx)->decodeTypeface(buf, len); + }; + procs->fTypefaceProc = decode; + procs->fTypefaceCtx = this; +} + +sk_sp<SkTypeface> SkRemoteGlyphCacheGPU::decodeTypeface(const void* buf, size_t len) { + WireTypeface wire; + if (len < sizeof(wire)) { + SK_ABORT("Incomplete transfer"); + return nullptr; + } + memcpy(&wire, buf, sizeof(wire)); + auto typeFace = fMapIdToTypeface.find(wire.typeface_id); + if (typeFace == nullptr) { + + auto newTypeface = sk_make_sp<SkTypefaceProxy>( + wire.typeface_id, + wire.style, + wire.is_fixed, + fRemoteScalerContext.get()); + + typeFace = fMapIdToTypeface.set(wire.typeface_id, newTypeface); + } + return *typeFace; +} + + diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h new file mode 100644 index 0000000000..3634ad0871 --- /dev/null +++ b/src/core/SkRemoteGlyphCache.h @@ -0,0 +1,99 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRemoteGlyphCache_DEFINED +#define SkRemoteGlyphCache_DEFINED + +#include <memory> +#include "SkData.h" +#include "SkDescriptor.h" +#include "SkSerialProcs.h" +#include "SkTHash.h" +#include "SkTypeface.h" +#include "SkTypeface_remote.h" + +class SkScalerContextRecDescriptor { +public: + SkScalerContextRecDescriptor() {} + explicit SkScalerContextRecDescriptor(const SkScalerContextRec& rec) { + auto desc = reinterpret_cast<SkDescriptor*>(&fDescriptor); + desc->init(); + desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + SkASSERT(sizeof(fDescriptor) == desc->getLength()); + } + + SkScalerContextRecDescriptor& operator=(const SkScalerContextRecDescriptor& rhs) { + std::memcpy(&fDescriptor, &rhs.fDescriptor, rhs.desc().getLength()); + return *this; + } + + const SkDescriptor& desc() const { + return *reinterpret_cast<const SkDescriptor*>(&fDescriptor); + } + + struct Hash { + uint32_t operator()(SkScalerContextRecDescriptor const& s) const { + return s.desc().getChecksum(); + } + }; + + friend bool operator==(const SkScalerContextRecDescriptor& lhs, + const SkScalerContextRecDescriptor& rhs ) { + return lhs.desc() == rhs.desc(); + } + +private: + // The system only passes descriptors without effects. That is why it uses a fixed size + // descriptor. storageFor is needed because some of the constructors below are private. + template <typename T> + using storageFor = typename std::aligned_storage<sizeof(T), alignof(T)>::type; + struct { + storageFor<SkDescriptor> dummy1; + storageFor<SkDescriptor::Entry> dummy2; + storageFor<SkScalerContextRec> dummy3; + } fDescriptor; +}; + +class SkRemoteGlyphCacheRenderer { +public: + void prepareSerializeProcs(SkSerialProcs* procs); + + SkScalerContext* generateScalerContext( + const SkScalerContextRecDescriptor& desc, SkFontID typefaceId); + +private: + + sk_sp<SkData> encodeTypeface(SkTypeface* tf); + + SkTHashMap<SkFontID, sk_sp<SkTypeface>> fTypefaceMap; + + using DescriptorToContextMap = + SkTHashMap< + SkScalerContextRecDescriptor, + std::unique_ptr<SkScalerContext>, + SkScalerContextRecDescriptor::Hash>; + + DescriptorToContextMap fScalerContextMap; +}; + +class SkRemoteGlyphCacheGPU { +public: + explicit SkRemoteGlyphCacheGPU(std::unique_ptr<SkRemoteScalerContext> remoteScalerContext); + + void prepareDeserializeProcs(SkDeserialProcs* procs); + +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; + +}; + + +#endif // SkRemoteGlyphCache_DEFINED diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h index 33021547cd..8f47434e18 100644 --- a/src/core/SkTypeface_remote.h +++ b/src/core/SkTypeface_remote.h @@ -71,13 +71,11 @@ class SkTypefaceProxy : public SkTypeface { public: SkTypefaceProxy( SkFontID fontId, - std::thread::id threadId, const SkFontStyle& style, bool isFixed, SkRemoteScalerContext* rsc) : INHERITED{style, false} , fFontId{fontId} - , fThreadId{threadId} , fRsc{rsc} { } SkFontID fontID() const {return fFontId;} protected: @@ -150,7 +148,7 @@ protected: private: const SkFontID fFontId; - const std::thread::id fThreadId; + // const std::thread::id fThreadId; // TODO: figure out a good solutions for this. SkRemoteScalerContext* const fRsc; typedef SkTypeface INHERITED; diff --git a/tools/remote_demo.cpp b/tools/remote_demo.cpp index 59ca1399b5..8549c63e75 100644 --- a/tools/remote_demo.cpp +++ b/tools/remote_demo.cpp @@ -32,53 +32,11 @@ #include <unistd.h> #include <sys/mman.h> #include "SkTypeface_remote.h" +#include "SkRemoteGlyphCache.h" +#include "SkMakeUnique.h" static const size_t kPageSize = 4096; -struct WireTypeface { - std::thread::id thread_id; - SkFontID typeface_id; - SkFontStyle style; - bool is_fixed; -}; - -class ScalerContextRecDescriptor { -public: - explicit ScalerContextRecDescriptor(const SkScalerContextRec& rec) { - auto desc = reinterpret_cast<SkDescriptor*>(&fDescriptor); - desc->init(); - desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - } - - const SkDescriptor& desc() const { - return *reinterpret_cast<const SkDescriptor*>(&fDescriptor); - } - - struct Hash { - size_t operator()(ScalerContextRecDescriptor const& s) const { - return SkOpts::hash_fn(&s.desc(), sizeof(s), 0); - } - }; - - struct Equal { - bool operator()( const ScalerContextRecDescriptor& lhs, - const ScalerContextRecDescriptor& rhs ) const { - return lhs.desc() == rhs.desc(); - } - }; - -private: - // The system only passes descriptors without effects. That is why it uses a fixed size - // descriptor. storageFor is needed because some of the constructors below are private. - template <typename T> - using storageFor = typename std::aligned_storage<sizeof(T), alignof(T)>::type; - struct { - storageFor<SkDescriptor> dummy1; - storageFor<SkDescriptor::Entry> dummy2; - storageFor<SkScalerContextRec> dummy3; - } fDescriptor; -}; - class Op { public: explicit Op(const SkScalerContextRec& rec) : descriptor{rec} {} @@ -95,12 +53,12 @@ public: size_t pathSize; }; }; - ScalerContextRecDescriptor descriptor; + SkScalerContextRecDescriptor descriptor; }; -class RemoteScalerContextPassThread : public SkRemoteScalerContext { +class RemoteScalerContextFIFO : public SkRemoteScalerContext { public: - explicit RemoteScalerContextPassThread(int readFd, int writeFd) + explicit RemoteScalerContextFIFO(int readFd, int writeFd) : fReadFd{readFd} , fWriteFd{writeFd} { } void generateFontMetrics(const SkTypefaceProxy& tf, @@ -157,81 +115,10 @@ private: } const int fReadFd, - fWriteFd; + fWriteFd; uint8_t fBuffer[1024 * kPageSize]; }; -static sk_sp<SkTypeface> gpu_from_renderer_by_ID(const void* buf, size_t len, void* ctx) { - static std::unordered_map<SkFontID, sk_sp<SkTypefaceProxy>> mapIdToTypeface; - WireTypeface wire; - if (len >= sizeof(wire)) { - memcpy(&wire, buf, sizeof(wire)); - auto i = mapIdToTypeface.find(wire.typeface_id); - if (i == mapIdToTypeface.end()) { - - auto newTypeface = sk_make_sp<SkTypefaceProxy>( - wire.typeface_id, - wire.thread_id, - wire.style, - wire.is_fixed, - (SkRemoteScalerContext*)ctx); - - i = mapIdToTypeface.emplace_hint(i, wire.typeface_id, newTypeface); - } - return i->second; - } - SK_ABORT("Bad data"); - return nullptr; -} - -std::unordered_map<SkFontID, sk_sp<SkTypeface>> gTypefaceMap; - - -// TODO: Figure out how to manage the entries. -std::unordered_map<ScalerContextRecDescriptor, - std::unique_ptr<SkScalerContext>, - ScalerContextRecDescriptor::Hash, - ScalerContextRecDescriptor::Equal> - gScalerContextMap(16, - ScalerContextRecDescriptor::Hash(), - ScalerContextRecDescriptor::Equal()); - -static SkScalerContext* scaler_context_from_op(Op* op) { - - SkScalerContext* sc; - auto j = gScalerContextMap.find(op->descriptor); - if (j != gScalerContextMap.end()) { - sc = j->second.get(); - } else { - auto i = gTypefaceMap.find(op->typeface_id); - if (i == gTypefaceMap.end()) { - std::cerr << "bad typeface id: " << op->typeface_id << std::endl; - SK_ABORT("unknown type face"); - } - auto tf = i->second; - SkScalerContextEffects effects; - auto mapSc = tf->createScalerContext(effects, &op->descriptor.desc(), false); - sc = mapSc.get(); - gScalerContextMap.emplace_hint(j, op->descriptor, std::move(mapSc)); - } - return sc; - -} - -static sk_sp<SkData> renderer_to_gpu_by_ID(SkTypeface* tf, void* ctx) { - WireTypeface wire = { - std::this_thread::get_id(), - SkTypeface::UniqueID(tf), - tf->fontStyle(), - tf->isFixedPitch() - }; - auto i = gTypefaceMap.find(SkTypeface::UniqueID(tf)); - if (i == gTypefaceMap.end()) { - gTypefaceMap.insert({SkTypeface::UniqueID(tf), sk_ref_sp(tf)}); - } - return SkData::MakeWithCopy(&wire, sizeof(wire)); -} - static void final_draw(std::string outFilename, SkDeserialProcs* procs, uint8_t* picData, @@ -283,32 +170,22 @@ static void gpu(int readFd, int writeFd) { readSoFar += readSize; } - SkDeserialProcs procs; - std::unique_ptr<SkRemoteScalerContext> rsc{ - new RemoteScalerContextPassThread{readFd, writeFd}}; - procs.fTypefaceProc = gpu_from_renderer_by_ID; - procs.fTypefaceCtx = rsc.get(); - final_draw("test.png", &procs, picBuffer.get(), picSize); - /* - auto pic = SkPicture::MakeFromData(picBuffer.get(), picSize, &procs); + SkRemoteGlyphCacheGPU rc{ + skstd::make_unique<RemoteScalerContextFIFO>(readFd, writeFd) + }; - auto cullRect = pic->cullRect(); - auto r = cullRect.round(); - auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height()); + SkDeserialProcs procs; + rc.prepareDeserializeProcs(&procs); - auto c = s->getCanvas(); - c->drawPicture(pic); + final_draw("test.png", &procs, picBuffer.get(), picSize); - auto i = s->makeImageSnapshot(); - auto data = i->encodeToData(); - SkFILEWStream f("test.png"); - f.write(data->data(), data->size()); - */ close(writeFd); close(readFd); } -static int renderer(const std::string& skpName, int readFd, int writeFd) { +static int renderer( + const std::string& skpName, int readFd, int writeFd) +{ std::string prefix{"skps/"}; std::string fileName{prefix + skpName + ".skp"}; @@ -317,9 +194,10 @@ static int renderer(const std::string& skpName, int readFd, int writeFd) { bool toGpu = true; + SkRemoteGlyphCacheRenderer rc; SkSerialProcs procs; if (toGpu) { - procs.fTypefaceProc = renderer_to_gpu_by_ID; + rc.prepareSerializeProcs(&procs); } auto stream = pic->serialize(&procs); @@ -362,7 +240,7 @@ static int renderer(const std::string& skpName, int readFd, int writeFd) { if (size <= 0) { std::cerr << "Exit op loop" << std::endl; break;} size_t writeSize = sizeof(*op); - auto sc = scaler_context_from_op(op); + auto sc = rc.generateScalerContext(op->descriptor, op->typeface_id); switch (op->op) { case 0: { sc->getFontMetrics(&op->fontMetrics); @@ -442,10 +320,9 @@ int main(int argc, char** argv) { SkGraphics::Init(); if (child == 0) { - start_render(skpName, render_to_gpu, gpu_to_render); - } else { start_gpu(render_to_gpu, gpu_to_render); - std::cerr << "Waiting for renderer." << std::endl; + } else { + start_render(skpName, render_to_gpu, gpu_to_render); waitpid(child, nullptr, 0); } } else { |