1 /* 2 * Copyright 2016 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 "Benchmark.h" 9 10 #include "Resources.h" 11 #include "SkAutoPixmapStorage.h" 12 #include "SkData.h" 13 #include "SkExecutor.h" 14 #include "SkFloatToDecimal.h" 15 #include "SkGradientShader.h" 16 #include "SkImage.h" 17 #include "SkPDFUnion.h" 18 #include "SkPixmap.h" 19 #include "SkRandom.h" 20 #include "SkStream.h" 21 #include "SkTo.h" 22 23 namespace { 24 struct WStreamWriteTextBenchmark : public Benchmark { 25 std::unique_ptr<SkWStream> fWStream; 26 WStreamWriteTextBenchmark() : fWStream(new SkNullWStream) {} 27 const char* onGetName() override { return "WStreamWriteText"; } 28 bool isSuitableFor(Backend backend) override { 29 return backend == kNonRendering_Backend; 30 } 31 void onDraw(int loops, SkCanvas*) override { 32 while (loops-- > 0) { 33 for (int i = 1000; i-- > 0;) { 34 fWStream->writeText("HELLO SKIA!\n"); 35 } 36 } 37 } 38 }; 39 } // namespace 40 41 DEF_BENCH(return new WStreamWriteTextBenchmark;) 42 43 // Test speed of SkFloatToDecimal for typical floats that 44 // might be found in a PDF document. 45 struct PDFScalarBench : public Benchmark { 46 PDFScalarBench(const char* n, float (*f)(SkRandom*)) : fName(n), fNextFloat(f) {} 47 const char* fName; 48 float (*fNextFloat)(SkRandom*); 49 bool isSuitableFor(Backend b) override { 50 return b == kNonRendering_Backend; 51 } 52 const char* onGetName() override { return fName; } 53 void onDraw(int loops, SkCanvas*) override { 54 SkRandom random; 55 char dst[kMaximumSkFloatToDecimalLength]; 56 while (loops-- > 0) { 57 auto f = fNextFloat(&random); 58 (void)SkFloatToDecimal(f, dst); 59 } 60 } 61 }; 62 63 float next_common(SkRandom* random) { 64 return random->nextRangeF(-500.0f, 1500.0f); 65 } 66 float next_any(SkRandom* random) { 67 union { uint32_t u; float f; }; 68 u = random->nextU(); 69 static_assert(sizeof(float) == sizeof(uint32_t), ""); 70 return f; 71 } 72 73 DEF_BENCH(return new PDFScalarBench("PDFScalar_common", next_common);) 74 DEF_BENCH(return new PDFScalarBench("PDFScalar_random", next_any);) 75 76 #ifdef SK_SUPPORT_PDF 77 78 #include "SkPDFBitmap.h" 79 #include "SkPDFDocumentPriv.h" 80 #include "SkPDFShader.h" 81 #include "SkPDFUtils.h" 82 83 namespace { 84 class PDFImageBench : public Benchmark { 85 public: 86 PDFImageBench() {} 87 ~PDFImageBench() override {} 88 89 protected: 90 const char* onGetName() override { return "PDFImage"; } 91 bool isSuitableFor(Backend backend) override { 92 return backend == kNonRendering_Backend; 93 } 94 void onDelayedSetup() override { 95 sk_sp<SkImage> img(GetResourceAsImage("images/color_wheel.png")); 96 if (img) { 97 // force decoding, throw away reference to encoded data. 98 SkAutoPixmapStorage pixmap; 99 pixmap.alloc(SkImageInfo::MakeN32Premul(img->dimensions())); 100 if (img->readPixels(pixmap, 0, 0)) { 101 fImage = SkImage::MakeRasterCopy(pixmap); 102 } 103 } 104 } 105 void onDraw(int loops, SkCanvas*) override { 106 if (!fImage) { 107 return; 108 } 109 while (loops-- > 0) { 110 SkNullWStream nullStream; 111 SkPDFDocument doc(&nullStream, SkPDF::Metadata()); 112 doc.beginPage(256, 256); 113 (void)SkPDFSerializeImage(fImage.get(), &doc); 114 } 115 } 116 117 private: 118 sk_sp<SkImage> fImage; 119 }; 120 121 class PDFJpegImageBench : public Benchmark { 122 public: 123 PDFJpegImageBench() {} 124 ~PDFJpegImageBench() override {} 125 126 protected: 127 const char* onGetName() override { return "PDFJpegImage"; } 128 bool isSuitableFor(Backend backend) override { 129 return backend == kNonRendering_Backend; 130 } 131 void onDelayedSetup() override { 132 sk_sp<SkImage> img(GetResourceAsImage("images/mandrill_512_q075.jpg")); 133 if (!img) { return; } 134 sk_sp<SkData> encoded = img->refEncodedData(); 135 SkASSERT(encoded); 136 if (!encoded) { return; } 137 fImage = img; 138 } 139 void onDraw(int loops, SkCanvas*) override { 140 if (!fImage) { 141 SkDEBUGFAIL(""); 142 return; 143 } 144 while (loops-- > 0) { 145 SkNullWStream nullStream; 146 SkPDFDocument doc(&nullStream, SkPDF::Metadata()); 147 doc.beginPage(256, 256); 148 (void)SkPDFSerializeImage(fImage.get(), &doc); 149 } 150 } 151 152 private: 153 sk_sp<SkImage> fImage; 154 }; 155 156 /** Test calling DEFLATE on a 78k PDF command stream. Used for measuring 157 alternate zlib settings, usage, and library versions. */ 158 class PDFCompressionBench : public Benchmark { 159 public: 160 PDFCompressionBench() {} 161 ~PDFCompressionBench() override {} 162 163 protected: 164 const char* onGetName() override { return "PDFCompression"; } 165 bool isSuitableFor(Backend backend) override { 166 return backend == kNonRendering_Backend; 167 } 168 void onDelayedSetup() override { 169 fAsset = GetResourceAsStream("pdf_command_stream.txt"); 170 } 171 void onDraw(int loops, SkCanvas*) override { 172 SkASSERT(fAsset); 173 if (!fAsset) { return; } 174 while (loops-- > 0) { 175 SkNullWStream wStream; 176 SkPDFDocument doc(&wStream, SkPDF::Metadata()); 177 doc.beginPage(256, 256); 178 (void)SkPDFStreamOut(nullptr, fAsset->duplicate(), &doc, true); 179 } 180 } 181 182 private: 183 std::unique_ptr<SkStreamAsset> fAsset; 184 }; 185 186 struct PDFColorComponentBench : public Benchmark { 187 bool isSuitableFor(Backend b) override { 188 return b == kNonRendering_Backend; 189 } 190 const char* onGetName() override { return "PDFColorComponent"; } 191 void onDraw(int loops, SkCanvas*) override { 192 char dst[5]; 193 while (loops-- > 0) { 194 for (int i = 0; i < 256; ++i) { 195 (void)SkPDFUtils::ColorToDecimal(SkToU8(i), dst); 196 } 197 } 198 } 199 }; 200 201 struct PDFShaderBench : public Benchmark { 202 sk_sp<SkShader> fShader; 203 const char* onGetName() final { return "PDFShader"; } 204 bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; } 205 void onDelayedSetup() final { 206 const SkPoint pts[2] = {{0.0f, 0.0f}, {100.0f, 100.0f}}; 207 const SkColor colors[] = { 208 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, 209 SK_ColorWHITE, SK_ColorBLACK, 210 }; 211 fShader = SkGradientShader::MakeLinear( 212 pts, colors, nullptr, SK_ARRAY_COUNT(colors), 213 SkShader::kClamp_TileMode); 214 } 215 void onDraw(int loops, SkCanvas*) final { 216 SkASSERT(fShader); 217 while (loops-- > 0) { 218 SkNullWStream nullStream; 219 SkPDFDocument doc(&nullStream, SkPDF::Metadata()); 220 doc.beginPage(256, 256); 221 (void) SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(), 222 {0, 0, 400, 400}, SK_ColorBLACK); 223 } 224 } 225 }; 226 227 struct WritePDFTextBenchmark : public Benchmark { 228 std::unique_ptr<SkWStream> fWStream; 229 WritePDFTextBenchmark() : fWStream(new SkNullWStream) {} 230 const char* onGetName() override { return "WritePDFText"; } 231 bool isSuitableFor(Backend backend) override { 232 return backend == kNonRendering_Backend; 233 } 234 void onDraw(int loops, SkCanvas*) override { 235 static const char kHello[] = "HELLO SKIA!\n"; 236 static const char kBinary[] = "\001\002\003\004\005\006"; 237 while (loops-- > 0) { 238 for (int i = 1000; i-- > 0;) { 239 SkPDFWriteString(fWStream.get(), kHello, strlen(kHello)); 240 SkPDFWriteString(fWStream.get(), kBinary, strlen(kBinary)); 241 } 242 } 243 } 244 }; 245 246 } // namespace 247 DEF_BENCH(return new PDFImageBench;) 248 DEF_BENCH(return new PDFJpegImageBench;) 249 DEF_BENCH(return new PDFCompressionBench;) 250 DEF_BENCH(return new PDFColorComponentBench;) 251 DEF_BENCH(return new PDFShaderBench;) 252 DEF_BENCH(return new WritePDFTextBenchmark;) 253 254 #ifdef SK_PDF_ENABLE_SLOW_TESTS 255 #include "SkExecutor.h" 256 namespace { 257 void big_pdf_test(SkDocument* doc, const SkBitmap& background) { 258 static const char* kText[] = { 259 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do", 260 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad", 261 "minim veniam, quis nostrud exercitation ullamco laboris nisi ut", 262 "aliquip ex ea commodo consequat. Duis aute irure dolor in", 263 "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla", 264 "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in", 265 "culpa qui officia deserunt mollit anim id est laborum.", 266 "", 267 "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem", 268 "accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae", 269 "ab illo inventore veritatis et quasi architecto beatae vitae dicta", 270 "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit,", 271 "aspernatur aut odit aut fugit, sed quia consequuntur magni dolores", 272 "eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est,", 273 "qui dolorem ipsum, quia dolor sit amet consectetur adipiscing velit,", 274 "sed quia non numquam do eius modi tempora incididunt, ut labore et", 275 "dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,", 276 "quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi", 277 "ut aliquid ex ea commodi consequatur? Quis autem vel eum iure", 278 "reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae", 279 "consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla", 280 "pariatur?", 281 "", 282 "At vero eos et accusamus et iusto odio dignissimos ducimus, qui", 283 "blanditiis praesentium voluptatum deleniti atque corrupti, quos", 284 "dolores et quas molestias excepturi sint, obcaecati cupiditate non", 285 "provident, similique sunt in culpa, qui officia deserunt mollitia", 286 "animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis", 287 "est et expedita distinctio. Nam libero tempore, cum soluta nobis est", 288 "eligendi optio, cumque nihil impedit, quo minus id, quod maxime", 289 "placeat, facere possimus, omnis voluptas assumenda est, omnis dolor", 290 "repellendus. Temporibus autem quibusdam et aut officiis debitis aut", 291 "rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint", 292 "et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente", 293 "delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut", 294 "perferendis doloribus asperiores repellat", 295 "", 296 "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem", 297 "accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae", 298 "ab illo inventore veritatis et quasi architecto beatae vitae dicta", 299 "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit,", 300 "aspernatur aut odit aut fugit, sed quia consequuntur magni dolores", 301 "eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est,", 302 "qui dolorem ipsum, quia dolor sit amet consectetur adipiscing velit,", 303 "sed quia non numquam do eius modi tempora incididunt, ut labore et", 304 "dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,", 305 "quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi", 306 "ut aliquid ex ea commodi consequatur? Quis autem vel eum iure", 307 "reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae", 308 "consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla", 309 "pariatur?", 310 "", 311 }; 312 SkCanvas* canvas = nullptr; 313 float x = 36; 314 float y = 36; 315 constexpr size_t kLineCount = SK_ARRAY_COUNT(kText); 316 constexpr int kLoopCount = 200; 317 SkFont font; 318 SkPaint paint; 319 for (int loop = 0; loop < kLoopCount; ++loop) { 320 for (size_t line = 0; line < kLineCount; ++line) { 321 y += font.getSpacing(); 322 if (!canvas || y > 792 - 36) { 323 y = 36 + font.getSpacing(); 324 canvas = doc->beginPage(612, 792); 325 background.notifyPixelsChanged(); 326 canvas->drawBitmap(background, 0, 0); 327 } 328 canvas->drawString(kText[line], x, y, font, paint); 329 } 330 } 331 } 332 333 SkBitmap make_background() { 334 SkBitmap background; 335 SkBitmap bitmap; 336 bitmap.allocN32Pixels(32, 32); 337 bitmap.eraseColor(SK_ColorWHITE); 338 SkCanvas tmp(bitmap); 339 SkPaint gray; 340 gray.setColor(SkColorSetARGB(0xFF, 0xEE, 0xEE, 0xEE)); 341 tmp.drawRect({0,0,16,16}, gray); 342 tmp.drawRect({16,16,32,32}, gray); 343 SkPaint shader; 344 shader.setShader( 345 SkShader::MakeBitmapShader( 346 bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); 347 background.allocN32Pixels(612, 792); 348 SkCanvas tmp2(background); 349 tmp2.drawPaint(shader); 350 return background; 351 } 352 353 struct PDFBigDocBench : public Benchmark { 354 bool fFast; 355 SkBitmap fBackground; 356 std::unique_ptr<SkExecutor> fExecutor; 357 PDFBigDocBench(bool fast) : fFast(fast) {} 358 void onDelayedSetup() override { 359 fBackground = make_background(); 360 fExecutor = fFast ? SkExecutor::MakeFIFOThreadPool() : nullptr; 361 } 362 const char* onGetName() override { 363 static const char kNameFast[] = "PDFBigDocBench_fast"; 364 static const char kNameSlow[] = "PDFBigDocBench_slow"; 365 return fFast ? kNameFast : kNameSlow; 366 } 367 bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } 368 void onDraw(int loops, SkCanvas*) override { 369 while (loops-- > 0) { 370 #ifdef SK_PDF_TEST_BIGDOCBENCH_OUTPUT 371 SkFILEWStream wStream("/tmp/big_pdf.pdf"); 372 #else 373 SkNullWStream wStream; 374 #endif 375 SkPDF::Metadata metadata; 376 metadata.fExecutor = fExecutor.get(); 377 auto doc = SkPDF::MakeDocument(&wStream, metadata); 378 big_pdf_test(doc.get(), fBackground); 379 } 380 } 381 }; 382 } // namespace 383 DEF_BENCH(return new PDFBigDocBench(false);) 384 DEF_BENCH(return new PDFBigDocBench(true);) 385 #endif 386 387 #endif // SK_SUPPORT_PDF 388