aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/core.gni2
-rw-r--r--src/core/SkRemoteGlyphCache.cpp92
-rw-r--r--src/core/SkRemoteGlyphCache.h99
-rw-r--r--src/core/SkTypeface_remote.h4
-rw-r--r--tools/remote_demo.cpp163
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 {