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