blob: 53aa6917eb016a68ce87a559653cdad9179e3aaa [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"
Herb Derbyb2922f62018-01-26 16:47:54 -050035#include "SkRemoteGlyphCache.h"
36#include "SkMakeUnique.h"
Mike Kleina8a51ce2018-01-09 12:34:11 -050037
38static const size_t kPageSize = 4096;
39
Herb Derby9d021822018-02-02 12:54:55 -050040static bool gUseGpu = true;
41static bool gPurgeFontCaches = true;
42static bool gUseProcess = true;
43
Herb Derbyca9c8792018-02-02 17:33:26 -050044enum class OpCode : int32_t {
45 kFontMetrics = 0,
46 kGlyphMetrics = 1,
47 kGlyphImage = 2,
48 kGlyphPath = 3,
49 kGlyphMetricsAndImage = 4,
50};
51
Mike Kleina8a51ce2018-01-09 12:34:11 -050052class Op {
53public:
Herb Derbyca9c8792018-02-02 17:33:26 -050054 Op(OpCode opCode, SkFontID typefaceId, const SkScalerContextRec& rec)
55 : opCode{opCode}
56 , typefaceId{typefaceId}
57 , descriptor{rec} { }
58 const OpCode opCode;
59 const SkFontID typefaceId;
60 const SkScalerContextRecDescriptor descriptor;
Mike Kleina8a51ce2018-01-09 12:34:11 -050061 union {
62 // op 0
63 SkPaint::FontMetrics fontMetrics;
64 // op 1 and 2
65 SkGlyph glyph;
66 // op 3
67 struct {
68 SkGlyphID glyphId;
69 size_t pathSize;
70 };
71 };
Mike Kleina8a51ce2018-01-09 12:34:11 -050072};
73
Herb Derbyb2922f62018-01-26 16:47:54 -050074class RemoteScalerContextFIFO : public SkRemoteScalerContext {
Mike Kleina8a51ce2018-01-09 12:34:11 -050075public:
Herb Derbyb2922f62018-01-26 16:47:54 -050076 explicit RemoteScalerContextFIFO(int readFd, int writeFd)
Mike Kleina8a51ce2018-01-09 12:34:11 -050077 : fReadFd{readFd}
78 , fWriteFd{writeFd} { }
79 void generateFontMetrics(const SkTypefaceProxy& tf,
80 const SkScalerContextRec& rec,
81 SkPaint::FontMetrics* metrics) override {
Herb Derbyca9c8792018-02-02 17:33:26 -050082 Op* op = this->createOp(OpCode::kFontMetrics, tf, rec);
Mike Kleina8a51ce2018-01-09 12:34:11 -050083 write(fWriteFd, fBuffer, sizeof(*op));
Herb Derby4f505f92018-01-09 12:34:11 -050084 read(fReadFd, fBuffer, sizeof(fBuffer));
Mike Kleina8a51ce2018-01-09 12:34:11 -050085 memcpy(metrics, &op->fontMetrics, sizeof(op->fontMetrics));
86 op->~Op();
87 }
88
89 void generateMetrics(const SkTypefaceProxy& tf,
90 const SkScalerContextRec& rec,
91 SkGlyph* glyph) override {
Herb Derbyca9c8792018-02-02 17:33:26 -050092 Op* op = this->createOp(OpCode::kGlyphMetrics, tf, rec);
Mike Kleina8a51ce2018-01-09 12:34:11 -050093 memcpy(&op->glyph, glyph, sizeof(*glyph));
94 write(fWriteFd, fBuffer, sizeof(*op));
95 read(fReadFd, fBuffer, sizeof(fBuffer));
96 memcpy(glyph, &op->glyph, sizeof(op->glyph));
97 op->~Op();
98 }
99
100 void generateImage(const SkTypefaceProxy& tf,
101 const SkScalerContextRec& rec,
102 const SkGlyph& glyph) override {
Herb Derbyca9c8792018-02-02 17:33:26 -0500103 SK_ABORT("generateImage should not be called.");
104 Op* op = this->createOp(OpCode::kGlyphImage, tf, rec);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500105 memcpy(&op->glyph, &glyph, sizeof(glyph));
106 write(fWriteFd, fBuffer, sizeof(*op));
107 read(fReadFd, fBuffer, sizeof(fBuffer));
Mike Kleina8a51ce2018-01-09 12:34:11 -0500108 memcpy(glyph.fImage, fBuffer + sizeof(Op), glyph.rowBytes() * glyph.fHeight);
109 op->~Op();
110 }
111
Herb Derbyca9c8792018-02-02 17:33:26 -0500112 void generateMetricsAndImage(const SkTypefaceProxy& tf,
113 const SkScalerContextRec& rec,
114 SkArenaAlloc* alloc,
115 SkGlyph* glyph) override {
116 Op* op = this->createOp(OpCode::kGlyphMetricsAndImage, tf, rec);
117 memcpy(&op->glyph, glyph, sizeof(op->glyph));
118 write(fWriteFd, fBuffer, sizeof(*op));
119 read(fReadFd, fBuffer, sizeof(fBuffer));
120 memcpy(glyph, &op->glyph, sizeof(*glyph));
121 glyph->allocImage(alloc);
122 memcpy(glyph->fImage, fBuffer + sizeof(Op), glyph->rowBytes() * glyph->fHeight);
123 op->~Op();
124 }
125
Mike Kleina8a51ce2018-01-09 12:34:11 -0500126 void generatePath(const SkTypefaceProxy& tf,
127 const SkScalerContextRec& rec,
128 SkGlyphID glyph, SkPath* path) override {
Herb Derbyca9c8792018-02-02 17:33:26 -0500129 Op* op = this->createOp(OpCode::kGlyphPath, tf, rec);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500130 op->glyphId = glyph;
131 write(fWriteFd, fBuffer, sizeof(*op));
132 read(fReadFd, fBuffer, sizeof(fBuffer));
133 path->readFromMemory(fBuffer + sizeof(Op), op->pathSize);
134 op->~Op();
135 }
136
137private:
Herb Derbyca9c8792018-02-02 17:33:26 -0500138 Op* createOp(OpCode opCode, const SkTypefaceProxy& tf,
Mike Kleina8a51ce2018-01-09 12:34:11 -0500139 const SkScalerContextRec& rec) {
Herb Derbyca9c8792018-02-02 17:33:26 -0500140 Op* op = new (fBuffer) Op(opCode, tf.fontID(), rec);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500141
Mike Kleina8a51ce2018-01-09 12:34:11 -0500142 return op;
143 }
144
145 const int fReadFd,
Herb Derby9d021822018-02-02 12:54:55 -0500146 fWriteFd;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500147 uint8_t fBuffer[1024 * kPageSize];
148};
149
Herb Derby4f505f92018-01-09 12:34:11 -0500150static void final_draw(std::string outFilename,
151 SkDeserialProcs* procs,
152 uint8_t* picData,
153 size_t picSize) {
Herb Derby4f505f92018-01-09 12:34:11 -0500154
155 auto pic = SkPicture::MakeFromData(picData, picSize, procs);
156
157 auto cullRect = pic->cullRect();
158 auto r = cullRect.round();
Herb Derby4f505f92018-01-09 12:34:11 -0500159
Herb Derbyd08c6822018-01-09 12:34:11 -0500160 auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
Herb Derby4f505f92018-01-09 12:34:11 -0500161 auto c = s->getCanvas();
Herb Derbyd08c6822018-01-09 12:34:11 -0500162 auto picUnderTest = SkPicture::MakeFromData(picData, picSize, procs);
Herb Derbyd08c6822018-01-09 12:34:11 -0500163
Herb Derbyd08c6822018-01-09 12:34:11 -0500164
Herb Derby9d021822018-02-02 12:54:55 -0500165 std::chrono::duration<double> total_seconds{0.0};
166 for (int i = 0; i < 20; i++) {
167 if (gPurgeFontCaches) {
168 SkGraphics::PurgeFontCache();
169 }
170 auto start = std::chrono::high_resolution_clock::now();
Herb Derbyd08c6822018-01-09 12:34:11 -0500171 c->drawPicture(picUnderTest);
Herb Derby9d021822018-02-02 12:54:55 -0500172 auto end = std::chrono::high_resolution_clock::now();
173 std::chrono::duration<double> elapsed_seconds = end-start;
174 total_seconds += elapsed_seconds;
175
Herb Derbyd08c6822018-01-09 12:34:11 -0500176 }
Herb Derby4f505f92018-01-09 12:34:11 -0500177
Herb Derby9d021822018-02-02 12:54:55 -0500178 std::cout << "useProcess: " << gUseProcess
179 << " useGPU: " << gUseGpu
180 << " purgeCache: " << gPurgeFontCaches << std::endl;
181 std::cerr << "elapsed time: " << total_seconds.count() << "s\n";
Herb Derby4f505f92018-01-09 12:34:11 -0500182
183 auto i = s->makeImageSnapshot();
184 auto data = i->encodeToData();
185 SkFILEWStream f(outFilename.c_str());
186 f.write(data->data(), data->size());
187}
188
Mike Kleina8a51ce2018-01-09 12:34:11 -0500189static void gpu(int readFd, int writeFd) {
190
191 size_t picSize = 0;
Herb Derby9d021822018-02-02 12:54:55 -0500192 ssize_t r = read(readFd, &picSize, sizeof(picSize));
193 if (r > 0) {
Mike Kleina8a51ce2018-01-09 12:34:11 -0500194
Herb Derby9d021822018-02-02 12:54:55 -0500195 static constexpr size_t kBufferSize = 10 * 1024 * kPageSize;
196 std::unique_ptr<uint8_t[]> picBuffer{new uint8_t[kBufferSize]};
Mike Kleina8a51ce2018-01-09 12:34:11 -0500197
Herb Derby9d021822018-02-02 12:54:55 -0500198 size_t readSoFar = 0;
199 while (readSoFar < picSize) {
200 ssize_t readSize;
201 if ((readSize = read(readFd, &picBuffer[readSoFar], kBufferSize - readSoFar)) <= 0) {
202 if (readSize == 0) return;
203 err(1, "gpu pic read error %d", errno);
204 }
205 readSoFar += readSize;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500206 }
Herb Derby9d021822018-02-02 12:54:55 -0500207
208 SkRemoteGlyphCacheGPU rc{
209 skstd::make_unique<RemoteScalerContextFIFO>(readFd, writeFd)
210 };
211
212 SkDeserialProcs procs;
213 rc.prepareDeserializeProcs(&procs);
214
215 final_draw("test.png", &procs, picBuffer.get(), picSize);
216
Mike Kleina8a51ce2018-01-09 12:34:11 -0500217 }
218
Mike Kleina8a51ce2018-01-09 12:34:11 -0500219 close(writeFd);
220 close(readFd);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500221}
222
Herb Derbyb2922f62018-01-26 16:47:54 -0500223static int renderer(
224 const std::string& skpName, int readFd, int writeFd)
225{
Mike Kleina8a51ce2018-01-09 12:34:11 -0500226 std::string prefix{"skps/"};
227 std::string fileName{prefix + skpName + ".skp"};
Mike Kleina8a51ce2018-01-09 12:34:11 -0500228
229 auto skp = SkData::MakeFromFileName(fileName.c_str());
Herb Derby9d021822018-02-02 12:54:55 -0500230 std::cout << "skp stream is " << skp->size() << " bytes long " << std::endl;
Herb Derby4f505f92018-01-09 12:34:11 -0500231
Herb Derbyb2922f62018-01-26 16:47:54 -0500232 SkRemoteGlyphCacheRenderer rc;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500233 SkSerialProcs procs;
Herb Derby9d021822018-02-02 12:54:55 -0500234 sk_sp<SkData> stream;
235 if (gUseGpu) {
236 auto pic = SkPicture::MakeFromData(skp.get());
Herb Derbyb2922f62018-01-26 16:47:54 -0500237 rc.prepareSerializeProcs(&procs);
Herb Derby9d021822018-02-02 12:54:55 -0500238 stream = pic->serialize(&procs);
239 } else {
240 stream = skp;
Herb Derby4f505f92018-01-09 12:34:11 -0500241 }
242
Herb Derby9d021822018-02-02 12:54:55 -0500243 std::cout << "stream is " << stream->size() << " bytes long" << std::endl;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500244
Mike Kleina8a51ce2018-01-09 12:34:11 -0500245 size_t picSize = stream->size();
246 uint8_t* picBuffer = (uint8_t*) stream->data();
Herb Derby4f505f92018-01-09 12:34:11 -0500247
Herb Derby9d021822018-02-02 12:54:55 -0500248 if (!gUseGpu) {
Herb Derby4f505f92018-01-09 12:34:11 -0500249 final_draw("test-direct.png", nullptr, picBuffer, picSize);
250 close(writeFd);
251 close(readFd);
252 return 0;
253 }
254
Mike Kleina8a51ce2018-01-09 12:34:11 -0500255 write(writeFd, &picSize, sizeof(picSize));
256
257 size_t writeSoFar = 0;
258 while (writeSoFar < picSize) {
259 ssize_t writeSize = write(writeFd, &picBuffer[writeSoFar], picSize - writeSoFar);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500260 if (writeSize <= 0) {
261 if (writeSize == 0) {
Herb Derby9d021822018-02-02 12:54:55 -0500262 std::cout << "Exit" << std::endl;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500263 return 1;
264 }
265 perror("Can't write picture from render to GPU ");
266 return 1;
267 }
268 writeSoFar += writeSize;
269 }
Herb Derby9d021822018-02-02 12:54:55 -0500270 std::cout << "Waiting for scaler context ops." << std::endl;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500271
272 static constexpr size_t kBufferSize = 1024 * kPageSize;
273 std::unique_ptr<uint8_t[]> glyphBuffer{new uint8_t[kBufferSize]};
274
275 Op* op = (Op*)glyphBuffer.get();
276 while (true) {
277 ssize_t size = read(readFd, glyphBuffer.get(), sizeof(*op));
Herb Derby9d021822018-02-02 12:54:55 -0500278 if (size <= 0) { std::cout << "Exit op loop" << std::endl; break;}
Mike Kleina8a51ce2018-01-09 12:34:11 -0500279 size_t writeSize = sizeof(*op);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500280
Herb Derbyca9c8792018-02-02 17:33:26 -0500281 auto sc = rc.generateScalerContext(op->descriptor, op->typefaceId);
282 switch (op->opCode) {
283 case OpCode::kFontMetrics : {
Mike Kleina8a51ce2018-01-09 12:34:11 -0500284 sc->getFontMetrics(&op->fontMetrics);
285 break;
286 }
Herb Derbyca9c8792018-02-02 17:33:26 -0500287 case OpCode::kGlyphMetrics : {
Mike Kleina8a51ce2018-01-09 12:34:11 -0500288 sc->getMetrics(&op->glyph);
289 break;
290 }
Herb Derbyca9c8792018-02-02 17:33:26 -0500291 case OpCode::kGlyphImage : {
Mike Kleina8a51ce2018-01-09 12:34:11 -0500292 // TODO: check for buffer overflow.
293 op->glyph.fImage = &glyphBuffer[sizeof(Op)];
294 sc->getImage(op->glyph);
295 writeSize += op->glyph.rowBytes() * op->glyph.fHeight;
296 break;
297 }
Herb Derbyca9c8792018-02-02 17:33:26 -0500298 case OpCode::kGlyphPath : {
Mike Kleina8a51ce2018-01-09 12:34:11 -0500299 // TODO: check for buffer overflow.
300 SkPath path;
301 sc->getPath(op->glyphId, &path);
302 op->pathSize = path.writeToMemory(&glyphBuffer[sizeof(Op)]);
303 writeSize += op->pathSize;
304 break;
305 }
Herb Derbyca9c8792018-02-02 17:33:26 -0500306 case OpCode::kGlyphMetricsAndImage : {
307 // TODO: check for buffer overflow.
308 sc->getMetrics(&op->glyph);
309 if (op->glyph.fWidth <= 0 || op->glyph.fWidth >= kMaxGlyphWidth) {
310 op->glyph.fImage = nullptr;
311 break;
312 }
313 op->glyph.fImage = &glyphBuffer[sizeof(Op)];
314 sc->getImage(op->glyph);
315 writeSize += op->glyph.rowBytes() * op->glyph.fHeight;
316 break;
317 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500318 default:
Herb Derbyca9c8792018-02-02 17:33:26 -0500319 SK_ABORT("Bad op");
Mike Kleina8a51ce2018-01-09 12:34:11 -0500320 }
Herb Derbyca9c8792018-02-02 17:33:26 -0500321
Herb Derby4f505f92018-01-09 12:34:11 -0500322 write(writeFd, glyphBuffer.get(), writeSize);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500323 }
324
325 close(readFd);
326 close(writeFd);
327
Herb Derby9d021822018-02-02 12:54:55 -0500328 std::cout << "Returning from render" << std::endl;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500329
330 return 0;
331}
332
Herb Derbyd08c6822018-01-09 12:34:11 -0500333enum direction : int {kRead = 0, kWrite = 1};
334
335static void start_gpu(int render_to_gpu[2], int gpu_to_render[2]) {
336 std::cout << "gpu - Starting GPU" << std::endl;
337 close(gpu_to_render[kRead]);
338 close(render_to_gpu[kWrite]);
339 gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
340}
341
342static void start_render(std::string& skpName, int render_to_gpu[2], int gpu_to_render[2]) {
343 std::cout << "renderer - Starting Renderer" << std::endl;
344 close(render_to_gpu[kRead]);
345 close(gpu_to_render[kWrite]);
346 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
347}
348
Mike Kleina8a51ce2018-01-09 12:34:11 -0500349int main(int argc, char** argv) {
350 std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"desk_nytimes"};
Herb Derby9d021822018-02-02 12:54:55 -0500351 int mode = argc > 2 ? atoi(argv[2]) : -1;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500352 printf("skp: %s\n", skpName.c_str());
353
354 int render_to_gpu[2],
355 gpu_to_render[2];
356
Herb Derby9d021822018-02-02 12:54:55 -0500357 for (int m = 0; m < 8; m++) {
358 int r = pipe(render_to_gpu);
359 if (r < 0) {
360 perror("Can't write picture from render to GPU ");
361 return 1;
Herb Derbyd08c6822018-01-09 12:34:11 -0500362 }
Herb Derby9d021822018-02-02 12:54:55 -0500363 r = pipe(gpu_to_render);
364 if (r < 0) {
365 perror("Can't write picture from render to GPU ");
366 return 1;
367 }
368
369 gPurgeFontCaches = (m & 4) == 4;
370 gUseGpu = (m & 2) == 2;
371 gUseProcess = (m & 1) == 1;
372
373 if (mode >= 0 && mode < 8 && mode != m) {
374 continue;
375 }
376
377 if (gUseProcess) {
378 pid_t child = fork();
379 SkGraphics::Init();
380
381 if (child == 0) {
382 start_gpu(render_to_gpu, gpu_to_render);
383 } else {
384 start_render(skpName, render_to_gpu, gpu_to_render);
385 waitpid(child, nullptr, 0);
386 }
387 } else {
388 SkGraphics::Init();
389 std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach();
390 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
391 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500392 }
393
Mike Kleina8a51ce2018-01-09 12:34:11 -0500394 return 0;
395}
396