1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include <chrono>
9cb93a386Sopenharmony_ci#include <err.h>
10cb93a386Sopenharmony_ci#include <iostream>
11cb93a386Sopenharmony_ci#include <memory>
12cb93a386Sopenharmony_ci#include <string>
13cb93a386Sopenharmony_ci#include <sys/types.h>
14cb93a386Sopenharmony_ci#include <sys/uio.h>
15cb93a386Sopenharmony_ci#include <sys/wait.h>
16cb93a386Sopenharmony_ci#include <thread>
17cb93a386Sopenharmony_ci#include <unistd.h>
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h"
20cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
21cb93a386Sopenharmony_ci#include "src/core/SkRemoteGlyphCache.h"
22cb93a386Sopenharmony_ci#include "src/core/SkScalerContext.h"
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cistatic std::string gSkpName;
25cb93a386Sopenharmony_cistatic bool gUseGpu = true;
26cb93a386Sopenharmony_cistatic bool gPurgeFontCaches = true;
27cb93a386Sopenharmony_cistatic bool gUseProcess = true;
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ciclass ServerDiscardableManager : public SkStrikeServer::DiscardableHandleManager {
30cb93a386Sopenharmony_cipublic:
31cb93a386Sopenharmony_ci    ServerDiscardableManager() = default;
32cb93a386Sopenharmony_ci    ~ServerDiscardableManager() override = default;
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    SkDiscardableHandleId createHandle() override { return ++nextHandleId; }
35cb93a386Sopenharmony_ci    bool lockHandle(SkDiscardableHandleId handleId) override {
36cb93a386Sopenharmony_ci        return handleId > lastPurgedHandleId;
37cb93a386Sopenharmony_ci    }
38cb93a386Sopenharmony_ci    void purgeAll() { lastPurgedHandleId = nextHandleId; }
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ciprivate:
41cb93a386Sopenharmony_ci    SkDiscardableHandleId nextHandleId = 0u;
42cb93a386Sopenharmony_ci    SkDiscardableHandleId lastPurgedHandleId = 0u;
43cb93a386Sopenharmony_ci};
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ciclass ClientDiscardableManager : public SkStrikeClient::DiscardableHandleManager {
46cb93a386Sopenharmony_cipublic:
47cb93a386Sopenharmony_ci    class ScopedPurgeCache {
48cb93a386Sopenharmony_ci    public:
49cb93a386Sopenharmony_ci        ScopedPurgeCache(ClientDiscardableManager* manager) : fManager(manager) {
50cb93a386Sopenharmony_ci            if (fManager) fManager->allowPurging = true;
51cb93a386Sopenharmony_ci        }
52cb93a386Sopenharmony_ci        ~ScopedPurgeCache() {
53cb93a386Sopenharmony_ci            if (fManager) fManager->allowPurging = false;
54cb93a386Sopenharmony_ci        }
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    private:
57cb93a386Sopenharmony_ci        ClientDiscardableManager* fManager;
58cb93a386Sopenharmony_ci    };
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci    ClientDiscardableManager() = default;
61cb93a386Sopenharmony_ci    ~ClientDiscardableManager() override = default;
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    bool deleteHandle(SkDiscardableHandleId) override { return allowPurging; }
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ciprivate:
66cb93a386Sopenharmony_ci    bool allowPurging = false;
67cb93a386Sopenharmony_ci};
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_cistatic bool write_SkData(int fd, const SkData& data) {
70cb93a386Sopenharmony_ci    size_t size = data.size();
71cb93a386Sopenharmony_ci    ssize_t bytesWritten = ::write(fd, &size, sizeof(size));
72cb93a386Sopenharmony_ci    if (bytesWritten < 0) {
73cb93a386Sopenharmony_ci        err(1,"Failed write %zu", size);
74cb93a386Sopenharmony_ci        return false;
75cb93a386Sopenharmony_ci    }
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_ci    bytesWritten = ::write(fd, data.data(), data.size());
78cb93a386Sopenharmony_ci    if (bytesWritten < 0) {
79cb93a386Sopenharmony_ci        err(1,"Failed write %zu", size);
80cb93a386Sopenharmony_ci        return false;
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    return true;
84cb93a386Sopenharmony_ci}
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_cistatic sk_sp<SkData> read_SkData(int fd) {
87cb93a386Sopenharmony_ci    size_t size;
88cb93a386Sopenharmony_ci    ssize_t readSize = ::read(fd, &size, sizeof(size));
89cb93a386Sopenharmony_ci    if (readSize <= 0) {
90cb93a386Sopenharmony_ci        if (readSize < 0) {
91cb93a386Sopenharmony_ci            err(1, "Failed read %zu", size);
92cb93a386Sopenharmony_ci        }
93cb93a386Sopenharmony_ci        return nullptr;
94cb93a386Sopenharmony_ci    }
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci    auto out = SkData::MakeUninitialized(size);
97cb93a386Sopenharmony_ci    auto data = (uint8_t*)out->data();
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    size_t totalRead = 0;
100cb93a386Sopenharmony_ci    while (totalRead < size) {
101cb93a386Sopenharmony_ci        ssize_t sizeRead;
102cb93a386Sopenharmony_ci        sizeRead = ::read(fd, &data[totalRead], size - totalRead);
103cb93a386Sopenharmony_ci        if (sizeRead <= 0) {
104cb93a386Sopenharmony_ci            if (readSize < 0) {
105cb93a386Sopenharmony_ci                err(1, "Failed read %zu", size);
106cb93a386Sopenharmony_ci            }
107cb93a386Sopenharmony_ci            return nullptr;
108cb93a386Sopenharmony_ci        }
109cb93a386Sopenharmony_ci        totalRead += sizeRead;
110cb93a386Sopenharmony_ci    }
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    return out;
113cb93a386Sopenharmony_ci}
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ciclass Timer {
116cb93a386Sopenharmony_cipublic:
117cb93a386Sopenharmony_ci    void start() {
118cb93a386Sopenharmony_ci        fStart = std::chrono::high_resolution_clock::now();
119cb93a386Sopenharmony_ci    }
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci    void stop() {
122cb93a386Sopenharmony_ci        auto end = std::chrono::high_resolution_clock::now();
123cb93a386Sopenharmony_ci        fElapsedSeconds += end - fStart;
124cb93a386Sopenharmony_ci    }
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    double elapsedSeconds() {
127cb93a386Sopenharmony_ci        return fElapsedSeconds.count();
128cb93a386Sopenharmony_ci    }
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ciprivate:
131cb93a386Sopenharmony_ci    decltype(std::chrono::high_resolution_clock::now()) fStart;
132cb93a386Sopenharmony_ci    std::chrono::duration<double>                       fElapsedSeconds{0.0};
133cb93a386Sopenharmony_ci};
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_cistatic bool push_font_data(const SkPicture& pic, SkStrikeServer* strikeServer,
136cb93a386Sopenharmony_ci                           sk_sp<SkColorSpace> colorSpace, int writeFd) {
137cb93a386Sopenharmony_ci    const SkIRect bounds = pic.cullRect().round();
138cb93a386Sopenharmony_ci    const SkSurfaceProps props(0, kRGB_H_SkPixelGeometry);
139cb93a386Sopenharmony_ci    std::unique_ptr<SkCanvas> filter = strikeServer->makeAnalysisCanvas(
140cb93a386Sopenharmony_ci            bounds.width(), bounds.height(), props, std::move(colorSpace), true);
141cb93a386Sopenharmony_ci    pic.playback(filter.get());
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci    std::vector<uint8_t> fontData;
144cb93a386Sopenharmony_ci    strikeServer->writeStrikeData(&fontData);
145cb93a386Sopenharmony_ci    auto data = SkData::MakeWithoutCopy(fontData.data(), fontData.size());
146cb93a386Sopenharmony_ci    return write_SkData(writeFd, *data);
147cb93a386Sopenharmony_ci}
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_cistatic void final_draw(std::string outFilename, SkData* picData, SkStrikeClient* client,
150cb93a386Sopenharmony_ci                       ClientDiscardableManager* discardableManager, int readFd, int writeFd) {
151cb93a386Sopenharmony_ci    SkDeserialProcs procs;
152cb93a386Sopenharmony_ci    auto decode = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
153cb93a386Sopenharmony_ci        return reinterpret_cast<SkStrikeClient*>(ctx)->deserializeTypeface(data, length);
154cb93a386Sopenharmony_ci    };
155cb93a386Sopenharmony_ci    procs.fTypefaceProc = decode;
156cb93a386Sopenharmony_ci    procs.fTypefaceCtx = client;
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci    auto pic = SkPicture::MakeFromData(picData, &procs);
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci    auto cullRect = pic->cullRect();
161cb93a386Sopenharmony_ci    auto r = cullRect.round();
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_ci    auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
164cb93a386Sopenharmony_ci    auto c = s->getCanvas();
165cb93a386Sopenharmony_ci    auto picUnderTest = SkPicture::MakeFromData(picData, &procs);
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci    Timer drawTime;
168cb93a386Sopenharmony_ci    auto randomData = SkData::MakeUninitialized(1u);
169cb93a386Sopenharmony_ci    for (int i = 0; i < 100; i++) {
170cb93a386Sopenharmony_ci        if (gPurgeFontCaches) {
171cb93a386Sopenharmony_ci            ClientDiscardableManager::ScopedPurgeCache purge(discardableManager);
172cb93a386Sopenharmony_ci            SkGraphics::PurgeFontCache();
173cb93a386Sopenharmony_ci            SkASSERT(SkGraphics::GetFontCacheUsed() == 0u);
174cb93a386Sopenharmony_ci        }
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci        drawTime.start();
177cb93a386Sopenharmony_ci        if (client != nullptr) {
178cb93a386Sopenharmony_ci            // Kick the renderer to send us the fonts.
179cb93a386Sopenharmony_ci            write_SkData(writeFd, *randomData);
180cb93a386Sopenharmony_ci            auto fontData = read_SkData(readFd);
181cb93a386Sopenharmony_ci            if (fontData && !fontData->isEmpty()) {
182cb93a386Sopenharmony_ci                if (!client->readStrikeData(fontData->data(), fontData->size()))
183cb93a386Sopenharmony_ci                    SK_ABORT("Bad serialization");
184cb93a386Sopenharmony_ci            }
185cb93a386Sopenharmony_ci        }
186cb93a386Sopenharmony_ci        c->drawPicture(picUnderTest);
187cb93a386Sopenharmony_ci        drawTime.stop();
188cb93a386Sopenharmony_ci    }
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci    std::cout << "useProcess: " << gUseProcess
191cb93a386Sopenharmony_ci              << " useGPU: " << gUseGpu
192cb93a386Sopenharmony_ci              << " purgeCache: " << gPurgeFontCaches << std::endl;
193cb93a386Sopenharmony_ci    fprintf(stderr, "%s use GPU %s elapsed time %8.6f s\n", gSkpName.c_str(),
194cb93a386Sopenharmony_ci            gUseGpu ? "true" : "false", drawTime.elapsedSeconds());
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci    auto i = s->makeImageSnapshot();
197cb93a386Sopenharmony_ci    auto data = i->encodeToData();
198cb93a386Sopenharmony_ci    SkFILEWStream f(outFilename.c_str());
199cb93a386Sopenharmony_ci    f.write(data->data(), data->size());
200cb93a386Sopenharmony_ci}
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_cistatic void gpu(int readFd, int writeFd) {
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci    if (gUseGpu) {
205cb93a386Sopenharmony_ci        auto picData = read_SkData(readFd);
206cb93a386Sopenharmony_ci        if (picData == nullptr) {
207cb93a386Sopenharmony_ci            return;
208cb93a386Sopenharmony_ci        }
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ci        sk_sp<ClientDiscardableManager> discardableManager = sk_make_sp<ClientDiscardableManager>();
211cb93a386Sopenharmony_ci        SkStrikeClient strikeClient(discardableManager);
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci        final_draw("test.png", picData.get(), &strikeClient, discardableManager.get(), readFd,
214cb93a386Sopenharmony_ci                   writeFd);
215cb93a386Sopenharmony_ci    }
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci    ::close(writeFd);
218cb93a386Sopenharmony_ci    ::close(readFd);
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    printf("GPU is exiting\n");
221cb93a386Sopenharmony_ci}
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_cistatic int renderer(
224cb93a386Sopenharmony_ci    const std::string& skpName, int readFd, int writeFd)
225cb93a386Sopenharmony_ci{
226cb93a386Sopenharmony_ci    ServerDiscardableManager discardableManager;
227cb93a386Sopenharmony_ci    SkStrikeServer server(&discardableManager);
228cb93a386Sopenharmony_ci    auto closeAll = [readFd, writeFd]() {
229cb93a386Sopenharmony_ci        ::close(writeFd);
230cb93a386Sopenharmony_ci        ::close(readFd);
231cb93a386Sopenharmony_ci    };
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_ci    auto skpData = SkData::MakeFromFileName(skpName.c_str());
234cb93a386Sopenharmony_ci    std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl;
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci    sk_sp<SkData> stream;
237cb93a386Sopenharmony_ci    if (gUseGpu) {
238cb93a386Sopenharmony_ci        auto pic = SkPicture::MakeFromData(skpData.get());
239cb93a386Sopenharmony_ci        auto colorSpace = SkColorSpace::MakeSRGB();
240cb93a386Sopenharmony_ci        SkSerialProcs procs;
241cb93a386Sopenharmony_ci        auto encode = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> {
242cb93a386Sopenharmony_ci            return reinterpret_cast<SkStrikeServer*>(ctx)->serializeTypeface(tf);
243cb93a386Sopenharmony_ci        };
244cb93a386Sopenharmony_ci        procs.fTypefaceProc = encode;
245cb93a386Sopenharmony_ci        procs.fTypefaceCtx = &server;
246cb93a386Sopenharmony_ci
247cb93a386Sopenharmony_ci        stream = pic->serialize(&procs);
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ci        if (!write_SkData(writeFd, *stream)) {
250cb93a386Sopenharmony_ci            closeAll();
251cb93a386Sopenharmony_ci            return 1;
252cb93a386Sopenharmony_ci        }
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ci        while (true) {
255cb93a386Sopenharmony_ci            auto inBuffer = read_SkData(readFd);
256cb93a386Sopenharmony_ci            if (inBuffer == nullptr) {
257cb93a386Sopenharmony_ci                closeAll();
258cb93a386Sopenharmony_ci                return 0;
259cb93a386Sopenharmony_ci            }
260cb93a386Sopenharmony_ci            if (gPurgeFontCaches) discardableManager.purgeAll();
261cb93a386Sopenharmony_ci            push_font_data(*pic, &server, colorSpace, writeFd);
262cb93a386Sopenharmony_ci        }
263cb93a386Sopenharmony_ci    } else {
264cb93a386Sopenharmony_ci        stream = skpData;
265cb93a386Sopenharmony_ci        final_draw("test-correct.png", stream.get(), nullptr, nullptr, -1, -1);
266cb93a386Sopenharmony_ci        closeAll();
267cb93a386Sopenharmony_ci        return 0;
268cb93a386Sopenharmony_ci    }
269cb93a386Sopenharmony_ci}
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ciint main(int argc, char** argv) {
272cb93a386Sopenharmony_ci    std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"skps/desk_nytimes.skp"};
273cb93a386Sopenharmony_ci    int mode = argc > 2 ? atoi(argv[2]) : -1;
274cb93a386Sopenharmony_ci    printf("skp: %s\n", skpName.c_str());
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ci    gSkpName = skpName;
277cb93a386Sopenharmony_ci
278cb93a386Sopenharmony_ci    enum direction : int {kRead = 0, kWrite = 1};
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci    int render_to_gpu[2],
282cb93a386Sopenharmony_ci        gpu_to_render[2];
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci    for (int m = 0; m < 8; m++) {
285cb93a386Sopenharmony_ci        int r = pipe(render_to_gpu);
286cb93a386Sopenharmony_ci        if (r < 0) {
287cb93a386Sopenharmony_ci            perror("Can't write picture from render to GPU ");
288cb93a386Sopenharmony_ci            return 1;
289cb93a386Sopenharmony_ci        }
290cb93a386Sopenharmony_ci        r = pipe(gpu_to_render);
291cb93a386Sopenharmony_ci        if (r < 0) {
292cb93a386Sopenharmony_ci            perror("Can't write picture from render to GPU ");
293cb93a386Sopenharmony_ci            return 1;
294cb93a386Sopenharmony_ci        }
295cb93a386Sopenharmony_ci
296cb93a386Sopenharmony_ci        gPurgeFontCaches = (m & 4) == 4;
297cb93a386Sopenharmony_ci        gUseGpu = (m & 2) == 2;
298cb93a386Sopenharmony_ci        gUseProcess = (m & 1) == 1;
299cb93a386Sopenharmony_ci
300cb93a386Sopenharmony_ci        if (mode >= 0 && mode < 8 && mode != m) {
301cb93a386Sopenharmony_ci            continue;
302cb93a386Sopenharmony_ci        }
303cb93a386Sopenharmony_ci
304cb93a386Sopenharmony_ci        if (gUseProcess) {
305cb93a386Sopenharmony_ci            pid_t child = fork();
306cb93a386Sopenharmony_ci            SkGraphics::Init();
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci            if (child == 0) {
309cb93a386Sopenharmony_ci                close(gpu_to_render[kRead]);
310cb93a386Sopenharmony_ci                close(render_to_gpu[kWrite]);
311cb93a386Sopenharmony_ci                gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
312cb93a386Sopenharmony_ci            } else {
313cb93a386Sopenharmony_ci                close(render_to_gpu[kRead]);
314cb93a386Sopenharmony_ci                close(gpu_to_render[kWrite]);
315cb93a386Sopenharmony_ci                renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
316cb93a386Sopenharmony_ci                waitpid(child, nullptr, 0);
317cb93a386Sopenharmony_ci            }
318cb93a386Sopenharmony_ci        } else {
319cb93a386Sopenharmony_ci            SkGraphics::Init();
320cb93a386Sopenharmony_ci            std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach();
321cb93a386Sopenharmony_ci            renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
322cb93a386Sopenharmony_ci        }
323cb93a386Sopenharmony_ci    }
324cb93a386Sopenharmony_ci
325cb93a386Sopenharmony_ci    return 0;
326cb93a386Sopenharmony_ci}
327