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 "SkCanvas.h" 9#include "SkPathEffect.h" 10#include "SkMaskFilter.h" 11#include "SkData.h" 12#include "SkDescriptor.h" 13#include "SkGraphics.h" 14#include "SkSemaphore.h" 15#include "SkPictureRecorder.h" 16#include "SkSerialProcs.h" 17#include "SkSurface.h" 18#include "SkTypeface.h" 19#include "SkWriteBuffer.h" 20 21#include <chrono> 22#include <ctype.h> 23#include <err.h> 24#include <memory> 25#include <stdio.h> 26#include <thread> 27#include <iostream> 28#include <unordered_map> 29 30#include <sys/types.h> 31#include <sys/wait.h> 32#include <unistd.h> 33#include <sys/mman.h> 34#include "SkTypeface_remote.h" 35#include "SkRemoteGlyphCache.h" 36#include "SkMakeUnique.h" 37 38static const size_t kPageSize = 4096; 39 40static bool gUseGpu = true; 41static bool gPurgeFontCaches = true; 42static bool gUseProcess = true; 43 44enum class OpCode : int32_t { 45 kFontMetrics = 0, 46 kGlyphMetrics = 1, 47 kGlyphImage = 2, 48 kGlyphPath = 3, 49 kGlyphMetricsAndImage = 4, 50}; 51 52class Op { 53public: 54 Op(OpCode opCode, SkFontID typefaceId, const SkScalerContextRec& rec) 55 : opCode{opCode} 56 , typefaceId{typefaceId} 57 , descriptor{rec} { } 58 const OpCode opCode; 59 const SkFontID typefaceId; 60 const SkScalerContextRecDescriptor descriptor; 61 union { 62 // op 0 63 SkPaint::FontMetrics fontMetrics; 64 // op 1 and 2 65 SkGlyph glyph; 66 // op 3 67 struct { 68 SkGlyphID glyphId; 69 size_t pathSize; 70 }; 71 }; 72}; 73 74class RemoteScalerContextFIFO : public SkRemoteScalerContext { 75public: 76 explicit RemoteScalerContextFIFO(int readFd, int writeFd) 77 : fReadFd{readFd} 78 , fWriteFd{writeFd} { } 79 void generateFontMetrics(const SkTypefaceProxy& tf, 80 const SkScalerContextRec& rec, 81 SkPaint::FontMetrics* metrics) override { 82 Op* op = this->createOp(OpCode::kFontMetrics, tf, rec); 83 write(fWriteFd, fBuffer, sizeof(*op)); 84 read(fReadFd, fBuffer, sizeof(fBuffer)); 85 memcpy(metrics, &op->fontMetrics, sizeof(op->fontMetrics)); 86 op->~Op(); 87 } 88 89 void generateMetrics(const SkTypefaceProxy& tf, 90 const SkScalerContextRec& rec, 91 SkGlyph* glyph) override { 92 Op* op = this->createOp(OpCode::kGlyphMetrics, tf, rec); 93 memcpy(&op->glyph, glyph, sizeof(*glyph)); 94 write(fWriteFd, fBuffer, sizeof(*op)); 95 read(fReadFd, fBuffer, sizeof(fBuffer)); 96 memcpy(glyph, &op->glyph, sizeof(op->glyph)); 97 op->~Op(); 98 } 99 100 void generateImage(const SkTypefaceProxy& tf, 101 const SkScalerContextRec& rec, 102 const SkGlyph& glyph) override { 103 SK_ABORT("generateImage should not be called."); 104 Op* op = this->createOp(OpCode::kGlyphImage, tf, rec); 105 memcpy(&op->glyph, &glyph, sizeof(glyph)); 106 write(fWriteFd, fBuffer, sizeof(*op)); 107 read(fReadFd, fBuffer, sizeof(fBuffer)); 108 memcpy(glyph.fImage, fBuffer + sizeof(Op), glyph.rowBytes() * glyph.fHeight); 109 op->~Op(); 110 } 111 112 void generateMetricsAndImage(const SkTypefaceProxy& tf, 113 const SkScalerContextRec& rec, 114 SkArenaAlloc* alloc, 115 SkGlyph* glyph) override { 116 Op* op = this->createOp(OpCode::kGlyphMetricsAndImage, tf, rec); 117 memcpy(&op->glyph, glyph, sizeof(op->glyph)); 118 write(fWriteFd, fBuffer, sizeof(*op)); 119 read(fReadFd, fBuffer, sizeof(fBuffer)); 120 memcpy(glyph, &op->glyph, sizeof(*glyph)); 121 glyph->allocImage(alloc); 122 memcpy(glyph->fImage, fBuffer + sizeof(Op), glyph->rowBytes() * glyph->fHeight); 123 op->~Op(); 124 } 125 126 void generatePath(const SkTypefaceProxy& tf, 127 const SkScalerContextRec& rec, 128 SkGlyphID glyph, SkPath* path) override { 129 Op* op = this->createOp(OpCode::kGlyphPath, tf, rec); 130 op->glyphId = glyph; 131 write(fWriteFd, fBuffer, sizeof(*op)); 132 read(fReadFd, fBuffer, sizeof(fBuffer)); 133 path->readFromMemory(fBuffer + sizeof(Op), op->pathSize); 134 op->~Op(); 135 } 136 137private: 138 Op* createOp(OpCode opCode, const SkTypefaceProxy& tf, 139 const SkScalerContextRec& rec) { 140 Op* op = new (fBuffer) Op(opCode, tf.fontID(), rec); 141 142 return op; 143 } 144 145 const int fReadFd, 146 fWriteFd; 147 uint8_t fBuffer[1024 * kPageSize]; 148}; 149 150static void final_draw(std::string outFilename, 151 SkDeserialProcs* procs, 152 uint8_t* picData, 153 size_t picSize) { 154 155 auto pic = SkPicture::MakeFromData(picData, picSize, procs); 156 157 auto cullRect = pic->cullRect(); 158 auto r = cullRect.round(); 159 160 auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height()); 161 auto c = s->getCanvas(); 162 auto picUnderTest = SkPicture::MakeFromData(picData, picSize, procs); 163 164 165 std::chrono::duration<double> total_seconds{0.0}; 166 for (int i = 0; i < 20; i++) { 167 if (gPurgeFontCaches) { 168 SkGraphics::PurgeFontCache(); 169 } 170 auto start = std::chrono::high_resolution_clock::now(); 171 c->drawPicture(picUnderTest); 172 auto end = std::chrono::high_resolution_clock::now(); 173 std::chrono::duration<double> elapsed_seconds = end-start; 174 total_seconds += elapsed_seconds; 175 176 } 177 178 std::cout << "useProcess: " << gUseProcess 179 << " useGPU: " << gUseGpu 180 << " purgeCache: " << gPurgeFontCaches << std::endl; 181 std::cerr << "elapsed time: " << total_seconds.count() << "s\n"; 182 183 auto i = s->makeImageSnapshot(); 184 auto data = i->encodeToData(); 185 SkFILEWStream f(outFilename.c_str()); 186 f.write(data->data(), data->size()); 187} 188 189static void gpu(int readFd, int writeFd) { 190 191 size_t picSize = 0; 192 ssize_t r = read(readFd, &picSize, sizeof(picSize)); 193 if (r > 0) { 194 195 static constexpr size_t kBufferSize = 10 * 1024 * kPageSize; 196 std::unique_ptr<uint8_t[]> picBuffer{new uint8_t[kBufferSize]}; 197 198 size_t readSoFar = 0; 199 while (readSoFar < picSize) { 200 ssize_t readSize; 201 if ((readSize = read(readFd, &picBuffer[readSoFar], kBufferSize - readSoFar)) <= 0) { 202 if (readSize == 0) return; 203 err(1, "gpu pic read error %d", errno); 204 } 205 readSoFar += readSize; 206 } 207 208 SkRemoteGlyphCacheGPU rc{ 209 skstd::make_unique<RemoteScalerContextFIFO>(readFd, writeFd) 210 }; 211 212 SkDeserialProcs procs; 213 rc.prepareDeserializeProcs(&procs); 214 215 final_draw("test.png", &procs, picBuffer.get(), picSize); 216 217 } 218 219 close(writeFd); 220 close(readFd); 221} 222 223static int renderer( 224 const std::string& skpName, int readFd, int writeFd) 225{ 226 std::string prefix{"skps/"}; 227 std::string fileName{prefix + skpName + ".skp"}; 228 229 auto skp = SkData::MakeFromFileName(fileName.c_str()); 230 std::cout << "skp stream is " << skp->size() << " bytes long " << std::endl; 231 232 SkRemoteGlyphCacheRenderer rc; 233 SkSerialProcs procs; 234 sk_sp<SkData> stream; 235 if (gUseGpu) { 236 auto pic = SkPicture::MakeFromData(skp.get()); 237 rc.prepareSerializeProcs(&procs); 238 stream = pic->serialize(&procs); 239 } else { 240 stream = skp; 241 } 242 243 std::cout << "stream is " << stream->size() << " bytes long" << std::endl; 244 245 size_t picSize = stream->size(); 246 uint8_t* picBuffer = (uint8_t*) stream->data(); 247 248 if (!gUseGpu) { 249 final_draw("test-direct.png", nullptr, picBuffer, picSize); 250 close(writeFd); 251 close(readFd); 252 return 0; 253 } 254 255 write(writeFd, &picSize, sizeof(picSize)); 256 257 size_t writeSoFar = 0; 258 while (writeSoFar < picSize) { 259 ssize_t writeSize = write(writeFd, &picBuffer[writeSoFar], picSize - writeSoFar); 260 if (writeSize <= 0) { 261 if (writeSize == 0) { 262 std::cout << "Exit" << std::endl; 263 return 1; 264 } 265 perror("Can't write picture from render to GPU "); 266 return 1; 267 } 268 writeSoFar += writeSize; 269 } 270 std::cout << "Waiting for scaler context ops." << std::endl; 271 272 static constexpr size_t kBufferSize = 1024 * kPageSize; 273 std::unique_ptr<uint8_t[]> glyphBuffer{new uint8_t[kBufferSize]}; 274 275 Op* op = (Op*)glyphBuffer.get(); 276 while (true) { 277 ssize_t size = read(readFd, glyphBuffer.get(), sizeof(*op)); 278 if (size <= 0) { std::cout << "Exit op loop" << std::endl; break;} 279 size_t writeSize = sizeof(*op); 280 281 auto sc = rc.generateScalerContext(op->descriptor, op->typefaceId); 282 switch (op->opCode) { 283 case OpCode::kFontMetrics : { 284 sc->getFontMetrics(&op->fontMetrics); 285 break; 286 } 287 case OpCode::kGlyphMetrics : { 288 sc->getMetrics(&op->glyph); 289 break; 290 } 291 case OpCode::kGlyphImage : { 292 // TODO: check for buffer overflow. 293 op->glyph.fImage = &glyphBuffer[sizeof(Op)]; 294 sc->getImage(op->glyph); 295 writeSize += op->glyph.rowBytes() * op->glyph.fHeight; 296 break; 297 } 298 case OpCode::kGlyphPath : { 299 // TODO: check for buffer overflow. 300 SkPath path; 301 sc->getPath(op->glyphId, &path); 302 op->pathSize = path.writeToMemory(&glyphBuffer[sizeof(Op)]); 303 writeSize += op->pathSize; 304 break; 305 } 306 case OpCode::kGlyphMetricsAndImage : { 307 // TODO: check for buffer overflow. 308 sc->getMetrics(&op->glyph); 309 if (op->glyph.fWidth <= 0 || op->glyph.fWidth >= kMaxGlyphWidth) { 310 op->glyph.fImage = nullptr; 311 break; 312 } 313 op->glyph.fImage = &glyphBuffer[sizeof(Op)]; 314 sc->getImage(op->glyph); 315 writeSize += op->glyph.rowBytes() * op->glyph.fHeight; 316 break; 317 } 318 default: 319 SK_ABORT("Bad op"); 320 } 321 322 write(writeFd, glyphBuffer.get(), writeSize); 323 } 324 325 close(readFd); 326 close(writeFd); 327 328 std::cout << "Returning from render" << std::endl; 329 330 return 0; 331} 332 333enum direction : int {kRead = 0, kWrite = 1}; 334 335static void start_gpu(int render_to_gpu[2], int gpu_to_render[2]) { 336 std::cout << "gpu - Starting GPU" << std::endl; 337 close(gpu_to_render[kRead]); 338 close(render_to_gpu[kWrite]); 339 gpu(render_to_gpu[kRead], gpu_to_render[kWrite]); 340} 341 342static void start_render(std::string& skpName, int render_to_gpu[2], int gpu_to_render[2]) { 343 std::cout << "renderer - Starting Renderer" << std::endl; 344 close(render_to_gpu[kRead]); 345 close(gpu_to_render[kWrite]); 346 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]); 347} 348 349int main(int argc, char** argv) { 350 std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"desk_nytimes"}; 351 int mode = argc > 2 ? atoi(argv[2]) : -1; 352 printf("skp: %s\n", skpName.c_str()); 353 354 int render_to_gpu[2], 355 gpu_to_render[2]; 356 357 for (int m = 0; m < 8; m++) { 358 int r = pipe(render_to_gpu); 359 if (r < 0) { 360 perror("Can't write picture from render to GPU "); 361 return 1; 362 } 363 r = pipe(gpu_to_render); 364 if (r < 0) { 365 perror("Can't write picture from render to GPU "); 366 return 1; 367 } 368 369 gPurgeFontCaches = (m & 4) == 4; 370 gUseGpu = (m & 2) == 2; 371 gUseProcess = (m & 1) == 1; 372 373 if (mode >= 0 && mode < 8 && mode != m) { 374 continue; 375 } 376 377 if (gUseProcess) { 378 pid_t child = fork(); 379 SkGraphics::Init(); 380 381 if (child == 0) { 382 start_gpu(render_to_gpu, gpu_to_render); 383 } else { 384 start_render(skpName, render_to_gpu, gpu_to_render); 385 waitpid(child, nullptr, 0); 386 } 387 } else { 388 SkGraphics::Init(); 389 std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach(); 390 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]); 391 } 392 } 393 394 return 0; 395} 396 397