blob: 91fd124fc6ca2960f13667a0198e1445c191f06a [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 Kleinc0bd9f92019-04-23 12:05:21 -050019#include "include/core/SkGraphics.h"
20#include "include/core/SkSurface.h"
21#include "src/core/SkRemoteGlyphCache.h"
22#include "src/core/SkScalerContext.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
Mike Reedf922c782019-02-19 15:46:38 -0500135static bool push_font_data(const SkPicture& pic, SkStrikeServer* strikeServer,
136 sk_sp<SkColorSpace> colorSpace, int writeFd) {
Khushal38a08432018-05-02 10:29:37 -0700137 const SkIRect bounds = pic.cullRect().round();
138 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500139 SkTextBlobCacheDiffCanvas filter(bounds.width(), bounds.height(), props,
herb7022b772019-08-15 22:45:43 -0400140 strikeServer, std::move(colorSpace), true);
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());
Mike Reedf922c782019-02-19 15:46:38 -0500239 auto colorSpace = SkColorSpace::MakeSRGB();
Khushal38a08432018-05-02 10:29:37 -0700240 SkSerialProcs procs;
241 auto encode = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> {
242 return reinterpret_cast<SkStrikeServer*>(ctx)->serializeTypeface(tf);
243 };
244 procs.fTypefaceProc = encode;
245 procs.fTypefaceCtx = &server;
246
Herb Derby9d021822018-02-02 12:54:55 -0500247 stream = pic->serialize(&procs);
Herb Derby97be88f2018-03-21 16:23:49 -0400248
Herb Derby209a5f32018-04-05 16:57:25 -0400249 if (!write_SkData(writeFd, *stream)) {
250 closeAll();
Herb Derby97be88f2018-03-21 16:23:49 -0400251 return 1;
252 }
253
Herb Derby209a5f32018-04-05 16:57:25 -0400254 while (true) {
255 auto inBuffer = read_SkData(readFd);
256 if (inBuffer == nullptr) {
257 closeAll();
258 return 0;
259 }
Khushal38a08432018-05-02 10:29:37 -0700260 if (gPurgeFontCaches) discardableManager.purgeAll();
Mike Reedf922c782019-02-19 15:46:38 -0500261 push_font_data(*pic.get(), &server, colorSpace, writeFd);
Herb Derby209a5f32018-04-05 16:57:25 -0400262 }
Herb Derby9d021822018-02-02 12:54:55 -0500263 } else {
Herb Derby67c47f22018-02-07 17:47:59 -0500264 stream = skpData;
Khushal38a08432018-05-02 10:29:37 -0700265 final_draw("test-correct.png", stream.get(), nullptr, nullptr, -1, -1);
Herb Derby209a5f32018-04-05 16:57:25 -0400266 closeAll();
Herb Derby4f505f92018-01-09 12:34:11 -0500267 return 0;
268 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500269}
270
271int main(int argc, char** argv) {
Herb Derby67c47f22018-02-07 17:47:59 -0500272 std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"skps/desk_nytimes.skp"};
Herb Derby9d021822018-02-02 12:54:55 -0500273 int mode = argc > 2 ? atoi(argv[2]) : -1;
Mike Kleina8a51ce2018-01-09 12:34:11 -0500274 printf("skp: %s\n", skpName.c_str());
275
Herb Derby67c47f22018-02-07 17:47:59 -0500276 gSkpName = skpName;
277
Herb Derby97be88f2018-03-21 16:23:49 -0400278 enum direction : int {kRead = 0, kWrite = 1};
279
280
Mike Kleina8a51ce2018-01-09 12:34:11 -0500281 int render_to_gpu[2],
282 gpu_to_render[2];
283
Herb Derby9d021822018-02-02 12:54:55 -0500284 for (int m = 0; m < 8; m++) {
285 int r = pipe(render_to_gpu);
286 if (r < 0) {
287 perror("Can't write picture from render to GPU ");
288 return 1;
Herb Derbyd08c6822018-01-09 12:34:11 -0500289 }
Herb Derby9d021822018-02-02 12:54:55 -0500290 r = pipe(gpu_to_render);
291 if (r < 0) {
292 perror("Can't write picture from render to GPU ");
293 return 1;
294 }
295
296 gPurgeFontCaches = (m & 4) == 4;
297 gUseGpu = (m & 2) == 2;
298 gUseProcess = (m & 1) == 1;
299
300 if (mode >= 0 && mode < 8 && mode != m) {
301 continue;
302 }
303
304 if (gUseProcess) {
305 pid_t child = fork();
306 SkGraphics::Init();
307
308 if (child == 0) {
Herb Derby97be88f2018-03-21 16:23:49 -0400309 close(gpu_to_render[kRead]);
310 close(render_to_gpu[kWrite]);
311 gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
Herb Derby9d021822018-02-02 12:54:55 -0500312 } else {
Herb Derby97be88f2018-03-21 16:23:49 -0400313 close(render_to_gpu[kRead]);
314 close(gpu_to_render[kWrite]);
315 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
Herb Derby9d021822018-02-02 12:54:55 -0500316 waitpid(child, nullptr, 0);
317 }
318 } else {
319 SkGraphics::Init();
320 std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach();
321 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
322 }
Mike Kleina8a51ce2018-01-09 12:34:11 -0500323 }
324
Mike Kleina8a51ce2018-01-09 12:34:11 -0500325 return 0;
326}
327