blob: 105a9b3ea78cd78a4db5a1e0a087914b36ff99da [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
Herb Derby4f505f92018-01-09 12:34:11 -05008#include <chrono>
Mike Kleina8a51ce2018-01-09 12:34:11 -05009#include <err.h>
Mike Kleina8a51ce2018-01-09 12:34:11 -050010#include <iostream>
Herb Derby97be88f2018-03-21 16:23:49 -040011#include <memory>
12#include <string>
Mike Kleina8a51ce2018-01-09 12:34:11 -050013#include <sys/types.h>
Herb Derby67c47f22018-02-07 17:47:59 -050014#include <sys/uio.h>
Mike Kleina8a51ce2018-01-09 12:34:11 -050015#include <sys/wait.h>
Herb Derby97be88f2018-03-21 16:23:49 -040016#include <thread>
Mike Kleina8a51ce2018-01-09 12:34:11 -050017#include <unistd.h>
Herb Derby97be88f2018-03-21 16:23:49 -040018
Mike Klein8a232022018-05-02 13:54:11 +000019#include "SkGraphics.h"
Khushal38a08432018-05-02 10:29:37 -070020#include "SkRemoteGlyphCache.h"
21#include "SkScalerContext.h"
Herb Derby97be88f2018-03-21 16:23:49 -040022#include "SkSurface.h"
Mike Kleina8a51ce2018-01-09 12:34:11 -050023
Herb Derby97be88f2018-03-21 16:23:49 -040024static std::string gSkpName;
Herb Derby9d021822018-02-02 12:54:55 -050025static bool gUseGpu = true;
26static bool gPurgeFontCaches = true;
27static bool gUseProcess = true;
28
Khushal38a08432018-05-02 10:29:37 -070029class ServerDiscardableManager : public SkStrikeServer::DiscardableHandleManager {
30public:
31 ServerDiscardableManager() = default;
32 ~ServerDiscardableManager() override = default;
33
34 SkDiscardableHandleId createHandle() override { return ++nextHandleId; }
35 bool lockHandle(SkDiscardableHandleId handleId) override {
36 return handleId > lastPurgedHandleId;
37 }
38 void purgeAll() { lastPurgedHandleId = nextHandleId; }
39
40private:
41 SkDiscardableHandleId nextHandleId = 0u;
42 SkDiscardableHandleId lastPurgedHandleId = 0u;
43};
44
45class ClientDiscardableManager : public SkStrikeClient::DiscardableHandleManager {
46public:
47 class ScopedPurgeCache {
48 public:
49 ScopedPurgeCache(ClientDiscardableManager* manager) : fManager(manager) {
50 if (fManager) fManager->allowPurging = true;
51 }
52 ~ScopedPurgeCache() {
53 if (fManager) fManager->allowPurging = false;
54 }
55
56 private:
57 ClientDiscardableManager* fManager;
58 };
59
60 ClientDiscardableManager() = default;
61 ~ClientDiscardableManager() override = default;
62
63 bool deleteHandle(SkDiscardableHandleId) override { return allowPurging; }
64
65private:
66 bool allowPurging = false;
67};
68
Herb Derby209a5f32018-04-05 16:57:25 -040069static bool write_SkData(int fd, const SkData& data) {
70 size_t size = data.size();
71 ssize_t bytesWritten = ::write(fd, &size, sizeof(size));
72 if (bytesWritten < 0) {
73 err(1,"Failed write %zu", size);
74 return false;
Herb Derby67c47f22018-02-07 17:47:59 -050075 }
76
Herb Derby209a5f32018-04-05 16:57:25 -040077 bytesWritten = ::write(fd, data.data(), data.size());
78 if (bytesWritten < 0) {
79 err(1,"Failed write %zu", size);
80 return false;
81 }
82
83 return true;
84}
85
86static sk_sp<SkData> read_SkData(int fd) {
Herb Derby209a5f32018-04-05 16:57:25 -040087 size_t size;
88 ssize_t readSize = ::read(fd, &size, sizeof(size));
89 if (readSize <= 0) {
Herb Derby97be88f2018-03-21 16:23:49 -040090 if (readSize < 0) {
Herb Derby209a5f32018-04-05 16:57:25 -040091 err(1, "Failed read %zu", size);
Herb Derby67c47f22018-02-07 17:47:59 -050092 }
Herb Derby209a5f32018-04-05 16:57:25 -040093 return nullptr;
Herb Derby67c47f22018-02-07 17:47:59 -050094 }
95
Herb Derby209a5f32018-04-05 16:57:25 -040096 auto out = SkData::MakeUninitialized(size);
97 auto data = (uint8_t*)out->data();
98
99 size_t totalRead = 0;
100 while (totalRead < size) {
101 ssize_t sizeRead;
102 sizeRead = ::read(fd, &data[totalRead], size - totalRead);
103 if (sizeRead <= 0) {
104 if (readSize < 0) {
105 err(1, "Failed read %zu", size);
106 }
107 return nullptr;
108 }
109 totalRead += sizeRead;
110 }
111
112 return out;
113}
Herb Derby67c47f22018-02-07 17:47:59 -0500114
Herb Derby39e45df2018-03-27 14:40:53 -0400115class Timer {
116public:
117 void start() {
118 fStart = std::chrono::high_resolution_clock::now();
119 }
120
121 void stop() {
122 auto end = std::chrono::high_resolution_clock::now();
123 fElapsedSeconds += end - fStart;
124 }
125
126 double elapsedSeconds() {
127 return fElapsedSeconds.count();
128 }
129
130private:
131 decltype(std::chrono::high_resolution_clock::now()) fStart;
132 std::chrono::duration<double> fElapsedSeconds{0.0};
133};
134
Khushal38a08432018-05-02 10:29:37 -0700135static bool push_font_data(const SkPicture& pic, SkStrikeServer* strikeServer, int writeFd) {
Herb Derby97be88f2018-03-21 16:23:49 -0400136 SkMatrix deviceMatrix = SkMatrix::I();
Khushal38a08432018-05-02 10:29:37 -0700137 const SkIRect bounds = pic.cullRect().round();
138 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
139 SkTextBlobCacheDiffCanvas filter(bounds.width(), bounds.height(), deviceMatrix, props,
140 strikeServer);
Mike Klein8a232022018-05-02 13:54:11 +0000141 pic.playback(&filter);
Khushal38a08432018-05-02 10:29:37 -0700142
143 std::vector<uint8_t> fontData;
144 strikeServer->writeStrikeData(&fontData);
145 auto data = SkData::MakeWithoutCopy(fontData.data(), fontData.size());
146 return write_SkData(writeFd, *data);
Herb Derby67c47f22018-02-07 17:47:59 -0500147}
148
Khushal38a08432018-05-02 10:29:37 -0700149static void final_draw(std::string outFilename, SkData* picData, SkStrikeClient* client,
150 ClientDiscardableManager* discardableManager, int readFd, int writeFd) {
151 SkDeserialProcs procs;
152 auto decode = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
153 return reinterpret_cast<SkStrikeClient*>(ctx)->deserializeTypeface(data, length);
154 };
155 procs.fTypefaceProc = decode;
156 procs.fTypefaceCtx = client;
Herb Derby67c47f22018-02-07 17:47:59 -0500157
Khushal38a08432018-05-02 10:29:37 -0700158 auto pic = SkPicture::MakeFromData(picData, &procs);
Herb Derby4f505f92018-01-09 12:34:11 -0500159
160 auto cullRect = pic->cullRect();
161 auto r = cullRect.round();
Herb Derby4f505f92018-01-09 12:34:11 -0500162
Herb Derbyd08c6822018-01-09 12:34:11 -0500163 auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
Herb Derby4f505f92018-01-09 12:34:11 -0500164 auto c = s->getCanvas();
Khushal38a08432018-05-02 10:29:37 -0700165 auto picUnderTest = SkPicture::MakeFromData(picData, &procs);
Herb Derbyd08c6822018-01-09 12:34:11 -0500166
Herb Derby39e45df2018-03-27 14:40:53 -0400167 Timer drawTime;
Khushal38a08432018-05-02 10:29:37 -0700168 auto randomData = SkData::MakeUninitialized(1u);
Herb Derby39e45df2018-03-27 14:40:53 -0400169 for (int i = 0; i < 100; i++) {
Herb Derby9d021822018-02-02 12:54:55 -0500170 if (gPurgeFontCaches) {
Khushal38a08432018-05-02 10:29:37 -0700171 ClientDiscardableManager::ScopedPurgeCache purge(discardableManager);
Herb Derby9d021822018-02-02 12:54:55 -0500172 SkGraphics::PurgeFontCache();
Khushal38a08432018-05-02 10:29:37 -0700173 SkASSERT(SkGraphics::GetFontCacheUsed() == 0u);
Herb Derby9d021822018-02-02 12:54:55 -0500174 }
Khushal38a08432018-05-02 10:29:37 -0700175
Herb Derby39e45df2018-03-27 14:40:53 -0400176 drawTime.start();
Herb Derby97be88f2018-03-21 16:23:49 -0400177 if (client != nullptr) {
Khushal38a08432018-05-02 10:29:37 -0700178 // Kick the renderer to send us the fonts.
179 write_SkData(writeFd, *randomData);
180 auto fontData = read_SkData(readFd);
181 if (fontData && !fontData->isEmpty()) {
182 if (!client->readStrikeData(fontData->data(), fontData->size()))
183 SK_ABORT("Bad serialization");
184 }
Herb Derby67c47f22018-02-07 17:47:59 -0500185 }
Herb Derbyd08c6822018-01-09 12:34:11 -0500186 c->drawPicture(picUnderTest);
Herb Derby39e45df2018-03-27 14:40:53 -0400187 drawTime.stop();
Herb Derbyd08c6822018-01-09 12:34:11 -0500188 }
Herb Derby4f505f92018-01-09 12:34:11 -0500189
Herb Derby9d021822018-02-02 12:54:55 -0500190 std::cout << "useProcess: " << gUseProcess
191 << " useGPU: " << gUseGpu
192 << " purgeCache: " << gPurgeFontCaches << std::endl;
Herb Derby67c47f22018-02-07 17:47:59 -0500193 fprintf(stderr, "%s use GPU %s elapsed time %8.6f s\n", gSkpName.c_str(),
Herb Derby39e45df2018-03-27 14:40:53 -0400194 gUseGpu ? "true" : "false", drawTime.elapsedSeconds());
Herb Derby4f505f92018-01-09 12:34:11 -0500195
196 auto i = s->makeImageSnapshot();
197 auto data = i->encodeToData();
198 SkFILEWStream f(outFilename.c_str());
199 f.write(data->data(), data->size());
200}
201
Mike Kleina8a51ce2018-01-09 12:34:11 -0500202static void gpu(int readFd, int writeFd) {
203
Herb Derby39e45df2018-03-27 14:40:53 -0400204 if (gUseGpu) {
Herb Derby209a5f32018-04-05 16:57:25 -0400205 auto picData = read_SkData(readFd);
Herb Derby39e45df2018-03-27 14:40:53 -0400206 if (picData == nullptr) {
207 return;
208 }
209
Khushal38a08432018-05-02 10:29:37 -0700210 sk_sp<ClientDiscardableManager> discardableManager = sk_make_sp<ClientDiscardableManager>();
211 SkStrikeClient strikeClient(discardableManager);
Herb Derby39e45df2018-03-27 14:40:53 -0400212
Khushal38a08432018-05-02 10:29:37 -0700213 final_draw("test.png", picData.get(), &strikeClient, discardableManager.get(), readFd,
214 writeFd);
Mike Kleina8a51ce2018-01-09 12:34:11 -0500215 }
216
Herb Derby209a5f32018-04-05 16:57:25 -0400217 ::close(writeFd);
218 ::close(readFd);
219
Herb Derby97be88f2018-03-21 16:23:49 -0400220 printf("GPU is exiting\n");
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{
Khushal38a08432018-05-02 10:29:37 -0700226 ServerDiscardableManager discardableManager;
227 SkStrikeServer server(&discardableManager);
Herb Derby209a5f32018-04-05 16:57:25 -0400228 auto closeAll = [readFd, writeFd]() {
229 ::close(writeFd);
230 ::close(readFd);
231 };
Mike Kleina8a51ce2018-01-09 12:34:11 -0500232
Herb Derby67c47f22018-02-07 17:47:59 -0500233 auto skpData = SkData::MakeFromFileName(skpName.c_str());
234 std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl;
Herb Derby4f505f92018-01-09 12:34:11 -0500235
Herb Derby9d021822018-02-02 12:54:55 -0500236 sk_sp<SkData> stream;
237 if (gUseGpu) {
Herb Derby67c47f22018-02-07 17:47:59 -0500238 auto pic = SkPicture::MakeFromData(skpData.get());
Khushal38a08432018-05-02 10:29:37 -0700239 SkSerialProcs procs;
240 auto encode = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> {
241 return reinterpret_cast<SkStrikeServer*>(ctx)->serializeTypeface(tf);
242 };
243 procs.fTypefaceProc = encode;
244 procs.fTypefaceCtx = &server;
245
Herb Derby9d021822018-02-02 12:54:55 -0500246 stream = pic->serialize(&procs);
Herb Derby97be88f2018-03-21 16:23:49 -0400247
Herb Derby209a5f32018-04-05 16:57:25 -0400248 if (!write_SkData(writeFd, *stream)) {
249 closeAll();
Herb Derby97be88f2018-03-21 16:23:49 -0400250 return 1;
251 }
252
Herb Derby209a5f32018-04-05 16:57:25 -0400253 while (true) {
254 auto inBuffer = read_SkData(readFd);
255 if (inBuffer == nullptr) {
256 closeAll();
257 return 0;
258 }
Khushal38a08432018-05-02 10:29:37 -0700259 if (gPurgeFontCaches) discardableManager.purgeAll();
260 push_font_data(*pic.get(), &server, writeFd);
Herb Derby209a5f32018-04-05 16:57:25 -0400261 }
Herb Derby9d021822018-02-02 12:54:55 -0500262 } else {
Herb Derby67c47f22018-02-07 17:47:59 -0500263 stream = skpData;
Khushal38a08432018-05-02 10:29:37 -0700264 final_draw("test-correct.png", stream.get(), nullptr, nullptr, -1, -1);
Herb Derby209a5f32018-04-05 16:57:25 -0400265 closeAll();
Herb Derby4f505f92018-01-09 12:34:11 -0500266 return 0;
267 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500268}
269
270int main(int argc, char** argv) {
Herb Derby67c47f22018-02-07 17:47:59 -0500271 std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"skps/desk_nytimes.skp"};
Herb Derby9d021822018-02-02 12:54:55 -0500272 int mode = argc > 2 ? atoi(argv[2]) : -1;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500273 printf("skp: %s\n", skpName.c_str());
274
Herb Derby67c47f22018-02-07 17:47:59 -0500275 gSkpName = skpName;
276
Herb Derby97be88f2018-03-21 16:23:49 -0400277 enum direction : int {kRead = 0, kWrite = 1};
278
279
Mike Kleina8a51ce2018-01-09 12:34:11 -0500280 int render_to_gpu[2],
281 gpu_to_render[2];
282
Herb Derby9d021822018-02-02 12:54:55 -0500283 for (int m = 0; m < 8; m++) {
284 int r = pipe(render_to_gpu);
285 if (r < 0) {
286 perror("Can't write picture from render to GPU ");
287 return 1;
Herb Derbyd08c6822018-01-09 12:34:11 -0500288 }
Herb Derby9d021822018-02-02 12:54:55 -0500289 r = pipe(gpu_to_render);
290 if (r < 0) {
291 perror("Can't write picture from render to GPU ");
292 return 1;
293 }
294
295 gPurgeFontCaches = (m & 4) == 4;
296 gUseGpu = (m & 2) == 2;
297 gUseProcess = (m & 1) == 1;
298
299 if (mode >= 0 && mode < 8 && mode != m) {
300 continue;
301 }
302
303 if (gUseProcess) {
304 pid_t child = fork();
305 SkGraphics::Init();
306
307 if (child == 0) {
Herb Derby97be88f2018-03-21 16:23:49 -0400308 close(gpu_to_render[kRead]);
309 close(render_to_gpu[kWrite]);
310 gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
Herb Derby9d021822018-02-02 12:54:55 -0500311 } else {
Herb Derby97be88f2018-03-21 16:23:49 -0400312 close(render_to_gpu[kRead]);
313 close(gpu_to_render[kWrite]);
314 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
Herb Derby9d021822018-02-02 12:54:55 -0500315 waitpid(child, nullptr, 0);
316 }
317 } else {
318 SkGraphics::Init();
319 std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach();
320 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
321 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500322 }
323
Mike Kleina8a51ce2018-01-09 12:34:11 -0500324 return 0;
325}
326