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