1/*
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
21#include <chrono>
22#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#include "SkRemoteGlyphCache.h"
36#include "SkMakeUnique.h"
37
38static const size_t kPageSize = 4096;
39
40static bool gUseGpu = true;
41static bool gPurgeFontCaches = true;
42static bool gUseProcess = true;
43
44enum class OpCode : int32_t {
45    kFontMetrics          = 0,
46    kGlyphMetrics         = 1,
47    kGlyphImage           = 2,
48    kGlyphPath            = 3,
49    kGlyphMetricsAndImage = 4,
50};
51
52class Op {
53public:
54    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;
61    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    };
72};
73
74class RemoteScalerContextFIFO : public SkRemoteScalerContext {
75public:
76    explicit RemoteScalerContextFIFO(int readFd, int writeFd)
77        : fReadFd{readFd}
78        , fWriteFd{writeFd} { }
79    void generateFontMetrics(const SkTypefaceProxy& tf,
80                             const SkScalerContextRec& rec,
81                             SkPaint::FontMetrics* metrics) override {
82        Op* op = this->createOp(OpCode::kFontMetrics, tf, rec);
83        write(fWriteFd, fBuffer, sizeof(*op));
84        read(fReadFd, fBuffer, sizeof(fBuffer));
85        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 {
92        Op* op = this->createOp(OpCode::kGlyphMetrics, tf, rec);
93        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 {
103        SK_ABORT("generateImage should not be called.");
104        Op* op = this->createOp(OpCode::kGlyphImage, tf, rec);
105        memcpy(&op->glyph, &glyph, sizeof(glyph));
106        write(fWriteFd, fBuffer, sizeof(*op));
107        read(fReadFd, fBuffer, sizeof(fBuffer));
108        memcpy(glyph.fImage, fBuffer + sizeof(Op), glyph.rowBytes() * glyph.fHeight);
109        op->~Op();
110    }
111
112    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
126    void generatePath(const SkTypefaceProxy& tf,
127                      const SkScalerContextRec& rec,
128                      SkGlyphID glyph, SkPath* path) override {
129        Op* op = this->createOp(OpCode::kGlyphPath, tf, rec);
130        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:
138    Op* createOp(OpCode opCode, const SkTypefaceProxy& tf,
139                 const SkScalerContextRec& rec) {
140        Op* op = new (fBuffer) Op(opCode, tf.fontID(), rec);
141
142        return op;
143    }
144
145    const int fReadFd,
146              fWriteFd;
147    uint8_t   fBuffer[1024 * kPageSize];
148};
149
150static void final_draw(std::string outFilename,
151                       SkDeserialProcs* procs,
152                       uint8_t* picData,
153                       size_t picSize) {
154
155    auto pic = SkPicture::MakeFromData(picData, picSize, procs);
156
157    auto cullRect = pic->cullRect();
158    auto r = cullRect.round();
159
160    auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
161    auto c = s->getCanvas();
162    auto picUnderTest = SkPicture::MakeFromData(picData, picSize, procs);
163
164
165    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();
171        c->drawPicture(picUnderTest);
172        auto end = std::chrono::high_resolution_clock::now();
173        std::chrono::duration<double> elapsed_seconds = end-start;
174        total_seconds += elapsed_seconds;
175
176    }
177
178    std::cout << "useProcess: " << gUseProcess
179              << " useGPU: " << gUseGpu
180              << " purgeCache: " << gPurgeFontCaches << std::endl;
181    std::cerr << "elapsed time: " << total_seconds.count() << "s\n";
182
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
189static void gpu(int readFd, int writeFd) {
190
191    size_t picSize = 0;
192    ssize_t r = read(readFd, &picSize, sizeof(picSize));
193    if (r > 0) {
194
195        static constexpr size_t kBufferSize = 10 * 1024 * kPageSize;
196        std::unique_ptr<uint8_t[]> picBuffer{new uint8_t[kBufferSize]};
197
198        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;
206        }
207
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
217    }
218
219    close(writeFd);
220    close(readFd);
221}
222
223static int renderer(
224    const std::string& skpName, int readFd, int writeFd)
225{
226    std::string prefix{"skps/"};
227    std::string fileName{prefix + skpName + ".skp"};
228
229    auto skp = SkData::MakeFromFileName(fileName.c_str());
230    std::cout << "skp stream is " << skp->size() << " bytes long " << std::endl;
231
232    SkRemoteGlyphCacheRenderer rc;
233    SkSerialProcs procs;
234    sk_sp<SkData> stream;
235    if (gUseGpu) {
236        auto pic = SkPicture::MakeFromData(skp.get());
237        rc.prepareSerializeProcs(&procs);
238        stream = pic->serialize(&procs);
239    } else {
240        stream = skp;
241    }
242
243    std::cout << "stream is " << stream->size() << " bytes long" << std::endl;
244
245    size_t picSize = stream->size();
246    uint8_t* picBuffer = (uint8_t*) stream->data();
247
248    if (!gUseGpu) {
249        final_draw("test-direct.png", nullptr, picBuffer, picSize);
250        close(writeFd);
251        close(readFd);
252        return 0;
253    }
254
255    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);
260        if (writeSize <= 0) {
261            if (writeSize == 0) {
262                std::cout << "Exit" << std::endl;
263                return 1;
264            }
265            perror("Can't write picture from render to GPU ");
266            return 1;
267        }
268        writeSoFar += writeSize;
269    }
270    std::cout << "Waiting for scaler context ops." << std::endl;
271
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));
278        if (size <= 0) { std::cout << "Exit op loop" << std::endl; break;}
279        size_t writeSize = sizeof(*op);
280
281            auto sc = rc.generateScalerContext(op->descriptor, op->typefaceId);
282            switch (op->opCode) {
283                case OpCode::kFontMetrics : {
284                    sc->getFontMetrics(&op->fontMetrics);
285                    break;
286                }
287                case OpCode::kGlyphMetrics : {
288                    sc->getMetrics(&op->glyph);
289                    break;
290                }
291                case OpCode::kGlyphImage : {
292                    // 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                }
298                case OpCode::kGlyphPath : {
299                    // 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                }
306                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                }
318                default:
319                    SK_ABORT("Bad op");
320            }
321
322        write(writeFd, glyphBuffer.get(), writeSize);
323    }
324
325    close(readFd);
326    close(writeFd);
327
328    std::cout << "Returning from render" << std::endl;
329
330    return 0;
331}
332
333enum 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
349int main(int argc, char** argv) {
350    std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"desk_nytimes"};
351    int mode = argc > 2 ? atoi(argv[2]) : -1;
352    printf("skp: %s\n", skpName.c_str());
353
354    int render_to_gpu[2],
355        gpu_to_render[2];
356
357    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;
362        }
363        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        }
392    }
393
394    return 0;
395}
396
397