blob: 1e78888e0c09c0a639438a1b568d201c4d2cd508 [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
Mike Kleina8a51ce2018-01-09 12:34:11 -050044class Op {
45public:
Herb Derby4f505f92018-01-09 12:34:11 -050046 explicit Op(const SkScalerContextRec& rec) : descriptor{rec} {}
Mike Kleina8a51ce2018-01-09 12:34:11 -050047 int32_t op;
48 SkFontID typeface_id;
49 union {
50 // op 0
51 SkPaint::FontMetrics fontMetrics;
52 // op 1 and 2
53 SkGlyph glyph;
54 // op 3
55 struct {
56 SkGlyphID glyphId;
57 size_t pathSize;
58 };
59 };
Herb Derbyb2922f62018-01-26 16:47:54 -050060 SkScalerContextRecDescriptor descriptor;
Mike Kleina8a51ce2018-01-09 12:34:11 -050061};
62
Herb Derbyb2922f62018-01-26 16:47:54 -050063class RemoteScalerContextFIFO : public SkRemoteScalerContext {
Mike Kleina8a51ce2018-01-09 12:34:11 -050064public:
Herb Derbyb2922f62018-01-26 16:47:54 -050065 explicit RemoteScalerContextFIFO(int readFd, int writeFd)
Mike Kleina8a51ce2018-01-09 12:34:11 -050066 : fReadFd{readFd}
67 , fWriteFd{writeFd} { }
68 void generateFontMetrics(const SkTypefaceProxy& tf,
69 const SkScalerContextRec& rec,
70 SkPaint::FontMetrics* metrics) override {
71 Op* op = this->createOp(0, tf, rec);
72 write(fWriteFd, fBuffer, sizeof(*op));
Herb Derby4f505f92018-01-09 12:34:11 -050073 read(fReadFd, fBuffer, sizeof(fBuffer));
Mike Kleina8a51ce2018-01-09 12:34:11 -050074 memcpy(metrics, &op->fontMetrics, sizeof(op->fontMetrics));
75 op->~Op();
76 }
77
78 void generateMetrics(const SkTypefaceProxy& tf,
79 const SkScalerContextRec& rec,
80 SkGlyph* glyph) override {
81 Op* op = this->createOp(1, tf, rec);
82 memcpy(&op->glyph, glyph, sizeof(*glyph));
83 write(fWriteFd, fBuffer, sizeof(*op));
84 read(fReadFd, fBuffer, sizeof(fBuffer));
85 memcpy(glyph, &op->glyph, sizeof(op->glyph));
86 op->~Op();
87 }
88
89 void generateImage(const SkTypefaceProxy& tf,
90 const SkScalerContextRec& rec,
91 const SkGlyph& glyph) override {
92 Op* op = this->createOp(2, tf, rec);
93 memcpy(&op->glyph, &glyph, sizeof(glyph));
94 write(fWriteFd, fBuffer, sizeof(*op));
95 read(fReadFd, fBuffer, sizeof(fBuffer));
Mike Kleina8a51ce2018-01-09 12:34:11 -050096 memcpy(glyph.fImage, fBuffer + sizeof(Op), glyph.rowBytes() * glyph.fHeight);
97 op->~Op();
98 }
99
100 void generatePath(const SkTypefaceProxy& tf,
101 const SkScalerContextRec& rec,
102 SkGlyphID glyph, SkPath* path) override {
103 Op* op = this->createOp(3, tf, rec);
104 op->glyphId = glyph;
105 write(fWriteFd, fBuffer, sizeof(*op));
106 read(fReadFd, fBuffer, sizeof(fBuffer));
107 path->readFromMemory(fBuffer + sizeof(Op), op->pathSize);
108 op->~Op();
109 }
110
111private:
112 Op* createOp(uint32_t opID, const SkTypefaceProxy& tf,
113 const SkScalerContextRec& rec) {
Herb Derby4f505f92018-01-09 12:34:11 -0500114 Op* op = new (fBuffer) Op(rec);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500115 op->op = opID;
116 op->typeface_id = tf.fontID();
117
Mike Kleina8a51ce2018-01-09 12:34:11 -0500118 return op;
119 }
120
121 const int fReadFd,
Herb Derby9d021822018-02-02 12:54:55 -0500122 fWriteFd;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500123 uint8_t fBuffer[1024 * kPageSize];
124};
125
Herb Derby4f505f92018-01-09 12:34:11 -0500126static void final_draw(std::string outFilename,
127 SkDeserialProcs* procs,
128 uint8_t* picData,
129 size_t picSize) {
Herb Derby4f505f92018-01-09 12:34:11 -0500130
131 auto pic = SkPicture::MakeFromData(picData, picSize, procs);
132
133 auto cullRect = pic->cullRect();
134 auto r = cullRect.round();
Herb Derby4f505f92018-01-09 12:34:11 -0500135
Herb Derbyd08c6822018-01-09 12:34:11 -0500136 auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
Herb Derby4f505f92018-01-09 12:34:11 -0500137 auto c = s->getCanvas();
Herb Derbyd08c6822018-01-09 12:34:11 -0500138 auto picUnderTest = SkPicture::MakeFromData(picData, picSize, procs);
Herb Derbyd08c6822018-01-09 12:34:11 -0500139
Herb Derbyd08c6822018-01-09 12:34:11 -0500140
Herb Derby9d021822018-02-02 12:54:55 -0500141 std::chrono::duration<double> total_seconds{0.0};
142 for (int i = 0; i < 20; i++) {
143 if (gPurgeFontCaches) {
144 SkGraphics::PurgeFontCache();
145 }
146 auto start = std::chrono::high_resolution_clock::now();
Herb Derbyd08c6822018-01-09 12:34:11 -0500147 c->drawPicture(picUnderTest);
Herb Derby9d021822018-02-02 12:54:55 -0500148 auto end = std::chrono::high_resolution_clock::now();
149 std::chrono::duration<double> elapsed_seconds = end-start;
150 total_seconds += elapsed_seconds;
151
Herb Derbyd08c6822018-01-09 12:34:11 -0500152 }
Herb Derby4f505f92018-01-09 12:34:11 -0500153
Herb Derby9d021822018-02-02 12:54:55 -0500154 std::cout << "useProcess: " << gUseProcess
155 << " useGPU: " << gUseGpu
156 << " purgeCache: " << gPurgeFontCaches << std::endl;
157 std::cerr << "elapsed time: " << total_seconds.count() << "s\n";
Herb Derby4f505f92018-01-09 12:34:11 -0500158
159 auto i = s->makeImageSnapshot();
160 auto data = i->encodeToData();
161 SkFILEWStream f(outFilename.c_str());
162 f.write(data->data(), data->size());
163}
164
Mike Kleina8a51ce2018-01-09 12:34:11 -0500165static void gpu(int readFd, int writeFd) {
166
167 size_t picSize = 0;
Herb Derby9d021822018-02-02 12:54:55 -0500168 ssize_t r = read(readFd, &picSize, sizeof(picSize));
169 if (r > 0) {
Mike Kleina8a51ce2018-01-09 12:34:11 -0500170
Herb Derby9d021822018-02-02 12:54:55 -0500171 static constexpr size_t kBufferSize = 10 * 1024 * kPageSize;
172 std::unique_ptr<uint8_t[]> picBuffer{new uint8_t[kBufferSize]};
Mike Kleina8a51ce2018-01-09 12:34:11 -0500173
Herb Derby9d021822018-02-02 12:54:55 -0500174 size_t readSoFar = 0;
175 while (readSoFar < picSize) {
176 ssize_t readSize;
177 if ((readSize = read(readFd, &picBuffer[readSoFar], kBufferSize - readSoFar)) <= 0) {
178 if (readSize == 0) return;
179 err(1, "gpu pic read error %d", errno);
180 }
181 readSoFar += readSize;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500182 }
Herb Derby9d021822018-02-02 12:54:55 -0500183
184 SkRemoteGlyphCacheGPU rc{
185 skstd::make_unique<RemoteScalerContextFIFO>(readFd, writeFd)
186 };
187
188 SkDeserialProcs procs;
189 rc.prepareDeserializeProcs(&procs);
190
191 final_draw("test.png", &procs, picBuffer.get(), picSize);
192
Mike Kleina8a51ce2018-01-09 12:34:11 -0500193 }
194
Mike Kleina8a51ce2018-01-09 12:34:11 -0500195 close(writeFd);
196 close(readFd);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500197}
198
Herb Derbyb2922f62018-01-26 16:47:54 -0500199static int renderer(
200 const std::string& skpName, int readFd, int writeFd)
201{
Mike Kleina8a51ce2018-01-09 12:34:11 -0500202 std::string prefix{"skps/"};
203 std::string fileName{prefix + skpName + ".skp"};
Mike Kleina8a51ce2018-01-09 12:34:11 -0500204
205 auto skp = SkData::MakeFromFileName(fileName.c_str());
Herb Derby9d021822018-02-02 12:54:55 -0500206 std::cout << "skp stream is " << skp->size() << " bytes long " << std::endl;
Herb Derby4f505f92018-01-09 12:34:11 -0500207
Herb Derbyb2922f62018-01-26 16:47:54 -0500208 SkRemoteGlyphCacheRenderer rc;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500209 SkSerialProcs procs;
Herb Derby9d021822018-02-02 12:54:55 -0500210 sk_sp<SkData> stream;
211 if (gUseGpu) {
212 auto pic = SkPicture::MakeFromData(skp.get());
Herb Derbyb2922f62018-01-26 16:47:54 -0500213 rc.prepareSerializeProcs(&procs);
Herb Derby9d021822018-02-02 12:54:55 -0500214 stream = pic->serialize(&procs);
215 } else {
216 stream = skp;
Herb Derby4f505f92018-01-09 12:34:11 -0500217 }
218
Herb Derby9d021822018-02-02 12:54:55 -0500219 std::cout << "stream is " << stream->size() << " bytes long" << std::endl;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500220
Mike Kleina8a51ce2018-01-09 12:34:11 -0500221 size_t picSize = stream->size();
222 uint8_t* picBuffer = (uint8_t*) stream->data();
Herb Derby4f505f92018-01-09 12:34:11 -0500223
Herb Derby9d021822018-02-02 12:54:55 -0500224 if (!gUseGpu) {
Herb Derby4f505f92018-01-09 12:34:11 -0500225 final_draw("test-direct.png", nullptr, picBuffer, picSize);
226 close(writeFd);
227 close(readFd);
228 return 0;
229 }
230
Mike Kleina8a51ce2018-01-09 12:34:11 -0500231 write(writeFd, &picSize, sizeof(picSize));
232
233 size_t writeSoFar = 0;
234 while (writeSoFar < picSize) {
235 ssize_t writeSize = write(writeFd, &picBuffer[writeSoFar], picSize - writeSoFar);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500236 if (writeSize <= 0) {
237 if (writeSize == 0) {
Herb Derby9d021822018-02-02 12:54:55 -0500238 std::cout << "Exit" << std::endl;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500239 return 1;
240 }
241 perror("Can't write picture from render to GPU ");
242 return 1;
243 }
244 writeSoFar += writeSize;
245 }
Herb Derby9d021822018-02-02 12:54:55 -0500246 std::cout << "Waiting for scaler context ops." << std::endl;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500247
248 static constexpr size_t kBufferSize = 1024 * kPageSize;
249 std::unique_ptr<uint8_t[]> glyphBuffer{new uint8_t[kBufferSize]};
250
251 Op* op = (Op*)glyphBuffer.get();
252 while (true) {
253 ssize_t size = read(readFd, glyphBuffer.get(), sizeof(*op));
Herb Derby9d021822018-02-02 12:54:55 -0500254 if (size <= 0) { std::cout << "Exit op loop" << std::endl; break;}
Mike Kleina8a51ce2018-01-09 12:34:11 -0500255 size_t writeSize = sizeof(*op);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500256
Herb Derbyb2922f62018-01-26 16:47:54 -0500257 auto sc = rc.generateScalerContext(op->descriptor, op->typeface_id);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500258 switch (op->op) {
259 case 0: {
260 sc->getFontMetrics(&op->fontMetrics);
261 break;
262 }
263 case 1: {
264 sc->getMetrics(&op->glyph);
265 break;
266 }
267 case 2: {
268 // TODO: check for buffer overflow.
269 op->glyph.fImage = &glyphBuffer[sizeof(Op)];
270 sc->getImage(op->glyph);
271 writeSize += op->glyph.rowBytes() * op->glyph.fHeight;
272 break;
273 }
274 case 3: {
275 // TODO: check for buffer overflow.
276 SkPath path;
277 sc->getPath(op->glyphId, &path);
278 op->pathSize = path.writeToMemory(&glyphBuffer[sizeof(Op)]);
279 writeSize += op->pathSize;
280 break;
281 }
282 default:
283 SkASSERT("Bad op");
284 }
Herb Derby4f505f92018-01-09 12:34:11 -0500285 write(writeFd, glyphBuffer.get(), writeSize);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500286 }
287
288 close(readFd);
289 close(writeFd);
290
Herb Derby9d021822018-02-02 12:54:55 -0500291 std::cout << "Returning from render" << std::endl;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500292
293 return 0;
294}
295
Herb Derbyd08c6822018-01-09 12:34:11 -0500296enum direction : int {kRead = 0, kWrite = 1};
297
298static void start_gpu(int render_to_gpu[2], int gpu_to_render[2]) {
299 std::cout << "gpu - Starting GPU" << std::endl;
300 close(gpu_to_render[kRead]);
301 close(render_to_gpu[kWrite]);
302 gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
303}
304
305static void start_render(std::string& skpName, int render_to_gpu[2], int gpu_to_render[2]) {
306 std::cout << "renderer - Starting Renderer" << std::endl;
307 close(render_to_gpu[kRead]);
308 close(gpu_to_render[kWrite]);
309 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
310}
311
Mike Kleina8a51ce2018-01-09 12:34:11 -0500312int main(int argc, char** argv) {
313 std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"desk_nytimes"};
Herb Derby9d021822018-02-02 12:54:55 -0500314 int mode = argc > 2 ? atoi(argv[2]) : -1;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500315 printf("skp: %s\n", skpName.c_str());
316
317 int render_to_gpu[2],
318 gpu_to_render[2];
319
Herb Derby9d021822018-02-02 12:54:55 -0500320 for (int m = 0; m < 8; m++) {
321 int r = pipe(render_to_gpu);
322 if (r < 0) {
323 perror("Can't write picture from render to GPU ");
324 return 1;
Herb Derbyd08c6822018-01-09 12:34:11 -0500325 }
Herb Derby9d021822018-02-02 12:54:55 -0500326 r = pipe(gpu_to_render);
327 if (r < 0) {
328 perror("Can't write picture from render to GPU ");
329 return 1;
330 }
331
332 gPurgeFontCaches = (m & 4) == 4;
333 gUseGpu = (m & 2) == 2;
334 gUseProcess = (m & 1) == 1;
335
336 if (mode >= 0 && mode < 8 && mode != m) {
337 continue;
338 }
339
340 if (gUseProcess) {
341 pid_t child = fork();
342 SkGraphics::Init();
343
344 if (child == 0) {
345 start_gpu(render_to_gpu, gpu_to_render);
346 } else {
347 start_render(skpName, render_to_gpu, gpu_to_render);
348 waitpid(child, nullptr, 0);
349 }
350 } else {
351 SkGraphics::Init();
352 std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach();
353 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
354 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500355 }
356
Mike Kleina8a51ce2018-01-09 12:34:11 -0500357 return 0;
358}
359