blob: 59ca1399b530272804110cd84dc11b3ba56be651 [file] [log] [blame]
Mike Kleina8a51ce2018-01-09 12:34:11 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkCanvas.h"
9#include "SkPathEffect.h"
10#include "SkMaskFilter.h"
11#include "SkData.h"
12#include "SkDescriptor.h"
13#include "SkGraphics.h"
14#include "SkSemaphore.h"
15#include "SkPictureRecorder.h"
16#include "SkSerialProcs.h"
17#include "SkSurface.h"
18#include "SkTypeface.h"
19#include "SkWriteBuffer.h"
20
Herb Derby4f505f92018-01-09 12:34:11 -050021#include <chrono>
Mike Kleina8a51ce2018-01-09 12:34:11 -050022#include <ctype.h>
23#include <err.h>
24#include <memory>
25#include <stdio.h>
26#include <thread>
27#include <iostream>
28#include <unordered_map>
29
30#include <sys/types.h>
31#include <sys/wait.h>
32#include <unistd.h>
33#include <sys/mman.h>
34#include "SkTypeface_remote.h"
35
36static const size_t kPageSize = 4096;
37
38struct WireTypeface {
39 std::thread::id thread_id;
40 SkFontID typeface_id;
41 SkFontStyle style;
42 bool is_fixed;
43};
44
Herb Derby4f505f92018-01-09 12:34:11 -050045class ScalerContextRecDescriptor {
46public:
47 explicit ScalerContextRecDescriptor(const SkScalerContextRec& rec) {
48 auto desc = reinterpret_cast<SkDescriptor*>(&fDescriptor);
49 desc->init();
50 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
51 }
52
53 const SkDescriptor& desc() const {
54 return *reinterpret_cast<const SkDescriptor*>(&fDescriptor);
55 }
56
57 struct Hash {
58 size_t operator()(ScalerContextRecDescriptor const& s) const {
59 return SkOpts::hash_fn(&s.desc(), sizeof(s), 0);
60 }
61 };
62
63 struct Equal {
64 bool operator()( const ScalerContextRecDescriptor& lhs,
65 const ScalerContextRecDescriptor& rhs ) const {
66 return lhs.desc() == rhs.desc();
67 }
68 };
69
70private:
71 // The system only passes descriptors without effects. That is why it uses a fixed size
72 // descriptor. storageFor is needed because some of the constructors below are private.
73 template <typename T>
74 using storageFor = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
75 struct {
76 storageFor<SkDescriptor> dummy1;
77 storageFor<SkDescriptor::Entry> dummy2;
78 storageFor<SkScalerContextRec> dummy3;
79 } fDescriptor;
80};
81
Mike Kleina8a51ce2018-01-09 12:34:11 -050082class Op {
83public:
Herb Derby4f505f92018-01-09 12:34:11 -050084 explicit Op(const SkScalerContextRec& rec) : descriptor{rec} {}
Mike Kleina8a51ce2018-01-09 12:34:11 -050085 int32_t op;
86 SkFontID typeface_id;
87 union {
88 // op 0
89 SkPaint::FontMetrics fontMetrics;
90 // op 1 and 2
91 SkGlyph glyph;
92 // op 3
93 struct {
94 SkGlyphID glyphId;
95 size_t pathSize;
96 };
97 };
Herb Derby4f505f92018-01-09 12:34:11 -050098 ScalerContextRecDescriptor descriptor;
Mike Kleina8a51ce2018-01-09 12:34:11 -050099};
100
101class RemoteScalerContextPassThread : public SkRemoteScalerContext {
102public:
103 explicit RemoteScalerContextPassThread(int readFd, int writeFd)
104 : fReadFd{readFd}
105 , fWriteFd{writeFd} { }
106 void generateFontMetrics(const SkTypefaceProxy& tf,
107 const SkScalerContextRec& rec,
108 SkPaint::FontMetrics* metrics) override {
109 Op* op = this->createOp(0, tf, rec);
110 write(fWriteFd, fBuffer, sizeof(*op));
Herb Derby4f505f92018-01-09 12:34:11 -0500111 read(fReadFd, fBuffer, sizeof(fBuffer));
Mike Kleina8a51ce2018-01-09 12:34:11 -0500112 memcpy(metrics, &op->fontMetrics, sizeof(op->fontMetrics));
113 op->~Op();
114 }
115
116 void generateMetrics(const SkTypefaceProxy& tf,
117 const SkScalerContextRec& rec,
118 SkGlyph* glyph) override {
119 Op* op = this->createOp(1, tf, rec);
120 memcpy(&op->glyph, glyph, sizeof(*glyph));
121 write(fWriteFd, fBuffer, sizeof(*op));
122 read(fReadFd, fBuffer, sizeof(fBuffer));
123 memcpy(glyph, &op->glyph, sizeof(op->glyph));
124 op->~Op();
125 }
126
127 void generateImage(const SkTypefaceProxy& tf,
128 const SkScalerContextRec& rec,
129 const SkGlyph& glyph) override {
130 Op* op = this->createOp(2, tf, rec);
131 memcpy(&op->glyph, &glyph, sizeof(glyph));
132 write(fWriteFd, fBuffer, sizeof(*op));
133 read(fReadFd, fBuffer, sizeof(fBuffer));
Mike Kleina8a51ce2018-01-09 12:34:11 -0500134 memcpy(glyph.fImage, fBuffer + sizeof(Op), glyph.rowBytes() * glyph.fHeight);
135 op->~Op();
136 }
137
138 void generatePath(const SkTypefaceProxy& tf,
139 const SkScalerContextRec& rec,
140 SkGlyphID glyph, SkPath* path) override {
141 Op* op = this->createOp(3, tf, rec);
142 op->glyphId = glyph;
143 write(fWriteFd, fBuffer, sizeof(*op));
144 read(fReadFd, fBuffer, sizeof(fBuffer));
145 path->readFromMemory(fBuffer + sizeof(Op), op->pathSize);
146 op->~Op();
147 }
148
149private:
150 Op* createOp(uint32_t opID, const SkTypefaceProxy& tf,
151 const SkScalerContextRec& rec) {
Herb Derby4f505f92018-01-09 12:34:11 -0500152 Op* op = new (fBuffer) Op(rec);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500153 op->op = opID;
154 op->typeface_id = tf.fontID();
155
Mike Kleina8a51ce2018-01-09 12:34:11 -0500156 return op;
157 }
158
159 const int fReadFd,
160 fWriteFd;
161 uint8_t fBuffer[1024 * kPageSize];
162};
163
164static sk_sp<SkTypeface> gpu_from_renderer_by_ID(const void* buf, size_t len, void* ctx) {
Herb Derbyd08c6822018-01-09 12:34:11 -0500165 static std::unordered_map<SkFontID, sk_sp<SkTypefaceProxy>> mapIdToTypeface;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500166 WireTypeface wire;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500167 if (len >= sizeof(wire)) {
168 memcpy(&wire, buf, sizeof(wire));
Herb Derbyd08c6822018-01-09 12:34:11 -0500169 auto i = mapIdToTypeface.find(wire.typeface_id);
170 if (i == mapIdToTypeface.end()) {
171
172 auto newTypeface = sk_make_sp<SkTypefaceProxy>(
173 wire.typeface_id,
174 wire.thread_id,
175 wire.style,
176 wire.is_fixed,
177 (SkRemoteScalerContext*)ctx);
178
179 i = mapIdToTypeface.emplace_hint(i, wire.typeface_id, newTypeface);
180 }
181 return i->second;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500182 }
Herb Derbyd08c6822018-01-09 12:34:11 -0500183 SK_ABORT("Bad data");
Mike Kleina8a51ce2018-01-09 12:34:11 -0500184 return nullptr;
185}
186
187std::unordered_map<SkFontID, sk_sp<SkTypeface>> gTypefaceMap;
188
189
Herb Derby4f505f92018-01-09 12:34:11 -0500190// TODO: Figure out how to manage the entries.
191std::unordered_map<ScalerContextRecDescriptor,
192 std::unique_ptr<SkScalerContext>,
193 ScalerContextRecDescriptor::Hash,
194 ScalerContextRecDescriptor::Equal>
195 gScalerContextMap(16,
196 ScalerContextRecDescriptor::Hash(),
197 ScalerContextRecDescriptor::Equal());
Mike Kleina8a51ce2018-01-09 12:34:11 -0500198
Herb Derby4f505f92018-01-09 12:34:11 -0500199static SkScalerContext* scaler_context_from_op(Op* op) {
200
201 SkScalerContext* sc;
202 auto j = gScalerContextMap.find(op->descriptor);
203 if (j != gScalerContextMap.end()) {
204 sc = j->second.get();
205 } else {
206 auto i = gTypefaceMap.find(op->typeface_id);
207 if (i == gTypefaceMap.end()) {
208 std::cerr << "bad typeface id: " << op->typeface_id << std::endl;
209 SK_ABORT("unknown type face");
210 }
211 auto tf = i->second;
212 SkScalerContextEffects effects;
213 auto mapSc = tf->createScalerContext(effects, &op->descriptor.desc(), false);
214 sc = mapSc.get();
215 gScalerContextMap.emplace_hint(j, op->descriptor, std::move(mapSc));
Mike Kleina8a51ce2018-01-09 12:34:11 -0500216 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500217 return sc;
218
219}
220
221static sk_sp<SkData> renderer_to_gpu_by_ID(SkTypeface* tf, void* ctx) {
222 WireTypeface wire = {
223 std::this_thread::get_id(),
224 SkTypeface::UniqueID(tf),
225 tf->fontStyle(),
226 tf->isFixedPitch()
227 };
228 auto i = gTypefaceMap.find(SkTypeface::UniqueID(tf));
229 if (i == gTypefaceMap.end()) {
Mike Kleina8a51ce2018-01-09 12:34:11 -0500230 gTypefaceMap.insert({SkTypeface::UniqueID(tf), sk_ref_sp(tf)});
231 }
232 return SkData::MakeWithCopy(&wire, sizeof(wire));
233}
234
Herb Derby4f505f92018-01-09 12:34:11 -0500235static void final_draw(std::string outFilename,
236 SkDeserialProcs* procs,
237 uint8_t* picData,
238 size_t picSize) {
Herb Derby4f505f92018-01-09 12:34:11 -0500239
240 auto pic = SkPicture::MakeFromData(picData, picSize, procs);
241
242 auto cullRect = pic->cullRect();
243 auto r = cullRect.round();
Herb Derby4f505f92018-01-09 12:34:11 -0500244
Herb Derbyd08c6822018-01-09 12:34:11 -0500245 auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
Herb Derby4f505f92018-01-09 12:34:11 -0500246 auto c = s->getCanvas();
Herb Derbyd08c6822018-01-09 12:34:11 -0500247
248 auto picUnderTest = SkPicture::MakeFromData(picData, picSize, procs);
249 auto start = std::chrono::high_resolution_clock::now();
250
251 for (int i = 0; i < 40; i++) {
252
253 c->drawPicture(picUnderTest);
254 }
Herb Derby4f505f92018-01-09 12:34:11 -0500255
256 auto end = std::chrono::high_resolution_clock::now();
257
258 std::chrono::duration<double> elapsed_seconds = end-start;
259
260 std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
261
262 auto i = s->makeImageSnapshot();
263 auto data = i->encodeToData();
264 SkFILEWStream f(outFilename.c_str());
265 f.write(data->data(), data->size());
266}
267
Mike Kleina8a51ce2018-01-09 12:34:11 -0500268static void gpu(int readFd, int writeFd) {
269
270 size_t picSize = 0;
271 read(readFd, &picSize, sizeof(picSize));
272
Mike Kleina8a51ce2018-01-09 12:34:11 -0500273 static constexpr size_t kBufferSize = 10 * 1024 * kPageSize;
274 std::unique_ptr<uint8_t[]> picBuffer{new uint8_t[kBufferSize]};
275
276 size_t readSoFar = 0;
277 while (readSoFar < picSize) {
278 ssize_t readSize;
279 if((readSize = read(readFd, &picBuffer[readSoFar], kBufferSize - readSoFar)) <= 0) {
280 if (readSize == 0) return;
281 err(1, "gpu pic read error %d", errno);
282 }
283 readSoFar += readSize;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500284 }
285
Mike Kleina8a51ce2018-01-09 12:34:11 -0500286 SkDeserialProcs procs;
287 std::unique_ptr<SkRemoteScalerContext> rsc{
288 new RemoteScalerContextPassThread{readFd, writeFd}};
289 procs.fTypefaceProc = gpu_from_renderer_by_ID;
290 procs.fTypefaceCtx = rsc.get();
Herb Derby4f505f92018-01-09 12:34:11 -0500291 final_draw("test.png", &procs, picBuffer.get(), picSize);
292 /*
Mike Kleina8a51ce2018-01-09 12:34:11 -0500293 auto pic = SkPicture::MakeFromData(picBuffer.get(), picSize, &procs);
294
295 auto cullRect = pic->cullRect();
296 auto r = cullRect.round();
297 auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
298
299 auto c = s->getCanvas();
300 c->drawPicture(pic);
301
Mike Kleina8a51ce2018-01-09 12:34:11 -0500302 auto i = s->makeImageSnapshot();
303 auto data = i->encodeToData();
304 SkFILEWStream f("test.png");
305 f.write(data->data(), data->size());
Herb Derby4f505f92018-01-09 12:34:11 -0500306 */
Mike Kleina8a51ce2018-01-09 12:34:11 -0500307 close(writeFd);
308 close(readFd);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500309}
310
311static int renderer(const std::string& skpName, int readFd, int writeFd) {
312 std::string prefix{"skps/"};
313 std::string fileName{prefix + skpName + ".skp"};
Mike Kleina8a51ce2018-01-09 12:34:11 -0500314
315 auto skp = SkData::MakeFromFileName(fileName.c_str());
316 auto pic = SkPicture::MakeFromData(skp.get());
317
Herb Derby4f505f92018-01-09 12:34:11 -0500318 bool toGpu = true;
319
Mike Kleina8a51ce2018-01-09 12:34:11 -0500320 SkSerialProcs procs;
Herb Derby4f505f92018-01-09 12:34:11 -0500321 if (toGpu) {
322 procs.fTypefaceProc = renderer_to_gpu_by_ID;
323 }
324
Mike Kleina8a51ce2018-01-09 12:34:11 -0500325 auto stream = pic->serialize(&procs);
326
327 std::cerr << "stream is " << stream->size() << " bytes long" << std::endl;
328
Mike Kleina8a51ce2018-01-09 12:34:11 -0500329 size_t picSize = stream->size();
330 uint8_t* picBuffer = (uint8_t*) stream->data();
Herb Derby4f505f92018-01-09 12:34:11 -0500331
332 if (!toGpu) {
333 final_draw("test-direct.png", nullptr, picBuffer, picSize);
334 close(writeFd);
335 close(readFd);
336 return 0;
337 }
338
Mike Kleina8a51ce2018-01-09 12:34:11 -0500339 write(writeFd, &picSize, sizeof(picSize));
340
341 size_t writeSoFar = 0;
342 while (writeSoFar < picSize) {
343 ssize_t writeSize = write(writeFd, &picBuffer[writeSoFar], picSize - writeSoFar);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500344 if (writeSize <= 0) {
345 if (writeSize == 0) {
346 std::cerr << "Exit" << std::endl;
347 return 1;
348 }
349 perror("Can't write picture from render to GPU ");
350 return 1;
351 }
352 writeSoFar += writeSize;
353 }
354 std::cerr << "Waiting for scaler context ops." << std::endl;
355
356 static constexpr size_t kBufferSize = 1024 * kPageSize;
357 std::unique_ptr<uint8_t[]> glyphBuffer{new uint8_t[kBufferSize]};
358
359 Op* op = (Op*)glyphBuffer.get();
360 while (true) {
361 ssize_t size = read(readFd, glyphBuffer.get(), sizeof(*op));
362 if (size <= 0) { std::cerr << "Exit op loop" << std::endl; break;}
363 size_t writeSize = sizeof(*op);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500364
365 auto sc = scaler_context_from_op(op);
366 switch (op->op) {
367 case 0: {
368 sc->getFontMetrics(&op->fontMetrics);
369 break;
370 }
371 case 1: {
372 sc->getMetrics(&op->glyph);
373 break;
374 }
375 case 2: {
376 // TODO: check for buffer overflow.
377 op->glyph.fImage = &glyphBuffer[sizeof(Op)];
378 sc->getImage(op->glyph);
379 writeSize += op->glyph.rowBytes() * op->glyph.fHeight;
380 break;
381 }
382 case 3: {
383 // TODO: check for buffer overflow.
384 SkPath path;
385 sc->getPath(op->glyphId, &path);
386 op->pathSize = path.writeToMemory(&glyphBuffer[sizeof(Op)]);
387 writeSize += op->pathSize;
388 break;
389 }
390 default:
391 SkASSERT("Bad op");
392 }
Herb Derby4f505f92018-01-09 12:34:11 -0500393 write(writeFd, glyphBuffer.get(), writeSize);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500394 }
395
396 close(readFd);
397 close(writeFd);
398
399 std::cerr << "Returning from render" << std::endl;
400
401 return 0;
402}
403
Herb Derbyd08c6822018-01-09 12:34:11 -0500404enum direction : int {kRead = 0, kWrite = 1};
405
406static void start_gpu(int render_to_gpu[2], int gpu_to_render[2]) {
407 std::cout << "gpu - Starting GPU" << std::endl;
408 close(gpu_to_render[kRead]);
409 close(render_to_gpu[kWrite]);
410 gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
411}
412
413static void start_render(std::string& skpName, int render_to_gpu[2], int gpu_to_render[2]) {
414 std::cout << "renderer - Starting Renderer" << std::endl;
415 close(render_to_gpu[kRead]);
416 close(gpu_to_render[kWrite]);
417 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
418}
419
Mike Kleina8a51ce2018-01-09 12:34:11 -0500420int main(int argc, char** argv) {
421 std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"desk_nytimes"};
422 printf("skp: %s\n", skpName.c_str());
423
424 int render_to_gpu[2],
425 gpu_to_render[2];
426
Mike Kleina8a51ce2018-01-09 12:34:11 -0500427 int r = pipe(render_to_gpu);
428 if (r < 0) {
429 perror("Can't write picture from render to GPU ");
430 return 1;
431 }
432 r = pipe(gpu_to_render);
433 if (r < 0) {
434 perror("Can't write picture from render to GPU ");
435 return 1;
436 }
437
Herb Derbyd08c6822018-01-09 12:34:11 -0500438 bool useProcess = true;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500439
Herb Derbyd08c6822018-01-09 12:34:11 -0500440 if (useProcess) {
441 pid_t child = fork();
442 SkGraphics::Init();
443
444 if (child == 0) {
445 start_render(skpName, render_to_gpu, gpu_to_render);
446 } else {
447 start_gpu(render_to_gpu, gpu_to_render);
448 std::cerr << "Waiting for renderer." << std::endl;
449 waitpid(child, nullptr, 0);
450 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500451 } else {
Herb Derbyd08c6822018-01-09 12:34:11 -0500452 SkGraphics::Init();
453 std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach();
454 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500455 }
456
Mike Kleina8a51ce2018-01-09 12:34:11 -0500457 return 0;
458}
459