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
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
45class 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
82class Op {
83public:
84    explicit Op(const SkScalerContextRec& rec) : descriptor{rec} {}
85    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    };
98    ScalerContextRecDescriptor descriptor;
99};
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));
111        read(fReadFd, fBuffer, sizeof(fBuffer));
112        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));
134        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) {
152        Op* op = new (fBuffer) Op(rec);
153        op->op = opID;
154        op->typeface_id = tf.fontID();
155
156        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) {
165    static std::unordered_map<SkFontID, sk_sp<SkTypefaceProxy>> mapIdToTypeface;
166    WireTypeface wire;
167    if (len >= sizeof(wire)) {
168        memcpy(&wire, buf, sizeof(wire));
169        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;
182    }
183    SK_ABORT("Bad data");
184    return nullptr;
185}
186
187std::unordered_map<SkFontID, sk_sp<SkTypeface>> gTypefaceMap;
188
189
190// 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());
198
199static 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));
216    }
217    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()) {
230        gTypefaceMap.insert({SkTypeface::UniqueID(tf), sk_ref_sp(tf)});
231    }
232    return SkData::MakeWithCopy(&wire, sizeof(wire));
233}
234
235static void final_draw(std::string outFilename,
236                       SkDeserialProcs* procs,
237                       uint8_t* picData,
238                       size_t picSize) {
239
240    auto pic = SkPicture::MakeFromData(picData, picSize, procs);
241
242    auto cullRect = pic->cullRect();
243    auto r = cullRect.round();
244
245    auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
246    auto c = s->getCanvas();
247
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    }
255
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
268static void gpu(int readFd, int writeFd) {
269
270    size_t picSize = 0;
271    read(readFd, &picSize, sizeof(picSize));
272
273    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;
284    }
285
286    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();
291    final_draw("test.png", &procs, picBuffer.get(), picSize);
292    /*
293    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
302    auto i = s->makeImageSnapshot();
303    auto data = i->encodeToData();
304    SkFILEWStream f("test.png");
305    f.write(data->data(), data->size());
306     */
307    close(writeFd);
308    close(readFd);
309}
310
311static int renderer(const std::string& skpName, int readFd, int writeFd) {
312    std::string prefix{"skps/"};
313    std::string fileName{prefix + skpName + ".skp"};
314
315    auto skp = SkData::MakeFromFileName(fileName.c_str());
316    auto pic = SkPicture::MakeFromData(skp.get());
317
318    bool toGpu = true;
319
320    SkSerialProcs procs;
321    if (toGpu) {
322        procs.fTypefaceProc = renderer_to_gpu_by_ID;
323    }
324
325    auto stream = pic->serialize(&procs);
326
327    std::cerr << "stream is " << stream->size() << " bytes long" << std::endl;
328
329    size_t picSize = stream->size();
330    uint8_t* picBuffer = (uint8_t*) stream->data();
331
332    if (!toGpu) {
333        final_draw("test-direct.png", nullptr, picBuffer, picSize);
334        close(writeFd);
335        close(readFd);
336        return 0;
337    }
338
339    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);
344        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);
364
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            }
393        write(writeFd, glyphBuffer.get(), writeSize);
394    }
395
396    close(readFd);
397    close(writeFd);
398
399    std::cerr << "Returning from render" << std::endl;
400
401    return 0;
402}
403
404enum 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
420int 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
427    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
438    bool useProcess = true;
439
440    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        }
451    } else {
452        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]);
455    }
456
457    return 0;
458}
459
460