Add cache for handling of contexts.
Added scaler context cache on the Renderer side that maps descriptors to scaler contexts. Added preliminary timing code. Remove unused print statements. BUG=skia:7515 Change-Id: I156ba656aab113e0ceae0c2ea0f9f3c1d3d61d6a Reviewed-on: https://skia-review.googlesource.com/99540 Reviewed-by: Mike Klein <mtklein@chromium.org> Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
5d4dd8bef5
commit
4f505f9c77
@ -120,7 +120,7 @@ protected:
|
|||||||
}
|
}
|
||||||
void onFilterRec(SkScalerContextRec* rec) const override {
|
void onFilterRec(SkScalerContextRec* rec) const override {
|
||||||
// Add all the device information here.
|
// Add all the device information here.
|
||||||
rec->fPost2x2[0][0] = 0.5f;
|
//rec->fPost2x2[0][0] = 0.5f;
|
||||||
|
|
||||||
// This would be the best place to run the host SkTypeface_* onFilterRec.
|
// This would be the best place to run the host SkTypeface_* onFilterRec.
|
||||||
// Can we move onFilterRec to the FongMgr, that way we don't need to cross the boundary to
|
// Can we move onFilterRec to the FongMgr, that way we don't need to cross the boundary to
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "SkTypeface.h"
|
#include "SkTypeface.h"
|
||||||
#include "SkWriteBuffer.h"
|
#include "SkWriteBuffer.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -41,9 +42,46 @@ struct WireTypeface {
|
|||||||
bool is_fixed;
|
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 {
|
class Op {
|
||||||
public:
|
public:
|
||||||
Op() {}
|
explicit Op(const SkScalerContextRec& rec) : descriptor{rec} {}
|
||||||
int32_t op;
|
int32_t op;
|
||||||
SkFontID typeface_id;
|
SkFontID typeface_id;
|
||||||
union {
|
union {
|
||||||
@ -57,15 +95,7 @@ public:
|
|||||||
size_t pathSize;
|
size_t pathSize;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// The system only passes descriptors without effects. That is why it uses a fixed size
|
ScalerContextRecDescriptor descriptor;
|
||||||
// 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;
|
|
||||||
} descriptor;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RemoteScalerContextPassThread : public SkRemoteScalerContext {
|
class RemoteScalerContextPassThread : public SkRemoteScalerContext {
|
||||||
@ -78,8 +108,7 @@ public:
|
|||||||
SkPaint::FontMetrics* metrics) override {
|
SkPaint::FontMetrics* metrics) override {
|
||||||
Op* op = this->createOp(0, tf, rec);
|
Op* op = this->createOp(0, tf, rec);
|
||||||
write(fWriteFd, fBuffer, sizeof(*op));
|
write(fWriteFd, fBuffer, sizeof(*op));
|
||||||
ssize_t readSize = read(fReadFd, fBuffer, sizeof(fBuffer));
|
read(fReadFd, fBuffer, sizeof(fBuffer));
|
||||||
std::cerr << "gpu - op 0 read size: " << readSize << std::endl;
|
|
||||||
memcpy(metrics, &op->fontMetrics, sizeof(op->fontMetrics));
|
memcpy(metrics, &op->fontMetrics, sizeof(op->fontMetrics));
|
||||||
op->~Op();
|
op->~Op();
|
||||||
}
|
}
|
||||||
@ -104,7 +133,6 @@ public:
|
|||||||
read(fReadFd, fBuffer, sizeof(fBuffer));
|
read(fReadFd, fBuffer, sizeof(fBuffer));
|
||||||
//memcpy((SkGlyph *)&glyph, &op->glyph, sizeof(op->glyph));
|
//memcpy((SkGlyph *)&glyph, &op->glyph, sizeof(op->glyph));
|
||||||
//((SkGlyph*)&glyph)->fImage = oldImage;
|
//((SkGlyph*)&glyph)->fImage = oldImage;
|
||||||
std::cerr << "rb: " << glyph.rowBytes() << " h: " << glyph.fHeight << std::endl;
|
|
||||||
memcpy(glyph.fImage, fBuffer + sizeof(Op), glyph.rowBytes() * glyph.fHeight);
|
memcpy(glyph.fImage, fBuffer + sizeof(Op), glyph.rowBytes() * glyph.fHeight);
|
||||||
op->~Op();
|
op->~Op();
|
||||||
}
|
}
|
||||||
@ -123,15 +151,10 @@ public:
|
|||||||
private:
|
private:
|
||||||
Op* createOp(uint32_t opID, const SkTypefaceProxy& tf,
|
Op* createOp(uint32_t opID, const SkTypefaceProxy& tf,
|
||||||
const SkScalerContextRec& rec) {
|
const SkScalerContextRec& rec) {
|
||||||
Op* op = new (fBuffer) Op();
|
Op* op = new (fBuffer) Op(rec);
|
||||||
op->op = opID;
|
op->op = opID;
|
||||||
op->typeface_id = tf.fontID();
|
op->typeface_id = tf.fontID();
|
||||||
|
|
||||||
SkASSERT(SkScalerContext::CheckBufferSizeForRec(
|
|
||||||
rec, SkScalerContextEffects{}, sizeof(op->descriptor)));
|
|
||||||
|
|
||||||
SkScalerContext::DescriptorBufferGiveRec(rec, &op->descriptor);
|
|
||||||
|
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,10 +165,8 @@ private:
|
|||||||
|
|
||||||
static sk_sp<SkTypeface> gpu_from_renderer_by_ID(const void* buf, size_t len, void* ctx) {
|
static sk_sp<SkTypeface> gpu_from_renderer_by_ID(const void* buf, size_t len, void* ctx) {
|
||||||
WireTypeface wire;
|
WireTypeface wire;
|
||||||
std::cerr << "gpu - typeface from rendere size: " << len << std::endl;
|
|
||||||
if (len >= sizeof(wire)) {
|
if (len >= sizeof(wire)) {
|
||||||
memcpy(&wire, buf, sizeof(wire));
|
memcpy(&wire, buf, sizeof(wire));
|
||||||
std::cerr << wire.thread_id << " " << wire.typeface_id << std::endl;
|
|
||||||
return sk_sp<SkTypeface>(
|
return sk_sp<SkTypeface>(
|
||||||
new SkTypefaceProxy(
|
new SkTypefaceProxy(
|
||||||
wire.typeface_id,
|
wire.typeface_id,
|
||||||
@ -160,18 +181,33 @@ static sk_sp<SkTypeface> gpu_from_renderer_by_ID(const void* buf, size_t len, vo
|
|||||||
std::unordered_map<SkFontID, sk_sp<SkTypeface>> gTypefaceMap;
|
std::unordered_map<SkFontID, sk_sp<SkTypeface>> gTypefaceMap;
|
||||||
|
|
||||||
|
|
||||||
static std::unique_ptr<SkScalerContext> scaler_context_from_op(Op* op) {
|
// 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());
|
||||||
|
|
||||||
auto i = gTypefaceMap.find(op->typeface_id);
|
static SkScalerContext* scaler_context_from_op(Op* op) {
|
||||||
if (i == gTypefaceMap.end()) {
|
|
||||||
std::cerr << "bad typeface id: " << op->typeface_id << std::endl;
|
SkScalerContext* sc;
|
||||||
SK_ABORT("unknown type face");
|
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));
|
||||||
}
|
}
|
||||||
auto tf = i->second;
|
|
||||||
std::cerr << "ops - got typeface: " << i->first << " , " << tf.get() << std::endl;
|
|
||||||
SkScalerContextEffects effects;
|
|
||||||
auto sc = tf->createScalerContext(effects, (SkDescriptor *)&op->descriptor, false);
|
|
||||||
std::cerr << "ops - created sc " << std::endl;
|
|
||||||
return sc;
|
return sc;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -185,18 +221,43 @@ static sk_sp<SkData> renderer_to_gpu_by_ID(SkTypeface* tf, void* ctx) {
|
|||||||
};
|
};
|
||||||
auto i = gTypefaceMap.find(SkTypeface::UniqueID(tf));
|
auto i = gTypefaceMap.find(SkTypeface::UniqueID(tf));
|
||||||
if (i == gTypefaceMap.end()) {
|
if (i == gTypefaceMap.end()) {
|
||||||
std::cerr << "font id table - inserting: " << SkTypeface::UniqueID(tf) << std::endl;
|
|
||||||
gTypefaceMap.insert({SkTypeface::UniqueID(tf), sk_ref_sp(tf)});
|
gTypefaceMap.insert({SkTypeface::UniqueID(tf), sk_ref_sp(tf)});
|
||||||
}
|
}
|
||||||
return SkData::MakeWithCopy(&wire, sizeof(wire));
|
return SkData::MakeWithCopy(&wire, sizeof(wire));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void final_draw(std::string outFilename,
|
||||||
|
SkDeserialProcs* procs,
|
||||||
|
uint8_t* picData,
|
||||||
|
size_t picSize) {
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
auto pic = SkPicture::MakeFromData(picData, picSize, procs);
|
||||||
|
|
||||||
|
auto cullRect = pic->cullRect();
|
||||||
|
auto r = cullRect.round();
|
||||||
|
auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
|
||||||
|
|
||||||
|
auto c = s->getCanvas();
|
||||||
|
c->drawPicture(pic);
|
||||||
|
|
||||||
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
std::chrono::duration<double> elapsed_seconds = end-start;
|
||||||
|
|
||||||
|
std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
|
||||||
|
|
||||||
|
auto i = s->makeImageSnapshot();
|
||||||
|
auto data = i->encodeToData();
|
||||||
|
SkFILEWStream f(outFilename.c_str());
|
||||||
|
f.write(data->data(), data->size());
|
||||||
|
}
|
||||||
|
|
||||||
static void gpu(int readFd, int writeFd) {
|
static void gpu(int readFd, int writeFd) {
|
||||||
|
|
||||||
size_t picSize = 0;
|
size_t picSize = 0;
|
||||||
read(readFd, &picSize, sizeof(picSize));
|
read(readFd, &picSize, sizeof(picSize));
|
||||||
|
|
||||||
std::cerr << "gpu - reading pic size: " << picSize << std::endl;
|
|
||||||
static constexpr size_t kBufferSize = 10 * 1024 * kPageSize;
|
static constexpr size_t kBufferSize = 10 * 1024 * kPageSize;
|
||||||
std::unique_ptr<uint8_t[]> picBuffer{new uint8_t[kBufferSize]};
|
std::unique_ptr<uint8_t[]> picBuffer{new uint8_t[kBufferSize]};
|
||||||
|
|
||||||
@ -208,15 +269,15 @@ static void gpu(int readFd, int writeFd) {
|
|||||||
err(1, "gpu pic read error %d", errno);
|
err(1, "gpu pic read error %d", errno);
|
||||||
}
|
}
|
||||||
readSoFar += readSize;
|
readSoFar += readSize;
|
||||||
//std::cerr << "gpu - recieved so far: " << readSoFar << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "gpu - Receiving picture" << std::endl;
|
|
||||||
SkDeserialProcs procs;
|
SkDeserialProcs procs;
|
||||||
std::unique_ptr<SkRemoteScalerContext> rsc{
|
std::unique_ptr<SkRemoteScalerContext> rsc{
|
||||||
new RemoteScalerContextPassThread{readFd, writeFd}};
|
new RemoteScalerContextPassThread{readFd, writeFd}};
|
||||||
procs.fTypefaceProc = gpu_from_renderer_by_ID;
|
procs.fTypefaceProc = gpu_from_renderer_by_ID;
|
||||||
procs.fTypefaceCtx = rsc.get();
|
procs.fTypefaceCtx = rsc.get();
|
||||||
|
final_draw("test.png", &procs, picBuffer.get(), picSize);
|
||||||
|
/*
|
||||||
auto pic = SkPicture::MakeFromData(picBuffer.get(), picSize, &procs);
|
auto pic = SkPicture::MakeFromData(picBuffer.get(), picSize, &procs);
|
||||||
|
|
||||||
auto cullRect = pic->cullRect();
|
auto cullRect = pic->cullRect();
|
||||||
@ -226,40 +287,48 @@ static void gpu(int readFd, int writeFd) {
|
|||||||
auto c = s->getCanvas();
|
auto c = s->getCanvas();
|
||||||
c->drawPicture(pic);
|
c->drawPicture(pic);
|
||||||
|
|
||||||
std::cerr << "gpu - output picture" << std::endl;
|
|
||||||
auto i = s->makeImageSnapshot();
|
auto i = s->makeImageSnapshot();
|
||||||
auto data = i->encodeToData();
|
auto data = i->encodeToData();
|
||||||
SkFILEWStream f("test.png");
|
SkFILEWStream f("test.png");
|
||||||
f.write(data->data(), data->size());
|
f.write(data->data(), data->size());
|
||||||
|
*/
|
||||||
close(writeFd);
|
close(writeFd);
|
||||||
close(readFd);
|
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 prefix{"skps/"};
|
||||||
std::string fileName{prefix + skpName + ".skp"};
|
std::string fileName{prefix + skpName + ".skp"};
|
||||||
std::cerr << "Reading skp: " << fileName << std::endl;
|
|
||||||
|
|
||||||
auto skp = SkData::MakeFromFileName(fileName.c_str());
|
auto skp = SkData::MakeFromFileName(fileName.c_str());
|
||||||
auto pic = SkPicture::MakeFromData(skp.get());
|
auto pic = SkPicture::MakeFromData(skp.get());
|
||||||
|
|
||||||
|
bool toGpu = true;
|
||||||
|
|
||||||
SkSerialProcs procs;
|
SkSerialProcs procs;
|
||||||
procs.fTypefaceProc = renderer_to_gpu_by_ID;
|
if (toGpu) {
|
||||||
|
procs.fTypefaceProc = renderer_to_gpu_by_ID;
|
||||||
|
}
|
||||||
|
|
||||||
auto stream = pic->serialize(&procs);
|
auto stream = pic->serialize(&procs);
|
||||||
|
|
||||||
std::cerr << "stream is " << stream->size() << " bytes long" << std::endl;
|
std::cerr << "stream is " << stream->size() << " bytes long" << std::endl;
|
||||||
|
|
||||||
std::cerr << "render - Sending stream." << std::endl;
|
|
||||||
|
|
||||||
size_t picSize = stream->size();
|
size_t picSize = stream->size();
|
||||||
uint8_t* picBuffer = (uint8_t*) stream->data();
|
uint8_t* picBuffer = (uint8_t*) stream->data();
|
||||||
|
|
||||||
|
if (!toGpu) {
|
||||||
|
final_draw("test-direct.png", nullptr, picBuffer, picSize);
|
||||||
|
close(writeFd);
|
||||||
|
close(readFd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
write(writeFd, &picSize, sizeof(picSize));
|
write(writeFd, &picSize, sizeof(picSize));
|
||||||
|
|
||||||
size_t writeSoFar = 0;
|
size_t writeSoFar = 0;
|
||||||
while (writeSoFar < picSize) {
|
while (writeSoFar < picSize) {
|
||||||
ssize_t writeSize = write(writeFd, &picBuffer[writeSoFar], picSize - writeSoFar);
|
ssize_t writeSize = write(writeFd, &picBuffer[writeSoFar], picSize - writeSoFar);
|
||||||
std::cerr << "renderer - bytes written: " << writeSize << std::endl;
|
|
||||||
if (writeSize <= 0) {
|
if (writeSize <= 0) {
|
||||||
if (writeSize == 0) {
|
if (writeSize == 0) {
|
||||||
std::cerr << "Exit" << std::endl;
|
std::cerr << "Exit" << std::endl;
|
||||||
@ -280,7 +349,6 @@ static int renderer(const std::string& skpName, int readFd, int writeFd) {
|
|||||||
ssize_t size = read(readFd, glyphBuffer.get(), sizeof(*op));
|
ssize_t size = read(readFd, glyphBuffer.get(), sizeof(*op));
|
||||||
if (size <= 0) { std::cerr << "Exit op loop" << std::endl; break;}
|
if (size <= 0) { std::cerr << "Exit op loop" << std::endl; break;}
|
||||||
size_t writeSize = sizeof(*op);
|
size_t writeSize = sizeof(*op);
|
||||||
std::cerr << "op: " << op << " op->op: " << op->op << std::endl;
|
|
||||||
|
|
||||||
auto sc = scaler_context_from_op(op);
|
auto sc = scaler_context_from_op(op);
|
||||||
switch (op->op) {
|
switch (op->op) {
|
||||||
@ -310,9 +378,7 @@ static int renderer(const std::string& skpName, int readFd, int writeFd) {
|
|||||||
default:
|
default:
|
||||||
SkASSERT("Bad op");
|
SkASSERT("Bad op");
|
||||||
}
|
}
|
||||||
std::cerr << "ops - writing" << std::endl;
|
write(writeFd, glyphBuffer.get(), writeSize);
|
||||||
ssize_t written = write(writeFd, glyphBuffer.get(), writeSize);
|
|
||||||
std::cerr << " opss - writing : " << writeSize << " written: " << written << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(readFd);
|
close(readFd);
|
||||||
@ -353,23 +419,21 @@ int main(int argc, char** argv) {
|
|||||||
close(gpu_to_render[kWrite]);
|
close(gpu_to_render[kWrite]);
|
||||||
std::cerr << "Starting renderer" << std::endl;
|
std::cerr << "Starting renderer" << std::endl;
|
||||||
printf("skp: %s\n", skpName.c_str());
|
printf("skp: %s\n", skpName.c_str());
|
||||||
renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
|
//renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
|
||||||
//gpu(gpu_to_render[kRead], render_to_gpu[kWrite]);
|
gpu(gpu_to_render[kRead], render_to_gpu[kWrite]);
|
||||||
} else {
|
} else {
|
||||||
// The parent - GPU
|
// The parent - GPU
|
||||||
// Close unused pipe ends.
|
// Close unused pipe ends.
|
||||||
std::cerr << "child id - " << child << std::endl;
|
std::cerr << "child id - " << child << std::endl;
|
||||||
close(gpu_to_render[kRead]);
|
close(gpu_to_render[kRead]);
|
||||||
close(render_to_gpu[kWrite]);
|
close(render_to_gpu[kWrite]);
|
||||||
gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
|
//gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
|
||||||
//renderer(skpName, render_to_gpu[kRead], gpu_to_render[kWrite]);
|
renderer(skpName, render_to_gpu[kRead], gpu_to_render[kWrite]);
|
||||||
|
|
||||||
|
|
||||||
std::cerr << "Waiting for renderer." << std::endl;
|
std::cerr << "Waiting for renderer." << std::endl;
|
||||||
waitpid(child, nullptr, 0);
|
waitpid(child, nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user