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 36static const size_t kPageSize = 4096; 37 38struct WireTypeface { 39 std::thread::id thread_id; 40 SkFontID typeface_id; 41 SkFontStyle style; 42 bool is_fixed; 43}; 44 45class ScalerContextRecDescriptor { 46public: 47 explicit ScalerContextRecDescriptor(const SkScalerContextRec& rec) { 48 auto desc = reinterpret_cast<SkDescriptor*>(&fDescriptor); 49 desc->init(); 50 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); 51 } 52 53 const SkDescriptor& desc() const { 54 return *reinterpret_cast<const SkDescriptor*>(&fDescriptor); 55 } 56 57 struct Hash { 58 size_t operator()(ScalerContextRecDescriptor const& s) const { 59 return SkOpts::hash_fn(&s.desc(), sizeof(s), 0); 60 } 61 }; 62 63 struct Equal { 64 bool operator()( const ScalerContextRecDescriptor& lhs, 65 const ScalerContextRecDescriptor& rhs ) const { 66 return lhs.desc() == rhs.desc(); 67 } 68 }; 69 70private: 71 // The system only passes descriptors without effects. That is why it uses a fixed size 72 // descriptor. storageFor is needed because some of the constructors below are private. 73 template <typename T> 74 using storageFor = typename std::aligned_storage<sizeof(T), alignof(T)>::type; 75 struct { 76 storageFor<SkDescriptor> dummy1; 77 storageFor<SkDescriptor::Entry> dummy2; 78 storageFor<SkScalerContextRec> dummy3; 79 } fDescriptor; 80}; 81 82class Op { 83public: 84 explicit Op(const SkScalerContextRec& rec) : descriptor{rec} {} 85 int32_t op; 86 SkFontID typeface_id; 87 union { 88 // op 0 89 SkPaint::FontMetrics fontMetrics; 90 // op 1 and 2 91 SkGlyph glyph; 92 // op 3 93 struct { 94 SkGlyphID glyphId; 95 size_t pathSize; 96 }; 97 }; 98 ScalerContextRecDescriptor descriptor; 99}; 100 101class RemoteScalerContextPassThread : public SkRemoteScalerContext { 102public: 103 explicit RemoteScalerContextPassThread(int readFd, int writeFd) 104 : fReadFd{readFd} 105 , fWriteFd{writeFd} { } 106 void generateFontMetrics(const SkTypefaceProxy& tf, 107 const SkScalerContextRec& rec, 108 SkPaint::FontMetrics* metrics) override { 109 Op* op = this->createOp(0, tf, rec); 110 write(fWriteFd, fBuffer, sizeof(*op)); 111 read(fReadFd, fBuffer, sizeof(fBuffer)); 112 memcpy(metrics, &op->fontMetrics, sizeof(op->fontMetrics)); 113 op->~Op(); 114 } 115 116 void generateMetrics(const SkTypefaceProxy& tf, 117 const SkScalerContextRec& rec, 118 SkGlyph* glyph) override { 119 Op* op = this->createOp(1, tf, rec); 120 memcpy(&op->glyph, glyph, sizeof(*glyph)); 121 write(fWriteFd, fBuffer, sizeof(*op)); 122 read(fReadFd, fBuffer, sizeof(fBuffer)); 123 memcpy(glyph, &op->glyph, sizeof(op->glyph)); 124 op->~Op(); 125 } 126 127 void generateImage(const SkTypefaceProxy& tf, 128 const SkScalerContextRec& rec, 129 const SkGlyph& glyph) override { 130 Op* op = this->createOp(2, tf, rec); 131 memcpy(&op->glyph, &glyph, sizeof(glyph)); 132 write(fWriteFd, fBuffer, sizeof(*op)); 133 read(fReadFd, fBuffer, sizeof(fBuffer)); 134 memcpy(glyph.fImage, fBuffer + sizeof(Op), glyph.rowBytes() * glyph.fHeight); 135 op->~Op(); 136 } 137 138 void generatePath(const SkTypefaceProxy& tf, 139 const SkScalerContextRec& rec, 140 SkGlyphID glyph, SkPath* path) override { 141 Op* op = this->createOp(3, tf, rec); 142 op->glyphId = glyph; 143 write(fWriteFd, fBuffer, sizeof(*op)); 144 read(fReadFd, fBuffer, sizeof(fBuffer)); 145 path->readFromMemory(fBuffer + sizeof(Op), op->pathSize); 146 op->~Op(); 147 } 148 149private: 150 Op* createOp(uint32_t opID, const SkTypefaceProxy& tf, 151 const SkScalerContextRec& rec) { 152 Op* op = new (fBuffer) Op(rec); 153 op->op = opID; 154 op->typeface_id = tf.fontID(); 155 156 return op; 157 } 158 159 const int fReadFd, 160 fWriteFd; 161 uint8_t fBuffer[1024 * kPageSize]; 162}; 163 164static sk_sp<SkTypeface> gpu_from_renderer_by_ID(const void* buf, size_t len, void* ctx) { 165 static std::unordered_map<SkFontID, sk_sp<SkTypefaceProxy>> mapIdToTypeface; 166 WireTypeface wire; 167 if (len >= sizeof(wire)) { 168 memcpy(&wire, buf, sizeof(wire)); 169 auto i = mapIdToTypeface.find(wire.typeface_id); 170 if (i == mapIdToTypeface.end()) { 171 172 auto newTypeface = sk_make_sp<SkTypefaceProxy>( 173 wire.typeface_id, 174 wire.thread_id, 175 wire.style, 176 wire.is_fixed, 177 (SkRemoteScalerContext*)ctx); 178 179 i = mapIdToTypeface.emplace_hint(i, wire.typeface_id, newTypeface); 180 } 181 return i->second; 182 } 183 SK_ABORT("Bad data"); 184 return nullptr; 185} 186 187std::unordered_map<SkFontID, sk_sp<SkTypeface>> gTypefaceMap; 188 189 190// TODO: Figure out how to manage the entries. 191std::unordered_map<ScalerContextRecDescriptor, 192 std::unique_ptr<SkScalerContext>, 193 ScalerContextRecDescriptor::Hash, 194 ScalerContextRecDescriptor::Equal> 195 gScalerContextMap(16, 196 ScalerContextRecDescriptor::Hash(), 197 ScalerContextRecDescriptor::Equal()); 198 199static SkScalerContext* scaler_context_from_op(Op* op) { 200 201 SkScalerContext* sc; 202 auto j = gScalerContextMap.find(op->descriptor); 203 if (j != gScalerContextMap.end()) { 204 sc = j->second.get(); 205 } else { 206 auto i = gTypefaceMap.find(op->typeface_id); 207 if (i == gTypefaceMap.end()) { 208 std::cerr << "bad typeface id: " << op->typeface_id << std::endl; 209 SK_ABORT("unknown type face"); 210 } 211 auto tf = i->second; 212 SkScalerContextEffects effects; 213 auto mapSc = tf->createScalerContext(effects, &op->descriptor.desc(), false); 214 sc = mapSc.get(); 215 gScalerContextMap.emplace_hint(j, op->descriptor, std::move(mapSc)); 216 } 217 return sc; 218 219} 220 221static sk_sp<SkData> renderer_to_gpu_by_ID(SkTypeface* tf, void* ctx) { 222 WireTypeface wire = { 223 std::this_thread::get_id(), 224 SkTypeface::UniqueID(tf), 225 tf->fontStyle(), 226 tf->isFixedPitch() 227 }; 228 auto i = gTypefaceMap.find(SkTypeface::UniqueID(tf)); 229 if (i == gTypefaceMap.end()) { 230 gTypefaceMap.insert({SkTypeface::UniqueID(tf), sk_ref_sp(tf)}); 231 } 232 return SkData::MakeWithCopy(&wire, sizeof(wire)); 233} 234 235static void final_draw(std::string outFilename, 236 SkDeserialProcs* procs, 237 uint8_t* picData, 238 size_t picSize) { 239 240 auto pic = SkPicture::MakeFromData(picData, picSize, procs); 241 242 auto cullRect = pic->cullRect(); 243 auto r = cullRect.round(); 244 245 auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height()); 246 auto c = s->getCanvas(); 247 248 auto picUnderTest = SkPicture::MakeFromData(picData, picSize, procs); 249 auto start = std::chrono::high_resolution_clock::now(); 250 251 for (int i = 0; i < 40; i++) { 252 253 c->drawPicture(picUnderTest); 254 } 255 256 auto end = std::chrono::high_resolution_clock::now(); 257 258 std::chrono::duration<double> elapsed_seconds = end-start; 259 260 std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n"; 261 262 auto i = s->makeImageSnapshot(); 263 auto data = i->encodeToData(); 264 SkFILEWStream f(outFilename.c_str()); 265 f.write(data->data(), data->size()); 266} 267 268static void gpu(int readFd, int writeFd) { 269 270 size_t picSize = 0; 271 read(readFd, &picSize, sizeof(picSize)); 272 273 static constexpr size_t kBufferSize = 10 * 1024 * kPageSize; 274 std::unique_ptr<uint8_t[]> picBuffer{new uint8_t[kBufferSize]}; 275 276 size_t readSoFar = 0; 277 while (readSoFar < picSize) { 278 ssize_t readSize; 279 if((readSize = read(readFd, &picBuffer[readSoFar], kBufferSize - readSoFar)) <= 0) { 280 if (readSize == 0) return; 281 err(1, "gpu pic read error %d", errno); 282 } 283 readSoFar += readSize; 284 } 285 286 SkDeserialProcs procs; 287 std::unique_ptr<SkRemoteScalerContext> rsc{ 288 new RemoteScalerContextPassThread{readFd, writeFd}}; 289 procs.fTypefaceProc = gpu_from_renderer_by_ID; 290 procs.fTypefaceCtx = rsc.get(); 291 final_draw("test.png", &procs, picBuffer.get(), picSize); 292 /* 293 auto pic = SkPicture::MakeFromData(picBuffer.get(), picSize, &procs); 294 295 auto cullRect = pic->cullRect(); 296 auto r = cullRect.round(); 297 auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height()); 298 299 auto c = s->getCanvas(); 300 c->drawPicture(pic); 301 302 auto i = s->makeImageSnapshot(); 303 auto data = i->encodeToData(); 304 SkFILEWStream f("test.png"); 305 f.write(data->data(), data->size()); 306 */ 307 close(writeFd); 308 close(readFd); 309} 310 311static int renderer(const std::string& skpName, int readFd, int writeFd) { 312 std::string prefix{"skps/"}; 313 std::string fileName{prefix + skpName + ".skp"}; 314 315 auto skp = SkData::MakeFromFileName(fileName.c_str()); 316 auto pic = SkPicture::MakeFromData(skp.get()); 317 318 bool toGpu = true; 319 320 SkSerialProcs procs; 321 if (toGpu) { 322 procs.fTypefaceProc = renderer_to_gpu_by_ID; 323 } 324 325 auto stream = pic->serialize(&procs); 326 327 std::cerr << "stream is " << stream->size() << " bytes long" << std::endl; 328 329 size_t picSize = stream->size(); 330 uint8_t* picBuffer = (uint8_t*) stream->data(); 331 332 if (!toGpu) { 333 final_draw("test-direct.png", nullptr, picBuffer, picSize); 334 close(writeFd); 335 close(readFd); 336 return 0; 337 } 338 339 write(writeFd, &picSize, sizeof(picSize)); 340 341 size_t writeSoFar = 0; 342 while (writeSoFar < picSize) { 343 ssize_t writeSize = write(writeFd, &picBuffer[writeSoFar], picSize - writeSoFar); 344 if (writeSize <= 0) { 345 if (writeSize == 0) { 346 std::cerr << "Exit" << std::endl; 347 return 1; 348 } 349 perror("Can't write picture from render to GPU "); 350 return 1; 351 } 352 writeSoFar += writeSize; 353 } 354 std::cerr << "Waiting for scaler context ops." << std::endl; 355 356 static constexpr size_t kBufferSize = 1024 * kPageSize; 357 std::unique_ptr<uint8_t[]> glyphBuffer{new uint8_t[kBufferSize]}; 358 359 Op* op = (Op*)glyphBuffer.get(); 360 while (true) { 361 ssize_t size = read(readFd, glyphBuffer.get(), sizeof(*op)); 362 if (size <= 0) { std::cerr << "Exit op loop" << std::endl; break;} 363 size_t writeSize = sizeof(*op); 364 365 auto sc = scaler_context_from_op(op); 366 switch (op->op) { 367 case 0: { 368 sc->getFontMetrics(&op->fontMetrics); 369 break; 370 } 371 case 1: { 372 sc->getMetrics(&op->glyph); 373 break; 374 } 375 case 2: { 376 // TODO: check for buffer overflow. 377 op->glyph.fImage = &glyphBuffer[sizeof(Op)]; 378 sc->getImage(op->glyph); 379 writeSize += op->glyph.rowBytes() * op->glyph.fHeight; 380 break; 381 } 382 case 3: { 383 // TODO: check for buffer overflow. 384 SkPath path; 385 sc->getPath(op->glyphId, &path); 386 op->pathSize = path.writeToMemory(&glyphBuffer[sizeof(Op)]); 387 writeSize += op->pathSize; 388 break; 389 } 390 default: 391 SkASSERT("Bad op"); 392 } 393 write(writeFd, glyphBuffer.get(), writeSize); 394 } 395 396 close(readFd); 397 close(writeFd); 398 399 std::cerr << "Returning from render" << std::endl; 400 401 return 0; 402} 403 404enum direction : int {kRead = 0, kWrite = 1}; 405 406static void start_gpu(int render_to_gpu[2], int gpu_to_render[2]) { 407 std::cout << "gpu - Starting GPU" << std::endl; 408 close(gpu_to_render[kRead]); 409 close(render_to_gpu[kWrite]); 410 gpu(render_to_gpu[kRead], gpu_to_render[kWrite]); 411} 412 413static void start_render(std::string& skpName, int render_to_gpu[2], int gpu_to_render[2]) { 414 std::cout << "renderer - Starting Renderer" << std::endl; 415 close(render_to_gpu[kRead]); 416 close(gpu_to_render[kWrite]); 417 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]); 418} 419 420int main(int argc, char** argv) { 421 std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"desk_nytimes"}; 422 printf("skp: %s\n", skpName.c_str()); 423 424 int render_to_gpu[2], 425 gpu_to_render[2]; 426 427 int r = pipe(render_to_gpu); 428 if (r < 0) { 429 perror("Can't write picture from render to GPU "); 430 return 1; 431 } 432 r = pipe(gpu_to_render); 433 if (r < 0) { 434 perror("Can't write picture from render to GPU "); 435 return 1; 436 } 437 438 bool useProcess = true; 439 440 if (useProcess) { 441 pid_t child = fork(); 442 SkGraphics::Init(); 443 444 if (child == 0) { 445 start_render(skpName, render_to_gpu, gpu_to_render); 446 } else { 447 start_gpu(render_to_gpu, gpu_to_render); 448 std::cerr << "Waiting for renderer." << std::endl; 449 waitpid(child, nullptr, 0); 450 } 451 } else { 452 SkGraphics::Init(); 453 std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach(); 454 renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]); 455 } 456 457 return 0; 458} 459 460