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